mirror of https://github.com/vector-im/riot-web
				
				
				
			Convert ActiveWidgetStore to TS
Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>pull/21833/head
							parent
							
								
									0354a7025d
								
							
						
					
					
						commit
						af9429c8a0
					
				|  | @ -49,6 +49,7 @@ import PerformanceMonitor from "../performance"; | |||
| import UIStore from "../stores/UIStore"; | ||||
| import { SetupEncryptionStore } from "../stores/SetupEncryptionStore"; | ||||
| import { RoomScrollStateStore } from "../stores/RoomScrollStateStore"; | ||||
| import ActiveWidgetStore from "../stores/ActiveWidgetStore"; | ||||
| 
 | ||||
| /* eslint-disable @typescript-eslint/naming-convention */ | ||||
| 
 | ||||
|  | @ -92,6 +93,7 @@ declare global { | |||
|         mxUIStore: UIStore; | ||||
|         mxSetupEncryptionStore?: SetupEncryptionStore; | ||||
|         mxRoomScrollStateStore?: RoomScrollStateStore; | ||||
|         mxActiveWidgetStore?: ActiveWidgetStore; | ||||
|         mxOnRecaptchaLoaded?: () => void; | ||||
|         electron?: Electron; | ||||
|     } | ||||
|  |  | |||
|  | @ -786,7 +786,7 @@ async function startMatrixClient(startSyncing = true): Promise<void> { | |||
|     UserActivity.sharedInstance().start(); | ||||
|     DMRoomMap.makeShared().start(); | ||||
|     IntegrationManagers.sharedInstance().startWatching(); | ||||
|     ActiveWidgetStore.start(); | ||||
|     ActiveWidgetStore.instance.start(); | ||||
|     CallHandler.sharedInstance().start(); | ||||
| 
 | ||||
|     // Start Mjolnir even though we haven't checked the feature flag yet. Starting
 | ||||
|  | @ -892,7 +892,7 @@ export function stopMatrixClient(unsetClient = true): void { | |||
|     UserActivity.sharedInstance().stop(); | ||||
|     TypingStore.sharedInstance().reset(); | ||||
|     Presence.stop(); | ||||
|     ActiveWidgetStore.stop(); | ||||
|     ActiveWidgetStore.instance.stop(); | ||||
|     IntegrationManagers.sharedInstance().stopWatching(); | ||||
|     Mjolnir.sharedInstance().stop(); | ||||
|     DeviceListener.sharedInstance().stop(); | ||||
|  |  | |||
|  | @ -163,7 +163,7 @@ export default class AppTile extends React.Component<IProps, IState> { | |||
| 
 | ||||
|         if (this.state.hasPermissionToLoad && !hasPermissionToLoad) { | ||||
|             // Force the widget to be non-persistent (able to be deleted/forgotten)
 | ||||
|             ActiveWidgetStore.destroyPersistentWidget(this.props.app.id); | ||||
|             ActiveWidgetStore.instance.destroyPersistentWidget(this.props.app.id); | ||||
|             PersistedElement.destroyElement(this.persistKey); | ||||
|             if (this.sgWidget) this.sgWidget.stop(); | ||||
|         } | ||||
|  | @ -198,8 +198,8 @@ export default class AppTile extends React.Component<IProps, IState> { | |||
|         if (this.dispatcherRef) dis.unregister(this.dispatcherRef); | ||||
| 
 | ||||
|         // if it's not remaining on screen, get rid of the PersistedElement container
 | ||||
|         if (!ActiveWidgetStore.getWidgetPersistence(this.props.app.id)) { | ||||
|             ActiveWidgetStore.destroyPersistentWidget(this.props.app.id); | ||||
|         if (!ActiveWidgetStore.instance.getWidgetPersistence(this.props.app.id)) { | ||||
|             ActiveWidgetStore.instance.destroyPersistentWidget(this.props.app.id); | ||||
|             PersistedElement.destroyElement(this.persistKey); | ||||
|         } | ||||
| 
 | ||||
|  | @ -282,7 +282,7 @@ export default class AppTile extends React.Component<IProps, IState> { | |||
| 
 | ||||
|         // Delete the widget from the persisted store for good measure.
 | ||||
|         PersistedElement.destroyElement(this.persistKey); | ||||
|         ActiveWidgetStore.destroyPersistentWidget(this.props.app.id); | ||||
|         ActiveWidgetStore.instance.destroyPersistentWidget(this.props.app.id); | ||||
| 
 | ||||
|         if (this.sgWidget) this.sgWidget.stop({ forceDestroy: true }); | ||||
|     } | ||||
|  |  | |||
|  | @ -17,7 +17,7 @@ limitations under the License. | |||
| 
 | ||||
| import React from 'react'; | ||||
| import RoomViewStore from '../../../stores/RoomViewStore'; | ||||
| import ActiveWidgetStore from '../../../stores/ActiveWidgetStore'; | ||||
| import ActiveWidgetStore, { ActiveWidgetStoreEvent } from '../../../stores/ActiveWidgetStore'; | ||||
| import WidgetUtils from '../../../utils/WidgetUtils'; | ||||
| import { MatrixClientPeg } from '../../../MatrixClientPeg'; | ||||
| import { replaceableComponent } from "../../../utils/replaceableComponent"; | ||||
|  | @ -39,13 +39,13 @@ export default class PersistentApp extends React.Component<{}, IState> { | |||
| 
 | ||||
|         this.state = { | ||||
|             roomId: RoomViewStore.getRoomId(), | ||||
|             persistentWidgetId: ActiveWidgetStore.getPersistentWidgetId(), | ||||
|             persistentWidgetId: ActiveWidgetStore.instance.getPersistentWidgetId(), | ||||
|         }; | ||||
|     } | ||||
| 
 | ||||
|     public componentDidMount(): void { | ||||
|         this.roomStoreToken = RoomViewStore.addListener(this.onRoomViewStoreUpdate); | ||||
|         ActiveWidgetStore.on('update', this.onActiveWidgetStoreUpdate); | ||||
|         ActiveWidgetStore.instance.on(ActiveWidgetStoreEvent.Update, this.onActiveWidgetStoreUpdate); | ||||
|         MatrixClientPeg.get().on("Room.myMembership", this.onMyMembership); | ||||
|     } | ||||
| 
 | ||||
|  | @ -53,7 +53,7 @@ export default class PersistentApp extends React.Component<{}, IState> { | |||
|         if (this.roomStoreToken) { | ||||
|             this.roomStoreToken.remove(); | ||||
|         } | ||||
|         ActiveWidgetStore.removeListener('update', this.onActiveWidgetStoreUpdate); | ||||
|         ActiveWidgetStore.instance.removeListener(ActiveWidgetStoreEvent.Update, this.onActiveWidgetStoreUpdate); | ||||
|         if (MatrixClientPeg.get()) { | ||||
|             MatrixClientPeg.get().removeListener("Room.myMembership", this.onMyMembership); | ||||
|         } | ||||
|  | @ -68,23 +68,23 @@ export default class PersistentApp extends React.Component<{}, IState> { | |||
| 
 | ||||
|     private onActiveWidgetStoreUpdate = (): void => { | ||||
|         this.setState({ | ||||
|             persistentWidgetId: ActiveWidgetStore.getPersistentWidgetId(), | ||||
|             persistentWidgetId: ActiveWidgetStore.instance.getPersistentWidgetId(), | ||||
|         }); | ||||
|     }; | ||||
| 
 | ||||
|     private onMyMembership = async (room: Room, membership: string): Promise<void> => { | ||||
|         const persistentWidgetInRoomId = ActiveWidgetStore.getRoomId(this.state.persistentWidgetId); | ||||
|         const persistentWidgetInRoomId = ActiveWidgetStore.instance.getRoomId(this.state.persistentWidgetId); | ||||
|         if (membership !== "join") { | ||||
|             // we're not in the room anymore - delete
 | ||||
|             if (room .roomId === persistentWidgetInRoomId) { | ||||
|                 ActiveWidgetStore.destroyPersistentWidget(this.state.persistentWidgetId); | ||||
|                 ActiveWidgetStore.instance.destroyPersistentWidget(this.state.persistentWidgetId); | ||||
|             } | ||||
|         } | ||||
|     }; | ||||
| 
 | ||||
|     public render(): JSX.Element { | ||||
|         if (this.state.persistentWidgetId) { | ||||
|             const persistentWidgetInRoomId = ActiveWidgetStore.getRoomId(this.state.persistentWidgetId); | ||||
|             const persistentWidgetInRoomId = ActiveWidgetStore.instance.getRoomId(this.state.persistentWidgetId); | ||||
| 
 | ||||
|             const persistentWidgetInRoom = MatrixClientPeg.get().getRoom(persistentWidgetInRoomId); | ||||
| 
 | ||||
|  | @ -96,7 +96,7 @@ export default class PersistentApp extends React.Component<{}, IState> { | |||
|             if (this.state.roomId !== persistentWidgetInRoomId && myMembership === "join") { | ||||
|                 // get the widget data
 | ||||
|                 const appEvent = WidgetUtils.getRoomWidgets(persistentWidgetInRoom).find((ev) => { | ||||
|                     return ev.getStateKey() === ActiveWidgetStore.getPersistentWidgetId(); | ||||
|                     return ev.getStateKey() === ActiveWidgetStore.instance.getPersistentWidgetId(); | ||||
|                 }); | ||||
|                 const app = WidgetUtils.makeAppConfig( | ||||
|                     appEvent.getStateKey(), appEvent.getContent(), appEvent.getSender(), | ||||
|  |  | |||
|  | @ -1,110 +0,0 @@ | |||
| /* | ||||
| Copyright 2018 New Vector Ltd | ||||
| 
 | ||||
| Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| you may not use this file except in compliance with the License. | ||||
| You may obtain a copy of the License at | ||||
| 
 | ||||
|     http://www.apache.org/licenses/LICENSE-2.0
 | ||||
| 
 | ||||
| Unless required by applicable law or agreed to in writing, software | ||||
| distributed under the License is distributed on an "AS IS" BASIS, | ||||
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| See the License for the specific language governing permissions and | ||||
| limitations under the License. | ||||
| */ | ||||
| 
 | ||||
| import EventEmitter from 'events'; | ||||
| 
 | ||||
| import { MatrixClientPeg } from '../MatrixClientPeg'; | ||||
| import { WidgetMessagingStore } from "./widgets/WidgetMessagingStore"; | ||||
| 
 | ||||
| /** | ||||
|  * Stores information about the widgets active in the app right now: | ||||
|  *  * What widget is set to remain always-on-screen, if any | ||||
|  *    Only one widget may be 'always on screen' at any one time. | ||||
|  *  * Negotiated capabilities for active apps | ||||
|  */ | ||||
| class ActiveWidgetStore extends EventEmitter { | ||||
|     constructor() { | ||||
|         super(); | ||||
|         this._persistentWidgetId = null; | ||||
| 
 | ||||
|         // What room ID each widget is associated with (if it's a room widget)
 | ||||
|         this._roomIdByWidgetId = {}; | ||||
| 
 | ||||
|         this.onRoomStateEvents = this.onRoomStateEvents.bind(this); | ||||
| 
 | ||||
|         this.dispatcherRef = null; | ||||
|     } | ||||
| 
 | ||||
|     start() { | ||||
|         MatrixClientPeg.get().on('RoomState.events', this.onRoomStateEvents); | ||||
|     } | ||||
| 
 | ||||
|     stop() { | ||||
|         if (MatrixClientPeg.get()) { | ||||
|             MatrixClientPeg.get().removeListener('RoomState.events', this.onRoomStateEvents); | ||||
|         } | ||||
|         this._roomIdByWidgetId = {}; | ||||
|     } | ||||
| 
 | ||||
|     onRoomStateEvents(ev, state) { | ||||
|         // XXX: This listens for state events in order to remove the active widget.
 | ||||
|         // Everything else relies on views listening for events and calling setters
 | ||||
|         // on this class which is terrible. This store should just listen for events
 | ||||
|         // and keep itself up to date.
 | ||||
|         // TODO: Enable support for m.widget event type (https://github.com/vector-im/element-web/issues/13111)
 | ||||
|         if (ev.getType() !== 'im.vector.modular.widgets') return; | ||||
| 
 | ||||
|         if (ev.getStateKey() === this._persistentWidgetId) { | ||||
|             this.destroyPersistentWidget(this._persistentWidgetId); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     destroyPersistentWidget(id) { | ||||
|         if (id !== this._persistentWidgetId) return; | ||||
|         const toDeleteId = this._persistentWidgetId; | ||||
| 
 | ||||
|         WidgetMessagingStore.instance.stopMessagingById(id); | ||||
| 
 | ||||
|         this.setWidgetPersistence(toDeleteId, false); | ||||
|         this.delRoomId(toDeleteId); | ||||
|     } | ||||
| 
 | ||||
|     setWidgetPersistence(widgetId, val) { | ||||
|         if (this._persistentWidgetId === widgetId && !val) { | ||||
|             this._persistentWidgetId = null; | ||||
|         } else if (this._persistentWidgetId !== widgetId && val) { | ||||
|             this._persistentWidgetId = widgetId; | ||||
|         } | ||||
|         this.emit('update'); | ||||
|     } | ||||
| 
 | ||||
|     getWidgetPersistence(widgetId) { | ||||
|         return this._persistentWidgetId === widgetId; | ||||
|     } | ||||
| 
 | ||||
|     getPersistentWidgetId() { | ||||
|         return this._persistentWidgetId; | ||||
|     } | ||||
| 
 | ||||
|     getRoomId(widgetId) { | ||||
|         return this._roomIdByWidgetId[widgetId]; | ||||
|     } | ||||
| 
 | ||||
|     setRoomId(widgetId, roomId) { | ||||
|         this._roomIdByWidgetId[widgetId] = roomId; | ||||
|         this.emit('update'); | ||||
|     } | ||||
| 
 | ||||
|     delRoomId(widgetId) { | ||||
|         delete this._roomIdByWidgetId[widgetId]; | ||||
|         this.emit('update'); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| if (global.singletonActiveWidgetStore === undefined) { | ||||
|     global.singletonActiveWidgetStore = new ActiveWidgetStore(); | ||||
| } | ||||
| export default global.singletonActiveWidgetStore; | ||||
|  | @ -0,0 +1,112 @@ | |||
| /* | ||||
| Copyright 2018 New Vector Ltd | ||||
| 
 | ||||
| Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| you may not use this file except in compliance with the License. | ||||
| You may obtain a copy of the License at | ||||
| 
 | ||||
|     http://www.apache.org/licenses/LICENSE-2.0
 | ||||
| 
 | ||||
| Unless required by applicable law or agreed to in writing, software | ||||
| distributed under the License is distributed on an "AS IS" BASIS, | ||||
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| See the License for the specific language governing permissions and | ||||
| limitations under the License. | ||||
| */ | ||||
| 
 | ||||
| import EventEmitter from 'events'; | ||||
| import { MatrixEvent } from "matrix-js-sdk"; | ||||
| 
 | ||||
| import { MatrixClientPeg } from '../MatrixClientPeg'; | ||||
| import { WidgetMessagingStore } from "./widgets/WidgetMessagingStore"; | ||||
| 
 | ||||
| export enum ActiveWidgetStoreEvent { | ||||
|     Update = "update", | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * Stores information about the widgets active in the app right now: | ||||
|  *  * What widget is set to remain always-on-screen, if any | ||||
|  *    Only one widget may be 'always on screen' at any one time. | ||||
|  *  * Negotiated capabilities for active apps | ||||
|  */ | ||||
| export default class ActiveWidgetStore extends EventEmitter { | ||||
|     private static internalInstance: ActiveWidgetStore; | ||||
|     private persistentWidgetId: string; | ||||
|     // What room ID each widget is associated with (if it's a room widget)
 | ||||
|     private roomIdByWidgetId = new Map<string, string>(); | ||||
| 
 | ||||
|     public static get instance(): ActiveWidgetStore { | ||||
|         if (!ActiveWidgetStore.internalInstance) { | ||||
|             ActiveWidgetStore.internalInstance = new ActiveWidgetStore(); | ||||
|         } | ||||
|         return ActiveWidgetStore.internalInstance; | ||||
|     } | ||||
| 
 | ||||
|     public start(): void { | ||||
|         MatrixClientPeg.get().on('RoomState.events', this.onRoomStateEvents); | ||||
|     } | ||||
| 
 | ||||
|     public stop(): void { | ||||
|         if (MatrixClientPeg.get()) { | ||||
|             MatrixClientPeg.get().removeListener('RoomState.events', this.onRoomStateEvents); | ||||
|         } | ||||
|         this.roomIdByWidgetId.clear(); | ||||
|     } | ||||
| 
 | ||||
|     private onRoomStateEvents = (ev: MatrixEvent): void => { | ||||
|         // XXX: This listens for state events in order to remove the active widget.
 | ||||
|         // Everything else relies on views listening for events and calling setters
 | ||||
|         // on this class which is terrible. This store should just listen for events
 | ||||
|         // and keep itself up to date.
 | ||||
|         // TODO: Enable support for m.widget event type (https://github.com/vector-im/element-web/issues/13111)
 | ||||
|         if (ev.getType() !== 'im.vector.modular.widgets') return; | ||||
| 
 | ||||
|         if (ev.getStateKey() === this.persistentWidgetId) { | ||||
|             this.destroyPersistentWidget(this.persistentWidgetId); | ||||
|         } | ||||
|     }; | ||||
| 
 | ||||
|     public destroyPersistentWidget(id: string): void { | ||||
|         if (id !== this.persistentWidgetId) return; | ||||
|         const toDeleteId = this.persistentWidgetId; | ||||
| 
 | ||||
|         WidgetMessagingStore.instance.stopMessagingById(id); | ||||
| 
 | ||||
|         this.setWidgetPersistence(toDeleteId, false); | ||||
|         this.delRoomId(toDeleteId); | ||||
|     } | ||||
| 
 | ||||
|     public setWidgetPersistence(widgetId: string, val: boolean): void { | ||||
|         if (this.persistentWidgetId === widgetId && !val) { | ||||
|             this.persistentWidgetId = null; | ||||
|         } else if (this.persistentWidgetId !== widgetId && val) { | ||||
|             this.persistentWidgetId = widgetId; | ||||
|         } | ||||
|         this.emit(ActiveWidgetStoreEvent.Update); | ||||
|     } | ||||
| 
 | ||||
|     public getWidgetPersistence(widgetId: string): boolean { | ||||
|         return this.persistentWidgetId === widgetId; | ||||
|     } | ||||
| 
 | ||||
|     public getPersistentWidgetId(): string { | ||||
|         return this.persistentWidgetId; | ||||
|     } | ||||
| 
 | ||||
|     public getRoomId(widgetId: string): string { | ||||
|         return this.roomIdByWidgetId.get(widgetId); | ||||
|     } | ||||
| 
 | ||||
|     public setRoomId(widgetId: string, roomId: string): void { | ||||
|         this.roomIdByWidgetId.set(widgetId, roomId); | ||||
|         this.emit(ActiveWidgetStoreEvent.Update); | ||||
|     } | ||||
| 
 | ||||
|     public delRoomId(widgetId: string): void { | ||||
|         this.roomIdByWidgetId.delete(widgetId); | ||||
|         this.emit(ActiveWidgetStoreEvent.Update); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| window.mxActiveWidgetStore = ActiveWidgetStore.instance; | ||||
|  | @ -142,14 +142,14 @@ export default class WidgetStore extends AsyncStoreWithClient<IState> { | |||
| 
 | ||||
|         // If a persistent widget is active, check to see if it's just been removed.
 | ||||
|         // If it has, it needs to destroyed otherwise unmounting the node won't kill it
 | ||||
|         const persistentWidgetId = ActiveWidgetStore.getPersistentWidgetId(); | ||||
|         const persistentWidgetId = ActiveWidgetStore.instance.getPersistentWidgetId(); | ||||
|         if (persistentWidgetId) { | ||||
|             if ( | ||||
|                 ActiveWidgetStore.getRoomId(persistentWidgetId) === room.roomId && | ||||
|                 ActiveWidgetStore.instance.getRoomId(persistentWidgetId) === room.roomId && | ||||
|                 !roomInfo.widgets.some(w => w.id === persistentWidgetId) | ||||
|             ) { | ||||
|                 logger.log(`Persistent widget ${persistentWidgetId} removed from room ${room.roomId}: destroying.`); | ||||
|                 ActiveWidgetStore.destroyPersistentWidget(persistentWidgetId); | ||||
|                 ActiveWidgetStore.instance.destroyPersistentWidget(persistentWidgetId); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|  | @ -195,7 +195,7 @@ export default class WidgetStore extends AsyncStoreWithClient<IState> { | |||
| 
 | ||||
|         // A persistent conference widget indicates that we're participating
 | ||||
|         const widgets = roomInfo.widgets.filter(w => WidgetType.JITSI.matches(w.type)); | ||||
|         return widgets.some(w => ActiveWidgetStore.getWidgetPersistence(w.id)); | ||||
|         return widgets.some(w => ActiveWidgetStore.instance.getWidgetPersistence(w.id)); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -266,7 +266,7 @@ export class StopGapWidget extends EventEmitter { | |||
|         WidgetMessagingStore.instance.storeMessaging(this.mockWidget, this.messaging); | ||||
| 
 | ||||
|         if (!this.appTileProps.userWidget && this.appTileProps.room) { | ||||
|             ActiveWidgetStore.setRoomId(this.mockWidget.id, this.appTileProps.room.roomId); | ||||
|             ActiveWidgetStore.instance.setRoomId(this.mockWidget.id, this.appTileProps.room.roomId); | ||||
|         } | ||||
| 
 | ||||
|         // Always attach a handler for ViewRoom, but permission check it internally
 | ||||
|  | @ -319,7 +319,7 @@ export class StopGapWidget extends EventEmitter { | |||
|                     if (WidgetType.JITSI.matches(this.mockWidget.type)) { | ||||
|                         CountlyAnalytics.instance.trackJoinCall(this.appTileProps.room.roomId, true, true); | ||||
|                     } | ||||
|                     ActiveWidgetStore.setWidgetPersistence(this.mockWidget.id, ev.detail.data.value); | ||||
|                     ActiveWidgetStore.instance.setWidgetPersistence(this.mockWidget.id, ev.detail.data.value); | ||||
|                     ev.preventDefault(); | ||||
|                     this.messaging.transport.reply(ev.detail, <IWidgetApiRequestEmptyData>{}); // ack
 | ||||
|                 } | ||||
|  | @ -406,13 +406,13 @@ export class StopGapWidget extends EventEmitter { | |||
|     } | ||||
| 
 | ||||
|     public stop(opts = { forceDestroy: false }) { | ||||
|         if (!opts?.forceDestroy && ActiveWidgetStore.getPersistentWidgetId() === this.mockWidget.id) { | ||||
|         if (!opts?.forceDestroy && ActiveWidgetStore.instance.getPersistentWidgetId() === this.mockWidget.id) { | ||||
|             logger.log("Skipping destroy - persistent widget"); | ||||
|             return; | ||||
|         } | ||||
|         if (!this.started) return; | ||||
|         WidgetMessagingStore.instance.stopMessaging(this.mockWidget); | ||||
|         ActiveWidgetStore.delRoomId(this.mockWidget.id); | ||||
|         ActiveWidgetStore.instance.delRoomId(this.mockWidget.id); | ||||
| 
 | ||||
|         if (MatrixClientPeg.get()) { | ||||
|             MatrixClientPeg.get().off('event', this.onEvent); | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	 Šimon Brandner
						Šimon Brandner