Force DMs to always be red notifications

This also passes the tagId to the sublist so it doesn't have to rip it out of the `layout`. It doesn't get a layout until later anyways, which causes some null issues.
This commit is contained in:
Travis Ralston 2020-06-22 14:52:17 -06:00
parent 894357f7f6
commit fb551781c2
4 changed files with 54 additions and 15 deletions

View file

@ -27,6 +27,7 @@ import { EventEmitter } from "events";
import { arrayDiff } from "../../../utils/arrays"; import { arrayDiff } from "../../../utils/arrays";
import { IDestroyable } from "../../../utils/IDestroyable"; import { IDestroyable } from "../../../utils/IDestroyable";
import SettingsStore from "../../../settings/SettingsStore"; import SettingsStore from "../../../settings/SettingsStore";
import { DefaultTagID, TagID } from "../../../stores/room-list/models";
export const NOTIFICATION_STATE_UPDATE = "update"; export const NOTIFICATION_STATE_UPDATE = "update";
@ -139,7 +140,7 @@ export default class NotificationBadge extends React.PureComponent<IProps, IStat
} }
} }
export class RoomNotificationState extends EventEmitter implements IDestroyable { export class RoomNotificationState extends EventEmitter implements IDestroyable, INotificationState {
private _symbol: string; private _symbol: string;
private _count: number; private _count: number;
private _color: NotificationColor; private _color: NotificationColor;
@ -237,13 +238,38 @@ export class RoomNotificationState extends EventEmitter implements IDestroyable
} }
} }
export class ListNotificationState extends EventEmitter implements IDestroyable { export class TagSpecificNotificationState extends RoomNotificationState {
private static TAG_TO_COLOR: {
// @ts-ignore - TS wants this to be a string key, but we know better
[tagId: TagID]: NotificationColor,
} = {
[DefaultTagID.DM]: NotificationColor.Red,
};
private readonly colorWhenNotIdle?: NotificationColor;
constructor(room: Room, tagId: TagID) {
super(room);
const specificColor = TagSpecificNotificationState.TAG_TO_COLOR[tagId];
if (specificColor) this.colorWhenNotIdle = specificColor;
}
public get color(): NotificationColor {
if (!this.colorWhenNotIdle) return super.color;
if (super.color !== NotificationColor.None) return this.colorWhenNotIdle;
return super.color;
}
}
export class ListNotificationState extends EventEmitter implements IDestroyable, INotificationState {
private _count: number; private _count: number;
private _color: NotificationColor; private _color: NotificationColor;
private rooms: Room[] = []; private rooms: Room[] = [];
private states: { [roomId: string]: RoomNotificationState } = {}; private states: { [roomId: string]: RoomNotificationState } = {};
constructor(private byTileCount = false) { constructor(private byTileCount = false, private tagId: TagID) {
super(); super();
} }
@ -278,7 +304,7 @@ export class ListNotificationState extends EventEmitter implements IDestroyable
state.destroy(); state.destroy();
} }
for (const newRoom of diff.added) { for (const newRoom of diff.added) {
const state = new RoomNotificationState(newRoom); const state = new TagSpecificNotificationState(newRoom, this.tagId);
state.on(NOTIFICATION_STATE_UPDATE, this.onRoomNotificationStateUpdate); state.on(NOTIFICATION_STATE_UPDATE, this.onRoomNotificationStateUpdate);
if (this.states[newRoom.roomId]) { if (this.states[newRoom.roomId]) {
// "Should never happen" disclaimer. // "Should never happen" disclaimer.
@ -291,6 +317,12 @@ export class ListNotificationState extends EventEmitter implements IDestroyable
this.calculateTotalState(); this.calculateTotalState();
} }
public getForRoom(room: Room) {
const state = this.states[room.roomId];
if (!state) throw new Error("Unknown room for notification state");
return state;
}
public destroy() { public destroy() {
for (const state of Object.values(this.states)) { for (const state of Object.values(this.states)) {
state.destroy(); state.destroy();

View file

@ -193,6 +193,7 @@ export default class RoomList2 extends React.Component<IProps, IState> {
components.push( components.push(
<RoomSublist2 <RoomSublist2
key={`sublist-${orderedTagId}`} key={`sublist-${orderedTagId}`}
tagId={orderedTagId}
forRooms={true} forRooms={true}
rooms={orderedRooms} rooms={orderedRooms}
startAsHidden={aesthetics.defaultHidden} startAsHidden={aesthetics.defaultHidden}

View file

@ -32,6 +32,7 @@ import StyledCheckbox from "../elements/StyledCheckbox";
import StyledRadioButton from "../elements/StyledRadioButton"; import StyledRadioButton from "../elements/StyledRadioButton";
import RoomListStore from "../../../stores/room-list/RoomListStore2"; import RoomListStore from "../../../stores/room-list/RoomListStore2";
import { ListAlgorithm, SortAlgorithm } from "../../../stores/room-list/algorithms/models"; import { ListAlgorithm, SortAlgorithm } from "../../../stores/room-list/algorithms/models";
import { TagID } from "../../../stores/room-list/models";
/******************************************************************* /*******************************************************************
* CAUTION * * CAUTION *
@ -56,6 +57,7 @@ interface IProps {
isInvite: boolean; isInvite: boolean;
layout: ListLayout; layout: ListLayout;
isMinimized: boolean; isMinimized: boolean;
tagId: TagID;
// TODO: Collapsed state // TODO: Collapsed state
// TODO: Group invites // TODO: Group invites
@ -78,7 +80,7 @@ export default class RoomSublist2 extends React.Component<IProps, IState> {
super(props); super(props);
this.state = { this.state = {
notificationState: new ListNotificationState(this.props.isInvite), notificationState: new ListNotificationState(this.props.isInvite, this.props.tagId),
menuDisplayed: false, menuDisplayed: false,
}; };
this.state.notificationState.setRooms(this.props.rooms); this.state.notificationState.setRooms(this.props.rooms);
@ -130,13 +132,13 @@ export default class RoomSublist2 extends React.Component<IProps, IState> {
}; };
private onUnreadFirstChanged = async () => { private onUnreadFirstChanged = async () => {
const isUnreadFirst = RoomListStore.instance.getListOrder(this.props.layout.tagId) === ListAlgorithm.Importance; const isUnreadFirst = RoomListStore.instance.getListOrder(this.props.tagId) === ListAlgorithm.Importance;
const newAlgorithm = isUnreadFirst ? ListAlgorithm.Natural : ListAlgorithm.Importance; const newAlgorithm = isUnreadFirst ? ListAlgorithm.Natural : ListAlgorithm.Importance;
await RoomListStore.instance.setListOrder(this.props.layout.tagId, newAlgorithm); await RoomListStore.instance.setListOrder(this.props.tagId, newAlgorithm);
}; };
private onTagSortChanged = async (sort: SortAlgorithm) => { private onTagSortChanged = async (sort: SortAlgorithm) => {
await RoomListStore.instance.setTagSorting(this.props.layout.tagId, sort); await RoomListStore.instance.setTagSorting(this.props.tagId, sort);
}; };
private onMessagePreviewChanged = () => { private onMessagePreviewChanged = () => {
@ -176,7 +178,7 @@ export default class RoomSublist2 extends React.Component<IProps, IState> {
key={`room-${room.roomId}`} key={`room-${room.roomId}`}
showMessagePreview={this.props.layout.showPreviews} showMessagePreview={this.props.layout.showPreviews}
isMinimized={this.props.isMinimized} isMinimized={this.props.isMinimized}
tag={this.props.layout.tagId} tag={this.props.tagId}
/> />
); );
} }
@ -189,8 +191,8 @@ export default class RoomSublist2 extends React.Component<IProps, IState> {
let contextMenu = null; let contextMenu = null;
if (this.state.menuDisplayed) { if (this.state.menuDisplayed) {
const elementRect = this.menuButtonRef.current.getBoundingClientRect(); const elementRect = this.menuButtonRef.current.getBoundingClientRect();
const isAlphabetical = RoomListStore.instance.getTagSorting(this.props.layout.tagId) === SortAlgorithm.Alphabetic; const isAlphabetical = RoomListStore.instance.getTagSorting(this.props.tagId) === SortAlgorithm.Alphabetic;
const isUnreadFirst = RoomListStore.instance.getListOrder(this.props.layout.tagId) === ListAlgorithm.Importance; const isUnreadFirst = RoomListStore.instance.getListOrder(this.props.tagId) === ListAlgorithm.Importance;
contextMenu = ( contextMenu = (
<ContextMenu <ContextMenu
chevronFace="none" chevronFace="none"
@ -204,14 +206,14 @@ export default class RoomSublist2 extends React.Component<IProps, IState> {
<StyledRadioButton <StyledRadioButton
onChange={() => this.onTagSortChanged(SortAlgorithm.Recent)} onChange={() => this.onTagSortChanged(SortAlgorithm.Recent)}
checked={!isAlphabetical} checked={!isAlphabetical}
name={`mx_${this.props.layout.tagId}_sortBy`} name={`mx_${this.props.tagId}_sortBy`}
> >
{_t("Activity")} {_t("Activity")}
</StyledRadioButton> </StyledRadioButton>
<StyledRadioButton <StyledRadioButton
onChange={() => this.onTagSortChanged(SortAlgorithm.Alphabetic)} onChange={() => this.onTagSortChanged(SortAlgorithm.Alphabetic)}
checked={isAlphabetical} checked={isAlphabetical}
name={`mx_${this.props.layout.tagId}_sortBy`} name={`mx_${this.props.tagId}_sortBy`}
> >
{_t("A-Z")} {_t("A-Z")}
</StyledRadioButton> </StyledRadioButton>

View file

@ -26,7 +26,11 @@ import RoomAvatar from "../../views/avatars/RoomAvatar";
import dis from '../../../dispatcher/dispatcher'; import dis from '../../../dispatcher/dispatcher';
import { Key } from "../../../Keyboard"; import { Key } from "../../../Keyboard";
import ActiveRoomObserver from "../../../ActiveRoomObserver"; import ActiveRoomObserver from "../../../ActiveRoomObserver";
import NotificationBadge, { INotificationState, NotificationColor, RoomNotificationState } from "./NotificationBadge"; import NotificationBadge, {
INotificationState,
NotificationColor,
TagSpecificNotificationState
} from "./NotificationBadge";
import { _t } from "../../../languageHandler"; import { _t } from "../../../languageHandler";
import { ContextMenu, ContextMenuButton } from "../../structures/ContextMenu"; import { ContextMenu, ContextMenuButton } from "../../structures/ContextMenu";
import { DefaultTagID, TagID } from "../../../stores/room-list/models"; import { DefaultTagID, TagID } from "../../../stores/room-list/models";
@ -79,7 +83,7 @@ export default class RoomTile2 extends React.Component<IProps, IState> {
this.state = { this.state = {
hover: false, hover: false,
notificationState: new RoomNotificationState(this.props.room), notificationState: new TagSpecificNotificationState(this.props.room, this.props.tag),
selected: ActiveRoomObserver.activeRoomId === this.props.room.roomId, selected: ActiveRoomObserver.activeRoomId === this.props.room.roomId,
generalMenuDisplayed: false, generalMenuDisplayed: false,
}; };