diff --git a/assets/layers/icons/icons.json b/assets/layers/icons/icons.json index 93e9e91ec..54ebd45d5 100644 --- a/assets/layers/icons/icons.json +++ b/assets/layers/icons/icons.json @@ -430,10 +430,10 @@ } }, { - "condition": "_favourite=yes", + "id": "favourite_icon", "description": "Only for rendering", "icon": "circle:white;heart:red", - "id": "favourite_icon", + "condition": "_favourite=yes", "metacondition": "__showTimeSensitiveIcons!=no" }, { diff --git a/assets/layers/last_click/last_click.json b/assets/layers/last_click/last_click.json index 6aaa19115..3185c513f 100644 --- a/assets/layers/last_click/last_click.json +++ b/assets/layers/last_click/last_click.json @@ -217,8 +217,8 @@ }, { "id": "debug", - "metacondition": "__featureSwitchIsDebugging=true", - "render": "{all_tags()}" + "render": "{all_tags()}", + "metacondition": "__featureSwitchIsDebugging=true" } ], "filter": [ diff --git a/assets/layers/note/note.json b/assets/layers/note/note.json index eedef08c6..b1dd36f32 100644 --- a/assets/layers/note/note.json +++ b/assets/layers/note/note.json @@ -114,9 +114,9 @@ "lineRendering": [], "tagRenderings": [ { - "classes": "p-0", "id": "conversation", - "render": "{visualize_note_comments()}" + "render": "{visualize_note_comments()}", + "classes": "p-0" }, { "id": "add_image", diff --git a/assets/layers/osm_community_index/osm_community_index.json b/assets/layers/osm_community_index/osm_community_index.json index 150fc6ecd..1c605ca38 100644 --- a/assets/layers/osm_community_index/osm_community_index.json +++ b/assets/layers/osm_community_index/osm_community_index.json @@ -66,16 +66,16 @@ ], "tagRenderings": [ { - "condition": "level=country", - "description": "The name of the country", "id": "country_name", - "render": "{nameEn} {emojiFlag}" + "description": "The name of the country", + "render": "{nameEn} {emojiFlag}", + "condition": "level=country" }, { - "condition": "_community_links~*", - "description": "Community Links (Discord, meetups, Slack groups, IRC channels, mailing lists etc...)", "id": "community_links", - "render": "{_community_links}" + "description": "Community Links (Discord, meetups, Slack groups, IRC channels, mailing lists etc...)", + "render": "{_community_links}", + "condition": "_community_links~*" } ], "filter": [ diff --git a/assets/layers/usersettings/usersettings.json b/assets/layers/usersettings/usersettings.json index a82beeaaf..907b37c2d 100644 --- a/assets/layers/usersettings/usersettings.json +++ b/assets/layers/usersettings/usersettings.json @@ -1898,6 +1898,46 @@ "render": { "*": "{storage_all_tags()}" } + }, + { + "id": "debug_serviceworker_accordeon", + "render": { + "special": { + "header": "debug_serviceworker_accordeon_title", + "labels": "debug_serviceworker", + "type": "group" + } + }, + "condition": "mapcomplete-show_debug=yes" + }, + { + "id": "debug_serviceworker_accordeon_title", + "labels": [ + "hidden" + ], + "render": { + "en": "Debug information about the service worker" + } + }, + { + "id": "expl", + "labels": [ + "debug_serviceworker", + "hidden" + ], + "render": { + "en": "To clear the service worker data, use the 'clear caches' button" + } + }, + { + "id": "service_worker_tags", + "labels": [ + "debug_serviceworker", + "hidden" + ], + "render": { + "*": "{serviceworker_all_tags()}" + } } ], "allowMove": false diff --git a/index.html b/index.html index 04cf21dcf..796ba73ec 100644 --- a/index.html +++ b/index.html @@ -43,8 +43,6 @@ - - diff --git a/langs/en.json b/langs/en.json index c5b3db254..1c368e3f5 100644 --- a/langs/en.json +++ b/langs/en.json @@ -335,6 +335,7 @@ "next": "Next", "noTagsSelected": "No tags selected", "number": "number", + "offline": "Your device is offline", "openTheMap": "Open the map", "openTheMapReason": "to view, edit and add information", "opening_hours": { diff --git a/langs/layers/en.json b/langs/layers/en.json index c9632acd7..7ccbab67b 100644 --- a/langs/layers/en.json +++ b/langs/layers/en.json @@ -14095,6 +14095,9 @@ "debug_accordeon_title": { "render": "Debug information" }, + "debug_serviceworker_accordeon_title": { + "render": "Debug information about the service worker" + }, "debug_storage_accordeon_title": { "render": "Debug information about local storage" }, @@ -14105,6 +14108,9 @@ } } }, + "expl": { + "render": "To clear the service worker data, use the 'clear caches' button" + }, "fixate-north": { "mappings": { "0": { diff --git a/scripts/generateIncludedImages.ts b/scripts/generateIncludedImages.ts index 69d15f0b9..6b4972b1f 100644 --- a/scripts/generateIncludedImages.ts +++ b/scripts/generateIncludedImages.ts @@ -1,7 +1,7 @@ import * as fs from "fs" import Script from "./Script" -function genImages(dryrun = false) { +function genImages() { console.log("Generating images") const dir = fs.readdirSync("./assets/svg") for (const path of dir) { @@ -64,7 +64,7 @@ class GenerateIncludedImages extends Script { super("Converts all images from assets/svg into svelte-classes.") } - async main(args: string[]): Promise { + async main(): Promise { genImages() } } diff --git a/scripts/generateLayerOverview.ts b/scripts/generateLayerOverview.ts index 503c50454..15af107cb 100644 --- a/scripts/generateLayerOverview.ts +++ b/scripts/generateLayerOverview.ts @@ -8,7 +8,7 @@ import { DoesImageExist, PrevalidateTheme, ValidateLayer, - ValidateThemeEnsemble, + ValidateThemeEnsemble } from "../src/Models/ThemeConfig/Conversion/Validation" import { Translation } from "../src/UI/i18n/Translation" import { OrderLayer, PrepareLayer } from "../src/Models/ThemeConfig/Conversion/PrepareLayer" @@ -19,7 +19,7 @@ import { DesugaringStep, Each, Fuse, - On, + On } from "../src/Models/ThemeConfig/Conversion/Conversion" import { Utils } from "../src/Utils" import Script from "./Script" @@ -182,7 +182,7 @@ class LayerBuilder extends Conversion> { return `./assets/layers/${id}/${id}.json` } - writeLayer(layer: LayerConfigJson) { + public writeLayer(layer: LayerConfigJson) { if (layer.labels?.some((l) => this._labelBlacklist.has(l))) { console.log("Not writing layer " + layer.id + ", censored") return @@ -191,6 +191,15 @@ class LayerBuilder extends Conversion> { if (!existsSync(LayerOverviewUtils.layerPath)) { mkdirSync(LayerOverviewUtils.layerPath) } + + const usedImages = Lists.dedup(new ExtractImages(true, new Set(this._desugaringState.tagRenderings.keys())) + .convertStrict({ layers: [layer], id: "dummy", icon: undefined, title: undefined }) + .map((x) => x.path)) + usedImages.sort() + + layer["_usedImages"] = usedImages + + writeFileSync(LayerBuilder.targetPath(layer.id), JSON.stringify(layer, null, " "), { encoding: "utf8", }) diff --git a/scripts/prepareServiceWorker.ts b/scripts/prepareServiceWorker.ts index 71f3ebbc7..d43184e66 100644 --- a/scripts/prepareServiceWorker.ts +++ b/scripts/prepareServiceWorker.ts @@ -9,7 +9,7 @@ class PrepareServiceWorker extends Script { } public async main() { - const v = Constants.vNumber + const v = Constants.vNumber + "-" + new Date().getTime() writeFileSync("./src/service-worker/SWGenerated.ts", ["export class SWGenerated {", "// generated by scripts/prepareServiceWorker.ts", diff --git a/src/InstallServiceWorker.ts b/src/InstallServiceWorker.ts index 85a0d76a7..c7fdbfbd2 100644 --- a/src/InstallServiceWorker.ts +++ b/src/InstallServiceWorker.ts @@ -1,13 +1,17 @@ -export {} -window.addEventListener("load", async () => { - if (!("serviceWorker" in navigator)) { - console.log("Service workers are not supported") - return - } - try { +export class InstallServiceWorker { + + static async installServiceWorker() { + if (!("serviceWorker" in navigator)) { + throw ("Service workers are not supported") + } await navigator.serviceWorker.register("/service-worker.js", { type: "module" }) console.log("Service worker registration successful") - } catch (err) { - console.error("Service worker registration failed", err) + } -}) + + static async precache(assets: string[]) { + if (assets?.length > 0) { + await fetch("./service-worker/precache?assets=" + assets.join(";")) + } + } +} diff --git a/src/Logic/Osm/OsmConnection.ts b/src/Logic/Osm/OsmConnection.ts index 733c4e5ec..0f44110cd 100644 --- a/src/Logic/Osm/OsmConnection.ts +++ b/src/Logic/Osm/OsmConnection.ts @@ -8,6 +8,7 @@ import Constants from "../../Models/Constants" import { Feature, Point } from "geojson" import { AndroidPolyfill } from "../Web/AndroidPolyfill" import { QueryParameters } from "../Web/QueryParameters" +import { IsOnline } from "../Web/IsOnline" interface OsmUserInfo { id: number @@ -131,6 +132,7 @@ export class OsmConnection { * Details of the currently logged-in user; undefined if not logged in */ public userDetails: UIEventSource + public isLoggedIn: Store public gpxServiceIsOnline: UIEventSource = new UIEventSource( "unknown" @@ -182,7 +184,7 @@ export class OsmConnection { this._oauth_config.oauth_secret = import.meta.env.VITE_OSM_OAUTH_SECRET } - this.userDetails = new UIEventSource(undefined, "userDetails") + this.userDetails = UIEventSource.asObject(LocalStorageSource.get("user_details"), undefined) if (options.fakeUser) { const ud = this.userDetails.data ud.csCount = 5678 @@ -197,13 +199,7 @@ export class OsmConnection { } this.updateCapabilities() - this.isLoggedIn = this.userDetails.map( - (user) => - !!user && - (this.apiIsOnline.data === "unknown" || this.apiIsOnline.data === "online"), - [this.apiIsOnline] - ) - + this.isLoggedIn = this.userDetails.map((user) => !!user) this._dryRun = options.dryRun ?? new UIEventSource(false) if (options?.shared_cookie) { @@ -284,6 +280,9 @@ export class OsmConnection { } public async AttemptLogin() { + if (!IsOnline.isOnline.data) { + return + } this.updateCapabilities() if (this.loadingStatus.data !== "logged-in") { this.loadingStatus.setData("loading") @@ -308,6 +307,9 @@ export class OsmConnection { } private async loadUserInfo() { + if (!IsOnline.isOnline.data) { + return + } try { const result = await this.interact("user/details.json") if (result === null) { diff --git a/src/UI/Base/LoginToggle.svelte b/src/UI/Base/LoginToggle.svelte index d4fa4fc6f..859f8fb0c 100644 --- a/src/UI/Base/LoginToggle.svelte +++ b/src/UI/Base/LoginToggle.svelte @@ -14,10 +14,15 @@ osmConnection: OsmConnection featureSwitches?: { featureSwitchEnableLogin?: UIEventSource } } + /** + * Do show this element when in offline mode + */ + export let offline = false /** * If set, 'loading' will act as if we are already logged in. */ - export let ignoreLoading: boolean = false + export let ignoreLoading: boolean = offline // If it works in offline mode, it'll work while we are logging in too + /** * If set and the OSM-api fails, do _not_ show any error messages nor the successful state, just hide. * Will still show the "not-logged-in"-slot @@ -32,23 +37,26 @@ unknown: t.loginFailedUnreachableMode, readonly: t.loginFailedReadonlyMode, } - const apiState: Store = + const apiState: Store = state?.osmConnection?.apiIsOnline ?? new ImmutableStore("online") const online = IsOnline.isOnline + let loggedIn = state?.osmConnection?.isLoggedIn {#if $badge} - {#if !$online} + {#if !$online && !offline} {#if !hiddenFail}
- Your device is offline +
{/if} {:else if !ignoreLoading && !hiddenFail && $loadingStatus === "loading"} - {:else if ($loadingStatus === "error" || $apiState === "readonly" || $apiState === "offline")} + {:else if $loggedIn} + + {:else if ($loadingStatus === "error" || $apiState === "readonly" || $apiState === "offline" || $apiState === "unreachable")} {#if !hiddenFail}
@@ -63,8 +71,7 @@
{/if} - {:else if $loadingStatus === "logged-in"} - + {:else if $loadingStatus === "not-attempted"} {/if} diff --git a/src/UI/BigComponents/MenuDrawerIndex.svelte b/src/UI/BigComponents/MenuDrawerIndex.svelte index 809068735..d9d0871e6 100644 --- a/src/UI/BigComponents/MenuDrawerIndex.svelte +++ b/src/UI/BigComponents/MenuDrawerIndex.svelte @@ -77,11 +77,9 @@ let usersettingslayer = new LayerConfig(usersettings, "usersettings", true) - let theme = state.theme let featureSwitches = state.featureSwitches let showHome = featureSwitches?.featureSwitchBackToThemeOverview let pg = state.guistate.pageStates - let location = state.mapProperties?.location export let onlyLink: boolean const t = Translations.t.general.menu let shown = new UIEventSource(state.guistate.pageStates.menu.data || !onlyLink) @@ -133,7 +131,7 @@ - +
{#if $userdetails.img} @@ -143,7 +141,7 @@ {/if}
- {$userdetails.name} + {$userdetails?.name ?? ''}
@@ -281,7 +279,7 @@ - {#if !state.theme} + {#if !state?.theme} diff --git a/src/UI/Popup/ClearCaches.svelte b/src/UI/Popup/ClearCaches.svelte index 0bc83e5e1..2adcffe7c 100644 --- a/src/UI/Popup/ClearCaches.svelte +++ b/src/UI/Popup/ClearCaches.svelte @@ -4,7 +4,7 @@ function clearCaches() { IdbLocalStorage.clearAll() - Utils.download("./service-worker-clear") + Utils.download("./service-worker/clear_caches.json") window.location.reload() } export let msg: string diff --git a/src/UI/Popup/TagRendering/TagRenderingEditable.svelte b/src/UI/Popup/TagRendering/TagRenderingEditable.svelte index 45d84ea9e..593488436 100644 --- a/src/UI/Popup/TagRendering/TagRenderingEditable.svelte +++ b/src/UI/Popup/TagRendering/TagRenderingEditable.svelte @@ -128,7 +128,7 @@ {layer} extraClasses="my-2" /> - {#if (!editingEnabled || $editingEnabled) && $apiState !== "readonly" && $apiState !== "offline"} + {#if !editingEnabled || $editingEnabled} {#if layer?.isNormal()} - + {#if $disabledInTheme.indexOf(config.id) >= 0} @@ -538,7 +538,7 @@ {/if} - +
{#if config.alwaysForceSaveButton}