From 806f5bee794f78f85259e944f09fe6bcc0672b0a Mon Sep 17 00:00:00 2001 From: Half-Shot Date: Thu, 10 Apr 2025 16:49:52 +0100 Subject: [PATCH] Rewrite tons of tests --- .../timeline/media-preview-settings.spec.ts | 129 ++++++++++++++ .../invite-no-avatar-linux.png | Bin 0 -> 17703 bytes .../invite-room-tree-no-avatar-linux.png | Bin 0 -> 3826 bytes .../invite-room-tree-with-avatar-linux.png | Bin 0 -> 3826 bytes .../invite-with-avatar-linux.png | Bin 0 -> 17703 bytes .../tabs/room/GeneralRoomSettingsTab.tsx | 2 + .../tabs/user/MediaPreviewSetting.tsx | 94 ++++++---- src/hooks/room/useJoinRule.ts | 30 ++++ src/hooks/room/useRoomAvatar.ts | 30 ++++ src/hooks/useMediaVisible.ts | 14 +- src/settings/SettingsStore.ts | 4 - .../MediaPreviewConfigController.ts | 41 ++--- .../MediaPreviewConfigController-test.ts | 165 ++++++++++++++++++ 13 files changed, 441 insertions(+), 68 deletions(-) create mode 100644 playwright/e2e/timeline/media-preview-settings.spec.ts create mode 100644 playwright/snapshots/timeline/media-preview-settings.spec.ts/invite-no-avatar-linux.png create mode 100644 playwright/snapshots/timeline/media-preview-settings.spec.ts/invite-room-tree-no-avatar-linux.png create mode 100644 playwright/snapshots/timeline/media-preview-settings.spec.ts/invite-room-tree-with-avatar-linux.png create mode 100644 playwright/snapshots/timeline/media-preview-settings.spec.ts/invite-with-avatar-linux.png create mode 100644 src/hooks/room/useJoinRule.ts create mode 100644 src/hooks/room/useRoomAvatar.ts create mode 100644 test/unit-tests/settings/controllers/MediaPreviewConfigController-test.ts diff --git a/playwright/e2e/timeline/media-preview-settings.spec.ts b/playwright/e2e/timeline/media-preview-settings.spec.ts new file mode 100644 index 0000000000..23777eea65 --- /dev/null +++ b/playwright/e2e/timeline/media-preview-settings.spec.ts @@ -0,0 +1,129 @@ +/* +Copyright 2024, 2025 New Vector Ltd. +Copyright 2022, 2023 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 * as fs from "node:fs"; +import { type EventType, type MsgType } from "matrix-js-sdk/src/types"; +import { JoinRule } from "matrix-js-sdk/src/matrix"; + +import type { Locator, Page } from "@playwright/test"; +import { test, expect } from "../../element-web-test"; +import { Bot } from "../../pages/bot"; + +const ROOM_NAME = "Test room"; +const OLD_NAME = "Alan"; + +const MEDIA_FILE = fs.readFileSync("playwright/sample-files/riot.png"); + +test.describe("Media preview settings", () => { + test.use({ + displayName: OLD_NAME, + room: async ({ app, page, homeserver, bot, user }, use) => { + const mxc = (await bot.uploadContent(MEDIA_FILE, { name: "image.png", type: "image/png" })).content_uri; + const roomId = await bot.createRoom({ + name: ROOM_NAME, + invite: [user.userId], + initial_state: [{ type: "m.room.avatar", content: { url: mxc }, state_key: "" }], + }); + await bot.sendEvent(roomId, null, "m.room.message" as EventType, { + msgtype: "m.image" as MsgType, + body: "image.png", + url: mxc, + }); + + await use({ roomId }); + }, + }); + + test("should be able to hide avatars of inviters", { tag: "@screenshot" }, async ({ page, app, room, user }) => { + let settings = await app.settings.openUserSettings("Preferences"); + await settings.getByLabel("Hide avatars of room and inviter").click(); + await app.closeDialog(); + await app.viewRoomById(room.roomId); + expect(page.getByRole("complementary").filter({ hasText: "Do you want to join Test room" })).toMatchScreenshot( + "invite-no-avatar.png", + ); + expect( + page.getByRole("tree", { name: "Rooms" }).getByRole("treeitem", { name: "Test room" }), + ).toMatchScreenshot("invite-room-tree-no-avatar.png"); + + // And then go back to being visible + settings = await app.settings.openUserSettings("Preferences"); + await settings.getByLabel("Hide avatars of room and inviter").click(); + await app.closeDialog(); + await page.goto("#/home"); + await app.viewRoomById(room.roomId); + expect(page.getByRole("complementary").filter({ hasText: "Do you want to join Test room" })).toMatchScreenshot( + "invite-with-avatar.png", + ); + expect( + page.getByRole("tree", { name: "Rooms" }).getByRole("treeitem", { name: "Test room" }), + ).toMatchScreenshot("invite-room-tree-with-avatar.png"); + }); + + test("should be able to hide media in rooms globally", async ({ page, app, room, user }) => { + const settings = await app.settings.openUserSettings("Preferences"); + await settings.getByLabel("Show media in timeline").getByRole("radio", { name: "Always hide" }).click(); + await app.closeDialog(); + await app.viewRoomById(room.roomId); + await page.getByRole("button", { name: "Accept" }).click(); + await expect(page.getByText("Show image")).toBeVisible(); + }); + test("should be able to hide media in non-private rooms globally", async ({ page, app, room, user, bot }) => { + await bot.sendStateEvent(room.roomId, "m.room.join_rules", { + join_rule: "public", + }); + const settings = await app.settings.openUserSettings("Preferences"); + await settings.getByLabel("Show media in timeline").getByLabel("In private rooms").click(); + await app.closeDialog(); + await app.viewRoomById(room.roomId); + await page.getByRole("button", { name: "Accept" }).click(); + await expect(page.getByText("Show image")).toBeVisible(); + for (const joinRule of [JoinRule.Invite, JoinRule.Knock, JoinRule.Restricted]) { + await bot.sendStateEvent(room.roomId, "m.room.join_rules", { + join_rule: joinRule, + }); + await expect(page.getByText("Show image")).not.toBeVisible(); + } + }); + test("should be able to show media in rooms globally", async ({ page, app, room, user }) => { + const settings = await app.settings.openUserSettings("Preferences"); + await settings.getByLabel("Show media in timeline").getByRole("radio", { name: "Always show" }).click(); + await app.closeDialog(); + await app.viewRoomById(room.roomId); + await page.getByRole("button", { name: "Accept" }).click(); + await expect(page.getByText("Show image")).not.toBeVisible(); + }); + test("should be able to hide media in an individual room", async ({ page, app, room, user }) => { + const settings = await app.settings.openUserSettings("Preferences"); + await settings.getByLabel("Show media in timeline").getByRole("radio", { name: "Always show" }).click(); + await app.closeDialog(); + + await app.viewRoomById(room.roomId); + await page.getByRole("button", { name: "Accept" }).click(); + + const roomSettings = await app.settings.openRoomSettings("General"); + await roomSettings.getByLabel("Show media in timeline").getByRole("radio", { name: "Always hide" }).click(); + await app.closeDialog(); + + await expect(page.getByText("Show image")).toBeVisible(); + }); + test("should be able to show media in an individual room", async ({ page, app, room, user }) => { + const settings = await app.settings.openUserSettings("Preferences"); + await settings.getByLabel("Show media in timeline").getByRole("radio", { name: "Always hide" }).click(); + await app.closeDialog(); + + await app.viewRoomById(room.roomId); + await page.getByRole("button", { name: "Accept" }).click(); + + const roomSettings = await app.settings.openRoomSettings("General"); + await roomSettings.getByLabel("Show media in timeline").getByRole("radio", { name: "Always show" }).click(); + await app.closeDialog(); + + await expect(page.getByText("Show image")).not.toBeVisible(); + }); +}); diff --git a/playwright/snapshots/timeline/media-preview-settings.spec.ts/invite-no-avatar-linux.png b/playwright/snapshots/timeline/media-preview-settings.spec.ts/invite-no-avatar-linux.png new file mode 100644 index 0000000000000000000000000000000000000000..00fdb29c814a2649dc52ee0a915cb18605574217 GIT binary patch literal 17703 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 literal 0 HcmV?d00001 diff --git a/playwright/snapshots/timeline/media-preview-settings.spec.ts/invite-room-tree-no-avatar-linux.png b/playwright/snapshots/timeline/media-preview-settings.spec.ts/invite-room-tree-no-avatar-linux.png new file mode 100644 index 0000000000000000000000000000000000000000..452f08d3e2803966e7d61d20ea4263413c3759aa GIT binary patch literal 3826 zcmVPx@tVu*cRCt{2-Fb9V*O>tD@4Ii+Vp+0mz+k{OCN{w=4iHSIP#8>rh9;f1(@fdQ zk}#b@Iz4SNZAl3bl1_Ta>7*n*2?-FOLqZc65;7Cg0EMux@q!^N1_K7$c#$_r*4yr# zKV%y$%V10hOYiUKAKm+O&%4t3^zOUcL%-h-%}mqM4UZj)R83*b5e0c2TJ6*>G?1OQ5Duu-=t zy?W3!Uo?+-?iO`CZh3@%RTzM#o2E(aHklA20)TFq*9Lins9!w~elDs`2P%*7+rgq# zH%wKLMM{}rSRMS>sU5{9K08-&raD*?3f49Pg57Pid(HlH?kzv1D1 zyXm?qOCnbLYBb$!NsW4;4%O?s-#T*S{X#uxw#{v!IOQQfcyQ#Lp{h&1J?G5bCwO>& zofKKbippx!YPZpDXy%dk3U@6((pax`uuz*z8TFH4L;t0}C<|ZRsdD!=9@uw~C=e_w zuWavDTMroPfA&f7!OIcp9l1GAACvOEmvdx?^p%__cMstqeYYWqSXy2gHLv=7?fQ9J zD$o0xel!G#`283##t@?Ys0;vEd`jFC%O=F9cy7n3a~#)kBx-7~CiLFiPpXP*5HK9# zzz`_3dNDvi7WKay0RXFtYt}!#CEyF)?mBQBcYRT==axa&%=oY*uN)8r7gId~b%HoF zR`klCGa!JBn6+l0u))Y}BtRGfHaFxM14Izrpu~uVVdz(&*Wm8cS3NFB(f?35j{6#j zZIceH&AXUijtEjb^E{{$L~2s0f%cx+m$)TnvT#$~G|aO6ijvoh;h519>Ie(~0f8w7 zK|}#A=9V2;oA(d1ANu<1#&KL&^HVq`*|OJ-Hs`9U>iqe?nK)s5WQRY;{oSxm7X^N`&^muHdN!q@ch(tu4?31SCp?hW zHosMz7auIKjH`2Ioa4K@s-S#diQX1igW7ws--m50Rh zSPv=NEhq#fVrpiH>P|t`EJG%uW*L$oT9l&2oF1o`B+)tp2ml2Tnd%j^T8n8-9dqHr zZxH7L24oHx002crXOA2?YO|?Rr%p~vO1io4gX8WyR(@e<&AZp8kQis;@1B=?C0+XI zGsfl8mh{k?cjbvWZ7=Dq;=KG+)wORK11o4EA~P9S)S#waRT5qC^`Stu>6ZMBrjHIEIcyk4R#w*ZX;TLd90-VK z&z@cV&YGiN9IdLV?%6YG{P^)t{P2g{w{QEyf4!<{`i`AD_a8WLZL`0jzG2~_MJG<2 z82`xlJ$v`WIAdOV=|#rahK(Ed?b}ybS=BEiBWGOB#0leVb~^xED!CLjYv<0Lix)2$ zHS(LDxVWvKZFPIxvu4doi1)5ou_`w=H>qdRoHeXu$Ma~+Wl{0qiXIr-=cI%dtGq!EBzq;DD`Qwj=4jD2yYfxij z@Re8oke8qTP*zrEW@c_~?$V{N)Ya8an>y9!^S$`uOHs4J) zbg9SVNlZ)}GGxf1!-tnIe=E6na!P7Sr)$k|Vb{%(xpp0&beDhFGSv%Gsc){GRuNCYfY^47uuE(Wu8m~L~PK5ac+0RkxGAQ zgXoqSrIMohc9+`HT(=##WjY*=^z?L5l5|ZkI#XmA z#^9{M4u=B(dM78RB&QS}KYroj#rCo;mo}~K@p`>Bn@R|=J8ZHndE>pJAW%_^aXKlb zhIzeZyd2k2a+`(Ti~^-VDQka+m}|9)b7#E0wzQ$;Edo%+6e202WKgqd9TH_gfgu%D zsqBNZ{ri98`1VtcAJ-8CMgbW%kE=;k)f>-2_`e4co$>b0)sZm(K)2gHXU>z!y_>eO zK!jMgCpOkKW%A?!0|p#CaIo{&{W38;(9d!A0wFz(?rSvz zg&C%Q*M2eXOBQTwdvMzlTFsMjcq2oR0h5TR3Q{207?bI>CpxW=2?)Rd1Q2!na@iM^ zFI*yK)3TPPakY9Dylfa1aBZWaZQ&hcv#H&>bq$3=ilPo3I%L?x!{WSgmrKilv0xy$ zd(WPln%Y^jX8!5**A_2YWVhRLb8{Q&8vp>2+;9o4EK6y9(P!gqX2~v+lRFxYZ9C^+4Jaz z<82Q@ii%S`{pq=yl@+Ruxw_gKwMHbs0H|m=`-pXZY6Y8ipg=^TGC>h6V$sH{vEMJJ zvprIXBeJu9|MJV5Hf=h5_((-%Wol~5?AfzNWRH*)`I%>bx#H~=yZ7wbvv;q{6*Ft* zj44y6D5}~gHT65+nY3p0+6@~vbnl*+nv&e!5SJ&;^UG&`;f!%^+4AWw!-$Xf{`}|v z{^+;AEr{ZEvN~B8j=OoJS5Mo&%?d7C-jYK7fzn?**Y-&JyeCP|C{s>atz*&r#w(*% znR-)CeeXZ@NyzG=>cpTXaVcj$D60B>DIkj(h)Rs88wL_!6ckwr)@uG^;U#Mb2*l1r zS+GoMH9rGFkjSqOKE-#E;q<)&05RlmOWcZr!^Qfs|YwN4=FoIF7qT(YI%Gb#+d8bCTka z83GUh0#~^X@_5FTLYg##uyQ3sg zhRC>_dz5K|b_X=+K9K~TzWRCpTp|YJ%7vs3Qg(8dC(9qxyggW>%^V2)eAOGvw zilXM{BD3b_BKP$^_(*E{7{1n;2+xO<{9 literal 0 HcmV?d00001 diff --git a/playwright/snapshots/timeline/media-preview-settings.spec.ts/invite-room-tree-with-avatar-linux.png b/playwright/snapshots/timeline/media-preview-settings.spec.ts/invite-room-tree-with-avatar-linux.png new file mode 100644 index 0000000000000000000000000000000000000000..452f08d3e2803966e7d61d20ea4263413c3759aa GIT binary patch literal 3826 zcmVPx@tVu*cRCt{2-Fb9V*O>tD@4Ii+Vp+0mz+k{OCN{w=4iHSIP#8>rh9;f1(@fdQ zk}#b@Iz4SNZAl3bl1_Ta>7*n*2?-FOLqZc65;7Cg0EMux@q!^N1_K7$c#$_r*4yr# zKV%y$%V10hOYiUKAKm+O&%4t3^zOUcL%-h-%}mqM4UZj)R83*b5e0c2TJ6*>G?1OQ5Duu-=t zy?W3!Uo?+-?iO`CZh3@%RTzM#o2E(aHklA20)TFq*9Lins9!w~elDs`2P%*7+rgq# zH%wKLMM{}rSRMS>sU5{9K08-&raD*?3f49Pg57Pid(HlH?kzv1D1 zyXm?qOCnbLYBb$!NsW4;4%O?s-#T*S{X#uxw#{v!IOQQfcyQ#Lp{h&1J?G5bCwO>& zofKKbippx!YPZpDXy%dk3U@6((pax`uuz*z8TFH4L;t0}C<|ZRsdD!=9@uw~C=e_w zuWavDTMroPfA&f7!OIcp9l1GAACvOEmvdx?^p%__cMstqeYYWqSXy2gHLv=7?fQ9J zD$o0xel!G#`283##t@?Ys0;vEd`jFC%O=F9cy7n3a~#)kBx-7~CiLFiPpXP*5HK9# zzz`_3dNDvi7WKay0RXFtYt}!#CEyF)?mBQBcYRT==axa&%=oY*uN)8r7gId~b%HoF zR`klCGa!JBn6+l0u))Y}BtRGfHaFxM14Izrpu~uVVdz(&*Wm8cS3NFB(f?35j{6#j zZIceH&AXUijtEjb^E{{$L~2s0f%cx+m$)TnvT#$~G|aO6ijvoh;h519>Ie(~0f8w7 zK|}#A=9V2;oA(d1ANu<1#&KL&^HVq`*|OJ-Hs`9U>iqe?nK)s5WQRY;{oSxm7X^N`&^muHdN!q@ch(tu4?31SCp?hW zHosMz7auIKjH`2Ioa4K@s-S#diQX1igW7ws--m50Rh zSPv=NEhq#fVrpiH>P|t`EJG%uW*L$oT9l&2oF1o`B+)tp2ml2Tnd%j^T8n8-9dqHr zZxH7L24oHx002crXOA2?YO|?Rr%p~vO1io4gX8WyR(@e<&AZp8kQis;@1B=?C0+XI zGsfl8mh{k?cjbvWZ7=Dq;=KG+)wORK11o4EA~P9S)S#waRT5qC^`Stu>6ZMBrjHIEIcyk4R#w*ZX;TLd90-VK z&z@cV&YGiN9IdLV?%6YG{P^)t{P2g{w{QEyf4!<{`i`AD_a8WLZL`0jzG2~_MJG<2 z82`xlJ$v`WIAdOV=|#rahK(Ed?b}ybS=BEiBWGOB#0leVb~^xED!CLjYv<0Lix)2$ zHS(LDxVWvKZFPIxvu4doi1)5ou_`w=H>qdRoHeXu$Ma~+Wl{0qiXIr-=cI%dtGq!EBzq;DD`Qwj=4jD2yYfxij z@Re8oke8qTP*zrEW@c_~?$V{N)Ya8an>y9!^S$`uOHs4J) zbg9SVNlZ)}GGxf1!-tnIe=E6na!P7Sr)$k|Vb{%(xpp0&beDhFGSv%Gsc){GRuNCYfY^47uuE(Wu8m~L~PK5ac+0RkxGAQ zgXoqSrIMohc9+`HT(=##WjY*=^z?L5l5|ZkI#XmA z#^9{M4u=B(dM78RB&QS}KYroj#rCo;mo}~K@p`>Bn@R|=J8ZHndE>pJAW%_^aXKlb zhIzeZyd2k2a+`(Ti~^-VDQka+m}|9)b7#E0wzQ$;Edo%+6e202WKgqd9TH_gfgu%D zsqBNZ{ri98`1VtcAJ-8CMgbW%kE=;k)f>-2_`e4co$>b0)sZm(K)2gHXU>z!y_>eO zK!jMgCpOkKW%A?!0|p#CaIo{&{W38;(9d!A0wFz(?rSvz zg&C%Q*M2eXOBQTwdvMzlTFsMjcq2oR0h5TR3Q{207?bI>CpxW=2?)Rd1Q2!na@iM^ zFI*yK)3TPPakY9Dylfa1aBZWaZQ&hcv#H&>bq$3=ilPo3I%L?x!{WSgmrKilv0xy$ zd(WPln%Y^jX8!5**A_2YWVhRLb8{Q&8vp>2+;9o4EK6y9(P!gqX2~v+lRFxYZ9C^+4Jaz z<82Q@ii%S`{pq=yl@+Ruxw_gKwMHbs0H|m=`-pXZY6Y8ipg=^TGC>h6V$sH{vEMJJ zvprIXBeJu9|MJV5Hf=h5_((-%Wol~5?AfzNWRH*)`I%>bx#H~=yZ7wbvv;q{6*Ft* zj44y6D5}~gHT65+nY3p0+6@~vbnl*+nv&e!5SJ&;^UG&`;f!%^+4AWw!-$Xf{`}|v z{^+;AEr{ZEvN~B8j=OoJS5Mo&%?d7C-jYK7fzn?**Y-&JyeCP|C{s>atz*&r#w(*% znR-)CeeXZ@NyzG=>cpTXaVcj$D60B>DIkj(h)Rs88wL_!6ckwr)@uG^;U#Mb2*l1r zS+GoMH9rGFkjSqOKE-#E;q<)&05RlmOWcZr!^Qfs|YwN4=FoIF7qT(YI%Gb#+d8bCTka z83GUh0#~^X@_5FTLYg##uyQ3sg zhRC>_dz5K|b_X=+K9K~TzWRCpTp|YJ%7vs3Qg(8dC(9qxyggW>%^V2)eAOGvw zilXM{BD3b_BKP$^_(*E{7{1n;2+xO<{9 literal 0 HcmV?d00001 diff --git a/playwright/snapshots/timeline/media-preview-settings.spec.ts/invite-with-avatar-linux.png b/playwright/snapshots/timeline/media-preview-settings.spec.ts/invite-with-avatar-linux.png new file mode 100644 index 0000000000000000000000000000000000000000..00fdb29c814a2649dc52ee0a915cb18605574217 GIT binary patch literal 17703 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 literal 0 HcmV?d00001 diff --git a/src/components/views/settings/tabs/room/GeneralRoomSettingsTab.tsx b/src/components/views/settings/tabs/room/GeneralRoomSettingsTab.tsx index 2615c083c9..e50dafd5d3 100644 --- a/src/components/views/settings/tabs/room/GeneralRoomSettingsTab.tsx +++ b/src/components/views/settings/tabs/room/GeneralRoomSettingsTab.tsx @@ -22,6 +22,7 @@ import { SettingsSubsection } from "../../shared/SettingsSubsection"; import SettingsTab from "../SettingsTab"; import { SettingsSection } from "../../shared/SettingsSection"; import { UrlPreviewSettings } from "../../../room_settings/UrlPreviewSettings"; +import { MediaPreviewAccountSettings } from "../user/MediaPreviewSetting"; interface IProps { room: Room; @@ -92,6 +93,7 @@ export default class GeneralRoomSettingsTab extends React.Component {urlPreviewSettings} + {leaveSection} diff --git a/src/components/views/settings/tabs/user/MediaPreviewSetting.tsx b/src/components/views/settings/tabs/user/MediaPreviewSetting.tsx index 859e750b21..fb22626b30 100644 --- a/src/components/views/settings/tabs/user/MediaPreviewSetting.tsx +++ b/src/components/views/settings/tabs/user/MediaPreviewSetting.tsx @@ -15,19 +15,30 @@ import { useSettingValue } from "../../../../../hooks/useSettings"; import SettingsStore from "../../../../../settings/SettingsStore"; import { SettingLevel } from "../../../../../settings/SettingLevel"; -export const MediaPreviewAccountSettings: React.FC = () => { - const currentMediaPreview = useSettingValue("mediaPreviewConfig"); +export const MediaPreviewAccountSettings: React.FC<{ roomId?: string }> = ({ roomId }) => { + const currentMediaPreview = useSettingValue("mediaPreviewConfig", roomId); + + const changeSetting = useCallback( + (newValue: MediaPreviewConfig) => { + SettingsStore.setValue( + "mediaPreviewConfig", + roomId ?? null, + roomId ? SettingLevel.ROOM_ACCOUNT : SettingLevel.ACCOUNT, + newValue, + ); + }, + [roomId], + ); const avatarOnChange = useCallback( (c: boolean) => { - const newValue = { + changeSetting({ ...currentMediaPreview, // Switch is inverted. "Hide avatars..." invite_avatars: c ? MediaPreviewValue.Off : MediaPreviewValue.On, - } satisfies MediaPreviewConfig; - SettingsStore.setValue("mediaPreviewConfig", null, SettingLevel.ACCOUNT, newValue); + }); }, - [currentMediaPreview], + [changeSetting, currentMediaPreview], ); const mediaPreviewOnChangeOff = useCallback>( @@ -35,12 +46,12 @@ export const MediaPreviewAccountSettings: React.FC = () => { if (!event.target.checked) { return; } - SettingsStore.setValue("mediaPreviewConfig", null, SettingLevel.ACCOUNT, { + changeSetting({ ...currentMediaPreview, media_previews: MediaPreviewValue.Off, - } satisfies MediaPreviewConfig); + }); }, - [currentMediaPreview], + [changeSetting, currentMediaPreview], ); const mediaPreviewOnChangePrivate = useCallback>( @@ -48,12 +59,12 @@ export const MediaPreviewAccountSettings: React.FC = () => { if (!event.target.checked) { return; } - SettingsStore.setValue("mediaPreviewConfig", null, SettingLevel.ACCOUNT, { + changeSetting({ ...currentMediaPreview, media_previews: MediaPreviewValue.Private, - } satisfies MediaPreviewConfig); + }); }, - [currentMediaPreview], + [changeSetting, currentMediaPreview], ); const mediaPreviewOnChangeOn = useCallback>( @@ -61,56 +72,71 @@ export const MediaPreviewAccountSettings: React.FC = () => { if (!event.target.checked) { return; } - SettingsStore.setValue("mediaPreviewConfig", null, SettingLevel.ACCOUNT, { + changeSetting({ ...currentMediaPreview, media_previews: MediaPreviewValue.On, - } satisfies MediaPreviewConfig); + }); }, - [currentMediaPreview], + [changeSetting, currentMediaPreview], ); return ( - - + {!roomId && ( + + )} + {/* Explict label here because htmlFor is not supported for linking to radiogroups */} + {_t("settings|media_preview|media_preview_description")} } > - - - - } - > - + + {!roomId && ( + + } + > + + + )} } > - + diff --git a/src/hooks/room/useJoinRule.ts b/src/hooks/room/useJoinRule.ts new file mode 100644 index 0000000000..f027ffe4cd --- /dev/null +++ b/src/hooks/room/useJoinRule.ts @@ -0,0 +1,30 @@ +/* +Copyright 2025 New Vector 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 { useEffect, useState } from "react"; +import { EventType, type MatrixEvent, type Room, RoomStateEvent, type JoinRule } from "matrix-js-sdk/src/matrix"; +import { type Optional } from "matrix-events-sdk"; + +import { useTypedEventEmitter } from "../useEventEmitter"; + +/** + * Helper to retrieve the join rules for given room + * @param room + * @returns the current join rule + */ +export function useJoinRule(room?: Room): Optional { + const [topic, setJoinRule] = useState(room?.getJoinRule()); + useTypedEventEmitter(room?.currentState, RoomStateEvent.Events, (ev: MatrixEvent) => { + if (ev.getType() !== EventType.RoomJoinRules) return; + setJoinRule(room?.getJoinRule()); + }); + useEffect(() => { + setJoinRule(room?.getJoinRule()); + }, [room]); + + return topic; +} diff --git a/src/hooks/room/useRoomAvatar.ts b/src/hooks/room/useRoomAvatar.ts new file mode 100644 index 0000000000..9236654cca --- /dev/null +++ b/src/hooks/room/useRoomAvatar.ts @@ -0,0 +1,30 @@ +/* +Copyright 2025 New Vector 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 { useEffect, useState } from "react"; +import { EventType, type MatrixEvent, type Room, RoomStateEvent } from "matrix-js-sdk/src/matrix"; +import { type Optional } from "matrix-events-sdk"; + +import { useTypedEventEmitter } from "../useEventEmitter"; + +/** + * Helper to retrieve the avatar for given room + * @param room + * @returns the current avatar + */ +export function useRoomAvatar(room?: Room): Optional { + const [topic, setAvatar] = useState(room?.getMxcAvatarUrl()); + useTypedEventEmitter(room?.currentState, RoomStateEvent.Events, (ev: MatrixEvent) => { + if (ev.getType() !== EventType.RoomAvatar) return; + setAvatar(room?.getMxcAvatarUrl()); + }); + useEffect(() => { + setAvatar(room?.getMxcAvatarUrl()); + }, [room]); + + return topic; +} diff --git a/src/hooks/useMediaVisible.ts b/src/hooks/useMediaVisible.ts index b34f561e6c..75237e33b2 100644 --- a/src/hooks/useMediaVisible.ts +++ b/src/hooks/useMediaVisible.ts @@ -5,7 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com Please see LICENSE files in the repository root for full details. */ -import { useCallback, useMemo } from "react"; +import { useCallback } from "react"; import { JoinRule } from "matrix-js-sdk/src/matrix"; import { SettingLevel } from "../settings/SettingLevel"; @@ -13,6 +13,7 @@ import { useSettingValue } from "./useSettings"; import SettingsStore from "../settings/SettingsStore"; import { useMatrixClientContext } from "../contexts/MatrixClientContext"; import { MediaPreviewValue } from "../@types/media_preview"; +import { useJoinRule } from "./room/useJoinRule"; const PRIVATE_JOIN_RULES: JoinRule[] = [JoinRule.Invite, JoinRule.Knock, JoinRule.Restricted]; @@ -25,6 +26,7 @@ export function useMediaVisible(eventId: string, roomId: string): [boolean, (vis const mediaPreviewSetting = useSettingValue("mediaPreviewConfig", roomId); const client = useMatrixClientContext(); const eventVisibility = useSettingValue("showMediaEventIds"); + const joinRule = useJoinRule(client.getRoom(roomId) ?? undefined); const setMediaVisible = useCallback( (visible: boolean) => { SettingsStore.setValue("showMediaEventIds", null, SettingLevel.DEVICE, { @@ -35,15 +37,7 @@ export function useMediaVisible(eventId: string, roomId: string): [boolean, (vis [eventId, eventVisibility], ); - const roomIsPrivate = useMemo(() => { - const joinRule = client?.getRoom(roomId)?.getJoinRule(); - if (PRIVATE_JOIN_RULES.includes(joinRule as JoinRule)) { - return true; - } else { - // All other join rules, and unknown will default to hiding. - return false; - } - }, [client, roomId]); + const roomIsPrivate = joinRule ? PRIVATE_JOIN_RULES.includes(joinRule) : false; const explicitEventVisiblity = eventVisibility[eventId]; // Always prefer the explicit per-event user preference here. diff --git a/src/settings/SettingsStore.ts b/src/settings/SettingsStore.ts index 89cd5a1f0c..17859f1b3f 100644 --- a/src/settings/SettingsStore.ts +++ b/src/settings/SettingsStore.ts @@ -374,10 +374,6 @@ export default class SettingsStore { roomId: string | null = null, excludeDefault = false, ): Settings[S]["default"] | undefined { - if (settingName === "mediaPreviewConfig") { - console.log("GET VALUE", SETTINGS[settingName]); - } - // Verify that the setting is actually a setting if (!SETTINGS[settingName]) { throw new Error("Setting '" + settingName + "' does not appear to be a setting."); diff --git a/src/settings/controllers/MediaPreviewConfigController.ts b/src/settings/controllers/MediaPreviewConfigController.ts index 9771df59ba..ec9a234aaa 100644 --- a/src/settings/controllers/MediaPreviewConfigController.ts +++ b/src/settings/controllers/MediaPreviewConfigController.ts @@ -5,7 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com Please see LICENSE files in the repository root for full details. */ -import { ClientEvent, type MatrixEvent, type MatrixClient, IContent } from "matrix-js-sdk/src/matrix"; +import { type IContent } from "matrix-js-sdk/src/matrix"; import { type AccountDataEvents } from "matrix-js-sdk/src/types"; import { @@ -31,17 +31,23 @@ export default class MediaPreviewConfigController extends MatrixClientBackedCont const inviteAvatars: MediaPreviewValue = content.invite_avatars; const validValues = Object.values(MediaPreviewValue); return { - invite_avatars: validValues.includes(inviteAvatars) ? inviteAvatars : MediaPreviewConfigController.default.invite_avatars, - media_previews: validValues.includes(mediaPreviews) ? mediaPreviews : MediaPreviewConfigController.default.media_previews, + invite_avatars: validValues.includes(inviteAvatars) + ? inviteAvatars + : MediaPreviewConfigController.default.invite_avatars, + media_previews: validValues.includes(mediaPreviews) + ? mediaPreviews + : MediaPreviewConfigController.default.media_previews, }; } + public constructor() { + super(); + } + private getValue = (roomId?: string): MediaPreviewConfig | null => { const source = roomId ? this.client?.getRoom(roomId) : this.client; - const value = source - ?.getAccountData(MEDIA_PREVIEW_ACCOUNT_DATA_TYPE) - ?.getContent(); - + const value = source?.getAccountData(MEDIA_PREVIEW_ACCOUNT_DATA_TYPE)?.getContent(); + if (!value) { return null; } else { @@ -49,20 +55,17 @@ export default class MediaPreviewConfigController extends MatrixClientBackedCont } }; - - protected async initMatrixClient(newClient: MatrixClient, oldClient?: MatrixClient): Promise { - + protected async initMatrixClient(): Promise { + // Unused } public getValueOverride(_level: SettingLevel, roomId: string | null): MediaPreviewConfig { - if (roomId) { - // Use globals for any undefined setting - return { - ...this.getRoomValue(roomId), - ...this.globalSetting, - }; + const roomConfig = roomId && this.getValue(roomId); + if (roomConfig) { + return roomConfig; } - return this.globalSetting; + // If no room config, or global settings request then return global. + return this.getValue() ?? MediaPreviewConfigController.default; } public get settingDisabled(): false { @@ -79,9 +82,7 @@ export default class MediaPreviewConfigController extends MatrixClientBackedCont return false; } if (roomId) { - await this.client.setRoomAccountData(roomId, MEDIA_PREVIEW_ACCOUNT_DATA_TYPE, { - value: newValue, - }); + await this.client.setRoomAccountData(roomId, MEDIA_PREVIEW_ACCOUNT_DATA_TYPE, newValue); return true; } await this.client.setAccountData(MEDIA_PREVIEW_ACCOUNT_DATA_TYPE, newValue); diff --git a/test/unit-tests/settings/controllers/MediaPreviewConfigController-test.ts b/test/unit-tests/settings/controllers/MediaPreviewConfigController-test.ts new file mode 100644 index 0000000000..444fa6b75a --- /dev/null +++ b/test/unit-tests/settings/controllers/MediaPreviewConfigController-test.ts @@ -0,0 +1,165 @@ +/* +Copyright 2024 New Vector Ltd. +Copyright 2024 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 { MatrixEvent } from "matrix-js-sdk/src/matrix"; + +import MatrixClientBackedController from "../../../../src/settings/controllers/MatrixClientBackedController"; +import MediaPreviewConfigController from "../../../../src/settings/controllers/MediaPreviewConfigController"; +import { SettingLevel } from "../../../../src/settings/SettingLevel"; +import { getMockClientWithEventEmitter, mockClientMethodsServer } from "../../../test-utils"; +import { MEDIA_PREVIEW_ACCOUNT_DATA_TYPE, MediaPreviewValue } from "../../../../src/@types/media_preview"; + +describe("MediaPreviewConfigController", () => { + afterEach(() => { + jest.restoreAllMocks(); + }); + + const ROOM_ID = "!room:example.org"; + + it("gets the default settings when none are specified.", () => { + const controller = new MediaPreviewConfigController(); + + MatrixClientBackedController.matrixClient = getMockClientWithEventEmitter({ + ...mockClientMethodsServer(), + getAccountData: jest.fn().mockReturnValue(null), + }); + + const value = controller.getValueOverride(SettingLevel.ACCOUNT, null); + expect(value).toEqual(MediaPreviewConfigController.default); + }); + + it("gets the default settings when the setting is empty.", () => { + const controller = new MediaPreviewConfigController(); + + MatrixClientBackedController.matrixClient = getMockClientWithEventEmitter({ + ...mockClientMethodsServer(), + getAccountData: jest + .fn() + .mockReturnValue(new MatrixEvent({ type: MEDIA_PREVIEW_ACCOUNT_DATA_TYPE, content: {} })), + }); + + const value = controller.getValueOverride(SettingLevel.ACCOUNT, null); + expect(value).toEqual(MediaPreviewConfigController.default); + }); + + it.each([["media_previews"], ["invite_avatars"]])("gets the correct value for %s at the global level", (key) => { + const controller = new MediaPreviewConfigController(); + + MatrixClientBackedController.matrixClient = getMockClientWithEventEmitter({ + ...mockClientMethodsServer(), + getAccountData: jest.fn().mockReturnValue( + new MatrixEvent({ + type: MEDIA_PREVIEW_ACCOUNT_DATA_TYPE, + content: { + [key]: MediaPreviewValue.Private, + }, + }), + ), + getRoom: jest.fn().mockReturnValue({ + getAccountData: jest.fn().mockReturnValue(null), + }), + }); + + const globalValue = controller.getValueOverride(SettingLevel.ACCOUNT, null); + expect(globalValue[key]).toEqual(MediaPreviewValue.Private); + + // Should follow the global value. + const roomValue = controller.getValueOverride(SettingLevel.ROOM_ACCOUNT, ROOM_ID); + expect(roomValue[key]).toEqual(MediaPreviewValue.Private); + }); + + it.each([["media_previews"], ["invite_avatars"]])("gets the correct value for %s at the room level", (key) => { + const controller = new MediaPreviewConfigController(); + + MatrixClientBackedController.matrixClient = getMockClientWithEventEmitter({ + ...mockClientMethodsServer(), + getAccountData: jest.fn().mockReturnValue(null), + getRoom: jest.fn().mockReturnValue({ + getAccountData: jest.fn().mockReturnValue( + new MatrixEvent({ + type: MEDIA_PREVIEW_ACCOUNT_DATA_TYPE, + content: { + [key]: MediaPreviewValue.Private, + }, + }), + ), + }), + }); + + const globalValue = controller.getValueOverride(SettingLevel.ACCOUNT, null); + expect(globalValue[key]).toEqual(MediaPreviewValue.On); + + // Should follow the global value. + const roomValue = controller.getValueOverride(SettingLevel.ROOM_ACCOUNT, ROOM_ID); + expect(roomValue[key]).toEqual(MediaPreviewValue.Private); + }); + + it.each([["media_previews"], ["invite_avatars"]])( + "uses defaults when an invalid value is set on the global level", + (key) => { + const controller = new MediaPreviewConfigController(); + + MatrixClientBackedController.matrixClient = getMockClientWithEventEmitter({ + ...mockClientMethodsServer(), + getAccountData: jest.fn().mockReturnValue( + new MatrixEvent({ + type: MEDIA_PREVIEW_ACCOUNT_DATA_TYPE, + content: { + [key]: "bibble", + }, + }), + ), + getRoom: jest.fn().mockReturnValue({ + getAccountData: jest.fn().mockReturnValue(null), + }), + }); + + const globalValue = controller.getValueOverride(SettingLevel.ACCOUNT, null); + expect(globalValue[key]).toEqual(MediaPreviewValue.On); + + // Should follow the global value. + const roomValue = controller.getValueOverride(SettingLevel.ROOM_ACCOUNT, ROOM_ID); + expect(roomValue[key]).toEqual(MediaPreviewValue.On); + }, + ); + it.each([["media_previews"], ["invite_avatars"]])( + "uses global value when an invalid value is set on the room level", + (key) => { + const controller = new MediaPreviewConfigController(); + + MatrixClientBackedController.matrixClient = getMockClientWithEventEmitter({ + ...mockClientMethodsServer(), + getAccountData: jest.fn().mockReturnValue( + new MatrixEvent({ + type: MEDIA_PREVIEW_ACCOUNT_DATA_TYPE, + content: { + [key]: MediaPreviewValue.Private, + }, + }), + ), + getRoom: jest.fn().mockReturnValue({ + getAccountData: jest.fn().mockReturnValue( + new MatrixEvent({ + type: MEDIA_PREVIEW_ACCOUNT_DATA_TYPE, + content: { + [key]: "bibble", + }, + }), + ), + }), + }); + + const globalValue = controller.getValueOverride(SettingLevel.ACCOUNT, null); + expect(globalValue[key]).toEqual(MediaPreviewValue.Private); + + // Should follow the global value. + const roomValue = controller.getValueOverride(SettingLevel.ROOM_ACCOUNT, ROOM_ID); + expect(roomValue[key]).toEqual(MediaPreviewValue.On); + }, + ); +});