@@ -17,7 +17,6 @@ limitations under the License.
17
17
*/
18
18
19
19
import React , { ReactNode } from "react" ;
20
- import { Store } from 'flux/utils' ;
21
20
import { MatrixError } from "matrix-js-sdk/src/http-api" ;
22
21
import { logger } from "matrix-js-sdk/src/logger" ;
23
22
import { ViewRoom as ViewRoomEvent } from "@matrix-org/analytics-events/types/typescript/ViewRoom" ;
@@ -26,13 +25,13 @@ import { JoinRule } from "matrix-js-sdk/src/@types/partials";
26
25
import { Room } from "matrix-js-sdk/src/models/room" ;
27
26
import { MatrixEvent } from "matrix-js-sdk/src/models/event" ;
28
27
import { Optional } from "matrix-events-sdk" ;
28
+ import EventEmitter from "events" ;
29
29
30
- import dis from '../dispatcher/dispatcher' ;
30
+ import { defaultDispatcher , MatrixDispatcher } from '../dispatcher/dispatcher' ;
31
31
import { MatrixClientPeg } from '../MatrixClientPeg' ;
32
32
import Modal from '../Modal' ;
33
33
import { _t } from '../languageHandler' ;
34
34
import { getCachedRoomIDForAlias , storeRoomAliasInCache } from '../RoomAliasCache' ;
35
- import { ActionPayload } from "../dispatcher/payloads" ;
36
35
import { Action } from "../dispatcher/actions" ;
37
36
import { retry } from "../utils/promise" ;
38
37
import { TimelineRenderingType } from "../contexts/RoomContext" ;
@@ -50,6 +49,7 @@ import { ActiveRoomChangedPayload } from "../dispatcher/payloads/ActiveRoomChang
50
49
import SettingsStore from "../settings/SettingsStore" ;
51
50
import { SlidingSyncManager } from "../SlidingSyncManager" ;
52
51
import { awaitRoomDownSync } from "../utils/RoomUpgrade" ;
52
+ import { UPDATE_EVENT } from "./AsyncStore" ;
53
53
54
54
const NUM_JOIN_RETRY = 5 ;
55
55
@@ -90,47 +90,34 @@ const INITIAL_STATE = {
90
90
type Listener = ( isActive : boolean ) => void ;
91
91
92
92
/**
93
- * A class for storing application state for RoomView. This is the RoomView's interface
94
- * with a subset of the js-sdk.
95
- * ```
93
+ * A class for storing application state for RoomView.
96
94
*/
97
- export class RoomViewStore extends Store < ActionPayload > {
95
+ export class RoomViewStore extends EventEmitter {
98
96
// Important: This cannot be a dynamic getter (lazily-constructed instance) because
99
97
// otherwise we'll miss view_room dispatches during startup, breaking relaunches of
100
98
// the app. We need to eagerly create the instance.
101
- public static readonly instance = new RoomViewStore ( ) ;
99
+ public static readonly instance = new RoomViewStore ( defaultDispatcher ) ;
102
100
103
101
private state = INITIAL_STATE ; // initialize state
104
102
105
- // Keep these out of state to avoid causing excessive/recursive updates
106
- private roomIdActivityListeners : Record < string , Listener [ ] > = { } ;
103
+ private dis : MatrixDispatcher ;
104
+ private dispatchToken : string ;
107
105
108
- public constructor ( ) {
109
- super ( dis ) ;
106
+ public constructor ( dis : MatrixDispatcher ) {
107
+ super ( ) ;
108
+ this . resetDispatcher ( dis ) ;
110
109
}
111
110
112
111
public addRoomListener ( roomId : string , fn : Listener ) : void {
113
- if ( ! this . roomIdActivityListeners [ roomId ] ) this . roomIdActivityListeners [ roomId ] = [ ] ;
114
- this . roomIdActivityListeners [ roomId ] . push ( fn ) ;
112
+ this . on ( roomId , fn ) ;
115
113
}
116
114
117
115
public removeRoomListener ( roomId : string , fn : Listener ) : void {
118
- if ( this . roomIdActivityListeners [ roomId ] ) {
119
- const i = this . roomIdActivityListeners [ roomId ] . indexOf ( fn ) ;
120
- if ( i > - 1 ) {
121
- this . roomIdActivityListeners [ roomId ] . splice ( i , 1 ) ;
122
- }
123
- } else {
124
- logger . warn ( "Unregistering unrecognised listener (roomId=" + roomId + ")" ) ;
125
- }
116
+ this . off ( roomId , fn ) ;
126
117
}
127
118
128
119
private emitForRoom ( roomId : string , isActive : boolean ) : void {
129
- if ( ! this . roomIdActivityListeners [ roomId ] ) return ;
130
-
131
- for ( const fn of this . roomIdActivityListeners [ roomId ] ) {
132
- fn . call ( null , isActive ) ;
133
- }
120
+ this . emit ( roomId , isActive ) ;
134
121
}
135
122
136
123
private setState ( newState : Partial < typeof INITIAL_STATE > ) : void {
@@ -156,17 +143,17 @@ export class RoomViewStore extends Store<ActionPayload> {
156
143
157
144
// Fired so we can reduce dependency on event emitters to this store, which is relatively
158
145
// central to the application and can easily cause import cycles.
159
- dis . dispatch < ActiveRoomChangedPayload > ( {
146
+ this . dis . dispatch < ActiveRoomChangedPayload > ( {
160
147
action : Action . ActiveRoomChanged ,
161
148
oldRoomId : lastRoomId ,
162
149
newRoomId : this . state . roomId ,
163
150
} ) ;
164
151
}
165
152
166
- this . __emitChange ( ) ;
153
+ this . emit ( UPDATE_EVENT ) ;
167
154
}
168
155
169
- protected __onDispatch ( payload ) : void { // eslint-disable-line @typescript-eslint/naming-convention
156
+ private onDispatch ( payload ) : void { // eslint-disable-line @typescript-eslint/naming-convention
170
157
switch ( payload . action ) {
171
158
// view_room:
172
159
// - room_alias: '#somealias:matrix.org'
@@ -243,7 +230,7 @@ export class RoomViewStore extends Store<ActionPayload> {
243
230
// both room and search timeline rendering types, search will get auto-closed by RoomView at this time.
244
231
if ( [ TimelineRenderingType . Room , TimelineRenderingType . Search ] . includes ( payload . context ) ) {
245
232
if ( payload . event && payload . event . getRoomId ( ) !== this . state . roomId ) {
246
- dis . dispatch < ViewRoomPayload > ( {
233
+ this . dis . dispatch < ViewRoomPayload > ( {
247
234
action : Action . ViewRoom ,
248
235
room_id : payload . event . getRoomId ( ) ,
249
236
replyingToEvent : payload . event ,
@@ -283,9 +270,9 @@ export class RoomViewStore extends Store<ActionPayload> {
283
270
} ) ;
284
271
}
285
272
if ( SettingsStore . getValue ( "feature_sliding_sync" ) && this . state . roomId !== payload . room_id ) {
286
- if ( this . state . roomId ) {
273
+ if ( this . state . subscribingRoomId && this . state . subscribingRoomId !== payload . room_id ) {
287
274
// unsubscribe from this room, but don't await it as we don't care when this gets done.
288
- SlidingSyncManager . instance . setRoomVisible ( this . state . roomId , false ) ;
275
+ SlidingSyncManager . instance . setRoomVisible ( this . state . subscribingRoomId , false ) ;
289
276
}
290
277
this . setState ( {
291
278
subscribingRoomId : payload . room_id ,
@@ -306,11 +293,11 @@ export class RoomViewStore extends Store<ActionPayload> {
306
293
// Whilst we were subscribing another room was viewed, so stop what we're doing and
307
294
// unsubscribe
308
295
if ( this . state . subscribingRoomId !== payload . room_id ) {
309
- SlidingSyncManager . instance . setRoomVisible ( this . state . roomId , false ) ;
296
+ SlidingSyncManager . instance . setRoomVisible ( payload . room_id , false ) ;
310
297
return ;
311
298
}
312
299
// Re-fire the payload: we won't re-process it because the prev room ID == payload room ID now
313
- dis . dispatch ( {
300
+ this . dis . dispatch ( {
314
301
...payload ,
315
302
} ) ;
316
303
return ;
@@ -346,7 +333,7 @@ export class RoomViewStore extends Store<ActionPayload> {
346
333
this . setState ( newState ) ;
347
334
348
335
if ( payload . auto_join ) {
349
- dis . dispatch < JoinRoomPayload > ( {
336
+ this . dis . dispatch < JoinRoomPayload > ( {
350
337
...payload ,
351
338
action : Action . JoinRoom ,
352
339
roomId : payload . room_id ,
@@ -378,7 +365,7 @@ export class RoomViewStore extends Store<ActionPayload> {
378
365
roomId = result . room_id ;
379
366
} catch ( err ) {
380
367
logger . error ( "RVS failed to get room id for alias: " , err ) ;
381
- dis . dispatch < ViewRoomErrorPayload > ( {
368
+ this . dis . dispatch < ViewRoomErrorPayload > ( {
382
369
action : Action . ViewRoomError ,
383
370
room_id : null ,
384
371
room_alias : payload . room_alias ,
@@ -389,7 +376,7 @@ export class RoomViewStore extends Store<ActionPayload> {
389
376
}
390
377
391
378
// Re-fire the payload with the newly found room_id
392
- dis . dispatch ( {
379
+ this . dis . dispatch ( {
393
380
...payload ,
394
381
room_id : roomId ,
395
382
} ) ;
@@ -427,13 +414,13 @@ export class RoomViewStore extends Store<ActionPayload> {
427
414
// We do *not* clear the 'joining' flag because the Room object and/or our 'joined' member event may not
428
415
// have come down the sync stream yet, and that's the point at which we'd consider the user joined to the
429
416
// room.
430
- dis . dispatch < JoinRoomReadyPayload > ( {
417
+ this . dis . dispatch < JoinRoomReadyPayload > ( {
431
418
action : Action . JoinRoomReady ,
432
419
roomId,
433
420
metricsTrigger : payload . metricsTrigger ,
434
421
} ) ;
435
422
} catch ( err ) {
436
- dis . dispatch ( {
423
+ this . dis . dispatch ( {
437
424
action : Action . JoinRoomError ,
438
425
roomId,
439
426
err,
@@ -493,6 +480,24 @@ export class RoomViewStore extends Store<ActionPayload> {
493
480
this . state = Object . assign ( { } , INITIAL_STATE ) ;
494
481
}
495
482
483
+ /**
484
+ * Reset which dispatcher should be used to listen for actions. The old dispatcher will be
485
+ * unregistered.
486
+ * @param dis The new dispatcher to use.
487
+ */
488
+ public resetDispatcher ( dis : MatrixDispatcher ) {
489
+ if ( this . dispatchToken ) {
490
+ this . dis . unregister ( this . dispatchToken ) ;
491
+ }
492
+ this . dis = dis ;
493
+ if ( dis ) {
494
+ // Some tests mock the dispatcher file resulting in an empty defaultDispatcher
495
+ // so rather than dying here, just ignore it. When we no longer mock files like this,
496
+ // we should remove the null check.
497
+ this . dispatchToken = this . dis . register ( this . onDispatch . bind ( this ) ) ;
498
+ }
499
+ }
500
+
496
501
// The room ID of the room currently being viewed
497
502
public getRoomId ( ) : Optional < string > {
498
503
return this . state . roomId ;
0 commit comments