Separate import and files tab state
Signed-off-by: trivernis <trivernis@protonmail.com>pull/14/head
parent
3f37fb4e5e
commit
642222e0c4
@ -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<TabState[]>([]);
|
||||
public selectedTab = new BehaviorSubject<number | undefined>(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,
|
||||
});
|
||||
}
|
||||
}
|
@ -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<string | undefined>(undefined);
|
||||
public loading = new BehaviorSubject<boolean>(false);
|
||||
|
||||
public files = new BehaviorSubject<File[]>([]);
|
||||
public filters = new BehaviorSubject<SearchFilters>(new SearchFilters([]));
|
||||
public sortingPreset = new BehaviorSubject<SortingPreset>(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) : [],
|
||||
};
|
||||
}
|
||||
}
|
@ -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<TabState[]>([]);
|
||||
public selectedTab = new BehaviorSubject<number | undefined>(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,
|
||||
});
|
||||
}
|
||||
}
|
@ -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<FilesTabSaveState> {
|
||||
|
||||
public mode = new BehaviorSubject<"grid" | "gallery">("grid");
|
||||
public selectedCD = new BehaviorSubject<string | undefined>(undefined);
|
||||
public loading = new BehaviorSubject<boolean>(false);
|
||||
|
||||
public files = new BehaviorSubject<File[]>([]);
|
||||
public filters = new BehaviorSubject<SearchFilters>(new SearchFilters([]));
|
||||
public sortingPreset = new BehaviorSubject<SortingPreset>(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());
|
||||
}
|
||||
}
|
@ -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<ImportTabSaveState> {
|
||||
|
||||
public mode = new BehaviorSubject<"grid" | "gallery">("grid");
|
||||
public selectedCD = new BehaviorSubject<string | undefined>(undefined);
|
||||
public files = new BehaviorSubject<File[]>([]);
|
||||
|
||||
constructor(uuid: number, services: StateServices) {
|
||||
super(uuid, TabCategory.Import, services);
|
||||
}
|
||||
|
||||
public restoreSaveState(state: ImportTabSaveState) {
|
||||
super.restoreSaveState(state);
|
||||
this.selectedCD = new BehaviorSubject<string | undefined>(state.selectedCd);
|
||||
this.files = new BehaviorSubject<File[]>(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
|
||||
};
|
||||
}
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
export interface SaveState<State> {
|
||||
restoreSaveState(state: State): void;
|
||||
|
||||
toSaveState(): State;
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
import {FileService} from "../../services/file/file.service";
|
||||
|
||||
export class StateServices {
|
||||
constructor(public fileService: FileService) {
|
||||
}
|
||||
}
|
@ -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<TabSaveState> {
|
||||
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;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue