diff --git a/src/@types/global.d.ts b/src/@types/global.d.ts index 080cdacafd..6510c02160 100644 --- a/src/@types/global.d.ts +++ b/src/@types/global.d.ts @@ -25,6 +25,7 @@ import { PlatformPeg } from "../PlatformPeg"; import RoomListLayoutStore from "../stores/room-list/RoomListLayoutStore"; import {IntegrationManagers} from "../integrations/IntegrationManagers"; import {ModalManager} from "../Modal"; +import SettingsStore from "../settings/SettingsStore"; declare global { interface Window { @@ -43,6 +44,7 @@ declare global { mxPlatformPeg: PlatformPeg; mxIntegrationManagers: typeof IntegrationManagers; singletonModalManager: ModalManager; + mxSettingsStore: SettingsStore; } // workaround for https://github.com/microsoft/TypeScript/issues/30933 diff --git a/src/CallHandler.js b/src/CallHandler.js index 4414bce457..d5e058ef1e 100644 --- a/src/CallHandler.js +++ b/src/CallHandler.js @@ -62,10 +62,11 @@ import Matrix from 'matrix-js-sdk'; import dis from './dispatcher/dispatcher'; import WidgetUtils from './utils/WidgetUtils'; import WidgetEchoStore from './stores/WidgetEchoStore'; -import SettingsStore, { SettingLevel } from './settings/SettingsStore'; +import SettingsStore from './settings/SettingsStore'; import {generateHumanReadableId} from "./utils/NamingUtils"; import {Jitsi} from "./widgets/Jitsi"; import {WidgetType} from "./widgets/WidgetType"; +import {SettingLevel} from "./settings/SettingLevel"; global.mxCalls = { //room_id: MatrixCall diff --git a/src/CallMediaHandler.js b/src/CallMediaHandler.js index a0364f798a..8d56467c57 100644 --- a/src/CallMediaHandler.js +++ b/src/CallMediaHandler.js @@ -15,7 +15,8 @@ */ import * as Matrix from 'matrix-js-sdk'; -import SettingsStore, {SettingLevel} from "./settings/SettingsStore"; +import SettingsStore from "./settings/SettingsStore"; +import {SettingLevel} from "./settings/SettingLevel"; export default { hasAnyLabeledDevices: async function() { diff --git a/src/MatrixClientPeg.ts b/src/MatrixClientPeg.ts index 5f334a639c..be16f5fe10 100644 --- a/src/MatrixClientPeg.ts +++ b/src/MatrixClientPeg.ts @@ -256,7 +256,7 @@ class _MatrixClientPeg implements IMatrixClientPeg { deviceId: creds.deviceId, pickleKey: creds.pickleKey, timelineSupport: true, - forceTURN: !SettingsStore.getValue('webRtcAllowPeerToPeer', false), + forceTURN: !SettingsStore.getValue('webRtcAllowPeerToPeer'), fallbackICEServerAllowed: !!SettingsStore.getValue('fallbackICEServerAllowed'), verificationMethods: [ verificationMethods.SAS, diff --git a/src/Notifier.js b/src/Notifier.js index c6fc7d7985..2ed302267e 100644 --- a/src/Notifier.js +++ b/src/Notifier.js @@ -27,10 +27,11 @@ import dis from './dispatcher/dispatcher'; import * as sdk from './index'; import { _t } from './languageHandler'; import Modal from './Modal'; -import SettingsStore, {SettingLevel} from "./settings/SettingsStore"; +import SettingsStore from "./settings/SettingsStore"; import { hideToast as hideNotificationsToast, } from "./toasts/DesktopNotificationsToast"; +import {SettingLevel} from "./settings/SettingLevel"; /* * Dispatches: diff --git a/src/async-components/views/dialogs/eventindex/DisableEventIndexDialog.js b/src/async-components/views/dialogs/eventindex/DisableEventIndexDialog.js index ec4b88f759..de50feaedb 100644 --- a/src/async-components/views/dialogs/eventindex/DisableEventIndexDialog.js +++ b/src/async-components/views/dialogs/eventindex/DisableEventIndexDialog.js @@ -20,9 +20,10 @@ import PropTypes from 'prop-types'; import dis from "../../../../dispatcher/dispatcher"; import { _t } from '../../../../languageHandler'; -import SettingsStore, {SettingLevel} from "../../../../settings/SettingsStore"; +import SettingsStore from "../../../../settings/SettingsStore"; import EventIndexPeg from "../../../../indexing/EventIndexPeg"; import {Action} from "../../../../dispatcher/actions"; +import {SettingLevel} from "../../../../settings/SettingLevel"; /* * Allows the user to disable the Event Index. diff --git a/src/async-components/views/dialogs/eventindex/ManageEventIndexDialog.js b/src/async-components/views/dialogs/eventindex/ManageEventIndexDialog.js index a9dd5be34b..be3368b87b 100644 --- a/src/async-components/views/dialogs/eventindex/ManageEventIndexDialog.js +++ b/src/async-components/views/dialogs/eventindex/ManageEventIndexDialog.js @@ -19,11 +19,12 @@ import * as sdk from '../../../../index'; import PropTypes from 'prop-types'; import { _t } from '../../../../languageHandler'; import SdkConfig from '../../../../SdkConfig'; -import SettingsStore, {SettingLevel} from "../../../../settings/SettingsStore"; +import SettingsStore from "../../../../settings/SettingsStore"; import Modal from '../../../../Modal'; import {formatBytes, formatCountLong} from "../../../../utils/FormattingUtils"; import EventIndexPeg from "../../../../indexing/EventIndexPeg"; +import {SettingLevel} from "../../../../settings/SettingLevel"; /* * Allows the user to introspect the event index state and disable it. diff --git a/src/components/structures/MatrixChat.tsx b/src/components/structures/MatrixChat.tsx index e68e1c53ae..a66d4c043f 100644 --- a/src/components/structures/MatrixChat.tsx +++ b/src/components/structures/MatrixChat.tsx @@ -51,7 +51,7 @@ import { getHomePageUrl } from '../../utils/pages'; import createRoom from "../../createRoom"; import {_t, _td, getCurrentLanguage} from '../../languageHandler'; -import SettingsStore, { SettingLevel } from "../../settings/SettingsStore"; +import SettingsStore from "../../settings/SettingsStore"; import ThemeController from "../../settings/controllers/ThemeController"; import { startAnyRegistrationFlow } from "../../Registration.js"; import { messageForSyncError } from '../../utils/ErrorUtils'; @@ -75,6 +75,7 @@ import {showToast as showNotificationsToast} from "../../toasts/DesktopNotificat import { OpenToTabPayload } from "../../dispatcher/payloads/OpenToTabPayload"; import ErrorDialog from "../views/dialogs/ErrorDialog"; import { RoomNotificationStateStore } from "../../stores/notifications/RoomNotificationStateStore"; +import { SettingLevel } from "../../settings/SettingLevel"; /** constants for MatrixChat.state.view */ export enum Views { diff --git a/src/components/structures/RoomView.js b/src/components/structures/RoomView.js index 7dc2d57ff0..f585a97fde 100644 --- a/src/components/structures/RoomView.js +++ b/src/components/structures/RoomView.js @@ -48,7 +48,7 @@ import RightPanel from './RightPanel'; import RoomViewStore from '../../stores/RoomViewStore'; import RoomScrollStateStore from '../../stores/RoomScrollStateStore'; import WidgetEchoStore from '../../stores/WidgetEchoStore'; -import SettingsStore, {SettingLevel} from "../../settings/SettingsStore"; +import SettingsStore from "../../settings/SettingsStore"; import AccessibleButton from "../views/elements/AccessibleButton"; import RightPanelStore from "../../stores/RightPanelStore"; import {haveTileForEvent} from "../views/rooms/EventTile"; @@ -56,6 +56,7 @@ import RoomContext from "../../contexts/RoomContext"; import MatrixClientContext from "../../contexts/MatrixClientContext"; import { shieldStatusForRoom } from '../../utils/ShieldUtils'; import {Action} from "../../dispatcher/actions"; +import {SettingLevel} from "../../settings/SettingLevel"; const DEBUG = false; let debuglog = function() {}; diff --git a/src/components/structures/UserMenu.tsx b/src/components/structures/UserMenu.tsx index 8f9ca8d734..3f2e387ccb 100644 --- a/src/components/structures/UserMenu.tsx +++ b/src/components/structures/UserMenu.tsx @@ -26,7 +26,7 @@ import { OpenToTabPayload } from "../../dispatcher/payloads/OpenToTabPayload"; import RedesignFeedbackDialog from "../views/dialogs/RedesignFeedbackDialog"; import Modal from "../../Modal"; import LogoutDialog from "../views/dialogs/LogoutDialog"; -import SettingsStore, {SettingLevel} from "../../settings/SettingsStore"; +import SettingsStore from "../../settings/SettingsStore"; import {getCustomTheme} from "../../theme"; import {getHostingLink} from "../../utils/HostingLink"; import {ButtonEvent} from "../views/elements/AccessibleButton"; @@ -37,6 +37,7 @@ import { UPDATE_EVENT } from "../../stores/AsyncStore"; import BaseAvatar from '../views/avatars/BaseAvatar'; import classNames from "classnames"; import AccessibleTooltipButton from "../views/elements/AccessibleTooltipButton"; +import { SettingLevel } from "../../settings/SettingLevel"; interface IProps { isMinimized: boolean; diff --git a/src/components/views/auth/LanguageSelector.js b/src/components/views/auth/LanguageSelector.js index 83db5d225b..0738ee43e4 100644 --- a/src/components/views/auth/LanguageSelector.js +++ b/src/components/views/auth/LanguageSelector.js @@ -16,10 +16,11 @@ limitations under the License. import SdkConfig from "../../../SdkConfig"; import {getCurrentLanguage} from "../../../languageHandler"; -import SettingsStore, {SettingLevel} from "../../../settings/SettingsStore"; +import SettingsStore from "../../../settings/SettingsStore"; import PlatformPeg from "../../../PlatformPeg"; import * as sdk from '../../../index'; import React from 'react'; +import {SettingLevel} from "../../../settings/SettingLevel"; function onChange(newLang) { if (getCurrentLanguage() !== newLang) { diff --git a/src/components/views/dialogs/AskInviteAnywayDialog.js b/src/components/views/dialogs/AskInviteAnywayDialog.js index 120ad8deca..7a12d2bd20 100644 --- a/src/components/views/dialogs/AskInviteAnywayDialog.js +++ b/src/components/views/dialogs/AskInviteAnywayDialog.js @@ -19,8 +19,8 @@ import PropTypes from 'prop-types'; import createReactClass from 'create-react-class'; import * as sdk from '../../../index'; import { _t } from '../../../languageHandler'; -import {SettingLevel} from "../../../settings/SettingsStore"; import SettingsStore from "../../../settings/SettingsStore"; +import {SettingLevel} from "../../../settings/SettingLevel"; export default createReactClass({ propTypes: { diff --git a/src/components/views/dialogs/WidgetOpenIDPermissionsDialog.js b/src/components/views/dialogs/WidgetOpenIDPermissionsDialog.js index 162cb4736a..42a5304f13 100644 --- a/src/components/views/dialogs/WidgetOpenIDPermissionsDialog.js +++ b/src/components/views/dialogs/WidgetOpenIDPermissionsDialog.js @@ -17,10 +17,11 @@ limitations under the License. import React from 'react'; import PropTypes from 'prop-types'; import {_t} from "../../../languageHandler"; -import SettingsStore, {SettingLevel} from "../../../settings/SettingsStore"; +import SettingsStore from "../../../settings/SettingsStore"; import * as sdk from "../../../index"; import LabelledToggleSwitch from "../elements/LabelledToggleSwitch"; import WidgetUtils from "../../../utils/WidgetUtils"; +import {SettingLevel} from "../../../settings/SettingLevel"; export default class WidgetOpenIDPermissionsDialog extends React.Component { static propTypes = { diff --git a/src/components/views/elements/AppTile.js b/src/components/views/elements/AppTile.js index 3e4418f945..d0fc56743f 100644 --- a/src/components/views/elements/AppTile.js +++ b/src/components/views/elements/AppTile.js @@ -35,12 +35,13 @@ import dis from '../../../dispatcher/dispatcher'; import ActiveWidgetStore from '../../../stores/ActiveWidgetStore'; import classNames from 'classnames'; import {IntegrationManagers} from "../../../integrations/IntegrationManagers"; -import SettingsStore, {SettingLevel} from "../../../settings/SettingsStore"; +import SettingsStore from "../../../settings/SettingsStore"; import {aboveLeftOf, ContextMenu, ContextMenuButton} from "../../structures/ContextMenu"; import PersistedElement from "./PersistedElement"; import {WidgetType} from "../../../widgets/WidgetType"; import {Capability} from "../../../widgets/WidgetApi"; import {sleep} from "../../../utils/promise"; +import {SettingLevel} from "../../../settings/SettingLevel"; const ALLOWED_APP_URL_SCHEMES = ['https:', 'http:']; const ENABLE_REACT_PERF = false; diff --git a/src/components/views/elements/IRCTimelineProfileResizer.tsx b/src/components/views/elements/IRCTimelineProfileResizer.tsx index 65140707d5..1098d0293e 100644 --- a/src/components/views/elements/IRCTimelineProfileResizer.tsx +++ b/src/components/views/elements/IRCTimelineProfileResizer.tsx @@ -15,8 +15,9 @@ limitations under the License. */ import React from 'react'; -import SettingsStore, {SettingLevel} from "../../../settings/SettingsStore"; +import SettingsStore from "../../../settings/SettingsStore"; import Draggable, {ILocationState} from './Draggable'; +import { SettingLevel } from "../../../settings/SettingLevel"; interface IProps { // Current room diff --git a/src/components/views/elements/SettingsFlag.tsx b/src/components/views/elements/SettingsFlag.tsx index 4f41db51e2..03e91fac62 100644 --- a/src/components/views/elements/SettingsFlag.tsx +++ b/src/components/views/elements/SettingsFlag.tsx @@ -20,11 +20,12 @@ import SettingsStore from "../../../settings/SettingsStore"; import { _t } from '../../../languageHandler'; import ToggleSwitch from "./ToggleSwitch"; import StyledCheckbox from "./StyledCheckbox"; +import { SettingLevel } from "../../../settings/SettingLevel"; interface IProps { // The setting must be a boolean name: string; - level: string; + level: SettingLevel; roomId?: string; // for per-room settings label?: string; // untranslated isExplicit?: boolean; @@ -52,8 +53,8 @@ export default class SettingsFlag extends React.Component { }; } - private onChange = (checked: boolean): void => { - this.save(checked); + private onChange = async (checked: boolean) => { + await this.save(checked); this.setState({ value: checked }); if (this.props.onChange) this.props.onChange(checked); }; @@ -62,8 +63,8 @@ export default class SettingsFlag extends React.Component { this.onChange(e.target.checked); }; - private save = (val?: boolean): void => { - return SettingsStore.setValue( + private save = async (val?: boolean) => { + await SettingsStore.setValue( this.props.name, this.props.roomId, this.props.level, diff --git a/src/components/views/room_settings/ColorSettings.js b/src/components/views/room_settings/ColorSettings.js index 1d26e956ab..4e8b6ba42f 100644 --- a/src/components/views/room_settings/ColorSettings.js +++ b/src/components/views/room_settings/ColorSettings.js @@ -20,7 +20,8 @@ import createReactClass from 'create-react-class'; import Tinter from '../../../Tinter'; import dis from '../../../dispatcher/dispatcher'; -import SettingsStore, {SettingLevel} from "../../../settings/SettingsStore"; +import SettingsStore from "../../../settings/SettingsStore"; +import {SettingLevel} from "../../../settings/SettingLevel"; const ROOM_COLORS = [ // magic room default values courtesy of Ribot diff --git a/src/components/views/room_settings/UrlPreviewSettings.js b/src/components/views/room_settings/UrlPreviewSettings.js index 51f6954975..fa5c1baf8f 100644 --- a/src/components/views/room_settings/UrlPreviewSettings.js +++ b/src/components/views/room_settings/UrlPreviewSettings.js @@ -22,10 +22,11 @@ import PropTypes from 'prop-types'; import createReactClass from 'create-react-class'; import * as sdk from "../../../index"; import { _t, _td } from '../../../languageHandler'; -import SettingsStore, {SettingLevel} from "../../../settings/SettingsStore"; +import SettingsStore from "../../../settings/SettingsStore"; import dis from "../../../dispatcher/dispatcher"; import {MatrixClientPeg} from "../../../MatrixClientPeg"; import {Action} from "../../../dispatcher/actions"; +import {SettingLevel} from "../../../settings/SettingLevel"; export default createReactClass({ diff --git a/src/components/views/rooms/RoomRecoveryReminder.js b/src/components/views/rooms/RoomRecoveryReminder.js index a29467b07f..859df6dd1b 100644 --- a/src/components/views/rooms/RoomRecoveryReminder.js +++ b/src/components/views/rooms/RoomRecoveryReminder.js @@ -21,7 +21,8 @@ import * as sdk from "../../../index"; import { _t } from "../../../languageHandler"; import Modal from "../../../Modal"; import {MatrixClientPeg} from "../../../MatrixClientPeg"; -import SettingsStore, {SettingLevel} from "../../../settings/SettingsStore"; +import SettingsStore from "../../../settings/SettingsStore"; +import {SettingLevel} from "../../../settings/SettingLevel"; export default class RoomRecoveryReminder extends React.PureComponent { static propTypes = { diff --git a/src/components/views/settings/E2eAdvancedPanel.js b/src/components/views/settings/E2eAdvancedPanel.js index 709465bcb0..2ba6190a9b 100644 --- a/src/components/views/settings/E2eAdvancedPanel.js +++ b/src/components/views/settings/E2eAdvancedPanel.js @@ -18,7 +18,7 @@ import React from 'react'; import * as sdk from '../../../index'; import {_t} from "../../../languageHandler"; -import {SettingLevel} from "../../../settings/SettingsStore"; +import {SettingLevel} from "../../../settings/SettingLevel"; const SETTING_MANUALLY_VERIFY_ALL_SESSIONS = "e2ee.manuallyVerifyAllSessions"; diff --git a/src/components/views/settings/EventIndexPanel.js b/src/components/views/settings/EventIndexPanel.js index 6fd1247c4b..35c751d91e 100644 --- a/src/components/views/settings/EventIndexPanel.js +++ b/src/components/views/settings/EventIndexPanel.js @@ -20,10 +20,11 @@ import { _t } from '../../../languageHandler'; import SdkConfig from "../../../SdkConfig"; import * as sdk from '../../../index'; import Modal from '../../../Modal'; -import SettingsStore, {SettingLevel} from "../../../settings/SettingsStore"; +import SettingsStore from "../../../settings/SettingsStore"; import AccessibleButton from "../elements/AccessibleButton"; import {formatBytes, formatCountLong} from "../../../utils/FormattingUtils"; import EventIndexPeg from "../../../indexing/EventIndexPeg"; +import {SettingLevel} from "../../../settings/SettingLevel"; export default class EventIndexPanel extends React.Component { constructor() { diff --git a/src/components/views/settings/Notifications.js b/src/components/views/settings/Notifications.js index cbdf3ec1a7..5c16e1ed4f 100644 --- a/src/components/views/settings/Notifications.js +++ b/src/components/views/settings/Notifications.js @@ -20,7 +20,7 @@ import createReactClass from 'create-react-class'; import * as sdk from '../../../index'; import { _t } from '../../../languageHandler'; import {MatrixClientPeg} from '../../../MatrixClientPeg'; -import SettingsStore, {SettingLevel} from '../../../settings/SettingsStore'; +import SettingsStore from '../../../settings/SettingsStore'; import Modal from '../../../Modal'; import { NotificationUtils, @@ -31,6 +31,7 @@ import { import SdkConfig from "../../../SdkConfig"; import LabelledToggleSwitch from "../elements/LabelledToggleSwitch"; import AccessibleButton from "../elements/AccessibleButton"; +import {SettingLevel} from "../../../settings/SettingLevel"; // TODO: this "view" component still has far too much application logic in it, // which should be factored out to other files. diff --git a/src/components/views/settings/SetIntegrationManager.js b/src/components/views/settings/SetIntegrationManager.js index da2953482f..e6fb3f6e1c 100644 --- a/src/components/views/settings/SetIntegrationManager.js +++ b/src/components/views/settings/SetIntegrationManager.js @@ -18,7 +18,8 @@ import React from 'react'; import {_t} from "../../../languageHandler"; import {IntegrationManagers} from "../../../integrations/IntegrationManagers"; import * as sdk from '../../../index'; -import SettingsStore, {SettingLevel} from "../../../settings/SettingsStore"; +import SettingsStore from "../../../settings/SettingsStore"; +import {SettingLevel} from "../../../settings/SettingLevel"; export default class SetIntegrationManager extends React.Component { constructor() { diff --git a/src/components/views/settings/tabs/room/NotificationSettingsTab.js b/src/components/views/settings/tabs/room/NotificationSettingsTab.js index 257f4a5d23..dd88b5018f 100644 --- a/src/components/views/settings/tabs/room/NotificationSettingsTab.js +++ b/src/components/views/settings/tabs/room/NotificationSettingsTab.js @@ -21,7 +21,7 @@ import {MatrixClientPeg} from "../../../../../MatrixClientPeg"; import AccessibleButton from "../../../elements/AccessibleButton"; import Notifier from "../../../../../Notifier"; import SettingsStore from '../../../../../settings/SettingsStore'; -import { SettingLevel } from '../../../../../settings/SettingsStore'; +import {SettingLevel} from "../../../../../settings/SettingLevel"; export default class NotificationsSettingsTab extends React.Component { static propTypes = { diff --git a/src/components/views/settings/tabs/room/SecurityRoomSettingsTab.js b/src/components/views/settings/tabs/room/SecurityRoomSettingsTab.js index c67596a3a5..596344d7cd 100644 --- a/src/components/views/settings/tabs/room/SecurityRoomSettingsTab.js +++ b/src/components/views/settings/tabs/room/SecurityRoomSettingsTab.js @@ -20,9 +20,9 @@ import {_t} from "../../../../../languageHandler"; import {MatrixClientPeg} from "../../../../../MatrixClientPeg"; import * as sdk from "../../../../.."; import LabelledToggleSwitch from "../../../elements/LabelledToggleSwitch"; -import {SettingLevel} from "../../../../../settings/SettingsStore"; import Modal from "../../../../../Modal"; import QuestionDialog from "../../../dialogs/QuestionDialog"; +import {SettingLevel} from "../../../../../settings/SettingLevel"; export default class SecurityRoomSettingsTab extends React.Component { static propTypes = { diff --git a/src/components/views/settings/tabs/user/AppearanceUserSettingsTab.tsx b/src/components/views/settings/tabs/user/AppearanceUserSettingsTab.tsx index 9f3b8ba46c..c646025bbe 100644 --- a/src/components/views/settings/tabs/user/AppearanceUserSettingsTab.tsx +++ b/src/components/views/settings/tabs/user/AppearanceUserSettingsTab.tsx @@ -18,7 +18,7 @@ limitations under the License. import React from 'react'; import {_t} from "../../../../../languageHandler"; import SdkConfig from "../../../../../SdkConfig"; -import SettingsStore, {SettingLevel} from "../../../../../settings/SettingsStore"; +import SettingsStore from "../../../../../settings/SettingsStore"; import { enumerateThemes } from "../../../../../theme"; import ThemeWatcher from "../../../../../settings/watchers/ThemeWatcher"; import Slider from "../../../elements/Slider"; @@ -35,6 +35,7 @@ import Field from '../../../elements/Field'; import EventTilePreview from '../../../elements/EventTilePreview'; import StyledRadioGroup from "../../../elements/StyledRadioGroup"; import classNames from 'classnames'; +import { SettingLevel } from "../../../../../settings/SettingLevel"; interface IProps { } diff --git a/src/components/views/settings/tabs/user/GeneralUserSettingsTab.js b/src/components/views/settings/tabs/user/GeneralUserSettingsTab.js index c7e7ce7c2c..1ebefae590 100644 --- a/src/components/views/settings/tabs/user/GeneralUserSettingsTab.js +++ b/src/components/views/settings/tabs/user/GeneralUserSettingsTab.js @@ -20,7 +20,6 @@ import React from 'react'; import {_t} from "../../../../../languageHandler"; import ProfileSettings from "../../ProfileSettings"; import * as languageHandler from "../../../../../languageHandler"; -import {SettingLevel} from "../../../../../settings/SettingsStore"; import SettingsStore from "../../../../../settings/SettingsStore"; import LanguageDropdown from "../../../elements/LanguageDropdown"; import AccessibleButton from "../../../elements/AccessibleButton"; @@ -37,6 +36,7 @@ import IdentityAuthClient from "../../../../../IdentityAuthClient"; import {abbreviateUrl} from "../../../../../utils/UrlUtils"; import { getThreepidsWithBindStatus } from '../../../../../boundThreepids'; import Spinner from "../../../elements/Spinner"; +import {SettingLevel} from "../../../../../settings/SettingLevel"; export default class GeneralUserSettingsTab extends React.Component { static propTypes = { diff --git a/src/components/views/settings/tabs/user/LabsUserSettingsTab.js b/src/components/views/settings/tabs/user/LabsUserSettingsTab.js index 2b8d7c5d3f..25dfd9e100 100644 --- a/src/components/views/settings/tabs/user/LabsUserSettingsTab.js +++ b/src/components/views/settings/tabs/user/LabsUserSettingsTab.js @@ -17,9 +17,10 @@ limitations under the License. import React from 'react'; import {_t} from "../../../../../languageHandler"; import PropTypes from "prop-types"; -import SettingsStore, {SettingLevel} from "../../../../../settings/SettingsStore"; +import SettingsStore from "../../../../../settings/SettingsStore"; import LabelledToggleSwitch from "../../../elements/LabelledToggleSwitch"; import * as sdk from "../../../../../index"; +import {SettingLevel} from "../../../../../settings/SettingLevel"; export class LabsSettingToggle extends React.Component { static propTypes = { diff --git a/src/components/views/settings/tabs/user/PreferencesUserSettingsTab.js b/src/components/views/settings/tabs/user/PreferencesUserSettingsTab.js index fe60a4a179..a77815a68c 100644 --- a/src/components/views/settings/tabs/user/PreferencesUserSettingsTab.js +++ b/src/components/views/settings/tabs/user/PreferencesUserSettingsTab.js @@ -17,12 +17,12 @@ limitations under the License. import React from 'react'; import {_t} from "../../../../../languageHandler"; -import {SettingLevel} from "../../../../../settings/SettingsStore"; import LabelledToggleSwitch from "../../../elements/LabelledToggleSwitch"; import SettingsStore from "../../../../../settings/SettingsStore"; import Field from "../../../elements/Field"; import * as sdk from "../../../../.."; import PlatformPeg from "../../../../../PlatformPeg"; +import {SettingLevel} from "../../../../../settings/SettingLevel"; export default class PreferencesUserSettingsTab extends React.Component { static ROOM_LIST_SETTINGS = [ diff --git a/src/components/views/settings/tabs/user/SecurityUserSettingsTab.js b/src/components/views/settings/tabs/user/SecurityUserSettingsTab.js index 591927411d..fda7ccb005 100644 --- a/src/components/views/settings/tabs/user/SecurityUserSettingsTab.js +++ b/src/components/views/settings/tabs/user/SecurityUserSettingsTab.js @@ -19,7 +19,6 @@ import React from 'react'; import PropTypes from 'prop-types'; import {_t} from "../../../../../languageHandler"; import SdkConfig from "../../../../../SdkConfig"; -import {SettingLevel} from "../../../../../settings/SettingsStore"; import {MatrixClientPeg} from "../../../../../MatrixClientPeg"; import * as FormattingUtils from "../../../../../utils/FormattingUtils"; import AccessibleButton from "../../../elements/AccessibleButton"; @@ -29,6 +28,7 @@ import * as sdk from "../../../../.."; import {sleep} from "../../../../../utils/promise"; import dis from "../../../../../dispatcher/dispatcher"; import {privateShouldBeEncrypted} from "../../../../../createRoom"; +import {SettingLevel} from "../../../../../settings/SettingLevel"; export class IgnoredUser extends React.Component { static propTypes = { diff --git a/src/components/views/settings/tabs/user/VoiceUserSettingsTab.js b/src/components/views/settings/tabs/user/VoiceUserSettingsTab.js index efd184069e..4114f6bb22 100644 --- a/src/components/views/settings/tabs/user/VoiceUserSettingsTab.js +++ b/src/components/views/settings/tabs/user/VoiceUserSettingsTab.js @@ -21,10 +21,10 @@ import SdkConfig from "../../../../../SdkConfig"; import CallMediaHandler from "../../../../../CallMediaHandler"; import Field from "../../../elements/Field"; import AccessibleButton from "../../../elements/AccessibleButton"; -import {SettingLevel} from "../../../../../settings/SettingsStore"; import {MatrixClientPeg} from "../../../../../MatrixClientPeg"; import * as sdk from "../../../../../index"; import Modal from "../../../../../Modal"; +import {SettingLevel} from "../../../../../settings/SettingLevel"; export default class VoiceUserSettingsTab extends React.Component { constructor() { diff --git a/src/emojipicker/recent.ts b/src/emojipicker/recent.ts index 1ba15d87b8..d86aad660d 100644 --- a/src/emojipicker/recent.ts +++ b/src/emojipicker/recent.ts @@ -15,8 +15,9 @@ See the License for the specific language governing permissions and limitations under the License. */ -import SettingsStore, {SettingLevel} from "../settings/SettingsStore"; +import SettingsStore from "../settings/SettingsStore"; import {orderBy} from "lodash"; +import { SettingLevel } from "../settings/SettingLevel"; interface ILegacyFormat { [emoji: string]: [number, number]; // [count, date] diff --git a/src/indexing/EventIndex.js b/src/indexing/EventIndex.js index 1dc31869c9..d5abb3f2d2 100644 --- a/src/indexing/EventIndex.js +++ b/src/indexing/EventIndex.js @@ -18,8 +18,9 @@ import PlatformPeg from "../PlatformPeg"; import {MatrixClientPeg} from "../MatrixClientPeg"; import {EventTimeline, RoomMember} from 'matrix-js-sdk'; import {sleep} from "../utils/promise"; -import SettingsStore, {SettingLevel} from "../settings/SettingsStore"; +import SettingsStore from "../settings/SettingsStore"; import {EventEmitter} from "events"; +import {SettingLevel} from "../settings/SettingLevel"; /* * Event indexing class that wraps the platform specific event indexing. diff --git a/src/indexing/EventIndexPeg.js b/src/indexing/EventIndexPeg.js index 20e05f985d..58e8430825 100644 --- a/src/indexing/EventIndexPeg.js +++ b/src/indexing/EventIndexPeg.js @@ -21,7 +21,8 @@ limitations under the License. import PlatformPeg from "../PlatformPeg"; import EventIndex from "../indexing/EventIndex"; -import SettingsStore, {SettingLevel} from '../settings/SettingsStore'; +import SettingsStore from '../settings/SettingsStore'; +import {SettingLevel} from "../settings/SettingLevel"; const INDEX_VERSION = 1; diff --git a/src/languageHandler.tsx b/src/languageHandler.tsx index 91d90d4e6c..9d28b7d07d 100644 --- a/src/languageHandler.tsx +++ b/src/languageHandler.tsx @@ -21,11 +21,12 @@ import request from 'browser-request'; import counterpart from 'counterpart'; import React from 'react'; -import SettingsStore, {SettingLevel} from "./settings/SettingsStore"; +import SettingsStore from "./settings/SettingsStore"; import PlatformPeg from "./PlatformPeg"; // @ts-ignore - $webapp is a webpack resolve alias pointing to the output directory, see webpack config import webpackLangJsonUrl from "$webapp/i18n/languages.json"; +import { SettingLevel } from "./settings/SettingLevel"; const i18nFolder = 'i18n/'; diff --git a/src/mjolnir/Mjolnir.js b/src/mjolnir/Mjolnir.js index 9876cb1f7f..891438bbb9 100644 --- a/src/mjolnir/Mjolnir.js +++ b/src/mjolnir/Mjolnir.js @@ -16,9 +16,10 @@ limitations under the License. import {MatrixClientPeg} from "../MatrixClientPeg"; import {ALL_RULE_TYPES, BanList} from "./BanList"; -import SettingsStore, {SettingLevel} from "../settings/SettingsStore"; +import SettingsStore from "../settings/SettingsStore"; import {_t} from "../languageHandler"; import dis from "../dispatcher/dispatcher"; +import {SettingLevel} from "../settings/SettingLevel"; // TODO: Move this and related files to the js-sdk or something once finalized. diff --git a/src/rageshake/submit-rageshake.ts b/src/rageshake/submit-rageshake.ts index 64a1ea0c33..350602aa5d 100644 --- a/src/rageshake/submit-rageshake.ts +++ b/src/rageshake/submit-rageshake.ts @@ -141,7 +141,7 @@ export default async function sendBugReport(bugReportEndpoint: string, opts: IOp } // add labs options - const enabledLabs = SettingsStore.getLabsFeatures().filter(SettingsStore.isFeatureEnabled); + const enabledLabs = SettingsStore.getLabsFeatures().filter(f => SettingsStore.isFeatureEnabled(f)); if (enabledLabs.length) { body.append('enabled_labs', enabledLabs.join(', ')); } diff --git a/src/settings/SettingLevel.ts b/src/settings/SettingLevel.ts new file mode 100644 index 0000000000..e4703be1a9 --- /dev/null +++ b/src/settings/SettingLevel.ts @@ -0,0 +1,29 @@ +/* +Copyright 2020 The Matrix.org Foundation C.I.C. + +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. +*/ + +/** + * Represents the various setting levels supported by the SettingsStore. + */ +export enum SettingLevel { + // TODO: [TS] Follow naming convention + DEVICE = "device", + ROOM_DEVICE = "room-device", + ROOM_ACCOUNT = "room-account", + ACCOUNT = "account", + ROOM = "room", + CONFIG = "config", + DEFAULT = "default", +} diff --git a/src/settings/Settings.js b/src/settings/Settings.ts similarity index 81% rename from src/settings/Settings.js rename to src/settings/Settings.ts index d5866c9064..1989bd7a34 100644 --- a/src/settings/Settings.js +++ b/src/settings/Settings.ts @@ -1,7 +1,6 @@ /* Copyright 2017 Travis Ralston -Copyright 2018, 2019 New Vector Ltd. -Copyright 2019, 2020 The Matrix.org Foundation C.I.C. +Copyright 2018, 2019, 2020 The Matrix.org Foundation C.I.C. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -16,9 +15,9 @@ See the License for the specific language governing permissions and limitations under the License. */ -import {MatrixClient} from 'matrix-js-sdk'; +import { MatrixClient } from 'matrix-js-sdk/src/client'; -import {_td} from '../languageHandler'; +import { _td } from '../languageHandler'; import { AudioNotificationsEnabledController, NotificationBodyEnabledController, @@ -28,75 +27,89 @@ import CustomStatusController from "./controllers/CustomStatusController"; import ThemeController from './controllers/ThemeController'; import PushToMatrixClientController from './controllers/PushToMatrixClientController'; import ReloadOnChangeController from "./controllers/ReloadOnChangeController"; -import {RightPanelPhases} from "../stores/RightPanelStorePhases"; import FontSizeController from './controllers/FontSizeController'; import SystemFontController from './controllers/SystemFontController'; import UseSystemFontController from './controllers/UseSystemFontController'; +import { SettingLevel } from "./SettingLevel"; +import SettingController from "./controllers/SettingController"; +import { RightPanelPhases } from "../stores/RightPanelStorePhases"; // 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_OR_ACCOUNT = ['room-account', 'account']; -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']; +const LEVELS_ROOM_SETTINGS = [ + SettingLevel.DEVICE, + SettingLevel.ROOM_DEVICE, + SettingLevel.ROOM_ACCOUNT, + SettingLevel.ACCOUNT, + SettingLevel.CONFIG, +]; +const LEVELS_ROOM_OR_ACCOUNT = [ + SettingLevel.ROOM_ACCOUNT, + SettingLevel.ACCOUNT, +]; +const LEVELS_ROOM_SETTINGS_WITH_ROOM = [ + SettingLevel.DEVICE, + SettingLevel.ROOM_DEVICE, + SettingLevel.ROOM_ACCOUNT, + SettingLevel.ACCOUNT, + SettingLevel.CONFIG, + SettingLevel.ROOM, +]; +const LEVELS_ACCOUNT_SETTINGS = [ + SettingLevel.DEVICE, + SettingLevel.ACCOUNT, + SettingLevel.CONFIG, +]; +const LEVELS_FEATURE = [ + SettingLevel.DEVICE, + SettingLevel.CONFIG, +]; +const LEVELS_DEVICE_ONLY_SETTINGS = [ + SettingLevel.DEVICE, +]; +const LEVELS_DEVICE_ONLY_SETTINGS_WITH_CONFIG = [ + SettingLevel.DEVICE, + SettingLevel.CONFIG, +]; -export const SETTINGS = { - // EXAMPLE SETTING: - // "my-setting": { - // // Must be set to true for features. Default is 'false'. - // isFeature: false, - // - // // Display names are strongly recommended for clarity. - // displayName: _td("Cool Name"), - // - // // Display name can also be an object for different levels. - // //displayName: { - // // "device": _td("Name for when the setting is used at 'device'"), - // // "room": _td("Name for when the setting is used at 'room'"), - // // "default": _td("The name for all other levels"), - // //} - // - // // The supported levels are required. Preferably, use the preset arrays - // // at the top of this file to define this rather than a custom array. - // 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. - // ], - // - // // Required. Can be any data type. The value specified here should match - // // the data being stored (ie: if a boolean is used, the setting should - // // represent a boolean). - // default: { - // your: "value", - // }, - // - // // Optional settings controller. See SettingsController for more information. - // controller: new MySettingController(), - // - // // Optional flag to make supportedLevels be respected as the order to handle - // // settings. The first element is treated as "most preferred". The "default" - // // level is always appended to the end. - // supportedLevelsAreOrdered: false, - // - // // Optional value to invert a boolean setting's value. The string given will - // // be read as the setting's ID instead of the one provided as the key for the - // // setting definition. By setting this, the returned value will automatically - // // be inverted, except for when the default value is returned. Inversion will - // // occur after the controller is asked for an override. This should be used by - // // historical settings which we don't want existing user's values be wiped. Do - // // not use this for new settings. - // invertedSettingName: "my-negative-setting", - // }, +export interface ISetting { + // Must be set to true for features. Default is 'false'. + isFeature?: boolean; + + // Display names are strongly recommended for clarity. + // Display name can also be an object for different levels. + displayName?: string | { + // @ts-ignore - TS wants the key to be a string, but we know better + [level: SettingLevel]: string; + }; + + // The supported levels are required. Preferably, use the preset arrays + // at the top of this file to define this rather than a custom array. + supportedLevels?: SettingLevel[]; + + // Required. Can be any data type. The value specified here should match + // the data being stored (ie: if a boolean is used, the setting should + // represent a boolean). + default: any; + + // Optional settings controller. See SettingsController for more information. + controller?: SettingController; + + // Optional flag to make supportedLevels be respected as the order to handle + // settings. The first element is treated as "most preferred". The "default" + // level is always appended to the end. + supportedLevelsAreOrdered?: boolean; + + // Optional value to invert a boolean setting's value. The string given will + // be read as the setting's ID instead of the one provided as the key for the + // setting definition. By setting this, the returned value will automatically + // be inverted, except for when the default value is returned. Inversion will + // occur after the controller is asked for an override. This should be used by + // historical settings which we don't want existing user's values be wiped. Do + // not use this for new settings. + invertedSettingName?: string; +} + +export const SETTINGS: {[setting: string]: ISetting} = { "feature_new_spinner": { isFeature: true, displayName: _td("New spinner design"), @@ -153,11 +166,11 @@ export const SETTINGS = { default: false, }, "mjolnirRooms": { - supportedLevels: ['account'], + supportedLevels: [SettingLevel.ACCOUNT], default: [], }, "mjolnirPersonalRoom": { - supportedLevels: ['account'], + supportedLevels: [SettingLevel.ACCOUNT], default: null, }, "feature_bridge_state": { @@ -354,24 +367,24 @@ export const SETTINGS = { }, "breadcrumb_rooms": { // not really a setting - supportedLevels: ['account'], + supportedLevels: [SettingLevel.ACCOUNT], default: [], }, "recent_emoji": { // not really a setting - supportedLevels: ['account'], + supportedLevels: [SettingLevel.ACCOUNT], default: [], }, "room_directory_servers": { - supportedLevels: ['account'], + supportedLevels: [SettingLevel.ACCOUNT], default: [], }, "integrationProvisioning": { - supportedLevels: ['account'], + supportedLevels: [SettingLevel.ACCOUNT], default: true, }, "allowedWidgets": { - supportedLevels: ['room-account'], + supportedLevels: [SettingLevel.ROOM_ACCOUNT], default: {}, // none allowed }, "analyticsOptIn": { @@ -398,7 +411,7 @@ export const SETTINGS = { "blacklistUnverifiedDevices": { // We specifically want to have room-device > device so that users may set a device default // with a per-room override. - supportedLevels: ['room-device', 'device'], + supportedLevels: [SettingLevel.ROOM_DEVICE, SettingLevel.DEVICE], supportedLevelsAreOrdered: true, displayName: { "default": _td('Never send encrypted messages to unverified sessions from this session'), @@ -416,7 +429,7 @@ export const SETTINGS = { default: true, }, "urlPreviewsEnabled_e2ee": { - supportedLevels: ['room-device', 'room-account'], + supportedLevels: [SettingLevel.ROOM_DEVICE, SettingLevel.ROOM_ACCOUNT], displayName: { "room-account": _td("Enable URL previews for this room (only affects you)"), }, @@ -455,7 +468,7 @@ export const SETTINGS = { default: false, }, "PinnedEvents.isOpen": { - supportedLevels: ['room-device'], + supportedLevels: [SettingLevel.ROOM_DEVICE], default: false, }, "promptBeforeInviteUnknownUsers": { @@ -565,7 +578,8 @@ export const SETTINGS = { "ircDisplayNameWidth": { // We specifically want to have room-device > device so that users may set a device default // with a per-room override. - supportedLevels: ['room-device', 'device'], + supportedLevels: [SettingLevel.ROOM_DEVICE, SettingLevel.DEVICE], + supportedLevelsAreOrdered: true, displayName: _td("IRC display name width"), default: 80, }, diff --git a/src/settings/SettingsStore.js b/src/settings/SettingsStore.ts similarity index 78% rename from src/settings/SettingsStore.js rename to src/settings/SettingsStore.ts index 488a15d003..e64de8af16 100644 --- a/src/settings/SettingsStore.js +++ b/src/settings/SettingsStore.ts @@ -1,6 +1,6 @@ /* Copyright 2017 Travis Ralston -Copyright 2019 New Vector Ltd. +Copyright 2019, 2020 The Matrix.org Foundation C.I.C. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -22,27 +22,14 @@ import RoomAccountSettingsHandler from "./handlers/RoomAccountSettingsHandler"; import AccountSettingsHandler from "./handlers/AccountSettingsHandler"; import RoomSettingsHandler from "./handlers/RoomSettingsHandler"; import ConfigSettingsHandler from "./handlers/ConfigSettingsHandler"; -import {_t} from '../languageHandler'; +import { _t } from '../languageHandler'; import SdkConfig from "../SdkConfig"; import dis from '../dispatcher/dispatcher'; -import {SETTINGS} from "./Settings"; +import { ISetting, SETTINGS } from "./Settings"; import LocalEchoWrapper from "./handlers/LocalEchoWrapper"; -import {WatchManager} from "./WatchManager"; - -/** - * 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", -}; +import { WatchManager } from "./WatchManager"; +import { SettingLevel } from "./SettingLevel"; +import SettingsHandler from "./handlers/SettingsHandler"; const defaultWatchManager = new WatchManager(); @@ -61,13 +48,13 @@ for (const key of Object.keys(SETTINGS)) { } const LEVEL_HANDLERS = { - "device": new DeviceSettingsHandler(featureNames, defaultWatchManager), - "room-device": new RoomDeviceSettingsHandler(defaultWatchManager), - "room-account": new RoomAccountSettingsHandler(defaultWatchManager), - "account": new AccountSettingsHandler(defaultWatchManager), - "room": new RoomSettingsHandler(defaultWatchManager), - "config": new ConfigSettingsHandler(), - "default": new DefaultSettingsHandler(defaultSettings, invertedDefaultSettings), + [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.CONFIG]: new ConfigSettingsHandler(), + [SettingLevel.DEFAULT]: new DefaultSettingsHandler(defaultSettings, invertedDefaultSettings), }; // Wrap all the handlers with local echo @@ -76,20 +63,41 @@ for (const key of Object.keys(LEVEL_HANDLERS)) { } const LEVEL_ORDER = [ - 'device', 'room-device', 'room-account', 'account', 'room', 'config', 'default', + SettingLevel.DEVICE, + SettingLevel.ROOM_DEVICE, + SettingLevel.ROOM_ACCOUNT, + SettingLevel.ACCOUNT, + SettingLevel.ROOM, + SettingLevel.CONFIG, + SettingLevel.DEFAULT, ]; +export type CallbackFn = ( + settingName: string, + roomId: string, + atLevel: SettingLevel, + newValAtLevel: any, + newVal: any, +) => void; + +interface IHandlerMap { + // @ts-ignore - TS wants this to be a string key but we know better + [level: SettingLevel]: SettingsHandler; +} + +export type LabsFeatureState = "labs" | "disable" | "enable" | string; + /** * 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 + * - SettingLevel.DEVICE - Values are determined by the current device + * - SettingLevel.ROOM_DEVICE - Values are determined by the current device for a particular room + * - SettingLevel.ROOM_ACCOUNT - Values are determined by the current account for a particular room + * - SettingLevel.ACCOUNT - Values are determined by the current account + * - SettingLevel.ROOM - Values are determined by a particular room (by the room admins) + * - SettingLevel.CONFIG - Values are determined by the config.json + * - SettingLevel.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 @@ -110,11 +118,11 @@ export default class SettingsStore { // We also maintain a list of monitors which are special watchers: they cause dispatches // when the setting changes. We track which rooms we're monitoring though to ensure we // don't duplicate updates on the bus. - static _watchers = {}; // { callbackRef => { callbackFn } } - static _monitors = {}; // { settingName => { roomId => callbackRef } } + private static watchers = {}; // { callbackRef => { callbackFn } } + private static monitors = {}; // { settingName => { roomId => callbackRef } } // Counter used for generation of watcher IDs - static _watcherCount = 1; + private static watcherCount = 1; /** * Watches for changes in a particular setting. This is done without any local echo @@ -132,7 +140,7 @@ export default class SettingsStore { * if the change in value is worthwhile enough to react upon. * @returns {string} A reference to the watcher that was employed. */ - static watchSetting(settingName, roomId, callbackFn) { + public static watchSetting(settingName: string, roomId: string, callbackFn: CallbackFn): string { const setting = SETTINGS[settingName]; const originalSettingName = settingName; if (!setting) throw new Error(`${settingName} is not a setting`); @@ -141,14 +149,14 @@ export default class SettingsStore { settingName = setting.invertedSettingName; } - const watcherId = `${new Date().getTime()}_${SettingsStore._watcherCount++}_${settingName}_${roomId}`; + const watcherId = `${new Date().getTime()}_${SettingsStore.watcherCount++}_${settingName}_${roomId}`; const localizedCallback = (changedInRoomId, atLevel, newValAtLevel) => { const newValue = SettingsStore.getValue(originalSettingName); callbackFn(originalSettingName, changedInRoomId, atLevel, newValAtLevel, newValue); }; - SettingsStore._watchers[watcherId] = localizedCallback; + SettingsStore.watchers[watcherId] = localizedCallback; defaultWatchManager.watchSetting(settingName, roomId, localizedCallback); return watcherId; @@ -160,14 +168,14 @@ export default class SettingsStore { * @param {string} watcherReference The watcher reference (received from #watchSetting) * to cancel. */ - static unwatchSetting(watcherReference) { - if (!SettingsStore._watchers[watcherReference]) { + public static unwatchSetting(watcherReference: string) { + if (!SettingsStore.watchers[watcherReference]) { console.warn(`Ending non-existent watcher ID ${watcherReference}`); return; } - defaultWatchManager.unwatchSetting(SettingsStore._watchers[watcherReference]); - delete SettingsStore._watchers[watcherReference]; + defaultWatchManager.unwatchSetting(SettingsStore.watchers[watcherReference]); + delete SettingsStore.watchers[watcherReference]; } /** @@ -178,13 +186,13 @@ export default class SettingsStore { * @param {string} settingName The setting name to monitor. * @param {String} roomId The room ID to monitor for changes in. Use null for all rooms. */ - static monitorSetting(settingName, roomId) { + public static monitorSetting(settingName: string, roomId: string) { roomId = roomId || null; // the thing wants null specifically to work, so appease it. - if (!this._monitors[settingName]) this._monitors[settingName] = {}; + if (!this.monitors[settingName]) this.monitors[settingName] = {}; const registerWatcher = () => { - this._monitors[settingName][roomId] = SettingsStore.watchSetting( + this.monitors[settingName][roomId] = SettingsStore.watchSetting( settingName, roomId, (settingName, inRoomId, level, newValueAtLevel, newValue) => { dis.dispatch({ action: 'setting_updated', @@ -198,16 +206,16 @@ export default class SettingsStore { ); }; - const hasRoom = Object.keys(this._monitors[settingName]).find((r) => r === roomId || r === null); + const hasRoom = Object.keys(this.monitors[settingName]).find((r) => r === roomId || r === null); if (!hasRoom) { registerWatcher(); } else { if (roomId === null) { // Unregister all existing watchers and register the new one - for (const roomId of Object.keys(this._monitors[settingName])) { - SettingsStore.unwatchSetting(this._monitors[settingName][roomId]); + for (const roomId of Object.keys(this.monitors[settingName])) { + SettingsStore.unwatchSetting(this.monitors[settingName][roomId]); } - this._monitors[settingName] = {}; + this.monitors[settingName] = {}; registerWatcher(); } // else a watcher is already registered for the room, so don't bother registering it again } @@ -216,11 +224,11 @@ export default class SettingsStore { /** * Gets the translated display name for a given setting * @param {string} settingName The setting to look up. - * @param {"device"|"room-device"|"room-account"|"account"|"room"|"config"|"default"} atLevel + * @param {SettingLevel} atLevel * The level to get the display name for; Defaults to 'default'. * @return {String} The display name for the setting, or null if not found. */ - static getDisplayName(settingName, atLevel = "default") { + public static getDisplayName(settingName: string, atLevel = SettingLevel.DEFAULT) { if (!SETTINGS[settingName] || !SETTINGS[settingName].displayName) return null; let displayName = SETTINGS[settingName].displayName; @@ -229,20 +237,20 @@ export default class SettingsStore { else displayName = displayName["default"]; } - return _t(displayName); + return _t(displayName as string); } /** * Returns a list of all available labs feature names * @returns {string[]} The list of available feature names */ - static getLabsFeatures() { + public static getLabsFeatures(): string[] { const possibleFeatures = Object.keys(SETTINGS).filter((s) => SettingsStore.isFeature(s)); const enableLabs = SdkConfig.get()["enableLabs"]; if (enableLabs) return possibleFeatures; - return possibleFeatures.filter((s) => SettingsStore._getFeatureState(s) === "labs"); + return possibleFeatures.filter((s) => SettingsStore.getFeatureState(s) === "labs"); } /** @@ -250,7 +258,7 @@ export default class SettingsStore { * @param {string} settingName The setting to look up. * @return {boolean} True if the setting is a feature. */ - static isFeature(settingName) { + public static isFeature(settingName: string) { if (!SETTINGS[settingName]) return false; return SETTINGS[settingName].isFeature; } @@ -262,7 +270,7 @@ export default class SettingsStore { * @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) { + public static isFeatureEnabled(settingName: string, roomId: string = null) { if (!SettingsStore.isFeature(settingName)) { throw new Error("Setting " + settingName + " is not a feature"); } @@ -276,7 +284,7 @@ export default class SettingsStore { * @param {boolean} value True to enable the feature, false otherwise. * @returns {Promise} Resolves when the setting has been set. */ - static setFeatureEnabled(settingName, value) { + public static setFeatureEnabled(settingName: string, value: any): Promise { // Verify that the setting is actually a setting if (!SETTINGS[settingName]) { throw new Error("Setting '" + settingName + "' does not appear to be a setting."); @@ -285,7 +293,7 @@ export default class SettingsStore { throw new Error("Setting " + settingName + " is not a feature"); } - return SettingsStore.setValue(settingName, null, "device", value); + return SettingsStore.setValue(settingName, null, SettingLevel.DEVICE, value); } /** @@ -296,7 +304,7 @@ export default class SettingsStore { * @param {boolean} excludeDefault True to disable using the default value. * @return {*} The value, or null if not found */ - static getValue(settingName, roomId = null, excludeDefault = false) { + public static getValue(settingName: string, roomId: string = null, excludeDefault = false): any { // Verify that the setting is actually a setting if (!SETTINGS[settingName]) { throw new Error("Setting '" + settingName + "' does not appear to be a setting."); @@ -310,7 +318,7 @@ export default class SettingsStore { /** * Gets a setting's value at a particular level, ignoring all levels that are more specific. - * @param {"device"|"room-device"|"room-account"|"account"|"room"|"config"|"default"} level The + * @param {SettingLevel|"config"|"default"} level The * level to look at. * @param {string} settingName The name of the setting to read. * @param {String} roomId The room ID to read the setting value in, may be null. @@ -319,7 +327,13 @@ export default class SettingsStore { * @param {boolean} excludeDefault True to disable using the default value. * @return {*} The value, or null if not found. */ - static getValueAt(level, settingName, roomId = null, explicit = false, excludeDefault = false) { + public static getValueAt( + level: SettingLevel, + settingName: string, + roomId: string = null, + explicit = false, + excludeDefault = false, + ): any { // Verify that the setting is actually a setting const setting = SETTINGS[settingName]; if (!setting) { @@ -327,19 +341,19 @@ export default class SettingsStore { } const levelOrder = (setting.supportedLevelsAreOrdered ? setting.supportedLevels : LEVEL_ORDER); - if (!levelOrder.includes("default")) levelOrder.push("default"); // always include default + if (!levelOrder.includes(SettingLevel.DEFAULT)) levelOrder.push(SettingLevel.DEFAULT); // always include default const minIndex = levelOrder.indexOf(level); if (minIndex === -1) throw new Error("Level " + level + " is not prioritized"); if (SettingsStore.isFeature(settingName)) { - const configValue = SettingsStore._getFeatureState(settingName); + const configValue = SettingsStore.getFeatureState(settingName); if (configValue === "enable") return true; if (configValue === "disable") return false; // else let it fall through the default process } - const handlers = SettingsStore._getHandlers(settingName); + const handlers = SettingsStore.getHandlers(settingName); // Check if we need to invert the setting at all. Do this after we get the setting // handlers though, otherwise we'll fail to read the value. @@ -351,10 +365,10 @@ export default class SettingsStore { if (explicit) { const handler = handlers[level]; if (!handler) { - return SettingsStore._getFinalValue(setting, level, roomId, null, null); + return SettingsStore.getFinalValue(setting, level, roomId, null, null); } const value = handler.getValue(settingName, roomId); - return SettingsStore._getFinalValue(setting, level, roomId, value, level); + return SettingsStore.getFinalValue(setting, level, roomId, value, level); } for (let i = minIndex; i < levelOrder.length; i++) { @@ -364,10 +378,10 @@ export default class SettingsStore { const value = handler.getValue(settingName, roomId); if (value === null || value === undefined) continue; - return SettingsStore._getFinalValue(setting, level, roomId, value, levelOrder[i]); + return SettingsStore.getFinalValue(setting, level, roomId, value, levelOrder[i]); } - return SettingsStore._getFinalValue(setting, level, roomId, null, null); + return SettingsStore.getFinalValue(setting, level, roomId, null, null); } /** @@ -376,7 +390,7 @@ export default class SettingsStore { * @param {String} roomId The room ID to read the setting value in, may be null. * @return {*} The default value */ - static getDefaultValue(settingName) { + public static getDefaultValue(settingName: string): any { // Verify that the setting is actually a setting if (!SETTINGS[settingName]) { throw new Error("Setting '" + settingName + "' does not appear to be a setting."); @@ -385,7 +399,13 @@ export default class SettingsStore { return SETTINGS[settingName].default; } - static _getFinalValue(setting, level, roomId, calculatedValue, calculatedAtLevel) { + private static getFinalValue( + setting: ISetting, + level: SettingLevel, + roomId: string, + calculatedValue: any, + calculatedAtLevel: SettingLevel, + ): any { let resultingValue = calculatedValue; if (setting.controller) { @@ -404,20 +424,21 @@ export default class SettingsStore { * 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 + * @param {SettingLevel} level The level * to change the value at. * @param {*} value The new value of the setting, may be null. * @return {Promise} Resolves when the setting has been changed. */ + /* eslint-enable valid-jsdoc */ - static async setValue(settingName, roomId, level, value) { + public static async setValue(settingName: string, roomId: string, level: SettingLevel, value: any): Promise { // Verify that the setting is actually a setting const setting = SETTINGS[settingName]; if (!setting) { throw new Error("Setting '" + settingName + "' does not appear to be a setting."); } - const handler = SettingsStore._getHandler(settingName, level); + const handler = SettingsStore.getHandler(settingName, level); if (!handler) { throw new Error("Setting " + settingName + " does not have a handler for " + level); } @@ -449,28 +470,28 @@ export default class SettingsStore { * 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 + * @param {SettingLevel} level The level to * check at. * @return {boolean} True if the user may set the setting, false otherwise. */ - static canSetValue(settingName, roomId, level) { + public static canSetValue(settingName: string, roomId: string, level: SettingLevel): boolean { // Verify that the setting is actually a setting if (!SETTINGS[settingName]) { throw new Error("Setting '" + settingName + "' does not appear to be a setting."); } - const handler = SettingsStore._getHandler(settingName, 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 + * @param {SettingLevel} level The level * to check the feasibility of. * @return {boolean} True if the level is supported, false otherwise. */ - static isLevelSupported(level) { + public static isLevelSupported(level: SettingLevel): boolean { if (!LEVEL_HANDLERS[level]) return false; return LEVEL_HANDLERS[level].isSupported(); } @@ -482,7 +503,7 @@ export default class SettingsStore { * @param {string} realSettingName The setting name to try and read. * @param {string} roomId Optional room ID to test the setting in. */ - static debugSetting(realSettingName, roomId) { + public static debugSetting(realSettingName: string, roomId: string) { console.log(`--- DEBUG ${realSettingName}`); // Note: we intentionally use JSON.stringify here to avoid the console masking the @@ -570,13 +591,13 @@ export default class SettingsStore { console.log(`--- END DEBUG`); } - static _getHandler(settingName, level) { - const handlers = SettingsStore._getHandlers(settingName); + private static getHandler(settingName: string, level: SettingLevel): SettingsHandler { + const handlers = SettingsStore.getHandlers(settingName); if (!handlers[level]) return null; return handlers[level]; } - static _getHandlers(settingName) { + private static getHandlers(settingName: string): IHandlerMap { if (!SETTINGS[settingName]) return {}; const handlers = {}; @@ -591,7 +612,7 @@ export default class SettingsStore { return handlers; } - static _getFeatureState(settingName) { + private static getFeatureState(settingName: string): LabsFeatureState { const featuresConfig = SdkConfig.get()['features']; const enableLabs = SdkConfig.get()['enableLabs']; // we'll honour the old flag @@ -611,4 +632,4 @@ export default class SettingsStore { } // For debugging purposes -global.mxSettingsStore = SettingsStore; +window.mxSettingsStore = SettingsStore; diff --git a/src/settings/WatchManager.js b/src/settings/WatchManager.ts similarity index 56% rename from src/settings/WatchManager.js rename to src/settings/WatchManager.ts index 3f54ca929e..d51439459c 100644 --- a/src/settings/WatchManager.js +++ b/src/settings/WatchManager.ts @@ -14,41 +14,52 @@ See the License for the specific language governing permissions and limitations under the License. */ +import { SettingLevel } from "./SettingLevel"; + +export type CallbackFn = (changedInRoomId: string, atLevel: SettingLevel, newValAtLevel: any) => void; + +const IRRELEVANT_ROOM = Symbol("any room"); + +interface RoomWatcherMap { + // @ts-ignore - TS wants string-only keys but we know better - https://github.com/Microsoft/TypeScript/issues/1863 + [roomId: string | symbol]: CallbackFn[]; +} + /** * Generalized management class for dealing with watchers on a per-handler (per-level) * basis without duplicating code. Handlers are expected to push updates through this * class, which are then proxied outwards to any applicable watchers. */ export class WatchManager { - _watchers = {}; // { settingName: { roomId: callbackFns[] } } + private watchers: {[settingName: string]: RoomWatcherMap} = {}; // Proxy for handlers to delegate changes to this manager - watchSetting(settingName, roomId, cb) { - if (!this._watchers[settingName]) this._watchers[settingName] = {}; - if (!this._watchers[settingName][roomId]) this._watchers[settingName][roomId] = []; - this._watchers[settingName][roomId].push(cb); + public watchSetting(settingName: string, roomId: string | null, cb: CallbackFn) { + if (!this.watchers[settingName]) this.watchers[settingName] = {}; + if (!this.watchers[settingName][roomId]) this.watchers[settingName][roomId] = []; + this.watchers[settingName][roomId].push(cb); } // Proxy for handlers to delegate changes to this manager - unwatchSetting(cb) { - for (const settingName of Object.keys(this._watchers)) { - for (const roomId of Object.keys(this._watchers[settingName])) { + public unwatchSetting(cb: CallbackFn) { + for (const settingName of Object.keys(this.watchers)) { + for (const roomId of Object.keys(this.watchers[settingName])) { let idx; - while ((idx = this._watchers[settingName][roomId].indexOf(cb)) !== -1) { - this._watchers[settingName][roomId].splice(idx, 1); + while ((idx = this.watchers[settingName][roomId].indexOf(cb)) !== -1) { + this.watchers[settingName][roomId].splice(idx, 1); } } } } - notifyUpdate(settingName, inRoomId, atLevel, newValueAtLevel) { + public notifyUpdate(settingName: string, inRoomId: string | null, atLevel: SettingLevel, newValueAtLevel: any) { // Dev note: We could avoid raising changes for ultimately inconsequential changes, but // we also don't have a reliable way to get the old value of a setting. Instead, we'll just // let it fall through regardless and let the receiver dedupe if they want to. - if (!this._watchers[settingName]) return; + if (!this.watchers[settingName]) return; - const roomWatchers = this._watchers[settingName]; + const roomWatchers = this.watchers[settingName]; const callbacks = []; if (inRoomId !== null && roomWatchers[inRoomId]) { @@ -59,8 +70,8 @@ export class WatchManager { // Fire updates to all the individual room watchers too, as they probably // care about the change higher up. callbacks.push(...Object.values(roomWatchers).reduce((r, a) => [...r, ...a], [])); - } else if (roomWatchers[null]) { - callbacks.push(...roomWatchers[null]); + } else if (roomWatchers[IRRELEVANT_ROOM]) { + callbacks.push(...roomWatchers[IRRELEVANT_ROOM]); } for (const callback of callbacks) { diff --git a/src/settings/controllers/CustomStatusController.js b/src/settings/controllers/CustomStatusController.ts similarity index 84% rename from src/settings/controllers/CustomStatusController.js rename to src/settings/controllers/CustomStatusController.ts index 031387bb6a..c7dfad0b3b 100644 --- a/src/settings/controllers/CustomStatusController.js +++ b/src/settings/controllers/CustomStatusController.ts @@ -1,5 +1,5 @@ /* -Copyright 2019 New Vector Ltd +Copyright 2019, 2020 The Matrix.org Foundation C.I.C. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -16,9 +16,10 @@ limitations under the License. import SettingController from "./SettingController"; import dis from "../../dispatcher/dispatcher"; +import { SettingLevel } from "../SettingLevel"; export default class CustomStatusController extends SettingController { - onChange(level, roomId, newValue) { + public onChange(level: SettingLevel, roomId: string, newValue: any) { // Dispatch setting change so that some components that are still visible when the // Settings page is open (such as RoomTiles) can reflect the change. dis.dispatch({ diff --git a/src/settings/controllers/FontSizeController.ts b/src/settings/controllers/FontSizeController.ts index 6440fd32fe..b86d596040 100644 --- a/src/settings/controllers/FontSizeController.ts +++ b/src/settings/controllers/FontSizeController.ts @@ -18,13 +18,14 @@ import SettingController from "./SettingController"; import dis from "../../dispatcher/dispatcher"; import { UpdateFontSizePayload } from "../../dispatcher/payloads/UpdateFontSizePayload"; import { Action } from "../../dispatcher/actions"; +import { SettingLevel } from "../SettingLevel"; export default class FontSizeController extends SettingController { constructor() { super(); } - onChange(level, roomId, newValue) { + public onChange(level: SettingLevel, roomId: string, newValue: any) { // Dispatch font size change so that everything open responds to the change. dis.dispatch({ action: Action.UpdateFontSize, diff --git a/src/settings/controllers/NotificationControllers.js b/src/settings/controllers/NotificationControllers.ts similarity index 77% rename from src/settings/controllers/NotificationControllers.js rename to src/settings/controllers/NotificationControllers.ts index e38a5bded1..fc50af6096 100644 --- a/src/settings/controllers/NotificationControllers.js +++ b/src/settings/controllers/NotificationControllers.ts @@ -1,5 +1,6 @@ /* Copyright 2017 Travis Ralston +Copyright 2020 The Matrix.org Foundation C.I.C. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -16,13 +17,14 @@ limitations under the License. import SettingController from "./SettingController"; import {MatrixClientPeg} from '../../MatrixClientPeg'; +import { SettingLevel } from "../SettingLevel"; // XXX: This feels wrong. import {PushProcessor} from "matrix-js-sdk/src/pushprocessor"; // .m.rule.master being enabled means all events match that push rule // default action on this rule is dont_notify, but it could be something else -function isPushNotifyDisabled() { +function isPushNotifyDisabled(): boolean { // Return the value of the master push rule as a default const processor = new PushProcessor(MatrixClientPeg.get()); const masterRule = processor.getPushRuleById(".m.rule.master"); @@ -36,14 +38,20 @@ function isPushNotifyDisabled() { return masterRule.enabled && !masterRule.actions.includes("notify"); } -function getNotifier() { +function getNotifier(): any { // TODO: [TS] Formal type that doesn't cause a cyclical reference. + // eslint-disable-next-line @typescript-eslint/no-var-requires let Notifier = require('../../Notifier'); // avoids cyclical references if (Notifier.default) Notifier = Notifier.default; // correct for webpack require() weirdness return Notifier; } export class NotificationsEnabledController extends SettingController { - getValueOverride(level, roomId, calculatedValue, calculatedAtLevel) { + public getValueOverride( + level: SettingLevel, + roomId: string, + calculatedValue: any, + calculatedAtLevel: SettingLevel, + ): any { if (!getNotifier().isPossible()) return false; if (calculatedValue === null || calculatedAtLevel === "default") { @@ -53,7 +61,7 @@ export class NotificationsEnabledController extends SettingController { return calculatedValue; } - onChange(level, roomId, newValue) { + public onChange(level: SettingLevel, roomId: string, newValue: any) { if (getNotifier().supportsDesktopNotifications()) { getNotifier().setEnabled(newValue); } @@ -61,7 +69,7 @@ export class NotificationsEnabledController extends SettingController { } export class NotificationBodyEnabledController extends SettingController { - getValueOverride(level, roomId, calculatedValue) { + public getValueOverride(level: SettingLevel, roomId: string, calculatedValue: any): any { if (!getNotifier().isPossible()) return false; if (calculatedValue === null) { @@ -73,7 +81,7 @@ export class NotificationBodyEnabledController extends SettingController { } export class AudioNotificationsEnabledController extends SettingController { - getValueOverride(level, roomId, calculatedValue) { + public getValueOverride(level: SettingLevel, roomId: string, calculatedValue: any): any { if (!getNotifier().isPossible()) return false; // Note: Audio notifications are *not* enabled by default. diff --git a/src/settings/controllers/PushToMatrixClientController.js b/src/settings/controllers/PushToMatrixClientController.ts similarity index 67% rename from src/settings/controllers/PushToMatrixClientController.js rename to src/settings/controllers/PushToMatrixClientController.ts index b7c285227f..8fbf7eb34c 100644 --- a/src/settings/controllers/PushToMatrixClientController.js +++ b/src/settings/controllers/PushToMatrixClientController.ts @@ -15,23 +15,20 @@ limitations under the License. */ import { MatrixClientPeg } from '../../MatrixClientPeg'; +import { SettingLevel } from "../SettingLevel"; +import SettingController from "./SettingController"; /** * When the value changes, call a setter function on the matrix client with the new value */ -export default class PushToMatrixClientController { - constructor(setter, inverse) { - this._setter = setter; - this._inverse = inverse; +export default class PushToMatrixClientController extends SettingController { + constructor(private setter: Function, private inverse: boolean) { + super(); } - getValueOverride(level, roomId, calculatedValue, calculatedAtLevel) { - return null; // no override - } - - onChange(level, roomId, newValue) { + public onChange(level: SettingLevel, roomId: string, newValue: any) { // XXX does this work? This surely isn't necessarily the effective value, // but it's what NotificationsEnabledController does... - this._setter.call(MatrixClientPeg.get(), this._inverse ? !newValue : newValue); + this.setter.call(MatrixClientPeg.get(), this.inverse ? !newValue : newValue); } } diff --git a/src/settings/controllers/ReloadOnChangeController.js b/src/settings/controllers/ReloadOnChangeController.ts similarity index 80% rename from src/settings/controllers/ReloadOnChangeController.js rename to src/settings/controllers/ReloadOnChangeController.ts index eadaee89ca..12bc23ef6c 100644 --- a/src/settings/controllers/ReloadOnChangeController.js +++ b/src/settings/controllers/ReloadOnChangeController.ts @@ -1,5 +1,5 @@ /* -Copyright 2019 The Matrix.org Foundation C.I.C. +Copyright 2019, 2020 The Matrix.org Foundation C.I.C. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -16,9 +16,10 @@ limitations under the License. import SettingController from "./SettingController"; import PlatformPeg from "../../PlatformPeg"; +import { SettingLevel } from "../SettingLevel"; export default class ReloadOnChangeController extends SettingController { - onChange(level, roomId, newValue) { + public onChange(level: SettingLevel, roomId: string, newValue: any) { PlatformPeg.get().reload(); } } diff --git a/src/settings/controllers/SettingController.js b/src/settings/controllers/SettingController.ts similarity index 79% rename from src/settings/controllers/SettingController.js rename to src/settings/controllers/SettingController.ts index a7d0ccf21a..d90eba1e9e 100644 --- a/src/settings/controllers/SettingController.js +++ b/src/settings/controllers/SettingController.ts @@ -1,5 +1,6 @@ /* Copyright 2017 Travis Ralston +Copyright 2020 The Matrix.org Foundation C.I.C. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -14,6 +15,8 @@ See the License for the specific language governing permissions and limitations under the License. */ +import { SettingLevel } from "../SettingLevel"; + /** * Represents a controller for individual settings to alter the reading behaviour * based upon environmental conditions, or to react to changes and therefore update @@ -22,7 +25,7 @@ limitations under the License. * This is not intended to replace the functionality of a SettingsHandler, it is only * intended to handle environmental factors for specific settings. */ -export default class SettingController { +export default abstract class SettingController { /** * Gets the overridden value for the setting, if any. This must return null if the * value is not to be overridden, otherwise it must return the new value. @@ -30,11 +33,16 @@ export default class SettingController { * @param {String} roomId The room ID, may be null. * @param {*} calculatedValue The value that the handlers think the setting should be, * may be null. - * @param {string} calculatedAtLevel The level for which the calculated value was + * @param {SettingLevel} calculatedAtLevel The level for which the calculated value was * calculated at. May be null. * @return {*} The value that should be used, or null if no override is applicable. */ - getValueOverride(level, roomId, calculatedValue, calculatedAtLevel) { + public getValueOverride( + level: SettingLevel, + roomId: string, + calculatedValue: any, + calculatedAtLevel: SettingLevel, + ): any { return null; // no override } @@ -44,7 +52,7 @@ export default class SettingController { * @param {String} roomId The room ID, may be null. * @param {*} newValue The new value for the setting, may be null. */ - onChange(level, roomId, newValue) { + public onChange(level: SettingLevel, roomId: string, newValue: any) { // do nothing by default } } diff --git a/src/settings/controllers/SystemFontController.ts b/src/settings/controllers/SystemFontController.ts index 4f591efc17..f38dbdbbf6 100644 --- a/src/settings/controllers/SystemFontController.ts +++ b/src/settings/controllers/SystemFontController.ts @@ -19,13 +19,14 @@ import SettingsStore from "../SettingsStore"; import dis from "../../dispatcher/dispatcher"; import { UpdateSystemFontPayload } from "../../dispatcher/payloads/UpdateSystemFontPayload"; import { Action } from "../../dispatcher/actions"; +import { SettingLevel } from "../SettingLevel"; export default class SystemFontController extends SettingController { constructor() { super(); } - onChange(level, roomId, newValue) { + public onChange(level: SettingLevel, roomId: string, newValue: any) { // Dispatch font size change so that everything open responds to the change. dis.dispatch({ action: Action.UpdateSystemFont, diff --git a/src/settings/controllers/ThemeController.js b/src/settings/controllers/ThemeController.ts similarity index 79% rename from src/settings/controllers/ThemeController.js rename to src/settings/controllers/ThemeController.ts index 4098a5ca3e..15dd64c901 100644 --- a/src/settings/controllers/ThemeController.js +++ b/src/settings/controllers/ThemeController.ts @@ -1,6 +1,6 @@ /* -Copyright 2019 New Vector Ltd Copyright 2019 Michael Telatynski <7t3chguy@gmail.com> +Copyright 2019, 2020 The Matrix.org Foundation C.I.C. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -17,11 +17,17 @@ limitations under the License. import SettingController from "./SettingController"; import {DEFAULT_THEME, enumerateThemes} from "../../theme"; +import { SettingLevel } from "../SettingLevel"; export default class ThemeController extends SettingController { - static isLogin = false; + public static isLogin = false; - getValueOverride(level, roomId, calculatedValue, calculatedAtLevel) { + public getValueOverride( + level: SettingLevel, + roomId: string, + calculatedValue: any, + calculatedAtLevel: SettingLevel, + ): any { if (!calculatedValue) return null; // Don't override null themes if (ThemeController.isLogin) return 'light'; diff --git a/src/settings/controllers/UseSystemFontController.ts b/src/settings/controllers/UseSystemFontController.ts index d598b25962..0b6acc590a 100644 --- a/src/settings/controllers/UseSystemFontController.ts +++ b/src/settings/controllers/UseSystemFontController.ts @@ -19,13 +19,14 @@ import SettingsStore from "../SettingsStore"; import dis from "../../dispatcher/dispatcher"; import { UpdateSystemFontPayload } from "../../dispatcher/payloads/UpdateSystemFontPayload"; import { Action } from "../../dispatcher/actions"; +import { SettingLevel } from "../SettingLevel"; export default class UseSystemFontController extends SettingController { constructor() { super(); } - onChange(level, roomId, newValue) { + public onChange(level: SettingLevel, roomId: string, newValue: any) { // Dispatch font size change so that everything open responds to the change. dis.dispatch({ action: Action.UpdateSystemFont, diff --git a/src/settings/handlers/AccountSettingsHandler.js b/src/settings/handlers/AccountSettingsHandler.ts similarity index 71% rename from src/settings/handlers/AccountSettingsHandler.js rename to src/settings/handlers/AccountSettingsHandler.ts index 4048d8ddea..53180aeba8 100644 --- a/src/settings/handlers/AccountSettingsHandler.js +++ b/src/settings/handlers/AccountSettingsHandler.ts @@ -1,6 +1,6 @@ /* Copyright 2017 Travis Ralston -Copyright 2019 New Vector Ltd. +Copyright 2019, 2020 The Matrix.org Foundation C.I.C. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -17,14 +17,16 @@ limitations under the License. import {MatrixClientPeg} from '../../MatrixClientPeg'; import MatrixClientBackedSettingsHandler from "./MatrixClientBackedSettingsHandler"; -import {SettingLevel} from "../SettingsStore"; import {objectClone, objectKeyChanges} from "../../utils/objects"; +import {SettingLevel} from "../SettingLevel"; +import { WatchManager } from "../WatchManager"; +import { MatrixClient } from "matrix-js-sdk/src/client"; +import { MatrixEvent } from "matrix-js-sdk/src/models/event"; const BREADCRUMBS_LEGACY_EVENT_TYPE = "im.vector.riot.breadcrumb_rooms"; const BREADCRUMBS_EVENT_TYPE = "im.vector.setting.breadcrumbs"; const BREADCRUMBS_EVENT_TYPES = [BREADCRUMBS_LEGACY_EVENT_TYPE, BREADCRUMBS_EVENT_TYPE]; const RECENT_EMOJI_EVENT_TYPE = "io.element.recent_emoji"; - const INTEG_PROVISIONING_EVENT_TYPE = "im.vector.setting.integration_provisioning"; /** @@ -32,22 +34,19 @@ const INTEG_PROVISIONING_EVENT_TYPE = "im.vector.setting.integration_provisionin * This handler does not make use of the roomId parameter. */ export default class AccountSettingsHandler extends MatrixClientBackedSettingsHandler { - constructor(watchManager) { + constructor(private watchers: WatchManager) { super(); - - this._watchers = watchManager; - this._onAccountData = this._onAccountData.bind(this); } - initMatrixClient(oldClient, newClient) { + public initMatrixClient(oldClient: MatrixClient, newClient: MatrixClient) { if (oldClient) { - oldClient.removeListener("accountData", this._onAccountData); + oldClient.removeListener("accountData", this.onAccountData); } - newClient.on("accountData", this._onAccountData); + newClient.on("accountData", this.onAccountData); } - _onAccountData(event, prevEvent) { + private onAccountData = (event: MatrixEvent, prevEvent: MatrixEvent) => { if (event.getType() === "org.matrix.preview_urls") { let val = event.getContent()['disable']; if (typeof(val) !== "boolean") { @@ -56,30 +55,30 @@ export default class AccountSettingsHandler extends MatrixClientBackedSettingsHa val = !val; } - this._watchers.notifyUpdate("urlPreviewsEnabled", null, SettingLevel.ACCOUNT, val); + this.watchers.notifyUpdate("urlPreviewsEnabled", null, SettingLevel.ACCOUNT, val); } else if (event.getType() === "im.vector.web.settings") { // Figure out what changed and fire those updates const prevContent = prevEvent ? prevEvent.getContent() : {}; const changedSettings = objectKeyChanges(prevContent, event.getContent()); for (const settingName of changedSettings) { const val = event.getContent()[settingName]; - this._watchers.notifyUpdate(settingName, null, SettingLevel.ACCOUNT, val); + this.watchers.notifyUpdate(settingName, null, SettingLevel.ACCOUNT, val); } } else if (BREADCRUMBS_EVENT_TYPES.includes(event.getType())) { - this._notifyBreadcrumbsUpdate(event); + this.notifyBreadcrumbsUpdate(event); } else if (event.getType() === INTEG_PROVISIONING_EVENT_TYPE) { const val = event.getContent()['enabled']; - this._watchers.notifyUpdate("integrationProvisioning", null, SettingLevel.ACCOUNT, val); + this.watchers.notifyUpdate("integrationProvisioning", null, SettingLevel.ACCOUNT, val); } else if (event.getType() === RECENT_EMOJI_EVENT_TYPE) { const val = event.getContent()['enabled']; - this._watchers.notifyUpdate("recent_emoji", null, SettingLevel.ACCOUNT, val); + this.watchers.notifyUpdate("recent_emoji", null, SettingLevel.ACCOUNT, val); } } - getValue(settingName, roomId) { + public getValue(settingName: string, roomId: string): any { // Special case URL previews if (settingName === "urlPreviewsEnabled") { - const content = this._getSettings("org.matrix.preview_urls") || {}; + const content = this.getSettings("org.matrix.preview_urls") || {}; // Check to make sure that we actually got a boolean if (typeof(content['disable']) !== "boolean") return null; @@ -88,9 +87,9 @@ export default class AccountSettingsHandler extends MatrixClientBackedSettingsHa // Special case for breadcrumbs if (settingName === "breadcrumb_rooms") { - let content = this._getSettings(BREADCRUMBS_EVENT_TYPE); + let content = this.getSettings(BREADCRUMBS_EVENT_TYPE); if (!content || !content['recent_rooms']) { - content = this._getSettings(BREADCRUMBS_LEGACY_EVENT_TYPE); + content = this.getSettings(BREADCRUMBS_LEGACY_EVENT_TYPE); // This is a bit of a hack, but it makes things slightly easier if (content) content['recent_rooms'] = content['rooms']; @@ -101,17 +100,17 @@ export default class AccountSettingsHandler extends MatrixClientBackedSettingsHa // Special case recent emoji if (settingName === "recent_emoji") { - const content = this._getSettings(RECENT_EMOJI_EVENT_TYPE); + const content = this.getSettings(RECENT_EMOJI_EVENT_TYPE); return content ? content["recent_emoji"] : null; } // Special case integration manager provisioning if (settingName === "integrationProvisioning") { - const content = this._getSettings(INTEG_PROVISIONING_EVENT_TYPE); + const content = this.getSettings(INTEG_PROVISIONING_EVENT_TYPE); return content ? content['enabled'] : null; } - const settings = this._getSettings() || {}; + const settings = this.getSettings() || {}; let preferredValue = settings[settingName]; if (preferredValue === null || preferredValue === undefined) { @@ -124,10 +123,10 @@ export default class AccountSettingsHandler extends MatrixClientBackedSettingsHa return preferredValue; } - setValue(settingName, roomId, newValue) { + public setValue(settingName: string, roomId: string, newValue: any): Promise { // Special case URL previews if (settingName === "urlPreviewsEnabled") { - const content = this._getSettings("org.matrix.preview_urls") || {}; + const content = this.getSettings("org.matrix.preview_urls") || {}; content['disable'] = !newValue; return MatrixClientPeg.get().setAccountData("org.matrix.preview_urls", content); } @@ -135,9 +134,9 @@ export default class AccountSettingsHandler extends MatrixClientBackedSettingsHa // Special case for breadcrumbs if (settingName === "breadcrumb_rooms") { // We read the value first just to make sure we preserve whatever random keys might be present. - let content = this._getSettings(BREADCRUMBS_EVENT_TYPE); + let content = this.getSettings(BREADCRUMBS_EVENT_TYPE); if (!content || !content['recent_rooms']) { - content = this._getSettings(BREADCRUMBS_LEGACY_EVENT_TYPE); + content = this.getSettings(BREADCRUMBS_LEGACY_EVENT_TYPE); } if (!content) content = {}; // If we still don't have content, make some @@ -147,33 +146,33 @@ export default class AccountSettingsHandler extends MatrixClientBackedSettingsHa // Special case recent emoji if (settingName === "recent_emoji") { - const content = this._getSettings(RECENT_EMOJI_EVENT_TYPE) || {}; + const content = this.getSettings(RECENT_EMOJI_EVENT_TYPE) || {}; content["recent_emoji"] = newValue; return MatrixClientPeg.get().setAccountData(RECENT_EMOJI_EVENT_TYPE, content); } // Special case integration manager provisioning if (settingName === "integrationProvisioning") { - const content = this._getSettings(INTEG_PROVISIONING_EVENT_TYPE) || {}; + const content = this.getSettings(INTEG_PROVISIONING_EVENT_TYPE) || {}; content['enabled'] = newValue; return MatrixClientPeg.get().setAccountData(INTEG_PROVISIONING_EVENT_TYPE, content); } - const content = this._getSettings() || {}; + const content = this.getSettings() || {}; content[settingName] = newValue; return MatrixClientPeg.get().setAccountData("im.vector.web.settings", content); } - canSetValue(settingName, roomId) { + public canSetValue(settingName: string, roomId: string): boolean { return true; // It's their account, so they should be able to } - isSupported() { + public isSupported(): boolean { const cli = MatrixClientPeg.get(); return cli !== undefined && cli !== null; } - _getSettings(eventType = "im.vector.web.settings") { + private getSettings(eventType = "im.vector.web.settings"): any { // TODO: [TS] Types on return const cli = MatrixClientPeg.get(); if (!cli) return null; @@ -182,11 +181,11 @@ export default class AccountSettingsHandler extends MatrixClientBackedSettingsHa return objectClone(event.getContent()); // clone to prevent mutation } - _notifyBreadcrumbsUpdate(event) { + private notifyBreadcrumbsUpdate(event: MatrixEvent) { let val = []; if (event.getType() === BREADCRUMBS_LEGACY_EVENT_TYPE) { // This seems fishy - try and get the event for the new rooms - const newType = this._getSettings(BREADCRUMBS_EVENT_TYPE); + const newType = this.getSettings(BREADCRUMBS_EVENT_TYPE); if (newType) val = newType['recent_rooms']; else val = event.getContent()['rooms']; } else if (event.getType() === BREADCRUMBS_EVENT_TYPE) { @@ -194,6 +193,6 @@ export default class AccountSettingsHandler extends MatrixClientBackedSettingsHa } else { return; // for sanity, not because we expect to be here. } - this._watchers.notifyUpdate("breadcrumb_rooms", null, SettingLevel.ACCOUNT, val || []); + this.watchers.notifyUpdate("breadcrumb_rooms", null, SettingLevel.ACCOUNT, val || []); } } diff --git a/src/settings/handlers/ConfigSettingsHandler.js b/src/settings/handlers/ConfigSettingsHandler.ts similarity index 81% rename from src/settings/handlers/ConfigSettingsHandler.js rename to src/settings/handlers/ConfigSettingsHandler.ts index 3b5b4b626e..3e8b1724c1 100644 --- a/src/settings/handlers/ConfigSettingsHandler.js +++ b/src/settings/handlers/ConfigSettingsHandler.ts @@ -1,6 +1,6 @@ /* Copyright 2017 Travis Ralston -Copyright 2019 New Vector Ltd +Copyright 2019, 2020 The Matrix.org Foundation C.I.C. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -24,7 +24,7 @@ import {isNullOrUndefined} from "matrix-js-sdk/src/utils"; * roomId parameter. */ export default class ConfigSettingsHandler extends SettingsHandler { - getValue(settingName, roomId) { + public getValue(settingName: string, roomId: string): any { const config = SdkConfig.get() || {}; // Special case themes @@ -37,15 +37,15 @@ export default class ConfigSettingsHandler extends SettingsHandler { return settingsConfig[settingName]; } - setValue(settingName, roomId, newValue) { + public async setValue(settingName: string, roomId: string, newValue: any): Promise { throw new Error("Cannot change settings at the config level"); } - canSetValue(settingName, roomId) { + public canSetValue(settingName: string, roomId: string): boolean { return false; } - isSupported() { + public isSupported(): boolean { return true; // SdkConfig is always there } } diff --git a/src/settings/handlers/DefaultSettingsHandler.js b/src/settings/handlers/DefaultSettingsHandler.ts similarity index 72% rename from src/settings/handlers/DefaultSettingsHandler.js rename to src/settings/handlers/DefaultSettingsHandler.ts index 37bc5b2348..f54c7eafe1 100644 --- a/src/settings/handlers/DefaultSettingsHandler.js +++ b/src/settings/handlers/DefaultSettingsHandler.ts @@ -1,6 +1,6 @@ /* Copyright 2017 Travis Ralston -Copyright 2019 New Vector Ltd. +Copyright 2019, 2020 The Matrix.org Foundation C.I.C. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -27,29 +27,27 @@ export default class DefaultSettingsHandler extends SettingsHandler { * @param {object} defaults The default setting values, keyed by setting name. * @param {object} invertedDefaults The default inverted setting values, keyed by setting name. */ - constructor(defaults, invertedDefaults) { + constructor(private defaults: Record, private invertedDefaults: Record) { super(); - this._defaults = defaults; - this._invertedDefaults = invertedDefaults; } - getValue(settingName, roomId) { - let value = this._defaults[settingName]; + public getValue(settingName: string, roomId: string): any { + let value = this.defaults[settingName]; if (value === undefined) { - value = this._invertedDefaults[settingName]; + value = this.invertedDefaults[settingName]; } return value; } - setValue(settingName, roomId, newValue) { + public async setValue(settingName: string, roomId: string, newValue: any): Promise { throw new Error("Cannot set values on the default level handler"); } - canSetValue(settingName, roomId) { + public canSetValue(settingName: string, roomId: string) { return false; } - isSupported() { + public isSupported(): boolean { return true; } } diff --git a/src/settings/handlers/DeviceSettingsHandler.js b/src/settings/handlers/DeviceSettingsHandler.ts similarity index 71% rename from src/settings/handlers/DeviceSettingsHandler.js rename to src/settings/handlers/DeviceSettingsHandler.ts index 44f89b9086..2096203598 100644 --- a/src/settings/handlers/DeviceSettingsHandler.js +++ b/src/settings/handlers/DeviceSettingsHandler.ts @@ -18,7 +18,8 @@ limitations under the License. import SettingsHandler from "./SettingsHandler"; import {MatrixClientPeg} from "../../MatrixClientPeg"; -import {SettingLevel} from "../SettingsStore"; +import {SettingLevel} from "../SettingLevel"; +import { CallbackFn, WatchManager } from "../WatchManager"; /** * Gets and sets settings at the "device" level for the current device. @@ -29,17 +30,15 @@ export default class DeviceSettingsHandler extends SettingsHandler { /** * Creates a new device settings handler * @param {string[]} featureNames The names of known features. - * @param {WatchManager} watchManager The watch manager to notify updates to + * @param {WatchManager} watchers The watch manager to notify updates to */ - constructor(featureNames, watchManager) { + constructor(private featureNames: string[], private watchers: WatchManager) { super(); - this._featureNames = featureNames; - this._watchers = watchManager; } - getValue(settingName, roomId) { - if (this._featureNames.includes(settingName)) { - return this._readFeature(settingName); + public getValue(settingName: string, roomId: string): any { + if (this.featureNames.includes(settingName)) { + return this.readFeature(settingName); } // Special case notifications @@ -68,28 +67,28 @@ export default class DeviceSettingsHandler extends SettingsHandler { return val['value']; } - const settings = this._getSettings() || {}; + const settings = this.getSettings() || {}; return settings[settingName]; } - setValue(settingName, roomId, newValue) { - if (this._featureNames.includes(settingName)) { - this._writeFeature(settingName, newValue); + public setValue(settingName: string, roomId: string, newValue: any): Promise { + if (this.featureNames.includes(settingName)) { + this.writeFeature(settingName, newValue); return Promise.resolve(); } // Special case notifications if (settingName === "notificationsEnabled") { localStorage.setItem("notifications_enabled", newValue); - this._watchers.notifyUpdate(settingName, null, SettingLevel.DEVICE, newValue); + this.watchers.notifyUpdate(settingName, null, SettingLevel.DEVICE, newValue); return Promise.resolve(); } else if (settingName === "notificationBodyEnabled") { localStorage.setItem("notifications_body_enabled", newValue); - this._watchers.notifyUpdate(settingName, null, SettingLevel.DEVICE, newValue); + this.watchers.notifyUpdate(settingName, null, SettingLevel.DEVICE, newValue); return Promise.resolve(); } else if (settingName === "audioNotificationsEnabled") { localStorage.setItem("audio_notifications_enabled", newValue); - this._watchers.notifyUpdate(settingName, null, SettingLevel.DEVICE, newValue); + this.watchers.notifyUpdate(settingName, null, SettingLevel.DEVICE, newValue); return Promise.resolve(); } @@ -103,35 +102,35 @@ export default class DeviceSettingsHandler extends SettingsHandler { "lastRightPanelPhaseForGroup", ].includes(settingName)) { localStorage.setItem(`mx_${settingName}`, JSON.stringify({value: newValue})); - this._watchers.notifyUpdate(settingName, null, SettingLevel.DEVICE, newValue); + this.watchers.notifyUpdate(settingName, null, SettingLevel.DEVICE, newValue); return Promise.resolve(); } - const settings = this._getSettings() || {}; + const settings = this.getSettings() || {}; settings[settingName] = newValue; localStorage.setItem("mx_local_settings", JSON.stringify(settings)); - this._watchers.notifyUpdate(settingName, null, SettingLevel.DEVICE, newValue); + this.watchers.notifyUpdate(settingName, null, SettingLevel.DEVICE, newValue); return Promise.resolve(); } - canSetValue(settingName, roomId) { + public canSetValue(settingName: string, roomId: string): boolean { return true; // It's their device, so they should be able to } - isSupported() { + public isSupported(): boolean { return localStorage !== undefined && localStorage !== null; } - watchSetting(settingName, roomId, cb) { - this._watchers.watchSetting(settingName, roomId, cb); + public watchSetting(settingName: string, roomId: string, cb: CallbackFn) { + this.watchers.watchSetting(settingName, roomId, cb); } - unwatchSetting(cb) { - this._watchers.unwatchSetting(cb); + public unwatchSetting(cb: CallbackFn) { + this.watchers.unwatchSetting(cb); } - _getSettings() { + private getSettings(): any { // TODO: [TS] Type return const value = localStorage.getItem("mx_local_settings"); if (!value) return null; return JSON.parse(value); @@ -140,7 +139,7 @@ export default class DeviceSettingsHandler extends SettingsHandler { // Note: features intentionally don't use the same key as settings to avoid conflicts // and to be backwards compatible. - _readFeature(featureName) { + private readFeature(featureName: string): boolean | null { if (MatrixClientPeg.get() && MatrixClientPeg.get().isGuest()) { // Guests should not have any labs features enabled. return false; @@ -153,8 +152,8 @@ export default class DeviceSettingsHandler extends SettingsHandler { return null; } - _writeFeature(featureName, enabled) { - localStorage.setItem("mx_labs_feature_" + featureName, enabled); - this._watchers.notifyUpdate(featureName, null, SettingLevel.DEVICE, enabled); + private writeFeature(featureName: string, enabled: boolean | null) { + localStorage.setItem("mx_labs_feature_" + featureName, `${enabled}`); + this.watchers.notifyUpdate(featureName, null, SettingLevel.DEVICE, enabled); } } diff --git a/src/settings/handlers/LocalEchoWrapper.js b/src/settings/handlers/LocalEchoWrapper.ts similarity index 62% rename from src/settings/handlers/LocalEchoWrapper.js rename to src/settings/handlers/LocalEchoWrapper.ts index fd0510296a..5cfcd27aed 100644 --- a/src/settings/handlers/LocalEchoWrapper.js +++ b/src/settings/handlers/LocalEchoWrapper.ts @@ -1,6 +1,6 @@ /* Copyright 2017 Travis Ralston -Copyright 2019 New Vector Ltd. +Copyright 2019, 2020 The Matrix.org Foundation C.I.C. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -23,47 +23,48 @@ import SettingsHandler from "./SettingsHandler"; * handler as much as possible to ensure values are not stale. */ export default class LocalEchoWrapper extends SettingsHandler { + private cache: { + [settingName: string]: { + [roomId: string]: any; + }; + } = {}; + /** * Creates a new local echo wrapper * @param {SettingsHandler} handler The handler to wrap */ - constructor(handler) { + constructor(private handler: SettingsHandler) { super(); - this._handler = handler; - this._cache = { - // settingName: { roomId: value } - }; } - getValue(settingName, roomId) { + public getValue(settingName: string, roomId: string): any { const cacheRoomId = roomId ? roomId : "UNDEFINED"; // avoid weird keys - const bySetting = this._cache[settingName]; + const bySetting = this.cache[settingName]; if (bySetting && bySetting.hasOwnProperty(cacheRoomId)) { return bySetting[cacheRoomId]; } - return this._handler.getValue(settingName, roomId); + return this.handler.getValue(settingName, roomId); } - setValue(settingName, roomId, newValue) { - if (!this._cache[settingName]) this._cache[settingName] = {}; - const bySetting = this._cache[settingName]; + public setValue(settingName: string, roomId: string, newValue: any): Promise { + if (!this.cache[settingName]) this.cache[settingName] = {}; + const bySetting = this.cache[settingName]; const cacheRoomId = roomId ? roomId : "UNDEFINED"; // avoid weird keys bySetting[cacheRoomId] = newValue; - const handlerPromise = this._handler.setValue(settingName, roomId, newValue); + const handlerPromise = this.handler.setValue(settingName, roomId, newValue); return Promise.resolve(handlerPromise).finally(() => { delete bySetting[cacheRoomId]; }); } - - canSetValue(settingName, roomId) { - return this._handler.canSetValue(settingName, roomId); + public canSetValue(settingName: string, roomId: string): boolean { + return this.handler.canSetValue(settingName, roomId); } - isSupported() { - return this._handler.isSupported(); + public isSupported(): boolean { + return this.handler.isSupported(); } } diff --git a/src/settings/handlers/MatrixClientBackedSettingsHandler.js b/src/settings/handlers/MatrixClientBackedSettingsHandler.ts similarity index 68% rename from src/settings/handlers/MatrixClientBackedSettingsHandler.js rename to src/settings/handlers/MatrixClientBackedSettingsHandler.ts index 63725b4dff..76825d1335 100644 --- a/src/settings/handlers/MatrixClientBackedSettingsHandler.js +++ b/src/settings/handlers/MatrixClientBackedSettingsHandler.ts @@ -1,5 +1,5 @@ /* -Copyright 2019 New Vector Ltd. +Copyright 2019, 2020 The Matrix.org Foundation C.I.C. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -15,6 +15,7 @@ limitations under the License. */ import SettingsHandler from "./SettingsHandler"; +import { MatrixClient } from "matrix-js-sdk/src/client"; // 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. @@ -23,30 +24,30 @@ import SettingsHandler from "./SettingsHandler"; * 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 = []; +export default abstract class MatrixClientBackedSettingsHandler extends SettingsHandler { + private static _matrixClient: MatrixClient; + private static instances: MatrixClientBackedSettingsHandler[] = []; - static set matrixClient(client) { + public static set matrixClient(client: MatrixClient) { const oldClient = MatrixClientBackedSettingsHandler._matrixClient; MatrixClientBackedSettingsHandler._matrixClient = client; - for (const instance of MatrixClientBackedSettingsHandler._instances) { + for (const instance of MatrixClientBackedSettingsHandler.instances) { instance.initMatrixClient(oldClient, client); } } - constructor() { + protected constructor() { super(); - MatrixClientBackedSettingsHandler._instances.push(this); + MatrixClientBackedSettingsHandler.instances.push(this); } - get client() { + public get client(): MatrixClient { return MatrixClientBackedSettingsHandler._matrixClient; } - initMatrixClient() { + protected initMatrixClient(oldClient: MatrixClient, newClient: MatrixClient) { console.warn("initMatrixClient not overridden"); } } diff --git a/src/settings/handlers/RoomAccountSettingsHandler.js b/src/settings/handlers/RoomAccountSettingsHandler.ts similarity index 65% rename from src/settings/handlers/RoomAccountSettingsHandler.js rename to src/settings/handlers/RoomAccountSettingsHandler.ts index b2af81779b..e3449e76c3 100644 --- a/src/settings/handlers/RoomAccountSettingsHandler.js +++ b/src/settings/handlers/RoomAccountSettingsHandler.ts @@ -1,6 +1,6 @@ /* Copyright 2017 Travis Ralston -Copyright 2019 New Vector Ltd. +Copyright 2019, 2020 The Matrix.org Foundation C.I.C. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -15,10 +15,14 @@ See the License for the specific language governing permissions and limitations under the License. */ -import {MatrixClientPeg} from '../../MatrixClientPeg'; +import { MatrixClientPeg } from '../../MatrixClientPeg'; import MatrixClientBackedSettingsHandler from "./MatrixClientBackedSettingsHandler"; -import {SettingLevel} from "../SettingsStore"; -import {objectClone, objectKeyChanges} from "../../utils/objects"; +import { objectClone, objectKeyChanges } from "../../utils/objects"; +import { SettingLevel } from "../SettingLevel"; +import { WatchManager } from "../WatchManager"; +import { MatrixClient } from "matrix-js-sdk/src/client"; +import { MatrixEvent } from "matrix-js-sdk/src/models/event"; +import { Room } from "matrix-js-sdk/src/models/room"; const ALLOWED_WIDGETS_EVENT_TYPE = "im.vector.setting.allowed_widgets"; @@ -26,22 +30,19 @@ 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(watchManager) { + constructor(private watchers: WatchManager) { super(); - - this._watchers = watchManager; - this._onAccountData = this._onAccountData.bind(this); } - initMatrixClient(oldClient, newClient) { + protected initMatrixClient(oldClient: MatrixClient, newClient: MatrixClient) { if (oldClient) { - oldClient.removeListener("Room.accountData", this._onAccountData); + oldClient.removeListener("Room.accountData", this.onAccountData); } - newClient.on("Room.accountData", this._onAccountData); + newClient.on("Room.accountData", this.onAccountData); } - _onAccountData(event, room, prevEvent) { + private onAccountData = (event: MatrixEvent, room: Room, prevEvent: MatrixEvent) => { const roomId = room.roomId; if (event.getType() === "org.matrix.room.preview_urls") { @@ -52,29 +53,29 @@ export default class RoomAccountSettingsHandler extends MatrixClientBackedSettin val = !val; } - this._watchers.notifyUpdate("urlPreviewsEnabled", roomId, SettingLevel.ROOM_ACCOUNT, val); + this.watchers.notifyUpdate("urlPreviewsEnabled", roomId, SettingLevel.ROOM_ACCOUNT, val); } else if (event.getType() === "org.matrix.room.color_scheme") { - this._watchers.notifyUpdate("roomColor", roomId, SettingLevel.ROOM_ACCOUNT, event.getContent()); + this.watchers.notifyUpdate("roomColor", roomId, SettingLevel.ROOM_ACCOUNT, event.getContent()); } else if (event.getType() === "im.vector.web.settings") { // Figure out what changed and fire those updates const prevContent = prevEvent ? prevEvent.getContent() : {}; const changedSettings = objectKeyChanges(prevContent, event.getContent()); for (const settingName of changedSettings) { const val = event.getContent()[settingName]; - this._watchers.notifyUpdate(settingName, roomId, SettingLevel.ROOM_ACCOUNT, val); + this.watchers.notifyUpdate(settingName, roomId, SettingLevel.ROOM_ACCOUNT, val); } } else if (event.getType() === ALLOWED_WIDGETS_EVENT_TYPE) { - this._watchers.notifyUpdate("allowedWidgets", roomId, SettingLevel.ROOM_ACCOUNT, event.getContent()); + this.watchers.notifyUpdate("allowedWidgets", roomId, SettingLevel.ROOM_ACCOUNT, event.getContent()); } - } + }; - getValue(settingName, roomId) { + public getValue(settingName: string, roomId: string): any { // Special case URL previews if (settingName === "urlPreviewsEnabled") { - const content = this._getSettings(roomId, "org.matrix.room.preview_urls") || {}; + const content = this.getSettings(roomId, "org.matrix.room.preview_urls") || {}; // Check to make sure that we actually got a boolean - if (typeof(content['disable']) !== "boolean") return null; + if (typeof (content['disable']) !== "boolean") return null; return !content['disable']; } @@ -83,22 +84,22 @@ export default class RoomAccountSettingsHandler extends MatrixClientBackedSettin // The event content should already be in an appropriate format, we just need // to get the right value. // don't fallback to {} because thats truthy and would imply there is an event specifying tint - return this._getSettings(roomId, "org.matrix.room.color_scheme"); + return this.getSettings(roomId, "org.matrix.room.color_scheme"); } // Special case allowed widgets if (settingName === "allowedWidgets") { - return this._getSettings(roomId, ALLOWED_WIDGETS_EVENT_TYPE); + return this.getSettings(roomId, ALLOWED_WIDGETS_EVENT_TYPE); } - const settings = this._getSettings(roomId) || {}; + const settings = this.getSettings(roomId) || {}; return settings[settingName]; } - setValue(settingName, roomId, newValue) { + public setValue(settingName: string, roomId: string, newValue: any): Promise { // Special case URL previews if (settingName === "urlPreviewsEnabled") { - const content = this._getSettings(roomId, "org.matrix.room.preview_urls") || {}; + const content = this.getSettings(roomId, "org.matrix.room.preview_urls") || {}; content['disable'] = !newValue; return MatrixClientPeg.get().setRoomAccountData(roomId, "org.matrix.room.preview_urls", content); } @@ -114,24 +115,24 @@ export default class RoomAccountSettingsHandler extends MatrixClientBackedSettin return MatrixClientPeg.get().setRoomAccountData(roomId, ALLOWED_WIDGETS_EVENT_TYPE, newValue); } - const content = this._getSettings(roomId) || {}; + const content = this.getSettings(roomId) || {}; content[settingName] = newValue; return MatrixClientPeg.get().setRoomAccountData(roomId, "im.vector.web.settings", content); } - canSetValue(settingName, roomId) { + public canSetValue(settingName: string, roomId: string): boolean { const room = MatrixClientPeg.get().getRoom(roomId); // If they have the room, they can set their own account data return room !== undefined && room !== null; } - isSupported() { + public isSupported(): boolean { const cli = MatrixClientPeg.get(); return cli !== undefined && cli !== null; } - _getSettings(roomId, eventType = "im.vector.web.settings") { + private getSettings(roomId: string, eventType = "im.vector.web.settings"): any { // TODO: [TS] Type return const room = MatrixClientPeg.get().getRoom(roomId); if (!room) return null; diff --git a/src/settings/handlers/RoomDeviceSettingsHandler.js b/src/settings/handlers/RoomDeviceSettingsHandler.ts similarity index 66% rename from src/settings/handlers/RoomDeviceSettingsHandler.js rename to src/settings/handlers/RoomDeviceSettingsHandler.ts index a9cf686c4c..2fcd58c27c 100644 --- a/src/settings/handlers/RoomDeviceSettingsHandler.js +++ b/src/settings/handlers/RoomDeviceSettingsHandler.ts @@ -1,6 +1,6 @@ /* Copyright 2017 Travis Ralston -Copyright 2019 New Vector Ltd. +Copyright 2019, 2020 The Matrix.org Foundation C.I.C. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -16,71 +16,70 @@ limitations under the License. */ import SettingsHandler from "./SettingsHandler"; -import {SettingLevel} from "../SettingsStore"; +import { SettingLevel } from "../SettingLevel"; +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(watchManager) { + constructor(private watchers: WatchManager) { super(); - - this._watchers = watchManager; } - getValue(settingName, roomId) { + public getValue(settingName: string, roomId: string): any { // Special case blacklist setting to use legacy values if (settingName === "blacklistUnverifiedDevices") { - const value = this._read("mx_local_settings"); + const value = this.read("mx_local_settings"); if (value && value['blacklistUnverifiedDevicesPerRoom']) { return value['blacklistUnverifiedDevicesPerRoom'][roomId]; } } - const value = this._read(this._getKey(settingName, roomId)); + const value = this.read(this.getKey(settingName, roomId)); if (value) return value.value; return null; } - setValue(settingName, roomId, newValue) { + public setValue(settingName: string, roomId: string, newValue: any): Promise { // Special case blacklist setting for legacy structure if (settingName === "blacklistUnverifiedDevices") { - let value = this._read("mx_local_settings"); + let value = this.read("mx_local_settings"); if (!value) value = {}; if (!value["blacklistUnverifiedDevicesPerRoom"]) value["blacklistUnverifiedDevicesPerRoom"] = {}; value["blacklistUnverifiedDevicesPerRoom"][roomId] = newValue; localStorage.setItem("mx_local_settings", JSON.stringify(value)); - this._watchers.notifyUpdate(settingName, roomId, SettingLevel.ROOM_DEVICE, newValue); + this.watchers.notifyUpdate(settingName, roomId, SettingLevel.ROOM_DEVICE, newValue); return Promise.resolve(); } if (newValue === null) { - localStorage.removeItem(this._getKey(settingName, roomId)); + localStorage.removeItem(this.getKey(settingName, roomId)); } else { newValue = JSON.stringify({value: newValue}); - localStorage.setItem(this._getKey(settingName, roomId), newValue); + localStorage.setItem(this.getKey(settingName, roomId), newValue); } - this._watchers.notifyUpdate(settingName, roomId, SettingLevel.ROOM_DEVICE, newValue); + this.watchers.notifyUpdate(settingName, roomId, SettingLevel.ROOM_DEVICE, newValue); return Promise.resolve(); } - canSetValue(settingName, roomId) { + public canSetValue(settingName: string, roomId: string): boolean { return true; // It's their device, so they should be able to } - isSupported() { + public isSupported(): boolean { return localStorage !== undefined && localStorage !== null; } - _read(key) { + private read(key: string): any { const rawValue = localStorage.getItem(key); if (!rawValue) return null; return JSON.parse(rawValue); } - _getKey(settingName, roomId) { + private getKey(settingName: string, roomId: string): string { return "mx_setting_" + settingName + "_" + roomId; } } diff --git a/src/settings/handlers/RoomSettingsHandler.js b/src/settings/handlers/RoomSettingsHandler.ts similarity index 66% rename from src/settings/handlers/RoomSettingsHandler.js rename to src/settings/handlers/RoomSettingsHandler.ts index 00dd5b8bec..4b4d4c4ad9 100644 --- a/src/settings/handlers/RoomSettingsHandler.js +++ b/src/settings/handlers/RoomSettingsHandler.ts @@ -1,6 +1,6 @@ /* Copyright 2017 Travis Ralston -Copyright 2019 New Vector Ltd. +Copyright 2019, 2020 The Matrix.org Foundation C.I.C. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -15,31 +15,32 @@ See the License for the specific language governing permissions and limitations under the License. */ -import {MatrixClientPeg} from '../../MatrixClientPeg'; +import { MatrixClientPeg } from '../../MatrixClientPeg'; import MatrixClientBackedSettingsHandler from "./MatrixClientBackedSettingsHandler"; -import {SettingLevel} from "../SettingsStore"; -import {objectClone, objectKeyChanges} from "../../utils/objects"; +import { objectClone, objectKeyChanges } from "../../utils/objects"; +import { SettingLevel } from "../SettingLevel"; +import { WatchManager } from "../WatchManager"; +import { MatrixClient } from "matrix-js-sdk/src/client"; +import { MatrixEvent } from "matrix-js-sdk/src/models/event"; +import { RoomState } from "matrix-js-sdk/src/models/room-state"; /** * Gets and sets settings at the "room" level. */ export default class RoomSettingsHandler extends MatrixClientBackedSettingsHandler { - constructor(watchManager) { + constructor(private watchers: WatchManager) { super(); - - this._watchers = watchManager; - this._onEvent = this._onEvent.bind(this); } - initMatrixClient(oldClient, newClient) { + protected initMatrixClient(oldClient: MatrixClient, newClient: MatrixClient) { if (oldClient) { - oldClient.removeListener("RoomState.events", this._onEvent); + oldClient.removeListener("RoomState.events", this.onEvent); } - newClient.on("RoomState.events", this._onEvent); + newClient.on("RoomState.events", this.onEvent); } - _onEvent(event, state, prevEvent) { + private onEvent = (event: MatrixEvent, state: RoomState, prevEvent: MatrixEvent) => { const roomId = event.getRoomId(); const room = this.client.getRoom(roomId); @@ -60,45 +61,45 @@ export default class RoomSettingsHandler extends MatrixClientBackedSettingsHandl val = !val; } - this._watchers.notifyUpdate("urlPreviewsEnabled", roomId, SettingLevel.ROOM, val); + this.watchers.notifyUpdate("urlPreviewsEnabled", roomId, SettingLevel.ROOM, val); } else if (event.getType() === "im.vector.web.settings") { // Figure out what changed and fire those updates const prevContent = prevEvent ? prevEvent.getContent() : {}; const changedSettings = objectKeyChanges(prevContent, event.getContent()); for (const settingName of changedSettings) { - this._watchers.notifyUpdate(settingName, roomId, SettingLevel.ROOM, event.getContent()[settingName]); + this.watchers.notifyUpdate(settingName, roomId, SettingLevel.ROOM, event.getContent()[settingName]); } } - } + }; - getValue(settingName, roomId) { + public getValue(settingName: string, roomId: string): any { // Special case URL previews if (settingName === "urlPreviewsEnabled") { - const content = this._getSettings(roomId, "org.matrix.room.preview_urls") || {}; + const content = this.getSettings(roomId, "org.matrix.room.preview_urls") || {}; // Check to make sure that we actually got a boolean - if (typeof(content['disable']) !== "boolean") return null; + if (typeof (content['disable']) !== "boolean") return null; return !content['disable']; } - const settings = this._getSettings(roomId) || {}; + const settings = this.getSettings(roomId) || {}; return settings[settingName]; } - setValue(settingName, roomId, newValue) { + public setValue(settingName: string, roomId: string, newValue: any): Promise { // Special case URL previews if (settingName === "urlPreviewsEnabled") { - const content = this._getSettings(roomId, "org.matrix.room.preview_urls") || {}; + const content = this.getSettings(roomId, "org.matrix.room.preview_urls") || {}; content['disable'] = !newValue; return MatrixClientPeg.get().sendStateEvent(roomId, "org.matrix.room.preview_urls", content); } - const content = this._getSettings(roomId) || {}; + const content = this.getSettings(roomId) || {}; content[settingName] = newValue; return MatrixClientPeg.get().sendStateEvent(roomId, "im.vector.web.settings", content, ""); } - canSetValue(settingName, roomId) { + public canSetValue(settingName: string, roomId: string): boolean { const cli = MatrixClientPeg.get(); const room = cli.getRoom(roomId); @@ -109,12 +110,12 @@ export default class RoomSettingsHandler extends MatrixClientBackedSettingsHandl return room.currentState.maySendStateEvent(eventType, cli.getUserId()); } - isSupported() { + public isSupported(): boolean { const cli = MatrixClientPeg.get(); return cli !== undefined && cli !== null; } - _getSettings(roomId, eventType = "im.vector.web.settings") { + private getSettings(roomId: string, eventType = "im.vector.web.settings"): any { const room = MatrixClientPeg.get().getRoom(roomId); if (!room) return null; diff --git a/src/settings/handlers/SettingsHandler.js b/src/settings/handlers/SettingsHandler.ts similarity index 82% rename from src/settings/handlers/SettingsHandler.js rename to src/settings/handlers/SettingsHandler.ts index 7d987fc136..ca9a068fd3 100644 --- a/src/settings/handlers/SettingsHandler.js +++ b/src/settings/handlers/SettingsHandler.ts @@ -1,6 +1,6 @@ /* Copyright 2017 Travis Ralston -Copyright 2019 New Vector Ltd. +Copyright 2019, 2020 The Matrix.org Foundation C.I.C. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -19,7 +19,7 @@ limitations under the License. * Represents the base class for all level handlers. This class performs no logic * and should be overridden. */ -export default class SettingsHandler { +export default abstract 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 @@ -28,10 +28,7 @@ export default class SettingsHandler { * @param {String} roomId The room ID to read from, may be null. * @returns {*} The setting value, or null if not found. */ - getValue(settingName, roomId) { - console.error("Invalid operation: getValue was not overridden"); - return null; - } + public abstract getValue(settingName: string, roomId: string): any; /** * Sets the value for a particular setting at this level for a particular room. @@ -44,10 +41,7 @@ export default class SettingsHandler { * @param {*} newValue The new value for the setting, may be null. * @returns {Promise} Resolves when the setting has been saved. */ - setValue(settingName, roomId, newValue) { - console.error("Invalid operation: setValue was not overridden"); - return Promise.reject(); - } + public abstract setValue(settingName: string, roomId: string, newValue: any): Promise; /** * Determines if the current user is able to set the value of the given setting @@ -56,15 +50,11 @@ export default class SettingsHandler { * @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; - } + public abstract canSetValue(settingName: string, roomId: string): boolean; /** * Determines if this level is supported on this device. * @returns {boolean} True if this level is supported on the current device. */ - isSupported() { - return false; - } + public abstract isSupported(): boolean; } diff --git a/src/settings/watchers/FontWatcher.ts b/src/settings/watchers/FontWatcher.ts index 53ef999f9b..6a17bf2aa3 100644 --- a/src/settings/watchers/FontWatcher.ts +++ b/src/settings/watchers/FontWatcher.ts @@ -15,10 +15,11 @@ limitations under the License. */ import dis from '../../dispatcher/dispatcher'; -import SettingsStore, {SettingLevel} from '../SettingsStore'; +import SettingsStore from '../SettingsStore'; import IWatcher from "./Watcher"; import { toPx } from '../../utils/units'; import { Action } from '../../dispatcher/actions'; +import { SettingLevel } from "../SettingLevel"; export class FontWatcher implements IWatcher { public static readonly MIN_SIZE = 8; diff --git a/src/settings/watchers/ThemeWatcher.ts b/src/settings/watchers/ThemeWatcher.ts index ce0db881c0..4330a15f57 100644 --- a/src/settings/watchers/ThemeWatcher.ts +++ b/src/settings/watchers/ThemeWatcher.ts @@ -15,17 +15,15 @@ See the License for the specific language governing permissions and limitations under the License. */ -import SettingsStore, { SettingLevel } from '../SettingsStore'; +import SettingsStore from '../SettingsStore'; import dis from '../../dispatcher/dispatcher'; import { Action } from '../../dispatcher/actions'; import ThemeController from "../controllers/ThemeController"; import { setTheme } from "../../theme"; import { ActionPayload } from '../../dispatcher/payloads'; +import { SettingLevel } from "../SettingLevel"; export default class ThemeWatcher { - // XXX: I think this is unused. - static _instance = null; - private themeWatchRef: string; private systemThemeWatchRef: string; private dispatcherRef: string; diff --git a/src/stores/BreadcrumbsStore.ts b/src/stores/BreadcrumbsStore.ts index ea29cb9dfc..24906f678c 100644 --- a/src/stores/BreadcrumbsStore.ts +++ b/src/stores/BreadcrumbsStore.ts @@ -14,13 +14,14 @@ See the License for the specific language governing permissions and limitations under the License. */ -import SettingsStore, { SettingLevel } from "../settings/SettingsStore"; +import SettingsStore from "../settings/SettingsStore"; import { Room } from "matrix-js-sdk/src/models/room"; import { ActionPayload } from "../dispatcher/payloads"; import { AsyncStoreWithClient } from "./AsyncStoreWithClient"; import defaultDispatcher from "../dispatcher/dispatcher"; import { arrayHasDiff } from "../utils/arrays"; import { isNullOrUndefined } from "matrix-js-sdk/src/utils"; +import { SettingLevel } from "../settings/SettingLevel"; const MAX_ROOMS = 20; // arbitrary const AUTOJOIN_WAIT_THRESHOLD_MS = 90000; // 90s, the time we wait for an autojoined room to show up diff --git a/src/stores/RightPanelStore.ts b/src/stores/RightPanelStore.ts index dc5eb99a36..c1799978ad 100644 --- a/src/stores/RightPanelStore.ts +++ b/src/stores/RightPanelStore.ts @@ -17,10 +17,11 @@ limitations under the License. import dis from '../dispatcher/dispatcher'; import {pendingVerificationRequestForUser} from '../verification'; import {Store} from 'flux/utils'; -import SettingsStore, {SettingLevel} from "../settings/SettingsStore"; +import SettingsStore from "../settings/SettingsStore"; import {RightPanelPhases, RIGHT_PANEL_PHASES_NO_ARGS} from "./RightPanelStorePhases"; import {ActionPayload} from "../dispatcher/payloads"; import {Action} from '../dispatcher/actions'; +import { SettingLevel } from "../settings/SettingLevel"; interface RightPanelStoreState { // Whether or not to show the right panel at all. We split out rooms and groups