From b6d5e9eb1e30ba4cc284db9acfd45cb2a94f1a3d Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Fri, 14 Apr 2023 09:47:24 +0100 Subject: [PATCH 1/6] Update reaction message previews to match designs --- .../context_menus/MessageContextMenu.tsx | 2 +- .../previews/ReactionEventPreview.ts | 34 ++++++++++--------- src/stores/room-list/previews/utils.ts | 4 +-- 3 files changed, 21 insertions(+), 19 deletions(-) diff --git a/src/components/views/context_menus/MessageContextMenu.tsx b/src/components/views/context_menus/MessageContextMenu.tsx index 3ffe63a235d..24f6884d2d6 100644 --- a/src/components/views/context_menus/MessageContextMenu.tsx +++ b/src/components/views/context_menus/MessageContextMenu.tsx @@ -556,7 +556,7 @@ export default class MessageContextMenu extends React.Component } let jumpToRelatedEventButton: JSX.Element | undefined; - const relatedEventId = mxEvent.getWireContent()?.["m.relates_to"]?.event_id; + const relatedEventId = mxEvent.relationEventId; if (relatedEventId && SettingsStore.getValue("developerMode")) { jumpToRelatedEventButton = ( Date: Fri, 14 Apr 2023 09:47:49 +0100 Subject: [PATCH 2/6] Delabs reaction message previews --- src/i18n/strings/en_EN.json | 6 ++---- src/settings/Settings.tsx | 18 ------------------ 2 files changed, 2 insertions(+), 22 deletions(-) diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 9d2ade976e3..b1f0eee4353 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -907,7 +907,8 @@ "%(senderName)s is calling": "%(senderName)s is calling", "* %(senderName)s %(emote)s": "* %(senderName)s %(emote)s", "%(senderName)s: %(message)s": "%(senderName)s: %(message)s", - "%(senderName)s: %(reaction)s": "%(senderName)s: %(reaction)s", + "You reacted %(reaction)s to %(message)s": "You reacted %(reaction)s to %(message)s", + "%(sender)s reacted %(reaction)s to %(message)s": "%(sender)s reacted %(reaction)s to %(message)s", "%(senderName)s: %(stickerName)s": "%(senderName)s: %(stickerName)s", "Threads": "Threads", "Back to chat": "Back to chat", @@ -929,7 +930,6 @@ "Voice & Video": "Voice & Video", "Moderation": "Moderation", "Analytics": "Analytics", - "Message Previews": "Message Previews", "Themes": "Themes", "Encryption": "Encryption", "Experimental": "Experimental", @@ -955,8 +955,6 @@ "New ways to ignore people": "New ways to ignore people", "Currently experimental.": "Currently experimental.", "Support adding custom themes": "Support adding custom themes", - "Show message previews for reactions in DMs": "Show message previews for reactions in DMs", - "Show message previews for reactions in all rooms": "Show message previews for reactions in all rooms", "Offline encrypted messaging using dehydrated devices": "Offline encrypted messaging using dehydrated devices", "Show current avatar and name for users in message history": "Show current avatar and name for users in message history", "Show HTML representation of room topics": "Show HTML representation of room topics", diff --git a/src/settings/Settings.tsx b/src/settings/Settings.tsx index a4271653d7a..9c0394dd7d2 100644 --- a/src/settings/Settings.tsx +++ b/src/settings/Settings.tsx @@ -84,7 +84,6 @@ export enum LabGroup { VoiceAndVideo, Moderation, Analytics, - MessagePreviews, Themes, Encryption, Experimental, @@ -105,7 +104,6 @@ export const labGroupNames: Record = { [LabGroup.VoiceAndVideo]: _td("Voice & Video"), [LabGroup.Moderation]: _td("Moderation"), [LabGroup.Analytics]: _td("Analytics"), - [LabGroup.MessagePreviews]: _td("Message Previews"), [LabGroup.Themes]: _td("Themes"), [LabGroup.Encryption]: _td("Encryption"), [LabGroup.Experimental]: _td("Experimental"), @@ -298,22 +296,6 @@ export const SETTINGS: { [setting: string]: ISetting } = { supportedLevels: LEVELS_FEATURE, default: false, }, - "feature_roomlist_preview_reactions_dms": { - isFeature: true, - labsGroup: LabGroup.MessagePreviews, - displayName: _td("Show message previews for reactions in DMs"), - supportedLevels: LEVELS_FEATURE, - default: false, - // this option is a subset of `feature_roomlist_preview_reactions_all` so disable it when that one is enabled - controller: new IncompatibleController("feature_roomlist_preview_reactions_all"), - }, - "feature_roomlist_preview_reactions_all": { - isFeature: true, - labsGroup: LabGroup.MessagePreviews, - displayName: _td("Show message previews for reactions in all rooms"), - supportedLevels: LEVELS_FEATURE, - default: false, - }, "feature_dehydration": { isFeature: true, labsGroup: LabGroup.Encryption, From b90e2c4de416e3fd3b8b203b3bec494f0523df28 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Fri, 14 Apr 2023 09:54:06 +0100 Subject: [PATCH 3/6] tsc strict --- src/stores/room-list/previews/ReactionEventPreview.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/stores/room-list/previews/ReactionEventPreview.ts b/src/stores/room-list/previews/ReactionEventPreview.ts index adce9920109..58fe5a947dd 100644 --- a/src/stores/room-list/previews/ReactionEventPreview.ts +++ b/src/stores/room-list/previews/ReactionEventPreview.ts @@ -28,17 +28,17 @@ export class ReactionEventPreview implements IPreview { const roomId = event.getRoomId(); if (!roomId) return null; // not a room event - const cli = MatrixClientPeg.get(); - const room = cli?.getRoom(roomId); - const relatedEvent = room?.findEventById(event.relationEventId); - if (!relatedEvent) return null; - const relation = event.getRelation(); if (!relation) return null; // invalid reaction (probably redacted) const reaction = relation.key; if (!reaction) return null; // invalid reaction (unknown format) + const cli = MatrixClientPeg.get(); + const room = cli?.getRoom(roomId); + const relatedEvent = relation.event_id ? room?.findEventById(relation.event_id) : null; + if (!relatedEvent) return null; + const message = MessagePreviewStore.instance.generatePreviewForEvent(relatedEvent); if (isSelf(event)) { return _t("You reacted %(reaction)s to %(message)s", { From 6fb6ac44d149d221493a17e17d6f1f202e1457bf Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Fri, 14 Apr 2023 10:02:59 +0100 Subject: [PATCH 4/6] Iterate --- .../views/settings/tabs/user/LabsUserSettingsTab-test.tsx | 2 +- test/stores/room-list/previews/PollStartEventPreview-test.ts | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/test/components/views/settings/tabs/user/LabsUserSettingsTab-test.tsx b/test/components/views/settings/tabs/user/LabsUserSettingsTab-test.tsx index ddf6105274c..a8001481f64 100644 --- a/test/components/views/settings/tabs/user/LabsUserSettingsTab-test.tsx +++ b/test/components/views/settings/tabs/user/LabsUserSettingsTab-test.tsx @@ -70,7 +70,7 @@ describe("", () => { const { container } = render(getComponent()); const labsSections = container.getElementsByClassName("mx_SettingsTab_section"); - expect(labsSections).toHaveLength(12); + expect(labsSections).toHaveLength(11); }); it("allow setting a labs flag which requires unstable support once support is confirmed", async () => { diff --git a/test/stores/room-list/previews/PollStartEventPreview-test.ts b/test/stores/room-list/previews/PollStartEventPreview-test.ts index 324f42d7b68..dc9bcabfe3f 100644 --- a/test/stores/room-list/previews/PollStartEventPreview-test.ts +++ b/test/stores/room-list/previews/PollStartEventPreview-test.ts @@ -22,6 +22,7 @@ import { makePollStartEvent } from "../../../test-utils"; jest.spyOn(MatrixClientPeg, "get").mockReturnValue({ getUserId: () => "@me:example.com", + getSafeUserId: () => "@me:example.com", } as unknown as MatrixClient); describe("PollStartEventPreview", () => { From f2e10ca11debad4d559c50cd4c84d52d9b94936d Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Mon, 17 Apr 2023 14:13:16 +0100 Subject: [PATCH 5/6] Add test --- .../context_menus/MessageContextMenu.tsx | 2 +- .../previews/ReactionEventPreview-test.ts | 99 +++++++++++++++++++ 2 files changed, 100 insertions(+), 1 deletion(-) create mode 100644 test/stores/room-list/previews/ReactionEventPreview-test.ts diff --git a/src/components/views/context_menus/MessageContextMenu.tsx b/src/components/views/context_menus/MessageContextMenu.tsx index 24f6884d2d6..a4cc689349a 100644 --- a/src/components/views/context_menus/MessageContextMenu.tsx +++ b/src/components/views/context_menus/MessageContextMenu.tsx @@ -114,7 +114,7 @@ interface IProps extends MenuProps { // True if the menu is being used as a right click menu rightClick?: boolean; // The Relations model from the JS SDK for reactions to `mxEvent` - reactions?: Relations | null | undefined; + reactions?: Relations | null; // A permalink to this event or an href of an anchor element the user has clicked link?: string; diff --git a/test/stores/room-list/previews/ReactionEventPreview-test.ts b/test/stores/room-list/previews/ReactionEventPreview-test.ts new file mode 100644 index 00000000000..0859fdd489e --- /dev/null +++ b/test/stores/room-list/previews/ReactionEventPreview-test.ts @@ -0,0 +1,99 @@ +/* +Copyright 2023 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import { RelationType, Room } from "matrix-js-sdk/src/matrix"; +import { mocked } from "jest-mock"; + +import { mkEvent, stubClient } from "../../../test-utils"; +import { ReactionEventPreview } from "../../../../src/stores/room-list/previews/ReactionEventPreview"; +import { MatrixClientPeg } from "../../../../src/MatrixClientPeg"; + +describe("ReactionEventPreview", () => { + const preview = new ReactionEventPreview(); + const userId = "@user:example.com"; + const roomId = "!room:example.com"; + + beforeAll(() => { + stubClient(); + }); + + describe("getTextFor", () => { + it("should return null for non-relations", () => { + const event = mkEvent({ + event: true, + content: {}, + user: userId, + type: "m.room.message", + room: roomId, + }); + expect(preview.getTextFor(event)).toBeNull(); + }); + + it("should return null for non-reactions", () => { + const event = mkEvent({ + event: true, + content: { + "body": "", + "m.relates_to": { + rel_type: RelationType.Thread, + event_id: "$foo:bar", + }, + }, + user: userId, + type: "m.room.message", + room: roomId, + }); + expect(preview.getTextFor(event)).toBeNull(); + }); + + it("should use 'You' for your own reactions", () => { + const cli = MatrixClientPeg.get(); + const room = new Room(roomId, cli, userId); + mocked(cli.getRoom).mockReturnValue(room); + + const message = mkEvent({ + event: true, + content: { + "body": "", + "m.relates_to": { + rel_type: RelationType.Thread, + event_id: "$foo:bar", + }, + }, + user: userId, + type: "m.room.message", + room: roomId, + }); + + room.getUnfilteredTimelineSet().addLiveEvent(message, {}); + + const event = mkEvent({ + event: true, + content: { + "m.relates_to": { + rel_type: RelationType.Annotation, + key: "🪿", + event_id: message.getId(), + }, + }, + user: cli.getSafeUserId(), + type: "m.reaction", + room: roomId, + }); + expect(preview.getTextFor(event)).toMatchInlineSnapshot(`"You reacted 🪿 to "`); + }); + }); +}); From 5c8d697e890749c15bca072fa1d31c0d8f5eb5d9 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Tue, 18 Apr 2023 09:24:29 +0100 Subject: [PATCH 6/6] Iterate --- .../previews/ReactionEventPreview.ts | 12 ++--- .../previews/ReactionEventPreview-test.ts | 46 +++++++++++++++++-- 2 files changed, 49 insertions(+), 9 deletions(-) diff --git a/src/stores/room-list/previews/ReactionEventPreview.ts b/src/stores/room-list/previews/ReactionEventPreview.ts index 58fe5a947dd..a9f06581415 100644 --- a/src/stores/room-list/previews/ReactionEventPreview.ts +++ b/src/stores/room-list/previews/ReactionEventPreview.ts @@ -45,12 +45,12 @@ export class ReactionEventPreview implements IPreview { reaction, message, }); - } else { - return _t("%(sender)s reacted %(reaction)s to %(message)s", { - sender: getSenderName(event), - reaction, - message, - }); } + + return _t("%(sender)s reacted %(reaction)s to %(message)s", { + sender: getSenderName(event), + reaction, + message, + }); } } diff --git a/test/stores/room-list/previews/ReactionEventPreview-test.ts b/test/stores/room-list/previews/ReactionEventPreview-test.ts index 0859fdd489e..e49dba342c3 100644 --- a/test/stores/room-list/previews/ReactionEventPreview-test.ts +++ b/test/stores/room-list/previews/ReactionEventPreview-test.ts @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { RelationType, Room } from "matrix-js-sdk/src/matrix"; +import { RelationType, Room, RoomMember } from "matrix-js-sdk/src/matrix"; import { mocked } from "jest-mock"; import { mkEvent, stubClient } from "../../../test-utils"; @@ -67,7 +67,7 @@ describe("ReactionEventPreview", () => { const message = mkEvent({ event: true, content: { - "body": "", + "body": "duck duck goose", "m.relates_to": { rel_type: RelationType.Thread, event_id: "$foo:bar", @@ -93,7 +93,47 @@ describe("ReactionEventPreview", () => { type: "m.reaction", room: roomId, }); - expect(preview.getTextFor(event)).toMatchInlineSnapshot(`"You reacted 🪿 to "`); + expect(preview.getTextFor(event)).toMatchInlineSnapshot(`"You reacted 🪿 to duck duck goose"`); + }); + + it("should use display name for your others' reactions", () => { + const cli = MatrixClientPeg.get(); + const room = new Room(roomId, cli, userId); + mocked(cli.getRoom).mockReturnValue(room); + + const message = mkEvent({ + event: true, + content: { + "body": "duck duck goose", + "m.relates_to": { + rel_type: RelationType.Thread, + event_id: "$foo:bar", + }, + }, + user: userId, + type: "m.room.message", + room: roomId, + }); + + room.getUnfilteredTimelineSet().addLiveEvent(message, {}); + + const event = mkEvent({ + event: true, + content: { + "m.relates_to": { + rel_type: RelationType.Annotation, + key: "🪿", + event_id: message.getId(), + }, + }, + user: userId, + type: "m.reaction", + room: roomId, + }); + event.sender = new RoomMember(roomId, userId); + event.sender.name = "Bob"; + + expect(preview.getTextFor(event)).toMatchInlineSnapshot(`"Bob reacted 🪿 to duck duck goose"`); }); }); });