Skip to content
This repository was archived by the owner on Sep 11, 2024. It is now read-only.

Commit 4dd2145

Browse files
authored
Move reaction message previews out of labs (#10601)
* Update reaction message previews to match designs * Delabs reaction message previews * tsc strict * Iterate * Add test * Iterate
1 parent 1f4d857 commit 4dd2145

File tree

8 files changed

+167
-45
lines changed

8 files changed

+167
-45
lines changed

src/components/views/context_menus/MessageContextMenu.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ interface IProps extends MenuProps {
114114
// True if the menu is being used as a right click menu
115115
rightClick?: boolean;
116116
// The Relations model from the JS SDK for reactions to `mxEvent`
117-
reactions?: Relations | null | undefined;
117+
reactions?: Relations | null;
118118
// A permalink to this event or an href of an anchor element the user has clicked
119119
link?: string;
120120

@@ -556,7 +556,7 @@ export default class MessageContextMenu extends React.Component<IProps, IState>
556556
}
557557

558558
let jumpToRelatedEventButton: JSX.Element | undefined;
559-
const relatedEventId = mxEvent.getWireContent()?.["m.relates_to"]?.event_id;
559+
const relatedEventId = mxEvent.relationEventId;
560560
if (relatedEventId && SettingsStore.getValue("developerMode")) {
561561
jumpToRelatedEventButton = (
562562
<IconizedContextMenuOption

src/i18n/strings/en_EN.json

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -915,7 +915,8 @@
915915
"%(senderName)s is calling": "%(senderName)s is calling",
916916
"* %(senderName)s %(emote)s": "* %(senderName)s %(emote)s",
917917
"%(senderName)s: %(message)s": "%(senderName)s: %(message)s",
918-
"%(senderName)s: %(reaction)s": "%(senderName)s: %(reaction)s",
918+
"You reacted %(reaction)s to %(message)s": "You reacted %(reaction)s to %(message)s",
919+
"%(sender)s reacted %(reaction)s to %(message)s": "%(sender)s reacted %(reaction)s to %(message)s",
919920
"%(senderName)s: %(stickerName)s": "%(senderName)s: %(stickerName)s",
920921
"Threads": "Threads",
921922
"Back to chat": "Back to chat",
@@ -937,7 +938,6 @@
937938
"Voice & Video": "Voice & Video",
938939
"Moderation": "Moderation",
939940
"Analytics": "Analytics",
940-
"Message Previews": "Message Previews",
941941
"Themes": "Themes",
942942
"Encryption": "Encryption",
943943
"Experimental": "Experimental",
@@ -963,8 +963,6 @@
963963
"New ways to ignore people": "New ways to ignore people",
964964
"Currently experimental.": "Currently experimental.",
965965
"Support adding custom themes": "Support adding custom themes",
966-
"Show message previews for reactions in DMs": "Show message previews for reactions in DMs",
967-
"Show message previews for reactions in all rooms": "Show message previews for reactions in all rooms",
968966
"Offline encrypted messaging using dehydrated devices": "Offline encrypted messaging using dehydrated devices",
969967
"Show current avatar and name for users in message history": "Show current avatar and name for users in message history",
970968
"Show HTML representation of room topics": "Show HTML representation of room topics",

src/settings/Settings.tsx

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,6 @@ export enum LabGroup {
8484
VoiceAndVideo,
8585
Moderation,
8686
Analytics,
87-
MessagePreviews,
8887
Themes,
8988
Encryption,
9089
Experimental,
@@ -105,7 +104,6 @@ export const labGroupNames: Record<LabGroup, string> = {
105104
[LabGroup.VoiceAndVideo]: _td("Voice & Video"),
106105
[LabGroup.Moderation]: _td("Moderation"),
107106
[LabGroup.Analytics]: _td("Analytics"),
108-
[LabGroup.MessagePreviews]: _td("Message Previews"),
109107
[LabGroup.Themes]: _td("Themes"),
110108
[LabGroup.Encryption]: _td("Encryption"),
111109
[LabGroup.Experimental]: _td("Experimental"),
@@ -298,22 +296,6 @@ export const SETTINGS: { [setting: string]: ISetting } = {
298296
supportedLevels: LEVELS_FEATURE,
299297
default: false,
300298
},
301-
"feature_roomlist_preview_reactions_dms": {
302-
isFeature: true,
303-
labsGroup: LabGroup.MessagePreviews,
304-
displayName: _td("Show message previews for reactions in DMs"),
305-
supportedLevels: LEVELS_FEATURE,
306-
default: false,
307-
// this option is a subset of `feature_roomlist_preview_reactions_all` so disable it when that one is enabled
308-
controller: new IncompatibleController("feature_roomlist_preview_reactions_all"),
309-
},
310-
"feature_roomlist_preview_reactions_all": {
311-
isFeature: true,
312-
labsGroup: LabGroup.MessagePreviews,
313-
displayName: _td("Show message previews for reactions in all rooms"),
314-
supportedLevels: LEVELS_FEATURE,
315-
default: false,
316-
},
317299
"feature_dehydration": {
318300
isFeature: true,
319301
labsGroup: LabGroup.Encryption,

src/stores/room-list/previews/ReactionEventPreview.ts

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -18,37 +18,39 @@ import { MatrixEvent } from "matrix-js-sdk/src/models/event";
1818

1919
import { IPreview } from "./IPreview";
2020
import { TagID } from "../models";
21-
import { getSenderName, isSelf, shouldPrefixMessagesIn } from "./utils";
21+
import { getSenderName, isSelf } from "./utils";
2222
import { _t } from "../../../languageHandler";
23-
import SettingsStore from "../../../settings/SettingsStore";
24-
import DMRoomMap from "../../../utils/DMRoomMap";
23+
import { MatrixClientPeg } from "../../../MatrixClientPeg";
24+
import { MessagePreviewStore } from "../MessagePreviewStore";
2525

2626
export class ReactionEventPreview implements IPreview {
2727
public getTextFor(event: MatrixEvent, tagId?: TagID, isThread?: boolean): string | null {
28-
const showDms = SettingsStore.getValue("feature_roomlist_preview_reactions_dms");
29-
const showAll = SettingsStore.getValue("feature_roomlist_preview_reactions_all");
30-
3128
const roomId = event.getRoomId();
3229
if (!roomId) return null; // not a room event
3330

34-
// If we're not showing all reactions, see if we're showing DMs instead
35-
if (!showAll) {
36-
// If we're not showing reactions on DMs, or we are and the room isn't a DM, skip
37-
if (!(showDms && DMRoomMap.shared().getUserIdForRoomId(roomId))) {
38-
return null;
39-
}
40-
}
41-
4231
const relation = event.getRelation();
4332
if (!relation) return null; // invalid reaction (probably redacted)
4433

4534
const reaction = relation.key;
4635
if (!reaction) return null; // invalid reaction (unknown format)
4736

48-
if (isThread || isSelf(event) || !shouldPrefixMessagesIn(roomId, tagId)) {
49-
return reaction;
50-
} else {
51-
return _t("%(senderName)s: %(reaction)s", { senderName: getSenderName(event), reaction });
37+
const cli = MatrixClientPeg.get();
38+
const room = cli?.getRoom(roomId);
39+
const relatedEvent = relation.event_id ? room?.findEventById(relation.event_id) : null;
40+
if (!relatedEvent) return null;
41+
42+
const message = MessagePreviewStore.instance.generatePreviewForEvent(relatedEvent);
43+
if (isSelf(event)) {
44+
return _t("You reacted %(reaction)s to %(message)s", {
45+
reaction,
46+
message,
47+
});
5248
}
49+
50+
return _t("%(sender)s reacted %(reaction)s to %(message)s", {
51+
sender: getSenderName(event),
52+
reaction,
53+
message,
54+
});
5355
}
5456
}

src/stores/room-list/previews/utils.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import { MatrixClientPeg } from "../../../MatrixClientPeg";
2020
import { DefaultTagID, TagID } from "../models";
2121

2222
export function isSelf(event: MatrixEvent): boolean {
23-
const selfUserId = MatrixClientPeg.get().getUserId();
23+
const selfUserId = MatrixClientPeg.get().getSafeUserId();
2424
if (event.getType() === "m.room.member") {
2525
return event.getStateKey() === selfUserId;
2626
}
@@ -37,5 +37,5 @@ export function shouldPrefixMessagesIn(roomId: string, tagId?: TagID): boolean {
3737
}
3838

3939
export function getSenderName(event: MatrixEvent): string {
40-
return event.sender ? event.sender.name : event.getSender() || "";
40+
return event.sender?.name ?? event.getSender() ?? "";
4141
}

test/components/views/settings/tabs/user/LabsUserSettingsTab-test.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ describe("<LabsUserSettingsTab />", () => {
7070
const { container } = render(getComponent());
7171

7272
const labsSections = container.getElementsByClassName("mx_SettingsTab_section");
73-
expect(labsSections).toHaveLength(12);
73+
expect(labsSections).toHaveLength(11);
7474
});
7575

7676
it("allow setting a labs flag which requires unstable support once support is confirmed", async () => {

test/stores/room-list/previews/PollStartEventPreview-test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import { makePollStartEvent } from "../../../test-utils";
2222

2323
jest.spyOn(MatrixClientPeg, "get").mockReturnValue({
2424
getUserId: () => "@me:example.com",
25+
getSafeUserId: () => "@me:example.com",
2526
} as unknown as MatrixClient);
2627

2728
describe("PollStartEventPreview", () => {
Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
/*
2+
Copyright 2023 The Matrix.org Foundation C.I.C.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
import { RelationType, Room, RoomMember } from "matrix-js-sdk/src/matrix";
18+
import { mocked } from "jest-mock";
19+
20+
import { mkEvent, stubClient } from "../../../test-utils";
21+
import { ReactionEventPreview } from "../../../../src/stores/room-list/previews/ReactionEventPreview";
22+
import { MatrixClientPeg } from "../../../../src/MatrixClientPeg";
23+
24+
describe("ReactionEventPreview", () => {
25+
const preview = new ReactionEventPreview();
26+
const userId = "@user:example.com";
27+
const roomId = "!room:example.com";
28+
29+
beforeAll(() => {
30+
stubClient();
31+
});
32+
33+
describe("getTextFor", () => {
34+
it("should return null for non-relations", () => {
35+
const event = mkEvent({
36+
event: true,
37+
content: {},
38+
user: userId,
39+
type: "m.room.message",
40+
room: roomId,
41+
});
42+
expect(preview.getTextFor(event)).toBeNull();
43+
});
44+
45+
it("should return null for non-reactions", () => {
46+
const event = mkEvent({
47+
event: true,
48+
content: {
49+
"body": "",
50+
"m.relates_to": {
51+
rel_type: RelationType.Thread,
52+
event_id: "$foo:bar",
53+
},
54+
},
55+
user: userId,
56+
type: "m.room.message",
57+
room: roomId,
58+
});
59+
expect(preview.getTextFor(event)).toBeNull();
60+
});
61+
62+
it("should use 'You' for your own reactions", () => {
63+
const cli = MatrixClientPeg.get();
64+
const room = new Room(roomId, cli, userId);
65+
mocked(cli.getRoom).mockReturnValue(room);
66+
67+
const message = mkEvent({
68+
event: true,
69+
content: {
70+
"body": "duck duck goose",
71+
"m.relates_to": {
72+
rel_type: RelationType.Thread,
73+
event_id: "$foo:bar",
74+
},
75+
},
76+
user: userId,
77+
type: "m.room.message",
78+
room: roomId,
79+
});
80+
81+
room.getUnfilteredTimelineSet().addLiveEvent(message, {});
82+
83+
const event = mkEvent({
84+
event: true,
85+
content: {
86+
"m.relates_to": {
87+
rel_type: RelationType.Annotation,
88+
key: "🪿",
89+
event_id: message.getId(),
90+
},
91+
},
92+
user: cli.getSafeUserId(),
93+
type: "m.reaction",
94+
room: roomId,
95+
});
96+
expect(preview.getTextFor(event)).toMatchInlineSnapshot(`"You reacted 🪿 to duck duck goose"`);
97+
});
98+
99+
it("should use display name for your others' reactions", () => {
100+
const cli = MatrixClientPeg.get();
101+
const room = new Room(roomId, cli, userId);
102+
mocked(cli.getRoom).mockReturnValue(room);
103+
104+
const message = mkEvent({
105+
event: true,
106+
content: {
107+
"body": "duck duck goose",
108+
"m.relates_to": {
109+
rel_type: RelationType.Thread,
110+
event_id: "$foo:bar",
111+
},
112+
},
113+
user: userId,
114+
type: "m.room.message",
115+
room: roomId,
116+
});
117+
118+
room.getUnfilteredTimelineSet().addLiveEvent(message, {});
119+
120+
const event = mkEvent({
121+
event: true,
122+
content: {
123+
"m.relates_to": {
124+
rel_type: RelationType.Annotation,
125+
key: "🪿",
126+
event_id: message.getId(),
127+
},
128+
},
129+
user: userId,
130+
type: "m.reaction",
131+
room: roomId,
132+
});
133+
event.sender = new RoomMember(roomId, userId);
134+
event.sender.name = "Bob";
135+
136+
expect(preview.getTextFor(event)).toMatchInlineSnapshot(`"Bob reacted 🪿 to duck duck goose"`);
137+
});
138+
});
139+
});

0 commit comments

Comments
 (0)