Move and improve notification state handling
Previously we were creating a notification state whenever we needed one, which was leading to hundreds of listeners even on a small account. To ease the burden, and reduce the load of having to wake so many listeners, we now record a single listener for each tag ID and room combination. This commit also introduces a number of utilities to make future notification work a bit of an easier transition, such as the `isX` and `hasX` getters on the new NotificationState abstract class. Similarly, "snapshots" have been added to reduce code duplication between different kinds of states checking for updates. The ListNotificationState is now heavily tied into the store which offers it to help reuse the cache of room notification states. Fixes https://github.com/vector-im/riot-web/issues/14370
This commit is contained in:
parent
ada68c4220
commit
47380306c2
12 changed files with 237 additions and 116 deletions
|
@ -14,23 +14,20 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import { EventEmitter } from "events";
|
||||
import { INotificationState, NOTIFICATION_STATE_UPDATE } from "./INotificationState";
|
||||
import { NotificationColor } from "./NotificationColor";
|
||||
import { IDestroyable } from "../../utils/IDestroyable";
|
||||
import { TagID } from "../room-list/models";
|
||||
import { Room } from "matrix-js-sdk/src/models/room";
|
||||
import { arrayDiff } from "../../utils/arrays";
|
||||
import { RoomNotificationState } from "./RoomNotificationState";
|
||||
import { TagSpecificNotificationState } from "./TagSpecificNotificationState";
|
||||
import { NOTIFICATION_STATE_UPDATE, NotificationState } from "./NotificationState";
|
||||
|
||||
export class ListNotificationState extends EventEmitter implements IDestroyable, INotificationState {
|
||||
private _count: number;
|
||||
private _color: NotificationColor;
|
||||
export type FetchRoomFn = (room: Room) => RoomNotificationState;
|
||||
|
||||
export class ListNotificationState extends NotificationState {
|
||||
private rooms: Room[] = [];
|
||||
private states: { [roomId: string]: RoomNotificationState } = {};
|
||||
|
||||
constructor(private byTileCount = false, private tagId: TagID) {
|
||||
constructor(private byTileCount = false, private tagId: TagID, private getRoomFn: FetchRoomFn) {
|
||||
super();
|
||||
}
|
||||
|
||||
|
@ -38,14 +35,6 @@ export class ListNotificationState extends EventEmitter implements IDestroyable,
|
|||
return null; // This notification state doesn't support symbols
|
||||
}
|
||||
|
||||
public get count(): number {
|
||||
return this._count;
|
||||
}
|
||||
|
||||
public get color(): NotificationColor {
|
||||
return this._color;
|
||||
}
|
||||
|
||||
public setRooms(rooms: Room[]) {
|
||||
// If we're only concerned about the tile count, don't bother setting up listeners.
|
||||
if (this.byTileCount) {
|
||||
|
@ -62,10 +51,9 @@ export class ListNotificationState extends EventEmitter implements IDestroyable,
|
|||
if (!state) continue; // We likely just didn't have a badge (race condition)
|
||||
delete this.states[oldRoom.roomId];
|
||||
state.off(NOTIFICATION_STATE_UPDATE, this.onRoomNotificationStateUpdate);
|
||||
state.destroy();
|
||||
}
|
||||
for (const newRoom of diff.added) {
|
||||
const state = new TagSpecificNotificationState(newRoom, this.tagId);
|
||||
const state = this.getRoomFn(newRoom);
|
||||
state.on(NOTIFICATION_STATE_UPDATE, this.onRoomNotificationStateUpdate);
|
||||
if (this.states[newRoom.roomId]) {
|
||||
// "Should never happen" disclaimer.
|
||||
|
@ -85,8 +73,9 @@ export class ListNotificationState extends EventEmitter implements IDestroyable,
|
|||
}
|
||||
|
||||
public destroy() {
|
||||
super.destroy();
|
||||
for (const state of Object.values(this.states)) {
|
||||
state.destroy();
|
||||
state.off(NOTIFICATION_STATE_UPDATE, this.onRoomNotificationStateUpdate);
|
||||
}
|
||||
this.states = {};
|
||||
}
|
||||
|
@ -96,7 +85,7 @@ export class ListNotificationState extends EventEmitter implements IDestroyable,
|
|||
};
|
||||
|
||||
private calculateTotalState() {
|
||||
const before = {count: this.count, symbol: this.symbol, color: this.color};
|
||||
const snapshot = this.snapshot();
|
||||
|
||||
if (this.byTileCount) {
|
||||
this._color = NotificationColor.Red;
|
||||
|
@ -111,10 +100,7 @@ export class ListNotificationState extends EventEmitter implements IDestroyable,
|
|||
}
|
||||
|
||||
// finally, publish an update if needed
|
||||
const after = {count: this.count, symbol: this.symbol, color: this.color};
|
||||
if (JSON.stringify(before) !== JSON.stringify(after)) {
|
||||
this.emit(NOTIFICATION_STATE_UPDATE);
|
||||
}
|
||||
this.emitIfUpdated(snapshot);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue