mirror of https://github.com/vector-im/riot-web
Merge pull request #107 from matrix-org/unread_sync
Use read receipts to calculate unread room statuspull/21833/head
commit
97d42b3ad7
|
@ -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;
|
||||||
|
}
|
||||||
|
};
|
|
@ -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;
|
|
||||||
}
|
|
||||||
};
|
|
|
@ -21,7 +21,7 @@ var GeminiScrollbar = require('react-gemini-scrollbar');
|
||||||
var MatrixClientPeg = require("../../../MatrixClientPeg");
|
var MatrixClientPeg = require("../../../MatrixClientPeg");
|
||||||
var CallHandler = require('../../../CallHandler');
|
var CallHandler = require('../../../CallHandler');
|
||||||
var RoomListSorter = require("../../../RoomListSorter");
|
var RoomListSorter = require("../../../RoomListSorter");
|
||||||
var UnreadStatus = require('../../../UnreadStatus');
|
var Unread = require('../../../Unread');
|
||||||
var dis = require("../../../dispatcher");
|
var dis = require("../../../dispatcher");
|
||||||
var sdk = require('../../../index');
|
var sdk = require('../../../index');
|
||||||
|
|
||||||
|
@ -38,7 +38,6 @@ module.exports = React.createClass({
|
||||||
|
|
||||||
getInitialState: function() {
|
getInitialState: function() {
|
||||||
return {
|
return {
|
||||||
activityMap: null,
|
|
||||||
isLoadingLeftRooms: false,
|
isLoadingLeftRooms: false,
|
||||||
lists: {},
|
lists: {},
|
||||||
incomingCall: null,
|
incomingCall: null,
|
||||||
|
@ -57,7 +56,6 @@ module.exports = React.createClass({
|
||||||
cli.on("RoomMember.name", this.onRoomMemberName);
|
cli.on("RoomMember.name", this.onRoomMemberName);
|
||||||
|
|
||||||
var s = this.getRoomLists();
|
var s = this.getRoomLists();
|
||||||
s.activityMap = {};
|
|
||||||
this.setState(s);
|
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) {
|
onRoom: function(room) {
|
||||||
this._delayedRefreshRoomList();
|
this._delayedRefreshRoomList();
|
||||||
},
|
},
|
||||||
|
@ -132,29 +123,7 @@ module.exports = React.createClass({
|
||||||
|
|
||||||
onRoomTimeline: function(ev, room, toStartOfTimeline) {
|
onRoomTimeline: function(ev, room, toStartOfTimeline) {
|
||||||
if (toStartOfTimeline) return;
|
if (toStartOfTimeline) return;
|
||||||
|
this.refreshRoomList();
|
||||||
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);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
onRoomReceipt: function(receiptEvent, room) {
|
onRoomReceipt: function(receiptEvent, room) {
|
||||||
|
@ -373,7 +342,6 @@ module.exports = React.createClass({
|
||||||
label="Invites"
|
label="Invites"
|
||||||
editable={ false }
|
editable={ false }
|
||||||
order="recent"
|
order="recent"
|
||||||
activityMap={ self.state.activityMap }
|
|
||||||
selectedRoom={ self.props.selectedRoom }
|
selectedRoom={ self.props.selectedRoom }
|
||||||
incomingCall={ self.state.incomingCall }
|
incomingCall={ self.state.incomingCall }
|
||||||
collapsed={ self.props.collapsed } />
|
collapsed={ self.props.collapsed } />
|
||||||
|
@ -384,7 +352,6 @@ module.exports = React.createClass({
|
||||||
verb="favourite"
|
verb="favourite"
|
||||||
editable={ true }
|
editable={ true }
|
||||||
order="manual"
|
order="manual"
|
||||||
activityMap={ self.state.activityMap }
|
|
||||||
selectedRoom={ self.props.selectedRoom }
|
selectedRoom={ self.props.selectedRoom }
|
||||||
incomingCall={ self.state.incomingCall }
|
incomingCall={ self.state.incomingCall }
|
||||||
collapsed={ self.props.collapsed } />
|
collapsed={ self.props.collapsed } />
|
||||||
|
@ -394,7 +361,6 @@ module.exports = React.createClass({
|
||||||
editable={ true }
|
editable={ true }
|
||||||
verb="restore"
|
verb="restore"
|
||||||
order="recent"
|
order="recent"
|
||||||
activityMap={ self.state.activityMap }
|
|
||||||
selectedRoom={ self.props.selectedRoom }
|
selectedRoom={ self.props.selectedRoom }
|
||||||
incomingCall={ self.state.incomingCall }
|
incomingCall={ self.state.incomingCall }
|
||||||
collapsed={ self.props.collapsed } />
|
collapsed={ self.props.collapsed } />
|
||||||
|
@ -408,7 +374,6 @@ module.exports = React.createClass({
|
||||||
verb={ "tag as " + tagName }
|
verb={ "tag as " + tagName }
|
||||||
editable={ true }
|
editable={ true }
|
||||||
order="manual"
|
order="manual"
|
||||||
activityMap={ self.state.activityMap }
|
|
||||||
selectedRoom={ self.props.selectedRoom }
|
selectedRoom={ self.props.selectedRoom }
|
||||||
incomingCall={ self.state.incomingCall }
|
incomingCall={ self.state.incomingCall }
|
||||||
collapsed={ self.props.collapsed } />
|
collapsed={ self.props.collapsed } />
|
||||||
|
@ -422,7 +387,6 @@ module.exports = React.createClass({
|
||||||
verb="demote"
|
verb="demote"
|
||||||
editable={ true }
|
editable={ true }
|
||||||
order="recent"
|
order="recent"
|
||||||
activityMap={ self.state.activityMap }
|
|
||||||
selectedRoom={ self.props.selectedRoom }
|
selectedRoom={ self.props.selectedRoom }
|
||||||
incomingCall={ self.state.incomingCall }
|
incomingCall={ self.state.incomingCall }
|
||||||
collapsed={ self.props.collapsed } />
|
collapsed={ self.props.collapsed } />
|
||||||
|
@ -431,7 +395,6 @@ module.exports = React.createClass({
|
||||||
label="Historical"
|
label="Historical"
|
||||||
editable={ false }
|
editable={ false }
|
||||||
order="recent"
|
order="recent"
|
||||||
activityMap={ self.state.activityMap }
|
|
||||||
selectedRoom={ self.props.selectedRoom }
|
selectedRoom={ self.props.selectedRoom }
|
||||||
collapsed={ self.props.collapsed }
|
collapsed={ self.props.collapsed }
|
||||||
alwaysShowHeader={ true }
|
alwaysShowHeader={ true }
|
||||||
|
|
Loading…
Reference in New Issue