Add saving and restoring of opened tabs

Signed-off-by: trivernis <trivernis@protonmail.com>
pull/4/head
trivernis 3 years ago
parent 02c013a1c3
commit f652785ccf

@ -1491,8 +1491,8 @@ checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f"
[[package]] [[package]]
name = "mediarepo-api" name = "mediarepo-api"
version = "0.14.0" version = "0.16.0"
source = "git+https://github.com/Trivernis/mediarepo-api.git?rev=5991f5d3038386c921a901a05c4a72e4ce00b418#5991f5d3038386c921a901a05c4a72e4ce00b418" source = "git+https://github.com/Trivernis/mediarepo-api.git?rev=9599020726eb9db47b9be7a6c41c2942a477ba09#9599020726eb9db47b9be7a6c41c2942a477ba09"
dependencies = [ dependencies = [
"async-trait", "async-trait",
"bromine", "bromine",

@ -25,7 +25,7 @@ features = [ "env-filter" ]
[dependencies.mediarepo-api] [dependencies.mediarepo-api]
git = "https://github.com/Trivernis/mediarepo-api.git" git = "https://github.com/Trivernis/mediarepo-api.git"
rev = "5991f5d3038386c921a901a05c4a72e4ce00b418" rev = "9599020726eb9db47b9be7a6c41c2942a477ba09"
features = [ "tauri-plugin" ] features = [ "tauri-plugin" ]
[features] [features]

@ -6,6 +6,7 @@ import {TagService} from "../../services/tag/tag.service";
import {TabService} from "../../services/tab/tab.service"; import {TabService} from "../../services/tab/tab.service";
import {TabCategory} from "../../models/TabCategory"; import {TabCategory} from "../../models/TabCategory";
import {TabState} from "../../models/TabState.rs"; import {TabState} from "../../models/TabState.rs";
import {AppState} from "../../models/AppState";
@Component({ @Component({
selector: "app-core", selector: "app-core",
@ -16,6 +17,8 @@ export class CoreComponent implements OnInit {
public selectedRepository: Repository | undefined; public selectedRepository: Repository | undefined;
public tabs: TabState[] = []; public tabs: TabState[] = [];
public appState: AppState = new AppState();
private stateInterval?: number;
@ViewChild("tabGroup") tabGroup!: MatTabGroup; @ViewChild("tabGroup") tabGroup!: MatTabGroup;
public newTab = false; public newTab = false;
@ -33,10 +36,14 @@ export class CoreComponent implements OnInit {
if (this.selectedRepository) { if (this.selectedRepository) {
await this.loadRepoData(); await this.loadRepoData();
if (this.appState.tabs.length === 0) {
this.addTab(); this.addTab();
}
} else { } else {
clearInterval(this.stateInterval);
this.newTab = false; this.newTab = false;
this.tabService.closeAllTabs(); this.tabService.closeAllTabs();
this.appState = new AppState();
} }
}); });
this.tabService.tabs.subscribe(tabs => { this.tabService.tabs.subscribe(tabs => {
@ -46,6 +53,9 @@ export class CoreComponent implements OnInit {
async loadRepoData() { async loadRepoData() {
await this.tagService.loadTags(); await this.tagService.loadTags();
this.appState = await this.repoService.getFrontendState();
this.tabService.restoreFromState(this.appState);
this.startStateSaveRoutine();
} }
public onTabSelectionChange(event: MatTabChangeEvent): void { public onTabSelectionChange(event: MatTabChangeEvent): void {
@ -90,4 +100,13 @@ export class CoreComponent implements OnInit {
this.closeTab(tab); this.closeTab(tab);
} }
} }
private startStateSaveRoutine() {
clearInterval(this.stateInterval);
this.stateInterval = setInterval(async () => this.saveState(), 10000);
}
private async saveState() {
await this.repoService.setFrontendState(this.appState);
}
} }

@ -0,0 +1,27 @@
import {TabState} from "./TabState.rs";
import {FileService} from "../services/file/file.service";
export class AppState {
public tabs: TabState[] = [];
constructor() {
}
public static deserializeJson(stateString: string, fileService: FileService): AppState {
let state = JSON.parse(stateString);
let appState = new AppState();
for (let tab of state.tabs) {
appState.tabs.push(TabState.fromDTO(tab, fileService));
}
return appState
}
public serializeJson(): string {
const tabDTOs = this.tabs.map(tab => tab.getDTO());
return JSON.stringify({
tabs: tabDTOs
});
}
}

@ -2,9 +2,14 @@ import {BehaviorSubject} from "rxjs";
import {TabCategory} from "./TabCategory"; import {TabCategory} from "./TabCategory";
import {FileService} from "../services/file/file.service"; import {FileService} from "../services/file/file.service";
import {File} from "./File"; import {File} from "./File";
import {FilterExpression} from "./FilterExpression"; import {
FilterExpression,
OrFilterExpression,
SingleFilterExpression
} from "./FilterExpression";
import {SortKey} from "./SortKey"; import {SortKey} from "./SortKey";
import {debounceTime} from "rxjs/operators"; import {debounceTime} from "rxjs/operators";
import {TagQuery} from "./TagQuery";
export class TabState { export class TabState {
public uuid: number; public uuid: number;
@ -40,4 +45,31 @@ export class TabState {
public setSortKeys(keys: SortKey[]) { public setSortKeys(keys: SortKey[]) {
this.sortKeys.next(keys) this.sortKeys.next(keys)
} }
public static fromDTO(dto: any, fileService: FileService): TabState {
const state = new TabState(dto.uuid, dto.category, fileService);
const filters = dto.filters.map((f: {filter: any, filter_type: any}) => {
if (f.filter_type === "OrExpression") {
return new OrFilterExpression(f.filter.map((f: any) => new TagQuery(f.tag, f.negate)))
} else {
return new SingleFilterExpression(new TagQuery(f.filter.tag, f.filter.negate))
}
})
const sortKeys = dto.sortKeys.map((s: {sortType: any, sortDirection: any, namespaceName: any}) =>
new SortKey(s.sortType, s.sortDirection, s.namespaceName)
);
state.filters.next(filters);
state.sortKeys.next(sortKeys);
return state
}
public getDTO(): any {
return {
uuid: this.uuid,
category: this.category,
filters: this.filters.value,
sortKeys: this.sortKeys.value,
};
}
} }

@ -13,19 +13,10 @@ import {FilterExpression} from "../../models/FilterExpression";
}) })
export class FileService { export class FileService {
thumbnailCache: { [key: number]: Thumbnail[] } = {};
constructor( constructor(
@Inject(DomSanitizer) private sanitizer: DomSanitizer, @Inject(DomSanitizer) private sanitizer: DomSanitizer,
private repoService: RepositoryService,
) { ) {
repoService.selectedRepository.subscribe(_ => this.clearCache());
}
public clearCache() {
this.thumbnailCache = {};
} }
public async getAllFiles(): Promise<File[]> { public async getAllFiles(): Promise<File[]> {
return await invoke<File[]>("plugin:mediarepo|get_all_files"); return await invoke<File[]>("plugin:mediarepo|get_all_files");
} }

@ -5,6 +5,8 @@ import {invoke} from "@tauri-apps/api/tauri";
import {listen} from "@tauri-apps/api/event"; import {listen} from "@tauri-apps/api/event";
import {Info} from "../../models/Info"; import {Info} from "../../models/Info";
import {ErrorBrokerService} from "../error-broker/error-broker.service"; import {ErrorBrokerService} from "../error-broker/error-broker.service";
import {AppState} from "../../models/AppState";
import {FileService} from "../file/file.service";
@Injectable({ @Injectable({
providedIn: "root" providedIn: "root"
@ -14,7 +16,7 @@ export class RepositoryService {
public selectedRepository = new BehaviorSubject<Repository | undefined>( public selectedRepository = new BehaviorSubject<Repository | undefined>(
undefined); undefined);
constructor(private errorBroker: ErrorBrokerService) { constructor(private errorBroker: ErrorBrokerService, private fileService: FileService) {
this.registerListener() this.registerListener()
} }
@ -145,10 +147,37 @@ export class RepositoryService {
await invoke("plugin:mediarepo|start_daemon", {repoPath}) await invoke("plugin:mediarepo|start_daemon", {repoPath})
} }
/**
* Initializes a folder as a repository
* @param {string} repoPath
* @returns {Promise<void>}
*/
public async initRepository(repoPath: string): Promise<void> { public async initRepository(repoPath: string): Promise<void> {
await invoke("plugin:mediarepo|init_repository", {repoPath}); await invoke("plugin:mediarepo|init_repository", {repoPath});
} }
/**
* Returns the state of the frontend
* @returns {Promise<AppState>}
*/
public async getFrontendState(): Promise<AppState> {
let stateString = await invoke<string | undefined>("plugin:mediarepo|get_frontend_state");
if (stateString) {
return AppState.deserializeJson(stateString, this.fileService)
} else {
return new AppState();
}
}
/**
* Sets the state of the frontend
* @param {AppState} state
* @returns {Promise<void>}
*/
public async setFrontendState(state: AppState): Promise<void> {
await invoke("plugin:mediarepo|set_frontend_state", {state: state.serializeJson()})
}
async loadSelectedRepository() { async loadSelectedRepository() {
let active_repo = await invoke<Repository | undefined>( let active_repo = await invoke<Repository | undefined>(
"plugin:mediarepo|get_active_repository"); "plugin:mediarepo|get_active_repository");

@ -3,6 +3,7 @@ import {BehaviorSubject} from "rxjs";
import {TabState} from "../../models/TabState.rs"; import {TabState} from "../../models/TabState.rs";
import {TabCategory} from "../../models/TabCategory"; import {TabCategory} from "../../models/TabCategory";
import {FileService} from "../file/file.service"; import {FileService} from "../file/file.service";
import {AppState} from "../../models/AppState";
@Injectable({ @Injectable({
providedIn: "root" providedIn: "root"
@ -12,10 +13,16 @@ export class TabService {
private tabIdCounter = 0; private tabIdCounter = 0;
public selectedTab = new BehaviorSubject<number>(0); public selectedTab = new BehaviorSubject<number>(0);
public tabs = new BehaviorSubject<TabState[]>([]); public tabs = new BehaviorSubject<TabState[]>([]);
private appState?: AppState;
constructor(private fileService: FileService) { constructor(private fileService: FileService) {
} }
public restoreFromState(appState: AppState) {
this.tabs.next(appState.tabs);
this.appState = appState;
}
public setSelectedTab(index: number) { public setSelectedTab(index: number) {
this.selectedTab.next(index); this.selectedTab.next(index);
} }
@ -23,6 +30,7 @@ export class TabService {
public addTab(category: TabCategory): TabState { public addTab(category: TabCategory): TabState {
const state = new TabState(this.tabIdCounter++, category, this.fileService); const state = new TabState(this.tabIdCounter++, category, this.fileService);
this.tabs.next([...this.tabs.value, state]); this.tabs.next([...this.tabs.value, state]);
this.saveState();
return state; return state;
} }
@ -30,10 +38,18 @@ export class TabService {
const index = this.tabs.value.findIndex(t => t.uuid === uuid); const index = this.tabs.value.findIndex(t => t.uuid === uuid);
const tabs = this.tabs.value; const tabs = this.tabs.value;
tabs.splice(index, 1) tabs.splice(index, 1)
this.saveState();
this.tabs.next(tabs); this.tabs.next(tabs);
} }
public closeAllTabs() { public closeAllTabs() {
this.tabs.next([]); this.tabs.next([]);
this.saveState();
}
private saveState() {
if (this.appState) {
this.appState.tabs = this.tabs.value;
}
} }
} }

Loading…
Cancel
Save