Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 3 additions & 17 deletions src/i18n/strings/en_EN.json
Original file line number Diff line number Diff line change
Expand Up @@ -1520,6 +1520,8 @@
"dynamic_room_predecessors": "Dynamic room predecessors",
"dynamic_room_predecessors_description": "Enable MSC3946 (to support late-arriving room archives)",
"element_call_video_rooms": "Element Call video rooms",
"element_call_video_rooms_element_call_exclusive": "Element is configured to use Element Call exlusively, so this cannot be disabled.",
"element_call_video_rooms_missing_video_rooms": "You must enable video rooms to enable this feature.",
"exclude_insecure_devices": "Exclude insecure devices when sending/receiving messages",
"exclude_insecure_devices_description": "When this mode is enabled, encrypted messages will not be shared with unverified devices, and messages from unverified devices will be shown as an error. Note that if you enable this mode, you may be unable to communicate with users who have not verified their devices.",
"experimental_description": "Feeling experimental? Try out our latest ideas in development. These features are not finalised; they may be unstable, may change, or may be dropped altogether. <a>Learn more</a>.",
Expand Down Expand Up @@ -3390,24 +3392,10 @@
"no_rooms_with_unread_threads": "You don't have rooms with unread threads yet."
},
"time": {
"about_day_ago": "about a day ago",
"about_hour_ago": "about an hour ago",
"about_minute_ago": "about a minute ago",
"date_at_time": "%(date)s at %(time)s",
"few_seconds_ago": "a few seconds ago",
"hours_minutes_seconds_left": "%(hours)sh %(minutes)sm %(seconds)ss left",
"in_about_day": "about a day from now",
"in_about_hour": "about an hour from now",
"in_about_minute": "about a minute from now",
"in_few_seconds": "a few seconds from now",
"in_n_days": "%(num)s days from now",
"in_n_hours": "%(num)s hours from now",
"in_n_minutes": "%(num)s minutes from now",
"left": "%(timeRemaining)s left",
"minutes_seconds_left": "%(minutes)sm %(seconds)ss left",
"n_days_ago": "%(num)s days ago",
"n_hours_ago": "%(num)s hours ago",
"n_minutes_ago": "%(num)s minutes ago",
"seconds_left": "%(seconds)ss left",
"short_days": "%(value)sd",
"short_days_hours_minutes_seconds": "%(days)sd %(hours)sh %(minutes)sm %(seconds)ss",
Expand Down Expand Up @@ -3462,11 +3450,9 @@
"unable_to_find": "Tried to load a specific point in this room's timeline, but was unable to find it."
},
"m.audio": {
"audio_player": "Audio player",
"error_downloading_audio": "Error downloading audio",
"error_processing_audio": "Error processing audio message",
"error_processing_voice_message": "Error processing voice message",
"unnamed_audio": "Unnamed audio"
"error_processing_voice_message": "Error processing voice message"
},
"m.beacon_info": {
"view_live_location": "View live location"
Expand Down
11 changes: 9 additions & 2 deletions src/settings/Settings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ import { SortingAlgorithm } from "../stores/room-list-v3/skip-list/sorters/index
import MediaPreviewConfigController from "./controllers/MediaPreviewConfigController.ts";
import InviteRulesConfigController from "./controllers/InviteRulesConfigController.ts";
import { type ComputedInviteConfig } from "../@types/invite-rules.ts";
import IncompatibleConfigController from "./controllers/IncompatibleConfigController.ts";
import CombinationIncompatbleController from "./controllers/CombinationIncompatbleController.ts";

export const defaultWatchManager = new WatchManager();

Expand Down Expand Up @@ -623,8 +625,13 @@ export const SETTINGS: Settings = {
supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS_WITH_CONFIG_PRIORITISED,
supportedLevelsAreOrdered: true,
displayName: _td("labs|element_call_video_rooms"),
controller: new ReloadOnChangeController(),
default: false,
controller: new CombinationIncompatbleController([
// Video rooms need to be enabled to enable this.
new IncompatibleController("feature_video_rooms", false, false, _t("labs|element_call_video_rooms_missing_video_rooms")),
// If the config only allows Element Call, force enable
new IncompatibleConfigController((c) => !!c.element_call?.use_exclusively, true, true, _t("labs|element_call_video_rooms_element_call_exclusive")),
]),
default: true,
},
"feature_group_calls": {
isFeature: true,
Expand Down
54 changes: 54 additions & 0 deletions src/settings/controllers/CombinationIncompatbleController.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/*
Copyright 2024 New Vector Ltd.
Copyright 2021 The Matrix.org Foundation C.I.C.

SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
Please see LICENSE files in the repository root for full details.
*/

import SettingController from "./SettingController.ts";
import { type SettingLevel } from "../SettingLevel.ts";
import IncompatibleController from "./IncompatibleController.ts";

Check failure on line 11 in src/settings/controllers/CombinationIncompatbleController.ts

View workflow job for this annotation

GitHub Actions / ESLint

All imports in the declaration are only used as types. Use `import type`
import IncompatibleConfigController from "./IncompatibleConfigController.ts";

Check failure on line 12 in src/settings/controllers/CombinationIncompatbleController.ts

View workflow job for this annotation

GitHub Actions / ESLint

All imports in the declaration are only used as types. Use `import type`

/**
* Enforces that a boolean setting cannot be enabled if the incompatible setting
* is also enabled, to prevent cascading undefined behaviour between conflicting
* labs flags.
*/
export default class CombinationIncompatbleController extends SettingController {
public constructor(
private readonly controllers: (IncompatibleConfigController|IncompatibleController)[]
) {
super();
}

public getValueOverride(
level: SettingLevel,
roomId: string,
calculatedValue: any,
calculatedAtLevel: SettingLevel | null,
): any {
for (const controller of this.controllers) {
const res = controller.getValueOverride(level, roomId, calculatedValue, calculatedAtLevel);
if (res !== null) {
return res;
}
}
return null;
}

public get settingDisabled(): boolean|string {
for (const controller of this.controllers) {
const res = controller.settingDisabled;
if (res) {
return res;
}
}
return false;
}

public get incompatibleSetting(): boolean {
return this.controllers.some(s => s.incompatibleSetting);
}
}
57 changes: 57 additions & 0 deletions src/settings/controllers/IncompatibleConfigController.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*
Copyright 2024 New Vector Ltd.
Copyright 2021 The Matrix.org Foundation C.I.C.

SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
Please see LICENSE files in the repository root for full details.
*/

import SettingController from "./SettingController.ts";
import { type SettingLevel } from "../SettingLevel.ts";
import { IConfigOptions } from "../../IConfigOptions.ts";

Check failure on line 11 in src/settings/controllers/IncompatibleConfigController.ts

View workflow job for this annotation

GitHub Actions / ESLint

All imports in the declaration are only used as types. Use `import type`
import SdkConfig from "../../SdkConfig.ts";

/**
* Enforces that a boolean setting cannot be enabled if the incompatible setting
* is also enabled, to prevent cascading undefined behaviour between conflicting
* labs flags.
*/
export default class IncompatibleConfigController extends SettingController {
public constructor(
private readonly getSetting: (c: IConfigOptions) => boolean,
private forcedValue: any = false,
private incompatibleValue: any | ((v: any) => boolean) = true,
private readonly disabledString?: string,
) {
super();
console.log(SdkConfig.get());
}

public getValueOverride(
level: SettingLevel,
roomId: string,
calculatedValue: any,
calculatedAtLevel: SettingLevel | null,
): any {
if (this.incompatibleSetting) {
return this.forcedValue;
}
return null; // no override
}

public get configSettingValue(): boolean {
return this.getSetting(SdkConfig.get());
}

public get settingDisabled(): boolean|string {
console.log("IncompatibleConfigController", this.configSettingValue, this.incompatibleSetting ? (this.disabledString ?? true) : false);
return this.incompatibleSetting ? (this.disabledString ?? true) : false;
}

public get incompatibleSetting(): boolean {
if (typeof this.incompatibleValue === "function") {
return this.incompatibleValue(this.configSettingValue);
}
return this.configSettingValue === this.incompatibleValue;
}
}
5 changes: 3 additions & 2 deletions src/settings/controllers/IncompatibleController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export default class IncompatibleController extends SettingController {
private settingName: BooleanSettingKey,
private forcedValue: any = false,
private incompatibleValue: any | ((v: any) => boolean) = true,
private readonly disabledString?: string,
) {
super();
}
Expand All @@ -37,8 +38,8 @@ export default class IncompatibleController extends SettingController {
return null; // no override
}

public get settingDisabled(): boolean {
return this.incompatibleSetting;
public get settingDisabled(): boolean|string {
return this.incompatibleSetting ? (this.disabledString ?? true) : false;
}

public get incompatibleSetting(): boolean {
Expand Down
Loading