Rebuild SettingsStore to be better supported
This does away with the room- and account-style settings, and just replaces them with `supportedLevels`. The handlers have also been moved out to be in better support of the other options, like SdkConfig and per-room-per-device. Signed-off-by: Travis Ralston <travpc@gmail.com>
This commit is contained in:
parent
c43bf336a9
commit
989bdcf5fb
10 changed files with 736 additions and 431 deletions
47
src/settings/AccountSettingsHandler.js
Normal file
47
src/settings/AccountSettingsHandler.js
Normal file
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
Copyright 2017 Travis Ralston
|
||||
|
||||
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 Promise from 'bluebird';
|
||||
import SettingsHandler from "./SettingsHandler";
|
||||
import MatrixClientPeg from '../MatrixClientPeg';
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
getValue(settingName, roomId) {
|
||||
const value = MatrixClientPeg.get().getAccountData(this._getEventType(settingName));
|
||||
if (!value) return Promise.reject();
|
||||
return Promise.resolve(value);
|
||||
}
|
||||
|
||||
setValue(settingName, roomId, newValue) {
|
||||
return MatrixClientPeg.get().setAccountData(this._getEventType(settingName), newValue);
|
||||
}
|
||||
|
||||
canSetValue(settingName, roomId) {
|
||||
return true; // It's their account, so they should be able to
|
||||
}
|
||||
|
||||
isSupported() {
|
||||
return !!MatrixClientPeg.get();
|
||||
}
|
||||
|
||||
_getEventType(settingName) {
|
||||
return "im.vector.setting." + settingName;
|
||||
}
|
||||
}
|
43
src/settings/ConfigSettingsHandler.js
Normal file
43
src/settings/ConfigSettingsHandler.js
Normal file
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
Copyright 2017 Travis Ralston
|
||||
|
||||
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 Promise from 'bluebird';
|
||||
import SettingsHandler from "./SettingsHandler";
|
||||
import SdkConfig from "../SdkConfig";
|
||||
|
||||
/**
|
||||
* Gets and sets settings at the "config" level. This handler does not make use of the
|
||||
* roomId parameter.
|
||||
*/
|
||||
export default class ConfigSettingsHandler extends SettingsHandler {
|
||||
getValue(settingName, roomId) {
|
||||
const settingsConfig = SdkConfig.get()["settingDefaults"];
|
||||
if (!settingsConfig || !settingsConfig[settingName]) return Promise.reject();
|
||||
return Promise.resolve(settingsConfig[settingName]);
|
||||
}
|
||||
|
||||
setValue(settingName, roomId, newValue) {
|
||||
throw new Error("Cannot change settings at the config level");
|
||||
}
|
||||
|
||||
canSetValue(settingName, roomId) {
|
||||
return false;
|
||||
}
|
||||
|
||||
isSupported() {
|
||||
return true; // SdkConfig is always there
|
||||
}
|
||||
}
|
51
src/settings/DefaultSettingsHandler.js
Normal file
51
src/settings/DefaultSettingsHandler.js
Normal file
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
Copyright 2017 Travis Ralston
|
||||
|
||||
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 Promise from 'bluebird';
|
||||
import SettingsHandler from "./SettingsHandler";
|
||||
|
||||
/**
|
||||
* Gets settings at the "default" level. This handler does not support setting values.
|
||||
* This handler does not make use of the roomId parameter.
|
||||
*/
|
||||
export default class DefaultSettingsHandler extends SettingsHandler {
|
||||
/**
|
||||
* Creates a new default settings handler with the given defaults
|
||||
* @param {object} defaults The default setting values, keyed by setting name.
|
||||
*/
|
||||
constructor(defaults) {
|
||||
super();
|
||||
this._defaults = defaults;
|
||||
}
|
||||
|
||||
getValue(settingName, roomId) {
|
||||
const value = this._defaults[settingName];
|
||||
if (!value) return Promise.reject();
|
||||
return Promise.resolve(value);
|
||||
}
|
||||
|
||||
setValue(settingName, roomId, newValue) {
|
||||
throw new Error("Cannot set values on the default level handler");
|
||||
}
|
||||
|
||||
canSetValue(settingName, roomId) {
|
||||
return false;
|
||||
}
|
||||
|
||||
isSupported() {
|
||||
return true;
|
||||
}
|
||||
}
|
90
src/settings/DeviceSettingsHandler.js
Normal file
90
src/settings/DeviceSettingsHandler.js
Normal file
|
@ -0,0 +1,90 @@
|
|||
/*
|
||||
Copyright 2017 Travis Ralston
|
||||
|
||||
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 Promise from 'bluebird';
|
||||
import SettingsHandler from "./SettingsHandler";
|
||||
import MatrixClientPeg from "../MatrixClientPeg";
|
||||
|
||||
/**
|
||||
* Gets and sets settings at the "device" level for the current device.
|
||||
* This handler does not make use of the roomId parameter. This handler
|
||||
* will special-case features to support legacy settings.
|
||||
*/
|
||||
export default class DeviceSettingsHandler extends SettingsHandler {
|
||||
/**
|
||||
* Creates a new device settings handler
|
||||
* @param {string[]} featureNames The names of known features.
|
||||
*/
|
||||
constructor(featureNames) {
|
||||
super();
|
||||
this._featureNames = featureNames;
|
||||
}
|
||||
|
||||
getValue(settingName, roomId) {
|
||||
if (this._featureNames.includes(settingName)) {
|
||||
return Promise.resolve(this._readFeature(settingName));
|
||||
}
|
||||
|
||||
const value = localStorage.getItem(this._getKey(settingName));
|
||||
if (!value) return Promise.reject();
|
||||
return Promise.resolve(value);
|
||||
}
|
||||
|
||||
setValue(settingName, roomId, newValue) {
|
||||
if (this._featureNames.includes(settingName)) {
|
||||
return Promise.resolve(this._writeFeature(settingName));
|
||||
}
|
||||
|
||||
if (newValue === null) {
|
||||
localStorage.removeItem(this._getKey(settingName));
|
||||
} else {
|
||||
localStorage.setItem(this._getKey(settingName), newValue);
|
||||
}
|
||||
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
canSetValue(settingName, roomId) {
|
||||
return true; // It's their device, so they should be able to
|
||||
}
|
||||
|
||||
isSupported() {
|
||||
return !!localStorage;
|
||||
}
|
||||
|
||||
_getKey(settingName) {
|
||||
return "mx_setting_" + settingName;
|
||||
}
|
||||
|
||||
// Note: features intentionally don't use the same key as settings to avoid conflicts
|
||||
// and to be backwards compatible.
|
||||
|
||||
_readFeature(featureName) {
|
||||
if (MatrixClientPeg.get() && MatrixClientPeg.get().isGuest()) {
|
||||
// Guests should not have any labs features enabled.
|
||||
return {enabled: false};
|
||||
}
|
||||
|
||||
const value = localStorage.getItem("mx_labs_feature_" + featureName);
|
||||
const enabled = value === "true";
|
||||
|
||||
return {enabled};
|
||||
}
|
||||
|
||||
_writeFeature(featureName, enabled) {
|
||||
localStorage.setItem("mx_labs_feature_" + featureName, enabled);
|
||||
}
|
||||
}
|
52
src/settings/RoomAccountSettingsHandler.js
Normal file
52
src/settings/RoomAccountSettingsHandler.js
Normal file
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
Copyright 2017 Travis Ralston
|
||||
|
||||
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 Promise from 'bluebird';
|
||||
import SettingsHandler from "./SettingsHandler";
|
||||
import MatrixClientPeg from '../MatrixClientPeg';
|
||||
|
||||
/**
|
||||
* Gets and sets settings at the "room-account" level for the current user.
|
||||
*/
|
||||
export default class RoomAccountSettingsHandler extends SettingsHandler {
|
||||
getValue(settingName, roomId) {
|
||||
const room = MatrixClientPeg.get().getRoom(roomId);
|
||||
if (!room) return Promise.reject();
|
||||
|
||||
const value = room.getAccountData(this._getEventType(settingName));
|
||||
if (!value) return Promise.reject();
|
||||
return Promise.resolve(value);
|
||||
}
|
||||
|
||||
setValue(settingName, roomId, newValue) {
|
||||
return MatrixClientPeg.get().setRoomAccountData(
|
||||
roomId, this._getEventType(settingName), newValue
|
||||
);
|
||||
}
|
||||
|
||||
canSetValue(settingName, roomId) {
|
||||
const room = MatrixClientPeg.get().getRoom(roomId);
|
||||
return !!room; // If they have the room, they can set their own account data
|
||||
}
|
||||
|
||||
isSupported() {
|
||||
return !!MatrixClientPeg.get();
|
||||
}
|
||||
|
||||
_getEventType(settingName) {
|
||||
return "im.vector.setting." + settingName;
|
||||
}
|
||||
}
|
52
src/settings/RoomDeviceSettingsHandler.js
Normal file
52
src/settings/RoomDeviceSettingsHandler.js
Normal file
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
Copyright 2017 Travis Ralston
|
||||
|
||||
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 Promise from 'bluebird';
|
||||
import SettingsHandler from "./SettingsHandler";
|
||||
|
||||
/**
|
||||
* Gets and sets settings at the "room-device" level for the current device in a particular
|
||||
* room.
|
||||
*/
|
||||
export default class RoomDeviceSettingsHandler extends SettingsHandler {
|
||||
getValue(settingName, roomId) {
|
||||
const value = localStorage.getItem(this._getKey(settingName, roomId));
|
||||
if (!value) return Promise.reject();
|
||||
return Promise.resolve(value);
|
||||
}
|
||||
|
||||
setValue(settingName, roomId, newValue) {
|
||||
if (newValue === null) {
|
||||
localStorage.removeItem(this._getKey(settingName, roomId));
|
||||
} else {
|
||||
localStorage.setItem(this._getKey(settingName, roomId), newValue);
|
||||
}
|
||||
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
canSetValue(settingName, roomId) {
|
||||
return true; // It's their device, so they should be able to
|
||||
}
|
||||
|
||||
isSupported() {
|
||||
return !!localStorage;
|
||||
}
|
||||
|
||||
_getKey(settingName, roomId) {
|
||||
return "mx_setting_" + settingName + "_" + roomId;
|
||||
}
|
||||
}
|
56
src/settings/RoomSettingsHandler.js
Normal file
56
src/settings/RoomSettingsHandler.js
Normal file
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
Copyright 2017 Travis Ralston
|
||||
|
||||
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 Promise from 'bluebird';
|
||||
import SettingsHandler from "./SettingsHandler";
|
||||
import MatrixClientPeg from '../MatrixClientPeg';
|
||||
|
||||
/**
|
||||
* Gets and sets settings at the "room" level.
|
||||
*/
|
||||
export default class RoomSettingsHandler extends SettingsHandler {
|
||||
getValue(settingName, roomId) {
|
||||
const room = MatrixClientPeg.get().getRoom(roomId);
|
||||
if (!room) return Promise.reject();
|
||||
|
||||
const event = room.currentState.getStateEvents(this._getEventType(settingName), "");
|
||||
if (!event || !event.getContent()) return Promise.reject();
|
||||
return Promise.resolve(event.getContent());
|
||||
}
|
||||
|
||||
setValue(settingName, roomId, newValue) {
|
||||
return MatrixClientPeg.get().sendStateEvent(
|
||||
roomId, this._getEventType(settingName), newValue, ""
|
||||
);
|
||||
}
|
||||
|
||||
canSetValue(settingName, roomId) {
|
||||
const cli = MatrixClientPeg.get();
|
||||
const room = cli.getRoom(roomId);
|
||||
const eventType = this._getEventType(settingName);
|
||||
|
||||
if (!room) return false;
|
||||
return room.currentState.maySendStateEvent(eventType, cli.getUserId());
|
||||
}
|
||||
|
||||
isSupported() {
|
||||
return !!MatrixClientPeg.get();
|
||||
}
|
||||
|
||||
_getEventType(settingName) {
|
||||
return "im.vector.setting." + settingName;
|
||||
}
|
||||
}
|
70
src/settings/SettingsHandler.js
Normal file
70
src/settings/SettingsHandler.js
Normal file
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
Copyright 2017 Travis Ralston
|
||||
|
||||
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 Promise from 'bluebird';
|
||||
|
||||
/**
|
||||
* Represents the base class for all level handlers. This class performs no logic
|
||||
* and should be overridden.
|
||||
*/
|
||||
export default class SettingsHandler {
|
||||
/**
|
||||
* 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
|
||||
* applicable to this level and may be ignored by the handler.
|
||||
* @param {string} settingName The name of the setting.
|
||||
* @param {String} roomId The room ID to read from, may be null.
|
||||
* @return {Promise<object>} Resolves to the setting value. Rejected if the value
|
||||
* could not be found.
|
||||
*/
|
||||
getValue(settingName, roomId) {
|
||||
throw new Error("Operation not possible: getValue was not overridden");
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets 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
|
||||
* applicable to this level and may be ignored by the handler. Setting a value
|
||||
* to null will cause the level to remove the value. The current user should be
|
||||
* able to set the value prior to calling this.
|
||||
* @param {string} settingName The name of the setting to change.
|
||||
* @param {String} roomId The room ID to set the value in, may be null.
|
||||
* @param {Object} newValue The new value for the setting, may be null.
|
||||
* @return {Promise} Resolves when the setting has been saved.
|
||||
*/
|
||||
setValue(settingName, roomId, newValue) {
|
||||
throw new Error("Operation not possible: setValue was not overridden");
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the current user is able to set the value of the given setting
|
||||
* in the given room at this level.
|
||||
* @param {string} settingName The name of the setting to check.
|
||||
* @param {String} roomId The room ID to check in, may be null
|
||||
* @returns {boolean} True if the setting can be set by the user, false otherwise.
|
||||
*/
|
||||
canSetValue(settingName, roomId) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if this level is supported on this device.
|
||||
* @returns {boolean} True if this level is supported on the current device.
|
||||
*/
|
||||
isSupported() {
|
||||
return false;
|
||||
}
|
||||
}
|
275
src/settings/SettingsStore.js
Normal file
275
src/settings/SettingsStore.js
Normal file
|
@ -0,0 +1,275 @@
|
|||
/*
|
||||
Copyright 2017 Travis Ralston
|
||||
|
||||
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 Promise from 'bluebird';
|
||||
import DeviceSettingsHandler from "./DeviceSettingsHandler";
|
||||
import RoomDeviceSettingsHandler from "./RoomDeviceSettingsHandler";
|
||||
import DefaultSettingsHandler from "./DefaultSettingsHandler";
|
||||
import RoomAccountSettingsHandler from "./RoomAccountSettingsHandler";
|
||||
import AccountSettingsHandler from "./AccountSettingsHandler";
|
||||
import RoomSettingsHandler from "./RoomSettingsHandler";
|
||||
import ConfigSettingsHandler from "./ConfigSettingsHandler";
|
||||
import {_t, _td} from '../languageHandler';
|
||||
import SdkConfig from "../SdkConfig";
|
||||
|
||||
// Preset levels for room-based settings (eg: URL previews).
|
||||
// Doesn't include 'room' because most settings don't need it. Use .concat('room') to add.
|
||||
const LEVELS_PRESET_ROOM = ['device', 'room-device', 'room-account', 'account'];
|
||||
|
||||
// Preset levels for account-based settings (eg: interface language).
|
||||
const LEVELS_PRESET_ACCOUNT = ['device', 'account'];
|
||||
|
||||
// Preset levels for features (labs) settings.
|
||||
const LEVELS_PRESET_FEATURE = ['device'];
|
||||
|
||||
const SETTINGS = {
|
||||
"my-setting": {
|
||||
isFeature: false, // optional
|
||||
displayName: _td("Cool Name"),
|
||||
supportedLevels: [
|
||||
// The order does not matter.
|
||||
|
||||
"device", // Affects the current device only
|
||||
"room-device", // Affects the current room on the current device
|
||||
"room-account", // Affects the current room for the current account
|
||||
"account", // Affects the current account
|
||||
"room", // Affects the current room (controlled by room admins)
|
||||
|
||||
// "default" and "config" are always supported and do not get listed here.
|
||||
],
|
||||
defaults: {
|
||||
your: "value",
|
||||
},
|
||||
},
|
||||
|
||||
// TODO: Populate this
|
||||
};
|
||||
|
||||
// Convert the above into simpler formats for the handlers
|
||||
let defaultSettings = {};
|
||||
let featureNames = [];
|
||||
for (let key of Object.keys(SETTINGS)) {
|
||||
defaultSettings[key] = SETTINGS[key].defaults;
|
||||
if (SETTINGS[key].isFeature) featureNames.push(key);
|
||||
}
|
||||
|
||||
const LEVEL_HANDLERS = {
|
||||
"device": new DeviceSettingsHandler(featureNames),
|
||||
"room-device": new RoomDeviceSettingsHandler(),
|
||||
"room-account": new RoomAccountSettingsHandler(),
|
||||
"account": new AccountSettingsHandler(),
|
||||
"room": new RoomSettingsHandler(),
|
||||
"config": new ConfigSettingsHandler(),
|
||||
"default": new DefaultSettingsHandler(defaultSettings),
|
||||
};
|
||||
|
||||
/**
|
||||
* Controls and manages application settings by providing varying levels at which the
|
||||
* setting value may be specified. The levels are then used to determine what the setting
|
||||
* value should be given a set of circumstances. The levels, in priority order, are:
|
||||
* - "device" - Values are determined by the current device
|
||||
* - "room-device" - Values are determined by the current device for a particular room
|
||||
* - "room-account" - Values are determined by the current account for a particular room
|
||||
* - "account" - Values are determined by the current account
|
||||
* - "room" - Values are determined by a particular room (by the room admins)
|
||||
* - "config" - Values are determined by the config.json
|
||||
* - "default" - Values are determined by the hardcoded defaults
|
||||
*
|
||||
* Each level has a different method to storing the setting value. For implementation
|
||||
* specific details, please see the handlers. The "config" and "default" levels are
|
||||
* both always supported on all platforms. All other settings should be guarded by
|
||||
* isLevelSupported() prior to attempting to set the value.
|
||||
*
|
||||
* Settings can also represent features. Features are significant portions of the
|
||||
* application that warrant a dedicated setting to toggle them on or off. Features are
|
||||
* special-cased to ensure that their values respect the configuration (for example, a
|
||||
* feature may be reported as disabled even though a user has specifically requested it
|
||||
* be enabled).
|
||||
*/
|
||||
export default class SettingsStore {
|
||||
/**
|
||||
* Gets the translated display name for a given setting
|
||||
* @param {string} settingName The setting to look up.
|
||||
* @return {String} The display name for the setting, or null if not found.
|
||||
*/
|
||||
static getDisplayName(settingName) {
|
||||
if (!SETTINGS[settingName] || !SETTINGS[settingName].displayName) return null;
|
||||
return _t(SETTINGS[settingName].displayName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if a setting is also a feature.
|
||||
* @param {string} settingName The setting to look up.
|
||||
* @return {boolean} True if the setting is a feature.
|
||||
*/
|
||||
static isFeature(settingName) {
|
||||
if (!SETTINGS[settingName]) return false;
|
||||
return SETTINGS[settingName].isFeature;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if a given feature is enabled. The feature given must be a known
|
||||
* feature.
|
||||
* @param {string} settingName The name of the setting that is a feature.
|
||||
* @param {String} roomId The optional room ID to validate in, may be null.
|
||||
* @return {boolean} True if the feature is enabled, false otherwise
|
||||
*/
|
||||
static isFeatureEnabled(settingName, roomId = null) {
|
||||
if (!SettingsStore.isFeature(settingName)) {
|
||||
throw new Error("Setting " + settingName + " is not a feature");
|
||||
}
|
||||
|
||||
// Synchronously get the setting value (which should be {enabled: true/false})
|
||||
const value = Promise.coroutine(function* () {
|
||||
return yield SettingsStore.getValue(settingName, roomId);
|
||||
})();
|
||||
|
||||
return value.enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of a setting. The room ID is optional if the setting is not to
|
||||
* be applied to any particular room, otherwise it should be supplied.
|
||||
* @param {string} settingName The name of the setting to read the value of.
|
||||
* @param {String} roomId The room ID to read the setting value in, may be null.
|
||||
* @return {Promise<*>} Resolves to the value for the setting. May result in null.
|
||||
*/
|
||||
static getValue(settingName, roomId) {
|
||||
const levelOrder = [
|
||||
'device', 'room-device', 'room-account', 'account', 'room', 'config', 'default'
|
||||
];
|
||||
|
||||
if (SettingsStore.isFeature(settingName)) {
|
||||
const configValue = SettingsStore._getFeatureState(settingName);
|
||||
if (configValue === "enable") return Promise.resolve({enabled: true});
|
||||
if (configValue === "disable") return Promise.resolve({enabled: false});
|
||||
// else let it fall through the default process
|
||||
}
|
||||
|
||||
const handlers = SettingsStore._getHandlers(settingName);
|
||||
|
||||
// This wrapper function allows for iterating over the levelOrder to find a suitable
|
||||
// handler that is supported by the setting. It does this by building the promise chain
|
||||
// on the fly, wrapping the rejection from handler.getValue() to try the next handler.
|
||||
// If the last handler also rejects the getValue() call, then this wrapper will convert
|
||||
// the reply to `null` as per our contract to the caller.
|
||||
let index = 0;
|
||||
const wrapperFn = () => {
|
||||
// Find the next handler that we can use
|
||||
let handler = null;
|
||||
while (!handler && index < levelOrder.length) {
|
||||
handler = handlers[levelOrder[index++]];
|
||||
}
|
||||
|
||||
// No handler == no reply (happens when the last available handler rejects)
|
||||
if (!handler) return null;
|
||||
|
||||
// Get the value and see if the handler will reject us (meaning it doesn't have
|
||||
// a value for us).
|
||||
const value = handler.getValue(settingName, roomId);
|
||||
return value.then(null, () => wrapperFn()); // pass success through
|
||||
};
|
||||
|
||||
return wrapperFn();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value for a setting. The room ID is optional if the setting is not being
|
||||
* set for a particular room, otherwise it should be supplied. The value may be null
|
||||
* to indicate that the level should no longer have an override.
|
||||
* @param {string} settingName The name of the setting to change.
|
||||
* @param {String} roomId The room ID to change the value in, may be null.
|
||||
* @param {"device"|"room-device"|"room-account"|"account"|"room"} level The level
|
||||
* to change the value at.
|
||||
* @param {Object} value The new value of the setting, may be null.
|
||||
* @return {Promise} Resolves when the setting has been changed.
|
||||
*/
|
||||
static setValue(settingName, roomId, level, value) {
|
||||
const handler = SettingsStore._getHandler(settingName, level);
|
||||
if (!handler) {
|
||||
throw new Error("Setting " + settingName + " does not have a handler for " + level);
|
||||
}
|
||||
|
||||
if (!handler.canSetValue(settingName, roomId)) {
|
||||
throw new Error("User cannot set " + settingName + " at level " + level);
|
||||
}
|
||||
|
||||
return handler.setValue(settingName, roomId, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the current user is permitted to set the given setting at the given
|
||||
* level for a particular room. The room ID is optional if the setting is not being
|
||||
* set for a particular room, otherwise it should be supplied.
|
||||
* @param {string} settingName The name of the setting to check.
|
||||
* @param {String} roomId The room ID to check in, may be null.
|
||||
* @param {"device"|"room-device"|"room-account"|"account"|"room"} level The level to
|
||||
* check at.
|
||||
* @return {boolean} True if the user may set the setting, false otherwise.
|
||||
*/
|
||||
static canSetValue(settingName, roomId, level) {
|
||||
const handler = SettingsStore._getHandler(settingName, level);
|
||||
if (!handler) return false;
|
||||
return handler.canSetValue(settingName, roomId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the given level is supported on this device.
|
||||
* @param {"device"|"room-device"|"room-account"|"account"|"room"} level The level
|
||||
* to check the feasibility of.
|
||||
* @return {boolean} True if the level is supported, false otherwise.
|
||||
*/
|
||||
static isLevelSupported(level) {
|
||||
if (!LEVEL_HANDLERS[level]) return false;
|
||||
return LEVEL_HANDLERS[level].isSupported();
|
||||
}
|
||||
|
||||
static _getHandler(settingName, level) {
|
||||
const handlers = SettingsStore._getHandlers(settingName);
|
||||
if (!handlers[level]) return null;
|
||||
return handlers[level];
|
||||
}
|
||||
|
||||
static _getHandlers(settingName) {
|
||||
if (!SETTINGS[settingName]) return {};
|
||||
|
||||
const handlers = {};
|
||||
for (let level of SETTINGS[settingName].supportedLevels) {
|
||||
if (!LEVEL_HANDLERS[level]) throw new Error("Unexpected level " + level);
|
||||
handlers[level] = LEVEL_HANDLERS[level];
|
||||
}
|
||||
|
||||
return handlers;
|
||||
}
|
||||
|
||||
static _getFeatureState(settingName) {
|
||||
const featuresConfig = SdkConfig.get()['features'];
|
||||
const enableLabs = SdkConfig.get()['enableLabs']; // we'll honour the old flag
|
||||
|
||||
let featureState = enableLabs ? "labs" : "disable";
|
||||
if (featuresConfig && featuresConfig[settingName] !== undefined) {
|
||||
featureState = featuresConfig[settingName];
|
||||
}
|
||||
|
||||
const allowedStates = ['enable', 'disable', 'labs'];
|
||||
if (!allowedStates.contains(featureState)) {
|
||||
console.warn("Feature state '" + featureState + "' is invalid for " + settingName);
|
||||
featureState = "disable"; // to prevent accidental features.
|
||||
}
|
||||
|
||||
return featureState;
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue