diff --git a/app/components/badge/index.tsx b/app/components/badge/index.tsx index 720530705..abf4ef5b0 100644 --- a/app/components/badge/index.tsx +++ b/app/components/badge/index.tsx @@ -2,37 +2,30 @@ // See LICENSE.txt for license information. import * as React from 'react'; -import {Animated, StyleProp, StyleSheet, TextStyle} from 'react-native'; +import {Animated, Platform, StyleProp, StyleSheet, TextStyle} from 'react-native'; import {useTheme} from '@context/theme'; type Props = { + backgroundColor?: string; + borderColor: string; + color?: string; + style?: Animated.WithAnimatedValue>; + type?: 'Normal' | 'Small'; - /** - * Whether the badge is visible - */ - visible: boolean; - - /** - * Content of the `Badge`. - */ - children?: string | number; - - /** - * Size of the `Badge`. - */ - size?: number; - - /** - * Style object for the tab bar container. - */ - style?: Animated.WithAnimatedValue>; + /** + * Value of the `Badge` for unread dot use a negative value. + */ + value: number; + visible: boolean; }; export default function Badge({ + borderColor, + color, visible = true, - size = 18, - children, + type = 'Normal', + value, style, ...rest }: Props) { @@ -66,11 +59,33 @@ export default function Badge({ } // @ts-expect-error: backgroundColor definitely exists - const {backgroundColor = theme.buttonBg, ...restStyle} = + const {backgroundColor = rest.backgroundColor || theme.mentionBg, ...restStyle} = StyleSheet.flatten(style) || {}; - const textColor = theme.buttonColor; + const textColor = color || theme.mentionColor; + let lineHeight = Platform.select({android: 21, ios: 16.5}); + let fontSize = 12; + let size = value < 0 ? 12 : 22; + let minWidth = value < 0 ? size : 26; + let additionalStyle; + if (type === 'Small') { + size = value < 0 ? 12 : 20; + lineHeight = Platform.select({android: 19, ios: 15}); + fontSize = 11; + minWidth = value < 0 ? size : 24; + } const borderRadius = size / 2; - const fontSize = Math.floor((size * 3) / 4); + + let badge: string = value?.toString(); + if (value < 0) { + badge = ''; + additionalStyle = {paddingHorizontal: 0}; + } else if (value < 99) { + badge = value.toString(); + additionalStyle = {paddingHorizontal: 5}; + } else { + badge = '99+'; + additionalStyle = {paddingLeft: 4, paddingRight: 3}; + } return ( - {children} + {badge} ); } @@ -113,5 +130,7 @@ const styles = StyleSheet.create({ textAlign: 'center', paddingHorizontal: 4, overflow: 'hidden', + borderWidth: 2, + fontFamily: 'OpenSans-Bold', }, }); diff --git a/app/components/team_sidebar/team_list/team_item/team_item.tsx b/app/components/team_sidebar/team_list/team_item/team_item.tsx index 6fa0f1b45..d644f3a2f 100644 --- a/app/components/team_sidebar/team_list/team_item/team_item.tsx +++ b/app/components/team_sidebar/team_list/team_item/team_item.tsx @@ -29,21 +29,27 @@ export default function TeamItem({team, hasUnreads, mentionCount, currentTeamId} const selected = team.id === currentTeamId; const hasBadge = Boolean(mentionCount || hasUnreads); - let mentionText = mentionCount ? mentionCount.toString() : ''; - let left = 35; + let badgeStyle = styles.unread; + let value = mentionCount; + if (!mentionCount && hasUnreads) { + value = -1; + } + switch (true) { - case mentionCount > 99: - mentionText = '99+'; - left = 20; + case value > 99: + badgeStyle = styles.mentionsThreeDigits; break; - case mentionCount > 9: - left = 26; + case value > 9: + badgeStyle = styles.mentionsTwoDigits; + break; + case value > 0: + badgeStyle = styles.mentionsOneDigit; break; } return ( <> - + handleTeamChange(serverUrl, team.id)} type='opacity' @@ -57,12 +63,11 @@ export default function TeamItem({team, hasUnreads, mentionCount, currentTeamId} 0 ? [styles.mentions, {left}] : styles.unread} - size={mentionCount > 0 ? 16 : 12} - > - {mentionText} - + borderColor={theme.sidebarTeamBarBg} + visible={hasBadge} + style={badgeStyle} + value={value} + /> ); } @@ -70,44 +75,33 @@ export default function TeamItem({team, hasUnreads, mentionCount, currentTeamId} const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => { return { container: { - height: 48, - width: 48, + height: 54, + width: 54, flex: 0, + padding: 3, borderRadius: 10, - marginVertical: 6, + marginVertical: 3, overflow: 'hidden', }, containerSelected: { - height: 48, - width: 48, - padding: 3, borderWidth: 3, borderColor: theme.sidebarTextActiveBorder, - borderRadius: 10, - marginVertical: 6, }, unread: { left: 40, top: 3, - borderColor: theme.sidebarTeamBarBg, - borderWidth: 2, - backgroundColor: theme.mentionBg, - width: 12, }, - mentions: { + mentionsOneDigit: { top: 1, - fontSize: 12, - fontWeight: 'bold', - fontFamily: 'OpenSans', - lineHeight: 15, - borderColor: theme.sidebarTeamBarBg, - alignItems: 'center', - borderWidth: 2, - minWidth: 22, - height: 18, - borderRadius: 9, - backgroundColor: theme.mentionBg, - color: theme.mentionColor, + left: 28, + }, + mentionsTwoDigits: { + top: 1, + left: 26, + }, + mentionsThreeDigits: { + top: 1, + left: 23, }, }; }); diff --git a/app/constants/view.ts b/app/constants/view.ts index 2e7b0ffa8..5f225a8c6 100644 --- a/app/constants/view.ts +++ b/app/constants/view.ts @@ -43,6 +43,7 @@ export const MAX_BADGE_RIGHT_POSITION = -13; export const LARGE_BADGE_RIGHT_POSITION = -11; export const SMALL_BADGE_RIGHT_POSITION = -9; export const TEAM_SIDEBAR_WIDTH = 72; +export const BOTTOM_TAB_ICON_SIZE = 31.2; export const TABLET = { SIDEBAR_WIDTH: 320, @@ -118,6 +119,7 @@ const RequiredServer = { export default { ...ViewTypes, RequiredServer, + BOTTOM_TAB_ICON_SIZE, FEATURE_TOGGLE_PREFIX: 'feature_enabled_', EMBED_PREVIEW: 'embed_preview', LINK_PREVIEW_DISPLAY: 'link_previews', diff --git a/app/screens/home/tab_bar/home.tsx b/app/screens/home/tab_bar/home.tsx index 807f4a6fd..459e0b804 100644 --- a/app/screens/home/tab_bar/home.tsx +++ b/app/screens/home/tab_bar/home.tsx @@ -3,13 +3,14 @@ import {Q} from '@nozbe/watermelondb'; import React, {useEffect, useState} from 'react'; -import {Platform, View} from 'react-native'; +import {StyleSheet, View} from 'react-native'; import Badge from '@components/badge'; import CompassIcon from '@components/compass_icon'; import {MM_TABLES} from '@constants/database'; +import {BOTTOM_TAB_ICON_SIZE} from '@constants/view'; import DatabaseManager from '@database/manager'; -import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme'; +import {changeOpacity} from '@utils/theme'; import type ServersModel from '@typings/database/models/app/servers'; import type MyChannelModel from '@typings/database/models/servers/my_channel'; @@ -33,29 +34,25 @@ const {SERVERS} = MM_TABLES.APP; const {CHANNEL, MY_CHANNEL} = MM_TABLES.SERVER; const subscriptions: Map = new Map(); -const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => ({ +const style = StyleSheet.create({ unread: { - left: 16, - top: 1, - borderColor: theme.centerChannelBg, - borderWidth: 2, - paddingHorizontal: 0, + left: 19, + top: 4, }, - mentions: { - fontSize: 10, - fontFamily: 'OpenSans-Semibold', - lineHeight: Platform.select({android: 15, ios: 12.6}), - borderColor: theme.centerChannelBg, - borderWidth: 2, - minWidth: 18, - height: 16, + mentionsOneDigit: { + left: 12, }, -})); + mentionsTwoDigits: { + left: 13, + }, + mentionsThreeDigits: { + left: 10, + }, +}); const Home = ({isFocused, theme}: Props) => { const db = DatabaseManager.appDatabase?.database; const [total, setTotal] = useState({mentions: 0, messages: 0}); - const style = getStyleSheet(theme); const updateTotal = () => { let messages = 0; @@ -128,30 +125,33 @@ const Home = ({isFocused, theme}: Props) => { }, []); let unreadStyle; - let text: string | number = ''; - let size = 16; if (total.mentions) { - text = total.mentions > 99 ? '99+' : total.mentions; - unreadStyle = style.mentions; + unreadStyle = style.mentionsOneDigit; + if (total.mentions > 9) { + unreadStyle = style.mentionsTwoDigits; + } else if (total.mentions > 99) { + unreadStyle = style.mentionsThreeDigits; + } } else if (total.messages) { unreadStyle = style.unread; - size = 12; } return ( - {text} - + type='Small' + value={total.mentions || (total.messages * -1)} + /> ); }; diff --git a/app/screens/home/tab_bar/mentions.tsx b/app/screens/home/tab_bar/mentions.tsx index 4265d8b89..806044ec9 100644 --- a/app/screens/home/tab_bar/mentions.tsx +++ b/app/screens/home/tab_bar/mentions.tsx @@ -5,6 +5,7 @@ import React from 'react'; import {View} from 'react-native'; import CompassIcon from '@components/compass_icon'; +import {BOTTOM_TAB_ICON_SIZE} from '@constants/view'; import {changeOpacity} from '@utils/theme'; type Props = { @@ -16,7 +17,7 @@ const Mentions = ({isFocused, theme}: Props) => { return ( diff --git a/app/screens/home/tab_bar/search.tsx b/app/screens/home/tab_bar/search.tsx index ad655e5f0..cec18074c 100644 --- a/app/screens/home/tab_bar/search.tsx +++ b/app/screens/home/tab_bar/search.tsx @@ -5,6 +5,7 @@ import React from 'react'; import {View} from 'react-native'; import CompassIcon from '@components/compass_icon'; +import {BOTTOM_TAB_ICON_SIZE} from '@constants/view'; import {changeOpacity} from '@utils/theme'; type Props = { @@ -16,7 +17,7 @@ const Search = ({isFocused, theme}: Props) => { return (