Update URL Preview settings (#32992)
* Remove ability for url previews to be set per-room * Add ability to enable E2EE URL Previews globally * Remove old migration * Cleanup * Remove room account handler * update snap * screenshot updated * Add a test
This commit is contained in:
@@ -1380,12 +1380,12 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
||||
if (data.timeline.getTimelineSet() !== room.getUnfilteredTimelineSet()) return;
|
||||
|
||||
if (ev.getType() === "org.matrix.room.preview_urls") {
|
||||
this.updatePreviewUrlVisibility(room);
|
||||
this.updatePreviewUrlVisibility();
|
||||
}
|
||||
|
||||
if (ev.getType() === "m.room.encryption") {
|
||||
this.updateE2EStatus(room);
|
||||
this.updatePreviewUrlVisibility(room);
|
||||
this.updatePreviewUrlVisibility();
|
||||
}
|
||||
|
||||
// ignore anything but real-time updates at the end of the room:
|
||||
@@ -1541,15 +1541,14 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
||||
});
|
||||
}
|
||||
|
||||
private updatePreviewUrlVisibility(room: Room): void {
|
||||
private updatePreviewUrlVisibility(): void {
|
||||
this.setState(({ isRoomEncrypted }) => ({
|
||||
showUrlPreview: this.getPreviewUrlVisibility(room, isRoomEncrypted),
|
||||
showUrlPreview: this.getPreviewUrlVisibility(isRoomEncrypted),
|
||||
}));
|
||||
}
|
||||
|
||||
private getPreviewUrlVisibility({ roomId }: Room, isRoomEncrypted: boolean | null): boolean {
|
||||
const key = isRoomEncrypted ? "urlPreviewsEnabled_e2ee" : "urlPreviewsEnabled";
|
||||
return SettingsStore.getValue(key, roomId);
|
||||
private getPreviewUrlVisibility(isRoomEncrypted: boolean | null): boolean {
|
||||
return SettingsStore.getValue(isRoomEncrypted ? "urlPreviewsEnabled_e2ee" : "urlPreviewsEnabled");
|
||||
}
|
||||
|
||||
private onRoom = (room: Room): void => {
|
||||
@@ -1608,9 +1607,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
||||
}
|
||||
|
||||
private onUrlPreviewsEnabledChange = (): void => {
|
||||
if (this.state.room) {
|
||||
this.updatePreviewUrlVisibility(this.state.room);
|
||||
}
|
||||
this.updatePreviewUrlVisibility();
|
||||
};
|
||||
|
||||
private onRoomStateEvents = async (ev: MatrixEvent, state: RoomState): Promise<void> => {
|
||||
@@ -1638,7 +1635,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
||||
|
||||
this.setState({
|
||||
isRoomEncrypted,
|
||||
showUrlPreview: this.getPreviewUrlVisibility(room, isRoomEncrypted),
|
||||
showUrlPreview: this.getPreviewUrlVisibility(isRoomEncrypted),
|
||||
...(newE2EStatus && { e2eStatus: newE2EStatus }),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ interface IProps {
|
||||
label?: string;
|
||||
isExplicit?: boolean;
|
||||
hideIfCannotSet?: boolean;
|
||||
requires?: BooleanSettingKey[];
|
||||
onChange?(checked: boolean): void;
|
||||
}
|
||||
|
||||
@@ -45,6 +46,12 @@ export default class SettingsFlag extends React.Component<IProps, IState> {
|
||||
|
||||
public componentDidMount(): void {
|
||||
defaultWatchManager.watchSetting(this.props.name, this.props.roomId ?? null, this.onSettingChange);
|
||||
if (this.props.requires) {
|
||||
// If we have any dependencies for this feature, also watch those features to ensure we catch the disabled state.
|
||||
for (const flag of this.props.requires) {
|
||||
defaultWatchManager.watchSetting(flag, this.props.roomId ?? null, this.onSettingChange);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public componentWillUnmount(): void {
|
||||
|
||||
@@ -1,152 +0,0 @@
|
||||
/*
|
||||
Copyright 2024 New Vector Ltd.
|
||||
Copyright 2019 The Matrix.org Foundation C.I.C.
|
||||
Copyright 2018, 2019 New Vector Ltd
|
||||
Copyright 2017 Travis Ralston
|
||||
Copyright 2016 OpenMarket Ltd
|
||||
|
||||
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 React, { type ReactNode, type JSX } from "react";
|
||||
import { type Room } from "matrix-js-sdk/src/matrix";
|
||||
import { InlineSpinner } from "@vector-im/compound-web";
|
||||
|
||||
import { _t } from "../../../languageHandler";
|
||||
import SettingsStore from "../../../settings/SettingsStore";
|
||||
import dis from "../../../dispatcher/dispatcher";
|
||||
import { Action } from "../../../dispatcher/actions";
|
||||
import { SettingLevel } from "../../../settings/SettingLevel";
|
||||
import SettingsFlag from "../elements/SettingsFlag";
|
||||
import SettingsFieldset from "../settings/SettingsFieldset";
|
||||
import AccessibleButton, { type ButtonEvent } from "../elements/AccessibleButton";
|
||||
import { useIsEncrypted } from "../../../hooks/useIsEncrypted.ts";
|
||||
import { useMatrixClientContext } from "../../../contexts/MatrixClientContext.tsx";
|
||||
import { useSettingValueAt } from "../../../hooks/useSettings.ts";
|
||||
|
||||
/**
|
||||
* The URL preview settings for a room
|
||||
*/
|
||||
interface UrlPreviewSettingsProps {
|
||||
/**
|
||||
* The room.
|
||||
*/
|
||||
room: Room;
|
||||
}
|
||||
|
||||
export function UrlPreviewSettings({ room }: UrlPreviewSettingsProps): JSX.Element {
|
||||
const { roomId } = room;
|
||||
const matrixClient = useMatrixClientContext();
|
||||
const isEncrypted = useIsEncrypted(matrixClient, room);
|
||||
const isLoading = isEncrypted === null;
|
||||
|
||||
return (
|
||||
<SettingsFieldset
|
||||
legend={_t("room_settings|general|url_previews_section")}
|
||||
description={!isLoading && <Description isEncrypted={isEncrypted} />}
|
||||
>
|
||||
{isLoading ? (
|
||||
<InlineSpinner />
|
||||
) : (
|
||||
<>
|
||||
<PreviewsForRoom isEncrypted={isEncrypted} roomId={roomId} />
|
||||
<SettingsFlag
|
||||
name={isEncrypted ? "urlPreviewsEnabled_e2ee" : "urlPreviewsEnabled"}
|
||||
level={SettingLevel.ROOM_DEVICE}
|
||||
roomId={roomId}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</SettingsFieldset>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Click handler for the user settings link
|
||||
* @param e
|
||||
*/
|
||||
function onClickUserSettings(e: ButtonEvent): void {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
dis.fire(Action.ViewUserSettings);
|
||||
}
|
||||
|
||||
/**
|
||||
* The description for the URL preview settings
|
||||
*/
|
||||
interface DescriptionProps {
|
||||
/**
|
||||
* Whether the room is encrypted
|
||||
*/
|
||||
isEncrypted: boolean;
|
||||
}
|
||||
|
||||
function Description({ isEncrypted }: DescriptionProps): JSX.Element {
|
||||
const urlPreviewsEnabled = useSettingValueAt(SettingLevel.ACCOUNT, "urlPreviewsEnabled");
|
||||
|
||||
let previewsForAccount: ReactNode | undefined;
|
||||
if (isEncrypted) {
|
||||
previewsForAccount = _t("room_settings|general|url_preview_encryption_warning");
|
||||
} else {
|
||||
const button = {
|
||||
a: (sub: string) => (
|
||||
<AccessibleButton kind="link_inline" onClick={onClickUserSettings}>
|
||||
{sub}
|
||||
</AccessibleButton>
|
||||
),
|
||||
};
|
||||
|
||||
previewsForAccount = urlPreviewsEnabled
|
||||
? _t("room_settings|general|user_url_previews_default_on", {}, button)
|
||||
: _t("room_settings|general|user_url_previews_default_off", {}, button);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<p>{_t("room_settings|general|url_preview_explainer")}</p>
|
||||
<p>{previewsForAccount}</p>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* The description for the URL preview settings
|
||||
*/
|
||||
interface PreviewsForRoomProps {
|
||||
/**
|
||||
* Whether the room is encrypted
|
||||
*/
|
||||
isEncrypted: boolean;
|
||||
/**
|
||||
* The room ID
|
||||
*/
|
||||
roomId: string;
|
||||
}
|
||||
|
||||
function PreviewsForRoom({ isEncrypted, roomId }: PreviewsForRoomProps): JSX.Element | null {
|
||||
const urlPreviewsEnabled = useSettingValueAt(
|
||||
SettingLevel.ACCOUNT,
|
||||
"urlPreviewsEnabled",
|
||||
roomId,
|
||||
/*explicit=*/ true,
|
||||
);
|
||||
if (isEncrypted) return null;
|
||||
|
||||
let previewsForRoom: ReactNode;
|
||||
if (SettingsStore.canSetValue("urlPreviewsEnabled", roomId, SettingLevel.ROOM)) {
|
||||
previewsForRoom = (
|
||||
<SettingsFlag name="urlPreviewsEnabled" level={SettingLevel.ROOM} roomId={roomId} isExplicit={true} />
|
||||
);
|
||||
} else {
|
||||
previewsForRoom = (
|
||||
<div>
|
||||
{urlPreviewsEnabled
|
||||
? _t("room_settings|general|default_url_previews_on")
|
||||
: _t("room_settings|general|default_url_previews_off")}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return previewsForRoom;
|
||||
}
|
||||
@@ -15,14 +15,11 @@ import RoomProfileSettings from "../../../room_settings/RoomProfileSettings";
|
||||
import AccessibleButton, { type ButtonEvent } from "../../../elements/AccessibleButton";
|
||||
import dis from "../../../../../dispatcher/dispatcher";
|
||||
import MatrixClientContext from "../../../../../contexts/MatrixClientContext";
|
||||
import SettingsStore from "../../../../../settings/SettingsStore";
|
||||
import { UIFeature } from "../../../../../settings/UIFeature";
|
||||
import AliasSettings from "../../../room_settings/AliasSettings";
|
||||
import PosthogTrackers from "../../../../../PosthogTrackers";
|
||||
import { SettingsSubsection } from "../../shared/SettingsSubsection";
|
||||
import SettingsTab from "../SettingsTab";
|
||||
import { SettingsSection } from "../../shared/SettingsSection";
|
||||
import { UrlPreviewSettings } from "../../../room_settings/UrlPreviewSettings";
|
||||
import { MediaPreviewAccountSettings } from "../user/MediaPreviewAccountSettings";
|
||||
|
||||
interface IProps {
|
||||
@@ -62,10 +59,6 @@ export default class GeneralRoomSettingsTab extends React.Component<IProps, ISta
|
||||
const canSetCanonical = room.currentState.mayClientSendStateEvent("m.room.canonical_alias", client);
|
||||
const canonicalAliasEv = room.currentState.getStateEvents("m.room.canonical_alias", "") ?? undefined;
|
||||
|
||||
const urlPreviewSettings = SettingsStore.getValue(UIFeature.URLPreviews) ? (
|
||||
<UrlPreviewSettings room={room} />
|
||||
) : null;
|
||||
|
||||
let leaveSection;
|
||||
if (room.getMyMembership() === KnownMembership.Join) {
|
||||
leaveSection = (
|
||||
@@ -99,7 +92,6 @@ export default class GeneralRoomSettingsTab extends React.Component<IProps, ISta
|
||||
</SettingsSection>
|
||||
|
||||
<SettingsSection heading={_t("room_settings|general|other_section")}>
|
||||
{urlPreviewSettings}
|
||||
<SettingsSubsection heading={_t("common|moderation_and_safety")} legacy={false}>
|
||||
<MediaPreviewAccountSettings roomId={room.roomId} />
|
||||
</SettingsSubsection>
|
||||
|
||||
@@ -147,11 +147,7 @@ export default class PreferencesUserSettingsTab extends React.Component<IProps,
|
||||
"showCodeLineNumbers",
|
||||
];
|
||||
|
||||
private static IMAGES_AND_VIDEOS_SETTINGS: BooleanSettingKey[] = [
|
||||
"urlPreviewsEnabled",
|
||||
"autoplayGifs",
|
||||
"autoplayVideo",
|
||||
];
|
||||
private static IMAGES_AND_VIDEOS_SETTINGS: BooleanSettingKey[] = ["autoplayGifs", "autoplayVideo"];
|
||||
|
||||
private static TIMELINE_SETTINGS: BooleanSettingKey[] = [
|
||||
"showTypingNotifications",
|
||||
@@ -350,6 +346,19 @@ export default class PreferencesUserSettingsTab extends React.Component<IProps,
|
||||
{this.renderGroup(PreferencesUserSettingsTab.CODE_BLOCKS_SETTINGS)}
|
||||
</SettingsSubsection>
|
||||
|
||||
<SettingsSubsection
|
||||
heading={_t("settings|preferences|link_previews_heading")}
|
||||
description={_t("settings|preferences|link_previews_description")}
|
||||
formWrap
|
||||
>
|
||||
<SettingsFlag name="urlPreviewsEnabled" level={SettingLevel.DEVICE} />
|
||||
<SettingsFlag
|
||||
name="urlPreviewsEnabled_e2ee"
|
||||
level={SettingLevel.DEVICE}
|
||||
requires={["urlPreviewsEnabled"]}
|
||||
/>
|
||||
</SettingsSubsection>
|
||||
|
||||
<SettingsSubsection heading={_t("settings|preferences|media_heading")} formWrap>
|
||||
{this.renderGroup(PreferencesUserSettingsTab.IMAGES_AND_VIDEOS_SETTINGS)}
|
||||
</SettingsSubsection>
|
||||
|
||||
Reference in New Issue
Block a user