Merge branch 'develop' into sort-imports

Signed-off-by: Aaron Raimist <aaron@raim.ist>
This commit is contained in:
Aaron Raimist 2021-12-09 08:34:20 +00:00
commit 7b94e13a84
642 changed files with 30052 additions and 8035 deletions

View file

@ -37,11 +37,12 @@ import { isMac } from '../Keyboard';
import UIFeatureController from "./controllers/UIFeatureController";
import { UIFeature } from "./UIFeature";
import { OrderedMultiController } from "./controllers/OrderedMultiController";
import { Layout } from "./Layout";
import { Layout } from "./enums/Layout";
import ReducedMotionController from './controllers/ReducedMotionController';
import IncompatibleController from "./controllers/IncompatibleController";
import PseudonymousAnalyticsController from './controllers/PseudonymousAnalyticsController';
import NewLayoutSwitcherController from './controllers/NewLayoutSwitcherController';
import { ImageSize } from "./enums/ImageSize";
import { MetaSpace } from "../stores/spaces";
// These are just a bunch of helper arrays to avoid copy/pasting a bunch of times
const LEVELS_ROOM_SETTINGS = [
@ -84,9 +85,38 @@ const LEVELS_UI_FEATURE = [
// in future we might have a .well-known level or something
];
export interface ISetting {
// Must be set to true for features. Default is 'false'.
isFeature?: boolean;
export enum LabGroup {
Messaging,
Profile,
Spaces,
Widgets,
Rooms,
Moderation,
Analytics,
MessagePreviews,
Themes,
Encryption,
Experimental,
Developer,
}
export const labGroupNames: Record<LabGroup, string> = {
[LabGroup.Messaging]: _td("Messaging"),
[LabGroup.Profile]: _td("Profile"),
[LabGroup.Spaces]: _td("Spaces"),
[LabGroup.Widgets]: _td("Widgets"),
[LabGroup.Rooms]: _td("Rooms"),
[LabGroup.Moderation]: _td("Moderation"),
[LabGroup.Analytics]: _td("Analytics"),
[LabGroup.MessagePreviews]: _td("Message Previews"),
[LabGroup.Themes]: _td("Themes"),
[LabGroup.Encryption]: _td("Encryption"),
[LabGroup.Experimental]: _td("Experimental"),
[LabGroup.Developer]: _td("Developer"),
};
interface IBaseSetting {
isFeature?: false | undefined;
// Display names are strongly recommended for clarity.
// Display name can also be an object for different levels.
@ -136,9 +166,19 @@ export interface ISetting {
};
}
export interface IFeature extends Omit<IBaseSetting, "isFeature"> {
// Must be set to true for features.
isFeature: true;
labsGroup: LabGroup;
}
// Type using I-identifier for backwards compatibility from before it became a discriminated union
export type ISetting = IBaseSetting | IFeature;
export const SETTINGS: {[setting: string]: ISetting} = {
"feature_report_to_moderators": {
isFeature: true,
labsGroup: LabGroup.Moderation,
displayName: _td("Report to moderators prototype. " +
"In rooms that support moderation, the `report` button will let you report abuse to room moderators"),
supportedLevels: LEVELS_FEATURE,
@ -146,18 +186,21 @@ export const SETTINGS: {[setting: string]: ISetting} = {
},
"feature_dnd": {
isFeature: true,
labsGroup: LabGroup.Profile,
displayName: _td("Show options to enable 'Do not disturb' mode"),
supportedLevels: LEVELS_FEATURE,
default: false,
},
"feature_latex_maths": {
isFeature: true,
labsGroup: LabGroup.Messaging,
displayName: _td("Render LaTeX maths in messages"),
supportedLevels: LEVELS_FEATURE,
default: false,
},
"feature_communities_v2_prototypes": {
isFeature: true,
labsGroup: LabGroup.Spaces,
displayName: _td(
"Communities v2 prototypes. Requires compatible homeserver. " +
"Highly experimental - use with caution.",
@ -168,12 +211,21 @@ export const SETTINGS: {[setting: string]: ISetting} = {
},
"feature_pinning": {
isFeature: true,
labsGroup: LabGroup.Messaging,
displayName: _td("Message Pinning"),
supportedLevels: LEVELS_FEATURE,
default: false,
},
"feature_maximised_widgets": {
isFeature: true,
labsGroup: LabGroup.Widgets,
displayName: _td("Maximised widgets"),
supportedLevels: LEVELS_FEATURE,
default: false,
},
"feature_thread": {
isFeature: true,
labsGroup: LabGroup.Messaging,
// Requires a reload as we change an option flag on the `js-sdk`
// And the entire sync history needs to be parsed again
controller: new ReloadOnChangeController(),
@ -183,6 +235,7 @@ export const SETTINGS: {[setting: string]: ISetting} = {
},
"feature_custom_status": {
isFeature: true,
labsGroup: LabGroup.Profile,
displayName: _td("Custom user status messages"),
supportedLevels: LEVELS_FEATURE,
default: false,
@ -190,6 +243,7 @@ export const SETTINGS: {[setting: string]: ISetting} = {
},
"feature_custom_tags": {
isFeature: true,
labsGroup: LabGroup.Experimental,
displayName: _td("Group & filter rooms by custom tags (refresh to apply changes)"),
supportedLevels: LEVELS_FEATURE,
default: false,
@ -197,30 +251,35 @@ export const SETTINGS: {[setting: string]: ISetting} = {
},
"feature_state_counters": {
isFeature: true,
labsGroup: LabGroup.Rooms,
displayName: _td("Render simple counters in room header"),
supportedLevels: LEVELS_FEATURE,
default: false,
},
"feature_many_integration_managers": {
isFeature: true,
labsGroup: LabGroup.Experimental,
displayName: _td("Multiple integration managers (requires manual setup)"),
supportedLevels: LEVELS_FEATURE,
default: false,
},
"feature_mjolnir": {
isFeature: true,
labsGroup: LabGroup.Moderation,
displayName: _td("Try out new ways to ignore people (experimental)"),
supportedLevels: LEVELS_FEATURE,
default: false,
},
"feature_custom_themes": {
isFeature: true,
labsGroup: LabGroup.Themes,
displayName: _td("Support adding custom themes"),
supportedLevels: LEVELS_FEATURE,
default: false,
},
"feature_roomlist_preview_reactions_dms": {
isFeature: true,
labsGroup: LabGroup.MessagePreviews,
displayName: _td("Show message previews for reactions in DMs"),
supportedLevels: LEVELS_FEATURE,
default: false,
@ -229,32 +288,36 @@ export const SETTINGS: {[setting: string]: ISetting} = {
},
"feature_roomlist_preview_reactions_all": {
isFeature: true,
labsGroup: LabGroup.MessagePreviews,
displayName: _td("Show message previews for reactions in all rooms"),
supportedLevels: LEVELS_FEATURE,
default: false,
},
"feature_dehydration": {
isFeature: true,
labsGroup: LabGroup.Encryption,
displayName: _td("Offline encrypted messaging using dehydrated devices"),
supportedLevels: LEVELS_FEATURE,
default: false,
},
"feature_pseudonymous_analytics_opt_in": {
isFeature: true,
supportedLevels: LEVELS_FEATURE,
displayName: _td('Send pseudonymous analytics data'),
default: false,
controller: new PseudonymousAnalyticsController(),
},
"feature_polls": {
isFeature: true,
labsGroup: LabGroup.Messaging,
supportedLevels: LEVELS_FEATURE,
displayName: _td("Polls (under active development)"),
default: false,
},
"feature_location_share": {
isFeature: true,
labsGroup: LabGroup.Messaging,
supportedLevels: LEVELS_FEATURE,
displayName: _td("Location sharing (under active development)"),
default: false,
},
"doNotDisturb": {
supportedLevels: [SettingLevel.DEVICE],
default: false,
controller: new IncompatibleController("feature_dnd", false, false),
},
"mjolnirRooms": {
supportedLevels: [SettingLevel.ACCOUNT],
@ -266,26 +329,44 @@ export const SETTINGS: {[setting: string]: ISetting} = {
},
"feature_bridge_state": {
isFeature: true,
labsGroup: LabGroup.Rooms,
supportedLevels: LEVELS_FEATURE,
displayName: _td("Show info about bridges in room settings"),
default: false,
},
"feature_new_layout_switcher": {
isFeature: true,
labsGroup: LabGroup.Messaging,
supportedLevels: LEVELS_FEATURE,
displayName: _td("New layout switcher (with message bubbles)"),
default: false,
controller: new NewLayoutSwitcherController(),
},
"feature_spaces_metaspaces": {
isFeature: true,
labsGroup: LabGroup.Spaces,
supportedLevels: LEVELS_FEATURE,
displayName: _td("Meta Spaces"),
default: false,
controller: new OrderedMultiController([
new IncompatibleController("showCommunitiesInsteadOfSpaces"),
new ReloadOnChangeController(),
]),
},
"feature_breadcrumbs_v2": {
isFeature: true,
labsGroup: LabGroup.Rooms,
supportedLevels: LEVELS_FEATURE,
displayName: _td("Use new room breadcrumbs"),
default: false,
},
"RoomList.backgroundImage": {
supportedLevels: LEVELS_ACCOUNT_SETTINGS,
default: null,
},
"feature_hidden_read_receipts": {
supportedLevels: LEVELS_FEATURE,
displayName: _td(
"Don't send read receipts",
),
displayName: _td("Don't send read receipts"),
default: false,
},
"baseFontSize": {
@ -309,6 +390,7 @@ export const SETTINGS: {[setting: string]: ISetting} = {
supportedLevels: LEVELS_ACCOUNT_SETTINGS,
displayName: _td('Show stickers button'),
default: true,
controller: new UIFeatureController(UIFeature.Widgets, false),
},
// TODO: Wire up appropriately to UI (FTUE notifications)
"Notifications.alwaysShowBadgeCounts": {
@ -317,7 +399,7 @@ export const SETTINGS: {[setting: string]: ISetting} = {
},
"useCompactLayout": {
supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS,
displayName: _td('Use a more compact Modern layout'),
displayName: _td("Use a more compact 'Modern' layout"),
default: false,
},
"showRedactions": {
@ -537,6 +619,11 @@ export const SETTINGS: {[setting: string]: ISetting} = {
supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS_WITH_CONFIG,
default: true,
},
"pseudonymousAnalyticsOptIn": {
supportedLevels: [SettingLevel.ACCOUNT],
displayName: _td('Send analytics data'),
default: null,
},
"autocompleteDelay": {
supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS_WITH_CONFIG,
default: 200,
@ -635,6 +722,7 @@ export const SETTINGS: {[setting: string]: ISetting} = {
supportedLevels: LEVELS_ACCOUNT_SETTINGS,
displayName: _td("Show shortcuts to recently viewed rooms above the room list"),
default: true,
controller: new IncompatibleController("feature_breadcrumbs_v2", true),
},
"showHiddenEventsInTimeline": {
displayName: _td("Show hidden events in timeline"),
@ -720,6 +808,10 @@ export const SETTINGS: {[setting: string]: ISetting} = {
supportedLevels: LEVELS_ACCOUNT_SETTINGS,
default: Layout.Group,
},
"Images.size": {
supportedLevels: LEVELS_ACCOUNT_SETTINGS,
default: ImageSize.Normal,
},
"showChatEffects": {
supportedLevels: LEVELS_ROOM_SETTINGS_WITH_ROOM,
displayName: _td("Show chat effects (animations when receiving e.g. confetti)"),
@ -749,6 +841,15 @@ export const SETTINGS: {[setting: string]: ISetting} = {
default: false,
controller: new IncompatibleController("showCommunitiesInsteadOfSpaces", null),
},
"Spaces.enabledMetaSpaces": {
supportedLevels: LEVELS_ACCOUNT_SETTINGS,
default: {
[MetaSpace.Home]: true,
},
controller: new IncompatibleController("feature_spaces_metaspaces", {
[MetaSpace.Home]: true,
}, false),
},
"showCommunitiesInsteadOfSpaces": {
displayName: _td("Display Communities instead of Spaces"),
description: _td("Temporarily show communities instead of Spaces for this session. " +
@ -762,6 +863,12 @@ export const SETTINGS: {[setting: string]: ISetting} = {
supportedLevels: LEVELS_ACCOUNT_SETTINGS,
default: false,
},
"automaticErrorReporting": {
displayName: _td("Automatically send debug logs on any error"),
supportedLevels: LEVELS_ACCOUNT_SETTINGS,
default: false,
controller: new ReloadOnChangeController(),
},
[UIFeature.RoomHistorySettings]: {
supportedLevels: LEVELS_UI_FEATURE,
default: true,

View file

@ -26,7 +26,7 @@ import RoomSettingsHandler from "./handlers/RoomSettingsHandler";
import ConfigSettingsHandler from "./handlers/ConfigSettingsHandler";
import { _t } from '../languageHandler';
import dis from '../dispatcher/dispatcher';
import { ISetting, SETTINGS } from "./Settings";
import { IFeature, ISetting, LabGroup, SETTINGS } from "./Settings";
import LocalEchoWrapper from "./handlers/LocalEchoWrapper";
import { WatchManager, CallbackFn as WatchCallbackFn } from "./WatchManager";
import { SettingLevel } from "./SettingLevel";
@ -273,7 +273,7 @@ export default class SettingsStore {
return SETTINGS[settingName].isFeature;
}
public static getBetaInfo(settingName: string) {
public static getBetaInfo(settingName: string): ISetting["betaInfo"] {
// consider a beta disabled if the config is explicitly set to false, in which case treat as normal Labs flag
if (SettingsStore.isFeature(settingName)
&& SettingsStore.getValueAt(SettingLevel.CONFIG, settingName, null, true, true) !== false
@ -282,6 +282,12 @@ export default class SettingsStore {
}
}
public static getLabGroup(settingName: string): LabGroup {
if (SettingsStore.isFeature(settingName)) {
return (<IFeature>SETTINGS[settingName]).labsGroup;
}
}
/**
* Determines if a setting is enabled.
* If a setting is disabled then it should be hidden from the user.

View file

@ -14,7 +14,7 @@ limitations under the License.
import SettingController from "./SettingController";
import { SettingLevel } from "../SettingLevel";
import SettingsStore from "../SettingsStore";
import { Layout } from "../Layout";
import { Layout } from "../enums/Layout";
export default class NewLayoutSwitcherController extends SettingController {
public onChange(level: SettingLevel, roomId: string, newValue: any) {

View file

@ -1,26 +0,0 @@
/*
Copyright 2021 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.
*/
import SettingController from "./SettingController";
import { SettingLevel } from "../SettingLevel";
import { PosthogAnalytics } from "../../PosthogAnalytics";
import { MatrixClientPeg } from "../../MatrixClientPeg";
export default class PseudonymousAnalyticsController extends SettingController {
public onChange(level: SettingLevel, roomId: string, newValue: any) {
PosthogAnalytics.instance.updateAnonymityFromSettings(MatrixClientPeg.get().getUserId());
}
}

View file

@ -54,6 +54,8 @@ export default abstract class SettingController {
*/
public onChange(level: SettingLevel, roomId: string, newValue: any) {
// do nothing by default
// FIXME: force a fresh on the RoomView for the roomId in question
}
/**

View file

@ -0,0 +1,38 @@
/*
Copyright 2021 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.
*/
// For Large the image gets drawn as big as possible.
// constraint by: timeline width, manual heigh overrides, SIZE_LARGE.h
const SIZE_LARGE = { w: 800, h: 600 };
// For Normal the image gets drawn to never exceed SIZE_NORMAL.w, SIZE_NORMAL.h
// constraint by: timeline width, manual heigh overrides
const SIZE_NORMAL_LANDSCAPE = { w: 324, h: 324 }; // for w > h
const SIZE_NORMAL_PORTRAIT = { w: 324 * (9/16), h: 324 }; // for h > w
export enum ImageSize {
Normal = "normal",
Large = "large",
}
export function suggestedSize(size: ImageSize, portrait = false): { w: number, h: number} {
switch (size) {
case ImageSize.Large:
return SIZE_LARGE;
case ImageSize.Normal:
default:
return portrait ? SIZE_NORMAL_PORTRAIT : SIZE_NORMAL_LANDSCAPE;
}
}

View file

@ -29,6 +29,7 @@ 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";
const ANALYTICS_EVENT_TYPE = "im.vector.analytics";
/**
* Gets and sets settings at the "account" level for the current user.
@ -57,7 +58,7 @@ export default class AccountSettingsHandler extends MatrixClientBackedSettingsHa
}
this.watchers.notifyUpdate("urlPreviewsEnabled", null, SettingLevel.ACCOUNT, val);
} else if (event.getType() === "im.vector.web.settings") {
} else if (event.getType() === "im.vector.web.settings" || event.getType() === ANALYTICS_EVENT_TYPE) {
// Figure out what changed and fire those updates
const prevContent = prevEvent ? prevEvent.getContent() : {};
const changedSettings = objectKeyChanges<Record<string, any>>(prevContent, event.getContent());
@ -128,6 +129,13 @@ export default class AccountSettingsHandler extends MatrixClientBackedSettingsHa
return value;
}
if (settingName === "pseudonymousAnalyticsOptIn") {
const content = this.getSettings(ANALYTICS_EVENT_TYPE) || {};
// Check to make sure that we actually got a boolean
if (typeof(content[settingName]) !== "boolean") return null;
return content[settingName];
}
const settings = this.getSettings() || {};
let preferredValue = settings[settingName];
@ -180,6 +188,14 @@ export default class AccountSettingsHandler extends MatrixClientBackedSettingsHa
return;
}
// Special case analytics
if (settingName === "pseudonymousAnalyticsOptIn") {
const content = this.getSettings(ANALYTICS_EVENT_TYPE) || {};
content[settingName] = newValue;
await MatrixClientPeg.get().setAccountData(ANALYTICS_EVENT_TYPE, content);
return;
}
const content = this.getSettings() || {};
content[settingName] = newValue;
await MatrixClientPeg.get().setAccountData("im.vector.web.settings", content);

View file

@ -20,7 +20,7 @@ import SettingsHandler from "./SettingsHandler";
import { MatrixClientPeg } from "../../MatrixClientPeg";
import { SettingLevel } from "../SettingLevel";
import { CallbackFn, WatchManager } from "../WatchManager";
import { Layout } from "../Layout";
import { Layout } from "../enums/Layout";
/**
* Gets and sets settings at the "device" level for the current device.