Files
standardnotes-app-web/packages/web/src/javascripts/Controllers/ViewControllerManager.ts

320 lines
12 KiB
TypeScript

import { PaneController } from './PaneController/PaneController'
import {
PersistedStateValue,
PersistenceKey,
storage,
StorageKey,
ToastService,
ToastServiceInterface,
} from '@standardnotes/ui-services'
import { WebApplication } from '@/Application/WebApplication'
import { AccountMenuController } from '@/Controllers/AccountMenu/AccountMenuController'
import { destroyAllObjectProperties } from '@/Utils'
import {
DeinitSource,
WebOrDesktopDeviceInterface,
SubscriptionManagerInterface,
InternalEventHandlerInterface,
InternalEventInterface,
} from '@standardnotes/snjs'
import { action, makeObservable, observable } from 'mobx'
import { ActionsMenuController } from './ActionsMenuController'
import { FeaturesController } from './FeaturesController'
import { FilesController } from './FilesController'
import { NotesController } from './NotesController/NotesController'
import { ItemListController } from './ItemList/ItemListController'
import { NoAccountWarningController } from './NoAccountWarningController'
import { PreferencesController } from './PreferencesController'
import { PurchaseFlowController } from './PurchaseFlow/PurchaseFlowController'
import { QuickSettingsController } from './QuickSettingsController'
import { SearchOptionsController } from './SearchOptionsController'
import { SubscriptionController } from './Subscription/SubscriptionController'
import { SyncStatusController } from './SyncStatusController'
import { NavigationController } from './Navigation/NavigationController'
import { FilePreviewModalController } from './FilePreviewModalController'
import { SelectedItemsController } from './SelectedItemsController'
import { HistoryModalController } from './NoteHistory/HistoryModalController'
import { LinkingController } from './LinkingController'
import { PersistenceService } from './Abstract/PersistenceService'
import { CrossControllerEvent } from './CrossControllerEvent'
import { EventObserverInterface } from '@/Event/EventObserverInterface'
import { ApplicationEventObserver } from '@/Event/ApplicationEventObserver'
import { ImportModalController } from './ImportModalController'
import { VaultSelectionMenuController } from './VaultSelectionMenuController'
export class ViewControllerManager implements InternalEventHandlerInterface {
readonly enableUnfinishedFeatures: boolean = window?.enabledUnfinishedFeatures
private unsubAppEventObserver!: () => void
showBetaWarning: boolean
public dealloced = false
readonly accountMenuController: AccountMenuController
readonly actionsMenuController = new ActionsMenuController()
readonly featuresController: FeaturesController
readonly filePreviewModalController: FilePreviewModalController
readonly filesController: FilesController
readonly noAccountWarningController: NoAccountWarningController
readonly notesController: NotesController
readonly itemListController: ItemListController
readonly preferencesController: PreferencesController
readonly purchaseFlowController: PurchaseFlowController
readonly quickSettingsMenuController: QuickSettingsController
readonly vaultSelectionController: VaultSelectionMenuController
readonly searchOptionsController: SearchOptionsController
readonly subscriptionController: SubscriptionController
readonly syncStatusController = new SyncStatusController()
readonly navigationController: NavigationController
readonly selectionController: SelectedItemsController
readonly historyModalController: HistoryModalController
readonly linkingController: LinkingController
readonly paneController: PaneController
readonly importModalController: ImportModalController
public isSessionsModalVisible = false
private appEventObserverRemovers: (() => void)[] = []
private subscriptionManager: SubscriptionManagerInterface
private persistenceService: PersistenceService
private applicationEventObserver: EventObserverInterface
private toastService: ToastServiceInterface
constructor(public application: WebApplication, private device: WebOrDesktopDeviceInterface) {
const eventBus = application.events
this.persistenceService = new PersistenceService(application, eventBus)
eventBus.addEventHandler(this, CrossControllerEvent.HydrateFromPersistedValues)
eventBus.addEventHandler(this, CrossControllerEvent.RequestValuePersistence)
this.subscriptionManager = application.subscriptions
this.filePreviewModalController = new FilePreviewModalController(application)
this.quickSettingsMenuController = new QuickSettingsController(application, eventBus)
this.vaultSelectionController = new VaultSelectionMenuController(application, eventBus)
this.paneController = new PaneController(application, eventBus)
this.preferencesController = new PreferencesController(application, eventBus)
this.selectionController = new SelectedItemsController(application, eventBus)
this.featuresController = new FeaturesController(application, eventBus)
this.navigationController = new NavigationController(application, this.featuresController, eventBus)
this.notesController = new NotesController(
application,
this.selectionController,
this.navigationController,
eventBus,
)
this.searchOptionsController = new SearchOptionsController(application, eventBus)
this.linkingController = new LinkingController(
application,
this.navigationController,
this.selectionController,
eventBus,
)
this.itemListController = new ItemListController(
application,
this.navigationController,
this.searchOptionsController,
this.selectionController,
this.notesController,
eventBus,
)
this.notesController.setServicesPostConstruction(this.itemListController)
this.selectionController.setServicesPostConstruction(this.itemListController)
this.noAccountWarningController = new NoAccountWarningController(application, eventBus)
this.accountMenuController = new AccountMenuController(application, eventBus)
this.subscriptionController = new SubscriptionController(application, eventBus, this.subscriptionManager)
this.purchaseFlowController = new PurchaseFlowController(application, eventBus)
this.filesController = new FilesController(
application,
this.notesController,
this.filePreviewModalController,
eventBus,
)
this.linkingController.setServicesPostConstruction(
this.itemListController,
this.filesController,
this.subscriptionController,
)
this.historyModalController = new HistoryModalController(this.application, eventBus, this.notesController)
this.importModalController = new ImportModalController(this.application, this.navigationController)
this.toastService = new ToastService()
this.applicationEventObserver = new ApplicationEventObserver(
application,
application.routeService,
this.purchaseFlowController,
this.accountMenuController,
this.preferencesController,
this.syncStatusController,
application.sync,
application.sessions,
application.subscriptions,
this.toastService,
application.user,
)
this.addAppEventObserver()
if (this.device.appVersion.includes('-beta')) {
this.showBetaWarning = storage.get(StorageKey.ShowBetaWarning) ?? true
} else {
this.showBetaWarning = false
}
makeObservable(this, {
showBetaWarning: observable,
isSessionsModalVisible: observable,
preferencesController: observable,
openSessionsModal: action,
closeSessionsModal: action,
})
}
deinit(source: DeinitSource): void {
this.dealloced = true
;(this.application as unknown) = undefined
if (source === DeinitSource.SignOut) {
storage.remove(StorageKey.ShowBetaWarning)
this.noAccountWarningController.reset()
}
this.unsubAppEventObserver?.()
;(this.unsubAppEventObserver as unknown) = undefined
this.appEventObserverRemovers.forEach((remover) => remover())
this.appEventObserverRemovers.length = 0
;(this.device as unknown) = undefined
this.filePreviewModalController.deinit()
;(this.filePreviewModalController as unknown) = undefined
;(this.preferencesController as unknown) = undefined
;(this.quickSettingsMenuController as unknown) = undefined
;(this.vaultSelectionController as unknown) = undefined
;(this.syncStatusController as unknown) = undefined
this.persistenceService.deinit()
;(this.persistenceService as unknown) = undefined
this.actionsMenuController.reset()
;(this.actionsMenuController as unknown) = undefined
this.featuresController.deinit()
;(this.featuresController as unknown) = undefined
this.accountMenuController.deinit()
;(this.accountMenuController as unknown) = undefined
this.filesController.deinit()
;(this.filesController as unknown) = undefined
this.noAccountWarningController.deinit()
;(this.noAccountWarningController as unknown) = undefined
this.notesController.deinit()
;(this.notesController as unknown) = undefined
this.itemListController.deinit()
;(this.itemListController as unknown) = undefined
this.linkingController.deinit()
;(this.linkingController as unknown) = undefined
this.purchaseFlowController.deinit()
;(this.purchaseFlowController as unknown) = undefined
this.searchOptionsController.deinit()
;(this.searchOptionsController as unknown) = undefined
this.subscriptionController.deinit()
;(this.subscriptionController as unknown) = undefined
this.navigationController.deinit()
;(this.navigationController as unknown) = undefined
this.historyModalController.deinit()
;(this.historyModalController as unknown) = undefined
this.paneController.deinit()
;(this.paneController as unknown) = undefined
destroyAllObjectProperties(this)
}
openSessionsModal = () => {
this.isSessionsModalVisible = true
}
closeSessionsModal = () => {
this.isSessionsModalVisible = false
}
addAppEventObserver() {
this.unsubAppEventObserver = this.application.addEventObserver(
this.applicationEventObserver.handle.bind(this.applicationEventObserver),
)
}
persistValues = (): void => {
const values: PersistedStateValue = {
[PersistenceKey.SelectedItemsController]: this.selectionController.getPersistableValue(),
[PersistenceKey.NavigationController]: this.navigationController.getPersistableValue(),
}
this.persistenceService.persistValues(values)
const selectedItemsState = values['selected-items-controller']
const navigationSelectionState = values['navigation-controller']
const launchPriorityUuids: string[] = []
if (selectedItemsState.selectedUuids.length) {
launchPriorityUuids.push(...selectedItemsState.selectedUuids)
}
if (navigationSelectionState.selectedTagUuid) {
launchPriorityUuids.push(navigationSelectionState.selectedTagUuid)
}
this.application.sync.setLaunchPriorityUuids(launchPriorityUuids)
}
clearPersistedValues = (): void => {
this.persistenceService.clearPersistedValues()
}
hydrateFromPersistedValues = (values: PersistedStateValue | undefined): void => {
const navigationState = values?.[PersistenceKey.NavigationController]
this.navigationController.hydrateFromPersistedValue(navigationState)
const selectedItemsState = values?.[PersistenceKey.SelectedItemsController]
this.selectionController.hydrateFromPersistedValue(selectedItemsState)
}
async handleEvent(event: InternalEventInterface): Promise<void> {
if (event.type === CrossControllerEvent.HydrateFromPersistedValues) {
this.hydrateFromPersistedValues(event.payload as PersistedStateValue | undefined)
} else if (event.type === CrossControllerEvent.RequestValuePersistence) {
this.persistValues()
}
}
}