From 94a0a904574ba3e63bf80dffc381db2f20842747 Mon Sep 17 00:00:00 2001 From: Luke Barnard Date: Fri, 16 Feb 2018 14:16:50 +0000 Subject: [PATCH 1/3] Make RoomListStore aware of Room.timeline events so that we can do reorderings of lists ordered by most recent event. No optimisations here; we only update for timeline events on live timelines that could update the "unread count". --- src/actions/MatrixActionCreators.js | 10 ++++++ src/components/views/rooms/RoomList.js | 9 ------ src/stores/RoomListStore.js | 43 +++++++++++++++++--------- 3 files changed, 39 insertions(+), 23 deletions(-) diff --git a/src/actions/MatrixActionCreators.js b/src/actions/MatrixActionCreators.js index dbfe910533..27fbb6dda5 100644 --- a/src/actions/MatrixActionCreators.js +++ b/src/actions/MatrixActionCreators.js @@ -66,6 +66,15 @@ function createRoomTagsAction(matrixClient, roomTagsEvent, room) { return { action: 'MatrixActions.Room.tags', room }; } +function createRoomTimelineAction(matrixClient, timelineEvent, room, toStartOfTimeline, removed, data) { + return { + action: 'MatrixActions.Room.timeline', + event: timelineEvent, + isLiveEvent: data.liveEvent, + room, + }; +} + function createRoomMembershipAction(matrixClient, membershipEvent, member, oldMembership) { return { action: 'MatrixActions.RoomMember.membership', member }; } @@ -87,6 +96,7 @@ export default { this._addMatrixClientListener(matrixClient, 'sync', createSyncAction); this._addMatrixClientListener(matrixClient, 'accountData', createAccountDataAction); this._addMatrixClientListener(matrixClient, 'Room.tags', createRoomTagsAction); + this._addMatrixClientListener(matrixClient, 'Room.timeline', createRoomTimelineAction); this._addMatrixClientListener(matrixClient, 'RoomMember.membership', createRoomMembershipAction); }, diff --git a/src/components/views/rooms/RoomList.js b/src/components/views/rooms/RoomList.js index 41a200420d..bab8054c60 100644 --- a/src/components/views/rooms/RoomList.js +++ b/src/components/views/rooms/RoomList.js @@ -76,7 +76,6 @@ module.exports = React.createClass({ cli.on("Room", this.onRoom); cli.on("deleteRoom", this.onDeleteRoom); - cli.on("Room.timeline", this.onRoomTimeline); cli.on("Room.name", this.onRoomName); cli.on("Room.receipt", this.onRoomReceipt); cli.on("RoomState.events", this.onRoomStateEvents); @@ -177,7 +176,6 @@ module.exports = React.createClass({ if (MatrixClientPeg.get()) { MatrixClientPeg.get().removeListener("Room", this.onRoom); MatrixClientPeg.get().removeListener("deleteRoom", this.onDeleteRoom); - MatrixClientPeg.get().removeListener("Room.timeline", this.onRoomTimeline); MatrixClientPeg.get().removeListener("Room.name", this.onRoomName); MatrixClientPeg.get().removeListener("Room.receipt", this.onRoomReceipt); MatrixClientPeg.get().removeListener("RoomState.events", this.onRoomStateEvents); @@ -236,13 +234,6 @@ module.exports = React.createClass({ this._updateStickyHeaders(true, scrollToPosition); }, - onRoomTimeline: function(ev, room, toStartOfTimeline, removed, data) { - if (toStartOfTimeline) return; - if (!room) return; - if (data.timeline.getTimelineSet() !== room.getUnfilteredTimelineSet()) return; - this._delayedRefreshRoomList(); - }, - onRoomReceipt: function(receiptEvent, room) { // because if we read a notification, it will affect notification count // only bother updating if there's a receipt from us diff --git a/src/stores/RoomListStore.js b/src/stores/RoomListStore.js index fdd9ca6692..707a9da17e 100644 --- a/src/stores/RoomListStore.js +++ b/src/stores/RoomListStore.js @@ -23,6 +23,16 @@ import Unread from '../Unread'; * the RoomList. */ class RoomListStore extends Store { + + static _listOrders = { + "m.favourite": "manual", + "im.vector.fake.invite": "recent", + "im.vector.fake.recent": "recent", + "im.vector.fake.direct": "recent", + "m.lowpriority": "recent", + "im.vector.fake.archived": "recent", + }; + constructor() { super(dis); @@ -68,6 +78,14 @@ class RoomListStore extends Store { this._generateRoomLists(); } break; + case 'MatrixActions.Room.timeline': { + if (!this._state.ready || + !payload.isLiveEvent || + !this._eventTriggersRecentReorder(payload.event) + ) break; + this._generateRoomLists(); + } + break; case 'MatrixActions.accountData': { if (payload.event_type !== 'm.direct') break; this._generateRoomLists(); @@ -159,18 +177,9 @@ class RoomListStore extends Store { } }); - const listOrders = { - "m.favourite": "manual", - "im.vector.fake.invite": "recent", - "im.vector.fake.recent": "recent", - "im.vector.fake.direct": "recent", - "m.lowpriority": "recent", - "im.vector.fake.archived": "recent", - }; - Object.keys(lists).forEach((listKey) => { let comparator; - switch (listOrders[listKey]) { + switch (RoomListStore._listOrders[listKey]) { case "recent": comparator = this._recentsComparator; break; @@ -188,13 +197,17 @@ class RoomListStore extends Store { }); } + _eventTriggersRecentReorder(ev) { + return ev.getTs() && ( + Unread.eventTriggersUnreadCount(ev) || + ev.getSender() === this._matrixClient.credentials.userId + ); + } + _tsOfNewestEvent(room) { for (let i = room.timeline.length - 1; i >= 0; --i) { const ev = room.timeline[i]; - if (ev.getTs() && - (Unread.eventTriggersUnreadCount(ev) || - (ev.getSender() === this._matrixClient.credentials.userId)) - ) { + if (this._eventTriggersRecentReorder(ev)) { return ev.getTs(); } } @@ -210,6 +223,8 @@ class RoomListStore extends Store { } _recentsComparator(roomA, roomB) { + // XXX: We could use a cache here and update it when we see new + // events that trigger a reorder return this._tsOfNewestEvent(roomB) - this._tsOfNewestEvent(roomA); } From 3f6c15506c4116cb7bbe016c167d8d759842ab1f Mon Sep 17 00:00:00 2001 From: Luke Barnard Date: Fri, 16 Feb 2018 16:17:47 +0000 Subject: [PATCH 2/3] Remove unused `room` parameter of MatrixActions.Room.timeline --- src/actions/MatrixActionCreators.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/actions/MatrixActionCreators.js b/src/actions/MatrixActionCreators.js index 27fbb6dda5..a9ea671fbe 100644 --- a/src/actions/MatrixActionCreators.js +++ b/src/actions/MatrixActionCreators.js @@ -71,7 +71,6 @@ function createRoomTimelineAction(matrixClient, timelineEvent, room, toStartOfTi action: 'MatrixActions.Room.timeline', event: timelineEvent, isLiveEvent: data.liveEvent, - room, }; } From 32130fbc28bc315adae9cd88bc19226f9ff121a6 Mon Sep 17 00:00:00 2001 From: Luke Barnard Date: Mon, 19 Feb 2018 09:56:03 +0000 Subject: [PATCH 3/3] Don't regenerate RoomListStore state for notifs/scrollback/etc. Only do so for the live timeline of rooms. --- src/actions/MatrixActionCreators.js | 2 ++ src/stores/RoomListStore.js | 1 + 2 files changed, 3 insertions(+) diff --git a/src/actions/MatrixActionCreators.js b/src/actions/MatrixActionCreators.js index a9ea671fbe..a307af6f57 100644 --- a/src/actions/MatrixActionCreators.js +++ b/src/actions/MatrixActionCreators.js @@ -71,6 +71,8 @@ function createRoomTimelineAction(matrixClient, timelineEvent, room, toStartOfTi action: 'MatrixActions.Room.timeline', event: timelineEvent, isLiveEvent: data.liveEvent, + isLiveUnfilteredRoomTimelineEvent: + room && data.timeline.getTimelineSet() === room.getUnfilteredTimelineSet(), }; } diff --git a/src/stores/RoomListStore.js b/src/stores/RoomListStore.js index 707a9da17e..8a3af309fc 100644 --- a/src/stores/RoomListStore.js +++ b/src/stores/RoomListStore.js @@ -81,6 +81,7 @@ class RoomListStore extends Store { case 'MatrixActions.Room.timeline': { if (!this._state.ready || !payload.isLiveEvent || + !payload.isLiveUnfilteredRoomTimelineEvent || !this._eventTriggersRecentReorder(payload.event) ) break; this._generateRoomLists();