Start refactoring state management
This commit is contained in:
parent
ca0bf943f7
commit
a9ad628488
3 changed files with 410 additions and 360 deletions
|
|
@ -1,93 +1,69 @@
|
|||
import { Injectable } from '@angular/core';
|
||||
import { StoreService } from './store.service';
|
||||
import { Page } from '../model/page';
|
||||
|
||||
const USER_DATA_KEY = 'life-towers.user-data.v.1';
|
||||
import { Root } from '../storage/root';
|
||||
import { Serializable } from '../model/serializable';
|
||||
import { Tower } from '../model/tower';
|
||||
import { Block } from '../model/block';
|
||||
import { IPage } from '../interfaces/persistance/page';
|
||||
import { BehaviorSubject } from 'rxjs/internal/BehaviorSubject';
|
||||
import { Observable } from 'rxjs/internal/Observable';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class DataService {
|
||||
get active(): Page {
|
||||
return this._active;
|
||||
export class DataService extends Root<Page> {
|
||||
get pages(): Array<Page> {
|
||||
return this.children;
|
||||
}
|
||||
|
||||
get pageNames(): string[] {
|
||||
return this.data.map(p => p.name);
|
||||
}
|
||||
private readonly _safeChildren: BehaviorSubject<Array<Page>> = new BehaviorSubject(null);
|
||||
readonly safeChildren$: Observable<Array<Page>> = this._safeChildren.asObservable();
|
||||
|
||||
private subscribers: (() => void)[] = [];
|
||||
private _active: Page = null;
|
||||
private data: Page[];
|
||||
private hasLoaded = new Promise(resolve => (this.afterLoadFinished = resolve));
|
||||
private afterLoadFinished: () => void;
|
||||
|
||||
constructor(private storeService: StoreService) {
|
||||
this.init();
|
||||
}
|
||||
|
||||
push(value: Page) {
|
||||
value.subscribe(() => this.save());
|
||||
this.data.push(value);
|
||||
this._active = value;
|
||||
this.save();
|
||||
}
|
||||
|
||||
remove() {
|
||||
this.data = this.data.filter(p => p !== this.active);
|
||||
this._active = this.data.length > 0 ? this.data[0] : null;
|
||||
this.save();
|
||||
}
|
||||
|
||||
subscribe(func: () => void) {
|
||||
this.subscribers.push(func);
|
||||
}
|
||||
|
||||
async changeActiveByName(name: string): Promise<void> {
|
||||
await this.hasLoaded;
|
||||
this._active = this.data.filter(p => p.name === name)[0];
|
||||
this.saveActiveIndex(this.data.indexOf(this.active));
|
||||
this.update();
|
||||
}
|
||||
|
||||
async changeActiveByIndex(index: number): Promise<void> {
|
||||
await this.hasLoaded;
|
||||
this._active = this.data[index];
|
||||
this.saveActiveIndex(index);
|
||||
this.update();
|
||||
constructor(private storeService: StoreService<Array<IPage>>) {
|
||||
super();
|
||||
this.init().catch();
|
||||
}
|
||||
|
||||
private async init() {
|
||||
this.data = await this.storeService.load();
|
||||
this.data.map(p => p.subscribe(() => this.save()));
|
||||
this._active = this.data.length > 0 ? this.data[0] : null;
|
||||
this.loadActiveIndex();
|
||||
this.afterLoadFinished();
|
||||
}
|
||||
|
||||
private save() {
|
||||
this.storeService.save(this.data);
|
||||
this.update();
|
||||
}
|
||||
|
||||
private update() {
|
||||
this.subscribers.map(f => f());
|
||||
}
|
||||
|
||||
private loadActiveIndex() {
|
||||
const userData = JSON.parse(window.localStorage.getItem(USER_DATA_KEY));
|
||||
if (userData === null) {
|
||||
return;
|
||||
const pages = await this.storeService.load();
|
||||
Serializable.childrenMap = {
|
||||
Page: {
|
||||
childrenListName: 'towers',
|
||||
childrenConstructor: Tower
|
||||
},
|
||||
Tower: {
|
||||
childrenListName: 'blocks',
|
||||
childrenConstructor: Block
|
||||
},
|
||||
Block: {
|
||||
childrenListName: null,
|
||||
childrenConstructor: null
|
||||
}
|
||||
};
|
||||
for (let page of pages) {
|
||||
new Page(this, page);
|
||||
}
|
||||
this._active = this.data[userData.index];
|
||||
this.children$.subscribe(value => {
|
||||
this.log();
|
||||
this._safeChildren.next(value);
|
||||
this.storeService.scheduleSave(this.pages);
|
||||
});
|
||||
}
|
||||
|
||||
private saveActiveIndex(index: number) {
|
||||
window.localStorage.setItem(
|
||||
USER_DATA_KEY,
|
||||
JSON.stringify({
|
||||
index
|
||||
})
|
||||
);
|
||||
addPage(name: string) {
|
||||
new Page(this, {
|
||||
name,
|
||||
userData: {},
|
||||
type: 'Page',
|
||||
towers: []
|
||||
});
|
||||
}
|
||||
|
||||
removePage(page: Page) {
|
||||
this.changeValue({
|
||||
oldValue: this.children,
|
||||
newValue: this.children.filter(c => c !== page)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@ import { Injectable } from '@angular/core';
|
|||
import { Tower } from '../model/tower';
|
||||
import { top } from '../utils/top';
|
||||
import { CancelService } from './cancel.service';
|
||||
import { Page } from '../model/page';
|
||||
import { Observable } from 'rxjs/internal/Observable';
|
||||
|
||||
export enum ModalType {
|
||||
createBlock,
|
||||
|
|
@ -44,8 +46,8 @@ export class ModalService {
|
|||
return this.createPromiseAndPushToStack(data, ModalType.editBlock);
|
||||
}
|
||||
|
||||
showSettings(): Promise<void> {
|
||||
return this.createPromiseAndPushToStack(null, ModalType.settings);
|
||||
showSettings(selectedPage: Observable<Page>): Promise<void> {
|
||||
return this.createPromiseAndPushToStack(selectedPage, ModalType.settings);
|
||||
}
|
||||
|
||||
showRemoveTower(tower: Tower): Promise<void> {
|
||||
|
|
|
|||
|
|
@ -1,82 +1,98 @@
|
|||
import { Injectable } from '@angular/core';
|
||||
import { Page } from '../model/page';
|
||||
import { IPage } from '../interfaces/persistance/page';
|
||||
|
||||
const LOCAL_STORAGE_KEY = 'life-towers.data.v.2';
|
||||
const LOCAL_STORAGE_KEY = 'life-towers.data.v.3';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class StoreService {
|
||||
private storedData: Page[];
|
||||
|
||||
export class StoreService<T> {
|
||||
private saveScheduled = false;
|
||||
private dataToSave: T;
|
||||
private storedData: T;
|
||||
private mockData: string = JSON.stringify([
|
||||
{
|
||||
name: 'Work & life',
|
||||
userData: {},
|
||||
type: 'Page',
|
||||
towers: [
|
||||
{
|
||||
name: 'work',
|
||||
baseColor: { h: 0, s: 100, l: 50 },
|
||||
baseColor: { h: 0, s: 100, l: 50, type: 'Color' },
|
||||
type: 'Tower',
|
||||
blocks: [
|
||||
{
|
||||
created: new Date(2015, 2, 13),
|
||||
tag: 'a',
|
||||
description: 'done it',
|
||||
isDone: true
|
||||
isDone: true,
|
||||
type: 'Block'
|
||||
},
|
||||
{
|
||||
created: new Date(2016, 2, 15),
|
||||
tag: 'go to school',
|
||||
description: 'done it'
|
||||
description: 'done it',
|
||||
type: 'Block'
|
||||
},
|
||||
{
|
||||
created: new Date(2017, 2, 15),
|
||||
tag: 'go to work',
|
||||
isDone: true
|
||||
isDone: true,
|
||||
type: 'Block'
|
||||
},
|
||||
{
|
||||
created: new Date(2018, 2, 13),
|
||||
tag: 'go to work',
|
||||
description: 'done it',
|
||||
isDone: true
|
||||
isDone: true,
|
||||
type: 'Block'
|
||||
},
|
||||
{
|
||||
created: new Date(2019, 3, 13),
|
||||
tag: 'go to work'
|
||||
tag: 'go to work',
|
||||
type: 'Block'
|
||||
},
|
||||
{
|
||||
created: new Date(2020, 2, 15),
|
||||
tag: 'go to school',
|
||||
description: 'done it',
|
||||
isDone: true
|
||||
isDone: true,
|
||||
type: 'Block'
|
||||
},
|
||||
{
|
||||
created: new Date(2021, 2, 15),
|
||||
tag: 'go to school'
|
||||
tag: 'go to school',
|
||||
type: 'Block'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
baseColor: { h: 180, s: 100, l: 50 },
|
||||
baseColor: { h: 180, s: 100, l: 50, type: 'Color' },
|
||||
name: 'life',
|
||||
type: 'Tower',
|
||||
blocks: [
|
||||
{
|
||||
created: new Date(2019, 3, 13),
|
||||
tag: 'go home',
|
||||
description: 'done it'
|
||||
description: 'done it',
|
||||
type: 'Block'
|
||||
},
|
||||
{
|
||||
created: new Date(2019, 4, 13),
|
||||
tag: 'go home'
|
||||
tag: 'go home',
|
||||
type: 'Block'
|
||||
},
|
||||
{
|
||||
created: new Date(2019, 4, 15),
|
||||
tag: 'go to work',
|
||||
description: 'done it'
|
||||
description: 'done it',
|
||||
type: 'Block'
|
||||
},
|
||||
{
|
||||
created: new Date(2019, 4, 15, 14),
|
||||
tag: 'go to work'
|
||||
tag: 'go to work',
|
||||
type: 'Block'
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -86,17 +102,30 @@ export class StoreService {
|
|||
|
||||
constructor() {
|
||||
const localStorageData = localStorage.getItem(LOCAL_STORAGE_KEY);
|
||||
const data = JSON.parse(localStorageData ? localStorageData : this.mockData);
|
||||
this.storedData = data.map(p => new Page(p));
|
||||
this.storedData = JSON.parse(localStorageData ? localStorageData : this.mockData) as T;
|
||||
}
|
||||
|
||||
async load(): Promise<Page[]> {
|
||||
scheduleSave(data: T) {
|
||||
this.dataToSave = data;
|
||||
if (!this.saveScheduled) {
|
||||
this.saveScheduled = true;
|
||||
setTimeout(() => {
|
||||
this.saveScheduled = false;
|
||||
this.save(this.dataToSave).catch();
|
||||
}, 0);
|
||||
}
|
||||
}
|
||||
|
||||
async load(): Promise<T> {
|
||||
console.log('load', this.storedData);
|
||||
return this.storedData;
|
||||
}
|
||||
|
||||
async save(data: Page[]) {
|
||||
async save(data: T) {
|
||||
this.storedData = data;
|
||||
console.log('save', this.storedData);
|
||||
window.localStorage.setItem(LOCAL_STORAGE_KEY, JSON.stringify(this.storedData));
|
||||
const stringified = JSON.stringify(this.storedData, null, 2);
|
||||
console.log('save');
|
||||
// console.log('save', stringified);
|
||||
window.localStorage.setItem(LOCAL_STORAGE_KEY, stringified);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue