Emit events from DeviceListenerCurrentDevice instead of delegating to DeviceListener (#32451)
* Emit events from DeviceListenerCurrentDevice instead of delegating to DeviceListener * Make CurrentDeviceEvents a const enum * Break out event emitting into its own class so the instance can be persistent
This commit is contained in:
@@ -24,7 +24,7 @@ import { RecoveryPanelOutOfSync } from "../../encryption/RecoveryPanelOutOfSync"
|
|||||||
import { useTypedEventEmitterState } from "../../../../../hooks/useEventEmitter";
|
import { useTypedEventEmitterState } from "../../../../../hooks/useEventEmitter";
|
||||||
import { KeyStoragePanel } from "../../encryption/KeyStoragePanel";
|
import { KeyStoragePanel } from "../../encryption/KeyStoragePanel";
|
||||||
import { DeleteKeyStoragePanel } from "../../encryption/DeleteKeyStoragePanel";
|
import { DeleteKeyStoragePanel } from "../../encryption/DeleteKeyStoragePanel";
|
||||||
import { DeviceListener, DeviceListenerEvents, type DeviceState } from "../../../../../device-listener";
|
import { DeviceListener, CurrentDeviceEvents, type DeviceState } from "../../../../../device-listener";
|
||||||
import { useKeyStoragePanelViewModel } from "../../../../viewmodels/settings/encryption/KeyStoragePanelViewModel";
|
import { useKeyStoragePanelViewModel } from "../../../../viewmodels/settings/encryption/KeyStoragePanelViewModel";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -64,8 +64,8 @@ export function EncryptionUserSettingsTab({ initialState = "main" }: Readonly<Pr
|
|||||||
const [state, setState] = useState<State>(initialState);
|
const [state, setState] = useState<State>(initialState);
|
||||||
|
|
||||||
const deviceState = useTypedEventEmitterState(
|
const deviceState = useTypedEventEmitterState(
|
||||||
DeviceListener.sharedInstance(),
|
DeviceListener.sharedInstance().currentDeviceChangedEmitter,
|
||||||
DeviceListenerEvents.DeviceState,
|
CurrentDeviceEvents.DeviceStateChanged,
|
||||||
(state?: DeviceState): DeviceState => {
|
(state?: DeviceState): DeviceState => {
|
||||||
return state ?? DeviceListener.sharedInstance().getDeviceState();
|
return state ?? DeviceListener.sharedInstance().getDeviceState();
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2026 Element Creations Ltd.
|
||||||
|
|
||||||
|
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
|
||||||
|
Please see LICENSE files in the repository root for full details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { TypedEventEmitter } from "matrix-js-sdk/src/matrix";
|
||||||
|
|
||||||
|
import { type DeviceState } from ".";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The events emitted when the {@link DeviceState} of the current device
|
||||||
|
* changes.
|
||||||
|
*/
|
||||||
|
export const enum CurrentDeviceEvents {
|
||||||
|
DeviceStateChanged = "device_state",
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* You must provide one of these if you listen to {@link CurrentDeviceEvents}
|
||||||
|
* emitted by {@link DeviceListenerCurrentDevice}. It specifies how to handle
|
||||||
|
* each type of event.
|
||||||
|
*/
|
||||||
|
type EventHandlerMap = {
|
||||||
|
[CurrentDeviceEvents.DeviceStateChanged]: (state: DeviceState) => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emits events when the current device changes state.
|
||||||
|
*/
|
||||||
|
export class CurrentDeviceChangedEmitter extends TypedEventEmitter<CurrentDeviceEvents, EventHandlerMap> {
|
||||||
|
public onStateChanged(newState: DeviceState): void {
|
||||||
|
this.emit(CurrentDeviceEvents.DeviceStateChanged, newState);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,7 +7,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
|
|||||||
Please see LICENSE files in the repository root for full details.
|
Please see LICENSE files in the repository root for full details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { type MatrixClient, ClientStoppedError, TypedEventEmitter } from "matrix-js-sdk/src/matrix";
|
import { type MatrixClient, ClientStoppedError } from "matrix-js-sdk/src/matrix";
|
||||||
import { logger as baseLogger, LogSpan } from "matrix-js-sdk/src/logger";
|
import { logger as baseLogger, LogSpan } from "matrix-js-sdk/src/logger";
|
||||||
import { type CryptoSessionStateChange } from "@matrix-org/analytics-events/types/typescript/CryptoSessionStateChange";
|
import { type CryptoSessionStateChange } from "@matrix-org/analytics-events/types/typescript/CryptoSessionStateChange";
|
||||||
import { secureRandomString } from "matrix-js-sdk/src/randomstring";
|
import { secureRandomString } from "matrix-js-sdk/src/randomstring";
|
||||||
@@ -20,22 +20,16 @@ import SdkConfig from "../SdkConfig";
|
|||||||
import PlatformPeg from "../PlatformPeg";
|
import PlatformPeg from "../PlatformPeg";
|
||||||
import { recordClientInformation, removeClientInformation } from "../utils/device/clientInformation";
|
import { recordClientInformation, removeClientInformation } from "../utils/device/clientInformation";
|
||||||
import SettingsStore, { type CallbackFn } from "../settings/SettingsStore";
|
import SettingsStore, { type CallbackFn } from "../settings/SettingsStore";
|
||||||
import { DeviceListenerOtherDevices, DeviceListenerCurrentDevice, type DeviceState } from ".";
|
import {
|
||||||
|
DeviceListenerOtherDevices,
|
||||||
|
DeviceListenerCurrentDevice,
|
||||||
|
type DeviceState,
|
||||||
|
CurrentDeviceChangedEmitter,
|
||||||
|
} from ".";
|
||||||
|
|
||||||
const logger = baseLogger.getChild("DeviceListener:");
|
const logger = baseLogger.getChild("DeviceListener:");
|
||||||
|
|
||||||
/**
|
export class DeviceListener {
|
||||||
* The events emitted by {@link DeviceListener}
|
|
||||||
*/
|
|
||||||
export enum DeviceListenerEvents {
|
|
||||||
DeviceState = "device_state",
|
|
||||||
}
|
|
||||||
|
|
||||||
type EventHandlerMap = {
|
|
||||||
[DeviceListenerEvents.DeviceState]: (state: DeviceState) => void;
|
|
||||||
};
|
|
||||||
|
|
||||||
export class DeviceListener extends TypedEventEmitter<DeviceListenerEvents, EventHandlerMap> {
|
|
||||||
private dispatcherRef?: string;
|
private dispatcherRef?: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -44,11 +38,34 @@ export class DeviceListener extends TypedEventEmitter<DeviceListenerEvents, Even
|
|||||||
*/
|
*/
|
||||||
public otherDevices?: DeviceListenerOtherDevices;
|
public otherDevices?: DeviceListenerOtherDevices;
|
||||||
|
|
||||||
/** All the information about whether this device's encrypytion is OK. Only
|
/**
|
||||||
* set if `running` is true, otherwise undefined.
|
* All the information about whether this device's encrypytion is OK.
|
||||||
|
*
|
||||||
|
* Defined after {@link DeviceListener.start} has been called, before {@link
|
||||||
|
* DeviceListener.stop} is called.
|
||||||
*/
|
*/
|
||||||
public currentDevice?: DeviceListenerCurrentDevice;
|
public currentDevice?: DeviceListenerCurrentDevice;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emits `CurrentDeviceEvents` events when the state
|
||||||
|
* of the current device changes.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* ```ts
|
||||||
|
* const deviceState = useTypedEventEmitterState(
|
||||||
|
* DeviceListener.sharedInstance().currentDeviceChangedEmitter,
|
||||||
|
* CurrentDeviceEvents.DeviceStateChanged,
|
||||||
|
* (state?: DeviceState): DeviceState => {
|
||||||
|
* return state ?? DeviceListener.sharedInstance().getDeviceState();
|
||||||
|
* },
|
||||||
|
* );
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* Now `deviceState` will reflect the state of the current device and
|
||||||
|
* trigger an update when it changes.
|
||||||
|
*/
|
||||||
|
public currentDeviceChangedEmitter = new CurrentDeviceChangedEmitter();
|
||||||
|
|
||||||
private running = false;
|
private running = false;
|
||||||
// The client with which the instance is running. Only set if `running` is true, otherwise undefined.
|
// The client with which the instance is running. Only set if `running` is true, otherwise undefined.
|
||||||
private client?: MatrixClient;
|
private client?: MatrixClient;
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ import {
|
|||||||
ClientEvent,
|
ClientEvent,
|
||||||
} from "matrix-js-sdk/src/matrix";
|
} from "matrix-js-sdk/src/matrix";
|
||||||
|
|
||||||
import { type DeviceListener, type DeviceState, DeviceListenerEvents } from ".";
|
import { type DeviceListener, type DeviceState } from ".";
|
||||||
import {
|
import {
|
||||||
hideToast as hideSetupEncryptionToast,
|
hideToast as hideSetupEncryptionToast,
|
||||||
showToast as showSetupEncryptionToast,
|
showToast as showSetupEncryptionToast,
|
||||||
@@ -263,7 +263,7 @@ export class DeviceListenerCurrentDevice {
|
|||||||
private async setDeviceState(newState: DeviceState, logSpan: LogSpan): Promise<void> {
|
private async setDeviceState(newState: DeviceState, logSpan: LogSpan): Promise<void> {
|
||||||
this.deviceState = newState;
|
this.deviceState = newState;
|
||||||
|
|
||||||
this.deviceListener.emit(DeviceListenerEvents.DeviceState, newState);
|
this.deviceListener.currentDeviceChangedEmitter.onStateChanged(newState);
|
||||||
|
|
||||||
if (newState === "ok" || this.dismissedThisDeviceToast) {
|
if (newState === "ok" || this.dismissedThisDeviceToast) {
|
||||||
hideSetupEncryptionToast();
|
hideSetupEncryptionToast();
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
|
|||||||
Please see LICENSE files in the repository root for full details.
|
Please see LICENSE files in the repository root for full details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
export * from "./CurrentDeviceChangedEmitter";
|
||||||
export * from "./DeviceListener";
|
export * from "./DeviceListener";
|
||||||
export * from "./DeviceListenerCurrentDevice";
|
export * from "./DeviceListenerCurrentDevice";
|
||||||
export * from "./DeviceListenerOtherDevices";
|
export * from "./DeviceListenerOtherDevices";
|
||||||
|
|||||||
Reference in New Issue
Block a user