Merge pull request #5062 from matrix-org/travis/settings/ts
Convert SettingsStore to TypeScriptpull/21833/head
						commit
						3443761007
					
				|  | @ -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
 | ||||
|  |  | |||
|  | @ -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
 | ||||
|  |  | |||
|  | @ -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() { | ||||
|  |  | |||
|  | @ -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, | ||||
|  |  | |||
|  | @ -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: | ||||
|  |  | |||
|  | @ -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. | ||||
|  |  | |||
|  | @ -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. | ||||
|  |  | |||
|  | @ -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 { | ||||
|  |  | |||
|  | @ -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() {}; | ||||
|  |  | |||
|  | @ -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; | ||||
|  |  | |||
|  | @ -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) { | ||||
|  |  | |||
|  | @ -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: { | ||||
|  |  | |||
|  | @ -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 = { | ||||
|  |  | |||
|  | @ -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; | ||||
|  |  | |||
|  | @ -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
 | ||||
|  |  | |||
|  | @ -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<IProps, IState> { | |||
|         }; | ||||
|     } | ||||
| 
 | ||||
|     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<IProps, IState> { | |||
|         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, | ||||
|  |  | |||
|  | @ -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
 | ||||
|  |  | |||
|  | @ -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({ | ||||
|  |  | |||
|  | @ -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 = { | ||||
|  |  | |||
|  | @ -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"; | ||||
| 
 | ||||
|  |  | |||
|  | @ -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() { | ||||
|  |  | |||
|  | @ -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.
 | ||||
|  |  | |||
|  | @ -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() { | ||||
|  |  | |||
|  | @ -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 = { | ||||
|  |  | |||
|  | @ -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 = { | ||||
|  |  | |||
|  | @ -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 { | ||||
| } | ||||
|  |  | |||
|  | @ -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 = { | ||||
|  |  | |||
|  | @ -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 = { | ||||
|  |  | |||
|  | @ -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 = [ | ||||
|  |  | |||
|  | @ -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 = { | ||||
|  |  | |||
|  | @ -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() { | ||||
|  |  | |||
|  | @ -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]
 | ||||
|  |  | |||
|  | @ -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. | ||||
|  |  | |||
|  | @ -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; | ||||
| 
 | ||||
|  |  | |||
|  | @ -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/'; | ||||
| 
 | ||||
|  |  | |||
|  | @ -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.
 | ||||
| 
 | ||||
|  |  | |||
|  | @ -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(', ')); | ||||
|     } | ||||
|  |  | |||
|  | @ -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", | ||||
| } | ||||
|  | @ -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, | ||||
|     }, | ||||
|  | @ -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<void> { | ||||
|         // 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<void> { | ||||
|         // 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; | ||||
|  | @ -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) { | ||||
|  | @ -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({ | ||||
|  | @ -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<UpdateFontSizePayload>({ | ||||
|             action: Action.UpdateFontSize, | ||||
|  |  | |||
|  | @ -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.
 | ||||
|  | @ -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); | ||||
|     } | ||||
| } | ||||
|  | @ -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(); | ||||
|     } | ||||
| } | ||||
|  | @ -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
 | ||||
|     } | ||||
| } | ||||
|  | @ -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<UpdateSystemFontPayload>({ | ||||
|             action: Action.UpdateSystemFont, | ||||
|  |  | |||
|  | @ -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'; | ||||
|  | @ -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<UpdateSystemFontPayload>({ | ||||
|             action: Action.UpdateSystemFont, | ||||
|  |  | |||
|  | @ -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<void> { | ||||
|         // 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 || []); | ||||
|     } | ||||
| } | ||||
|  | @ -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<void> { | ||||
|         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
 | ||||
|     } | ||||
| } | ||||
|  | @ -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<string, any>, private invertedDefaults: Record<string, any>) { | ||||
|         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<void> { | ||||
|         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; | ||||
|     } | ||||
| } | ||||
|  | @ -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<void> { | ||||
|         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); | ||||
|     } | ||||
| } | ||||
|  | @ -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<void> { | ||||
|         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(); | ||||
|     } | ||||
| } | ||||
|  | @ -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"); | ||||
|     } | ||||
| } | ||||
|  | @ -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<void> { | ||||
|         // 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; | ||||
| 
 | ||||
|  | @ -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<void> { | ||||
|         // 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; | ||||
|     } | ||||
| } | ||||
|  | @ -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<void> { | ||||
|         // 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; | ||||
| 
 | ||||
|  | @ -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<void>; | ||||
| 
 | ||||
|     /** | ||||
|      * 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; | ||||
| } | ||||
|  | @ -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; | ||||
|  |  | |||
|  | @ -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; | ||||
|  |  | |||
|  | @ -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
 | ||||
|  |  | |||
|  | @ -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
 | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	 Travis Ralston
						Travis Ralston