@@ -30,7 +30,7 @@ import {
3030 SortAlgorithm
3131} from "./models" ;
3232import { FILTER_CHANGED , FilterPriority , IFilterCondition } from "../filters/IFilterCondition" ;
33- import { EffectiveMembership , splitRoomsByMembership } from "../membership" ;
33+ import { EffectiveMembership , getEffectiveMembership , splitRoomsByMembership } from "../membership" ;
3434import { OrderingAlgorithm } from "./list-ordering/OrderingAlgorithm" ;
3535import { getListAlgorithmInstance } from "./list-ordering" ;
3636
@@ -99,6 +99,14 @@ export class Algorithm extends EventEmitter {
9999 return this . _cachedRooms ;
100100 }
101101
102+ /**
103+ * Awaitable version of the sticky room setter.
104+ * @param val The new room to sticky.
105+ */
106+ public async setStickyRoomAsync ( val : Room ) {
107+ await this . updateStickyRoom ( val ) ;
108+ }
109+
102110 public getTagSorting ( tagId : TagID ) : SortAlgorithm {
103111 return this . sortAlgorithms [ tagId ] ;
104112 }
@@ -160,10 +168,13 @@ export class Algorithm extends EventEmitter {
160168 // It's possible to have no selected room. In that case, clear the sticky room
161169 if ( ! val ) {
162170 if ( this . _stickyRoom ) {
171+ const stickyRoom = this . _stickyRoom . room ;
172+ this . _stickyRoom = null ; // clear before we go to update the algorithm
173+
163174 // Lie to the algorithm and re-add the room to the algorithm
164- await this . handleRoomUpdate ( this . _stickyRoom . room , RoomUpdateCause . NewRoom ) ;
175+ await this . handleRoomUpdate ( stickyRoom , RoomUpdateCause . NewRoom ) ;
176+ return ;
165177 }
166- this . _stickyRoom = null ;
167178 return ;
168179 }
169180
@@ -289,6 +300,8 @@ export class Algorithm extends EventEmitter {
289300 }
290301
291302 protected recalculateFilteredRoomsForTag ( tagId : TagID ) : void {
303+ if ( ! this . hasFilters ) return ; // don't bother doing work if there's nothing to do
304+
292305 console . log ( `Recalculating filtered rooms for ${ tagId } ` ) ;
293306 delete this . filteredRooms [ tagId ] ;
294307 const rooms = this . cachedRooms [ tagId ] . map ( r => r ) ; // cheap clone
@@ -428,6 +441,13 @@ export class Algorithm extends EventEmitter {
428441 if ( isNullOrUndefined ( rooms ) ) throw new Error ( `Array of rooms cannot be null` ) ;
429442 if ( ! this . sortAlgorithms ) throw new Error ( `Cannot set known rooms without a tag sorting map` ) ;
430443
444+ console . warn ( "Resetting known rooms, initiating regeneration" ) ;
445+
446+ // Before we go any further we need to clear (but remember) the sticky room to
447+ // avoid accidentally duplicating it in the list.
448+ const oldStickyRoom = this . _stickyRoom ;
449+ await this . updateStickyRoom ( null ) ;
450+
431451 this . rooms = rooms ;
432452
433453 const newTags : ITagMap = { } ;
@@ -458,14 +478,7 @@ export class Algorithm extends EventEmitter {
458478
459479 // Now process all the joined rooms. This is a bit more complicated
460480 for ( const room of memberships [ EffectiveMembership . Join ] ) {
461- let tags = Object . keys ( room . tags || { } ) ;
462-
463- if ( tags . length === 0 ) {
464- // Check to see if it's a DM if it isn't anything else
465- if ( DMRoomMap . shared ( ) . getUserIdForRoomId ( room . roomId ) ) {
466- tags = [ DefaultTagID . DM ] ;
467- }
468- }
481+ const tags = this . getTagsOfJoinedRoom ( room ) ;
469482
470483 let inTag = false ;
471484 if ( tags . length > 0 ) {
@@ -494,6 +507,54 @@ export class Algorithm extends EventEmitter {
494507
495508 this . cachedRooms = newTags ;
496509 this . updateTagsFromCache ( ) ;
510+ this . recalculateFilteredRooms ( ) ;
511+
512+ // Now that we've finished generation, we need to update the sticky room to what
513+ // it was. It's entirely possible that it changed lists though, so if it did then
514+ // we also have to update the position of it.
515+ if ( oldStickyRoom && oldStickyRoom . room ) {
516+ await this . updateStickyRoom ( oldStickyRoom . room ) ;
517+ if ( this . _stickyRoom && this . _stickyRoom . room ) { // just in case the update doesn't go according to plan
518+ if ( this . _stickyRoom . tag !== oldStickyRoom . tag ) {
519+ // We put the sticky room at the top of the list to treat it as an obvious tag change.
520+ this . _stickyRoom . position = 0 ;
521+ this . recalculateStickyRoom ( this . _stickyRoom . tag ) ;
522+ }
523+ }
524+ }
525+ }
526+
527+ private getTagsForRoom ( room : Room ) : TagID [ ] {
528+ // XXX: This duplicates a lot of logic from setKnownRooms above, but has a slightly
529+ // different use case and therefore different performance curve
530+
531+ const tags : TagID [ ] = [ ] ;
532+
533+ const membership = getEffectiveMembership ( room . getMyMembership ( ) ) ;
534+ if ( membership === EffectiveMembership . Invite ) {
535+ tags . push ( DefaultTagID . Invite ) ;
536+ } else if ( membership === EffectiveMembership . Leave ) {
537+ tags . push ( DefaultTagID . Archived ) ;
538+ } else {
539+ tags . push ( ...this . getTagsOfJoinedRoom ( room ) ) ;
540+ }
541+
542+ if ( ! tags . length ) tags . push ( DefaultTagID . Untagged ) ;
543+
544+ return tags ;
545+ }
546+
547+ private getTagsOfJoinedRoom ( room : Room ) : TagID [ ] {
548+ let tags = Object . keys ( room . tags || { } ) ;
549+
550+ if ( tags . length === 0 ) {
551+ // Check to see if it's a DM if it isn't anything else
552+ if ( DMRoomMap . shared ( ) . getUserIdForRoomId ( room . roomId ) ) {
553+ tags = [ DefaultTagID . DM ] ;
554+ }
555+ }
556+
557+ return tags ;
497558 }
498559
499560 /**
@@ -548,6 +609,14 @@ export class Algorithm extends EventEmitter {
548609 public async handleRoomUpdate ( room : Room , cause : RoomUpdateCause ) : Promise < boolean > {
549610 if ( ! this . algorithms ) throw new Error ( "Not ready: no algorithms to determine tags from" ) ;
550611
612+ if ( cause === RoomUpdateCause . NewRoom ) {
613+ const roomTags = this . roomIdsToTags [ room . roomId ] ;
614+ if ( roomTags && roomTags . length > 0 ) {
615+ console . warn ( `${ room . roomId } is reportedly new but is already known - assuming TagChange instead` ) ;
616+ cause = RoomUpdateCause . PossibleTagChange ;
617+ }
618+ }
619+
551620 if ( cause === RoomUpdateCause . PossibleTagChange ) {
552621 // TODO: Be smarter and splice rather than regen the planet. https://github.com/vector-im/riot-web/issues/14035
553622 // TODO: No-op if no change. https://github.com/vector-im/riot-web/issues/14035
@@ -566,6 +635,19 @@ export class Algorithm extends EventEmitter {
566635 }
567636 }
568637
638+ if ( cause === RoomUpdateCause . NewRoom && ! this . roomIdsToTags [ room . roomId ] ) {
639+ console . log ( `[RoomListDebug] Updating tags for new room ${ room . roomId } (${ room . name } )` ) ;
640+
641+ // Get the tags for the room and populate the cache
642+ const roomTags = this . getTagsForRoom ( room ) . filter ( t => ! isNullOrUndefined ( this . cachedRooms [ t ] ) ) ;
643+
644+ // "This should never happen" condition - we specify DefaultTagID.Untagged in getTagsForRoom(),
645+ // which means we should *always* have a tag to go off of.
646+ if ( ! roomTags . length ) throw new Error ( `Tags cannot be determined for ${ room . roomId } ` ) ;
647+
648+ this . roomIdsToTags [ room . roomId ] = roomTags ;
649+ }
650+
569651 let tags = this . roomIdsToTags [ room . roomId ] ;
570652 if ( ! tags ) {
571653 console . warn ( `No tags known for "${ room . name } " (${ room . roomId } )` ) ;
0 commit comments