Improve storing of the state on change rather than periodically
Signed-off-by: trivernis <trivernis@protonmail.com>pull/4/head
parent
f652785ccf
commit
08632080cb
@ -1,25 +1,27 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import {ComponentFixture, TestBed} from "@angular/core/testing";
|
||||
|
||||
import { DownloadDaemonDialogComponent } from './download-daemon-dialog.component';
|
||||
import {
|
||||
DownloadDaemonDialogComponent
|
||||
} from "./download-daemon-dialog.component";
|
||||
|
||||
describe('DownloadDaemonDialogComponent', () => {
|
||||
let component: DownloadDaemonDialogComponent;
|
||||
let fixture: ComponentFixture<DownloadDaemonDialogComponent>;
|
||||
describe("DownloadDaemonDialogComponent", () => {
|
||||
let component: DownloadDaemonDialogComponent;
|
||||
let fixture: ComponentFixture<DownloadDaemonDialogComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ DownloadDaemonDialogComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
});
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ DownloadDaemonDialogComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(DownloadDaemonDialogComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(DownloadDaemonDialogComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
it("should create", () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
@ -1,25 +1,27 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import {ComponentFixture, TestBed} from "@angular/core/testing";
|
||||
|
||||
import { EditRepositoryDialogComponent } from './edit-repository-dialog.component';
|
||||
import {
|
||||
EditRepositoryDialogComponent
|
||||
} from "./edit-repository-dialog.component";
|
||||
|
||||
describe('EditRepositoryDialogComponent', () => {
|
||||
let component: EditRepositoryDialogComponent;
|
||||
let fixture: ComponentFixture<EditRepositoryDialogComponent>;
|
||||
describe("EditRepositoryDialogComponent", () => {
|
||||
let component: EditRepositoryDialogComponent;
|
||||
let fixture: ComponentFixture<EditRepositoryDialogComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ EditRepositoryDialogComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
});
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ EditRepositoryDialogComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(EditRepositoryDialogComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(EditRepositoryDialogComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
it("should create", () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
@ -1,25 +1,25 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import {ComponentFixture, TestBed} from "@angular/core/testing";
|
||||
|
||||
import { RepositoryFormComponent } from './repository-form.component';
|
||||
import {RepositoryFormComponent} from "./repository-form.component";
|
||||
|
||||
describe('RepositoryFormComponent', () => {
|
||||
let component: RepositoryFormComponent;
|
||||
let fixture: ComponentFixture<RepositoryFormComponent>;
|
||||
describe("RepositoryFormComponent", () => {
|
||||
let component: RepositoryFormComponent;
|
||||
let fixture: ComponentFixture<RepositoryFormComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ RepositoryFormComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
});
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ RepositoryFormComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(RepositoryFormComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(RepositoryFormComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
it("should create", () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
@ -1,25 +1,25 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import {ComponentFixture, TestBed} from "@angular/core/testing";
|
||||
|
||||
import { FileImportComponent } from './file-import.component';
|
||||
import {FileImportComponent} from "./file-import.component";
|
||||
|
||||
describe('FileImportComponent', () => {
|
||||
let component: FileImportComponent;
|
||||
let fixture: ComponentFixture<FileImportComponent>;
|
||||
describe("FileImportComponent", () => {
|
||||
let component: FileImportComponent;
|
||||
let fixture: ComponentFixture<FileImportComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ FileImportComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
});
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ FileImportComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(FileImportComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(FileImportComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
it("should create", () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
@ -1,25 +1,27 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import {ComponentFixture, TestBed} from "@angular/core/testing";
|
||||
|
||||
import { EditableMetadataEntryComponent } from './editable-metadata-entry.component';
|
||||
import {
|
||||
EditableMetadataEntryComponent
|
||||
} from "./editable-metadata-entry.component";
|
||||
|
||||
describe('EditableMetadataEntryComponent', () => {
|
||||
let component: EditableMetadataEntryComponent;
|
||||
let fixture: ComponentFixture<EditableMetadataEntryComponent>;
|
||||
describe("EditableMetadataEntryComponent", () => {
|
||||
let component: EditableMetadataEntryComponent;
|
||||
let fixture: ComponentFixture<EditableMetadataEntryComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ EditableMetadataEntryComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
});
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ EditableMetadataEntryComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(EditableMetadataEntryComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(EditableMetadataEntryComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
it("should create", () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
@ -1,25 +1,25 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import {ComponentFixture, TestBed} from "@angular/core/testing";
|
||||
|
||||
import { FileMetadataComponent } from './file-metadata.component';
|
||||
import {FileMetadataComponent} from "./file-metadata.component";
|
||||
|
||||
describe('FileMetadataComponent', () => {
|
||||
let component: FileMetadataComponent;
|
||||
let fixture: ComponentFixture<FileMetadataComponent>;
|
||||
describe("FileMetadataComponent", () => {
|
||||
let component: FileMetadataComponent;
|
||||
let fixture: ComponentFixture<FileMetadataComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ FileMetadataComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
});
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ FileMetadataComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(FileMetadataComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(FileMetadataComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
it("should create", () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
@ -1,25 +1,25 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import {ComponentFixture, TestBed} from "@angular/core/testing";
|
||||
|
||||
import { MetadataEntryComponent } from './metadata-entry.component';
|
||||
import {MetadataEntryComponent} from "./metadata-entry.component";
|
||||
|
||||
describe('MetadataEntryComponent', () => {
|
||||
let component: MetadataEntryComponent;
|
||||
let fixture: ComponentFixture<MetadataEntryComponent>;
|
||||
describe("MetadataEntryComponent", () => {
|
||||
let component: MetadataEntryComponent;
|
||||
let fixture: ComponentFixture<MetadataEntryComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ MetadataEntryComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
});
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ MetadataEntryComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(MetadataEntryComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(MetadataEntryComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
it("should create", () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
@ -1,27 +1,48 @@
|
||||
import {TabState} from "./TabState.rs";
|
||||
import {FileService} from "../services/file/file.service";
|
||||
import {BehaviorSubject} from "rxjs";
|
||||
import {TabCategory} from "./TabCategory";
|
||||
|
||||
export class AppState {
|
||||
|
||||
public tabs: TabState[] = [];
|
||||
private tabIdCounter = 0;
|
||||
public tabs = new BehaviorSubject<TabState[]>([]);
|
||||
|
||||
constructor() {
|
||||
private readonly fileService: FileService
|
||||
|
||||
constructor(fileService: FileService) {
|
||||
this.fileService = fileService;
|
||||
}
|
||||
|
||||
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 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));
|
||||
}
|
||||
let appState = new AppState(fileService);
|
||||
const tabs = state.tabs.map((tab: any) => TabState.fromDTO(tab, fileService));
|
||||
appState.tabs.next(tabs);
|
||||
|
||||
appState.tabIdCounter = state.tabIdCounter;
|
||||
|
||||
return appState
|
||||
}
|
||||
|
||||
public serializeJson(): string {
|
||||
const tabDTOs = this.tabs.map(tab => tab.getDTO());
|
||||
const tabDTOs = this.tabs.value.map(tab => tab.getDTO());
|
||||
return JSON.stringify({
|
||||
tabs: tabDTOs
|
||||
tabs: tabDTOs,
|
||||
tabIdCounter: this.tabIdCounter,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,16 @@
|
||||
import {TestBed} from "@angular/core/testing";
|
||||
|
||||
import {StateService} from "./state.service";
|
||||
|
||||
describe("StateServiceService", () => {
|
||||
let service: StateService;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({});
|
||||
service = TestBed.inject(StateService);
|
||||
});
|
||||
|
||||
it("should be created", () => {
|
||||
expect(service).toBeTruthy();
|
||||
});
|
||||
});
|
@ -0,0 +1,76 @@
|
||||
import {Injectable} from "@angular/core";
|
||||
import {BehaviorSubject, Subscription} from "rxjs";
|
||||
import {AppState} from "../../models/AppState";
|
||||
import {invoke} from "@tauri-apps/api/tauri";
|
||||
import {FileService} from "../file/file.service";
|
||||
import {RepositoryService} from "../repository/repository.service";
|
||||
import {TabState} from "../../models/TabState.rs";
|
||||
import {debounceTime} from "rxjs/operators";
|
||||
|
||||
@Injectable({
|
||||
providedIn: "root"
|
||||
})
|
||||
export class StateService {
|
||||
|
||||
public state: BehaviorSubject<AppState>;
|
||||
|
||||
private tabSubscriptions: Subscription[] = [];
|
||||
|
||||
private stateChange = new BehaviorSubject<void>(undefined);
|
||||
|
||||
constructor(private fileService: FileService, private repoService: RepositoryService) {
|
||||
this.state = new BehaviorSubject(new AppState(fileService));
|
||||
this.repoService.selectedRepository.subscribe(async (repo) => {
|
||||
if (repo) {
|
||||
await this.loadState();
|
||||
} else {
|
||||
const state = new AppState(this.fileService);
|
||||
this.subscribeToState(state);
|
||||
this.state.next(state);
|
||||
}
|
||||
});
|
||||
this.stateChange.pipe(debounceTime(1000)).subscribe(async () => this.saveState());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the state of the frontend
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
public async loadState() {
|
||||
let stateString = await invoke<string | undefined>(
|
||||
"plugin:mediarepo|get_frontend_state");
|
||||
let state;
|
||||
|
||||
if (stateString) {
|
||||
state = AppState.deserializeJson(stateString, this.fileService)
|
||||
} else {
|
||||
state = new AppState(this.fileService);
|
||||
}
|
||||
this.subscribeToState(state);
|
||||
this.state.next(state);
|
||||
}
|
||||
|
||||
private subscribeToState(state: AppState) {
|
||||
state.tabs.subscribe(async tabs => {
|
||||
this.tabSubscriptions.forEach(s => s.unsubscribe());
|
||||
tabs.forEach((tab) => this.subscribeToTab(tab));
|
||||
this.stateChange.next();
|
||||
})
|
||||
}
|
||||
|
||||
private subscribeToTab(tab: TabState) {
|
||||
this.tabSubscriptions.push(tab.filters
|
||||
.subscribe(() => this.stateChange.next()));
|
||||
this.tabSubscriptions.push(tab.sortKeys
|
||||
.subscribe(() => this.stateChange.next()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the state of the frontend
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
public async saveState(): Promise<void> {
|
||||
await invoke("plugin:mediarepo|set_frontend_state",
|
||||
{state: this.state.value.serializeJson()})
|
||||
}
|
||||
}
|
@ -1,55 +1,17 @@
|
||||
import {Injectable} from "@angular/core";
|
||||
import {BehaviorSubject} from "rxjs";
|
||||
import {TabState} from "../../models/TabState.rs";
|
||||
import {TabCategory} from "../../models/TabCategory";
|
||||
import {FileService} from "../file/file.service";
|
||||
import {AppState} from "../../models/AppState";
|
||||
|
||||
@Injectable({
|
||||
providedIn: "root"
|
||||
})
|
||||
export class TabService {
|
||||
|
||||
private tabIdCounter = 0;
|
||||
public selectedTab = new BehaviorSubject<number>(0);
|
||||
public tabs = new BehaviorSubject<TabState[]>([]);
|
||||
private appState?: AppState;
|
||||
|
||||
constructor(private fileService: FileService) {
|
||||
}
|
||||
|
||||
public restoreFromState(appState: AppState) {
|
||||
this.tabs.next(appState.tabs);
|
||||
this.appState = appState;
|
||||
constructor() {
|
||||
}
|
||||
|
||||
public setSelectedTab(index: number) {
|
||||
this.selectedTab.next(index);
|
||||
}
|
||||
|
||||
public addTab(category: TabCategory): TabState {
|
||||
const state = new TabState(this.tabIdCounter++, category, this.fileService);
|
||||
this.tabs.next([...this.tabs.value, state]);
|
||||
this.saveState();
|
||||
return state;
|
||||
}
|
||||
|
||||
public closeTab(uuid: number) {
|
||||
const index = this.tabs.value.findIndex(t => t.uuid === uuid);
|
||||
const tabs = this.tabs.value;
|
||||
tabs.splice(index, 1)
|
||||
this.saveState();
|
||||
this.tabs.next(tabs);
|
||||
}
|
||||
|
||||
public closeAllTabs() {
|
||||
this.tabs.next([]);
|
||||
this.saveState();
|
||||
}
|
||||
|
||||
private saveState() {
|
||||
if (this.appState) {
|
||||
this.appState.tabs = this.tabs.value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 3.5 KiB |
Loading…
Reference in New Issue