Generic badge & fixes to home tab & team sidebar items (#5794)

This commit is contained in:
Elias Nahum 2021-10-27 17:50:41 -03:00 committed by GitHub
parent 458a006cde
commit c01bcb7559
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 115 additions and 98 deletions

View file

@ -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<StyleProp<TextStyle>>;
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<StyleProp<TextStyle>>;
/**
* 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 (
<Animated.Text
@ -86,20 +101,22 @@ export default function Badge({
}),
},
],
borderColor,
backgroundColor,
color: textColor,
fontSize,
lineHeight: size - 1,
lineHeight,
minWidth,
height: size,
minWidth: size,
borderRadius,
},
styles.container,
additionalStyle,
restStyle,
]}
{...rest}
>
{children}
{badge}
</Animated.Text>
);
}
@ -113,5 +130,7 @@ const styles = StyleSheet.create({
textAlign: 'center',
paddingHorizontal: 4,
overflow: 'hidden',
borderWidth: 2,
fontFamily: 'OpenSans-Bold',
},
});

View file

@ -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 (
<>
<View style={selected ? styles.containerSelected : styles.container}>
<View style={[styles.container, selected ? styles.containerSelected : undefined]}>
<TouchableWithFeedback
onPress={() => handleTeamChange(serverUrl, team.id)}
type='opacity'
@ -57,12 +63,11 @@ export default function TeamItem({team, hasUnreads, mentionCount, currentTeamId}
</TouchableWithFeedback>
</View>
<Badge
visible={hasBadge && !selected}
style={mentionCount > 0 ? [styles.mentions, {left}] : styles.unread}
size={mentionCount > 0 ? 16 : 12}
>
{mentionText}
</Badge>
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,
},
};
});

View file

@ -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',

View file

@ -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<string, UnreadSubscription> = 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<UnreadMessages>({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 (
<View>
<CompassIcon
size={28}
size={BOTTOM_TAB_ICON_SIZE}
name='home-variant-outline'
color={isFocused ? theme.buttonBg : changeOpacity(theme.centerChannelColor, 0.48)}
/>
<Badge
style={[unreadStyle]}
backgroundColor={theme.buttonBg}
borderColor={theme.centerChannelBg}
color={theme.buttonColor}
style={unreadStyle}
visible={!isFocused && Boolean(unreadStyle)}
size={size}
>
{text}
</Badge>
type='Small'
value={total.mentions || (total.messages * -1)}
/>
</View>
);
};

View file

@ -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 (
<View>
<CompassIcon
size={28}
size={BOTTOM_TAB_ICON_SIZE}
name='at'
color={isFocused ? theme.buttonBg : changeOpacity(theme.centerChannelColor, 0.48)}
/>

View file

@ -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 (
<View>
<CompassIcon
size={28}
size={BOTTOM_TAB_ICON_SIZE}
name='magnify'
color={isFocused ? theme.buttonBg : changeOpacity(theme.centerChannelColor, 0.48)}
/>