import { removeFromArray } from '@standardnotes/utils' import { AlertService, ComponentManagerInterface, FileItem, ItemManagerInterface, MutatorClientInterface, PreferenceServiceInterface, SNNote, SessionsClientInterface, SyncServiceInterface, } from '@standardnotes/snjs' import { NoteViewController } from './NoteViewController' import { FileViewController } from './FileViewController' import { TemplateNoteViewControllerOptions } from './TemplateNoteViewControllerOptions' import { IsNativeMobileWeb } from '@standardnotes/ui-services' type ItemControllerGroupChangeCallback = (activeController: NoteViewController | FileViewController | undefined) => void export class ItemGroupController { public itemControllers: (NoteViewController | FileViewController)[] = [] changeObservers: ItemControllerGroupChangeCallback[] = [] eventObservers: (() => void)[] = [] constructor( private items: ItemManagerInterface, private mutator: MutatorClientInterface, private sync: SyncServiceInterface, private sessions: SessionsClientInterface, private preferences: PreferenceServiceInterface, private components: ComponentManagerInterface, private alerts: AlertService, private _isNativeMobileWeb: IsNativeMobileWeb, ) {} public deinit(): void { ;(this.items as unknown) = undefined this.eventObservers.forEach((removeObserver) => { removeObserver() }) this.changeObservers.length = 0 for (const controller of this.itemControllers) { this.closeItemController(controller, { notify: false }) } this.itemControllers.length = 0 } async createItemController(context: { file?: FileItem note?: SNNote templateOptions?: TemplateNoteViewControllerOptions }): Promise { if (this.activeItemViewController) { this.closeItemController(this.activeItemViewController, { notify: false }) } let controller!: NoteViewController | FileViewController if (context.file) { controller = new FileViewController(context.file, this.items) } else if (context.note) { controller = new NoteViewController( context.note, this.items, this.mutator, this.sync, this.sessions, this.preferences, this.components, this.alerts, this._isNativeMobileWeb, ) } else if (context.templateOptions) { controller = new NoteViewController( undefined, this.items, this.mutator, this.sync, this.sessions, this.preferences, this.components, this.alerts, this._isNativeMobileWeb, context.templateOptions, ) } else { throw Error('Invalid input to createItemController') } this.itemControllers.push(controller) await controller.initialize() this.notifyObservers() return controller } public closeItemController( controller: NoteViewController | FileViewController, { notify = true }: { notify: boolean } = { notify: true }, ): void { if (controller instanceof NoteViewController) { controller.syncOnlyIfLargeNote() } controller.deinit() removeFromArray(this.itemControllers, controller) if (notify) { this.notifyObservers() } } closeActiveItemController(): void { const activeController = this.activeItemViewController if (activeController) { this.closeItemController(activeController, { notify: true }) } } closeAllItemControllers(): void { for (const controller of this.itemControllers) { this.closeItemController(controller, { notify: false }) } this.notifyObservers() } get activeItemViewController(): NoteViewController | FileViewController | undefined { return this.itemControllers[0] } /** * Notifies observer when the active controller has changed. */ public addActiveControllerChangeObserver(callback: ItemControllerGroupChangeCallback): () => void { this.changeObservers.push(callback) if (this.activeItemViewController) { callback(this.activeItemViewController) } const thislessChangeObservers = this.changeObservers return () => { removeFromArray(thislessChangeObservers, callback) } } private notifyObservers(): void { for (const observer of this.changeObservers) { observer(this.activeItemViewController) } } }