From 106d9927aaa7027686188dee7d2d3e9f95d2bee8 Mon Sep 17 00:00:00 2001 From: pietervdvn Date: Sat, 19 Jun 2021 19:16:20 +0200 Subject: [PATCH] Fixed the personal layer --- Customizations/JSON/LayerConfig.ts | 3 +- Logic/UIEventSource.ts | 13 +- UI/BigComponents/PersonalLayersPanel.ts | 212 +++++++++++------------- 3 files changed, 110 insertions(+), 118 deletions(-) diff --git a/Customizations/JSON/LayerConfig.ts b/Customizations/JSON/LayerConfig.ts index fa615d7a6..10d8ddfe1 100644 --- a/Customizations/JSON/LayerConfig.ts +++ b/Customizations/JSON/LayerConfig.ts @@ -12,7 +12,6 @@ import Combine from "../../UI/Base/Combine"; import {VariableUiElement} from "../../UI/Base/VariableUIElement"; import {UIEventSource} from "../../Logic/UIEventSource"; import {FixedUiElement} from "../../UI/Base/FixedUiElement"; -import {SubstitutedTranslation} from "../../UI/SubstitutedTranslation"; import SourceConfig from "./SourceConfig"; import {TagsFilter} from "../../Logic/Tags/TagsFilter"; import {Tag} from "../../Logic/Tags/Tag"; @@ -290,7 +289,7 @@ export default class LayerConfig { } - public GenerateLeafletStyle(tags: UIEventSource, clickable: boolean): + public GenerateLeafletStyle(tags: UIEventSource, clickable: boolean, widthHeight= "100%"): { icon: { diff --git a/Logic/UIEventSource.ts b/Logic/UIEventSource.ts index 63ed45d09..7fa5a432d 100644 --- a/Logic/UIEventSource.ts +++ b/Logic/UIEventSource.ts @@ -92,9 +92,16 @@ export class UIEventSource { } } - public map(f: ((T) => J), + /** + * Monoidal map: + * Given a function 'f', will construct a new UIEventSource where the contents will always be "f(this.data)' + * @param f: The transforming function + * @param extraSources: also trigger the update if one of these sources change + * @param g: a 'backfunction to let the sync run in two directions. (data of the new UIEVEntSource, currentData) => newData + */ + public map(f: ((t: T) => J), extraSources: UIEventSource[] = [], - g: ((J) => T) = undefined): UIEventSource { + g: ((j:J, t:T) => T) = undefined): UIEventSource { const self = this; const newSource = new UIEventSource( @@ -113,7 +120,7 @@ export class UIEventSource { if (g !== undefined) { newSource.addCallback((latest) => { - self.setData(g(latest)); + self.setData(g(latest, self.data)); }) } diff --git a/UI/BigComponents/PersonalLayersPanel.ts b/UI/BigComponents/PersonalLayersPanel.ts index 51438c759..7c30d916a 100644 --- a/UI/BigComponents/PersonalLayersPanel.ts +++ b/UI/BigComponents/PersonalLayersPanel.ts @@ -1,6 +1,3 @@ -import {UIEventSource} from "../../Logic/UIEventSource"; -import {UIElement} from "../UIElement"; -import LayoutConfig from "../../Customizations/JSON/LayoutConfig"; import {AllKnownLayouts} from "../../Customizations/AllKnownLayouts"; import Svg from "../../Svg"; import State from "../../State"; @@ -8,130 +5,119 @@ import Combine from "../Base/Combine"; import Toggle from "../Input/Toggle"; import {SubtleButton} from "../Base/SubtleButton"; import Translations from "../i18n/Translations"; -import * as personal from "../../assets/themes/personalLayout/personalLayout.json" -import Locale from "../i18n/Locale"; import BaseUIElement from "../BaseUIElement"; +import {VariableUiElement} from "../Base/VariableUIElement"; +import LayerConfig from "../../Customizations/JSON/LayerConfig"; +import Img from "../Base/Img"; +import {UIEventSource} from "../../Logic/UIEventSource"; -export default class PersonalLayersPanel extends UIElement { - private checkboxes: BaseUIElement[] = []; +export default class PersonalLayersPanel extends VariableUiElement { constructor() { - super(State.state.favouriteLayers); - this.ListenTo(State.state.osmConnection.userDetails); - this.ListenTo(Locale.language); - this.UpdateView([]); - const self = this; - State.state.installedThemes.addCallback(extraThemes => { - self.UpdateView(extraThemes.map(layout => layout.layout)); - }) - } + super( + State.state.installedThemes.map(installedThemes => { + const t = Translations.t.favourite; + // Lets get all the layers + const allThemes = AllKnownLayouts.layoutsList.concat(installedThemes.map(layout => layout.layout)) + .filter(theme => !theme.hideFromOverview) - private UpdateView(extraThemes: LayoutConfig[]) { - this.checkboxes = []; - const favs = State.state.favouriteLayers.data ?? []; - const controls = new Map>(); - const allLayouts = AllKnownLayouts.layoutsList.concat(extraThemes); - for (const layout of allLayouts) { - if (layout.id === personal.id) { - continue; - } - - if(layout.hideFromOverview){ - continue; - } - - const header = - new Combine([ - ``, - "", - layout.title, - "
", - layout.shortDescription ?? "" - ]).SetClass("block p1 overflow-auto rounded") - .SetStyle("background: #eee;") - this.checkboxes.push(header); - - for (const layer of layout.layers) { - if(layer === undefined){ - console.warn("Undefined layer for ",layout.id) - continue; - } - if (typeof layer === "string") { - continue; - } - let icon :BaseUIElement = layer.GenerateLeafletStyle(new UIEventSource({id:"node/-1"}), false).icon.html - ?? Svg.checkmark_svg(); - let iconUnset =new Combine([icon]); - icon.SetClass("single-layer-selection-toggle") - iconUnset.SetClass("single-layer-selection-toggle") - - - let name = layer.name ?? layer.id; - if (name === undefined) { - continue; - } - const content = new Combine([ - "", - name, - " ", - layer.description !== undefined ? new Combine(["
", layer.description]) : "", - ]) - - - const cb = new Toggle( - new SubtleButton( - icon, - content), - new SubtleButton( - iconUnset.SetStyle("opacity:0.1"), - new Combine(["", - content, - "" - ])), - controls[layer.id] ?? (favs.indexOf(layer.id) >= 0) - ).ToggleOnClick(); - cb.SetClass("custom-layer-checkbox"); - controls[layer.id] = cb.isEnabled; - - cb.isEnabled.addCallback((isEnabled) => { - const favs = State.state.favouriteLayers; - if (isEnabled) { - if(favs.data.indexOf(layer.id)>= 0){ - return; // Already added + const allLayers = [] + { + const seenLayers = new Set() + for (const layers of allThemes.map(theme => theme.layers)) { + for (const layer of layers) { + if (seenLayers.has(layer.id)) { + continue + } + seenLayers.add(layer.id) + allLayers.push(layer) } - favs.data.push(layer.id); - } else { - favs.data.splice(favs.data.indexOf(layer.id), 1); } - favs.ping(); - }) + } - this.checkboxes.push(cb); + // Time to create a panel based on them! + const panel: BaseUIElement = new Combine(allLayers.map(PersonalLayersPanel.CreateLayerToggle)); - } - - } - - State.state.favouriteLayers.addCallback((layers) => { - for (const layerId of layers) { - controls[layerId]?.setData(true); - } - }); + return new Toggle( + new Combine([ + t.panelIntro.Clone(), + panel + ]).SetClass("flex flex-col"), + new SubtleButton( + Svg.osm_logo_ui(), + t.loginNeeded.Clone().SetClass("text-center") + ).onClick(() => State.state.osmConnection.AttemptLogin()), + State.state.osmConnection.isLoggedIn + ) + }) + ) } - InnerRender(): BaseUIElement { - const t = Translations.t.favourite; + /*** + * Creates a toggle for the given layer, which'll update State.state.favouriteLayers right away + * @param layer + * @constructor + * @private + */ + private static CreateLayerToggle(layer: LayerConfig): Toggle { + const iconUrl = layer.icon.GetRenderValue({id: "node/-1"}).txt + let icon :BaseUIElement =new Combine([ layer.GenerateLeafletStyle( + new UIEventSource({id: "node/-1"}), + false, + "2em" + ).icon.html]).SetClass("relative") + let iconUnset =new Combine([ layer.GenerateLeafletStyle( + new UIEventSource({id: "node/-1"}), + false, + "2em" + ).icon.html]).SetClass("relative") + + iconUnset.SetStyle("opacity:0.1") + + let name = layer.name ; + if (name === undefined) { + return undefined; + } + const content = new Combine([ + Translations.WT(name).Clone().SetClass("font-bold"), + Translations.WT(layer.description)?.Clone() + ]).SetClass("flex flex-col") + + const contentUnselected = new Combine([ + Translations.WT(name).Clone().SetClass("font-bold"), + Translations.WT(layer.description)?.Clone() + ]).SetClass("flex flex-col line-through") + return new Toggle( - new Combine([ - t.panelIntro, - ...this.checkboxes - ]), - t.loginNeeded, - State.state.osmConnection.isLoggedIn - - ) + new SubtleButton( + icon, + content ), + new SubtleButton( + iconUnset, + contentUnselected + ), + State.state.favouriteLayers.map(favLayers => { + return favLayers.indexOf(layer.id) >= 0 + }, [], (selected, current) => { + if (!selected && current.indexOf(layer.id) <= 0) { + // Not selected and not contained: nothing to change: we return current as is + return current; + } + if (selected && current.indexOf(layer.id) >= 0) { + // Selected and contained: this is fine! + return current; + } + const clone = [...current] + if (selected) { + clone.push(layer.id) + } else { + clone.splice(clone.indexOf(layer.id), 1) + } + return clone + }) + ).ToggleOnClick(); }