Skip to content

Commit 1925132

Browse files
authored
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
1 parent 8fa3d7e commit 1925132

File tree

15 files changed

+204
-103
lines changed

15 files changed

+204
-103
lines changed

playwright/e2e/timeline/timeline.spec.ts

Lines changed: 28 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -908,23 +908,37 @@ test.describe("Timeline", () => {
908908
});
909909
});
910910

911-
test("should be able to hide an image", { tag: "@screenshot" }, async ({ page, app, room, context }) => {
912-
await app.viewRoomById(room.roomId);
913-
await sendImage(app.client, room.roomId, NEW_AVATAR);
914-
await app.timeline.scrollToBottom();
915-
const imgTile = page.locator(".mx_MImageBody").first();
916-
await expect(imgTile).toBeVisible();
917-
await imgTile.hover();
918-
await page.getByRole("button", { name: "Hide" }).click();
911+
test(
912+
"should be able to hide an image",
913+
{ tag: "@screenshot" },
914+
async ({ page, app, homeserver, room, context }) => {
915+
await app.viewRoomById(room.roomId);
919916

920-
// Check that the image is now hidden.
921-
await expect(page.getByRole("button", { name: "Show image" })).toBeVisible();
922-
});
917+
const bot = new Bot(page, homeserver, {});
918+
await bot.prepareClient();
919+
await app.client.inviteUser(room.roomId, bot.credentials.userId);
923920

924-
test("should be able to hide a video", async ({ page, app, room, context }) => {
921+
await sendImage(bot, room.roomId, NEW_AVATAR);
922+
await app.timeline.scrollToBottom();
923+
const imgTile = page.locator(".mx_MImageBody").first();
924+
await expect(imgTile).toBeVisible();
925+
await imgTile.hover();
926+
await page.getByRole("button", { name: "Hide" }).click();
927+
928+
// Check that the image is now hidden.
929+
await expect(page.getByRole("button", { name: "Show image" })).toBeVisible();
930+
},
931+
);
932+
933+
test("should be able to hide a video", async ({ page, app, homeserver, room, context }) => {
925934
await app.viewRoomById(room.roomId);
926-
const upload = await app.client.uploadContent(VIDEO_FILE, { name: "bbb.webm", type: "video/webm" });
927-
await app.client.sendEvent(room.roomId, null, "m.room.message" as EventType, {
935+
936+
const bot = new Bot(page, homeserver, {});
937+
await bot.prepareClient();
938+
await app.client.inviteUser(room.roomId, bot.credentials.userId);
939+
940+
const upload = await bot.uploadContent(VIDEO_FILE, { name: "bbb.webm", type: "video/webm" });
941+
await bot.sendEvent(room.roomId, null, "m.room.message" as EventType, {
928942
msgtype: "m.video" as MsgType,
929943
body: "bbb.webm",
930944
url: upload.content_uri,

src/components/views/messages/EventContentBody.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ interface Props extends ReplacerOptions {
151151
const EventContentBody = memo(
152152
({ as, mxEvent, stripReply, content, linkify, highlights, includeDir = true, ref, ...options }: Props) => {
153153
const enableBigEmoji = useSettingValue("TextualBody.enableBigEmoji");
154-
const [mediaIsVisible] = useMediaVisible(mxEvent?.getId(), mxEvent?.getRoomId());
154+
const [mediaIsVisible] = useMediaVisible(mxEvent);
155155

156156
const replacer = useReplacer(content, mxEvent, options);
157157
const linkifyOptions = useMemo(

src/components/views/messages/HideActionButton.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ interface IProps {
2525
* Quick action button for marking a media event as hidden.
2626
*/
2727
export const HideActionButton: React.FC<IProps> = ({ mxEvent }) => {
28-
const [mediaIsVisible, setVisible] = useMediaVisible(mxEvent.getId(), mxEvent.getRoomId());
28+
const [mediaIsVisible, setVisible] = useMediaVisible(mxEvent);
2929

3030
if (!mediaIsVisible) {
3131
return;

src/components/views/messages/MImageBody.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -686,7 +686,7 @@ export class MImageBodyInner extends React.Component<IProps, IState> {
686686

687687
// Wrap MImageBody component so we can use a hook here.
688688
const MImageBody: React.FC<IBodyProps> = (props) => {
689-
const [mediaVisible, setVisible] = useMediaVisible(props.mxEvent.getId(), props.mxEvent.getRoomId());
689+
const [mediaVisible, setVisible] = useMediaVisible(props.mxEvent);
690690
return <MImageBodyInner mediaVisible={mediaVisible} setMediaVisible={setVisible} {...props} />;
691691
};
692692

src/components/views/messages/MImageReplyBody.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ class MImageReplyBodyInner extends MImageBodyInner {
3838
}
3939
}
4040
const MImageReplyBody: React.FC<IBodyProps> = (props) => {
41-
const [mediaVisible, setVisible] = useMediaVisible(props.mxEvent.getId(), props.mxEvent.getRoomId());
41+
const [mediaVisible, setVisible] = useMediaVisible(props.mxEvent);
4242
return <MImageReplyBodyInner mediaVisible={mediaVisible} setMediaVisible={setVisible} {...props} />;
4343
};
4444

src/components/views/messages/MStickerBody.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ class MStickerBodyInner extends MImageBodyInner {
2020
protected onClick = (ev: React.MouseEvent): void => {
2121
ev.preventDefault();
2222
if (!this.props.mediaVisible) {
23-
this.props.setMediaVisible?.(true);
23+
this.props.setMediaVisible(true);
2424
}
2525
};
2626

@@ -79,7 +79,7 @@ class MStickerBodyInner extends MImageBodyInner {
7979
}
8080

8181
const MStickerBody: React.FC<IBodyProps> = (props) => {
82-
const [mediaVisible, setVisible] = useMediaVisible(props.mxEvent.getId(), props.mxEvent.getRoomId());
82+
const [mediaVisible, setVisible] = useMediaVisible(props.mxEvent);
8383
return <MStickerBodyInner mediaVisible={mediaVisible} setMediaVisible={setVisible} {...props} />;
8484
};
8585

src/components/views/messages/MVideoBody.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -342,7 +342,7 @@ class MVideoBodyInner extends React.PureComponent<IProps, IState> {
342342

343343
// Wrap MVideoBody component so we can use a hook here.
344344
const MVideoBody: React.FC<IBodyProps> = (props) => {
345-
const [mediaVisible, setVisible] = useMediaVisible(props.mxEvent.getId(), props.mxEvent.getRoomId());
345+
const [mediaVisible, setVisible] = useMediaVisible(props.mxEvent);
346346
return <MVideoBodyInner mediaVisible={mediaVisible} setMediaVisible={setVisible} {...props} />;
347347
};
348348

src/components/views/rooms/LinkPreviewGroup.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ interface IProps {
3030
const LinkPreviewGroup: React.FC<IProps> = ({ links, mxEvent, onCancelClick }) => {
3131
const cli = useContext(MatrixClientContext);
3232
const [expanded, toggleExpanded] = useStateToggle();
33-
const [mediaVisible] = useMediaVisible(mxEvent.getId(), mxEvent.getRoomId());
33+
const [mediaVisible] = useMediaVisible(mxEvent);
3434

3535
const ts = mxEvent.getTs();
3636
const previews = useAsyncMemo<[string, IPreviewUrlResponse][]>(

src/hooks/useMediaVisible.ts

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ Please see LICENSE files in the repository root for full details.
66
*/
77

88
import { useCallback } from "react";
9-
import { JoinRule } from "matrix-js-sdk/src/matrix";
9+
import { JoinRule, type MatrixEvent } from "matrix-js-sdk/src/matrix";
1010

1111
import { SettingLevel } from "../settings/SettingLevel";
1212
import { useSettingValue } from "./useSettings";
@@ -19,14 +19,25 @@ const PRIVATE_JOIN_RULES: JoinRule[] = [JoinRule.Invite, JoinRule.Knock, JoinRul
1919

2020
/**
2121
* Should the media event be visible in the client, or hidden.
22-
* @param eventId The eventId of the media event.
23-
* @returns A boolean describing the hidden status, and a function to set the visiblity.
22+
*
23+
* This function uses the `mediaPreviewConfig` setting to determine the rules for the room
24+
* along with the `showMediaEventIds` setting for specific events.
25+
*
26+
* A function may be provided to alter the visible state.
27+
*
28+
* @param The event that contains the media. If not provided, the global rule is used.
29+
*
30+
* @returns Returns a tuple of:
31+
* A boolean describing the hidden status.
32+
* A function to show or hide the event.
2433
*/
25-
export function useMediaVisible(eventId?: string, roomId?: string): [boolean, (visible: boolean) => void] {
26-
const mediaPreviewSetting = useSettingValue("mediaPreviewConfig", roomId);
34+
export function useMediaVisible(mxEvent?: MatrixEvent): [boolean, (visible: boolean) => void] {
35+
const eventId = mxEvent?.getId();
36+
const mediaPreviewSetting = useSettingValue("mediaPreviewConfig", mxEvent?.getRoomId());
2737
const client = useMatrixClientContext();
2838
const eventVisibility = useSettingValue("showMediaEventIds");
29-
const joinRule = useRoomState(client.getRoom(roomId) ?? undefined, (state) => state.getJoinRule());
39+
const room = client.getRoom(mxEvent?.getRoomId()) ?? undefined;
40+
const joinRule = useRoomState(room, (state) => state.getJoinRule());
3041
const setMediaVisible = useCallback(
3142
(visible: boolean) => {
3243
SettingsStore.setValue("showMediaEventIds", null, SettingLevel.DEVICE, {
@@ -43,6 +54,9 @@ export function useMediaVisible(eventId?: string, roomId?: string): [boolean, (v
4354
// Always prefer the explicit per-event user preference here.
4455
if (explicitEventVisiblity !== undefined) {
4556
return [explicitEventVisiblity, setMediaVisible];
57+
} else if (mxEvent?.getSender() === client.getUserId()) {
58+
// If this event is ours and we've not set an explicit visibility, default to on.
59+
return [true, setMediaVisible];
4660
} else if (mediaPreviewSetting.media_previews === MediaPreviewValue.Off) {
4761
return [false, setMediaVisible];
4862
} else if (mediaPreviewSetting.media_previews === MediaPreviewValue.On) {

src/utils/MediaEventHelper.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ export class MediaEventHelper implements IDestroyable {
117117
/**
118118
* Determine if the media event in question supports being hidden in the timeline.
119119
* @param event Any matrix event.
120-
* @returns `true` if the media can be hidden, otherwise false.
120+
* @returns `true` if the media can be hidden, otherwise `false`.
121121
*/
122122
public static canHide(event: MatrixEvent): boolean {
123123
if (!event) return false;

0 commit comments

Comments
 (0)