diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index d41ae68..70bdc36 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -85,7 +85,16 @@ fn load_plan(path: PathBuf, state: tauri::State>) -> Option fn save_plan(path: PathBuf, plan: Plan) -> bool { if let Some(path_string) = path.with_extension("json").to_str() { log::trace!("Attempting to save plan at path {path_string}"); - return Storage::save_plan(path_string, plan).is_ok(); + return Storage::save_plan_at_path(path_string, plan).is_ok(); + } + + false +} + +#[tauri::command] +fn save_plan_at_path(path: PathBuf, plan: Plan) -> bool { + if let Some(path_string) = path.with_extension("json").to_str() { + return Storage::save_plan_at_path(path_string, plan).is_ok(); } false diff --git a/src-tauri/src/storage.rs b/src-tauri/src/storage.rs index dec4780..792aa6b 100644 --- a/src-tauri/src/storage.rs +++ b/src-tauri/src/storage.rs @@ -73,13 +73,11 @@ impl Storage { } } - pub fn save_plan>(file: T, plan: Plan) -> Result<(), Box> { + pub fn save_plan_at_path>(file: T, plan: Plan) -> Result<(), Box> { std::fs::write(&file.into(), serde_json::to_string(&plan)?)?; Ok(()) } - - pub fn load_plan>(file: T) -> Option { let mut file = file.into(); let plan_file = Path::new(&file); diff --git a/src/app/_models/plan.ts b/src/app/_models/plan.ts index 4b211fc..d01de44 100644 --- a/src/app/_models/plan.ts +++ b/src/app/_models/plan.ts @@ -14,9 +14,9 @@ export class Plan { current: number; update_url?: string; name?: string; + private path?: string; - private saveSubject: Subject = new Subject(); - + private selfSaveSubject: Subject = new Subject(); constructor(plan: PlanInterface) { this.plan = plan.plan; @@ -24,7 +24,7 @@ export class Plan { if (plan.stored_path) { this.path = plan.stored_path; } - this.saveSubject.pipe(debounceTime(500)).subscribe(() => this.underlyingSave()); + this.selfSaveSubject.pipe(debounceTime(500)).subscribe(() => this.directSelfSave()); } setPath(path: string) { @@ -34,38 +34,24 @@ export class Plan { next() { if (this.current + 1 < this.plan!.length) { this.current++; - this.save(); + this.requestSelfSave(); } } prev() { if (this.current - 1 >= 0) { this.current--; - this.save(); - } - } - - setPrevious(prev: string) { - from(invoke('path_for_previous', { prev })).subscribe(path => { - if (path) { - this.setPath(path); - } - }); - } - - setPreviousPlan(prev: Plan) { - if (prev.path) { - this.setPath(prev.path); + this.requestSelfSave(); } } - private save() { + private requestSelfSave() { if (this.path) { - this.saveSubject.next(); + this.selfSaveSubject.next(); } } - private underlyingSave() { + private directSelfSave() { console.log("Underlying save"); invoke('save_plan', { plan: { @@ -74,6 +60,7 @@ export class Plan { }, path: this.path }); } + } export interface PlanElement { diff --git a/src/app/_services/plan.service.ts b/src/app/_services/plan.service.ts index 0c94657..f415cf8 100644 --- a/src/app/_services/plan.service.ts +++ b/src/app/_services/plan.service.ts @@ -10,115 +10,39 @@ import { fetch } from '@tauri-apps/api/http'; providedIn: 'root' }) export class PlanService { - currentPlan?: Plan; - planStore: Map = new Map(); - basePlan?: Plan; - private basePlanSubj: Subject = new ReplaySubject(1); - + private _currentPlanSubject: Subject = new ReplaySubject(1); + private _basePlanSubject: Subject = new ReplaySubject(1); constructor(private dialog: MatDialog) { - this.getPreviousPlans(); this.loadBasePlan(); } - loadPlan(path: string) { - return from(invoke('load_plan', { path })).pipe( - map(plan => { - this.currentPlan = new Plan(plan); - return plan - }) - ); - } - - loadPlanNoSave(path: string) { - return from(invoke('load_plan', { path })).pipe( - map(plan => { - this.currentPlan = new Plan(plan); - this.currentPlan.setPath(path); - return plan - }) - ); - } - - - - loadBasePlan() { - if (!this.basePlan) { - from(invoke('base_plan')).subscribe(plan => { - plan.plan.forEach(elem => { elem.edited = false; }); - this.basePlan = new Plan(plan); - this.basePlanSubj?.next(this.basePlan); - }); - } - - return this.basePlanSubj!.asObservable(); - } - - savePlan(path: string, plan: Plan) { - plan.plan.forEach(elem => { - if (!elem.notes) { elem.notes = "" } - }); - - return from(invoke('save_plan', { - path, - plan: { - plan: plan.plan, - current: plan.current - }, - })).subscribe(status => { - }); + public getBasePlan(): Observable { + return this._basePlanSubject.asObservable(); } - savePlanByName(name: string, plan: Plan) { - plan.plan.forEach(elem => { - if (!elem.notes) { elem.notes = "" } - }); - - return from(invoke('save_plan_by_name', { - name, - plan: { - plan: plan.plan, - current: plan.current, - update_url: plan.update_url - }, - })).subscribe(status => { - }); + public getCurrentPlan(): Observable { + return this._currentPlanSubject.asObservable(); } - getPreviousPlans() { - from(invoke>('load_stored_plans')).subscribe(plans => this.planStore = plans); + public setCurrentPlan(plan: Plan) { + this._currentPlanSubject.next(plan); } - loadPrevious(name: string) { - return from(invoke('load_previous', { name })).pipe(tap(plan => { - console.log("previous loaded: ", plan); - this.currentPlan = new Plan(plan); - this.currentPlan.setPrevious(name); - })); + public enumerateStoredPlans(): Observable { + return from(invoke('enumerate_stored_plans')); } - loadPreviousPlan(plan: Plan): Observable { - return new Observable(observer => { - observer.next(plan); - }).pipe(map(plan => { - console.log("previous loaded: ", plan); - this.currentPlan = plan; - this.currentPlan.setPreviousPlan(plan); - - return plan as PlanInterface; - })); + public getPathFromKnownName(name: string): Observable { + return from(invoke('path_from_name', { name })); } - zoneFromUuid(uuid: string) { - if (!this.basePlan) { - return undefined; - } - - return this.basePlan.plan.find(elem => elem.uuid === uuid); + public loadPlanFromPath(path: string): Observable { + return from(invoke('load_plan', { path })); } - loadFromUrl(url?: string, name?: string): Observable { + public loadFromUrl(url?: string, name?: string): Observable { if (!url || !name) { const dialogRef = this.dialog.open(UrlDialog, { data: { @@ -128,12 +52,11 @@ export class PlanService { }); return dialogRef.afterClosed().pipe(switchMap(data => { - console.log("import from url data: ", data); if (data.url) { return this._loadFromUrl(data.url, data.name); } - return new Observable((s) => s.complete()); + return new Observable((s) => s.complete()); })); } else { @@ -141,22 +64,29 @@ export class PlanService { } } - private _loadFromUrl(url: string, name: string): Observable { + public savePlanAtPath(path: string, plan: Plan) { + invoke('save_plan_at_path', { path, plan: plan }); + } + + private _loadFromUrl(url: string, name: string): Observable { + //Tauri fetch return from(fetch( url, { method: 'GET', timeout: 30 })).pipe(map(response => { - return response.data as PlanInterface; + return new Plan(response.data as PlanInterface); })).pipe(tap(plan => { plan.update_url = url; - const planObj = new Plan(plan); - planObj.update_url = url; - console.log("plan and plan interface: ", planObj, plan); - this.savePlanByName(name, planObj); - this.currentPlan = planObj; - this.getPreviousPlans(); + plan.name = name; })); } + + private loadBasePlan() { + from(invoke('base_plan')).subscribe(plan => { + plan.plan.forEach(elem => { elem.edited = false; }); + this._basePlanSubject?.next(new Plan(plan)); + }); + } } diff --git a/src/app/_services/shortcut.service.ts b/src/app/_services/shortcut.service.ts index 2bff581..a35fe74 100644 --- a/src/app/_services/shortcut.service.ts +++ b/src/app/_services/shortcut.service.ts @@ -1,6 +1,6 @@ import { Injectable, NgZone } from '@angular/core'; import { ShortcutHandler, register, unregister } from '@tauri-apps/api/globalShortcut'; -import { EMPTY, Observable, Subscriber, TeardownLogic, from } from 'rxjs'; +import { Observable, Subscriber } from 'rxjs'; @Injectable({ providedIn: 'root' @@ -8,8 +8,7 @@ import { EMPTY, Observable, Subscriber, TeardownLogic, from } from 'rxjs'; export class ShortcutService { private internalHandlers: Map, () => void]> = new Map, () => void]>(); - constructor(private zone: NgZone) { - } + constructor(private zone: NgZone) {} register(shortcut: string) { return new Observable((subscriber) => { @@ -29,12 +28,6 @@ export class ShortcutService { }); } - unregister(shortcut: string) { - this.internalHandlers.get(shortcut)?.[1].complete(); - this.internalHandlers.delete(shortcut); - } - - rebind_from_to(previousShortcut: string, nextShortcut: string) { let [oldHandler, subscriber, teardown] = this.internalHandlers.get(previousShortcut)!; diff --git a/src/app/editor/editor.component.ts b/src/app/editor/editor.component.ts index 51ff44e..2756e69 100644 --- a/src/app/editor/editor.component.ts +++ b/src/app/editor/editor.component.ts @@ -51,10 +51,10 @@ interface Act { ], }) export class EditorComponent implements OnInit { + planInEditing: Plan; areas?: WorldArea[]; planAreas: WorldArea[]; - plan: Plan; areasMap?: Map; areaSearchString: string = ""; planSearchString: string = ""; @@ -69,7 +69,7 @@ export class EditorComponent implements OnInit { constructor(public worldAreaService: WorldAreaService, private cdr: ChangeDetectorRef, private planService: PlanService, public dialog: MatDialog) { - this.plan = new Plan({ + this.planInEditing = new Plan({ plan: [], current: 0 }); @@ -77,7 +77,7 @@ export class EditorComponent implements OnInit { this.autoScrollToEnd = false; - this.planFuzzer = new Fuzzr(this.plan.plan, { + this.planFuzzer = new Fuzzr(this.planInEditing.plan, { toString: (e: PlanElement) => { return this.areasMap?.get(e.area_key)?.name; } @@ -113,11 +113,11 @@ export class EditorComponent implements OnInit { dropHandler(event: CdkDragDrop | CdkDragDrop) { if (event.previousContainer === event.container && !isWorldAreaEvent(event)) { - const realCurrent = this.plan.plan.indexOf(event.previousContainer.data[event.currentIndex]); - const realPrev = this.plan.plan.indexOf(event.previousContainer.data[event.previousIndex]); - moveItemInArray(this.plan.plan, realPrev, realCurrent); + const realCurrent = this.planInEditing.plan.indexOf(event.previousContainer.data[event.currentIndex]); + const realPrev = this.planInEditing.plan.indexOf(event.previousContainer.data[event.previousIndex]); + moveItemInArray(this.planInEditing.plan, realPrev, realCurrent); } else - if (this.plan && this.areas && isWorldAreaEvent(event)) { + if (this.planInEditing && this.areas && isWorldAreaEvent(event)) { if (event.container.data.length > 0 && 'connections_world_areas_keys' in event.container.data[0]) { return; } @@ -127,17 +127,15 @@ export class EditorComponent implements OnInit { if(bounds) { index += bounds[0]; } - this.plan.plan.splice(index, 0, this.planItemFromArea(event.previousContainer.data[event.previousIndex])); + this.planInEditing.plan.splice(index, 0, this.planItemFromArea(event.previousContainer.data[event.previousIndex])); } } dropEndHandler(event: CdkDragDrop | CdkDragDrop) { - - if (isWorldAreaEvent(event) && this.areas) { - this.plan.plan.splice(this.getEnd(), 0, this.planItemFromArea(event.previousContainer.data[event.previousIndex])); + this.planInEditing.plan.splice(this.getEnd(), 0, this.planItemFromArea(event.previousContainer.data[event.previousIndex])); } else { - moveItemInArray(this.plan.plan, event.previousIndex, this.getEnd()); + moveItemInArray(this.planInEditing.plan, event.previousIndex, this.getEnd()); } this.scrollToEnd(); @@ -148,12 +146,12 @@ export class EditorComponent implements OnInit { if (bounds) { return bounds[1]; } else { - return this.plan.plan.length; + return this.planInEditing.plan.length; } } remove(item: PlanElement) { - this.plan.plan.splice(this.planIndexOf(item), 1); + this.planInEditing.plan.splice(this.planIndexOf(item), 1); } canDrop = () => { @@ -192,13 +190,13 @@ export class EditorComponent implements OnInit { } doubleClickArea(item: WorldArea) { - this.plan.plan.splice(this.plan.plan.length, 0, this.planItemFromArea(item)); + this.planInEditing.plan.splice(this.planInEditing.plan.length, 0, this.planItemFromArea(item)); this.scrollToEnd(); } planElemFilterBounds() { if(this.planFilterAct.value !== 0) { - let bounds = this.plan.plan.filter(item => item.anchor_act === this.planFilterAct.value || this.planFilterAct.value + 1 === item.anchor_act).map((value) => this.planIndexOf(value)); + let bounds = this.planInEditing.plan.filter(item => item.anchor_act === this.planFilterAct.value || this.planFilterAct.value + 1 === item.anchor_act).map((value) => this.planIndexOf(value)); console.log("bounds, ", bounds); if (bounds.length == 2) { return bounds; @@ -206,7 +204,7 @@ export class EditorComponent implements OnInit { if(bounds.length == 1 && this.planFilterAct.value == 10) { console.log("Setting bound to last index"); - bounds[1] = this.plan.plan.length; + bounds[1] = this.planInEditing.plan.length; return bounds; } } @@ -241,7 +239,7 @@ export class EditorComponent implements OnInit { } } else { - return this.plan.plan; + return this.planInEditing.plan; } } @@ -253,12 +251,12 @@ export class EditorComponent implements OnInit { } planIndexOf(planElement: PlanElement) { - const index = this.plan.plan.indexOf(planElement); + const index = this.planInEditing.plan.indexOf(planElement); return index; } clearPlan() { - this.plan.plan.length = 0; + this.planInEditing.plan.length = 0; this.cdr.detectChanges(); } @@ -270,7 +268,7 @@ export class EditorComponent implements OnInit { }] })).subscribe(file => { if (file) { - this.planService.savePlan(file as string, this.plan); + this.planService.savePlan(file as string, this.planInEditing); } }); } @@ -287,8 +285,8 @@ export class EditorComponent implements OnInit { })).subscribe(file => { if (file) { this.planService.loadPlanNoSave(file as string).subscribe(plan => { - this.plan.plan.length = 0; - plan.plan.forEach(p => this.plan.plan.push(p)); + this.planInEditing.plan.length = 0; + plan.plan.forEach(p => this.planInEditing.plan.push(p)); }); } }); @@ -296,8 +294,8 @@ export class EditorComponent implements OnInit { loadBasePlan() { this.planService.loadBasePlan().subscribe(plan => { - this.plan.plan.length = 0; - plan.plan.forEach(p => this.plan.plan.push(p)); + this.planInEditing.plan.length = 0; + plan.plan.forEach(p => this.planInEditing.plan.push(p)); }) } diff --git a/src/app/editor/notes/notes.component.ts b/src/app/editor/notes/notes.component.ts index f1dc5d4..463d8b3 100644 --- a/src/app/editor/notes/notes.component.ts +++ b/src/app/editor/notes/notes.component.ts @@ -1,7 +1,7 @@ import { AfterViewInit, Component, ElementRef, Inject, Input, ViewChild, ViewEncapsulation } from '@angular/core'; import { MAT_DIALOG_DATA, MatDialogRef, MatDialogModule } from '@angular/material/dialog'; -import { CommonModule, NgIf } from '@angular/common'; -import { MatButton, MatButtonModule } from '@angular/material/button'; +import { CommonModule } from '@angular/common'; +import { MatButtonModule } from '@angular/material/button'; import { FormsModule } from '@angular/forms'; import { MatInputModule } from '@angular/material/input'; import { MatFormFieldModule } from '@angular/material/form-field';