mirror of
https://github.com/vector-im/element-web.git
synced 2026-05-04 11:51:36 +02:00
Harden settings types (#33311)
* Harden settings types * Fix types * Update apps/web/src/emojipicker/recent.ts Co-authored-by: Will Hunt <2072976+Half-Shot@users.noreply.github.com> * Fix suggestion --------- Co-authored-by: Will Hunt <2072976+Half-Shot@users.noreply.github.com>
This commit is contained in:
parent
4bee845010
commit
5ff302539e
@ -25,9 +25,9 @@ export interface MediaPreviewConfig extends Record<string, unknown> {
|
||||
/**
|
||||
* Media preview setting for thumbnails of media in rooms.
|
||||
*/
|
||||
media_previews: MediaPreviewValue;
|
||||
media_previews?: MediaPreviewValue;
|
||||
/**
|
||||
* Media preview settings for avatars of rooms we have been invited to.
|
||||
*/
|
||||
invite_avatars: MediaPreviewValue.On | MediaPreviewValue.Off;
|
||||
invite_avatars?: MediaPreviewValue.On | MediaPreviewValue.Off;
|
||||
}
|
||||
|
||||
@ -725,7 +725,7 @@ export default class LegacyCallHandler extends TypedEventEmitter<LegacyCallHandl
|
||||
);
|
||||
|
||||
finished.then(([allow]) => {
|
||||
SettingsStore.setValue("fallbackICEServerAllowed", null, SettingLevel.DEVICE, allow);
|
||||
SettingsStore.setValue("fallbackICEServerAllowed", null, SettingLevel.DEVICE, allow ?? null);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@ -142,6 +142,16 @@ interface EmittedEvents {
|
||||
[NotifierEvent.NotificationHiddenChange]: (hidden: boolean) => void;
|
||||
}
|
||||
|
||||
/**
|
||||
* Type representing a notification sound setting
|
||||
*/
|
||||
export type NotificationSound = {
|
||||
url: string;
|
||||
name?: string;
|
||||
type?: string;
|
||||
size?: number;
|
||||
};
|
||||
|
||||
class NotifierClass extends TypedEventEmitter<keyof EmittedEvents, EmittedEvents> {
|
||||
private notifsByRoom: Record<string, Notification[]> = {};
|
||||
|
||||
@ -223,12 +233,7 @@ class NotifierClass extends TypedEventEmitter<keyof EmittedEvents, EmittedEvents
|
||||
}
|
||||
}
|
||||
|
||||
public getSoundForRoom(roomId: string): {
|
||||
url: string;
|
||||
name: string;
|
||||
type: string;
|
||||
size: number;
|
||||
} | null {
|
||||
public getSoundForRoom(roomId: string): NotificationSound | null {
|
||||
// We do no caching here because the SDK caches setting
|
||||
// and the browser will cache the sound.
|
||||
const content = SettingsStore.getValue("notificationSound", roomId);
|
||||
|
||||
@ -19,7 +19,7 @@ import SettingsStore from "./settings/SettingsStore";
|
||||
import { type ScreenName } from "./PosthogTrackers";
|
||||
import { type ActionPayload } from "./dispatcher/payloads";
|
||||
import { Action } from "./dispatcher/actions";
|
||||
import { type SettingUpdatedPayload } from "./dispatcher/payloads/SettingUpdatedPayload";
|
||||
import { isSettingUpdatedPayload, type SettingUpdatedPayload } from "./dispatcher/payloads/SettingUpdatedPayload";
|
||||
import dis from "./dispatcher/dispatcher";
|
||||
import { Layout } from "./settings/enums/Layout";
|
||||
|
||||
@ -199,8 +199,8 @@ export class PosthogAnalytics {
|
||||
const settingsPayload = payload as SettingUpdatedPayload;
|
||||
if (["layout", "useCompactLayout"].includes(settingsPayload.settingName)) {
|
||||
this.onLayoutUpdated();
|
||||
} else if (settingsPayload.settingName === "urlPreviewsEnabled" && !settingsPayload.roomId) {
|
||||
this.onUrlPreviewSettingUpdated(settingsPayload.newValue as boolean);
|
||||
} else if (isSettingUpdatedPayload(settingsPayload, "urlPreviewsEnabled") && !settingsPayload.roomId) {
|
||||
this.onUrlPreviewSettingUpdated(settingsPayload.newValue);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -122,7 +122,7 @@ export default class ManageEventIndexDialog extends React.Component<IProps, ISta
|
||||
|
||||
private onCrawlerSleepTimeChange = (e: ChangeEvent<HTMLInputElement>): void => {
|
||||
this.setState({ crawlerSleepTime: parseInt(e.target.value, 10) });
|
||||
SettingsStore.setValue("crawlerSleepTime", null, SettingLevel.DEVICE, e.target.value);
|
||||
SettingsStore.setValue("crawlerSleepTime", null, SettingLevel.DEVICE, e.target.valueAsNumber);
|
||||
};
|
||||
|
||||
public render(): React.ReactNode {
|
||||
|
||||
@ -1794,11 +1794,11 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||
SettingsStore.watchSetting(
|
||||
"blacklistUnverifiedDevices",
|
||||
null,
|
||||
(_settingName, _roomId, atLevel, blacklistEnabled: boolean) => {
|
||||
(_settingName, _roomId, atLevel, blacklistEnabled) => {
|
||||
if (atLevel != SettingLevel.DEVICE) {
|
||||
return;
|
||||
}
|
||||
crypto.globalBlacklistUnverifiedDevices = blacklistEnabled;
|
||||
crypto.globalBlacklistUnverifiedDevices = !!blacklistEnabled;
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@ -38,8 +38,8 @@ function LayoutSelector(): JSX.Element {
|
||||
<Root
|
||||
className="mx_LayoutSwitcher_LayoutSelector"
|
||||
onChange={async (evt) => {
|
||||
// We don't have any file in the form, we can cast it as string safely
|
||||
const newLayout = new FormData(evt.currentTarget).get("layout") as string | null;
|
||||
// We don't have any file in the form, we can cast it as Layout safely
|
||||
const newLayout = new FormData(evt.currentTarget).get("layout") as Layout;
|
||||
await SettingsStore.setValue("layout", null, SettingLevel.DEVICE, newLayout);
|
||||
}}
|
||||
>
|
||||
|
||||
@ -211,17 +211,17 @@ export default class PreferencesUserSettingsTab extends React.Component<IProps,
|
||||
|
||||
private onAutocompleteDelayChange = (e: React.ChangeEvent<HTMLInputElement>): void => {
|
||||
this.setState({ autocompleteDelay: e.target.value });
|
||||
SettingsStore.setValue("autocompleteDelay", null, SettingLevel.DEVICE, e.target.value);
|
||||
SettingsStore.setValue("autocompleteDelay", null, SettingLevel.DEVICE, e.target.valueAsNumber);
|
||||
};
|
||||
|
||||
private onReadMarkerInViewThresholdMs = (e: React.ChangeEvent<HTMLInputElement>): void => {
|
||||
this.setState({ readMarkerInViewThresholdMs: e.target.value });
|
||||
SettingsStore.setValue("readMarkerInViewThresholdMs", null, SettingLevel.DEVICE, e.target.value);
|
||||
SettingsStore.setValue("readMarkerInViewThresholdMs", null, SettingLevel.DEVICE, e.target.valueAsNumber);
|
||||
};
|
||||
|
||||
private onReadMarkerOutOfViewThresholdMs = (e: React.ChangeEvent<HTMLInputElement>): void => {
|
||||
this.setState({ readMarkerOutOfViewThresholdMs: e.target.value });
|
||||
SettingsStore.setValue("readMarkerOutOfViewThresholdMs", null, SettingLevel.DEVICE, e.target.value);
|
||||
SettingsStore.setValue("readMarkerOutOfViewThresholdMs", null, SettingLevel.DEVICE, e.target.valueAsNumber);
|
||||
};
|
||||
|
||||
private renderGroup(settingIds: BooleanSettingKey[], level = SettingLevel.ACCOUNT): JSX.Element {
|
||||
|
||||
@ -340,7 +340,7 @@ export class DeviceListener {
|
||||
});
|
||||
}
|
||||
|
||||
private onRecordClientInformationSettingChange: CallbackFn = (
|
||||
private onRecordClientInformationSettingChange: CallbackFn<"deviceClientInformationOptIn"> = (
|
||||
_originalSettingName,
|
||||
_roomId,
|
||||
_level,
|
||||
|
||||
@ -9,14 +9,26 @@ Please see LICENSE files in the repository root for full details.
|
||||
import { type ActionPayload } from "../payloads";
|
||||
import { type Action } from "../actions";
|
||||
import { type SettingLevel } from "../../settings/SettingLevel";
|
||||
import { type SettingValueType } from "../../settings/Settings";
|
||||
import { type SettingKey, type Settings } from "../../settings/Settings";
|
||||
|
||||
export interface SettingUpdatedPayload extends ActionPayload {
|
||||
export interface SettingUpdatedPayload<S extends SettingKey = SettingKey> extends ActionPayload {
|
||||
action: Action.SettingUpdated;
|
||||
|
||||
settingName: string;
|
||||
settingName: S;
|
||||
roomId: string | null;
|
||||
level: SettingLevel;
|
||||
newValueAtLevel: SettingLevel;
|
||||
newValue: SettingValueType;
|
||||
newValueAtLevel: Settings[S]["default"];
|
||||
newValue: Settings[S]["default"];
|
||||
}
|
||||
|
||||
/**
|
||||
* Type guard to check if a payload is a SettingUpdatedPayload for a specific setting.
|
||||
* @param payload the payload to assert
|
||||
* @param settingName the setting name to check for
|
||||
*/
|
||||
export function isSettingUpdatedPayload<S extends SettingKey>(
|
||||
payload: SettingUpdatedPayload<any>,
|
||||
settingName: S,
|
||||
): payload is SettingUpdatedPayload<S> {
|
||||
return payload.settingName === settingName;
|
||||
}
|
||||
|
||||
@ -29,7 +29,7 @@ const STORAGE_LIMIT = 100;
|
||||
function migrate(): void {
|
||||
const data: ILegacyFormat = JSON.parse(window.localStorage.mx_reaction_count || "{}");
|
||||
const sorted = Object.entries(data).sort(([, [count1, date1]], [, [count2, date2]]) => date2 - date1);
|
||||
const newFormat = sorted.map(([emoji, [count, date]]) => [emoji, count]);
|
||||
const newFormat = sorted.map<RecentEmojiData[number]>(([emoji, [count, date]]) => [emoji, count]);
|
||||
SettingsStore.setValue(SETTING_NAME, null, SettingLevel.ACCOUNT, newFormat.slice(0, STORAGE_LIMIT));
|
||||
}
|
||||
|
||||
@ -41,7 +41,7 @@ export function add(emoji: string): void {
|
||||
const recents = getRecentEmoji();
|
||||
const i = recents.findIndex(([e]) => e === emoji);
|
||||
|
||||
let newEntry;
|
||||
let newEntry: RecentEmojiData[number];
|
||||
if (i >= 0) {
|
||||
// first remove the existing tuple so that we can increment it and push it to the front
|
||||
[newEntry] = recents.splice(i, 1);
|
||||
|
||||
@ -11,7 +11,7 @@ import { logger } from "matrix-js-sdk/src/logger";
|
||||
|
||||
import { MatrixClientPeg } from "../MatrixClientPeg";
|
||||
import { ALL_RULE_TYPES, BanList } from "./BanList";
|
||||
import SettingsStore from "../settings/SettingsStore";
|
||||
import SettingsStore, { type CallbackFn } from "../settings/SettingsStore";
|
||||
import { _t } from "../languageHandler";
|
||||
import dis from "../dispatcher/dispatcher";
|
||||
import { SettingLevel } from "../settings/SettingLevel";
|
||||
@ -38,7 +38,7 @@ export class Mjolnir {
|
||||
}
|
||||
|
||||
public start(): void {
|
||||
this.mjolnirWatchRef = SettingsStore.watchSetting("mjolnirRooms", null, this.onListsChanged.bind(this));
|
||||
this.mjolnirWatchRef = SettingsStore.watchSetting("mjolnirRooms", null, this.onListsChanged);
|
||||
|
||||
this.dispatcherRef = dis.register(this.onAction);
|
||||
dis.dispatch<DoAfterSyncPreparedPayload<ActionPayload>>({
|
||||
@ -130,15 +130,10 @@ export class Mjolnir {
|
||||
this.updateLists(this._roomIds);
|
||||
};
|
||||
|
||||
private onListsChanged(
|
||||
settingName: string,
|
||||
roomId: string | null,
|
||||
atLevel: SettingLevel,
|
||||
newValue: string[],
|
||||
): void {
|
||||
private onListsChanged: CallbackFn<"mjolnirRooms"> = (settingName, roomId, atLevel, newValue): void => {
|
||||
// We know that ban lists are only recorded at one level so we don't need to re-eval them
|
||||
this.updateLists(newValue);
|
||||
}
|
||||
this.updateLists(newValue ?? []);
|
||||
};
|
||||
|
||||
private updateLists(listRoomIds: string[]): void {
|
||||
if (!MatrixClientPeg.get()) return;
|
||||
|
||||
@ -54,6 +54,7 @@ import { type ComputedInviteConfig } from "../@types/invite-rules.ts";
|
||||
import BlockInvitesConfigController from "./controllers/BlockInvitesConfigController.ts";
|
||||
import RequiresSettingsController from "./controllers/RequiresSettingsController.ts";
|
||||
import { type OrderedCustomSections, type CustomSectionsData } from "../stores/room-list-v3/section.ts";
|
||||
import { type NotificationSound } from "../Notifier.ts";
|
||||
|
||||
export const defaultWatchManager = new WatchManager();
|
||||
|
||||
@ -311,15 +312,7 @@ export interface Settings {
|
||||
"urlPreviewsEnabled_e2ee": IBaseSetting<boolean>;
|
||||
"notificationsEnabled": IBaseSetting<boolean>;
|
||||
"deviceNotificationsEnabled": IBaseSetting<boolean>;
|
||||
"notificationSound": IBaseSetting<
|
||||
| {
|
||||
name: string;
|
||||
type: string;
|
||||
size: number;
|
||||
url: string;
|
||||
}
|
||||
| false
|
||||
>;
|
||||
"notificationSound": IBaseSetting<NotificationSound | false>;
|
||||
"notificationBodyEnabled": IBaseSetting<boolean>;
|
||||
"audioNotificationsEnabled": IBaseSetting<boolean>;
|
||||
"enableWidgetScreenshots": IBaseSetting<boolean>;
|
||||
|
||||
@ -79,7 +79,7 @@ export const LEVEL_ORDER = [
|
||||
SettingLevel.DEFAULT,
|
||||
];
|
||||
|
||||
function getLevelOrder(setting: ISetting): SettingLevel[] {
|
||||
function getLevelOrder(setting: Settings[keyof Settings]): SettingLevel[] {
|
||||
// Settings which support only a single setting level are inherently ordered
|
||||
if (setting.supportedLevelsAreOrdered || setting.supportedLevels.length === 1) {
|
||||
// return a copy to prevent callers from modifying the array
|
||||
@ -88,12 +88,12 @@ function getLevelOrder(setting: ISetting): SettingLevel[] {
|
||||
return LEVEL_ORDER;
|
||||
}
|
||||
|
||||
export type CallbackFn = (
|
||||
settingName: SettingKey,
|
||||
export type CallbackFn<S extends SettingKey> = (
|
||||
settingName: S,
|
||||
roomId: string | null,
|
||||
atLevel: SettingLevel,
|
||||
newValAtLevel: any,
|
||||
newVal: any,
|
||||
newValAtLevel: Settings[S]["default"] | null,
|
||||
newVal: Settings[S]["default"] | null,
|
||||
) => void;
|
||||
|
||||
type HandlerMap = Partial<{
|
||||
@ -167,7 +167,11 @@ 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.
|
||||
*/
|
||||
public static watchSetting(settingName: SettingKey, roomId: string | null, callbackFn: CallbackFn): string {
|
||||
public static watchSetting<S extends SettingKey>(
|
||||
settingName: S,
|
||||
roomId: string | null,
|
||||
callbackFn: CallbackFn<S>,
|
||||
): string {
|
||||
const setting = SETTINGS[settingName];
|
||||
if (!setting) throw new Error(`${settingName} is not a setting`);
|
||||
|
||||
@ -175,7 +179,11 @@ export default class SettingsStore {
|
||||
|
||||
const watcherId = `${new Date().getTime()}_${SettingsStore.watcherCount++}_${finalSettingName}_${roomId}`;
|
||||
|
||||
const localizedCallback = (changedInRoomId: string | null, atLevel: SettingLevel, newValAtLevel: any): void => {
|
||||
const localizedCallback = (
|
||||
changedInRoomId: string | null,
|
||||
atLevel: SettingLevel,
|
||||
newValAtLevel: Settings[S]["default"],
|
||||
): void => {
|
||||
if (!SettingsStore.doesSettingSupportLevel(settingName, atLevel)) {
|
||||
logger.warn(
|
||||
`Setting handler notified for an update of an invalid setting level: ` +
|
||||
@ -220,7 +228,7 @@ 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.
|
||||
*/
|
||||
public static monitorSetting(settingName: SettingKey, roomId: string | null): void {
|
||||
public static monitorSetting<S extends SettingKey>(settingName: S, roomId: string | null): void {
|
||||
roomId = roomId || null; // the thing wants null specifically to work, so appease it.
|
||||
|
||||
if (!this.monitors.has(settingName)) this.monitors.set(settingName, new Map());
|
||||
@ -228,7 +236,7 @@ export default class SettingsStore {
|
||||
const registerWatcher = (): void => {
|
||||
this.monitors.get(settingName)!.set(
|
||||
roomId,
|
||||
SettingsStore.watchSetting(
|
||||
SettingsStore.watchSetting<S>(
|
||||
settingName,
|
||||
roomId,
|
||||
(settingName, inRoomId, level, newValueAtLevel, newValue) => {
|
||||
@ -449,11 +457,10 @@ export default class SettingsStore {
|
||||
|
||||
/**
|
||||
* Gets the default value of a setting.
|
||||
* @param {string} settingName The name of the setting to read the value of.
|
||||
* @param {String} roomId The room ID to read the setting value in, may be null.
|
||||
* @return {*} The default value
|
||||
* @param settingName The name of the setting to read the value of.
|
||||
* @return The default value
|
||||
*/
|
||||
public static getDefaultValue(settingName: SettingKey): any {
|
||||
public static getDefaultValue<S extends SettingKey>(settingName: S): Settings[S]["default"] {
|
||||
// Verify that the setting is actually a setting
|
||||
if (!SETTINGS[settingName]) {
|
||||
throw new Error("Setting '" + settingName + "' does not appear to be a setting.");
|
||||
@ -462,13 +469,13 @@ export default class SettingsStore {
|
||||
return SETTINGS[settingName].default;
|
||||
}
|
||||
|
||||
private static getFinalValue(
|
||||
setting: ISetting,
|
||||
private static getFinalValue<S extends SettingKey>(
|
||||
setting: Settings[S],
|
||||
level: SettingLevel,
|
||||
roomId: string | null,
|
||||
calculatedValue: any,
|
||||
calculatedValue: Settings[S]["default"],
|
||||
calculatedAtLevel: SettingLevel | null,
|
||||
): any {
|
||||
): Settings[S]["default"] {
|
||||
let resultingValue = calculatedValue;
|
||||
|
||||
if (setting.controller) {
|
||||
@ -480,25 +487,22 @@ export default class SettingsStore {
|
||||
return resultingValue;
|
||||
}
|
||||
|
||||
/* eslint-disable valid-jsdoc */ //https://github.com/eslint/eslint/issues/7307
|
||||
/**
|
||||
* Sets the value for a setting. The room ID is optional if the setting is not being
|
||||
* set for a particular room, otherwise it should be supplied. The value may be null
|
||||
* to indicate that the level should no longer have an override.
|
||||
* @param {string} settingName The name of the setting to change.
|
||||
* @param {String} roomId The room ID to change the value in, may be null.
|
||||
* @param {SettingLevel} level The level
|
||||
* @param settingName The name of the setting to change.
|
||||
* @param roomId The room ID to change the value in, may be null.
|
||||
* @param 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.
|
||||
* @param value The new value of the setting, may be null.
|
||||
* @return Resolves when the setting has been changed.
|
||||
*/
|
||||
|
||||
/* eslint-enable valid-jsdoc */
|
||||
public static async setValue(
|
||||
settingName: SettingKey,
|
||||
public static async setValue<S extends SettingKey>(
|
||||
settingName: S,
|
||||
roomId: string | null,
|
||||
level: SettingLevel,
|
||||
value: any,
|
||||
value: Settings[S]["default"] | null,
|
||||
): Promise<void> {
|
||||
// Verify that the setting is actually a setting
|
||||
const setting = SETTINGS[settingName];
|
||||
|
||||
@ -38,8 +38,8 @@ export default class MediaPreviewConfigController extends MatrixClientBackedCont
|
||||
const validMediaPreviews = Object.values(MediaPreviewValue);
|
||||
const validInviteAvatars = [MediaPreviewValue.Off, MediaPreviewValue.On];
|
||||
return {
|
||||
invite_avatars: validInviteAvatars.includes(inviteAvatars) ? inviteAvatars : undefined,
|
||||
media_previews: validMediaPreviews.includes(mediaPreviews) ? mediaPreviews : undefined,
|
||||
invite_avatars: validInviteAvatars.includes(inviteAvatars!) ? inviteAvatars : undefined,
|
||||
media_previews: validMediaPreviews.includes(mediaPreviews!) ? mediaPreviews : undefined,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -60,8 +60,8 @@ export type IRightPanelForRoomStored = {
|
||||
history: Array<IRightPanelCardStored>;
|
||||
};
|
||||
|
||||
export function convertToStorePanel(cacheRoom?: IRightPanelForRoom): IRightPanelForRoomStored | undefined {
|
||||
if (!cacheRoom) return undefined;
|
||||
export function convertToStorePanel(cacheRoom?: IRightPanelForRoom): IRightPanelForRoomStored | null {
|
||||
if (!cacheRoom) return null;
|
||||
const storeHistory = [...cacheRoom.history].map((panelState) => convertCardToStore(panelState));
|
||||
return { isOpen: cacheRoom.isOpen, history: storeHistory };
|
||||
}
|
||||
|
||||
@ -69,7 +69,7 @@ export class RoomListStoreClass extends AsyncStoreWithClient<EmptyObject> implem
|
||||
"feature_dynamic_room_predecessors",
|
||||
null,
|
||||
(_settingName, _roomId, _level, _newValAtLevel, newVal) => {
|
||||
this.msc3946ProcessDynamicPredecessor = newVal;
|
||||
this.msc3946ProcessDynamicPredecessor = !!newVal;
|
||||
this.regenerateAllLists({ trigger: true });
|
||||
},
|
||||
);
|
||||
|
||||
@ -231,7 +231,7 @@ export class EventContentBodyViewModel
|
||||
"TextualBody.enableBigEmoji",
|
||||
null,
|
||||
(_settingName, _roomId, _level, _newValAtLevel, newVal) => {
|
||||
this.setEnableBigEmoji(newVal);
|
||||
this.setEnableBigEmoji(!!newVal);
|
||||
},
|
||||
);
|
||||
this.disposables.track(() => SettingsStore.unwatchSetting(enableBigEmojiWatcherRef));
|
||||
@ -240,7 +240,7 @@ export class EventContentBodyViewModel
|
||||
"Pill.shouldShowPillAvatar",
|
||||
null,
|
||||
(_settingName, _roomId, _level, _newValAtLevel, newVal) => {
|
||||
this.setShouldShowPillAvatar(newVal);
|
||||
this.setShouldShowPillAvatar(!!newVal);
|
||||
},
|
||||
);
|
||||
this.disposables.track(() => SettingsStore.unwatchSetting(shouldShowPillAvatarWatcherRef));
|
||||
|
||||
@ -75,7 +75,7 @@ export class RedactedBodyViewModel
|
||||
(_settingName, _roomId, _level, _newValAtLevel, newVal) => {
|
||||
if (this.showTwelveHour === newVal) return;
|
||||
|
||||
this.showTwelveHour = newVal;
|
||||
this.showTwelveHour = !!newVal;
|
||||
this.updateTooltip();
|
||||
},
|
||||
);
|
||||
|
||||
@ -296,7 +296,7 @@ export class UrlPreviewGroupViewModel
|
||||
null,
|
||||
(_setting, _roomid, _level, compactLayout) => {
|
||||
this.snapshot.merge({
|
||||
compactLayout,
|
||||
compactLayout: !!compactLayout,
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
@ -79,7 +79,7 @@ export class DateSeparatorViewModel
|
||||
"feature_jump_to_date",
|
||||
null,
|
||||
(_settingName, _roomId, _level, _newValAtLevel, newVal) => {
|
||||
this.jumpToDateEnabled = newVal;
|
||||
this.jumpToDateEnabled = !!newVal;
|
||||
this.updateSnapshot();
|
||||
},
|
||||
);
|
||||
@ -89,7 +89,7 @@ export class DateSeparatorViewModel
|
||||
UIFeature.TimelineEnableRelativeDates,
|
||||
null,
|
||||
(_settingName, _roomId, _level, _newValAtLevel, newVal) => {
|
||||
this.relativeDatesEnabled = newVal;
|
||||
this.relativeDatesEnabled = !!newVal;
|
||||
this.updateSnapshot();
|
||||
},
|
||||
);
|
||||
|
||||
@ -557,7 +557,7 @@ describe("<MatrixChat />", () => {
|
||||
});
|
||||
|
||||
it("should not persist device language when not available", async () => {
|
||||
await SettingsStore.setValue("language", null, SettingLevel.DEVICE, undefined);
|
||||
await SettingsStore.setValue("language", null, SettingLevel.DEVICE, null);
|
||||
const languageBefore = SettingsStore.getValueAt(SettingLevel.DEVICE, "language", null, true, true);
|
||||
|
||||
jest.spyOn(Lifecycle, "attemptDelegatedAuthLogin");
|
||||
|
||||
@ -225,7 +225,7 @@ describe("<UserSettingsDialog />", () => {
|
||||
});
|
||||
|
||||
it("watches settings", async () => {
|
||||
const watchSettingCallbacks: Record<string, CallbackFn> = {};
|
||||
const watchSettingCallbacks: Record<string, CallbackFn<any>> = {};
|
||||
|
||||
mockSettingsStore.watchSetting.mockImplementation((settingName, roomId, callback) => {
|
||||
watchSettingCallbacks[settingName] = callback;
|
||||
|
||||
@ -28,7 +28,7 @@ describe("ReleaseAnnouncementStore", () => {
|
||||
settings = {
|
||||
releaseAnnouncementData: {},
|
||||
};
|
||||
const watchCallbacks: Array<CallbackFn> = [];
|
||||
const watchCallbacks: Array<CallbackFn<any>> = [];
|
||||
|
||||
mocked(SettingsStore.getValue).mockImplementation((setting: string) => {
|
||||
return settings[setting];
|
||||
|
||||
@ -203,13 +203,11 @@ describe("RoomListStore", () => {
|
||||
let featureFlagValue = false;
|
||||
jest.spyOn(SettingsStore, "getValue").mockImplementation(() => featureFlagValue);
|
||||
|
||||
let watchCallback: CallbackFn | undefined;
|
||||
jest.spyOn(SettingsStore, "watchSetting").mockImplementation(
|
||||
(_settingName: string, _roomId: string | null, callbackFn: CallbackFn) => {
|
||||
watchCallback = callbackFn;
|
||||
return "dyn_pred_ref";
|
||||
},
|
||||
);
|
||||
let watchCallback: CallbackFn<any> | undefined;
|
||||
jest.spyOn(SettingsStore, "watchSetting").mockImplementation((_settingName, _roomId, callbackFn) => {
|
||||
watchCallback = callbackFn;
|
||||
return "dyn_pred_ref";
|
||||
});
|
||||
jest.spyOn(SettingsStore, "unwatchSetting");
|
||||
|
||||
const { store } = createStore();
|
||||
|
||||
@ -664,7 +664,7 @@ describe("RoomListItemViewModel", () => {
|
||||
});
|
||||
|
||||
it("should update sections when OrderedCustomSections setting changes", () => {
|
||||
let watchCallback: CallbackFn = () => {};
|
||||
let watchCallback: CallbackFn<"RoomList.OrderedCustomSections"> = () => {};
|
||||
jest.spyOn(SettingsStore, "watchSetting").mockImplementation((setting, _room, callback) => {
|
||||
if (setting === "RoomList.OrderedCustomSections") watchCallback = callback;
|
||||
return "watcher-id";
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user