Update badge logic for new setting and behaviour
For https://github.com/vector-im/riot-web/issues/14084pull/21833/head
							parent
							
								
									30d8dc06fc
								
							
						
					
					
						commit
						eeb408a081
					
				|  | @ -32,13 +32,14 @@ import ActiveRoomObserver from "../../../ActiveRoomObserver"; | |||
| import { EventEmitter } from "events"; | ||||
| import { arrayDiff } from "../../../utils/arrays"; | ||||
| import { IDestroyable } from "../../../utils/IDestroyable"; | ||||
| import SettingsStore from "../../../settings/SettingsStore"; | ||||
| 
 | ||||
| export const NOTIFICATION_STATE_UPDATE = "update"; | ||||
| 
 | ||||
| export enum NotificationColor { | ||||
|     // Inverted (None -> Red) because we do integer comparisons on this
 | ||||
|     None, // nothing special
 | ||||
|     Bold, // no badge, show as unread
 | ||||
|     Bold, // no badge, show as unread // TODO: This goes away with new notification structures
 | ||||
|     Grey, // unread notified messages
 | ||||
|     Red,  // unread pings
 | ||||
| } | ||||
|  | @ -53,18 +54,45 @@ interface IProps { | |||
|     notification: INotificationState; | ||||
| 
 | ||||
|     /** | ||||
|      * If true, the badge will conditionally display a badge without count for the user. | ||||
|      * If true, the badge will show a count if at all possible. This is typically | ||||
|      * used to override the user's preference for things like room sublists. | ||||
|      */ | ||||
|     allowNoCount: boolean; | ||||
|     forceCount: boolean; | ||||
| 
 | ||||
|     /** | ||||
|      * The room ID, if any, the badge represents. | ||||
|      */ | ||||
|     roomId?: string; | ||||
| } | ||||
| 
 | ||||
| interface IState { | ||||
|     showCounts: boolean; // whether or not to show counts. Independent of props.forceCount
 | ||||
| } | ||||
| 
 | ||||
