import { Injectable, Component } from "@angular/core" import { Observable, BehaviorSubject, Subject, ReplaySubject, combineLatest } from 'rxjs' import { map, take } from 'rxjs/operators' import { LngLat, LngLatLike } from "maplibre-gl" import { DataService } from "./data.service" import { DefaultService } from "./openapi/services.gen" import { Bootstrap, Map } from "./openapi/types.gen" export type MapPos = { center: LngLatLike, zoom: number, bearing: number, pitch: number, } export const dbName = 'treetrail' // See also dbConfig in app.module export const settingsDbName = 'settings' export class Config { constructor( public user: string = undefined, public skipIntro: boolean = false, public vibrate: boolean = true, public showZones: { [zone: string]: boolean } = {}, public alertDistance = 250, public map?: Map, public bootstrap?: Bootstrap, public mapPos?: MapPos, public background: string = undefined, // public server: {} = {}, // public client: {} = {}, // public app: {} = {}, ) { } } @Injectable() export class ConfigService { constructor( public dataService: DataService, private api: DefaultService, ) { } public conf: BehaviorSubject // = new BehaviorSubject(new Config()) userPrefsKeyList = ['userName', 'skipIntro', 'vibrate', 'showZones', 'background'] bootstrap(): Observable { return this.api.getBootstrapBootstrapGet().pipe(map( resp => { this.conf = new BehaviorSubject(new Config( '', false, true, {}, 250, resp.map, resp, undefined, )) // this.conf.value.bootstrap = resp // this.conf.value.map = resp.map // this.conf.next(this.conf.value) return resp } )) } getMapCenter(): Observable { return this.conf.pipe(map( conf => { lng: conf.map.lng, lat: conf.map.lat } )) } loadUserSettings(data: unknown[]) { // TODO: assert the whole idea and use of storing the config in a BahaviourSubject data.forEach(kv => { if (kv['value']) { this.conf.value[kv['key']] = kv['value'] } }) // Update the list of types of zones from actual data this.dataService.all.subscribe( all => { let zoneTypes = new Set((Object.values(all.zones).map( zone => zone.type ))) zoneTypes.forEach( zoneType => { if (this.conf.value.showZones[zoneType] === undefined) { this.conf.value.showZones[zoneType] = false } } ) this.conf.next(this.conf.value) } ) // if (!this.conf.value.skipIntro) { // this.router.navigate(['intro'], {relativeTo: this.route}); // } } storeUserData(): void { this.userPrefsKeyList.forEach( key => this.dataService.dbService.update( settingsDbName, { key: key, value: this.conf.value[key] }).subscribe() ) } setUserPrefValue(pref: string, key: string, value: any) { let conf = this.conf.value conf[pref][key] = value this.conf.next(conf) this.storeUserData() } setUserPref(pref: string, value: any) { let conf = this.conf.value // userName is special, read (and thus stored) in bootstrap if (pref == 'userName') { conf.bootstrap.user = value this.conf.next(this.conf.value) } else { conf[pref] = value } this.conf.next(conf) this.storeUserData() } setMapPos(mapPos: MapPos): Observable { this.updateConf({mapPos: mapPos}) return this.dataService.dbService.update(settingsDbName, { key: 'mapPos', value: { center: mapPos.center, zoom: mapPos.zoom, pitch: mapPos.pitch, bearing: mapPos.bearing, } }) } updateConf(newConf: Object) { this.conf.pipe(take(1)).subscribe( conf => this.conf.next({ ...conf, ...newConf }) ) } }