diff --git a/mediarepo-ui/src/app/components/core/core.component.html b/mediarepo-ui/src/app/components/core/core.component.html index 5cbb8c5..def7489 100644 --- a/mediarepo-ui/src/app/components/core/core.component.html +++ b/mediarepo-ui/src/app/components/core/core.component.html @@ -14,8 +14,8 @@ - - + + diff --git a/mediarepo-ui/src/app/components/core/core.component.ts b/mediarepo-ui/src/app/components/core/core.component.ts index b6ade5c..edf3026 100644 --- a/mediarepo-ui/src/app/components/core/core.component.ts +++ b/mediarepo-ui/src/app/components/core/core.component.ts @@ -4,10 +4,10 @@ import {RepositoryService} from "../../services/repository/repository.service"; import {MatTabChangeEvent, MatTabGroup} from "@angular/material/tabs"; import {TagService} from "../../services/tag/tag.service"; import {TabService} from "../../services/tab/tab.service"; -import {TabCategory} from "../../models/TabCategory"; -import {TabState} from "../../models/TabState"; -import {AppState} from "../../models/AppState"; +import {TabCategory} from "../../models/state/TabCategory"; +import {AppState} from "../../models/state/AppState"; import {StateService} from "../../services/state/state.service"; +import {TabState} from "../../models/state/TabState"; @Component({ selector: "app-core", diff --git a/mediarepo-ui/src/app/components/core/empty-tab/empty-tab.component.ts b/mediarepo-ui/src/app/components/core/empty-tab/empty-tab.component.ts index 831bd11..fd9fa5f 100644 --- a/mediarepo-ui/src/app/components/core/empty-tab/empty-tab.component.ts +++ b/mediarepo-ui/src/app/components/core/empty-tab/empty-tab.component.ts @@ -1,5 +1,5 @@ import {ChangeDetectionStrategy, Component, EventEmitter, Output} from "@angular/core"; -import {TabCategory} from "../../../models/TabCategory"; +import {TabCategory} from "../../../models/state/TabCategory"; type TabCategoryName = "files" | "import"; diff --git a/mediarepo-ui/src/app/components/core/files-tab/files-tab-sidebar/files-tab-sidebar.component.ts b/mediarepo-ui/src/app/components/core/files-tab/files-tab-sidebar/files-tab-sidebar.component.ts index 311bce8..e9d3d5f 100644 --- a/mediarepo-ui/src/app/components/core/files-tab/files-tab-sidebar/files-tab-sidebar.component.ts +++ b/mediarepo-ui/src/app/components/core/files-tab/files-tab-sidebar/files-tab-sidebar.component.ts @@ -5,7 +5,7 @@ import {File} from "../../../../../api/models/File"; import {FileSearchComponent} from "../../../shared/sidebar/file-search/file-search.component"; import {RepositoryService} from "../../../../services/repository/repository.service"; import {TagEditComponent} from "../../../shared/sidebar/tag-edit/tag-edit.component"; -import {TabState} from "../../../../models/TabState"; +import {FilesTabState} from "../../../../models/state/FilesTabState"; @Component({ selector: "app-files-tab-sidebar", @@ -14,7 +14,7 @@ import {TabState} from "../../../../models/TabState"; }) export class FilesTabSidebarComponent implements OnInit, OnChanges { - @Input() state!: TabState; + @Input() state!: FilesTabState; @Input() selectedFiles: File[] = []; @Output() searchStartEvent = new EventEmitter(); @Output() searchEndEvent = new EventEmitter(); diff --git a/mediarepo-ui/src/app/components/core/files-tab/files-tab.component.ts b/mediarepo-ui/src/app/components/core/files-tab/files-tab.component.ts index 706866f..8233c6c 100644 --- a/mediarepo-ui/src/app/components/core/files-tab/files-tab.component.ts +++ b/mediarepo-ui/src/app/components/core/files-tab/files-tab.component.ts @@ -1,9 +1,9 @@ import {Component, Input, OnInit} from "@angular/core"; import {File} from "../../../../api/models/File"; -import {TabState} from "../../../models/TabState"; +import {FilesTabState} from "../../../models/state/FilesTabState"; import {RepositoryMetadata} from "../../../../api/api-types/repo"; import {RepositoryService} from "../../../services/repository/repository.service"; -import {TabCategory} from "../../../models/TabCategory"; +import {TabCategory} from "../../../models/state/TabCategory"; @Component({ selector: "app-files-tab", @@ -12,7 +12,7 @@ import {TabCategory} from "../../../models/TabCategory"; }) export class FilesTabComponent implements OnInit { - @Input() state!: TabState; + @Input() state!: FilesTabState; files: File[] = []; contentLoading = false; diff --git a/mediarepo-ui/src/app/components/core/import-tab/import-tab.component.ts b/mediarepo-ui/src/app/components/core/import-tab/import-tab.component.ts index ba47f1e..857f3b9 100644 --- a/mediarepo-ui/src/app/components/core/import-tab/import-tab.component.ts +++ b/mediarepo-ui/src/app/components/core/import-tab/import-tab.component.ts @@ -1,6 +1,6 @@ import {ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnInit} from "@angular/core"; import {File} from "../../../../api/models/File"; -import {TabState} from "../../../models/TabState"; +import {ImportTabState} from "../../../models/state/ImportTabState"; @Component({ selector: "app-import-tab", @@ -10,7 +10,7 @@ import {TabState} from "../../../models/TabState"; }) export class ImportTabComponent implements OnInit { - @Input() state!: TabState; + @Input() state!: ImportTabState; public files: File[] = []; public selectedFiles: File[] = []; diff --git a/mediarepo-ui/src/app/components/shared/file/file-multiview/file-multiview.component.ts b/mediarepo-ui/src/app/components/shared/file/file-multiview/file-multiview.component.ts index 37f4fed..8a69d99 100644 --- a/mediarepo-ui/src/app/components/shared/file/file-multiview/file-multiview.component.ts +++ b/mediarepo-ui/src/app/components/shared/file/file-multiview/file-multiview.component.ts @@ -6,7 +6,7 @@ import {FileActionBaseComponent} from "../../app-base/file-action-base/file-acti import {MatDialog} from "@angular/material/dialog"; import {LoggingService} from "../../../../services/logging/logging.service"; import {FileService} from "../../../../services/file/file.service"; -import {TabState} from "../../../../models/TabState"; +import {FilesTabState} from "../../../../models/state/FilesTabState"; @Component({ selector: "app-file-multiview", @@ -17,7 +17,7 @@ export class FileMultiviewComponent extends FileActionBaseComponent implements A @Input() files!: File[]; @Input() mode: "grid" | "gallery" = "grid"; - @Input() tabState!: TabState; + @Input() tabState!: FilesTabState; @Output() fileOpenEvent = new EventEmitter(); @Output() fileSelectEvent = new EventEmitter(); diff --git a/mediarepo-ui/src/app/components/shared/sidebar/file-search/file-search.component.ts b/mediarepo-ui/src/app/components/shared/sidebar/file-search/file-search.component.ts index 97d1c46..fe88675 100644 --- a/mediarepo-ui/src/app/components/shared/sidebar/file-search/file-search.component.ts +++ b/mediarepo-ui/src/app/components/shared/sidebar/file-search/file-search.component.ts @@ -15,7 +15,7 @@ import {LoggingService} from "../../../../services/logging/logging.service"; import {FilterDialogComponent} from "./filter-dialog/filter-dialog.component"; import {Tag} from "../../../../../api/models/Tag"; import {clipboard} from "@tauri-apps/api"; -import {TabState} from "../../../../models/TabState"; +import {FilesTabState} from "../../../../models/state/FilesTabState"; import {FilterQueryBuilder} from "../../../../../api/models/FilterQueryBuilder"; import {SearchFilters} from "../../../../../api/models/SearchFilters"; import {FileStatus, FilterExpression,} from "../../../../../api/api-types/files"; @@ -37,7 +37,7 @@ export class FileSearchComponent implements AfterViewChecked, OnInit { @Input() availableTags: Tag[] = []; @Input() contextTags: Tag[] = []; - @Input() state!: TabState; + @Input() state!: FilesTabState; @Input() tagsLoading = false; @Output() searchStartEvent = new EventEmitter(); diff --git a/mediarepo-ui/src/app/models/AppState.ts b/mediarepo-ui/src/app/models/AppState.ts deleted file mode 100644 index 923e4c3..0000000 --- a/mediarepo-ui/src/app/models/AppState.ts +++ /dev/null @@ -1,53 +0,0 @@ -import {TabState} from "./TabState"; -import {FileService} from "../services/file/file.service"; -import {BehaviorSubject} from "rxjs"; -import {TabCategory} from "./TabCategory"; - -export class AppState { - - public tabs = new BehaviorSubject([]); - public selectedTab = new BehaviorSubject(undefined); - public repoName: string | undefined; - private tabIdCounter = 0; - private readonly fileService: FileService; - - constructor(fileService: FileService) { - this.fileService = fileService; - } - - public static deserializeJson(stateString: string, fileService: FileService): AppState { - let state = JSON.parse(stateString); - let appState = new AppState(fileService); - const tabs = state.tabs.map((tab: any) => TabState.fromDTO(tab, fileService)); - appState.tabs.next(tabs); - - appState.tabIdCounter = state.tabIdCounter; - appState.selectedTab.next(state.selectedTab); - appState.repoName = state.repoName; - - return appState; - } - - public addTab(category: TabCategory): TabState { - const state = new TabState(this.tabIdCounter++, category, this.fileService); - this.tabs.next([...this.tabs.value, state]); - return state; - } - - public async closeTab(uuid: number) { - const index = this.tabs.value.findIndex(t => t.uuid === uuid); - const tabs = this.tabs.value; - tabs.splice(index, 1); - this.tabs.next(tabs); - } - - public serializeJson(): string { - const tabDTOs = this.tabs.value.map(tab => tab.getDTO()); - return JSON.stringify({ - repoName: this.repoName, - tabs: tabDTOs, - tabIdCounter: this.tabIdCounter, - selectedTab: this.selectedTab.value, - }); - } -} diff --git a/mediarepo-ui/src/app/models/TabState.ts b/mediarepo-ui/src/app/models/TabState.ts deleted file mode 100644 index fc75b1b..0000000 --- a/mediarepo-ui/src/app/models/TabState.ts +++ /dev/null @@ -1,96 +0,0 @@ -import {BehaviorSubject} from "rxjs"; -import {TabCategory} from "./TabCategory"; -import {FileService} from "../services/file/file.service"; -import {File} from "../../api/models/File"; -import {SortKey} from "../../api/models/SortKey"; -import {debounceTime} from "rxjs/operators"; -import {mapNew} from "../../api/models/adaptors"; -import {SearchFilters} from "../../api/models/SearchFilters"; -import {SortingPreset} from "../../api/models/SortingPreset"; - -export class TabState { - public uuid: number; - public category: TabCategory; - public mode = new BehaviorSubject<"grid" | "gallery">("grid"); - public selectedCD = new BehaviorSubject(undefined); - public loading = new BehaviorSubject(false); - - public files = new BehaviorSubject([]); - public filters = new BehaviorSubject(new SearchFilters([])); - public sortingPreset = new BehaviorSubject(SortingPreset.fromValues( - -1, - [SortKey.fromValues( - "FileImportedTime", - "Ascending", - undefined - )] - )); - - private fileService: FileService; - - constructor( - uuid: number, - category: TabCategory, - fileService: FileService - ) { - this.category = category; - this.uuid = uuid; - this.fileService = fileService; - if (this.category === TabCategory.Files) { - this.filters.pipe(debounceTime(500)) - .subscribe(async () => await this.findFiles()); - this.sortingPreset.pipe(debounceTime(100)) - .subscribe(async () => await this.findFiles()); - } - } - - public static fromDTO( - dto: any, - fileService: FileService - ): TabState { - const state = new TabState( - dto.uuid, - dto.category, - fileService - ); - - state.filters.next(new SearchFilters(dto.filters ?? [])); - state.sortingPreset.next(new SortingPreset(dto.sortingPreset)); - state.mode.next(dto.mode ?? "grid"); - state.selectedCD.next(dto.selectedFileHash); - state.files.next((dto.files ?? []).map(mapNew(File))); - - return state; - } - - public async findFiles() { - this.loading.next(true); - const files = await this.fileService.findFiles( - this.filters.value, - this.sortingPreset.value.sortKeys - ); - this.files.next(files); - this.loading.next(false); - } - - public setTagFilters(filters: SearchFilters) { - this.filters.next(filters); - } - - public setSortingPreset(preset: SortingPreset) { - this.sortingPreset.next(preset); - } - - public getDTO(): any { - return { - uuid: this.uuid, - category: this.category, - filters: this.filters.value.getFilters(), - sortingPreset: this.sortingPreset.value.rawData, - mode: this.mode.value, - selectedFileHash: this.selectedCD.value, - files: this.category === TabCategory.Import ? this.files.value.map( - f => f.rawData) : [], - }; - } -} diff --git a/mediarepo-ui/src/app/models/state/AppState.ts b/mediarepo-ui/src/app/models/state/AppState.ts new file mode 100644 index 0000000..b1b5559 --- /dev/null +++ b/mediarepo-ui/src/app/models/state/AppState.ts @@ -0,0 +1,75 @@ +import {FilesTabSaveState, FilesTabState} from "./FilesTabState"; +import {BehaviorSubject} from "rxjs"; +import {TabCategory} from "./TabCategory"; +import {TabSaveState, TabState} from "./TabState"; +import {StateServices} from "./StateServices"; +import {ImportTabSaveState, ImportTabState} from "./ImportTabState"; + +export class AppState { + + public tabs = new BehaviorSubject([]); + public selectedTab = new BehaviorSubject(undefined); + public repoName: string | undefined; + private tabIdCounter = 0; + private readonly services: StateServices; + + constructor(services: StateServices) { + this.services = services; + } + + public static deserializeJson(stateString: string, services: StateServices): AppState { + let state = JSON.parse(stateString); + let appState = new AppState(services); + + const tabs = state.tabs.map((saveState: TabSaveState) => { + let tab; + + if (saveState.category === TabCategory.Files) { + tab = new FilesTabState(saveState.uuid, services); + tab.restoreSaveState(saveState as FilesTabSaveState); + } else if (saveState.category === TabCategory.Import) { + tab = new ImportTabState(saveState.uuid, services); + tab.restoreSaveState(saveState as ImportTabSaveState); + } + + return tab; + }); + appState.tabs.next(tabs); + + appState.tabIdCounter = state.tabIdCounter; + appState.selectedTab.next(state.selectedTab); + appState.repoName = state.repoName; + + return appState; + } + + public addTab(category: TabCategory): TabState { + let state; + + if (category == TabCategory.Files) { + state = new FilesTabState(this.tabIdCounter++, this.services); + } else { + state = new ImportTabState(this.tabIdCounter++, this.services); + } + + this.tabs.next([...this.tabs.value, state]); + return state; + } + + public async closeTab(uuid: number) { + const index = this.tabs.value.findIndex(t => t.uuid === uuid); + const tabs = this.tabs.value; + tabs.splice(index, 1); + this.tabs.next(tabs); + } + + public serializeJson(): string { + const tabDTOs = this.tabs.value.map(tab => tab.toSaveState()); + return JSON.stringify({ + repoName: this.repoName, + tabs: tabDTOs, + tabIdCounter: this.tabIdCounter, + selectedTab: this.selectedTab.value, + }); + } +} diff --git a/mediarepo-ui/src/app/models/state/FilesTabState.ts b/mediarepo-ui/src/app/models/state/FilesTabState.ts new file mode 100644 index 0000000..2bd5072 --- /dev/null +++ b/mediarepo-ui/src/app/models/state/FilesTabState.ts @@ -0,0 +1,97 @@ +import {BehaviorSubject} from "rxjs"; +import {TabCategory} from "./TabCategory"; +import {File} from "../../../api/models/File"; +import {SortKey} from "../../../api/models/SortKey"; +import {debounceTime} from "rxjs/operators"; +import {mapNew} from "../../../api/models/adaptors"; +import {SearchFilters} from "../../../api/models/SearchFilters"; +import {SortingPreset} from "../../../api/models/SortingPreset"; +import {TabSaveState, TabState} from "./TabState"; +import {StateServices} from "./StateServices"; +import {FileBasicData, FilterExpression} from "../../../api/api-types/files"; +import {SortingPresetData} from "../../../api/api-types/presets"; +import {SaveState} from "./SaveState"; + +export type FilesTabSaveState = { + mode: "gallery" | "grid", + selectedCd: string | undefined, + files: FileBasicData[], + filters: FilterExpression[], + sortingPreset: SortingPresetData, +} & TabSaveState; + +export class FilesTabState extends TabState implements SaveState { + + public mode = new BehaviorSubject<"grid" | "gallery">("grid"); + public selectedCD = new BehaviorSubject(undefined); + public loading = new BehaviorSubject(false); + + public files = new BehaviorSubject([]); + public filters = new BehaviorSubject(new SearchFilters([])); + public sortingPreset = new BehaviorSubject(SortingPreset.fromValues( + -1, + [SortKey.fromValues( + "FileImportedTime", + "Ascending", + undefined + )] + )); + + constructor( + uuid: number, + services: StateServices, + ) { + super(uuid, TabCategory.Files, services); + this.subscribe(); + } + + public restoreSaveState( + state: FilesTabSaveState, + ) { + super.restoreSaveState(state); + this.filters = new BehaviorSubject(new SearchFilters(state.filters ?? [])); + this.sortingPreset = new BehaviorSubject(new SortingPreset(state.sortingPreset)); + this.mode = new BehaviorSubject(state.mode ?? "grid"); + this.selectedCD = new BehaviorSubject(state.selectedCd); + this.files = new BehaviorSubject((state.files ?? []).map(mapNew(File))); + this.subscribe(); + } + + public async findFiles() { + this.loading.next(true); + const files = await this.services.fileService.findFiles( + this.filters.value, + this.sortingPreset.value.sortKeys + ); + this.files.next(files); + this.loading.next(false); + } + + public setTagFilters(filters: SearchFilters) { + this.filters.next(filters); + } + + public setSortingPreset(preset: SortingPreset) { + this.sortingPreset.next(preset); + } + + public toSaveState(): FilesTabSaveState { + return { + uuid: this.uuid, + category: this.category, + filters: this.filters.value.getFilters(), + sortingPreset: this.sortingPreset.value.rawData, + mode: this.mode.value, + selectedCd: this.selectedCD.value, + files: this.category === TabCategory.Import ? this.files.value.map( + f => f.rawData) : [], + }; + } + + private subscribe() { + this.filters.pipe(debounceTime(500)) + .subscribe(async () => await this.findFiles()); + this.sortingPreset.pipe(debounceTime(100)) + .subscribe(async () => await this.findFiles()); + } +} diff --git a/mediarepo-ui/src/app/models/state/ImportTabState.ts b/mediarepo-ui/src/app/models/state/ImportTabState.ts new file mode 100644 index 0000000..dcda802 --- /dev/null +++ b/mediarepo-ui/src/app/models/state/ImportTabState.ts @@ -0,0 +1,44 @@ +import {TabSaveState, TabState} from "./TabState"; +import {SaveState} from "./SaveState"; +import {StateServices} from "./StateServices"; +import {TabCategory} from "./TabCategory"; +import {BehaviorSubject} from "rxjs"; +import {File} from "../../../api/models/File"; +import {FileBasicData} from "../../../api/api-types/files"; +import {mapNew} from "../../../api/models/adaptors"; + +export type ImportTabSaveState = { + selectedCd: string | undefined, + mode: "grid" | "gallery", + files: FileBasicData[], +} & TabSaveState; + +export class ImportTabState extends TabState implements SaveState { + + public mode = new BehaviorSubject<"grid" | "gallery">("grid"); + public selectedCD = new BehaviorSubject(undefined); + public files = new BehaviorSubject([]); + + constructor(uuid: number, services: StateServices) { + super(uuid, TabCategory.Import, services); + } + + public restoreSaveState(state: ImportTabSaveState) { + super.restoreSaveState(state); + this.selectedCD = new BehaviorSubject(state.selectedCd); + this.files = new BehaviorSubject(state.files.map(mapNew(File))); + this.mode = new BehaviorSubject<"grid" | "gallery">(state.mode); + + return self; + } + + public toSaveState(): ImportTabSaveState { + return { + uuid: this.uuid, + category: this.category, + selectedCd: this.selectedCD.value, + files: this.files.value.map(f => f.rawData), + mode: this.mode.value + }; + } +} diff --git a/mediarepo-ui/src/app/models/state/SaveState.ts b/mediarepo-ui/src/app/models/state/SaveState.ts new file mode 100644 index 0000000..50906dd --- /dev/null +++ b/mediarepo-ui/src/app/models/state/SaveState.ts @@ -0,0 +1,5 @@ +export interface SaveState { + restoreSaveState(state: State): void; + + toSaveState(): State; +} diff --git a/mediarepo-ui/src/app/models/state/StateServices.ts b/mediarepo-ui/src/app/models/state/StateServices.ts new file mode 100644 index 0000000..0cd930a --- /dev/null +++ b/mediarepo-ui/src/app/models/state/StateServices.ts @@ -0,0 +1,6 @@ +import {FileService} from "../../services/file/file.service"; + +export class StateServices { + constructor(public fileService: FileService) { + } +} diff --git a/mediarepo-ui/src/app/models/TabCategory.ts b/mediarepo-ui/src/app/models/state/TabCategory.ts similarity index 100% rename from mediarepo-ui/src/app/models/TabCategory.ts rename to mediarepo-ui/src/app/models/state/TabCategory.ts diff --git a/mediarepo-ui/src/app/models/state/TabState.ts b/mediarepo-ui/src/app/models/state/TabState.ts new file mode 100644 index 0000000..da50cd4 --- /dev/null +++ b/mediarepo-ui/src/app/models/state/TabState.ts @@ -0,0 +1,49 @@ +import {TabCategory} from "./TabCategory"; +import {StateServices} from "./StateServices"; +import {SaveState} from "./SaveState"; +import {FilesTabState} from "./FilesTabState"; +import {ImportTabState} from "./ImportTabState"; + +export type TabSaveState = { + uuid: number, + category: TabCategory, +} + +export class TabState implements SaveState { + constructor( + public uuid: number, + public category: TabCategory, + protected services: StateServices + ) { + } + + public toSaveState(): TabSaveState { + return { + uuid: this.uuid, + category: this.category + }; + } + + public restoreSaveState(state: TabSaveState): void { + this.uuid = state.uuid; + this.category = state.category; + } + + /** + * Converts the state into a files tab state + * Warning: This should only be called when it's guaranteed that this tab is a files tab + * @returns {ImportTabState} + */ + public filesTab(): FilesTabState { + return this as unknown as FilesTabState; + } + + /** + * Converts the state into an import tab state + * Warning: This should only be called when it's guaranteed that this tab is an import tab + * @returns {ImportTabState} + */ + public importTab(): ImportTabState { + return this as unknown as ImportTabState; + } +} diff --git a/mediarepo-ui/src/app/services/state/state.service.ts b/mediarepo-ui/src/app/services/state/state.service.ts index 3d2a0f7..a11ae49 100644 --- a/mediarepo-ui/src/app/services/state/state.service.ts +++ b/mediarepo-ui/src/app/services/state/state.service.ts @@ -1,11 +1,15 @@ import {Injectable} from "@angular/core"; import {BehaviorSubject, Subscription} from "rxjs"; -import {AppState} from "../../models/AppState"; +import {AppState} from "../../models/state/AppState"; import {FileService} from "../file/file.service"; import {RepositoryService} from "../repository/repository.service"; -import {TabState} from "../../models/TabState"; +import {FilesTabState} from "../../models/state/FilesTabState"; import {debounceTime} from "rxjs/operators"; import {MediarepoApi} from "../../../api/Api"; +import {StateServices} from "../../models/state/StateServices"; +import {ImportTabState} from "../../models/state/ImportTabState"; +import {TabState} from "../../models/state/TabState"; +import {TabCategory} from "../../models/state/TabCategory"; @Injectable({ providedIn: "root" @@ -19,12 +23,12 @@ export class StateService { private stateChange = new BehaviorSubject(undefined); constructor(private fileService: FileService, private repoService: RepositoryService) { - this.state = new BehaviorSubject(new AppState(fileService)); + this.state = new BehaviorSubject(new AppState(this.getServices())); this.repoService.selectedRepository.subscribe(async (repo) => { if (repo && (!this.state.value.repoName || this.state.value.repoName !== repo.name)) { await this.loadState(); } else { - const state = new AppState(this.fileService); + const state = new AppState(this.getServices()); this.subscribeToState(state); this.state.next(state); } @@ -43,13 +47,13 @@ export class StateService { if (stateString) { try { - state = AppState.deserializeJson(stateString, this.fileService); + state = AppState.deserializeJson(stateString, this.getServices()); } catch (err) { console.error("could not deserialize malformed state: ", err); - state = new AppState(this.fileService); + state = new AppState(this.getServices()); } } else { - state = new AppState(this.fileService); + state = new AppState(this.getServices()); } let selectedRepo = this.repoService.selectedRepository.value; if (selectedRepo) { @@ -78,14 +82,34 @@ export class StateService { } private subscribeToTab(tab: TabState) { + if (tab.category === TabCategory.Files) { + this.subscribeToFilesTab(tab as FilesTabState); + } else if (tab.category === TabCategory.Import) { + this.subscribeToImportTab(tab as ImportTabState); + } + } + + private subscribeToImportTab(tab: ImportTabState) { + this.tabSubscriptions.push(tab.mode + .subscribe(() => this.stateChange.next())); + } + + private subscribeToFilesTab(tab: FilesTabState) { this.tabSubscriptions.push(tab.filters .subscribe(() => this.stateChange.next())); + this.tabSubscriptions.push(tab.files + .subscribe(() => this.stateChange.next())); this.tabSubscriptions.push(tab.sortingPreset .subscribe(() => this.stateChange.next())); this.tabSubscriptions.push( tab.selectedCD.subscribe(() => this.stateChange.next())); this.tabSubscriptions.push( tab.mode.subscribe(() => this.stateChange.next())); - this.tabSubscriptions.push(tab.files.subscribe(() => this.stateChange.next())); + this.tabSubscriptions.push(tab.mode + .subscribe(() => this.stateChange.next())); + } + + private getServices(): StateServices { + return new StateServices(this.fileService); } }