From 419f2b13519e2c5380d1f2fd141ca75e2bb46b8c Mon Sep 17 00:00:00 2001 From: pietervdvn Date: Mon, 14 Feb 2022 18:18:05 +0100 Subject: [PATCH] Fix personal theme, add possibility to sync layer selection --- Logic/Osm/OsmPreferences.ts | 6 +-- Logic/State/FeatureSwitchState.ts | 6 +-- Logic/State/MapState.ts | 52 ++++++++++++++-------- Logic/UIEventSource.ts | 6 ++- Logic/Web/QueryParameters.ts | 4 +- Models/ThemeConfig/Json/LayerConfigJson.ts | 9 ++++ Models/ThemeConfig/LayerConfig.ts | 4 +- UI/DefaultGuiState.ts | 10 ++--- assets/layers/gps_track/gps_track.json | 3 +- assets/themes/personal/personal.json | 4 +- 10 files changed, 68 insertions(+), 36 deletions(-) diff --git a/Logic/Osm/OsmPreferences.ts b/Logic/Osm/OsmPreferences.ts index 14880f329..7e06bdfc6 100644 --- a/Logic/Osm/OsmPreferences.ts +++ b/Logic/Osm/OsmPreferences.ts @@ -138,7 +138,6 @@ export class OsmPreferences { const prefixes = ["mapcomplete-installed-theme", "mapcomplete-installed-themes-", "mapcomplete-current-open-changeset", "mapcomplete-personal-theme-layer"] for (const key in prefs) { for (const prefix of prefixes) { - // console.log(key) if (key.startsWith(prefix)) { console.log("Clearing ", key) self.GetPreference(key, "").setData("") @@ -173,8 +172,9 @@ export class OsmPreferences { // We merge all the preferences: new keys are uploaded // For differing values, the server overrides local changes self.preferenceSources.forEach((preference, key) => { - const osmValue = self.preferences[key] - if(osmValue === undefined){ + const osmValue = self.preferences.data[key] + console.log("Sending value to osm:", key," osm has: ", osmValue, " local has: ", preference.data) + if(osmValue === undefined && preference.data !== undefined){ // OSM doesn't know this value yet self.UploadPreference(key, preference.data) } else { diff --git a/Logic/State/FeatureSwitchState.ts b/Logic/State/FeatureSwitchState.ts index 6d73bc75a..787d6a4ee 100644 --- a/Logic/State/FeatureSwitchState.ts +++ b/Logic/State/FeatureSwitchState.ts @@ -146,17 +146,17 @@ export default class FeatureSwitchState { this.featureSwitchIsTesting = QueryParameters.GetBooleanQueryParameter( "test", - "" + testingDefaultValue, + testingDefaultValue, "If true, 'dryrun' mode is activated. The app will behave as normal, except that changes to OSM will be printed onto the console instead of actually uploaded to osm.org" ) this.featureSwitchIsDebugging = QueryParameters.GetBooleanQueryParameter( "debug", - "false", + false, "If true, shows some extra debugging help such as all the available tags on every object" ) - this.featureSwitchFakeUser = QueryParameters.GetBooleanQueryParameter("fake-user", "false", + this.featureSwitchFakeUser = QueryParameters.GetBooleanQueryParameter("fake-user", false, "If true, 'dryrun' mode is activated and a fake user account is loaded") diff --git a/Logic/State/MapState.ts b/Logic/State/MapState.ts index 07e45a0e4..16c457660 100644 --- a/Logic/State/MapState.ts +++ b/Logic/State/MapState.ts @@ -10,7 +10,6 @@ import BaseUIElement from "../../UI/BaseUIElement"; import FilteredLayer, {FilterState} from "../../Models/FilteredLayer"; import TilesourceConfig from "../../Models/ThemeConfig/TilesourceConfig"; import {QueryParameters} from "../Web/QueryParameters"; -import * as personal from "../../assets/themes/personal/personal.json"; import ShowOverlayLayer from "../../UI/ShowDataLayer/ShowOverlayLayer"; import {FeatureSourceForLayer, Tiled} from "../FeatureSource/FeatureSource"; import SimpleFeatureSource from "../FeatureSource/Sources/SimpleFeatureSource"; @@ -18,7 +17,7 @@ import {LocalStorageSource} from "../Web/LocalStorageSource"; import {GeoOperations} from "../GeoOperations"; import TitleHandler from "../Actors/TitleHandler"; import {BBox} from "../BBox"; -import MetaTagging from "../MetaTagging"; +import LayerConfig from "../../Models/ThemeConfig/LayerConfig"; /** * Contains all the leaflet-map related state @@ -120,7 +119,7 @@ export default class MapState extends UserRelatedState { this.overlayToggles = this.layoutToUse.tileLayerSources.filter(c => c.name !== undefined).map(c => ({ config: c, - isDisplayed: QueryParameters.GetBooleanQueryParameter("overlay-" + c.id, "" + c.defaultState, "Wether or not the overlay " + c.id + " is shown") + isDisplayed: QueryParameters.GetBooleanQueryParameter("overlay-" + c.id, c.defaultState, "Wether or not the overlay " + c.id + " is shown") })) this.filteredLayers = this.InitializeFilteredLayers() @@ -345,24 +344,41 @@ export default class MapState extends UserRelatedState { } + private getPref(key: string, layer: LayerConfig): UIEventSource { + const pref = this.osmConnection + .GetPreference(key) + .map(v => { + if(v === undefined){ + return undefined + } + return v === "true"; + }, [], b => { + if(b === undefined){ + return undefined + } + return "" + b; + }) + pref.setData(layer.shownByDefault) + return pref + } + private InitializeFilteredLayers() { const layoutToUse = this.layoutToUse; const flayers: FilteredLayer[] = []; for (const layer of layoutToUse.layers) { let isDisplayed: UIEventSource - if (layoutToUse.id === personal.id) { - isDisplayed = this.osmConnection.GetPreference("personal-theme-layer-" + layer.id + "-enabled") - .map(value => value === "yes", [], enabled => { - return enabled ? "yes" : ""; - }) + if (layer.syncSelection === "local") { + isDisplayed = LocalStorageSource.GetParsed(layoutToUse.id + "-layer-" + layer.id + "-enabled", layer.shownByDefault) + } else if (layer.syncSelection === "theme-only") { + isDisplayed = this.getPref(layoutToUse.id+ "-layer-" + layer.id + "-enabled", layer) + } else if (layer.syncSelection === "global") { + isDisplayed = this.getPref("layer-" + layer.id + "-enabled", layer) } else { - isDisplayed = QueryParameters.GetBooleanQueryParameter( - "layer-" + layer.id, - "" + layer.shownByDefault, - "Wether or not layer " + layer.id + " is shown" - ) + isDisplayed = QueryParameters.GetBooleanQueryParameter("layer-" + layer.id + "-enabled",layer.shownByDefault, "Wether or not layer "+layer.id+" is shown") } + + const flayer: FilteredLayer = { isDisplayed: isDisplayed, layerDef: layer, @@ -380,14 +396,14 @@ export default class MapState extends UserRelatedState { } for (const layer of layoutToUse.layers) { - if(layer.filterIsSameAs === undefined){ + if (layer.filterIsSameAs === undefined) { continue } const toReuse = flayers.find(l => l.layerDef.id === layer.filterIsSameAs) - if(toReuse === undefined){ - throw "Error in layer "+layer.id+": it defines that it should be use the filters of "+layer.filterIsSameAs+", but this layer was not loaded" + if (toReuse === undefined) { + throw "Error in layer " + layer.id + ": it defines that it should be use the filters of " + layer.filterIsSameAs + ", but this layer was not loaded" } - console.warn("Linking filter and isDisplayed-states of "+layer.id+" and "+layer.filterIsSameAs) + console.warn("Linking filter and isDisplayed-states of " + layer.id + " and " + layer.filterIsSameAs) const selfLayer = flayers.findIndex(l => l.layerDef.id === layer.id) flayers[selfLayer] = { isDisplayed: toReuse.isDisplayed, @@ -395,7 +411,7 @@ export default class MapState extends UserRelatedState { appliedFilters: toReuse.appliedFilters }; } - + return new UIEventSource(flayers); } diff --git a/Logic/UIEventSource.ts b/Logic/UIEventSource.ts index b0646b117..fad6e0737 100644 --- a/Logic/UIEventSource.ts +++ b/Logic/UIEventSource.ts @@ -326,8 +326,10 @@ export class UIEventSource { this.addCallback((latest) => otherSource.setData(latest)); const self = this; otherSource.addCallback((latest) => self.setData(latest)); - if (reverseOverride && otherSource.data !== undefined) { - this.setData(otherSource.data); + if (reverseOverride) { + if(otherSource.data !== undefined){ + this.setData(otherSource.data); + } } else if (this.data === undefined) { this.setData(otherSource.data); } else { diff --git a/Logic/Web/QueryParameters.ts b/Logic/Web/QueryParameters.ts index a268cb8d2..6dc084305 100644 --- a/Logic/Web/QueryParameters.ts +++ b/Logic/Web/QueryParameters.ts @@ -32,8 +32,8 @@ export class QueryParameters { return source; } - public static GetBooleanQueryParameter(key: string, deflt: string, documentation?: string): UIEventSource { - return QueryParameters.GetQueryParameter(key, deflt, documentation).map(str => str === "true", [], b => "" + b) + public static GetBooleanQueryParameter(key: string, deflt: boolean, documentation?: string): UIEventSource { + return QueryParameters.GetQueryParameter(key, ""+ deflt, documentation).map(str => str === "true", [], b => "" + b) } diff --git a/Models/ThemeConfig/Json/LayerConfigJson.ts b/Models/ThemeConfig/Json/LayerConfigJson.ts index 8f15b9a7a..5c32c1986 100644 --- a/Models/ThemeConfig/Json/LayerConfigJson.ts +++ b/Models/ThemeConfig/Json/LayerConfigJson.ts @@ -399,4 +399,13 @@ export interface LayerConfigJson { */ units?: UnitConfigJson[] + /** + * If set, synchronizes wether or not this layer is selected. + * + * no: Do not sync at all, always revert to default + * local: keep selection on local storage + * theme-only: sync via OSM, but this layer will only be toggled in this theme + * global: all layers with this ID will be synced accross all themes + */ + syncSelection?: "no" | "local" | "theme-only" | "global" } \ No newline at end of file diff --git a/Models/ThemeConfig/LayerConfig.ts b/Models/ThemeConfig/LayerConfig.ts index f503aa7f3..f650aef5d 100644 --- a/Models/ThemeConfig/LayerConfig.ts +++ b/Models/ThemeConfig/LayerConfig.ts @@ -61,6 +61,8 @@ export default class LayerConfig extends WithContextLoader { public readonly filterIsSameAs: string; public readonly forceLoad: boolean; + public readonly syncSelection: "no" | "local" | "theme-only" | "global" + constructor( json: LayerConfigJson, context?: string, @@ -90,7 +92,7 @@ export default class LayerConfig extends WithContextLoader { } this.maxAgeOfCache = json.source.maxCacheAge ?? 24 * 60 * 60 * 30 - + this.syncSelection = json.syncSelection; const osmTags = TagUtils.Tag( json.source.osmTags, context + "source.osmTags" diff --git a/UI/DefaultGuiState.ts b/UI/DefaultGuiState.ts index 21d471474..b67723c10 100644 --- a/UI/DefaultGuiState.ts +++ b/UI/DefaultGuiState.ts @@ -22,27 +22,27 @@ export class DefaultGuiState { )); this.welcomeMessageIsOpened = QueryParameters.GetBooleanQueryParameter( "welcome-control-toggle", - "false", + false, "Whether or not the welcome panel is shown" ) this.downloadControlIsOpened = QueryParameters.GetBooleanQueryParameter( "download-control-toggle", - "false", + false, "Whether or not the download panel is shown" ) this.filterViewIsOpened = QueryParameters.GetBooleanQueryParameter( "filter-toggle", - "false", + false, "Whether or not the filter view is shown" ) this.copyrightViewIsOpened = QueryParameters.GetBooleanQueryParameter( "copyright-toggle", - "false", + false, "Whether or not the copyright view is shown" ) this.currentViewControlIsOpened = QueryParameters.GetBooleanQueryParameter( "currentview-toggle", - "false", + false, "Whether or not the current view box is shown" ) const states = { diff --git a/assets/layers/gps_track/gps_track.json b/assets/layers/gps_track/gps_track.json index ff7a9f4c2..596c6ca80 100644 --- a/assets/layers/gps_track/gps_track.json +++ b/assets/layers/gps_track/gps_track.json @@ -34,5 +34,6 @@ "width": 3, "color": "#bb000077" } - ] + ], + "syncSelection": "global" } \ No newline at end of file diff --git a/assets/themes/personal/personal.json b/assets/themes/personal/personal.json index a795c88f8..c9e7d8d57 100644 --- a/assets/themes/personal/personal.json +++ b/assets/themes/personal/personal.json @@ -40,7 +40,9 @@ "#note": "The 'overpassMaxZoom' should be exactly the same as or less then the overrideAll", "overpassMaxZoom": 15, "overrideAll": { - "minZoom": 16 + "minZoom": 16, + "syncSelection": "theme", + "shownByDefault": false }, "layers": [] } \ No newline at end of file