From 9427083939bb6958b07e6fd48f5356101f06e681 Mon Sep 17 00:00:00 2001 From: Pieter Vander Vennet Date: Thu, 17 Oct 2024 02:10:25 +0200 Subject: [PATCH] Fix: see #2212: actually save custom themes as visited --- src/Logic/Actors/GeoLocationHandler.ts | 2 +- src/Logic/Actors/InitialMapPositioning.ts | 2 +- src/Logic/DetermineLayout.ts | 4 +- src/Logic/Osm/Changes.ts | 2 +- src/Logic/Osm/OsmConnection.ts | 4 +- src/Logic/Osm/OsmPreferences.ts | 15 +++++-- src/Logic/State/GeoLocationState.ts | 2 +- src/Logic/State/UserRelatedState.ts | 32 +++++++++----- src/Logic/UIEventSource.ts | 52 +++++++++++++--------- src/Logic/Web/LocalStorageSource.ts | 53 +++++++++++++---------- src/Models/FilteredLayer.ts | 2 +- src/Models/MenuState.ts | 2 +- src/Models/ThemeViewState.ts | 19 +++++++- src/UI/AllThemesGui.svelte | 1 - src/UI/DownloadFlow/DownloadPanel.svelte | 4 +- src/UI/Popup/Notes/CreateNewNote.svelte | 2 +- src/UI/Studio/EditLayerState.ts | 2 +- src/UI/Studio/TagRenderingInput.svelte | 2 +- src/UI/i18n/Locale.ts | 2 +- 19 files changed, 129 insertions(+), 75 deletions(-) diff --git a/src/Logic/Actors/GeoLocationHandler.ts b/src/Logic/Actors/GeoLocationHandler.ts index e7143d374..1909daa52 100644 --- a/src/Logic/Actors/GeoLocationHandler.ts +++ b/src/Logic/Actors/GeoLocationHandler.ts @@ -183,7 +183,7 @@ export default class GeoLocationHandler { } private initUserLocationTrail() { - const features = LocalStorageSource.GetParsed("gps_location_history", []) + const features = LocalStorageSource.getParsed("gps_location_history", []) const now = new Date().getTime() features.data = features.data.filter((ff) => { if (ff.properties === undefined) { diff --git a/src/Logic/Actors/InitialMapPositioning.ts b/src/Logic/Actors/InitialMapPositioning.ts index 027195d58..f62a11fd8 100644 --- a/src/Logic/Actors/InitialMapPositioning.ts +++ b/src/Logic/Actors/InitialMapPositioning.ts @@ -31,7 +31,7 @@ export default class InitialMapPositioning { deflt: number, docs: string ): UIEventSource { - const localStorage = LocalStorageSource.Get(key) + const localStorage = LocalStorageSource.get(key) const previousValue = localStorage.data const src = UIEventSource.asFloat( QueryParameters.GetQueryParameter(key, "" + deflt, docs).syncWith(localStorage) diff --git a/src/Logic/DetermineLayout.ts b/src/Logic/DetermineLayout.ts index 0225b16b9..9a4e5f4e2 100644 --- a/src/Logic/DetermineLayout.ts +++ b/src/Logic/DetermineLayout.ts @@ -132,14 +132,14 @@ export default class DetermineLayout { let json: any // layoutFromBase64 contains the name of the theme. This is partly to do tracking with goat counter - const dedicatedHashFromLocalStorage = LocalStorageSource.Get( + const dedicatedHashFromLocalStorage = LocalStorageSource.get( "user-layout-" + userLayoutParam.data?.replace(" ", "_") ) if (dedicatedHashFromLocalStorage.data?.length < 10) { dedicatedHashFromLocalStorage.setData(undefined) } - const hashFromLocalStorage = LocalStorageSource.Get("last-loaded-user-layout") + const hashFromLocalStorage = LocalStorageSource.get("last-loaded-user-layout") if (hash.length < 10) { hash = dedicatedHashFromLocalStorage.data ?? hashFromLocalStorage.data } else { diff --git a/src/Logic/Osm/Changes.ts b/src/Logic/Osm/Changes.ts index a44aa4a02..113fc27a4 100644 --- a/src/Logic/Osm/Changes.ts +++ b/src/Logic/Osm/Changes.ts @@ -24,7 +24,7 @@ import FeaturePropertiesStore from "../FeatureSource/Actors/FeaturePropertiesSto */ export class Changes { public readonly pendingChanges: UIEventSource = - LocalStorageSource.GetParsed("pending-changes", []) + LocalStorageSource.getParsed("pending-changes", []) public readonly allChanges = new UIEventSource(undefined) public readonly state: { allElements?: IndexedFeatureSource diff --git a/src/Logic/Osm/OsmConnection.ts b/src/Logic/Osm/OsmConnection.ts index d6be0d87c..f4732adfa 100644 --- a/src/Logic/Osm/OsmConnection.ts +++ b/src/Logic/Osm/OsmConnection.ts @@ -210,7 +210,7 @@ export class OsmConnection { console.log("Trying to log in...") this.updateAuthObject() - LocalStorageSource.Get("location_before_login").setData( + LocalStorageSource.get("location_before_login").setData( Utils.runningFromConsole ? undefined : window.location.href ) this.auth.xhr( @@ -521,7 +521,7 @@ export class OsmConnection { this.auth.authenticate(function () { // Fully authed at this point console.log("Authentication successful!") - const previousLocation = LocalStorageSource.Get("location_before_login") + const previousLocation = LocalStorageSource.get("location_before_login") callback(previousLocation.data) }) } diff --git a/src/Logic/Osm/OsmPreferences.ts b/src/Logic/Osm/OsmPreferences.ts index b444cf469..3686f743c 100644 --- a/src/Logic/Osm/OsmPreferences.ts +++ b/src/Logic/Osm/OsmPreferences.ts @@ -6,7 +6,11 @@ import { Utils } from "../../Utils" export class OsmPreferences { - private preferences: Record> = {} + /** + * A 'cache' of all the preference stores + * @private + */ + private readonly preferences: Record> = {} private localStorageInited: Set = new Set() /** @@ -15,6 +19,10 @@ export class OsmPreferences { */ private seenKeys: string[] = [] + /** + * Contains a dictionary which has all preferences + * @private + */ private readonly _allPreferences: UIEventSource> = new UIEventSource({}) public readonly allPreferences: Store>> = this._allPreferences private readonly _fakeUser: boolean @@ -51,6 +59,7 @@ export class OsmPreferences { this.setPreferencesAll(key, value) } pref.addCallback(v => { + console.log("Got an update:", key, "--->", v) this.uploadKvSplit(key, v) this.setPreferencesAll(key, v) }) @@ -101,11 +110,11 @@ export class OsmPreferences { key = key.replace(/[:/"' {}.%\\]/g, "") - const localStorage = LocalStorageSource.Get(key) + const localStorage = LocalStorageSource.get(key) // cached if (localStorage.data === "null" || localStorage.data === "undefined") { localStorage.set(undefined) } - const pref: UIEventSource = this.initPreference(key, localStorage.data ?? defaultValue) + const pref: UIEventSource = this.initPreference(key, localStorage.data ?? defaultValue) // cached if (this.localStorageInited.has(key)) { return pref } diff --git a/src/Logic/State/GeoLocationState.ts b/src/Logic/State/GeoLocationState.ts index 03ba3a04d..967c48aa9 100644 --- a/src/Logic/State/GeoLocationState.ts +++ b/src/Logic/State/GeoLocationState.ts @@ -58,7 +58,7 @@ export class GeoLocationState { * @private */ private readonly _previousLocationGrant: UIEventSource = - LocalStorageSource.GetParsed("geolocation-permissions", false) + LocalStorageSource.getParsed("geolocation-permissions", false) /** * Used to detect a permission retraction diff --git a/src/Logic/State/UserRelatedState.ts b/src/Logic/State/UserRelatedState.ts index e7ac6c931..d958c3cf4 100644 --- a/src/Logic/State/UserRelatedState.ts +++ b/src/Logic/State/UserRelatedState.ts @@ -43,8 +43,8 @@ export class OptionallySyncedHistory { "sync", ) const synced = this.synced = UIEventSource.asObject(osmconnection.getPreference(key + "-history"), []) - const local = this.local = LocalStorageSource.GetParsed(key + "-history", []) - const thisSession = this.thisSession = new UIEventSource([], "optionally-synced:"+key+"(session only)") + const local = this.local = LocalStorageSource.getParsed(key + "-history", []) + const thisSession = this.thisSession = new UIEventSource([], "optionally-synced:" + key + "(session only)") this.syncPreference.addCallback(syncmode => { if (syncmode === "sync") { let list = [...thisSession.data, ...synced.data].slice(0, maxHistory) @@ -164,7 +164,7 @@ export default class UserRelatedState { "button" | "button_click_right" | "button_click" | "click" | "click_right" >("button_click_right") - public readonly showScale : UIEventSource + public readonly showScale: UIEventSource /** * Preferences as tags exposes many preferences and state properties as record. @@ -202,8 +202,8 @@ export default class UserRelatedState { this.a11y = this.osmConnection.getPreference("a11y") this.mangroveIdentity = new MangroveIdentity( - this.osmConnection.getPreference("identity", undefined,"mangrove"), - this.osmConnection.getPreference("identity-creation-date", undefined,"mangrove"), + this.osmConnection.getPreference("identity", undefined, "mangrove"), + this.osmConnection.getPreference("identity-creation-date", undefined, "mangrove"), ) this.preferredBackgroundLayer = this.osmConnection.getPreference("preferred-background-layer") @@ -211,7 +211,7 @@ export default class UserRelatedState { "preferences-add-new-mode", "button_click_right", ) - this.showScale = UIEventSource.asBoolean(this.osmConnection.GetPreference("preference-show-scale","false")) + this.showScale = UIEventSource.asBoolean(this.osmConnection.GetPreference("preference-show-scale", "false")) this.imageLicense = this.osmConnection.getPreference("pictures-license", "CC0") this.installedUserThemes = UserRelatedState.initInstalledUserThemes(osmConnection) @@ -272,7 +272,19 @@ export default class UserRelatedState { } } - public getUnofficialTheme(id: string): (MinimalLayoutInformation & { definition }) | undefined { + /** + * Adds a newly visited unofficial theme (or update the info). + * + * @param themeInfo note that themeInfo.id should be the URL where it was found + */ + public addUnofficialTheme(themeInfo: MinimalLayoutInformation) { + const pref = this.osmConnection.getPreference("unofficial-theme-" + themeInfo.id) + this.osmConnection.isLoggedIn.when( + () => pref.set(JSON.stringify(themeInfo)) + ) + } + + public getUnofficialTheme(id: string): MinimalLayoutInformation | undefined { const pref = this.osmConnection.getPreference("unofficial-theme-" + id) const str = pref.data @@ -282,7 +294,7 @@ export default class UserRelatedState { } try { - return JSON.parse(str) + return JSON.parse(str) } catch (e) { console.warn( "Removing theme " + @@ -516,10 +528,10 @@ export default class UserRelatedState { // Language is managed separately continue } - if(tags[key] === null){ + if (tags[key] === null) { continue } - let pref = this.osmConnection.GetPreference(key, undefined, {prefix: ""}) + let pref = this.osmConnection.GetPreference(key, undefined, { prefix: "" }) pref.set(tags[key]) } diff --git a/src/Logic/UIEventSource.ts b/src/Logic/UIEventSource.ts index 15a27da2c..022cbe869 100644 --- a/src/Logic/UIEventSource.ts +++ b/src/Logic/UIEventSource.ts @@ -23,7 +23,7 @@ export class Stores { } public static FromPromiseWithErr( - promise: Promise + promise: Promise, ): Store<{ success: T } | { error: any }> { return UIEventSource.FromPromiseWithErr(promise) } @@ -133,13 +133,13 @@ export abstract class Store implements Readable { abstract map( f: (t: T) => J, extraStoresToWatch: Store[], - callbackDestroyFunction: (f: () => void) => void + callbackDestroyFunction: (f: () => void) => void, ): Store public mapD( f: (t: Exclude) => J, extraStoresToWatch?: Store[], - callbackDestroyFunction?: (f: () => void) => void + callbackDestroyFunction?: (f: () => void) => void, ): Store { return this.map((t) => { if (t === undefined) { @@ -176,7 +176,7 @@ export abstract class Store implements Readable { abstract addCallbackAndRun(callback: (data: T) => void): () => void public withEqualityStabilized( - comparator: (t: T | undefined, t1: T | undefined) => boolean + comparator: (t: T | undefined, t1: T | undefined) => boolean, ): Store { let oldValue = undefined return this.map((v) => { @@ -342,6 +342,16 @@ export abstract class Store implements Readable { } public abstract destroy() + + when(callback: () => void, condition?: (v:T) => boolean) { + condition ??= v => v === true + this.addCallbackAndRunD(v => { + if ( condition(v)) { + callback() + return true + } + }) + } } export class ImmutableStore extends Store { @@ -384,7 +394,7 @@ export class ImmutableStore extends Store { map( f: (t: T) => J, extraStores: Store[] = undefined, - ondestroyCallback?: (f: () => void) => void + ondestroyCallback?: (f: () => void) => void, ): ImmutableStore { if (extraStores?.length > 0) { return new MappedStore(this, f, extraStores, undefined, f(this.data), ondestroyCallback) @@ -454,7 +464,7 @@ class ListenerTracker { let endTime = new Date().getTime() / 1000 if (endTime - startTime > 500) { console.trace( - "Warning: a ping took more then 500ms; this is probably a performance issue" + "Warning: a ping took more then 500ms; this is probably a performance issue", ) } if (toDelete !== undefined) { @@ -496,7 +506,7 @@ class MappedStore extends Store { extraStores: Store[], upstreamListenerHandler: ListenerTracker | undefined, initialState: T, - onDestroy?: (f: () => void) => void + onDestroy?: (f: () => void) => void, ) { super() this._upstream = upstream @@ -536,7 +546,7 @@ class MappedStore extends Store { map( f: (t: T) => J, extraStores: Store[] = undefined, - ondestroyCallback?: (f: () => void) => void + ondestroyCallback?: (f: () => void) => void, ): Store { let stores: Store[] = undefined if (extraStores?.length > 0 || this._extraStores?.length > 0) { @@ -558,7 +568,7 @@ class MappedStore extends Store { stores, this._callbacks, f(this.data), - ondestroyCallback + ondestroyCallback, ) } @@ -614,7 +624,7 @@ class MappedStore extends Store { this._unregisterFromUpstream = this._upstream.addCallback((_) => self.update()) this._unregisterFromExtraStores = this._extraStores?.map((store) => - store?.addCallback((_) => self.update()) + store?.addCallback((_) => self.update()), ) this._callbacksAreRegistered = true } @@ -651,7 +661,7 @@ export class UIEventSource extends Store implements Writable { public static flatten( source: Store>, - possibleSources?: Store[] + possibleSources?: Store[], ): UIEventSource { const sink = new UIEventSource(source.data?.data) @@ -680,7 +690,7 @@ export class UIEventSource extends Store implements Writable { */ public static FromPromise( promise: Promise, - onError: (e) => void = undefined + onError: (e) => void = undefined, ): UIEventSource { const src = new UIEventSource(undefined) promise?.then((d) => src.setData(d)) @@ -701,7 +711,7 @@ export class UIEventSource extends Store implements Writable { * @constructor */ public static FromPromiseWithErr( - promise: Promise + promise: Promise, ): UIEventSource<{ success: T } | { error: any } | undefined> { const src = new UIEventSource<{ success: T } | { error: any }>(undefined) promise @@ -733,7 +743,7 @@ export class UIEventSource extends Store implements Writable { return undefined } return "" + fl - } + }, ) } @@ -764,7 +774,7 @@ export class UIEventSource extends Store implements Writable { return undefined } return "" + fl - } + }, ) } @@ -772,7 +782,7 @@ export class UIEventSource extends Store implements Writable { return stringUIEventSource.sync( (str) => str === "true", [], - (b) => "" + b + (b) => "" + b, ) } @@ -790,7 +800,7 @@ export class UIEventSource extends Store implements Writable { } }, [], - (b) => JSON.stringify(b) ?? "" + (b) => JSON.stringify(b) ?? "", ) } @@ -880,7 +890,7 @@ export class UIEventSource extends Store implements Writable { public map( f: (t: T) => J, extraSources: Store[] = [], - onDestroy?: (f: () => void) => void + onDestroy?: (f: () => void) => void, ): Store { return new MappedStore(this, f, extraSources, this._callbacks, f(this.data), onDestroy) } @@ -892,7 +902,7 @@ export class UIEventSource extends Store implements Writable { public mapD( f: (t: Exclude) => J, extraSources: Store[] = [], - callbackDestroyFunction?: (f: () => void) => void + callbackDestroyFunction?: (f: () => void) => void, ): Store { return new MappedStore( this, @@ -910,7 +920,7 @@ export class UIEventSource extends Store implements Writable { this.data === undefined || this.data === null ? this.data : f(this.data), - callbackDestroyFunction + callbackDestroyFunction, ) } @@ -930,7 +940,7 @@ export class UIEventSource extends Store implements Writable { f: (t: T) => J, extraSources: Store[], g: (j: J, t: T) => T, - allowUnregister = false + allowUnregister = false, ): UIEventSource { const self = this diff --git a/src/Logic/Web/LocalStorageSource.ts b/src/Logic/Web/LocalStorageSource.ts index 0923a4a7c..e1453597e 100644 --- a/src/Logic/Web/LocalStorageSource.ts +++ b/src/Logic/Web/LocalStorageSource.ts @@ -4,8 +4,11 @@ import { UIEventSource } from "../UIEventSource" * UIEventsource-wrapper around localStorage */ export class LocalStorageSource { - static GetParsed(key: string, defaultValue: T): UIEventSource { - return LocalStorageSource.Get(key).sync( + + private static readonly _cache: Record> = {} + + static getParsed(key: string, defaultValue: T): UIEventSource { + return LocalStorageSource.get(key).sync( (str) => { if (str === undefined) { return defaultValue @@ -17,34 +20,40 @@ export class LocalStorageSource { } }, [], - (value) => JSON.stringify(value) + (value) => JSON.stringify(value), ) } - static Get(key: string, defaultValue: string = undefined): UIEventSource { + static get(key: string, defaultValue: string = undefined): UIEventSource { + const cached = LocalStorageSource._cache[key] + if (cached) { + return cached + } + let saved = defaultValue try { - let saved = localStorage.getItem(key) + saved = localStorage.getItem(key) if (saved === "undefined") { saved = undefined } - const source = new UIEventSource(saved ?? defaultValue, "localstorage:" + key) - - source.addCallback((data) => { - if(data === undefined || data === "" || data === null){ - localStorage.removeItem(key) - return - } - try { - localStorage.setItem(key, data) - } catch (e) { - // Probably exceeded the quota with this item! - // Lets nuke everything - localStorage.clear() - } - }) - return source } catch (e) { - return new UIEventSource(defaultValue) + console.error("Could not get value", key, "from local storage") } + const source = new UIEventSource(saved ?? defaultValue, "localstorage:" + key) + + source.addCallback((data) => { + if (data === undefined || data === "" || data === null) { + localStorage.removeItem(key) + return + } + try { + localStorage.setItem(key, data) + } catch (e) { + // Probably exceeded the quota with this item! + // Let's nuke everything + localStorage.clear() + } + }) + LocalStorageSource._cache[key] = source + return source } } diff --git a/src/Models/FilteredLayer.ts b/src/Models/FilteredLayer.ts index 0077039f4..79c59c03c 100644 --- a/src/Models/FilteredLayer.ts +++ b/src/Models/FilteredLayer.ts @@ -86,7 +86,7 @@ export default class FilteredLayer { ) { let isDisplayed: UIEventSource if (layer.syncSelection === "local") { - isDisplayed = LocalStorageSource.GetParsed( + isDisplayed = LocalStorageSource.getParsed( context + "-layer-" + layer.id + "-enabled", layer.shownByDefault, ) diff --git a/src/Models/MenuState.ts b/src/Models/MenuState.ts index 6d3e5f868..a7b43523e 100644 --- a/src/Models/MenuState.ts +++ b/src/Models/MenuState.ts @@ -57,7 +57,7 @@ export class MenuState { }) } - const visitedBefore = LocalStorageSource.GetParsed( + const visitedBefore = LocalStorageSource.getParsed( themeid + "thememenuisopened", false ) diff --git a/src/Models/ThemeViewState.ts b/src/Models/ThemeViewState.ts index 6ce86801d..933215c92 100644 --- a/src/Models/ThemeViewState.ts +++ b/src/Models/ThemeViewState.ts @@ -370,7 +370,7 @@ export default class ThemeViewState implements SpecialVisualizationState { this.changes, this.geolocation.geolocationState.currentGPSLocation, this.indexedFeatures, - this.reportError + this.reportError, ) this.favourites = new FavouritesFeatureSource(this) const longAgo = new Date() @@ -532,7 +532,7 @@ export default class ThemeViewState implements SpecialVisualizationState { * Selects the feature that is 'i' closest to the map center */ private selectClosestAtCenter(i: number = 0) { - console.log("Selecting closest",i) + console.log("Selecting closest", i) if (this.userRelatedState.a11y.data !== "never") { this.visualFeedback.setData(true) } @@ -908,6 +908,21 @@ export default class ThemeViewState implements SpecialVisualizationState { * Setup various services for which no reference are needed */ private initActors() { + + if (!this.layout.official) { + // Add custom themes to the "visited custom themes" + const th = this.layout + this.userRelatedState.addUnofficialTheme({ + id: th.id, + icon: th.icon, + title: th.title.translations, + shortDescription: th.shortDescription.translations , + layers: th.layers.filter(l => l.isNormal()).map(l => l.id) + + }) + } + + this.selectedElement.addCallback((selected) => { if (selected === undefined) { this.focusOnMap() diff --git a/src/UI/AllThemesGui.svelte b/src/UI/AllThemesGui.svelte index 81afe3dbc..ab6575b32 100644 --- a/src/UI/AllThemesGui.svelte +++ b/src/UI/AllThemesGui.svelte @@ -55,7 +55,6 @@ const customThemes: Store = Stores.ListStabilized(state.installedUserThemes) .mapD(stableIds => Utils.NoNullInplace(stableIds.map(id => state.getUnofficialTheme(id)))) - function filtered(themes: Store): Store { return searchStable.map(search => { if (!search) { diff --git a/src/UI/DownloadFlow/DownloadPanel.svelte b/src/UI/DownloadFlow/DownloadPanel.svelte index 0be2d6d48..691d7f568 100644 --- a/src/UI/DownloadFlow/DownloadPanel.svelte +++ b/src/UI/DownloadFlow/DownloadPanel.svelte @@ -42,8 +42,8 @@ }) } - let customWidth = LocalStorageSource.Get("custom-png-width", "20") - let customHeight = LocalStorageSource.Get("custom-png-height", "20") + let customWidth = LocalStorageSource.get("custom-png-width", "20") + let customHeight = LocalStorageSource.get("custom-png-height", "20") async function offerCustomPng(): Promise { console.log( diff --git a/src/UI/Popup/Notes/CreateNewNote.svelte b/src/UI/Popup/Notes/CreateNewNote.svelte index bb6a56d1e..9bc1437ad 100644 --- a/src/UI/Popup/Notes/CreateNewNote.svelte +++ b/src/UI/Popup/Notes/CreateNewNote.svelte @@ -24,7 +24,7 @@ export let coordinate: UIEventSource<{ lon: number; lat: number }> export let state: SpecialVisualizationState - let comment: UIEventSource = LocalStorageSource.Get("note-text") + let comment: UIEventSource = LocalStorageSource.get("note-text") let created = false let notelayer: FilteredLayer = state.layerState.filteredLayers.get("note") diff --git a/src/UI/Studio/EditLayerState.ts b/src/UI/Studio/EditLayerState.ts index d52ebf765..33cde4885 100644 --- a/src/UI/Studio/EditLayerState.ts +++ b/src/UI/Studio/EditLayerState.ts @@ -37,7 +37,7 @@ export abstract class EditJsonState { public readonly osmConnection: OsmConnection public readonly showIntro: UIEventSource<"no" | "intro" | "tagrenderings"> = ( - LocalStorageSource.Get("studio-show-intro", "intro") + LocalStorageSource.get("studio-show-intro", "intro") ) public readonly expertMode: UIEventSource diff --git a/src/UI/Studio/TagRenderingInput.svelte b/src/UI/Studio/TagRenderingInput.svelte index 2ce2a5881..0f3714aec 100644 --- a/src/UI/Studio/TagRenderingInput.svelte +++ b/src/UI/Studio/TagRenderingInput.svelte @@ -29,7 +29,7 @@ const store = state.getStoreFor(path) let value = store.data let hasSeenIntro = UIEventSource.asBoolean( - LocalStorageSource.Get("studio-seen-tagrendering-tutorial", "false") + LocalStorageSource.get("studio-seen-tagrendering-tutorial", "false") ) onMount(() => { if (!hasSeenIntro.data) { diff --git a/src/UI/i18n/Locale.ts b/src/UI/i18n/Locale.ts index c74381c36..ccd0351b3 100644 --- a/src/UI/i18n/Locale.ts +++ b/src/UI/i18n/Locale.ts @@ -74,7 +74,7 @@ export default class Locale { if (typeof navigator !== "undefined") { browserLanguage = Locale.getBestSupportedLanguage() } - source = LocalStorageSource.Get("language", browserLanguage) + source = LocalStorageSource.get("language", browserLanguage) } if (!Utils.runningFromConsole && typeof document !== undefined) {