| export default class NotificationBadge extends React.PureComponent<IProps, IState> { | ||||
|     private countWatcherRef: string; | ||||
| 
 | ||||
|     constructor(props: IProps) { | ||||
|         super(props); | ||||
|         this.props.notification.on(NOTIFICATION_STATE_UPDATE, this.onNotificationUpdate); | ||||
| 
 | ||||
|         this.state = { | ||||
|             showCounts: SettingsStore.getValue("Notifications.alwaysShowBadgeCounts", this.roomId), | ||||
|         }; | ||||
| 
 | ||||
|         this.countWatcherRef = SettingsStore.watchSetting( | ||||
|             "Notifications.alwaysShowBadgeCounts", this.roomId, | ||||
|             this.countPreferenceChanged, | ||||
|         ); | ||||
|     } | ||||
| 
 | ||||
|     private get roomId(): string { | ||||
|         // We should convert this to null for safety with the SettingsStore
 | ||||
|         return this.props.roomId || null; | ||||
|     } | ||||
| 
 | ||||
|     public componentWillUnmount() { | ||||
|         SettingsStore.unwatchSetting(this.countWatcherRef); | ||||
|     } | ||||
| 
 | ||||
|     public componentDidUpdate(prevProps: Readonly<IProps>) { | ||||
|  | @ -75,24 +103,34 @@ export default class NotificationBadge extends React.PureComponent<IProps, IStat | |||
|         this.props.notification.on(NOTIFICATION_STATE_UPDATE, this.onNotificationUpdate); | ||||
|     } | ||||
| 
 | ||||
|     private countPreferenceChanged = () => { | ||||
|         this.setState({showCounts: SettingsStore.getValue("Notifications.alwaysShowBadgeCounts", this.roomId)}); | ||||
|     }; | ||||
| 
 | ||||
|     private onNotificationUpdate = () => { | ||||
|         this.forceUpdate(); // notification state changed - update
 | ||||
|     }; | ||||
| 
 | ||||
|     public render(): React.ReactElement { | ||||
|         // Don't show a badge if we don't need to
 | ||||
|         if (this.props.notification.color <= NotificationColor.Bold) return null; | ||||
|         if (this.props.notification.color <= NotificationColor.None) return null; | ||||
| 
 | ||||
|         const hasNotif = this.props.notification.color >= NotificationColor.Red; | ||||
|         const hasCount = this.props.notification.color >= NotificationColor.Grey; | ||||
|         const isEmptyBadge = this.props.allowNoCount && !localStorage.getItem("mx_rl_rt_badgeCount"); | ||||
|         const hasUnread = this.props.notification.color >= NotificationColor.Bold; | ||||
|         const couldBeEmpty = !this.state.showCounts || hasUnread; | ||||
|         let isEmptyBadge = couldBeEmpty && (!this.state.showCounts || !hasCount); | ||||
|         if (this.props.forceCount) { | ||||
|             isEmptyBadge = false; | ||||
|             if (!hasCount) return null; // Can't render a badge
 | ||||
|         } | ||||
| 
 | ||||
|         let symbol = this.props.notification.symbol || formatMinimalBadgeCount(this.props.notification.count); | ||||
|         if (isEmptyBadge) symbol = ""; | ||||
| 
 | ||||
|         const classes = classNames({ | ||||
|             'mx_NotificationBadge': true, | ||||
|             'mx_NotificationBadge_visible': hasCount, | ||||
|             'mx_NotificationBadge_visible': isEmptyBadge ? true : hasCount, | ||||
|             'mx_NotificationBadge_highlighted': hasNotif, | ||||
|             'mx_NotificationBadge_dot': isEmptyBadge, | ||||
|             'mx_NotificationBadge_2char': symbol.length > 0 && symbol.length < 3, | ||||
|  |  | |||
|  | @ -267,7 +267,7 @@ export default class RoomSublist2 extends React.Component<IProps, IState> { | |||
| 
 | ||||
|                     // TODO: Collapsed state
 | ||||
| 
 | ||||
|                     const badge = <NotificationBadge allowNoCount={false} notification={this.state.notificationState}/>; | ||||
|                     const badge = <NotificationBadge forceCount={true} notification={this.state.notificationState}/>; | ||||
| 
 | ||||
|                     let addRoomButton = null; | ||||
|                     if (!!this.props.onAddRoom) { | ||||
|  |  | |||
|  | @ -248,7 +248,13 @@ export default class RoomTile2 extends React.Component<IProps, IState> { | |||
|             'mx_RoomTile2_minimized': this.props.isMinimized, | ||||
|         }); | ||||
| 
 | ||||
|         const badge = <NotificationBadge notification={this.state.notificationState} allowNoCount={true} />; | ||||
|         const badge = ( | ||||
|             <NotificationBadge | ||||
|                 notification={this.state.notificationState} | ||||
|                 forceCount={false} | ||||
|                 roomId={this.props.room.roomId} | ||||
|             /> | ||||
|         ); | ||||
| 
 | ||||
|         // TODO: the original RoomTile uses state for the room name. Do we need to?
 | ||||
|         let name = this.props.room.name; | ||||
|  |  | |||
|  | @ -188,6 +188,11 @@ export const SETTINGS = { | |||
|         default: true, | ||||
|         invertedSettingName: 'MessageComposerInput.dontSuggestEmoji', | ||||
|     }, | ||||
|     // TODO: Wire up appropriately to UI (FTUE notifications)
 | ||||
|     "Notifications.alwaysShowBadgeCounts": { | ||||
|         supportedLevels: LEVELS_ROOM_OR_ACCOUNT, | ||||
|         default: false, | ||||
|     }, | ||||
|     "useCompactLayout": { | ||||
|         supportedLevels: LEVELS_ACCOUNT_SETTINGS, | ||||
|         displayName: _td('Use compact timeline layout'), | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	 Travis Ralston
						Travis Ralston