From b6366412eaf3cf9fe4d86ce4e2468490c72a3fc2 Mon Sep 17 00:00:00 2001 From: Pieter Vander Vennet Date: Fri, 1 Aug 2025 00:42:15 +0200 Subject: [PATCH] UX: indicate incomplete search in offline mode --- src/Logic/Search/CombinedSearcher.ts | 3 +++ src/Logic/Search/CoordinateSearch.ts | 2 ++ src/Logic/Search/GeocodingProvider.ts | 1 + src/Logic/Search/LocalElementSearch.ts | 2 ++ src/Logic/Search/NominatimGeocoding.ts | 1 + src/Logic/Search/OpenLocationCodeSearch.ts | 2 ++ src/Logic/Search/OpenStreetMapIdSearch.ts | 1 + src/Logic/Search/PhotonSearch.ts | 6 ++--- src/Logic/State/SearchState.ts | 5 ++++- src/UI/Base/CrossedOut.svelte | 15 +++++++++++++ .../BigComponents/ServiceWorkerStatus.svelte | 22 +++++++++++++++++++ src/UI/Search/GeocodeResults.svelte | 1 + src/UI/Search/SearchResults.svelte | 13 +++++++++++ 13 files changed, 69 insertions(+), 5 deletions(-) create mode 100644 src/UI/Base/CrossedOut.svelte create mode 100644 src/UI/BigComponents/ServiceWorkerStatus.svelte diff --git a/src/Logic/Search/CombinedSearcher.ts b/src/Logic/Search/CombinedSearcher.ts index 261826c7d..46ed96fb1 100644 --- a/src/Logic/Search/CombinedSearcher.ts +++ b/src/Logic/Search/CombinedSearcher.ts @@ -6,6 +6,8 @@ export default class CombinedSearcher implements GeocodingProvider { public readonly name = "CombinedSearcher" private _providers: ReadonlyArray private _providersWithSuggest: ReadonlyArray + public readonly needsInternet + /** * Merges the various providers together; ignores errors. @@ -15,6 +17,7 @@ export default class CombinedSearcher implements GeocodingProvider { constructor(...providers: ReadonlyArray) { this._providers = Utils.NoNull(providers) this._providersWithSuggest = this._providers.filter((pr) => pr.suggest !== undefined) + this.needsInternet = this._providers.some(p => p.needsInternet) } /** diff --git a/src/Logic/Search/CoordinateSearch.ts b/src/Logic/Search/CoordinateSearch.ts index de74239c1..e83cda837 100644 --- a/src/Logic/Search/CoordinateSearch.ts +++ b/src/Logic/Search/CoordinateSearch.ts @@ -8,6 +8,8 @@ import CoordinateParser from "coordinate-parser" */ export default class CoordinateSearch implements GeocodingProvider { public readonly name = "CoordinateSearch" + public readonly needsInternet = false + private static readonly latLonRegexes: ReadonlyArray = [ /^ *(-?[0-9]+\.[0-9]+)[ ,;/\\]+(-?[0-9]+\.[0-9]+)/, /^ *(-?[0-9]+,[0-9]+)[ ;/\\]+(-?[0-9]+,[0-9]+)/, diff --git a/src/Logic/Search/GeocodingProvider.ts b/src/Logic/Search/GeocodingProvider.ts index 9ec66c40a..593cb0616 100644 --- a/src/Logic/Search/GeocodingProvider.ts +++ b/src/Logic/Search/GeocodingProvider.ts @@ -49,6 +49,7 @@ export interface GeocodingOptions { export default interface GeocodingProvider { readonly name: string + readonly needsInternet: boolean /** * Performs search. diff --git a/src/Logic/Search/LocalElementSearch.ts b/src/Logic/Search/LocalElementSearch.ts index b96741eef..5d81b929f 100644 --- a/src/Logic/Search/LocalElementSearch.ts +++ b/src/Logic/Search/LocalElementSearch.ts @@ -21,6 +21,8 @@ export default class LocalElementSearch implements GeocodingProvider { private readonly _state: ThemeViewState private readonly _limit: number public readonly name = "LocalElementSearch" + public readonly needsInternet = false + constructor(state: ThemeViewState, limit: number) { this._state = state this._limit = limit diff --git a/src/Logic/Search/NominatimGeocoding.ts b/src/Logic/Search/NominatimGeocoding.ts index 0877be8d9..4cc6df4ec 100644 --- a/src/Logic/Search/NominatimGeocoding.ts +++ b/src/Logic/Search/NominatimGeocoding.ts @@ -10,6 +10,7 @@ export class NominatimGeocoding implements GeocodingProvider { private readonly _host private readonly limit: number public readonly name = "Nominatim" + public readonly needsInternet = true constructor(limit: number = 3, host: string = Constants.nominatimEndpoint) { this.limit = limit diff --git a/src/Logic/Search/OpenLocationCodeSearch.ts b/src/Logic/Search/OpenLocationCodeSearch.ts index 6081950f8..f7f1feb20 100644 --- a/src/Logic/Search/OpenLocationCodeSearch.ts +++ b/src/Logic/Search/OpenLocationCodeSearch.ts @@ -3,6 +3,8 @@ import GeocodingProvider, { GeocodeResult, GeocodingOptions } from "./GeocodingP import { decode as pluscode_decode } from "pluscodes" export default class OpenLocationCodeSearch implements GeocodingProvider { + public readonly needsInternet = false + /** * A regex describing all plus-codes */ diff --git a/src/Logic/Search/OpenStreetMapIdSearch.ts b/src/Logic/Search/OpenStreetMapIdSearch.ts index 75f3ee373..74187102e 100644 --- a/src/Logic/Search/OpenStreetMapIdSearch.ts +++ b/src/Logic/Search/OpenStreetMapIdSearch.ts @@ -7,6 +7,7 @@ import OsmObjectDownloader from "../Osm/OsmObjectDownloader" export default class OpenStreetMapIdSearch implements GeocodingProvider { private static readonly regex = /((https?:\/\/)?(www.)?(osm|openstreetmap).org\/)?(n|node|w|way|r|relation)[/ ]?([0-9]+)/ + public readonly needsInternet = true public readonly name = "OpenStreetMapId" private static readonly types: Readonly> = { n: "node", diff --git a/src/Logic/Search/PhotonSearch.ts b/src/Logic/Search/PhotonSearch.ts index 6745b8912..016a3b3fe 100644 --- a/src/Logic/Search/PhotonSearch.ts +++ b/src/Logic/Search/PhotonSearch.ts @@ -5,7 +5,7 @@ import GeocodingProvider, { GeocodingOptions, GeocodingUtils, ReverseGeocodingProvider, - ReverseGeocodingResult, + ReverseGeocodingResult } from "./GeocodingProvider" import { Utils } from "../../Utils" import { Feature, FeatureCollection } from "geojson" @@ -15,6 +15,7 @@ import { Store, Stores } from "../UIEventSource" export default class PhotonSearch implements GeocodingProvider, ReverseGeocodingProvider { private readonly _endpoint: string + public readonly needsInternet = true public readonly name = "photon" private supportedLanguages = ["en", "de", "fr"] private static readonly types = { @@ -23,17 +24,14 @@ export default class PhotonSearch implements GeocodingProvider, ReverseGeocoding N: "node", } private readonly ignoreBounds: boolean - private readonly suggestionLimit: number = 5 private readonly searchLimit: number = 1 constructor( ignoreBounds: boolean = false, - suggestionLimit: number = 5, searchLimit: number = 1, endpoint?: string ) { this.ignoreBounds = ignoreBounds - this.suggestionLimit = suggestionLimit this.searchLimit = searchLimit this._endpoint = endpoint ?? Constants.photonEndpoint ?? "https://photon.komoot.io/" diff --git a/src/Logic/State/SearchState.ts b/src/Logic/State/SearchState.ts index 31b75a7b3..4c0d6798e 100644 --- a/src/Logic/State/SearchState.ts +++ b/src/Logic/State/SearchState.ts @@ -20,6 +20,7 @@ import { BBox } from "../BBox" import { QueryParameters } from "../Web/QueryParameters" import { Utils } from "../../Utils" import { NominatimGeocoding } from "../Search/NominatimGeocoding" +import { IsOnline } from "../Web/IsOnline" export default class SearchState { public readonly feedback: UIEventSource = new UIEventSource(undefined) @@ -62,7 +63,9 @@ export default class SearchState { if (search.length === 0) { return undefined } - return this.locationSearchers.map((ls) => ({ + return this.locationSearchers + .filter(ls => !ls.needsInternet || IsOnline.isOnline.data) + .map((ls) => ({ source: ls, results: ls.suggest(search, { bbox: bounds.data }), })) diff --git a/src/UI/Base/CrossedOut.svelte b/src/UI/Base/CrossedOut.svelte new file mode 100644 index 000000000..8ba88ac59 --- /dev/null +++ b/src/UI/Base/CrossedOut.svelte @@ -0,0 +1,15 @@ + + +
+
+ + +
+
+ +
+
diff --git a/src/UI/BigComponents/ServiceWorkerStatus.svelte b/src/UI/BigComponents/ServiceWorkerStatus.svelte new file mode 100644 index 000000000..1c7c9297b --- /dev/null +++ b/src/UI/BigComponents/ServiceWorkerStatus.svelte @@ -0,0 +1,22 @@ + + +{#if $loadedAssets === undefined} + +{:else} + + {JSON.stringify($loadedAssets)} +{/if} diff --git a/src/UI/Search/GeocodeResults.svelte b/src/UI/Search/GeocodeResults.svelte index 0f2e4edbc..1ed5f0719 100644 --- a/src/UI/Search/GeocodeResults.svelte +++ b/src/UI/Search/GeocodeResults.svelte @@ -12,6 +12,7 @@ import type { GeocodeResult } from "../../Logic/Search/GeocodingProvider" import type { MapProperties } from "../../Models/MapProperties" import { ExclamationTriangle } from "@babeard/svelte-heroicons/solid/ExclamationTriangle" + import { IsOnline } from "../../Logic/Web/IsOnline" export let state: { searchState: { diff --git a/src/UI/Search/SearchResults.svelte b/src/UI/Search/SearchResults.svelte index 43d643ecc..0db7cb8b6 100644 --- a/src/UI/Search/SearchResults.svelte +++ b/src/UI/Search/SearchResults.svelte @@ -16,6 +16,9 @@ import DotMenu from "../Base/DotMenu.svelte" import type { GeocodeResult } from "../../Logic/Search/GeocodingProvider" import { default as GeocodeResultSvelte } from "./GeocodeResult.svelte" + import { IsOnline } from "../../Logic/Web/IsOnline" + import CrossedOut from "../Base/CrossedOut.svelte" + import Wifi from "@babeard/svelte-heroicons/solid/Wifi" /** * The big overview of all search bar results @@ -41,6 +44,7 @@ let allowOtherThemes = state.featureSwitches.featureSwitchBackToThemeOverview let allowFilters = state.featureSwitches.featureSwitchFilter + let isOnline = IsOnline.isOnline
@@ -55,6 +59,15 @@
{/if} + {#if !$isOnline} +
+ + + + Your device is currently offline. This impacts search results +
+ {/if} + {#if $allowFilters} {/if}