diff --git a/src/components/structures/MatrixChat.tsx b/src/components/structures/MatrixChat.tsx index 73d614a430..e05c451255 100644 --- a/src/components/structures/MatrixChat.tsx +++ b/src/components/structures/MatrixChat.tsx @@ -401,6 +401,8 @@ export default class MatrixChat extends React.PureComponent { } } + private get cli(): MatrixClient { return MatrixClientPeg.get(); } + public componentDidMount(): void { window.addEventListener("resize", this.onWindowResized); } @@ -1258,8 +1260,7 @@ export default class MatrixChat extends React.PureComponent { this.themeWatcher.recheck(); StorageManager.tryPersistStorage(); - const cli = MatrixClientPeg.get(); - createLocalNotificationSettingsIfNeeded(cli); + this.cli.on(ClientEvent.Sync, this.onInitialSync); if ( MatrixClientPeg.currentUserIsJustRegistered() && @@ -1287,6 +1288,14 @@ export default class MatrixChat extends React.PureComponent { } } + private onInitialSync = (): void => { + if (this.cli.isInitialSyncComplete()) { + this.cli.off(ClientEvent.Sync, this.onInitialSync); + } + + createLocalNotificationSettingsIfNeeded(this.cli); + }; + private async onShowPostLoginScreen(useCase?: UseCase) { if (useCase) { PosthogAnalytics.instance.setProperty("ftueUseCaseSelection", useCase); diff --git a/src/components/views/settings/devices/useOwnDevices.ts b/src/components/views/settings/devices/useOwnDevices.ts index 255bcc2d53..94fe560553 100644 --- a/src/components/views/settings/devices/useOwnDevices.ts +++ b/src/components/views/settings/devices/useOwnDevices.ts @@ -16,10 +16,12 @@ limitations under the License. import { useCallback, useContext, useEffect, useState } from "react"; import { + ClientEvent, IMyDevice, IPusher, LOCAL_NOTIFICATION_SETTINGS_PREFIX, MatrixClient, + MatrixEvent, PUSHER_DEVICE_ID, PUSHER_ENABLED, } from "matrix-js-sdk/src/matrix"; @@ -32,6 +34,7 @@ import { LocalNotificationSettings } from "matrix-js-sdk/src/@types/local_notifi import MatrixClientContext from "../../../../contexts/MatrixClientContext"; import { _t } from "../../../../languageHandler"; import { DevicesDictionary, DeviceWithVerification } from "./types"; +import { useEventEmitter } from "../../../../hooks/useEventEmitter"; const isDeviceVerified = ( matrixClient: MatrixClient, @@ -161,6 +164,16 @@ export const useOwnDevices = (): DevicesState => { refreshDevices(); }, [refreshDevices]); + useEventEmitter(matrixClient, ClientEvent.AccountData, (event: MatrixEvent): void => { + const type = event.getType(); + if (type.startsWith(LOCAL_NOTIFICATION_SETTINGS_PREFIX.name)) { + const newSettings = new Map(localNotificationSettings); + const deviceId = type.slice(type.lastIndexOf(".") + 1); + newSettings.set(deviceId, event.getContent()); + setLocalNotificationSettings(newSettings); + } + }); + const isCurrentDeviceVerified = !!devices[currentDeviceId]?.isVerified; const requestDeviceVerification = isCurrentDeviceVerified && userId diff --git a/test/components/views/settings/tabs/user/SessionManagerTab-test.tsx b/test/components/views/settings/tabs/user/SessionManagerTab-test.tsx index 70bb171b12..2cc5a32b79 100644 --- a/test/components/views/settings/tabs/user/SessionManagerTab-test.tsx +++ b/test/components/views/settings/tabs/user/SessionManagerTab-test.tsx @@ -23,6 +23,7 @@ import { DeviceTrustLevel } from 'matrix-js-sdk/src/crypto/CrossSigning'; import { VerificationRequest } from 'matrix-js-sdk/src/crypto/verification/request/VerificationRequest'; import { sleep } from 'matrix-js-sdk/src/utils'; import { + ClientEvent, IMyDevice, LOCAL_NOTIFICATION_SETTINGS_PREFIX, MatrixEvent, @@ -745,4 +746,37 @@ describe('', () => { { is_silenced: true }, ); }); + + it("updates the UI when another session changes the local notifications", async () => { + const { getByTestId } = render(getComponent()); + + await act(async () => { + await flushPromisesWithFakeTimers(); + }); + + toggleDeviceDetails(getByTestId, alicesDevice.device_id); + + // device details are expanded + expect(getByTestId(`device-detail-${alicesDevice.device_id}`)).toBeTruthy(); + expect(getByTestId('device-detail-push-notification')).toBeTruthy(); + + const checkbox = getByTestId('device-detail-push-notification-checkbox'); + + expect(checkbox).toBeTruthy(); + + expect(checkbox.getAttribute('aria-checked')).toEqual("true"); + + const evt = new MatrixEvent({ + type: LOCAL_NOTIFICATION_SETTINGS_PREFIX.name + "." + alicesDevice.device_id, + content: { + is_silenced: true, + }, + }); + + await act(async () => { + mockClient.emit(ClientEvent.AccountData, evt); + }); + + expect(checkbox.getAttribute('aria-checked')).toEqual("false"); + }); });