From 169ed80243679a599a9d0ea87055b38b9c9d7f8d Mon Sep 17 00:00:00 2001 From: Adrian Brown Date: Mon, 17 Aug 2020 12:46:49 -0400 Subject: [PATCH] [MM-22948] - Improve unread badge UI on the hamburger menu and team icons (#4635) * updates to bage UI * fixed spacing * updated tests with npm test command * fixed badge theme colors * updated badge width to deal with larger mention counts * updated tests * fixed sizing issue * fixed sizing issue & moved maxWidth to Badge layout * added constants for badge maxWidth & adjusted badge position * adjusted top position for badge on burger menu * fixed last issue for max mentions positioning on burger menu badge --- app/components/badge.js | 16 ++++++--- .../__snapshots__/channel_item.test.js.snap | 2 ++ .../channel_item/channel_item.js | 2 ++ .../switch_teams_button.js | 25 ++++++++++++-- .../teams_list_item/teams_list_item.js | 25 ++++++++++++-- app/constants/view.js | 8 +++++ .../channel_drawer_button.test.js.snap | 9 ++--- .../channel_drawer_button.js | 33 +++++++++++++++---- 8 files changed, 99 insertions(+), 21 deletions(-) diff --git a/app/components/badge.js b/app/components/badge.js index 9905067cf..34064e69a 100644 --- a/app/components/badge.js +++ b/app/components/badge.js @@ -11,6 +11,7 @@ import { View, ViewPropTypes, } from 'react-native'; +import {CHANNEL_ITEM_LARGE_BADGE_MAX_WIDTH, CHANNEL_ITEM_SMALL_BADGE_MAX_WIDTH, LARGE_BADGE_MAX_WIDTH, SMALL_BADGE_MAX_WIDTH} from '@constants/view'; export default class Badge extends PureComponent { static defaultProps = { @@ -27,6 +28,7 @@ export default class Badge extends PureComponent { countStyle: Text.propTypes.style, minHeight: PropTypes.number, minWidth: PropTypes.number, + isChannelItem: PropTypes.bool, onPress: PropTypes.func, }; @@ -78,6 +80,12 @@ export default class Badge extends PureComponent { onLayout = (e) => { if (!this.layoutReady) { let width; + let maxWidth; + if (this.props.isChannelItem) { + maxWidth = this.props.count > 99 ? CHANNEL_ITEM_LARGE_BADGE_MAX_WIDTH : CHANNEL_ITEM_SMALL_BADGE_MAX_WIDTH; + } else { + maxWidth = this.props.count > 99 ? LARGE_BADGE_MAX_WIDTH : SMALL_BADGE_MAX_WIDTH; + } if (e.nativeEvent.layout.width <= e.nativeEvent.layout.height) { width = e.nativeEvent.layout.height; @@ -86,11 +94,13 @@ export default class Badge extends PureComponent { } width = Math.max(this.props.count < 10 ? width : width + 10, this.props.minWidth); const borderRadius = width / 2; + this.setNativeProps({ style: { width, borderRadius, opacity: 1, + maxWidth, }, }); this.layoutReady = true; @@ -106,11 +116,7 @@ export default class Badge extends PureComponent { - - - - + /> ); } else { let mentionCount = count; diff --git a/app/components/sidebars/main/channels_list/channel_item/__snapshots__/channel_item.test.js.snap b/app/components/sidebars/main/channels_list/channel_item/__snapshots__/channel_item.test.js.snap index 2abd735bc..68fa645ac 100644 --- a/app/components/sidebars/main/channels_list/channel_item/__snapshots__/channel_item.test.js.snap +++ b/app/components/sidebars/main/channels_list/channel_item/__snapshots__/channel_item.test.js.snap @@ -965,9 +965,11 @@ exports[`ChannelItem should match snapshot with mentions and muted 1`] = ` Object { "color": "#145dbf", "fontSize": 12, + "fontWeight": "bold", } } extraPaddingHorizontal={10} + isChannelItem={true} minHeight={20} minWidth={21} onPress={[Function]} diff --git a/app/components/sidebars/main/channels_list/channel_item/channel_item.js b/app/components/sidebars/main/channels_list/channel_item/channel_item.js index 9ccafa76d..717b8998b 100644 --- a/app/components/sidebars/main/channels_list/channel_item/channel_item.js +++ b/app/components/sidebars/main/channels_list/channel_item/channel_item.js @@ -143,6 +143,7 @@ export default class ChannelItem extends PureComponent { count={mentions} onPress={this.onPress} minWidth={21} + isChannelItem={true} /> ); } @@ -246,6 +247,7 @@ const getStyleSheet = makeStyleSheetFromTheme((theme) => { mention: { color: theme.mentionColor, fontSize: 12, + fontWeight: 'bold', }, muted: { opacity: 0.5, diff --git a/app/components/sidebars/main/channels_list/switch_teams_button/switch_teams_button.js b/app/components/sidebars/main/channels_list/switch_teams_button/switch_teams_button.js index 67549d9d5..7cf6cff66 100644 --- a/app/components/sidebars/main/channels_list/switch_teams_button/switch_teams_button.js +++ b/app/components/sidebars/main/channels_list/switch_teams_button/switch_teams_button.js @@ -46,12 +46,17 @@ export default class SwitchTeamsButton extends React.PureComponent { const styles = getStyleSheet(theme); + const lowMentionCount = mentionCount <= 0; + const minWidth = lowMentionCount ? 8 : 20; + const badgeStyle = lowMentionCount ? styles.smallBadge : styles.badge; + const containerStyle = lowMentionCount ? styles.smallBadgeContainer : styles.badgeContainer; + const badge = ( ); @@ -89,6 +94,11 @@ const getStyleSheet = makeStyleSheetFromTheme((theme) => { height: 20, padding: 3, }, + smallBadge: { + backgroundColor: theme.mentionBg, + height: 8, + padding: 3, + }, badgeContainer: { borderColor: theme.sidebarBg, borderRadius: 14, @@ -97,9 +107,18 @@ const getStyleSheet = makeStyleSheetFromTheme((theme) => { right: 0, top: -9, }, + smallBadgeContainer: { + borderColor: theme.sidebarBg, + borderRadius: 14, + borderWidth: 2, + position: 'absolute', + right: 6, + top: -5, + }, mention: { color: theme.mentionColor, fontSize: 10, + fontWeight: 'bold', }, switcherArrow: { color: theme.sidebarHeaderBg, diff --git a/app/components/sidebars/main/teams_list/teams_list_item/teams_list_item.js b/app/components/sidebars/main/teams_list/teams_list_item/teams_list_item.js index bdf5f1ef8..2281b5681 100644 --- a/app/components/sidebars/main/teams_list/teams_list_item/teams_list_item.js +++ b/app/components/sidebars/main/teams_list/teams_list_item/teams_list_item.js @@ -46,13 +46,18 @@ export default class TeamsListItem extends React.PureComponent { } = this.props; const styles = getStyleSheet(theme); + const lowMentionCount = mentionCount <= 0; + const minWidth = lowMentionCount ? 8 : 20; + const badgeStyle = lowMentionCount ? styles.smallBadge : styles.badge; + const containerStyle = lowMentionCount ? styles.smallBadgeContainer : styles.badgeContainer; + const badge = ( ); @@ -152,6 +157,11 @@ const getStyleSheet = makeStyleSheetFromTheme((theme) => { height: 20, padding: 3, }, + smallBadge: { + backgroundColor: theme.mentionBg, + height: 8, + padding: 3, + }, badgeContainer: { borderColor: theme.sidebarBg, borderRadius: 14, @@ -160,9 +170,18 @@ const getStyleSheet = makeStyleSheetFromTheme((theme) => { right: -12, top: -10, }, + smallBadgeContainer: { + borderColor: theme.sidebarBg, + borderRadius: 14, + borderWidth: 2, + position: 'absolute', + right: -7, + top: -6, + }, mention: { color: theme.mentionColor, fontSize: 10, + fontWeight: 'bold', }, }; }); diff --git a/app/constants/view.js b/app/constants/view.js index 1d52b1b1e..fcda722d1 100644 --- a/app/constants/view.js +++ b/app/constants/view.js @@ -36,6 +36,14 @@ export const NotificationLevels = { export const NOTIFY_ALL_MEMBERS = 5; export const INDICATOR_BAR_HEIGHT = 38; +export const CHANNEL_ITEM_LARGE_BADGE_MAX_WIDTH = 38; +export const CHANNEL_ITEM_SMALL_BADGE_MAX_WIDTH = 32; +export const LARGE_BADGE_MAX_WIDTH = 30; +export const SMALL_BADGE_MAX_WIDTH = 26; +export const MAX_BADGE_RIGHT_POSITION = -17; +export const LARGE_BADGE_RIGHT_POSITION = -16; +export const SMALL_BADGE_RIGHT_POSITION = -13; + const ViewTypes = keyMirror({ DATA_CLEANUP: null, SERVER_URL_CHANGED: null, diff --git a/app/screens/channel/channel_nav_bar/channel_drawer_button/__snapshots__/channel_drawer_button.test.js.snap b/app/screens/channel/channel_nav_bar/channel_drawer_button/__snapshots__/channel_drawer_button.test.js.snap index 0344c9500..353342ce9 100644 --- a/app/screens/channel/channel_nav_bar/channel_drawer_button/__snapshots__/channel_drawer_button.test.js.snap +++ b/app/screens/channel/channel_nav_bar/channel_drawer_button/__snapshots__/channel_drawer_button.test.js.snap @@ -79,8 +79,8 @@ exports[`ChannelDrawerButton should match, full snapshot 2`] = ` "borderRadius": 14, "borderWidth": 2, "position": "absolute", - "right": -14, - "top": -7, + "right": -13, + "top": -6, } } count={1} @@ -88,16 +88,17 @@ exports[`ChannelDrawerButton should match, full snapshot 2`] = ` Object { "color": "#145dbf", "fontSize": 10, + "fontWeight": "bold", } } extraPaddingHorizontal={10} minHeight={20} - minWidth={19} + minWidth={18} onPress={[Function]} style={ Object { "backgroundColor": "#ffffff", - "height": 19, + "height": 18, "padding": 3, } } diff --git a/app/screens/channel/channel_nav_bar/channel_drawer_button/channel_drawer_button.js b/app/screens/channel/channel_nav_bar/channel_drawer_button/channel_drawer_button.js index 89bc63074..6e60f6243 100644 --- a/app/screens/channel/channel_nav_bar/channel_drawer_button/channel_drawer_button.js +++ b/app/screens/channel/channel_nav_bar/channel_drawer_button/channel_drawer_button.js @@ -18,6 +18,7 @@ import {t} from 'app/utils/i18n'; import {intlShape} from 'react-intl'; import telemetry from 'app/telemetry'; +import {LARGE_BADGE_RIGHT_POSITION, SMALL_BADGE_RIGHT_POSITION, MAX_BADGE_RIGHT_POSITION} from '@constants/view'; export default class ChannelDrawerButton extends PureComponent { static propTypes = { @@ -87,14 +88,21 @@ export default class ChannelDrawerButton extends PureComponent { let badge; if (badgeCount && visible) { + const badgeCountLow = badgeCount <= 0; + const minWidth = badgeCountLow ? 8 : 18; + const badgeStyle = badgeCountLow ? style.smallBadge : style.badge; + const smallBadgeRightPosition = badgeCount > 9 ? LARGE_BADGE_RIGHT_POSITION : SMALL_BADGE_RIGHT_POSITION; + const rightStylePosition = badgeCount > 99 ? MAX_BADGE_RIGHT_POSITION : smallBadgeRightPosition; + const containerStyle = badgeCountLow ? style.smallBadgeContainer : {...style.badgeContainer, right: rightStylePosition}; + badge = ( ); } @@ -155,7 +163,12 @@ const getStyleFromTheme = makeStyleSheetFromTheme((theme) => { }, badge: { backgroundColor: theme.mentionBg, - height: 19, + height: 18, + padding: 3, + }, + smallBadge: { + backgroundColor: theme.mentionBg, + height: 8, padding: 3, }, badgeContainer: { @@ -163,12 +176,20 @@ const getStyleFromTheme = makeStyleSheetFromTheme((theme) => { borderRadius: 14, borderWidth: 2, position: 'absolute', - right: -14, - top: -7, + top: -6, + }, + smallBadgeContainer: { + borderColor: theme.sidebarHeaderBg, + borderRadius: 14, + borderWidth: 2, + position: 'absolute', + right: -7, + top: 0, }, mention: { color: theme.mentionColor, fontSize: 10, + fontWeight: 'bold', }, }; });