Implement support for watching for changes in settings
This implements a dream of one day being able to listen for changes in a settings to react to them, regardless of which device actually changed the setting. The use case for this kind of thing is extremely limited, but when it is needed it should be more than powerful enough.
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
Copyright 2017 Travis Ralston
|
||||
Copyright 2019 New Vector Ltd.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
@@ -14,14 +15,49 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import SettingsHandler from "./SettingsHandler";
|
||||
import MatrixClientPeg from '../../MatrixClientPeg';
|
||||
import {WatchManager} from "../WatchManager";
|
||||
import MatrixClientBackedSettingsHandler from "./MatrixClientBackedSettingsHandler";
|
||||
|
||||
/**
|
||||
* Gets and sets settings at the "account" level for the current user.
|
||||
* This handler does not make use of the roomId parameter.
|
||||
*/
|
||||
export default class AccountSettingHandler extends SettingsHandler {
|
||||
export default class AccountSettingsHandler extends MatrixClientBackedSettingsHandler {
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this._watchers = new WatchManager();
|
||||
this._onAccountData = this._onAccountData.bind(this);
|
||||
}
|
||||
|
||||
initMatrixClient(oldClient, newClient) {
|
||||
if (oldClient) {
|
||||
oldClient.removeListener("accountData", this._onAccountData);
|
||||
}
|
||||
|
||||
newClient.on("accountData", this._onAccountData);
|
||||
}
|
||||
|
||||
_onAccountData(event) {
|
||||
if (event.getType() === "org.matrix.preview_urls") {
|
||||
let val = event.getContent()['disable'];
|
||||
if (typeof(val) !== "boolean") {
|
||||
val = null;
|
||||
} else {
|
||||
val = !val;
|
||||
}
|
||||
|
||||
this._watchers.notifyUpdate("urlPreviewsEnabled", null, val);
|
||||
} else if (event.getType() === "im.vector.web.settings") {
|
||||
// We can't really discern what changed, so trigger updates for everything
|
||||
for (const settingName of Object.keys(event.getContent())) {
|
||||
console.log(settingName);
|
||||
this._watchers.notifyUpdate(settingName, null, event.getContent()[settingName]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getValue(settingName, roomId) {
|
||||
// Special case URL previews
|
||||
if (settingName === "urlPreviewsEnabled") {
|
||||
@@ -67,6 +103,14 @@ export default class AccountSettingHandler extends SettingsHandler {
|
||||
return cli !== undefined && cli !== null;
|
||||
}
|
||||
|
||||
watchSetting(settingName, roomId, cb) {
|
||||
this._watchers.watchSetting(settingName, roomId, cb);
|
||||
}
|
||||
|
||||
unwatchSetting(cb) {
|
||||
this._watchers.unwatchSetting(cb);
|
||||
}
|
||||
|
||||
_getSettings(eventType = "im.vector.web.settings") {
|
||||
const cli = MatrixClientPeg.get();
|
||||
if (!cli) return null;
|
||||
|
||||
@@ -47,4 +47,12 @@ export default class ConfigSettingsHandler extends SettingsHandler {
|
||||
isSupported() {
|
||||
return true; // SdkConfig is always there
|
||||
}
|
||||
|
||||
watchSetting(settingName, roomId, cb) {
|
||||
// no-op: no changes possible
|
||||
}
|
||||
|
||||
unwatchSetting(cb) {
|
||||
// no-op: no changes possible
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
Copyright 2017 Travis Ralston
|
||||
Copyright 2019 New Vector Ltd.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
@@ -51,4 +52,12 @@ export default class DefaultSettingsHandler extends SettingsHandler {
|
||||
isSupported() {
|
||||
return true;
|
||||
}
|
||||
|
||||
watchSetting(settingName, roomId, cb) {
|
||||
// no-op: no changes possible
|
||||
}
|
||||
|
||||
unwatchSetting(cb) {
|
||||
// no-op: no changes possible
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
Copyright 2017 Travis Ralston
|
||||
Copyright 2019 New Vector Ltd.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
@@ -17,6 +18,7 @@ limitations under the License.
|
||||
import Promise from 'bluebird';
|
||||
import SettingsHandler from "./SettingsHandler";
|
||||
import MatrixClientPeg from "../../MatrixClientPeg";
|
||||
import {WatchManager} from "../WatchManager";
|
||||
|
||||
/**
|
||||
* Gets and sets settings at the "device" level for the current device.
|
||||
@@ -31,6 +33,7 @@ export default class DeviceSettingsHandler extends SettingsHandler {
|
||||
constructor(featureNames) {
|
||||
super();
|
||||
this._featureNames = featureNames;
|
||||
this._watchers = new WatchManager();
|
||||
}
|
||||
|
||||
getValue(settingName, roomId) {
|
||||
@@ -66,18 +69,22 @@ export default class DeviceSettingsHandler extends SettingsHandler {
|
||||
// Special case notifications
|
||||
if (settingName === "notificationsEnabled") {
|
||||
localStorage.setItem("notifications_enabled", newValue);
|
||||
this._watchers.notifyUpdate(settingName, null, newValue);
|
||||
return Promise.resolve();
|
||||
} else if (settingName === "notificationBodyEnabled") {
|
||||
localStorage.setItem("notifications_body_enabled", newValue);
|
||||
this._watchers.notifyUpdate(settingName, null, newValue);
|
||||
return Promise.resolve();
|
||||
} else if (settingName === "audioNotificationsEnabled") {
|
||||
localStorage.setItem("audio_notifications_enabled", newValue);
|
||||
this._watchers.notifyUpdate(settingName, null, newValue);
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
const settings = this._getSettings() || {};
|
||||
settings[settingName] = newValue;
|
||||
localStorage.setItem("mx_local_settings", JSON.stringify(settings));
|
||||
this._watchers.notifyUpdate(settingName, null, newValue);
|
||||
|
||||
return Promise.resolve();
|
||||
}
|
||||
@@ -90,6 +97,14 @@ export default class DeviceSettingsHandler extends SettingsHandler {
|
||||
return localStorage !== undefined && localStorage !== null;
|
||||
}
|
||||
|
||||
watchSetting(settingName, roomId, cb) {
|
||||
this._watchers.watchSetting(settingName, roomId, cb);
|
||||
}
|
||||
|
||||
unwatchSetting(cb) {
|
||||
this._watchers.unwatchSetting(cb);
|
||||
}
|
||||
|
||||
_getSettings() {
|
||||
const value = localStorage.getItem("mx_local_settings");
|
||||
if (!value) return null;
|
||||
@@ -111,5 +126,6 @@ export default class DeviceSettingsHandler extends SettingsHandler {
|
||||
|
||||
_writeFeature(featureName, enabled) {
|
||||
localStorage.setItem("mx_labs_feature_" + featureName, enabled);
|
||||
this._watchers.notifyUpdate(featureName, null, enabled);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
Copyright 2017 Travis Ralston
|
||||
Copyright 2019 New Vector Ltd.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
@@ -66,4 +67,12 @@ export default class LocalEchoWrapper extends SettingsHandler {
|
||||
isSupported() {
|
||||
return this._handler.isSupported();
|
||||
}
|
||||
|
||||
watchSetting(settingName, roomId, cb) {
|
||||
this._handler.watchSetting(settingName, roomId, cb);
|
||||
}
|
||||
|
||||
unwatchSetting(cb) {
|
||||
this._handler.unwatchSetting(cb);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
Copyright 2019 New Vector Ltd.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import SettingsHandler from "./SettingsHandler";
|
||||
|
||||
// Dev note: This whole class exists in the event someone logs out and back in - we want
|
||||
// to make sure the right MatrixClient is listening for changes.
|
||||
|
||||
/**
|
||||
* Represents the base class for settings handlers which need access to a MatrixClient.
|
||||
* This class performs no logic and should be overridden.
|
||||
*/
|
||||
export default class MatrixClientBackedSettingsHandler extends SettingsHandler {
|
||||
static _matrixClient;
|
||||
static _instances = [];
|
||||
|
||||
static set matrixClient(client) {
|
||||
const oldClient = MatrixClientBackedSettingsHandler._matrixClient;
|
||||
MatrixClientBackedSettingsHandler._matrixClient = client;
|
||||
|
||||
for (const instance of MatrixClientBackedSettingsHandler._instances) {
|
||||
instance.initMatrixClient(oldClient, client);
|
||||
}
|
||||
}
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
MatrixClientBackedSettingsHandler._instances.push(this);
|
||||
}
|
||||
|
||||
initMatrixClient() {
|
||||
console.warn("initMatrixClient not overridden");
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
Copyright 2017 Travis Ralston
|
||||
Copyright 2019 New Vector Ltd.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
@@ -14,13 +15,51 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import SettingsHandler from "./SettingsHandler";
|
||||
import MatrixClientPeg from '../../MatrixClientPeg';
|
||||
import MatrixClientBackedSettingsHandler from "./MatrixClientBackedSettingsHandler";
|
||||
import {WatchManager} from "../WatchManager";
|
||||
|
||||
/**
|
||||
* Gets and sets settings at the "room-account" level for the current user.
|
||||
*/
|
||||
export default class RoomAccountSettingsHandler extends SettingsHandler {
|
||||
export default class RoomAccountSettingsHandler extends MatrixClientBackedSettingsHandler {
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this._watchers = new WatchManager();
|
||||
this._onAccountData = this._onAccountData.bind(this);
|
||||
}
|
||||
|
||||
initMatrixClient(oldClient, newClient) {
|
||||
if (oldClient) {
|
||||
oldClient.removeListener("Room.accountData", this._onAccountData);
|
||||
}
|
||||
|
||||
newClient.on("Room.accountData", this._onAccountData);
|
||||
}
|
||||
|
||||
_onAccountData(event, room) {
|
||||
const roomId = room.roomId;
|
||||
|
||||
if (event.getType() === "org.matrix.room.preview_urls") {
|
||||
let val = event.getContent()['disable'];
|
||||
if (typeof (val) !== "boolean") {
|
||||
val = null;
|
||||
} else {
|
||||
val = !val;
|
||||
}
|
||||
|
||||
this._watchers.notifyUpdate("urlPreviewsEnabled", roomId, val);
|
||||
} else if (event.getType() === "org.matrix.room.color_scheme") {
|
||||
this._watchers.notifyUpdate("roomColor", roomId, event.getContent());
|
||||
} else if (event.getType() === "im.vector.web.settings") {
|
||||
// We can't really discern what changed, so trigger updates for everything
|
||||
for (const settingName of Object.keys(event.getContent())) {
|
||||
this._watchers.notifyUpdate(settingName, roomId, event.getContent()[settingName]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getValue(settingName, roomId) {
|
||||
// Special case URL previews
|
||||
if (settingName === "urlPreviewsEnabled") {
|
||||
@@ -74,6 +113,14 @@ export default class RoomAccountSettingsHandler extends SettingsHandler {
|
||||
return cli !== undefined && cli !== null;
|
||||
}
|
||||
|
||||
watchSetting(settingName, roomId, cb) {
|
||||
this._watchers.watchSetting(settingName, roomId, cb);
|
||||
}
|
||||
|
||||
unwatchSetting(cb) {
|
||||
this._watchers.unwatchSetting(cb);
|
||||
}
|
||||
|
||||
_getSettings(roomId, eventType = "im.vector.web.settings") {
|
||||
const room = MatrixClientPeg.get().getRoom(roomId);
|
||||
if (!room) return null;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
Copyright 2017 Travis Ralston
|
||||
Copyright 2019 New Vector Ltd.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
@@ -16,12 +17,19 @@ limitations under the License.
|
||||
|
||||
import Promise from 'bluebird';
|
||||
import SettingsHandler from "./SettingsHandler";
|
||||
import {WatchManager} from "../WatchManager";
|
||||
|
||||
/**
|
||||
* Gets and sets settings at the "room-device" level for the current device in a particular
|
||||
* room.
|
||||
*/
|
||||
export default class RoomDeviceSettingsHandler extends SettingsHandler {
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this._watchers = new WatchManager();
|
||||
}
|
||||
|
||||
getValue(settingName, roomId) {
|
||||
// Special case blacklist setting to use legacy values
|
||||
if (settingName === "blacklistUnverifiedDevices") {
|
||||
@@ -44,6 +52,7 @@ export default class RoomDeviceSettingsHandler extends SettingsHandler {
|
||||
if (!value["blacklistUnverifiedDevicesPerRoom"]) value["blacklistUnverifiedDevicesPerRoom"] = {};
|
||||
value["blacklistUnverifiedDevicesPerRoom"][roomId] = newValue;
|
||||
localStorage.setItem("mx_local_settings", JSON.stringify(value));
|
||||
this._watchers.notifyUpdate(settingName, roomId, newValue);
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
@@ -54,6 +63,7 @@ export default class RoomDeviceSettingsHandler extends SettingsHandler {
|
||||
localStorage.setItem(this._getKey(settingName, roomId), newValue);
|
||||
}
|
||||
|
||||
this._watchers.notifyUpdate(settingName, roomId, newValue);
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
@@ -65,6 +75,14 @@ export default class RoomDeviceSettingsHandler extends SettingsHandler {
|
||||
return localStorage !== undefined && localStorage !== null;
|
||||
}
|
||||
|
||||
watchSetting(settingName, roomId, cb) {
|
||||
this._watchers.watchSetting(settingName, roomId, cb);
|
||||
}
|
||||
|
||||
unwatchSetting(cb) {
|
||||
this._watchers.unwatchSetting(cb);
|
||||
}
|
||||
|
||||
_read(key) {
|
||||
const rawValue = localStorage.getItem(key);
|
||||
if (!rawValue) return null;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
Copyright 2017 Travis Ralston
|
||||
Copyright 2019 New Vector Ltd.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
@@ -14,13 +15,49 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import SettingsHandler from "./SettingsHandler";
|
||||
import MatrixClientPeg from '../../MatrixClientPeg';
|
||||
import MatrixClientBackedSettingsHandler from "./MatrixClientBackedSettingsHandler";
|
||||
import {WatchManager} from "../WatchManager";
|
||||
|
||||
/**
|
||||
* Gets and sets settings at the "room" level.
|
||||
*/
|
||||
export default class RoomSettingsHandler extends SettingsHandler {
|
||||
export default class RoomSettingsHandler extends MatrixClientBackedSettingsHandler {
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this._watchers = new WatchManager();
|
||||
this._onEvent = this._onEvent.bind(this);
|
||||
}
|
||||
|
||||
initMatrixClient(oldClient, newClient) {
|
||||
if (oldClient) {
|
||||
oldClient.removeListener("RoomState.events", this._onEvent);
|
||||
}
|
||||
|
||||
newClient.on("RoomState.events", this._onEvent);
|
||||
}
|
||||
|
||||
_onEvent(event) {
|
||||
const roomId = event.getRoomId();
|
||||
|
||||
if (event.getType() === "org.matrix.room.preview_urls") {
|
||||
let val = event.getContent()['disable'];
|
||||
if (typeof (val) !== "boolean") {
|
||||
val = null;
|
||||
} else {
|
||||
val = !val;
|
||||
}
|
||||
|
||||
this._watchers.notifyUpdate("urlPreviewsEnabled", roomId, val);
|
||||
} else if (event.getType() === "im.vector.web.settings") {
|
||||
// We can't really discern what changed, so trigger updates for everything
|
||||
for (const settingName of Object.keys(event.getContent())) {
|
||||
this._watchers.notifyUpdate(settingName, roomId, event.getContent()[settingName]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getValue(settingName, roomId) {
|
||||
// Special case URL previews
|
||||
if (settingName === "urlPreviewsEnabled") {
|
||||
@@ -64,6 +101,14 @@ export default class RoomSettingsHandler extends SettingsHandler {
|
||||
return cli !== undefined && cli !== null;
|
||||
}
|
||||
|
||||
watchSetting(settingName, roomId, cb) {
|
||||
this._watchers.watchSetting(settingName, roomId, cb);
|
||||
}
|
||||
|
||||
unwatchSetting(cb) {
|
||||
this._watchers.unwatchSetting(cb);
|
||||
}
|
||||
|
||||
_getSettings(roomId, eventType = "im.vector.web.settings") {
|
||||
const room = MatrixClientPeg.get().getRoom(roomId);
|
||||
if (!room) return null;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
Copyright 2017 Travis Ralston
|
||||
Copyright 2019 New Vector Ltd.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
@@ -68,4 +69,27 @@ export default class SettingsHandler {
|
||||
isSupported() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Watches for a setting change within this handler. The caller should preserve
|
||||
* a reference to the callback so that it may be unwatched. The caller should
|
||||
* additionally provide a unique callback for multiple watchers on the same setting.
|
||||
* @param {string} settingName The setting name to watch for changes in.
|
||||
* @param {String} roomId The room ID to watch for changes in.
|
||||
* @param {function} cb A function taking two arguments: the room ID the setting changed
|
||||
* in and the new value for the setting at this level in the given room.
|
||||
*/
|
||||
watchSetting(settingName, roomId, cb) {
|
||||
throw new Error("Invalid operation: watchSetting was not overridden");
|
||||
}
|
||||
|
||||
/**
|
||||
* Unwatches a previously watched setting. If the callback is not associated with
|
||||
* a watcher, this is a no-op.
|
||||
* @param {function} cb A callback function previously supplied to watchSetting
|
||||
* which should no longer be used.
|
||||
*/
|
||||
unwatchSetting(cb) {
|
||||
throw new Error("Invalid operation: unwatchSetting was not overridden");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user