From 2d9982f9f087de4010f6984fb5a2958942332d3a Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Fri, 1 Nov 2024 15:15:04 +0000 Subject: [PATCH] Remove boilerplate around dispatcher and settings watchers (#28338) * Remove boilerplate around dispatcher and settings watchers Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Iterate Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Iterate Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --------- Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- src/DeviceListener.ts | 10 +++------- src/PosthogAnalytics.ts | 2 +- src/Presence.ts | 20 ++++++++----------- src/components/structures/EmbeddedPage.tsx | 4 ++-- src/components/structures/LoggedInView.tsx | 6 +++--- src/components/structures/ThreadView.tsx | 4 ++-- src/components/structures/UserMenu.tsx | 6 +++--- .../views/dialogs/RoomSettingsDialog.tsx | 4 +--- src/components/views/elements/AppTile.tsx | 4 ++-- .../views/messages/DateSeparator.tsx | 2 +- src/components/views/messages/MImageBody.tsx | 2 +- src/components/views/messages/MVideoBody.tsx | 2 +- .../views/right_panel/TimelineCard.tsx | 10 +++------- src/components/views/rooms/AppsDrawer.tsx | 2 +- .../views/rooms/MessageComposer.tsx | 2 +- src/components/views/rooms/RoomList.tsx | 2 +- src/components/views/rooms/RoomSublist.tsx | 2 +- src/components/views/rooms/RoomTile.tsx | 2 +- src/components/views/rooms/Stickerpicker.tsx | 4 +--- .../views/settings/FontScalingPanel.tsx | 4 +--- .../views/settings/IntegrationManager.tsx | 2 +- src/components/views/settings/SetIdServer.tsx | 2 +- .../tabs/user/SecurityUserSettingsTab.tsx | 2 +- src/components/views/voip/LegacyCallView.tsx | 2 +- src/dispatcher/dispatcher.ts | 5 ++++- src/mjolnir/Mjolnir.ts | 18 +++++++---------- src/models/Call.ts | 14 +++++-------- src/settings/SettingsStore.ts | 7 ++++--- src/settings/watchers/FontWatcher.ts | 7 +------ src/settings/watchers/ThemeWatcher.ts | 16 ++++++--------- src/stores/AsyncStore.ts | 2 +- src/stores/AsyncStoreWithClient.ts | 2 +- src/stores/OwnBeaconStore.ts | 2 +- src/stores/ReadyWatchingStore.ts | 10 +++++----- src/stores/widgets/WidgetLayoutStore.ts | 6 +++--- test/unit-tests/DeviceListener-test.ts | 1 + 36 files changed, 81 insertions(+), 111 deletions(-) diff --git a/src/DeviceListener.ts b/src/DeviceListener.ts index 3cf153fc58..02e26729d2 100644 --- a/src/DeviceListener.ts +++ b/src/DeviceListener.ts @@ -113,13 +113,9 @@ export default class DeviceListener { this.client.removeListener(ClientEvent.Sync, this.onSync); this.client.removeListener(RoomStateEvent.Events, this.onRoomStateEvents); } - if (this.deviceClientInformationSettingWatcherRef) { - SettingsStore.unwatchSetting(this.deviceClientInformationSettingWatcherRef); - } - if (this.dispatcherRef) { - dis.unregister(this.dispatcherRef); - this.dispatcherRef = undefined; - } + SettingsStore.unwatchSetting(this.deviceClientInformationSettingWatcherRef); + dis.unregister(this.dispatcherRef); + this.dispatcherRef = undefined; this.dismissed.clear(); this.dismissedThisDeviceToast = false; this.keyBackupInfo = null; diff --git a/src/PosthogAnalytics.ts b/src/PosthogAnalytics.ts index 2ffe8b8166..6217d9b7dd 100644 --- a/src/PosthogAnalytics.ts +++ b/src/PosthogAnalytics.ts @@ -326,7 +326,7 @@ export class PosthogAnalytics { if (this.enabled) { this.posthog.reset(); } - if (this.watchSettingRef) SettingsStore.unwatchSetting(this.watchSettingRef); + SettingsStore.unwatchSetting(this.watchSettingRef); this.setAnonymity(Anonymity.Disabled); } diff --git a/src/Presence.ts b/src/Presence.ts index 11a333ce04..af06d4a1d6 100644 --- a/src/Presence.ts +++ b/src/Presence.ts @@ -20,9 +20,9 @@ import { ActionPayload } from "./dispatcher/payloads"; const UNAVAILABLE_TIME_MS = 3 * 60 * 1000; // 3 mins class Presence { - private unavailableTimer: Timer | null = null; - private dispatcherRef: string | null = null; - private state: SetPresence | null = null; + private unavailableTimer?: Timer; + private dispatcherRef?: string; + private state?: SetPresence; /** * Start listening the user activity to evaluate his presence state. @@ -46,14 +46,10 @@ class Presence { * Stop tracking user activity */ public stop(): void { - if (this.dispatcherRef) { - dis.unregister(this.dispatcherRef); - this.dispatcherRef = null; - } - if (this.unavailableTimer) { - this.unavailableTimer.abort(); - this.unavailableTimer = null; - } + dis.unregister(this.dispatcherRef); + this.dispatcherRef = undefined; + this.unavailableTimer?.abort(); + this.unavailableTimer = undefined; } /** @@ -61,7 +57,7 @@ class Presence { * @returns {string} the presence state (see PRESENCE enum) */ public getState(): SetPresence | null { - return this.state; + return this.state ?? null; } private onAction = (payload: ActionPayload): void => { diff --git a/src/components/structures/EmbeddedPage.tsx b/src/components/structures/EmbeddedPage.tsx index 5de1261ecb..5c7e81caf5 100644 --- a/src/components/structures/EmbeddedPage.tsx +++ b/src/components/structures/EmbeddedPage.tsx @@ -38,7 +38,7 @@ export default class EmbeddedPage extends React.PureComponent { public static contextType = MatrixClientContext; public declare context: React.ContextType; private unmounted = false; - private dispatcherRef: string | null = null; + private dispatcherRef?: string; public constructor(props: IProps, context: React.ContextType) { super(props, context); @@ -100,7 +100,7 @@ export default class EmbeddedPage extends React.PureComponent { public componentWillUnmount(): void { this.unmounted = true; - if (this.dispatcherRef !== null) dis.unregister(this.dispatcherRef); + dis.unregister(this.dispatcherRef); } private onAction = (payload: ActionPayload): void => { diff --git a/src/components/structures/LoggedInView.tsx b/src/components/structures/LoggedInView.tsx index 84c43fc19d..75156cdf60 100644 --- a/src/components/structures/LoggedInView.tsx +++ b/src/components/structures/LoggedInView.tsx @@ -228,9 +228,9 @@ class LoggedInView extends React.Component { this._matrixClient.removeListener(ClientEvent.Sync, this.onSync); this._matrixClient.removeListener(RoomStateEvent.Events, this.onRoomStateEvents); OwnProfileStore.instance.off(UPDATE_EVENT, this.refreshBackgroundImage); - if (this.layoutWatcherRef) SettingsStore.unwatchSetting(this.layoutWatcherRef); - if (this.compactLayoutWatcherRef) SettingsStore.unwatchSetting(this.compactLayoutWatcherRef); - if (this.backgroundImageWatcherRef) SettingsStore.unwatchSetting(this.backgroundImageWatcherRef); + SettingsStore.unwatchSetting(this.layoutWatcherRef); + SettingsStore.unwatchSetting(this.compactLayoutWatcherRef); + SettingsStore.unwatchSetting(this.backgroundImageWatcherRef); this.timezoneProfileUpdateRef?.forEach((s) => SettingsStore.unwatchSetting(s)); this.resizer?.detach(); } diff --git a/src/components/structures/ThreadView.tsx b/src/components/structures/ThreadView.tsx index e5c1ccb266..8d2a286de1 100644 --- a/src/components/structures/ThreadView.tsx +++ b/src/components/structures/ThreadView.tsx @@ -77,7 +77,7 @@ export default class ThreadView extends React.Component { public static contextType = RoomContext; public declare context: React.ContextType; - private dispatcherRef: string | null = null; + private dispatcherRef?: string; private readonly layoutWatcherRef: string; private timelinePanel = createRef(); private card = createRef(); @@ -118,7 +118,7 @@ export default class ThreadView extends React.Component { } public componentWillUnmount(): void { - if (this.dispatcherRef) dis.unregister(this.dispatcherRef); + dis.unregister(this.dispatcherRef); const roomId = this.props.mxEvent.getRoomId(); SettingsStore.unwatchSetting(this.layoutWatcherRef); diff --git a/src/components/structures/UserMenu.tsx b/src/components/structures/UserMenu.tsx index 971e07193b..84bd93cc36 100644 --- a/src/components/structures/UserMenu.tsx +++ b/src/components/structures/UserMenu.tsx @@ -121,9 +121,9 @@ export default class UserMenu extends React.Component { } public componentWillUnmount(): void { - if (this.themeWatcherRef) SettingsStore.unwatchSetting(this.themeWatcherRef); - if (this.dndWatcherRef) SettingsStore.unwatchSetting(this.dndWatcherRef); - if (this.dispatcherRef) defaultDispatcher.unregister(this.dispatcherRef); + SettingsStore.unwatchSetting(this.themeWatcherRef); + SettingsStore.unwatchSetting(this.dndWatcherRef); + defaultDispatcher.unregister(this.dispatcherRef); OwnProfileStore.instance.off(UPDATE_EVENT, this.onProfileUpdate); SpaceStore.instance.off(UPDATE_SELECTED_SPACE, this.onSelectedSpaceUpdate); this.context.voiceBroadcastRecordingsStore.off( diff --git a/src/components/views/dialogs/RoomSettingsDialog.tsx b/src/components/views/dialogs/RoomSettingsDialog.tsx index 2c4656745a..cb804b8e00 100644 --- a/src/components/views/dialogs/RoomSettingsDialog.tsx +++ b/src/components/views/dialogs/RoomSettingsDialog.tsx @@ -80,9 +80,7 @@ class RoomSettingsDialog extends React.Component { } public componentWillUnmount(): void { - if (this.dispatcherRef) { - dis.unregister(this.dispatcherRef); - } + dis.unregister(this.dispatcherRef); MatrixClientPeg.get()?.removeListener(RoomEvent.Name, this.onRoomName); MatrixClientPeg.get()?.removeListener(RoomStateEvent.Events, this.onStateEvent); diff --git a/src/components/views/elements/AppTile.tsx b/src/components/views/elements/AppTile.tsx index 4803ac5272..8f5aa732be 100644 --- a/src/components/views/elements/AppTile.tsx +++ b/src/components/views/elements/AppTile.tsx @@ -340,13 +340,13 @@ export default class AppTile extends React.Component { } // Widget action listeners - if (this.dispatcherRef) dis.unregister(this.dispatcherRef); + dis.unregister(this.dispatcherRef); if (this.props.room) { this.context.off(RoomEvent.MyMembership, this.onMyMembership); } - if (this.allowedWidgetsWatchRef) SettingsStore.unwatchSetting(this.allowedWidgetsWatchRef); + SettingsStore.unwatchSetting(this.allowedWidgetsWatchRef); OwnProfileStore.instance.removeListener(UPDATE_EVENT, this.onUserReady); } diff --git a/src/components/views/messages/DateSeparator.tsx b/src/components/views/messages/DateSeparator.tsx index 10ec7ddad9..7996b3bebe 100644 --- a/src/components/views/messages/DateSeparator.tsx +++ b/src/components/views/messages/DateSeparator.tsx @@ -71,7 +71,7 @@ export default class DateSeparator extends React.Component { } public componentWillUnmount(): void { - if (this.settingWatcherRef) SettingsStore.unwatchSetting(this.settingWatcherRef); + SettingsStore.unwatchSetting(this.settingWatcherRef); } private onContextMenuOpenClick = (e: ButtonEvent): void => { diff --git a/src/components/views/messages/MImageBody.tsx b/src/components/views/messages/MImageBody.tsx index 5c7a553364..332777be5e 100644 --- a/src/components/views/messages/MImageBody.tsx +++ b/src/components/views/messages/MImageBody.tsx @@ -368,7 +368,7 @@ export default class MImageBody extends React.Component { this.unmounted = true; MatrixClientPeg.get()?.off(ClientEvent.Sync, this.reconnectedListener); this.clearBlurhashTimeout(); - if (this.sizeWatcher) SettingsStore.unwatchSetting(this.sizeWatcher); + SettingsStore.unwatchSetting(this.sizeWatcher); if (this.state.isAnimated && this.state.thumbUrl) { URL.revokeObjectURL(this.state.thumbUrl); } diff --git a/src/components/views/messages/MVideoBody.tsx b/src/components/views/messages/MVideoBody.tsx index 4900432b8c..4036b9ddec 100644 --- a/src/components/views/messages/MVideoBody.tsx +++ b/src/components/views/messages/MVideoBody.tsx @@ -175,7 +175,7 @@ export default class MVideoBody extends React.PureComponent } public componentWillUnmount(): void { - if (this.sizeWatcher) SettingsStore.unwatchSetting(this.sizeWatcher); + SettingsStore.unwatchSetting(this.sizeWatcher); } private videoOnPlay = async (): Promise => { diff --git a/src/components/views/right_panel/TimelineCard.tsx b/src/components/views/right_panel/TimelineCard.tsx index 4f9d1dd917..e0988eeaa5 100644 --- a/src/components/views/right_panel/TimelineCard.tsx +++ b/src/components/views/right_panel/TimelineCard.tsx @@ -100,14 +100,10 @@ export default class TimelineCard extends React.Component { public componentWillUnmount(): void { SdkContextClass.instance.roomViewStore.removeListener(UPDATE_EVENT, this.onRoomViewStoreUpdate); - if (this.readReceiptsSettingWatcher) { - SettingsStore.unwatchSetting(this.readReceiptsSettingWatcher); - } - if (this.layoutWatcherRef) { - SettingsStore.unwatchSetting(this.layoutWatcherRef); - } + SettingsStore.unwatchSetting(this.readReceiptsSettingWatcher); + SettingsStore.unwatchSetting(this.layoutWatcherRef); - if (this.dispatcherRef) dis.unregister(this.dispatcherRef); + dis.unregister(this.dispatcherRef); } private onRoomViewStoreUpdate = async (_initial?: boolean): Promise => { diff --git a/src/components/views/rooms/AppsDrawer.tsx b/src/components/views/rooms/AppsDrawer.tsx index cba6e6c691..1d768cae35 100644 --- a/src/components/views/rooms/AppsDrawer.tsx +++ b/src/components/views/rooms/AppsDrawer.tsx @@ -82,7 +82,7 @@ export default class AppsDrawer extends React.Component { this.unmounted = true; ScalarMessaging.stopListening(); WidgetLayoutStore.instance.off(WidgetLayoutStore.emissionForRoom(this.props.room), this.updateApps); - if (this.dispatcherRef) dis.unregister(this.dispatcherRef); + dis.unregister(this.dispatcherRef); if (this.resizeContainer) { this.resizer.detach(); } diff --git a/src/components/views/rooms/MessageComposer.tsx b/src/components/views/rooms/MessageComposer.tsx index e44265b947..c8d1573ebc 100644 --- a/src/components/views/rooms/MessageComposer.tsx +++ b/src/components/views/rooms/MessageComposer.tsx @@ -331,7 +331,7 @@ export class MessageComposer extends React.Component { public componentWillUnmount(): void { VoiceRecordingStore.instance.off(UPDATE_EVENT, this.onVoiceStoreUpdate); - if (this.dispatcherRef) dis.unregister(this.dispatcherRef); + dis.unregister(this.dispatcherRef); UIStore.instance.stopTrackingElementDimensions(`MessageComposer${this.instanceId}`); UIStore.instance.removeListener(`MessageComposer${this.instanceId}`, this.onResize); diff --git a/src/components/views/rooms/RoomList.tsx b/src/components/views/rooms/RoomList.tsx index e27b2ca03f..853bebc4fe 100644 --- a/src/components/views/rooms/RoomList.tsx +++ b/src/components/views/rooms/RoomList.tsx @@ -446,7 +446,7 @@ export default class RoomList extends React.PureComponent { public componentWillUnmount(): void { SpaceStore.instance.off(UPDATE_SUGGESTED_ROOMS, this.updateSuggestedRooms); RoomListStore.instance.off(LISTS_UPDATE_EVENT, this.updateLists); - if (this.dispatcherRef) defaultDispatcher.unregister(this.dispatcherRef); + defaultDispatcher.unregister(this.dispatcherRef); SdkContextClass.instance.roomViewStore.off(UPDATE_EVENT, this.onRoomViewStoreUpdate); } diff --git a/src/components/views/rooms/RoomSublist.tsx b/src/components/views/rooms/RoomSublist.tsx index 12f6e70d31..34961c0853 100644 --- a/src/components/views/rooms/RoomSublist.tsx +++ b/src/components/views/rooms/RoomSublist.tsx @@ -248,7 +248,7 @@ export default class RoomSublist extends React.Component { } public componentWillUnmount(): void { - if (this.dispatcherRef) defaultDispatcher.unregister(this.dispatcherRef); + defaultDispatcher.unregister(this.dispatcherRef); RoomListStore.instance.off(LISTS_UPDATE_EVENT, this.onListsUpdated); RoomListStore.instance.off(LISTS_LOADING_EVENT, this.onListsLoading); this.tilesRef.current?.removeEventListener("scroll", this.onScrollPrevent); diff --git a/src/components/views/rooms/RoomTile.tsx b/src/components/views/rooms/RoomTile.tsx index 93fb42f447..de14808f33 100644 --- a/src/components/views/rooms/RoomTile.tsx +++ b/src/components/views/rooms/RoomTile.tsx @@ -175,7 +175,7 @@ export class RoomTile extends React.PureComponent { this.onRoomPreviewChanged, ); this.props.room.off(RoomEvent.Name, this.onRoomNameUpdate); - if (this.dispatcherRef) defaultDispatcher.unregister(this.dispatcherRef); + defaultDispatcher.unregister(this.dispatcherRef); this.notificationState.off(NotificationStateEvents.Update, this.onNotificationUpdate); this.roomProps.off(PROPERTY_UPDATED, this.onRoomPropertyUpdate); CallStore.instance.off(CallStoreEvent.Call, this.onCallChanged); diff --git a/src/components/views/rooms/Stickerpicker.tsx b/src/components/views/rooms/Stickerpicker.tsx index 6793f90159..ad1b11f368 100644 --- a/src/components/views/rooms/Stickerpicker.tsx +++ b/src/components/views/rooms/Stickerpicker.tsx @@ -141,9 +141,7 @@ export default class Stickerpicker extends React.PureComponent { if (client) client.removeListener(ClientEvent.AccountData, this.updateWidget); RightPanelStore.instance.off(UPDATE_EVENT, this.onRightPanelStoreUpdate); window.removeEventListener("resize", this.onResize); - if (this.dispatcherRef) { - dis.unregister(this.dispatcherRef); - } + dis.unregister(this.dispatcherRef); } public componentDidUpdate(): void { diff --git a/src/components/views/settings/FontScalingPanel.tsx b/src/components/views/settings/FontScalingPanel.tsx index 5cdd9d16bb..f6dedb3ffb 100644 --- a/src/components/views/settings/FontScalingPanel.tsx +++ b/src/components/views/settings/FontScalingPanel.tsx @@ -79,9 +79,7 @@ export default class FontScalingPanel extends React.Component { public componentWillUnmount(): void { this.unmounted = true; - if (this.layoutWatcherRef) { - SettingsStore.unwatchSetting(this.layoutWatcherRef); - } + SettingsStore.unwatchSetting(this.layoutWatcherRef); } /** diff --git a/src/components/views/settings/IntegrationManager.tsx b/src/components/views/settings/IntegrationManager.tsx index 91b3b4633f..3a31a9e9c8 100644 --- a/src/components/views/settings/IntegrationManager.tsx +++ b/src/components/views/settings/IntegrationManager.tsx @@ -52,7 +52,7 @@ export default class IntegrationManager extends React.Component } public componentWillUnmount(): void { - if (this.dispatcherRef) dis.unregister(this.dispatcherRef); + dis.unregister(this.dispatcherRef); document.removeEventListener("keydown", this.onKeyDown); } diff --git a/src/components/views/settings/SetIdServer.tsx b/src/components/views/settings/SetIdServer.tsx index e7a55f1133..8ed6461d0a 100644 --- a/src/components/views/settings/SetIdServer.tsx +++ b/src/components/views/settings/SetIdServer.tsx @@ -101,7 +101,7 @@ export default class SetIdServer extends React.Component { } public componentWillUnmount(): void { - if (this.dispatcherRef) dis.unregister(this.dispatcherRef); + dis.unregister(this.dispatcherRef); } private onAction = (payload: ActionPayload): void => { diff --git a/src/components/views/settings/tabs/user/SecurityUserSettingsTab.tsx b/src/components/views/settings/tabs/user/SecurityUserSettingsTab.tsx index 9e15df6e92..ba4b5eb54b 100644 --- a/src/components/views/settings/tabs/user/SecurityUserSettingsTab.tsx +++ b/src/components/views/settings/tabs/user/SecurityUserSettingsTab.tsx @@ -129,7 +129,7 @@ export default class SecurityUserSettingsTab extends React.Component { document.removeEventListener("keydown", this.onNativeKeyDown); this.updateCallListeners(this.props.call, null); - if (this.dispatcherRef) dis.unregister(this.dispatcherRef); + dis.unregister(this.dispatcherRef); } public static getDerivedStateFromProps(props: IProps): Partial { diff --git a/src/dispatcher/dispatcher.ts b/src/dispatcher/dispatcher.ts index 6d8d3a15a8..0c28de0e2b 100644 --- a/src/dispatcher/dispatcher.ts +++ b/src/dispatcher/dispatcher.ts @@ -45,8 +45,11 @@ export class MatrixDispatcher { /** * Removes a callback based on its token. + * @param id The token that was returned by `register`. + * Can be undefined to avoid needing an if around every caller. */ - public unregister(id: DispatchToken): void { + public unregister(id: DispatchToken | undefined): void { + if (!id) return; invariant(this.callbacks.has(id), `Dispatcher.unregister(...): '${id}' does not map to a registered callback.`); this.callbacks.delete(id); } diff --git a/src/mjolnir/Mjolnir.ts b/src/mjolnir/Mjolnir.ts index 8c9d939908..9dacc0d41f 100644 --- a/src/mjolnir/Mjolnir.ts +++ b/src/mjolnir/Mjolnir.ts @@ -22,12 +22,12 @@ import { Action } from "../dispatcher/actions"; // TODO: Move this and related files to the js-sdk or something once finalized. export class Mjolnir { - private static instance: Mjolnir | null = null; + private static instance?: Mjolnir; private _lists: BanList[] = []; // eslint-disable-line @typescript-eslint/naming-convention private _roomIds: string[] = []; // eslint-disable-line @typescript-eslint/naming-convention - private mjolnirWatchRef: string | null = null; - private dispatcherRef: string | null = null; + private mjolnirWatchRef?: string; + private dispatcherRef?: string; public get roomIds(): string[] { return this._roomIds; @@ -61,15 +61,11 @@ export class Mjolnir { } public stop(): void { - if (this.mjolnirWatchRef) { - SettingsStore.unwatchSetting(this.mjolnirWatchRef); - this.mjolnirWatchRef = null; - } + SettingsStore.unwatchSetting(this.mjolnirWatchRef); + this.mjolnirWatchRef = undefined; - if (this.dispatcherRef) { - dis.unregister(this.dispatcherRef); - this.dispatcherRef = null; - } + dis.unregister(this.dispatcherRef); + this.dispatcherRef = undefined; MatrixClientPeg.get()?.removeListener(RoomStateEvent.Events, this.onEvent); } diff --git a/src/models/Call.ts b/src/models/Call.ts index 0238d15914..4beb5fccc1 100644 --- a/src/models/Call.ts +++ b/src/models/Call.ts @@ -643,8 +643,8 @@ export class ElementCall extends Call { public static readonly MEMBER_EVENT_TYPE = new NamespacedValue(null, EventType.GroupCallMemberPrefix); public readonly STUCK_DEVICE_TIMEOUT_MS = 1000 * 60 * 60; // 1 hour - private settingsStoreCallEncryptionWatcher: string | null = null; - private terminationTimer: number | null = null; + private settingsStoreCallEncryptionWatcher?: string; + private terminationTimer?: number; private _layout = Layout.Tile; public get layout(): Layout { return this._layout; @@ -938,13 +938,9 @@ export class ElementCall extends Call { this.session.off(MatrixRTCSessionEvent.MembershipsChanged, this.onMembershipChanged); this.client.matrixRTC.off(MatrixRTCSessionManagerEvents.SessionEnded, this.onRTCSessionEnded); - if (this.settingsStoreCallEncryptionWatcher) { - SettingsStore.unwatchSetting(this.settingsStoreCallEncryptionWatcher); - } - if (this.terminationTimer !== null) { - clearTimeout(this.terminationTimer); - this.terminationTimer = null; - } + SettingsStore.unwatchSetting(this.settingsStoreCallEncryptionWatcher); + clearTimeout(this.terminationTimer); + this.terminationTimer = undefined; super.destroy(); } diff --git a/src/settings/SettingsStore.ts b/src/settings/SettingsStore.ts index 45ba4e3dbb..98ae347a0a 100644 --- a/src/settings/SettingsStore.ts +++ b/src/settings/SettingsStore.ts @@ -192,10 +192,11 @@ export default class SettingsStore { /** * Stops the SettingsStore from watching a setting. This is a no-op if the watcher * provided is not found. - * @param {string} watcherReference The watcher reference (received from #watchSetting) - * to cancel. + * @param watcherReference The watcher reference (received from #watchSetting) to cancel. + * Can be undefined to avoid needing an if around every caller. */ - public static unwatchSetting(watcherReference: string): void { + public static unwatchSetting(watcherReference: string | undefined): void { + if (!watcherReference) return; if (!SettingsStore.watchers.has(watcherReference)) { logger.warn(`Ending non-existent watcher ID ${watcherReference}`); return; diff --git a/src/settings/watchers/FontWatcher.ts b/src/settings/watchers/FontWatcher.ts index 0c7e596530..64a6a27f58 100644 --- a/src/settings/watchers/FontWatcher.ts +++ b/src/settings/watchers/FontWatcher.ts @@ -28,11 +28,7 @@ export class FontWatcher implements IWatcher { */ public static readonly DEFAULT_DELTA = 0; - private dispatcherRef: string | null; - - public constructor() { - this.dispatcherRef = null; - } + private dispatcherRef?: string; public async start(): Promise { this.updateFont(); @@ -148,7 +144,6 @@ export class FontWatcher implements IWatcher { } public stop(): void { - if (!this.dispatcherRef) return; dis.unregister(this.dispatcherRef); } diff --git a/src/settings/watchers/ThemeWatcher.ts b/src/settings/watchers/ThemeWatcher.ts index 74a3158c62..d0f00c52d9 100644 --- a/src/settings/watchers/ThemeWatcher.ts +++ b/src/settings/watchers/ThemeWatcher.ts @@ -18,9 +18,9 @@ import { ActionPayload } from "../../dispatcher/payloads"; import { SettingLevel } from "../SettingLevel"; export default class ThemeWatcher { - private themeWatchRef: string | null; - private systemThemeWatchRef: string | null; - private dispatcherRef: string | null; + private themeWatchRef?: string; + private systemThemeWatchRef?: string; + private dispatcherRef?: string; private preferDark: MediaQueryList; private preferLight: MediaQueryList; @@ -29,10 +29,6 @@ export default class ThemeWatcher { private currentTheme: string; public constructor() { - this.themeWatchRef = null; - this.systemThemeWatchRef = null; - this.dispatcherRef = null; - // we have both here as each may either match or not match, so by having both // we can get the tristate of dark/light/unsupported this.preferDark = (global).matchMedia("(prefers-color-scheme: dark)"); @@ -55,9 +51,9 @@ export default class ThemeWatcher { this.preferDark.removeEventListener("change", this.onChange); this.preferLight.removeEventListener("change", this.onChange); this.preferHighContrast.removeEventListener("change", this.onChange); - if (this.systemThemeWatchRef) SettingsStore.unwatchSetting(this.systemThemeWatchRef); - if (this.themeWatchRef) SettingsStore.unwatchSetting(this.themeWatchRef); - if (this.dispatcherRef) dis.unregister(this.dispatcherRef); + SettingsStore.unwatchSetting(this.systemThemeWatchRef); + SettingsStore.unwatchSetting(this.themeWatchRef); + dis.unregister(this.dispatcherRef); } private onChange = (): void => { diff --git a/src/stores/AsyncStore.ts b/src/stores/AsyncStore.ts index 5697969a1d..4baf807247 100644 --- a/src/stores/AsyncStore.ts +++ b/src/stores/AsyncStore.ts @@ -65,7 +65,7 @@ export abstract class AsyncStore extends EventEmitter { * Stops the store's listening functions, such as the listener to the dispatcher. */ protected stop(): void { - if (this.dispatcherRef) this.dispatcher.unregister(this.dispatcherRef); + this.dispatcher.unregister(this.dispatcherRef); } /** diff --git a/src/stores/AsyncStoreWithClient.ts b/src/stores/AsyncStoreWithClient.ts index 418143a16c..a131614c7c 100644 --- a/src/stores/AsyncStoreWithClient.ts +++ b/src/stores/AsyncStoreWithClient.ts @@ -23,7 +23,7 @@ export abstract class AsyncStoreWithClient extends AsyncStore< const asyncStore = this; // eslint-disable-line @typescript-eslint/no-this-alias this.readyStore = new (class extends ReadyWatchingStore { public get mxClient(): MatrixClient | null { - return this.matrixClient; + return this.matrixClient ?? null; } protected async onReady(): Promise { diff --git a/src/stores/OwnBeaconStore.ts b/src/stores/OwnBeaconStore.ts index f60dae07fe..ccd4bf33a3 100644 --- a/src/stores/OwnBeaconStore.ts +++ b/src/stores/OwnBeaconStore.ts @@ -142,7 +142,7 @@ export class OwnBeaconStore extends AsyncStoreWithClient { this.matrixClient.removeListener(BeaconEvent.Destroy, this.onDestroyBeacon); this.matrixClient.removeListener(RoomStateEvent.Members, this.onRoomStateMembers); } - SettingsStore.unwatchSetting(this.dynamicWatcherRef ?? ""); + SettingsStore.unwatchSetting(this.dynamicWatcherRef); this.clearBeacons(); } diff --git a/src/stores/ReadyWatchingStore.ts b/src/stores/ReadyWatchingStore.ts index a46a09899a..922e8b8393 100644 --- a/src/stores/ReadyWatchingStore.ts +++ b/src/stores/ReadyWatchingStore.ts @@ -16,8 +16,8 @@ import { Action } from "../dispatcher/actions"; import { MatrixDispatcher } from "../dispatcher/dispatcher"; export abstract class ReadyWatchingStore extends EventEmitter implements IDestroyable { - protected matrixClient: MatrixClient | null = null; - private dispatcherRef: string | null = null; + protected matrixClient?: MatrixClient; + private dispatcherRef?: string; public constructor(protected readonly dispatcher: MatrixDispatcher) { super(); @@ -35,7 +35,7 @@ export abstract class ReadyWatchingStore extends EventEmitter implements IDestro } public get mxClient(): MatrixClient | null { - return this.matrixClient; // for external readonly access + return this.matrixClient ?? null; // for external readonly access } public useUnitTestClient(cli: MatrixClient): void { @@ -43,7 +43,7 @@ export abstract class ReadyWatchingStore extends EventEmitter implements IDestro } public destroy(): void { - if (this.dispatcherRef !== null) this.dispatcher.unregister(this.dispatcherRef); + this.dispatcher.unregister(this.dispatcherRef); } protected async onReady(): Promise { @@ -80,7 +80,7 @@ export abstract class ReadyWatchingStore extends EventEmitter implements IDestro } else if (payload.action === "on_client_not_viable" || payload.action === Action.OnLoggedOut) { if (this.matrixClient) { await this.onNotReady(); - this.matrixClient = null; + this.matrixClient = undefined; } } }; diff --git a/src/stores/widgets/WidgetLayoutStore.ts b/src/stores/widgets/WidgetLayoutStore.ts index cefbee0f6b..f0d3cafc83 100644 --- a/src/stores/widgets/WidgetLayoutStore.ts +++ b/src/stores/widgets/WidgetLayoutStore.ts @@ -91,9 +91,9 @@ export class WidgetLayoutStore extends ReadyWatchingStore { this.byRoom = new MapWithDefault(() => new Map()); this.matrixClient?.off(RoomStateEvent.Events, this.updateRoomFromState); - if (this.pinnedRef) SettingsStore.unwatchSetting(this.pinnedRef); - if (this.layoutRef) SettingsStore.unwatchSetting(this.layoutRef); - if (this.dynamicRef) SettingsStore.unwatchSetting(this.dynamicRef); + SettingsStore.unwatchSetting(this.pinnedRef); + SettingsStore.unwatchSetting(this.layoutRef); + SettingsStore.unwatchSetting(this.dynamicRef); WidgetStore.instance.off(UPDATE_EVENT, this.updateFromWidgetStore); } diff --git a/test/unit-tests/DeviceListener-test.ts b/test/unit-tests/DeviceListener-test.ts index 0f3bb68254..0862c6b385 100644 --- a/test/unit-tests/DeviceListener-test.ts +++ b/test/unit-tests/DeviceListener-test.ts @@ -39,6 +39,7 @@ jest.mock("matrix-js-sdk/src/logger"); jest.mock("../../src/dispatcher/dispatcher", () => ({ dispatch: jest.fn(), register: jest.fn(), + unregister: jest.fn(), })); jest.mock("../../src/SecurityManager", () => ({