diff --git a/src/CallMediaHandler.js b/src/CallMediaHandler.js index 2c3c707102..cdc5c61921 100644 --- a/src/CallMediaHandler.js +++ b/src/CallMediaHandler.js @@ -15,7 +15,7 @@ */ import * as Matrix from 'matrix-js-sdk'; -import SettingsStore from "./settings/SettingsStore"; +import SettingsStore, {SettingLevel} from "./settings/SettingsStore"; export default { getDevices: function() { @@ -51,12 +51,12 @@ export default { }, setAudioInput: function(deviceId) { - SettingsStore.setValue("webrtc_audioinput", null, "device", deviceId); + SettingsStore.setValue("webrtc_audioinput", null, SettingLevel.DEVICE, deviceId); Matrix.setMatrixCallAudioInput(deviceId); }, setVideoInput: function(deviceId) { - SettingsStore.setValue("webrtc_videoinput", null, "device", deviceId); + SettingsStore.setValue("webrtc_videoinput", null, SettingLevel.DEVICE, deviceId); Matrix.setMatrixCallVideoInput(deviceId); }, }; diff --git a/src/UserSettingsStore.js b/src/UserSettingsStore.js index e69ebf2818..b5c7d2ed00 100644 --- a/src/UserSettingsStore.js +++ b/src/UserSettingsStore.js @@ -48,10 +48,12 @@ export default { // TODO }, + // TODO: {Travis} Granular setting getEnableNotifications: function() { return Notifier.isEnabled(); }, + // TODO: {Travis} Granular setting setEnableNotifications: function(enable) { if (!Notifier.supportsDesktopNotifications()) { return; @@ -59,10 +61,12 @@ export default { Notifier.setEnabled(enable); }, + // TODO: {Travis} Granular setting getEnableNotificationBody: function() { return Notifier.isBodyEnabled(); }, + // TODO: {Travis} Granular setting setEnableNotificationBody: function(enable) { if (!Notifier.supportsDesktopNotifications()) { return; @@ -70,10 +74,12 @@ export default { Notifier.setBodyEnabled(enable); }, + // TODO: {Travis} Granular setting getEnableAudioNotifications: function() { return Notifier.isAudioEnabled(); }, + // TODO: {Travis} Granular setting setEnableAudioNotifications: function(enable) { Notifier.setAudioEnabled(enable); }, diff --git a/src/components/structures/UserSettings.js b/src/components/structures/UserSettings.js index 228d82911c..342680e8da 100644 --- a/src/components/structures/UserSettings.js +++ b/src/components/structures/UserSettings.js @@ -15,7 +15,7 @@ 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 SettingsStore from "../../settings/SettingsStore"; +import SettingsStore, {SettingLevel} from "../../settings/SettingsStore"; const React = require('react'); const ReactDOM = require('react-dom'); @@ -282,8 +282,8 @@ module.exports = React.createClass({ if (this._unmounted) return; this.setState({ mediaDevices, - activeAudioInput: SettingsStore.getValueAt("device", 'webrtc_audioinput'), - activeVideoInput: SettingsStore.getValueAt("device", 'webrtc_videoinput'), + activeAudioInput: SettingsStore.getValueAt(SettingLevel.DEVICE, 'webrtc_audioinput'), + activeVideoInput: SettingsStore.getValueAt(SettingLevel.DEVICE, 'webrtc_videoinput'), }); }); }, @@ -616,7 +616,7 @@ module.exports = React.createClass({ onLanguageChange: function(newLang) { if(this.state.language !== newLang) { // We intentionally promote this to the account level at this point - SettingsStore.setValue("language", null, "account", newLang); + SettingsStore.setValue("language", null, SettingLevel.ACCOUNT, newLang); this.setState({ language: newLang, }); @@ -639,7 +639,7 @@ module.exports = React.createClass({ // TODO: this ought to be a separate component so that we don't need // to rebind the onChange each time we render const onChange = (e) => - SettingsStore.setValue("autocompleteDelay", null, "device", e.target.value); + SettingsStore.setValue("autocompleteDelay", null, SettingLevel.DEVICE, e.target.value); return (

{ _t("User Interface") }

@@ -653,7 +653,7 @@ module.exports = React.createClass({ @@ -672,7 +672,7 @@ module.exports = React.createClass({
); @@ -685,7 +685,7 @@ module.exports = React.createClass({
@@ -764,7 +764,7 @@ module.exports = React.createClass({
); diff --git a/src/components/structures/login/Login.js b/src/components/structures/login/Login.js index de79c57ec4..8864f9cefd 100644 --- a/src/components/structures/login/Login.js +++ b/src/components/structures/login/Login.js @@ -23,7 +23,7 @@ import * as languageHandler from '../../../languageHandler'; import sdk from '../../../index'; import Login from '../../../Login'; import PlatformPeg from '../../../PlatformPeg'; -import SettingsStore from "../../../settings/SettingsStore"; +import SettingsStore, {SettingLevel} from "../../../settings/SettingsStore"; // For validating phone numbers without country codes const PHONE_NUMBER_REGEX = /^[0-9\(\)\-\s]*$/; @@ -312,7 +312,7 @@ module.exports = React.createClass({ _onLanguageChange: function(newLang) { if(languageHandler.getCurrentLanguage() !== newLang) { - SettingsStore.setValue("language", null, "device", newLang); + SettingsStore.setValue("language", null, SettingLevel.DEVICE, newLang); PlatformPeg.get().reload(); } }, diff --git a/src/components/views/room_settings/UrlPreviewSettings.js b/src/components/views/room_settings/UrlPreviewSettings.js index 580d2660d8..7e8769268e 100644 --- a/src/components/views/room_settings/UrlPreviewSettings.js +++ b/src/components/views/room_settings/UrlPreviewSettings.js @@ -18,7 +18,7 @@ limitations under the License. const React = require('react'); const sdk = require("../../../index"); import { _t, _tJsx } from '../../../languageHandler'; -import SettingsStore from "../../../settings/SettingsStore"; +import SettingsStore, {SettingLevel} from "../../../settings/SettingsStore"; module.exports = React.createClass({ @@ -38,7 +38,7 @@ module.exports = React.createClass({ const roomId = this.props.room.roomId; let previewsForAccount = null; - if (SettingsStore.getValueAt("account", "urlPreviewsEnabled")) { + if (SettingsStore.getValueAt(SettingLevel.ACCOUNT, "urlPreviewsEnabled")) { previewsForAccount = ( _tJsx("You have enabled URL previews by default.", /(.*?)<\/a>/, (sub)=>{ sub }) ); @@ -54,14 +54,14 @@ module.exports = React.createClass({ previewsForRoom = ( ); } else { let str = "URL previews are enabled by default for participants in this room."; - if (!SettingsStore.getValueAt("room", "urlPreviewsEnabled")) { + if (!SettingsStore.getValueAt(SettingLevel.ROOM, "urlPreviewsEnabled")) { str = "URL previews are disabled by default for participants in this room."; } previewsForRoom = (); @@ -69,7 +69,7 @@ module.exports = React.createClass({ let previewsForRoomAccount = ( ); diff --git a/src/components/views/rooms/MessageComposer.js b/src/components/views/rooms/MessageComposer.js index eae9a98a8a..585900e2c0 100644 --- a/src/components/views/rooms/MessageComposer.js +++ b/src/components/views/rooms/MessageComposer.js @@ -22,7 +22,7 @@ import Modal from '../../../Modal'; import sdk from '../../../index'; import dis from '../../../dispatcher'; import Autocomplete from './Autocomplete'; -import SettingsStore from "../../../settings/SettingsStore"; +import SettingsStore, {SettingLevel} from "../../../settings/SettingsStore"; export default class MessageComposer extends React.Component { @@ -226,7 +226,7 @@ export default class MessageComposer extends React.Component { } onToggleFormattingClicked() { - SettingsStore.setValue("MessageComposer.showFormatting", null, "account", !this.state.showFormatting); + SettingsStore.setValue("MessageComposer.showFormatting", null, SettingLevel.DEVICE, !this.state.showFormatting); this.setState({showFormatting: !this.state.showFormatting}); } diff --git a/src/components/views/rooms/MessageComposerInput.js b/src/components/views/rooms/MessageComposerInput.js index 73f4728834..eef7f410cc 100644 --- a/src/components/views/rooms/MessageComposerInput.js +++ b/src/components/views/rooms/MessageComposerInput.js @@ -49,7 +49,7 @@ const REGEX_MATRIXTO = new RegExp(MATRIXTO_URL_PATTERN); const REGEX_MATRIXTO_MARKDOWN_GLOBAL = new RegExp(MATRIXTO_MD_LINK_PATTERN, 'g'); import {asciiRegexp, shortnameToUnicode, emojioneList, asciiList, mapUnicodeToShort} from 'emojione'; -import SettingsStore from "../../../settings/SettingsStore"; +import SettingsStore, {SettingLevel} from "../../../settings/SettingsStore"; const EMOJI_SHORTNAMES = Object.keys(emojioneList); const EMOJI_UNICODE_TO_SHORTNAME = mapUnicodeToShort(); const REGEX_EMOJI_WHITESPACE = new RegExp('(?:^|\\s)(' + asciiRegexp + ')\\s$'); @@ -535,7 +535,7 @@ export default class MessageComposerInput extends React.Component { editorState: this.createEditorState(enabled, contentState), isRichtextEnabled: enabled, }); - SettingsStore.setValue("MessageComposerInput.isRichTextEnabled", null, "account", enabled); + SettingsStore.setValue("MessageComposerInput.isRichTextEnabled", null, SettingLevel.ACCOUNT, enabled); } handleKeyCommand = (command: string): boolean => { diff --git a/src/components/views/rooms/RoomSettings.js b/src/components/views/rooms/RoomSettings.js index f38096b217..a7606a2bdd 100644 --- a/src/components/views/rooms/RoomSettings.js +++ b/src/components/views/rooms/RoomSettings.js @@ -24,7 +24,7 @@ import Modal from '../../../Modal'; import ObjectUtils from '../../../ObjectUtils'; import dis from '../../../dispatcher'; import AccessibleButton from '../elements/AccessibleButton'; -import SettingsStore from "../../../settings/SettingsStore"; +import SettingsStore, {SettingLevel} from "../../../settings/SettingsStore"; // parse a string as an integer; if the input is undefined, or cannot be parsed @@ -382,7 +382,7 @@ module.exports = React.createClass({ // TODO: {Travis} Use generic blacklistUnverifiedDevices const blacklistUnverifiedDevicesPerRoom = SettingsStore.getValue("blacklistUnverifiedDevicesPerRoom"); blacklistUnverifiedDevicesPerRoom[this.props.room.roomId] = value; - SettingsStore.setValue("blacklistUnverifiedDevicesPerRoom", null, "device", blacklistUnverifiedDevicesPerRoom); + SettingsStore.setValue("blacklistUnverifiedDevicesPerRoom", null, SettingLevel.DEVICE, blacklistUnverifiedDevicesPerRoom); this.props.room.setBlacklistUnverifiedDevices(value); }, diff --git a/src/languageHandler.js b/src/languageHandler.js index 6fd8d604b1..34b28e848f 100644 --- a/src/languageHandler.js +++ b/src/languageHandler.js @@ -19,7 +19,7 @@ import request from 'browser-request'; import counterpart from 'counterpart'; import Promise from 'bluebird'; import React from 'react'; -import SettingsStore from "./settings/SettingsStore"; +import SettingsStore, {SettingLevel} from "./settings/SettingsStore"; const i18nFolder = 'i18n/'; @@ -167,7 +167,7 @@ export function setLanguage(preferredLangs) { }).then((langData) => { counterpart.registerTranslations(langToUse, langData); counterpart.setLocale(langToUse); - SettingsStore.setValue("language", null, "device", langToUse); + SettingsStore.setValue("language", null, SettingLevel.DEVICE, langToUse); console.log("set language to " + langToUse); // Set 'en' as fallback language: diff --git a/src/settings/AccountSettingsHandler.js b/src/settings/AccountSettingsHandler.js index 5bda5bd910..5511851435 100644 --- a/src/settings/AccountSettingsHandler.js +++ b/src/settings/AccountSettingsHandler.js @@ -50,7 +50,8 @@ export default class AccountSettingHandler extends SettingsHandler { } isSupported() { - return !!MatrixClientPeg.get(); + const cli = MatrixClientPeg.get(); + return cli !== undefined && cli !== null; } _getSettings(eventType = "im.vector.web.settings") { diff --git a/src/settings/DeviceSettingsHandler.js b/src/settings/DeviceSettingsHandler.js index f15c651131..d4f5a5d727 100644 --- a/src/settings/DeviceSettingsHandler.js +++ b/src/settings/DeviceSettingsHandler.js @@ -59,7 +59,7 @@ export default class DeviceSettingsHandler extends SettingsHandler { } isSupported() { - return !!localStorage; + return localStorage !== undefined && localStorage !== null; } _getSettings() { diff --git a/src/settings/RoomAccountSettingsHandler.js b/src/settings/RoomAccountSettingsHandler.js index d8274d2ed9..682f76a05f 100644 --- a/src/settings/RoomAccountSettingsHandler.js +++ b/src/settings/RoomAccountSettingsHandler.js @@ -46,11 +46,14 @@ export default class RoomAccountSettingsHandler extends SettingsHandler { canSetValue(settingName, roomId) { const room = MatrixClientPeg.get().getRoom(roomId); - return !!room; // If they have the room, they can set their own account data + + // If they have the room, they can set their own account data + return room !== undefined && room !== null; } isSupported() { - return !!MatrixClientPeg.get(); + const cli = MatrixClientPeg.get(); + return cli !== undefined && cli !== null; } _getSettings(roomId, eventType = "im.vector.settings") { diff --git a/src/settings/RoomDeviceSettingsHandler.js b/src/settings/RoomDeviceSettingsHandler.js index b61e266a4a..394d8cd319 100644 --- a/src/settings/RoomDeviceSettingsHandler.js +++ b/src/settings/RoomDeviceSettingsHandler.js @@ -44,7 +44,7 @@ export default class RoomDeviceSettingsHandler extends SettingsHandler { } isSupported() { - return !!localStorage; + return localStorage !== undefined && localStorage !== null; } _getKey(settingName, roomId) { diff --git a/src/settings/RoomSettingsHandler.js b/src/settings/RoomSettingsHandler.js index 8f3f8fa1e4..fbdeec2c62 100644 --- a/src/settings/RoomSettingsHandler.js +++ b/src/settings/RoomSettingsHandler.js @@ -53,7 +53,8 @@ export default class RoomSettingsHandler extends SettingsHandler { } isSupported() { - return !!MatrixClientPeg.get(); + const cli = MatrixClientPeg.get(); + return cli !== undefined && cli !== null; } _getSettings(roomId, eventType = "im.vector.web.settings") { diff --git a/src/settings/Settings.js b/src/settings/Settings.js new file mode 100644 index 0000000000..7ce6b8b02c --- /dev/null +++ b/src/settings/Settings.js @@ -0,0 +1,198 @@ +/* +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 {_td} from '../languageHandler'; + + +// These are just a bunch of helper arrays to avoid copy/pasting a bunch of times +const LEVELS_ROOM_SETTINGS = ['device', 'room-device', 'room-account', 'account', 'config']; +const LEVELS_ROOM_SETTINGS_WITH_ROOM = ['device', 'room-device', 'room-account', 'account', 'config', 'room']; +const LEVELS_ACCOUNT_SETTINGS = ['device', 'account', 'config']; +const LEVELS_FEATURE = ['device', 'config']; +const LEVELS_DEVICE_ONLY_SETTINGS = ['device']; +const LEVELS_DEVICE_ONLY_SETTINGS_WITH_CONFIG = ['device', 'config']; + +export const SETTINGS = { + // EXAMPLE SETTING: + // "my-setting": { + // // Required by features, optional otherwise + // isFeature: false, + // + // // Recommended. + // displayName: _td("Cool Name"), + // + // // Required. + // 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) + // "config", // Affects the current application + // + // // "default" is always supported and does not get listed here. + // ], + // + // // Optional. Any data type. + // default: { + // your: "value", + // }, + // }, + "feature_groups": { + isFeature: true, + displayName: _td("Communities"), + supportedLevels: LEVELS_FEATURE, + }, + "feature_pinning": { + isFeature: true, + displayName: _td("Message Pinning"), + supportedLevels: LEVELS_FEATURE, + }, + "MessageComposerInput.dontSuggestEmoji": { + supportedLevels: LEVELS_ACCOUNT_SETTINGS, + displayName: _td('Disable Emoji suggestions while typing'), + default: false, + }, + "useCompactLayout": { + supportedLevels: LEVELS_ACCOUNT_SETTINGS, + displayName: _td('Use compact timeline layout'), + default: false, + }, + "hideRedactions": { + supportedLevels: LEVELS_ROOM_SETTINGS_WITH_ROOM, + displayName: _td('Hide removed messages'), + default: false, + }, + "hideJoinLeaves": { + supportedLevels: LEVELS_ROOM_SETTINGS_WITH_ROOM, + displayName: _td('Hide join/leave messages (invites/kicks/bans unaffected)'), + default: false, + }, + "hideAvatarDisplaynameChanges": { + supportedLevels: LEVELS_ROOM_SETTINGS_WITH_ROOM, + displayName: _td('Hide avatar and display name changes'), + default: false, + }, + "hideReadReceipts": { + supportedLevels: LEVELS_ROOM_SETTINGS, + displayName: _td('Hide read receipts'), + default: false, + }, + "showTwelveHourTimestamps": { + supportedLevels: LEVELS_ACCOUNT_SETTINGS, + displayName: _td('Show timestamps in 12 hour format (e.g. 2:30pm)'), + default: false, + }, + "alwaysShowTimestamps": { + supportedLevels: LEVELS_ACCOUNT_SETTINGS, + displayName: _td('Always show message timestamps'), + default: false, + }, + "autoplayGifsAndVideos": { + supportedLevels: LEVELS_ACCOUNT_SETTINGS, + displayName: _td('Autoplay GIFs and videos'), + default: false, + }, + "enableSyntaxHighlightLanguageDetection": { + supportedLevels: LEVELS_ACCOUNT_SETTINGS, + displayName: _td('Enable automatic language detection for syntax highlighting'), + default: false, + }, + "Pill.shouldHidePillAvatar": { + supportedLevels: LEVELS_ACCOUNT_SETTINGS, + displayName: _td('Hide avatars in user and room mentions'), + default: false, + }, + "TextualBody.disableBigEmoji": { + supportedLevels: LEVELS_ACCOUNT_SETTINGS, + displayName: _td('Disable big emoji in chat'), + default: false, + }, + "MessageComposerInput.isRichTextEnabled": { + supportedLevels: LEVELS_ACCOUNT_SETTINGS, + default: false, + }, + "MessageComposer.showFormatting": { + supportedLevels: LEVELS_ACCOUNT_SETTINGS, + default: false, + }, + "dontSendTypingNotifications": { + supportedLevels: LEVELS_ACCOUNT_SETTINGS, + displayName: _td("Don't send typing notifications"), + default: false, + }, + "MessageComposerInput.autoReplaceEmoji": { + supportedLevels: LEVELS_ACCOUNT_SETTINGS, + displayName: _td('Automatically replace plain text Emoji'), + default: false, + }, + "VideoView.flipVideoHorizontally": { + supportedLevels: LEVELS_ACCOUNT_SETTINGS, + displayName: _td('Mirror local video feed'), + default: false, + }, + "theme": { + supportedLevels: LEVELS_ACCOUNT_SETTINGS, + default: "light", + }, + "webRtcForceTURN": { + supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS_WITH_CONFIG, + displayName: _td('Disable Peer-to-Peer for 1:1 calls'), + default: false, + }, + "webrtc_audioinput": { + supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS, + }, + "webrtc_videoinput": { + supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS, + }, + "language": { + supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS_WITH_CONFIG, + default: "en" + }, + "analyticsOptOut": { + supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS_WITH_CONFIG, + displayName: _td('Opt out of analytics'), + default: false, + }, + "autocompleteDelay": { + supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS_WITH_CONFIG, + default: 200, + }, + "blacklistUnverifiedDevicesPerRoom": { + // TODO: {Travis} Write a migration path to support blacklistUnverifiedDevices + supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS, + displayName: _td('Never send encrypted messages to unverified devices from this device'), + default: {}, + }, + "blacklistUnverifiedDevices": { + // TODO: {Travis} Write a migration path to support blacklistUnverifiedDevices + supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS, + displayName: _td('Never send encrypted messages to unverified devices from this device'), + default: false, + }, + "urlPreviewsEnabled": { + supportedLevels: LEVELS_ROOM_SETTINGS_WITH_ROOM, + displayName: { + "default": _td('Enable inline URL previews by default'), + "room-account": _td("Enable URL previews for this room (only affects you)"), + "room": _td("Enable URL previews by default for participants in this room"), + }, + default: true, + }, +}; \ No newline at end of file diff --git a/src/settings/SettingsStore.js b/src/settings/SettingsStore.js index 3fe569e387..4f0f3061eb 100644 --- a/src/settings/SettingsStore.js +++ b/src/settings/SettingsStore.js @@ -22,190 +22,27 @@ import RoomAccountSettingsHandler from "./RoomAccountSettingsHandler"; import AccountSettingsHandler from "./AccountSettingsHandler"; import RoomSettingsHandler from "./RoomSettingsHandler"; import ConfigSettingsHandler from "./ConfigSettingsHandler"; -import {_t, _td} from '../languageHandler'; +import {_t} from '../languageHandler'; import SdkConfig from "../SdkConfig"; +import {SETTINGS} from "./Settings"; -// 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', 'config']; - -// Preset levels for account-based settings (eg: interface language). -const LEVELS_PRESET_ACCOUNT = ['device', 'account', 'config']; - -// Preset levels for features (labs) settings. -const LEVELS_PRESET_FEATURE = ['device', 'config']; - -const SETTINGS = { - // EXAMPLE SETTING: - // "my-setting": { - // // Required by features, optional otherwise - // isFeature: false, - // displayName: _td("Cool Name"), - // - // // Required. - // 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) - // "config", // Affects the current application - // - // // "default" is always supported and does not get listed here. - // ], - // - // // Optional. Any data type. - // default: { - // your: "value", - // }, - // }, - "feature_groups": { - isFeature: true, - displayName: _td("Communities"), - supportedLevels: LEVELS_PRESET_FEATURE, - }, - "feature_pinning": { - isFeature: true, - displayName: _td("Message Pinning"), - supportedLevels: LEVELS_PRESET_FEATURE, - }, - "MessageComposerInput.dontSuggestEmoji": { - supportedLevels: LEVELS_PRESET_ACCOUNT, - default: false, - displayName: _td('Disable Emoji suggestions while typing'), - }, - "useCompactLayout": { - supportedLevels: LEVELS_PRESET_ACCOUNT, - default: false, - displayName: _td('Use compact timeline layout'), - }, - "hideRedactions": { - supportedLevels: LEVELS_PRESET_ROOM.concat("room"), - default: false, - displayName: _td('Hide removed messages'), - }, - "hideJoinLeaves": { - supportedLevels: LEVELS_PRESET_ROOM.concat("room"), - default: false, - displayName: _td('Hide join/leave messages (invites/kicks/bans unaffected)'), - }, - "hideAvatarDisplaynameChanges": { - supportedLevels: LEVELS_PRESET_ROOM.concat("room"), - default: false, - displayName: _td('Hide avatar and display name changes'), - }, - "hideReadReceipts": { - supportedLevels: LEVELS_PRESET_ROOM, - default: false, - displayName: _td('Hide read receipts'), - }, - "showTwelveHourTimestamps": { - supportedLevels: LEVELS_PRESET_ACCOUNT, - default: false, - displayName: _td('Show timestamps in 12 hour format (e.g. 2:30pm)'), - }, - "alwaysShowTimestamps": { - supportedLevels: LEVELS_PRESET_ACCOUNT, - default: false, - displayName: _td('Always show message timestamps'), - }, - "autoplayGifsAndVideos": { - supportedLevels: LEVELS_PRESET_ACCOUNT, - default: false, - displayName: _td('Autoplay GIFs and videos'), - }, - "enableSyntaxHighlightLanguageDetection": { - supportedLevels: LEVELS_PRESET_ACCOUNT, - default: false, - displayName: _td('Enable automatic language detection for syntax highlighting'), - }, - "Pill.shouldHidePillAvatar": { - supportedLevels: LEVELS_PRESET_ACCOUNT, - default: false, - displayName: _td('Hide avatars in user and room mentions'), - }, - "TextualBody.disableBigEmoji": { - supportedLevels: LEVELS_PRESET_ACCOUNT, - default: false, - displayName: _td('Disable big emoji in chat'), - }, - "MessageComposerInput.isRichTextEnabled": { - supportedLevels: LEVELS_PRESET_ACCOUNT, - default: false, - }, - "MessageComposer.showFormatting": { - supportedLevels: LEVELS_PRESET_ACCOUNT, - default: false, - }, - "dontSendTypingNotifications": { - supportedLevels: LEVELS_PRESET_ACCOUNT, - default: false, - displayName: _td("Don't send typing notifications"), - }, - "MessageComposerInput.autoReplaceEmoji": { - supportedLevels: LEVELS_PRESET_ACCOUNT, - default: false, - displayName: _td('Automatically replace plain text Emoji'), - }, - "VideoView.flipVideoHorizontally": { - supportedLevels: LEVELS_PRESET_ACCOUNT, - default: false, - displayName: _td('Mirror local video feed'), - }, - "theme": { - supportedLevels: LEVELS_PRESET_ACCOUNT, - default: "light", - }, - "webRtcForceTURN": { - supportedLevels: ['device', 'config'], - default: false, - displayName: _td('Disable Peer-to-Peer for 1:1 calls'), - }, - "webrtc_audioinput": { - supportedLevels: ['device'], - }, - "webrtc_videoinput": { - supportedLevels: ['device'], - }, - "language": { - supportedLevels: ['device', 'config'], - default: "en" - }, - "analyticsOptOut": { - supportedLevels: ['device', 'config'], - default: false, - displayName: _td('Opt out of analytics'), - }, - "autocompleteDelay": { - supportedLevels: ['device', 'config'], - default: 200, - }, - "blacklistUnverifiedDevicesPerRoom": { - // TODO: {Travis} Write a migration path to support blacklistUnverifiedDevices - supportedLevels: ['device'], - default: {}, - displayName: _td('Never send encrypted messages to unverified devices from this device'), - }, - "blacklistUnverifiedDevices": { - // TODO: {Travis} Write a migration path to support blacklistUnverifiedDevices - supportedLevels: ['device'], - default: false, - displayName: _td('Never send encrypted messages to unverified devices from this device'), - }, - "urlPreviewsEnabled": { - supportedLevels: LEVELS_PRESET_ROOM.concat("room"), - default: true, - displayName: { - "default": _td('Enable inline URL previews by default'), - "room-account": _td("Enable URL previews for this room (only affects you)"), - "room": _td("Enable URL previews by default for participants in this room"), - }, - }, +/** + * Represents the various setting levels supported by the SettingsStore. + */ +export const SettingLevel = { + // Note: This enum is not used in this class or in the Settings file + // This should always be used elsewhere in the project. + DEVICE: "device", + ROOM_DEVICE: "room-device", + ROOM_ACCOUNT: "room-account", + ACCOUNT: "account", + ROOM: "room", + CONFIG: "config", + DEFAULT: "default", }; -// Convert the above into simpler formats for the handlers + +// Convert the settings to easier to manage objects for the handlers const defaultSettings = {}; const featureNames = []; for (const key of Object.keys(SETTINGS)) {