From 9ed771ad7a28e0626a1a36794140e831c43857d5 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Fri, 17 Dec 2021 08:53:03 +0000 Subject: [PATCH] Have LocalEchoWrapper emit updates so the app can react faster (#7358) --- src/settings/SettingsStore.ts | 17 ++++++++--------- src/settings/handlers/AccountSettingsHandler.ts | 6 +++++- src/settings/handlers/DeviceSettingsHandler.ts | 2 +- src/settings/handlers/LocalEchoWrapper.ts | 11 +++++++++-- .../handlers/RoomAccountSettingsHandler.ts | 2 +- .../handlers/RoomDeviceSettingsHandler.ts | 2 +- src/settings/handlers/RoomSettingsHandler.ts | 2 +- src/settings/handlers/SettingsHandler.ts | 4 ++++ 8 files changed, 30 insertions(+), 16 deletions(-) diff --git a/src/settings/SettingsStore.ts b/src/settings/SettingsStore.ts index 9d3151f68a..ca9bfe3703 100644 --- a/src/settings/SettingsStore.ts +++ b/src/settings/SettingsStore.ts @@ -28,7 +28,7 @@ import { _t } from '../languageHandler'; import dis from '../dispatcher/dispatcher'; import { IFeature, ISetting, LabGroup, SETTINGS } from "./Settings"; import LocalEchoWrapper from "./handlers/LocalEchoWrapper"; -import { WatchManager, CallbackFn as WatchCallbackFn } from "./WatchManager"; +import { CallbackFn as WatchCallbackFn, WatchManager } from "./WatchManager"; import { SettingLevel } from "./SettingLevel"; import SettingsHandler from "./handlers/SettingsHandler"; import { SettingUpdatedPayload } from "../dispatcher/payloads/SettingUpdatedPayload"; @@ -50,21 +50,20 @@ for (const key of Object.keys(SETTINGS)) { } } +// Only wrap the handlers with async setters in a local echo wrapper const LEVEL_HANDLERS = { [SettingLevel.DEVICE]: new DeviceSettingsHandler(featureNames, defaultWatchManager), [SettingLevel.ROOM_DEVICE]: new RoomDeviceSettingsHandler(defaultWatchManager), - [SettingLevel.ROOM_ACCOUNT]: new RoomAccountSettingsHandler(defaultWatchManager), - [SettingLevel.ACCOUNT]: new AccountSettingsHandler(defaultWatchManager), - [SettingLevel.ROOM]: new RoomSettingsHandler(defaultWatchManager), + [SettingLevel.ROOM_ACCOUNT]: new LocalEchoWrapper( + new RoomAccountSettingsHandler(defaultWatchManager), + SettingLevel.ROOM_ACCOUNT, + ), + [SettingLevel.ACCOUNT]: new LocalEchoWrapper(new AccountSettingsHandler(defaultWatchManager), SettingLevel.ACCOUNT), + [SettingLevel.ROOM]: new LocalEchoWrapper(new RoomSettingsHandler(defaultWatchManager), SettingLevel.ROOM), [SettingLevel.CONFIG]: new ConfigSettingsHandler(featureNames), [SettingLevel.DEFAULT]: new DefaultSettingsHandler(defaultSettings, invertedDefaultSettings), }; -// Wrap all the handlers with local echo -for (const key of Object.keys(LEVEL_HANDLERS)) { - LEVEL_HANDLERS[key] = new LocalEchoWrapper(LEVEL_HANDLERS[key]); -} - export const LEVEL_ORDER = [ SettingLevel.DEVICE, SettingLevel.ROOM_DEVICE, diff --git a/src/settings/handlers/AccountSettingsHandler.ts b/src/settings/handlers/AccountSettingsHandler.ts index cf6653dc0c..70fe915d69 100644 --- a/src/settings/handlers/AccountSettingsHandler.ts +++ b/src/settings/handlers/AccountSettingsHandler.ts @@ -36,10 +36,14 @@ const ANALYTICS_EVENT_TYPE = "im.vector.analytics"; * This handler does not make use of the roomId parameter. */ export default class AccountSettingsHandler extends MatrixClientBackedSettingsHandler { - constructor(private watchers: WatchManager) { + constructor(public readonly watchers: WatchManager) { super(); } + public get level(): SettingLevel { + return SettingLevel.ACCOUNT; + } + public initMatrixClient(oldClient: MatrixClient, newClient: MatrixClient) { if (oldClient) { oldClient.removeListener("accountData", this.onAccountData); diff --git a/src/settings/handlers/DeviceSettingsHandler.ts b/src/settings/handlers/DeviceSettingsHandler.ts index f7a9fe9108..03da2755b1 100644 --- a/src/settings/handlers/DeviceSettingsHandler.ts +++ b/src/settings/handlers/DeviceSettingsHandler.ts @@ -33,7 +33,7 @@ export default class DeviceSettingsHandler extends SettingsHandler { * @param {string[]} featureNames The names of known features. * @param {WatchManager} watchers The watch manager to notify updates to */ - constructor(private featureNames: string[], private watchers: WatchManager) { + constructor(private featureNames: string[], public readonly watchers: WatchManager) { super(); } diff --git a/src/settings/handlers/LocalEchoWrapper.ts b/src/settings/handlers/LocalEchoWrapper.ts index 5cfcd27aed..0ce47ede2d 100644 --- a/src/settings/handlers/LocalEchoWrapper.ts +++ b/src/settings/handlers/LocalEchoWrapper.ts @@ -16,6 +16,7 @@ limitations under the License. */ import SettingsHandler from "./SettingsHandler"; +import { SettingLevel } from "../SettingLevel"; /** * A wrapper for a SettingsHandler that performs local echo on @@ -32,8 +33,9 @@ export default class LocalEchoWrapper extends SettingsHandler { /** * Creates a new local echo wrapper * @param {SettingsHandler} handler The handler to wrap + * @param {SettingLevel} level The level to notify updates at */ - constructor(private handler: SettingsHandler) { + constructor(private readonly handler: SettingsHandler, private readonly level: SettingLevel) { super(); } @@ -54,8 +56,13 @@ export default class LocalEchoWrapper extends SettingsHandler { const cacheRoomId = roomId ? roomId : "UNDEFINED"; // avoid weird keys bySetting[cacheRoomId] = newValue; + const currentValue = this.handler.getValue(settingName, roomId); const handlerPromise = this.handler.setValue(settingName, roomId, newValue); - return Promise.resolve(handlerPromise).finally(() => { + this.handler.watchers?.notifyUpdate(settingName, roomId, this.level, newValue); + return Promise.resolve(handlerPromise).catch(() => { + // notify of a rollback + this.handler.watchers?.notifyUpdate(settingName, roomId, this.level, currentValue); + }).finally(() => { delete bySetting[cacheRoomId]; }); } diff --git a/src/settings/handlers/RoomAccountSettingsHandler.ts b/src/settings/handlers/RoomAccountSettingsHandler.ts index 05596ae1a4..14db4024bf 100644 --- a/src/settings/handlers/RoomAccountSettingsHandler.ts +++ b/src/settings/handlers/RoomAccountSettingsHandler.ts @@ -31,7 +31,7 @@ const ALLOWED_WIDGETS_EVENT_TYPE = "im.vector.setting.allowed_widgets"; * Gets and sets settings at the "room-account" level for the current user. */ export default class RoomAccountSettingsHandler extends MatrixClientBackedSettingsHandler { - constructor(private watchers: WatchManager) { + constructor(public readonly watchers: WatchManager) { super(); } diff --git a/src/settings/handlers/RoomDeviceSettingsHandler.ts b/src/settings/handlers/RoomDeviceSettingsHandler.ts index 2a068eb060..47fcecdfac 100644 --- a/src/settings/handlers/RoomDeviceSettingsHandler.ts +++ b/src/settings/handlers/RoomDeviceSettingsHandler.ts @@ -24,7 +24,7 @@ import { WatchManager } from "../WatchManager"; * room. */ export default class RoomDeviceSettingsHandler extends SettingsHandler { - constructor(private watchers: WatchManager) { + constructor(public readonly watchers: WatchManager) { super(); } diff --git a/src/settings/handlers/RoomSettingsHandler.ts b/src/settings/handlers/RoomSettingsHandler.ts index 13eab3c0c2..7adabc8f5c 100644 --- a/src/settings/handlers/RoomSettingsHandler.ts +++ b/src/settings/handlers/RoomSettingsHandler.ts @@ -29,7 +29,7 @@ import { WatchManager } from "../WatchManager"; * Gets and sets settings at the "room" level. */ export default class RoomSettingsHandler extends MatrixClientBackedSettingsHandler { - constructor(private watchers: WatchManager) { + constructor(public readonly watchers: WatchManager) { super(); } diff --git a/src/settings/handlers/SettingsHandler.ts b/src/settings/handlers/SettingsHandler.ts index ca9a068fd3..c0070bc1ef 100644 --- a/src/settings/handlers/SettingsHandler.ts +++ b/src/settings/handlers/SettingsHandler.ts @@ -15,11 +15,15 @@ See the License for the specific language governing permissions and limitations under the License. */ +import { WatchManager } from "../WatchManager"; + /** * Represents the base class for all level handlers. This class performs no logic * and should be overridden. */ export default abstract class SettingsHandler { + public readonly watchers?: WatchManager; + /** * Gets the value for a particular setting at this level for a particular room. * If no room is applicable, the roomId may be null. The roomId may not be