+ let icon;
+ if (this.state.icon !== Icon.None) {
+ icon =
;
+ }
+
+ const classes = classNames("mx_DecoratedRoomAvatar", {
+ mx_DecoratedRoomAvatar_cutout: icon,
+ });
+
+ return
-
+ {icon}
{badge}
;
}
diff --git a/src/components/views/messages/MessageActionBar.js b/src/components/views/messages/MessageActionBar.js
index 513f21b8b7..c94f296eac 100644
--- a/src/components/views/messages/MessageActionBar.js
+++ b/src/components/views/messages/MessageActionBar.js
@@ -18,6 +18,7 @@ limitations under the License.
import React, {useEffect} from 'react';
import PropTypes from 'prop-types';
+import { EventStatus } from 'matrix-js-sdk';
import { _t } from '../../../languageHandler';
import * as sdk from '../../../index';
@@ -114,13 +115,19 @@ export default class MessageActionBar extends React.PureComponent {
static contextType = RoomContext;
componentDidMount() {
- this.props.mxEvent.on("Event.decrypted", this.onDecrypted);
+ if (this.props.mxEvent.status && this.props.mxEvent.status !== EventStatus.SENT) {
+ this.props.mxEvent.on("Event.status", this.onSent);
+ }
+ if (this.props.mxEvent.isBeingDecrypted()) {
+ this.props.mxEvent.once("Event.decrypted", this.onDecrypted);
+ }
this.props.mxEvent.on("Event.beforeRedaction", this.onBeforeRedaction);
}
componentWillUnmount() {
- this.props.mxEvent.removeListener("Event.decrypted", this.onDecrypted);
- this.props.mxEvent.removeListener("Event.beforeRedaction", this.onBeforeRedaction);
+ this.props.mxEvent.off("Event.status", this.onSent);
+ this.props.mxEvent.off("Event.decrypted", this.onDecrypted);
+ this.props.mxEvent.off("Event.beforeRedaction", this.onBeforeRedaction);
}
onDecrypted = () => {
@@ -134,6 +141,11 @@ export default class MessageActionBar extends React.PureComponent {
this.forceUpdate();
};
+ onSent = () => {
+ // When an event is sent and echoed the possible actions change.
+ this.forceUpdate();
+ };
+
onFocusChange = (focused) => {
if (!this.props.onFocusChange) {
return;
diff --git a/src/components/views/rooms/RoomTileIcon.tsx b/src/components/views/rooms/RoomTileIcon.tsx
deleted file mode 100644
index 94833ac818..0000000000
--- a/src/components/views/rooms/RoomTileIcon.tsx
+++ /dev/null
@@ -1,168 +0,0 @@
-/*
-Copyright 2020 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 React from "react";
-import { Room } from "matrix-js-sdk/src/models/room";
-import { DefaultTagID, TagID } from "../../../stores/room-list/models";
-import { User } from "matrix-js-sdk/src/models/user";
-import { MatrixEvent } from "matrix-js-sdk/src/models/event";
-import DMRoomMap from "../../../utils/DMRoomMap";
-import { MatrixClientPeg } from "../../../MatrixClientPeg";
-import { isPresenceEnabled } from "../../../utils/presence";
-import { _t } from "../../../languageHandler";
-import TextWithTooltip from "../elements/TextWithTooltip";
-
-enum Icon {
- // Note: the names here are used in CSS class names
- None = "NONE", // ... except this one
- Globe = "GLOBE",
- PresenceOnline = "ONLINE",
- PresenceAway = "AWAY",
- PresenceOffline = "OFFLINE",
-}
-
-function tooltipText(variant: Icon) {
- switch (variant) {
- case Icon.Globe:
- return _t("This room is public");
- case Icon.PresenceOnline:
- return _t("Online");
- case Icon.PresenceAway:
- return _t("Away");
- case Icon.PresenceOffline:
- return _t("Offline");
- }
-}
-
-interface IProps {
- room: Room;
-}
-
-interface IState {
- icon: Icon;
-}
-
-export default class RoomTileIcon extends React.Component
{
- private _dmUser: User;
- private isUnmounted = false;
- private isWatchingTimeline = false;
-
- constructor(props: IProps) {
- super(props);
-
- this.state = {
- icon: this.calculateIcon(),
- };
- }
-
- private get isPublicRoom(): boolean {
- const joinRules = this.props.room.currentState.getStateEvents("m.room.join_rules", "");
- const joinRule = joinRules && joinRules.getContent().join_rule;
- return joinRule === 'public';
- }
-
- private get dmUser(): User {
- return this._dmUser;
- }
-
- private set dmUser(val: User) {
- const oldUser = this._dmUser;
- this._dmUser = val;
- if (oldUser && oldUser !== this._dmUser) {
- oldUser.off('User.currentlyActive', this.onPresenceUpdate);
- oldUser.off('User.presence', this.onPresenceUpdate);
- }
- if (this._dmUser && oldUser !== this._dmUser) {
- this._dmUser.on('User.currentlyActive', this.onPresenceUpdate);
- this._dmUser.on('User.presence', this.onPresenceUpdate);
- }
- }
-
- public componentWillUnmount() {
- this.isUnmounted = true;
- if (this.isWatchingTimeline) this.props.room.off('Room.timeline', this.onRoomTimeline);
- this.dmUser = null; // clear listeners, if any
- }
-
- private onRoomTimeline = (ev: MatrixEvent, room: Room) => {
- if (this.isUnmounted) return;
-
- // apparently these can happen?
- if (!room) return;
- if (this.props.room.roomId !== room.roomId) return;
-
- if (ev.getType() === 'm.room.join_rules' || ev.getType() === 'm.room.member') {
- this.setState({icon: this.calculateIcon()});
- }
- };
-
- private onPresenceUpdate = () => {
- if (this.isUnmounted) return;
-
- let newIcon = this.getPresenceIcon();
- if (newIcon !== this.state.icon) this.setState({icon: newIcon});
- };
-
- private getPresenceIcon(): Icon {
- if (!this.dmUser) return Icon.None;
-
- let icon = Icon.None;
-
- const isOnline = this.dmUser.currentlyActive || this.dmUser.presence === 'online';
- if (isOnline) {
- icon = Icon.PresenceOnline;
- } else if (this.dmUser.presence === 'offline') {
- icon = Icon.PresenceOffline;
- } else if (this.dmUser.presence === 'unavailable') {
- icon = Icon.PresenceAway;
- }
-
- return icon;
- }
-
- private calculateIcon(): Icon {
- let icon = Icon.None;
-
- // We look at the DMRoomMap and not the tag here so that we don't exclude DMs in Favourites
- const otherUserId = DMRoomMap.shared().getUserIdForRoomId(this.props.room.roomId);
- if (otherUserId && this.props.room.getJoinedMemberCount() === 2) {
- // Track presence, if available
- if (isPresenceEnabled()) {
- if (otherUserId) {
- this.dmUser = MatrixClientPeg.get().getUser(otherUserId);
- icon = this.getPresenceIcon();
- }
- }
- } else {
- // Track publicity
- icon = this.isPublicRoom ? Icon.Globe : Icon.None;
- if (!this.isWatchingTimeline) {
- this.props.room.on('Room.timeline', this.onRoomTimeline);
- this.isWatchingTimeline = true;
- }
- }
- return icon;
- }
-
- public render(): React.ReactElement {
- if (this.state.icon === Icon.None) return null;
-
- return ;
- }
-}
diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json
index b311a0cd5b..e82581de8d 100644
--- a/src/i18n/strings/en_EN.json
+++ b/src/i18n/strings/en_EN.json
@@ -448,6 +448,8 @@
"Multiple integration managers": "Multiple integration managers",
"Try out new ways to ignore people (experimental)": "Try out new ways to ignore people (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",
"Enable advanced debugging for the room list": "Enable advanced debugging for the room list",
"Show info about bridges in room settings": "Show info about bridges in room settings",
"Font size": "Font size",
@@ -1187,8 +1189,6 @@
"%(count)s unread messages.|other": "%(count)s unread messages.",
"%(count)s unread messages.|one": "1 unread message.",
"Unread messages.": "Unread messages.",
- "This room is public": "This room is public",
- "Away": "Away",
"Add a topic": "Add a topic",
"Upgrading this room will shut down the current instance of the room and create an upgraded room with the same name.": "Upgrading this room will shut down the current instance of the room and create an upgraded room with the same name.",
"This room has already been upgraded.": "This room has already been upgraded.",
@@ -1894,6 +1894,8 @@
"Take picture": "Take picture",
"Remove for everyone": "Remove for everyone",
"Remove for me": "Remove for me",
+ "This room is public": "This room is public",
+ "Away": "Away",
"User Status": "User Status",
"powered by Matrix": "powered by Matrix",
"This homeserver would like to make sure you are not a robot.": "This homeserver would like to make sure you are not a robot.",
diff --git a/src/settings/Settings.ts b/src/settings/Settings.ts
index 714d80f983..3d18c14e16 100644
--- a/src/settings/Settings.ts
+++ b/src/settings/Settings.ts
@@ -158,6 +158,18 @@ export const SETTINGS: {[setting: string]: ISetting} = {
supportedLevels: LEVELS_FEATURE,
default: false,
},
+ "feature_roomlist_preview_reactions_dms": {
+ isFeature: true,
+ displayName: _td("Show message previews for reactions in DMs"),
+ supportedLevels: LEVELS_FEATURE,
+ default: false,
+ },
+ "feature_roomlist_preview_reactions_all": {
+ isFeature: true,
+ displayName: _td("Show message previews for reactions in all rooms"),
+ supportedLevels: LEVELS_FEATURE,
+ default: false,
+ },
"advancedRoomListLogging": {
// TODO: Remove flag before launch: https://github.com/vector-im/element-web/issues/14231
displayName: _td("Enable advanced debugging for the room list"),
diff --git a/src/stores/room-list/previews/IPreview.ts b/src/stores/room-list/previews/IPreview.ts
index 9beb92bfbf..fe69637543 100644
--- a/src/stores/room-list/previews/IPreview.ts
+++ b/src/stores/room-list/previews/IPreview.ts
@@ -27,5 +27,5 @@ export interface IPreview {
* @param tagId Optional. The tag where the room the event was sent in resides.
* @returns The preview.
*/
- getTextFor(event: MatrixEvent, tagId?: TagID): string;
+ getTextFor(event: MatrixEvent, tagId?: TagID): string | null;
}
diff --git a/src/stores/room-list/previews/ReactionEventPreview.ts b/src/stores/room-list/previews/ReactionEventPreview.ts
index 07fac107ca..c8f2be9a6e 100644
--- a/src/stores/room-list/previews/ReactionEventPreview.ts
+++ b/src/stores/room-list/previews/ReactionEventPreview.ts
@@ -19,9 +19,16 @@ import { TagID } from "../models";
import { MatrixEvent } from "matrix-js-sdk/src/models/event";
import { getSenderName, isSelf, shouldPrefixMessagesIn } from "./utils";
import { _t } from "../../../languageHandler";
+import SettingsStore from "../../../settings/SettingsStore";
+import DMRoomMap from "../../../utils/DMRoomMap";
export class ReactionEventPreview implements IPreview {
public getTextFor(event: MatrixEvent, tagId?: TagID): string {
+ const showDms = SettingsStore.isFeatureEnabled("feature_roomlist_preview_reactions_dms");
+ const showAll = SettingsStore.isFeatureEnabled("feature_roomlist_preview_reactions_all");
+
+ if (!showAll && (!showDms || DMRoomMap.shared().getUserIdForRoomId(event.getRoomId()))) return null;
+
const relation = event.getRelation();
if (!relation) return null; // invalid reaction (probably redacted)