@@ -21,79 +21,83 @@ import { MatrixClientPeg } from "../../../../MatrixClientPeg";
21
21
import * as Unread from "../../../../Unread" ;
22
22
import { EffectiveMembership , getEffectiveMembership } from "../../../../utils/membership" ;
23
23
24
- /**
25
- * Sorts rooms according to the last event's timestamp in each room that seems
26
- * useful to the user.
27
- */
28
- export class RecentAlgorithm implements IAlgorithm {
29
- public async sortRooms ( rooms : Room [ ] , tagId : TagID ) : Promise < Room [ ] > {
30
- // We cache the timestamp lookup to avoid iterating forever on the timeline
31
- // of events. This cache only survives a single sort though.
32
- // We wouldn't need this if `.sort()` didn't constantly try and compare all
33
- // of the rooms to each other.
34
-
35
- // TODO: We could probably improve the sorting algorithm here by finding changes.
36
- // See https://github.com/vector-im/element-web/issues/14459
37
- // For example, if we spent a little bit of time to determine which elements have
38
- // actually changed (probably needs to be done higher up?) then we could do an
39
- // insertion sort or similar on the limited set of changes.
40
-
41
- // TODO: Don't assume we're using the same client as the peg
42
- // See https://github.com/vector-im/element-web/issues/14458
43
- let myUserId = '' ;
44
- if ( MatrixClientPeg . get ( ) ) {
45
- myUserId = MatrixClientPeg . get ( ) . getUserId ( ) ;
24
+ export const sortRooms = ( rooms : Room [ ] ) : Room [ ] => {
25
+ // We cache the timestamp lookup to avoid iterating forever on the timeline
26
+ // of events. This cache only survives a single sort though.
27
+ // We wouldn't need this if `.sort()` didn't constantly try and compare all
28
+ // of the rooms to each other.
29
+
30
+ // TODO: We could probably improve the sorting algorithm here by finding changes.
31
+ // See https://github.com/vector-im/element-web/issues/14459
32
+ // For example, if we spent a little bit of time to determine which elements have
33
+ // actually changed (probably needs to be done higher up?) then we could do an
34
+ // insertion sort or similar on the limited set of changes.
35
+
36
+ // TODO: Don't assume we're using the same client as the peg
37
+ // See https://github.com/vector-im/element-web/issues/14458
38
+ let myUserId = '' ;
39
+ if ( MatrixClientPeg . get ( ) ) {
40
+ myUserId = MatrixClientPeg . get ( ) . getUserId ( ) ;
41
+ }
42
+
43
+ const tsCache : { [ roomId : string ] : number } = { } ;
44
+ const getLastTs = ( r : Room ) => {
45
+ if ( tsCache [ r . roomId ] ) {
46
+ return tsCache [ r . roomId ] ;
46
47
}
47
48
48
- const tsCache : { [ roomId : string ] : number } = { } ;
49
- const getLastTs = ( r : Room ) => {
50
- if ( tsCache [ r . roomId ] ) {
51
- return tsCache [ r . roomId ] ;
49
+ const ts = ( ( ) => {
50
+ // Apparently we can have rooms without timelines, at least under testing
51
+ // environments. Just return MAX_INT when this happens.
52
+ if ( ! r || ! r . timeline ) {
53
+ return Number . MAX_SAFE_INTEGER ;
52
54
}
53
55
54
- const ts = ( ( ) => {
55
- // Apparently we can have rooms without timelines, at least under testing
56
- // environments. Just return MAX_INT when this happens.
57
- if ( ! r || ! r . timeline ) {
58
- return Number . MAX_SAFE_INTEGER ;
59
- }
60
-
61
- // If the room hasn't been joined yet, it probably won't have a timeline to
62
- // parse. We'll still fall back to the timeline if this fails, but chances
63
- // are we'll at least have our own membership event to go off of.
64
- const effectiveMembership = getEffectiveMembership ( r . getMyMembership ( ) ) ;
65
- if ( effectiveMembership !== EffectiveMembership . Join ) {
66
- const membershipEvent = r . currentState . getStateEvents ( "m.room.member" , myUserId ) ;
67
- if ( membershipEvent && ! Array . isArray ( membershipEvent ) ) {
68
- return membershipEvent . getTs ( ) ;
69
- }
56
+ // If the room hasn't been joined yet, it probably won't have a timeline to
57
+ // parse. We'll still fall back to the timeline if this fails, but chances
58
+ // are we'll at least have our own membership event to go off of.
59
+ const effectiveMembership = getEffectiveMembership ( r . getMyMembership ( ) ) ;
60
+ if ( effectiveMembership !== EffectiveMembership . Join ) {
61
+ const membershipEvent = r . currentState . getStateEvents ( "m.room.member" , myUserId ) ;
62
+ if ( membershipEvent && ! Array . isArray ( membershipEvent ) ) {
63
+ return membershipEvent . getTs ( ) ;
70
64
}
65
+ }
71
66
72
- for ( let i = r . timeline . length - 1 ; i >= 0 ; -- i ) {
73
- const ev = r . timeline [ i ] ;
74
- if ( ! ev . getTs ( ) ) continue ; // skip events that don't have timestamps (tests only?)
67
+ for ( let i = r . timeline . length - 1 ; i >= 0 ; -- i ) {
68
+ const ev = r . timeline [ i ] ;
69
+ if ( ! ev . getTs ( ) ) continue ; // skip events that don't have timestamps (tests only?)
75
70
76
- if ( ev . getSender ( ) === myUserId || Unread . eventTriggersUnreadCount ( ev ) ) {
77
- return ev . getTs ( ) ;
78
- }
71
+ if ( ev . getSender ( ) === myUserId || Unread . eventTriggersUnreadCount ( ev ) ) {
72
+ return ev . getTs ( ) ;
79
73
}
74
+ }
80
75
81
- // we might only have events that don't trigger the unread indicator,
82
- // in which case use the oldest event even if normally it wouldn't count.
83
- // This is better than just assuming the last event was forever ago.
84
- if ( r . timeline . length && r . timeline [ 0 ] . getTs ( ) ) {
85
- return r . timeline [ 0 ] . getTs ( ) ;
86
- } else {
87
- return Number . MAX_SAFE_INTEGER ;
88
- }
89
- } ) ( ) ;
76
+ // we might only have events that don't trigger the unread indicator,
77
+ // in which case use the oldest event even if normally it wouldn't count.
78
+ // This is better than just assuming the last event was forever ago.
79
+ if ( r . timeline . length && r . timeline [ 0 ] . getTs ( ) ) {
80
+ return r . timeline [ 0 ] . getTs ( ) ;
81
+ } else {
82
+ return Number . MAX_SAFE_INTEGER ;
83
+ }
84
+ } ) ( ) ;
85
+
86
+ tsCache [ r . roomId ] = ts ;
87
+ return ts ;
88
+ } ;
90
89
91
- tsCache [ r . roomId ] = ts ;
92
- return ts ;
93
- } ;
90
+ return rooms . sort ( ( a , b ) => {
91
+ return getLastTs ( b ) - getLastTs ( a ) ;
92
+ } ) ;
93
+ } ;
94
94
95
- return rooms . sort ( ( a , b ) => {
96
- return getLastTs ( b ) - getLastTs ( a ) ;
97
- } ) ;
95
+ /**
96
+ * Sorts rooms according to the last event's timestamp in each room that seems
97
+ * useful to the user.
98
+ */
99
+ export class RecentAlgorithm implements IAlgorithm {
100
+ public async sortRooms ( rooms : Room [ ] , tagId : TagID ) : Promise < Room [ ] > {
101
+ return sortRooms ( rooms ) ;
98
102
}
99
103
}
0 commit comments