@@ -54,6 +54,24 @@ class RoomListStore extends Store {
5454 "im.vector.fake.archived" : [ ] ,
5555 } ,
5656 ready : false ,
57+
58+ // The room cache stores a mapping of roomId to cache record.
59+ // Each cache record is a key/value pair for various bits of
60+ // data used to sort the room list. Currently this stores the
61+ // following bits of informations:
62+ // "timestamp": number, The timestamp of the last relevant
63+ // event in the room.
64+ // "notifications": boolean, Whether or not the user has been
65+ // highlighted on any unread events.
66+ // "unread": boolean, Whether or not the user has any
67+ // unread events.
68+ //
69+ // All of the cached values are lazily loaded on read in the
70+ // recents comparator. When an event is received for a particular
71+ // room, all the cached values are invalidated - forcing the
72+ // next read to set new values. The entries do not expire on
73+ // their own.
74+ roomCache : { } ,
5775 } ;
5876 }
5977
@@ -85,6 +103,8 @@ class RoomListStore extends Store {
85103 ! payload . isLiveUnfilteredRoomTimelineEvent ||
86104 ! this . _eventTriggersRecentReorder ( payload . event )
87105 ) break ;
106+
107+ this . _clearCachedRoomState ( payload . event . getRoomId ( ) ) ;
88108 this . _generateRoomLists ( ) ;
89109 }
90110 break ;
@@ -112,6 +132,8 @@ class RoomListStore extends Store {
112132 if ( liveTimeline !== eventTimeline ||
113133 ! this . _eventTriggersRecentReorder ( payload . event )
114134 ) break ;
135+
136+ this . _clearCachedRoomState ( payload . event . getRoomId ( ) ) ;
115137 this . _generateRoomLists ( ) ;
116138 }
117139 break ;
@@ -217,11 +239,18 @@ class RoomListStore extends Store {
217239 }
218240 } ) ;
219241
242+ // Note: we check the settings up here instead of in the forEach or
243+ // in the _recentsComparator to avoid hitting the SettingsStore a few
244+ // thousand times.
245+ const pinUnread = SettingsStore . getValue ( "pinUnreadRooms" ) ;
246+ const pinMentioned = SettingsStore . getValue ( "pinMentionedRooms" ) ;
220247 Object . keys ( lists ) . forEach ( ( listKey ) => {
221248 let comparator ;
222249 switch ( RoomListStore . _listOrders [ listKey ] ) {
223250 case "recent" :
224- comparator = this . _recentsComparator ;
251+ comparator = ( roomA , roomB ) => {
252+ return this . _recentsComparator ( roomA , roomB , pinUnread , pinMentioned ) ;
253+ } ;
225254 break ;
226255 case "manual" :
227256 default :
@@ -237,6 +266,44 @@ class RoomListStore extends Store {
237266 } ) ;
238267 }
239268
269+ _updateCachedRoomState ( roomId , type , value ) {
270+ const roomCache = this . _state . roomCache ;
271+ if ( ! roomCache [ roomId ] ) roomCache [ roomId ] = { } ;
272+
273+ if ( value ) roomCache [ roomId ] [ type ] = value ;
274+ else delete roomCache [ roomId ] [ type ] ;
275+
276+ this . _setState ( { roomCache} ) ;
277+ }
278+
279+ _clearCachedRoomState ( roomId ) {
280+ const roomCache = this . _state . roomCache ;
281+ delete roomCache [ roomId ] ;
282+ this . _setState ( { roomCache} ) ;
283+ }
284+
285+ _getRoomState ( room , type ) {
286+ const roomId = room . roomId ;
287+ const roomCache = this . _state . roomCache ;
288+ if ( roomCache [ roomId ] && typeof roomCache [ roomId ] [ type ] !== 'undefined' ) {
289+ return roomCache [ roomId ] [ type ] ;
290+ }
291+
292+ if ( type === "timestamp" ) {
293+ const ts = this . _tsOfNewestEvent ( room ) ;
294+ this . _updateCachedRoomState ( roomId , "timestamp" , ts ) ;
295+ return ts ;
296+ } else if ( type === "unread" ) {
297+ const unread = room . getUnreadNotificationCount ( ) > 0 ;
298+ this . _updateCachedRoomState ( roomId , "unread" , unread ) ;
299+ return unread ;
300+ } else if ( type === "notifications" ) {
301+ const notifs = room . getUnreadNotificationCount ( "highlight" ) > 0 ;
302+ this . _updateCachedRoomState ( roomId , "notifications" , notifs ) ;
303+ return notifs ;
304+ } else throw new Error ( "Unrecognized room cache type: " + type ) ;
305+ }
306+
240307 _eventTriggersRecentReorder ( ev ) {
241308 return ev . getTs ( ) && (
242309 Unread . eventTriggersUnreadCount ( ev ) ||
@@ -262,34 +329,40 @@ class RoomListStore extends Store {
262329 }
263330 }
264331
265- _recentsComparator ( roomA , roomB ) {
266- const pinUnread = SettingsStore . getValue ( "pinUnreadRooms" ) ;
267- const pinMentioned = SettingsStore . getValue ( "pinMentionedRooms" ) ;
268-
332+ _recentsComparator ( roomA , roomB , pinUnread , pinMentioned ) {
269333 // We try and set the ordering to be Mentioned > Unread > Recent
270- // assuming the user has the right settings, of course
334+ // assuming the user has the right settings, of course.
335+
336+ const timestampA = this . _getRoomState ( roomA , "timestamp" ) ;
337+ const timestampB = this . _getRoomState ( roomB , "timestamp" ) ;
338+ const timestampDiff = timestampB - timestampA ;
271339
272340 if ( pinMentioned ) {
273- const mentionsA = roomA . getUnreadNotificationCount ( "highlight" ) > 0 ;
274- const mentionsB = roomB . getUnreadNotificationCount ( "highlight" ) > 0 ;
275- if ( mentionsA && ! mentionsB ) return - 1 ;
276- if ( ! mentionsA && mentionsB ) return 1 ;
277- if ( mentionsA && mentionsB ) return 0 ;
278- // If neither have mentions, fall through to remaining checks
341+ const mentionsA = this . _getRoomState ( roomA , "notifications" ) ;
342+ const mentionsB = this . _getRoomState ( roomB , "notifications" ) ;
343+ if ( mentionsA && ! mentionsB ) return - 1 ;
344+ if ( ! mentionsA && mentionsB ) return 1 ;
345+
346+ // If they both have notifications, sort by timestamp.
347+ // If neither have notifications (the fourth check not shown
348+ // here), then try and sort by unread messages and finally by
349+ // timestamp.
350+ if ( mentionsA && mentionsB ) return timestampDiff ;
279351 }
280352
281353 if ( pinUnread ) {
282- const unreadA = Unread . doesRoomHaveUnreadMessages ( roomA ) ;
283- const unreadB = Unread . doesRoomHaveUnreadMessages ( roomB ) ;
354+ const unreadA = this . _getRoomState ( roomA , "unread" ) ;
355+ const unreadB = this . _getRoomState ( roomB , "unread" ) ;
284356 if ( unreadA && ! unreadB ) return - 1 ;
285357 if ( ! unreadA && unreadB ) return 1 ;
286- if ( unreadA && unreadB ) return 0 ;
287- // If neither have unread messages, fall through to remaining checks
358+
359+ // If they both have unread messages, sort by timestamp
360+ // If nether have unread message (the fourth check not shown
361+ // here), then just sort by timestamp anyways.
362+ if ( unreadA && unreadB ) return timestampDiff ;
288363 }
289364
290- // XXX: We could use a cache here and update it when we see new
291- // events that trigger a reorder
292- return this . _tsOfNewestEvent ( roomB ) - this . _tsOfNewestEvent ( roomA ) ;
365+ return timestampDiff ;
293366 }
294367
295368 _lexicographicalComparator ( roomA , roomB ) {
0 commit comments