diff --git a/res/css/_components.scss b/res/css/_components.scss
index 20395550ab..7b8ca77739 100644
--- a/res/css/_components.scss
+++ b/res/css/_components.scss
@@ -173,6 +173,7 @@
@import "./views/rooms/_SendMessageComposer.scss";
@import "./views/rooms/_Stickers.scss";
@import "./views/rooms/_TopUnreadMessagesBar.scss";
+@import "./views/rooms/_UserOnlineDot.scss";
@import "./views/rooms/_WhoIsTypingTile.scss";
@import "./views/settings/_AvatarSetting.scss";
@import "./views/settings/_CrossSigningPanel.scss";
diff --git a/res/css/views/rooms/_RoomTile.scss b/res/css/views/rooms/_RoomTile.scss
index 1814919b61..e5c7948216 100644
--- a/res/css/views/rooms/_RoomTile.scss
+++ b/res/css/views/rooms/_RoomTile.scss
@@ -1,5 +1,6 @@
/*
Copyright 2015, 2016 OpenMarket Ltd
+Copyright 2019 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.
diff --git a/res/css/views/rooms/_UserOnlineDot.scss b/res/css/views/rooms/_UserOnlineDot.scss
new file mode 100644
index 0000000000..339e5cc48a
--- /dev/null
+++ b/res/css/views/rooms/_UserOnlineDot.scss
@@ -0,0 +1,23 @@
+/*
+Copyright 2019 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.
+*/
+
+.mx_UserOnlineDot {
+ border-radius: 50%;
+ background-color: $accent-color;
+ height: 5px;
+ width: 5px;
+ display: inline-block;
+}
diff --git a/src/components/views/rooms/RoomTile.js b/src/components/views/rooms/RoomTile.js
index 817ada9706..ecf2de394b 100644
--- a/src/components/views/rooms/RoomTile.js
+++ b/src/components/views/rooms/RoomTile.js
@@ -68,11 +68,6 @@ module.exports = createReactClass({
});
},
- _isDirectMessageRoom: function(roomId) {
- const dmRooms = DMRoomMap.shared().getUserIdForRoomId(roomId);
- return Boolean(dmRooms);
- },
-
_shouldShowStatusMessage() {
if (!SettingsStore.isFeatureEnabled("feature_custom_status")) {
return false;
@@ -371,8 +366,11 @@ module.exports = createReactClass({
let ariaLabel = name;
+ const dmUserId = DMRoomMap.shared().getUserIdForRoomId(this.props.room.roomId);
+
let dmIndicator;
- if (this._isDirectMessageRoom(this.props.room.roomId)) {
+ let dmOnline;
+ if (dmUserId) {
dmIndicator = ;
+
+ const { room } = this.props;
+ if (room.getMember(dmUserId).membership === "join" && room.getJoinedMemberCount() === 2) {
+ const UserOnlineDot = sdk.getComponent('rooms.UserOnlineDot');
+ dmOnline = ;
+ }
}
// The following labels are written in such a fashion to increase screen reader efficiency (speed).
@@ -428,6 +432,7 @@ module.exports = createReactClass({
{ label }
{ subtextLabel }
+ { dmOnline }
{ contextMenuButton }
{ badge }
diff --git a/src/components/views/rooms/UserOnlineDot.js b/src/components/views/rooms/UserOnlineDot.js
new file mode 100644
index 0000000000..426dd1bf64
--- /dev/null
+++ b/src/components/views/rooms/UserOnlineDot.js
@@ -0,0 +1,48 @@
+/*
+Copyright 2019 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, {useContext, useEffect, useMemo, useState, useCallback} from "react";
+import PropTypes from "prop-types";
+
+import {useEventEmitter} from "../../../hooks/useEventEmitter";
+import MatrixClientContext from "../../../contexts/MatrixClientContext";
+
+const UserOnlineDot = ({userId}) => {
+ const cli = useContext(MatrixClientContext);
+ const user = useMemo(() => cli.getUser(userId), [cli, userId]);
+
+ const [isOnline, setIsOnline] = useState(false);
+
+ // Recheck if the user or client changes
+ useEffect(() => {
+ setIsOnline(user && (user.currentlyActive || user.presence === "online"));
+ }, [cli, user]);
+ // Recheck also if we receive a User.currentlyActive event
+ const currentlyActiveHandler = useCallback((ev) => {
+ const content = ev.getContent();
+ setIsOnline(content.currently_active || content.presence === "online");
+ }, []);
+ useEventEmitter(user, "User.currentlyActive", currentlyActiveHandler);
+ useEventEmitter(user, "User.presence", currentlyActiveHandler);
+
+ return isOnline ? : null;
+};
+
+UserOnlineDot.propTypes = {
+ userId: PropTypes.string.isRequired,
+};
+
+export default UserOnlineDot;