Do not hide media from your own user by default (#29797)

* Always show media from your own user

* Update usages of useMediaVisible

* lint

* Add a test for HideActionButton

* Improve docs

* Document the event

* fixup test

* Allow users to hide their own media if they wish.

* Update tests

* remove a check\

* tweak

* tweak
This commit is contained in:
Will Hunt
2025-09-02 13:21:12 +01:00
committed by GitHub
parent 8fa3d7e4b7
commit 1925132a3c
15 changed files with 205 additions and 104 deletions

View File

@@ -151,7 +151,7 @@ interface Props extends ReplacerOptions {
const EventContentBody = memo(
({ as, mxEvent, stripReply, content, linkify, highlights, includeDir = true, ref, ...options }: Props) => {
const enableBigEmoji = useSettingValue("TextualBody.enableBigEmoji");
const [mediaIsVisible] = useMediaVisible(mxEvent?.getId(), mxEvent?.getRoomId());
const [mediaIsVisible] = useMediaVisible(mxEvent);
const replacer = useReplacer(content, mxEvent, options);
const linkifyOptions = useMemo(

View File

@@ -25,7 +25,7 @@ interface IProps {
* Quick action button for marking a media event as hidden.
*/
export const HideActionButton: React.FC<IProps> = ({ mxEvent }) => {
const [mediaIsVisible, setVisible] = useMediaVisible(mxEvent.getId(), mxEvent.getRoomId());
const [mediaIsVisible, setVisible] = useMediaVisible(mxEvent);
if (!mediaIsVisible) {
return;

View File

@@ -686,7 +686,7 @@ export class MImageBodyInner extends React.Component<IProps, IState> {
// Wrap MImageBody component so we can use a hook here.
const MImageBody: React.FC<IBodyProps> = (props) => {
const [mediaVisible, setVisible] = useMediaVisible(props.mxEvent.getId(), props.mxEvent.getRoomId());
const [mediaVisible, setVisible] = useMediaVisible(props.mxEvent);
return <MImageBodyInner mediaVisible={mediaVisible} setMediaVisible={setVisible} {...props} />;
};

View File

@@ -38,7 +38,7 @@ class MImageReplyBodyInner extends MImageBodyInner {
}
}
const MImageReplyBody: React.FC<IBodyProps> = (props) => {
const [mediaVisible, setVisible] = useMediaVisible(props.mxEvent.getId(), props.mxEvent.getRoomId());
const [mediaVisible, setVisible] = useMediaVisible(props.mxEvent);
return <MImageReplyBodyInner mediaVisible={mediaVisible} setMediaVisible={setVisible} {...props} />;
};

View File

@@ -20,7 +20,7 @@ class MStickerBodyInner extends MImageBodyInner {
protected onClick = (ev: React.MouseEvent): void => {
ev.preventDefault();
if (!this.props.mediaVisible) {
this.props.setMediaVisible?.(true);
this.props.setMediaVisible(true);
}
};
@@ -79,7 +79,7 @@ class MStickerBodyInner extends MImageBodyInner {
}
const MStickerBody: React.FC<IBodyProps> = (props) => {
const [mediaVisible, setVisible] = useMediaVisible(props.mxEvent.getId(), props.mxEvent.getRoomId());
const [mediaVisible, setVisible] = useMediaVisible(props.mxEvent);
return <MStickerBodyInner mediaVisible={mediaVisible} setMediaVisible={setVisible} {...props} />;
};

View File

@@ -342,7 +342,7 @@ class MVideoBodyInner extends React.PureComponent<IProps, IState> {
// Wrap MVideoBody component so we can use a hook here.
const MVideoBody: React.FC<IBodyProps> = (props) => {
const [mediaVisible, setVisible] = useMediaVisible(props.mxEvent.getId(), props.mxEvent.getRoomId());
const [mediaVisible, setVisible] = useMediaVisible(props.mxEvent);
return <MVideoBodyInner mediaVisible={mediaVisible} setMediaVisible={setVisible} {...props} />;
};

View File

@@ -30,7 +30,7 @@ interface IProps {
const LinkPreviewGroup: React.FC<IProps> = ({ links, mxEvent, onCancelClick }) => {
const cli = useContext(MatrixClientContext);
const [expanded, toggleExpanded] = useStateToggle();
const [mediaVisible] = useMediaVisible(mxEvent.getId(), mxEvent.getRoomId());
const [mediaVisible] = useMediaVisible(mxEvent);
const ts = mxEvent.getTs();
const previews = useAsyncMemo<[string, IPreviewUrlResponse][]>(

View File

@@ -6,7 +6,7 @@ Please see LICENSE files in the repository root for full details.
*/
import { useCallback } from "react";
import { JoinRule } from "matrix-js-sdk/src/matrix";
import { JoinRule, type MatrixEvent } from "matrix-js-sdk/src/matrix";
import { SettingLevel } from "../settings/SettingLevel";
import { useSettingValue } from "./useSettings";
@@ -19,14 +19,25 @@ const PRIVATE_JOIN_RULES: JoinRule[] = [JoinRule.Invite, JoinRule.Knock, JoinRul
/**
* Should the media event be visible in the client, or hidden.
* @param eventId The eventId of the media event.
* @returns A boolean describing the hidden status, and a function to set the visiblity.
*
* This function uses the `mediaPreviewConfig` setting to determine the rules for the room
* along with the `showMediaEventIds` setting for specific events.
*
* A function may be provided to alter the visible state.
*
* @param The event that contains the media. If not provided, the global rule is used.
*
* @returns Returns a tuple of:
* A boolean describing the hidden status.
* A function to show or hide the event.
*/
export function useMediaVisible(eventId?: string, roomId?: string): [boolean, (visible: boolean) => void] {
const mediaPreviewSetting = useSettingValue("mediaPreviewConfig", roomId);
export function useMediaVisible(mxEvent?: MatrixEvent): [boolean, (visible: boolean) => void] {
const eventId = mxEvent?.getId();
const mediaPreviewSetting = useSettingValue("mediaPreviewConfig", mxEvent?.getRoomId());
const client = useMatrixClientContext();
const eventVisibility = useSettingValue("showMediaEventIds");
const joinRule = useRoomState(client.getRoom(roomId) ?? undefined, (state) => state.getJoinRule());
const room = client.getRoom(mxEvent?.getRoomId()) ?? undefined;
const joinRule = useRoomState(room, (state) => state.getJoinRule());
const setMediaVisible = useCallback(
(visible: boolean) => {
SettingsStore.setValue("showMediaEventIds", null, SettingLevel.DEVICE, {
@@ -43,6 +54,9 @@ export function useMediaVisible(eventId?: string, roomId?: string): [boolean, (v
// Always prefer the explicit per-event user preference here.
if (explicitEventVisiblity !== undefined) {
return [explicitEventVisiblity, setMediaVisible];
} else if (mxEvent?.getSender() === client.getUserId()) {
// If this event is ours and we've not set an explicit visibility, default to on.
return [true, setMediaVisible];
} else if (mediaPreviewSetting.media_previews === MediaPreviewValue.Off) {
return [false, setMediaVisible];
} else if (mediaPreviewSetting.media_previews === MediaPreviewValue.On) {

View File

@@ -117,7 +117,7 @@ export class MediaEventHelper implements IDestroyable {
/**
* Determine if the media event in question supports being hidden in the timeline.
* @param event Any matrix event.
* @returns `true` if the media can be hidden, otherwise false.
* @returns `true` if the media can be hidden, otherwise `false`.
*/
public static canHide(event: MatrixEvent): boolean {
if (!event) return false;