diff --git a/src/Unread.js b/src/Unread.js new file mode 100644 index 0000000000..cf121f9bd6 --- /dev/null +++ b/src/Unread.js @@ -0,0 +1,62 @@ +/* +Copyright 2015, 2016 OpenMarket Ltd + +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. +*/ + +var MatrixClientPeg = require('./MatrixClientPeg'); + +module.exports = { + /** + * Returns true iff this event arriving in a room should affect the room's + * count of unread messages + */ + eventTriggersUnreadCount: function(ev) { + if (ev.getType() == "m.room.member") { + return false; + } else if (ev.getType == 'm.room.message' && ev.getContent().msgtype == 'm.notify') { + return false; + } + return true; + }, + + doesRoomHaveUnreadMessages: function(room) { + var readUpToId = room.getEventReadUpTo(MatrixClientPeg.get().credentials.userId); + // 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. + + // 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) { + // 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; + } + } + // 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; + } +}; diff --git a/src/UnreadStatus.js b/src/UnreadStatus.js deleted file mode 100644 index 1227614257..0000000000 --- a/src/UnreadStatus.js +++ /dev/null @@ -1,30 +0,0 @@ -/* -Copyright 2015, 2016 OpenMarket Ltd - -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. -*/ - -module.exports = { - /** - * Returns true iff this event arriving in a room should affect the room's - * count of unread messages - */ - eventTriggersUnreadCount: function(ev) { - if (ev.getType() == "m.room.member") { - return false; - } else if (ev.getType == 'm.room.message' && ev.getContent().msgtype == 'm.notify') { - return false; - } - return true; - } -}; diff --git a/src/components/views/rooms/RoomList.js b/src/components/views/rooms/RoomList.js index 73b8d054e0..1e18e79c07 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,29 +123,7 @@ 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) { @@ -373,7 +342,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 } /> @@ -384,7 +352,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 } /> @@ -394,7 +361,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 } /> @@ -408,7 +374,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 } /> @@ -422,7 +387,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 } /> @@ -431,7 +395,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 }