@@ -35,6 +35,7 @@ import { EffectiveMembership, getEffectiveMembership, splitRoomsByMembership } f
3535import { OrderingAlgorithm } from "./list-ordering/OrderingAlgorithm" ;
3636import { getListAlgorithmInstance } from "./list-ordering" ;
3737import { VisibilityProvider } from "../filters/VisibilityProvider" ;
38+ import VideoChannelStore , { VideoChannelEvent } from "../../VideoChannelStore" ;
3839
3940/**
4041 * Fired when the Algorithm has determined a list has been updated.
@@ -84,8 +85,14 @@ export class Algorithm extends EventEmitter {
8485 */
8586 public updatesInhibited = false ;
8687
87- public constructor ( ) {
88- super ( ) ;
88+ public start ( ) {
89+ VideoChannelStore . instance . on ( VideoChannelEvent . Connect , this . updateVideoRoom ) ;
90+ VideoChannelStore . instance . on ( VideoChannelEvent . Disconnect , this . updateVideoRoom ) ;
91+ }
92+
93+ public stop ( ) {
94+ VideoChannelStore . instance . off ( VideoChannelEvent . Connect , this . updateVideoRoom ) ;
95+ VideoChannelStore . instance . off ( VideoChannelEvent . Disconnect , this . updateVideoRoom ) ;
8996 }
9097
9198 public get stickyRoom ( ) : Room {
@@ -108,6 +115,7 @@ export class Algorithm extends EventEmitter {
108115 this . _cachedRooms = val ;
109116 this . recalculateFilteredRooms ( ) ;
110117 this . recalculateStickyRoom ( ) ;
118+ this . recalculateVideoRoom ( ) ;
111119 }
112120
113121 protected get cachedRooms ( ) : ITagMap {
@@ -145,6 +153,7 @@ export class Algorithm extends EventEmitter {
145153 this . _cachedRooms [ tagId ] = algorithm . orderedRooms ;
146154 this . recalculateFilteredRoomsForTag ( tagId ) ; // update filter to re-sort the list
147155 this . recalculateStickyRoom ( tagId ) ; // update sticky room to make sure it appears if needed
156+ this . recalculateVideoRoom ( tagId ) ;
148157 }
149158
150159 public getListOrdering ( tagId : TagID ) : ListAlgorithm {
@@ -164,6 +173,7 @@ export class Algorithm extends EventEmitter {
164173 this . _cachedRooms [ tagId ] = algorithm . orderedRooms ;
165174 this . recalculateFilteredRoomsForTag ( tagId ) ; // update filter to re-sort the list
166175 this . recalculateStickyRoom ( tagId ) ; // update sticky room to make sure it appears if needed
176+ this . recalculateVideoRoom ( tagId ) ;
167177 }
168178
169179 public addFilterCondition ( filterCondition : IFilterCondition ) : void {
@@ -311,12 +321,30 @@ export class Algorithm extends EventEmitter {
311321 this . recalculateFilteredRoomsForTag ( tag ) ;
312322 if ( lastStickyRoom && lastStickyRoom . tag !== tag ) this . recalculateFilteredRoomsForTag ( lastStickyRoom . tag ) ;
313323 this . recalculateStickyRoom ( ) ;
324+ this . recalculateVideoRoom ( tag ) ;
325+ if ( lastStickyRoom && lastStickyRoom . tag !== tag ) this . recalculateVideoRoom ( lastStickyRoom . tag ) ;
314326
315327 // Finally, trigger an update
316328 if ( this . updatesInhibited ) return ;
317329 this . emit ( LIST_UPDATED_EVENT ) ;
318330 }
319331
332+ /**
333+ * Update the stickiness of video rooms.
334+ */
335+ public updateVideoRoom = ( ) => {
336+ // In case we're unsticking a video room, sort it back into natural order
337+ this . recalculateFilteredRooms ( ) ;
338+ this . recalculateStickyRoom ( ) ;
339+
340+ this . recalculateVideoRoom ( ) ;
341+
342+ if ( this . updatesInhibited ) return ;
343+ // This isn't in response to any particular RoomListStore update,
344+ // so notify the store that it needs to force-update
345+ this . emit ( LIST_UPDATED_EVENT , true ) ;
346+ } ;
347+
320348 protected recalculateFilteredRooms ( ) {
321349 if ( ! this . hasFilters ) {
322350 return ;
@@ -374,6 +402,13 @@ export class Algorithm extends EventEmitter {
374402 }
375403 }
376404
405+ private initCachedStickyRooms ( ) {
406+ this . _cachedStickyRooms = { } ;
407+ for ( const tagId of Object . keys ( this . cachedRooms ) ) {
408+ this . _cachedStickyRooms [ tagId ] = [ ...this . cachedRooms [ tagId ] ] ; // shallow clone
409+ }
410+ }
411+
377412 /**
378413 * Recalculate the sticky room position. If this is being called in relation to
379414 * a specific tag being updated, it should be given to this function to optimize
@@ -400,17 +435,13 @@ export class Algorithm extends EventEmitter {
400435 }
401436
402437 if ( ! this . _cachedStickyRooms || ! updatedTag ) {
403- const stickiedTagMap : ITagMap = { } ;
404- for ( const tagId of Object . keys ( this . cachedRooms ) ) {
405- stickiedTagMap [ tagId ] = this . cachedRooms [ tagId ] . map ( r => r ) ; // shallow clone
406- }
407- this . _cachedStickyRooms = stickiedTagMap ;
438+ this . initCachedStickyRooms ( ) ;
408439 }
409440
410441 if ( updatedTag ) {
411442 // Update the tag indicated by the caller, if possible. This is mostly to ensure
412443 // our cache is up to date.
413- this . _cachedStickyRooms [ updatedTag ] = this . cachedRooms [ updatedTag ] . map ( r => r ) ; // shallow clone
444+ this . _cachedStickyRooms [ updatedTag ] = [ ... this . cachedRooms [ updatedTag ] ] ; // shallow clone
414445 }
415446
416447 // Now try to insert the sticky room, if we need to.
@@ -426,6 +457,46 @@ export class Algorithm extends EventEmitter {
426457 this . emit ( LIST_UPDATED_EVENT ) ;
427458 }
428459
460+ /**
461+ * Recalculate the position of any video rooms. If this is being called in relation to
462+ * a specific tag being updated, it should be given to this function to optimize
463+ * the call.
464+ *
465+ * This expects to be called *after* the sticky rooms are updated, and sticks the
466+ * currently connected video room to the top of its tag.
467+ *
468+ * @param updatedTag The tag that was updated, if possible.
469+ */
470+ protected recalculateVideoRoom ( updatedTag : TagID = null ) : void {
471+ if ( ! updatedTag ) {
472+ // Assume all tags need updating
473+ // We're not modifying the map here, so can safely rely on the cached values
474+ // rather than the explicitly sticky map.
475+ for ( const tagId of Object . keys ( this . cachedRooms ) ) {
476+ if ( ! tagId ) {
477+ throw new Error ( "Unexpected recursion: falsy tag" ) ;
478+ }
479+ this . recalculateVideoRoom ( tagId ) ;
480+ }
481+ return ;
482+ }
483+
484+ const videoRoomId = VideoChannelStore . instance . connected ? VideoChannelStore . instance . roomId : null ;
485+
486+ if ( videoRoomId ) {
487+ // We operate directly on the sticky rooms map
488+ if ( ! this . _cachedStickyRooms ) this . initCachedStickyRooms ( ) ;
489+ const rooms = this . _cachedStickyRooms [ updatedTag ] ;
490+ const videoRoomIdxInTag = rooms . findIndex ( r => r . roomId === videoRoomId ) ;
491+ if ( videoRoomIdxInTag < 0 ) return ; // no-op
492+
493+ const videoRoom = rooms [ videoRoomIdxInTag ] ;
494+ rooms . splice ( videoRoomIdxInTag , 1 ) ;
495+ rooms . unshift ( videoRoom ) ;
496+ this . _cachedStickyRooms [ updatedTag ] = rooms ; // re-set because references aren't always safe
497+ }
498+ }
499+
429500 /**
430501 * Asks the Algorithm to regenerate all lists, using the tags given
431502 * as reference for which lists to generate and which way to generate
@@ -706,6 +777,7 @@ export class Algorithm extends EventEmitter {
706777 this . _cachedRooms [ rmTag ] = algorithm . orderedRooms ;
707778 this . recalculateFilteredRoomsForTag ( rmTag ) ; // update filter to re-sort the list
708779 this . recalculateStickyRoom ( rmTag ) ; // update sticky room to make sure it moves if needed
780+ this . recalculateVideoRoom ( rmTag ) ;
709781 }
710782 for ( const addTag of diff . added ) {
711783 const algorithm : OrderingAlgorithm = this . algorithms [ addTag ] ;
@@ -782,6 +854,7 @@ export class Algorithm extends EventEmitter {
782854 // Flag that we've done something
783855 this . recalculateFilteredRoomsForTag ( tag ) ; // update filter to re-sort the list
784856 this . recalculateStickyRoom ( tag ) ; // update sticky room to make sure it appears if needed
857+ this . recalculateVideoRoom ( tag ) ;
785858 changed = true ;
786859 }
787860
0 commit comments