From 04c7792b513fef97e345634956b57f45c88e4a72 Mon Sep 17 00:00:00 2001 From: David Baker Date: Wed, 6 Jan 2016 18:07:24 +0000 Subject: [PATCH 1/4] Use our read receipt to calculate whether rooms are unread. --- src/{UnreadStatus.js => Unread.js} | 19 ++++++++++++ src/components/views/rooms/RoomList.js | 43 ++------------------------ 2 files changed, 22 insertions(+), 40 deletions(-) rename src/{UnreadStatus.js => Unread.js} (64%) diff --git a/src/UnreadStatus.js b/src/Unread.js similarity index 64% rename from src/UnreadStatus.js rename to src/Unread.js index c8693c1e50..63a9d51ea1 100644 --- a/src/UnreadStatus.js +++ b/src/Unread.js @@ -14,6 +14,8 @@ See the License for the specific language governing permissions and limitations under the License. */ +var MatrixClientPeg = require('./MatrixClientPeg'); + module.exports = { /** * Returns true iff this event arriving in a room should affect the room's @@ -26,5 +28,22 @@ module.exports = { return false; } return true; + }, + + doesRoomHaveUnreadMessages: function(room) { + var readUpToId = room.getEventReadUpTo(MatrixClientPeg.get().credentials.userId); + var unread = false; + for (var i = room.timeline.length - 1; i >= 0; --i) { + var ev = room.timeline[i]; + + if (ev.getId() == readUpToId) { + break; + } + + if (this.eventTriggersUnreadCount(ev)) { + unread = true; + } + } + return unread; } }; diff --git a/src/components/views/rooms/RoomList.js b/src/components/views/rooms/RoomList.js index f60cc3a08a..fe2b7b229b 100644 --- a/src/components/views/rooms/RoomList.js +++ b/src/components/views/rooms/RoomList.js @@ -21,7 +21,7 @@ var GeminiScrollbar = require('react-gemini-scrollbar'); var MatrixClientPeg = require("../../../MatrixClientPeg"); var CallHandler = require('../../../CallHandler'); var RoomListSorter = require("../../../RoomListSorter"); -var UnreadStatus = require('../../../UnreadStatus'); +var Unread = require('../../../Unread'); var dis = require("../../../dispatcher"); var sdk = require('../../../index'); @@ -38,7 +38,6 @@ module.exports = React.createClass({ getInitialState: function() { return { - activityMap: null, isLoadingLeftRooms: false, lists: {}, incomingCall: null, @@ -57,7 +56,6 @@ module.exports = React.createClass({ cli.on("RoomMember.name", this.onRoomMemberName); var s = this.getRoomLists(); - s.activityMap = {}; this.setState(s); }, @@ -100,13 +98,6 @@ module.exports = React.createClass({ } }, - componentWillReceiveProps: function(newProps) { - this.state.activityMap[newProps.selectedRoom] = undefined; - this.setState({ - activityMap: this.state.activityMap - }); - }, - onRoom: function(room) { this._delayedRefreshRoomList(); }, @@ -132,33 +123,11 @@ module.exports = React.createClass({ onRoomTimeline: function(ev, room, toStartOfTimeline) { if (toStartOfTimeline) return; - - var hl = 0; - if ( - room.roomId != this.props.selectedRoom && - ev.getSender() != MatrixClientPeg.get().credentials.userId) - { - if (UnreadStatus.eventTriggersUnreadCount(ev)) { - hl = 1; - } - } - - var newState = this.getRoomLists(); - if (hl > 0) { - // obviously this won't deep copy but this shouldn't be necessary - var amap = this.state.activityMap; - amap[room.roomId] = Math.max(amap[room.roomId] || 0, hl); - - newState.activityMap = amap; - - } - // still want to update the list even if the highlight status - // hasn't changed because the ordering may have - this.setState(newState); + this.refreshRoomList(); }, onRoomReceipt: function(receiptEvent, room) { - // because if we read a notification, it will affect notification count + // because if we read a message it will affect notification / unread counts this.refreshRoomList(); }, @@ -365,7 +334,6 @@ module.exports = React.createClass({ label="Invites" editable={ false } order="recent" - activityMap={ self.state.activityMap } selectedRoom={ self.props.selectedRoom } incomingCall={ self.state.incomingCall } collapsed={ self.props.collapsed } /> @@ -376,7 +344,6 @@ module.exports = React.createClass({ verb="favourite" editable={ true } order="manual" - activityMap={ self.state.activityMap } selectedRoom={ self.props.selectedRoom } incomingCall={ self.state.incomingCall } collapsed={ self.props.collapsed } /> @@ -386,7 +353,6 @@ module.exports = React.createClass({ editable={ true } verb="restore" order="recent" - activityMap={ self.state.activityMap } selectedRoom={ self.props.selectedRoom } incomingCall={ self.state.incomingCall } collapsed={ self.props.collapsed } /> @@ -400,7 +366,6 @@ module.exports = React.createClass({ verb={ "tag as " + tagName } editable={ true } order="manual" - activityMap={ self.state.activityMap } selectedRoom={ self.props.selectedRoom } incomingCall={ self.state.incomingCall } collapsed={ self.props.collapsed } /> @@ -414,7 +379,6 @@ module.exports = React.createClass({ verb="demote" editable={ true } order="recent" - activityMap={ self.state.activityMap } selectedRoom={ self.props.selectedRoom } incomingCall={ self.state.incomingCall } collapsed={ self.props.collapsed } /> @@ -423,7 +387,6 @@ module.exports = React.createClass({ label="Historical" editable={ false } order="recent" - activityMap={ self.state.activityMap } selectedRoom={ self.props.selectedRoom } collapsed={ self.props.collapsed } alwaysShowHeader={ true } From 76177378f3bf9102d4b36840b8bc29c7bbec2771 Mon Sep 17 00:00:00 2001 From: David Baker Date: Wed, 6 Jan 2016 18:28:13 +0000 Subject: [PATCH 2/4] Comment & change the default to assuming there are unread messages. --- src/Unread.js | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/Unread.js b/src/Unread.js index 63a9d51ea1..1cc9865fdd 100644 --- a/src/Unread.js +++ b/src/Unread.js @@ -32,16 +32,23 @@ module.exports = { doesRoomHaveUnreadMessages: function(room) { var readUpToId = room.getEventReadUpTo(MatrixClientPeg.get().credentials.userId); - var unread = false; + // this just looks at whatever history we have, which if we've only just started + // up probably won't be very much, so if the last couple of events are ones that + // don't count, we don't know if there are any events that do count between where + // we have and the read receipt. We could fetch more history to try & find out, + // but currently we just guess. This impl assumes there are unread messages + // on the theory that false positives are better than false negatives here. + var unread = true; for (var i = room.timeline.length - 1; i >= 0; --i) { var ev = room.timeline[i]; if (ev.getId() == readUpToId) { + unread = false; break; } if (this.eventTriggersUnreadCount(ev)) { - unread = true; + break; } } return unread; From 548dac2ad903444333f865642339f721dd132b96 Mon Sep 17 00:00:00 2001 From: David Baker Date: Wed, 20 Jan 2016 17:19:52 +0000 Subject: [PATCH 3/4] Use new unread count methods --- src/components/structures/MatrixChat.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/structures/MatrixChat.js b/src/components/structures/MatrixChat.js index adb2ba14b5..ab9a73f77e 100644 --- a/src/components/structures/MatrixChat.js +++ b/src/components/structures/MatrixChat.js @@ -639,8 +639,8 @@ module.exports = React.createClass({ var rooms = MatrixClientPeg.get().getRooms(); for (var i = 0; i < rooms.length; ++i) { - if (rooms[i].unread_notification_count) { - notifCount += rooms[i].unread_notification_count; + if (rooms[i].getUnreadNotificationCount()) { + notifCount += rooms[i].getUnreadNotificationCount(); } } this.favicon.badge(notifCount); From 876646ac546c2ef7cca557694d5f3c323e48209f Mon Sep 17 00:00:00 2001 From: David Baker Date: Thu, 21 Jan 2016 13:22:13 +0000 Subject: [PATCH 4/4] Hopefully make unread loop a bit more digrestable. --- src/Unread.js | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/src/Unread.js b/src/Unread.js index 6c5e622265..cf121f9bd6 100644 --- a/src/Unread.js +++ b/src/Unread.js @@ -36,21 +36,27 @@ module.exports = { // up probably won't be very much, so if the last couple of events are ones that // don't count, we don't know if there are any events that do count between where // we have and the read receipt. We could fetch more history to try & find out, - // but currently we just guess. This impl assumes there are unread messages - // on the theory that false positives are better than false negatives here. - var unread = true; + // but currently we just guess. + + // Loop through messages, starting with the most recent... for (var i = room.timeline.length - 1; i >= 0; --i) { var ev = room.timeline[i]; if (ev.getId() == readUpToId) { - unread = false; - break; - } - - if (this.eventTriggersUnreadCount(ev)) { - break; + // If we've read up to this event, there's nothing more recents + // that counts and we can stop looking because the user's read + // this and everything before. + return false; + } else if (this.eventTriggersUnreadCount(ev)) { + // We've found a message that counts before we hit + // the read marker, so this room is definitely unread. + return true; } } - return unread; + // If we got here, we didn't find a message that counted but didn't + // find the read marker either, so we guess and say that the room + // is unread on the theory that false positives are better than + // false negatives here. + return true; } };