diff --git a/langs/en.json b/langs/en.json index aa99604c7..c02a61142 100644 --- a/langs/en.json +++ b/langs/en.json @@ -274,6 +274,7 @@ "background": "Change background", "filter": "Filter data", "jumpToLocation": "Go to your current location", + "locationNotAvailable": "GPS location not available. Does this device have location or are you in a tunnel?", "menu": "Menu", "zoomIn": "Zoom in", "zoomOut": "Zoom out" diff --git a/src/Logic/Actors/InitialMapPositioning.ts b/src/Logic/Actors/InitialMapPositioning.ts index f00279d72..027195d58 100644 --- a/src/Logic/Actors/InitialMapPositioning.ts +++ b/src/Logic/Actors/InitialMapPositioning.ts @@ -99,7 +99,8 @@ export default class InitialMapPositioning { Utils.downloadJson<{ latitude: number; longitude: number }>( Constants.GeoIpServer + "ip" ).then(({ longitude, latitude }) => { - if (geolocationState.currentGPSLocation.data !== undefined) { + const gpsLoc = geolocationState.currentGPSLocation.data + if (gpsLoc !== undefined) { return // We got a geolocation by now, abort } console.log("Setting location based on geoip", longitude, latitude) diff --git a/src/Logic/State/GeoLocationState.ts b/src/Logic/State/GeoLocationState.ts index f0525de5f..47f640311 100644 --- a/src/Logic/State/GeoLocationState.ts +++ b/src/Logic/State/GeoLocationState.ts @@ -1,4 +1,4 @@ -import { UIEventSource } from "../UIEventSource" +import { Store, UIEventSource } from "../UIEventSource" import { LocalStorageSource } from "../Web/LocalStorageSource" import { QueryParameters } from "../Web/QueryParameters" @@ -25,6 +25,13 @@ export class GeoLocationState { "prompt" ) + /** + * If an error occurs with a code indicating "gps unavailable", this will be set to "false". + * This is about the physical availability of the GPS-signal; this might e.g. become false if the user is in a tunnel + */ + private readonly _gpsAvailable: UIEventSource = new UIEventSource(true) + public readonly gpsAvailable: Store = this._gpsAvailable + /** * Important to determine e.g. if we move automatically on fix or not */ @@ -48,9 +55,7 @@ export class GeoLocationState { * If the user denies the geolocation this time, we unset this flag * @private */ - private readonly _previousLocationGrant: UIEventSource<"true" | "false"> = ( - LocalStorageSource.Get("geolocation-permissions") - ) + private readonly _previousLocationGrant: UIEventSource = LocalStorageSource.GetParsed("geolocation-permissions", false) /** * Used to detect a permission retraction @@ -62,27 +67,27 @@ export class GeoLocationState { this.permission.addCallbackAndRunD(async (state) => { if (state === "granted") { - self._previousLocationGrant.setData("true") + self._previousLocationGrant.setData(true) self._grantedThisSession.setData(true) } if (state === "prompt" && self._grantedThisSession.data) { // This is _really_ weird: we had a grant earlier, but it's 'prompt' now? // This means that the rights have been revoked again! - self._previousLocationGrant.setData("false") + self._previousLocationGrant.setData(false) self.permission.setData("denied") self.currentGPSLocation.setData(undefined) console.warn("Detected a downgrade in permissions!") } if (state === "denied") { - self._previousLocationGrant.setData("false") + self._previousLocationGrant.setData(false) } }) console.log("Previous location grant:", this._previousLocationGrant.data) - if (this._previousLocationGrant.data === "true") { + if (this._previousLocationGrant.data) { // A previous visit successfully granted permission. Chance is high that we are allowed to use it again! // We set the flag to false again. If the user only wanted to share their location once, we are not gonna keep bothering them - this._previousLocationGrant.setData("false") + this._previousLocationGrant.setData(false) console.log("Requesting access to GPS as this was previously granted") const latLonGivenViaUrl = QueryParameters.wasInitialized("lat") || QueryParameters.wasInitialized("lon") @@ -124,9 +129,11 @@ export class GeoLocationState { } if (GeoLocationState.isSafari()) { - // This is probably safari - // Safari does not support the 'permissions'-API for geolocation, - // so we just start watching right away + /* + This is probably safari + Safari does not support the 'permissions'-API for geolocation, + so we just start watching right away + */ this.permission.setData("requested") this.startWatching() @@ -143,7 +150,7 @@ export class GeoLocationState { self.startWatching() return } - status.addEventListener("change", (e) => { + status.addEventListener("change", () => { self.permission.setData(status.state) }) // The code above might have reset it to 'prompt', but we _did_ request permission! @@ -163,10 +170,22 @@ export class GeoLocationState { const self = this navigator.geolocation.watchPosition( function (position) { + self._gpsAvailable.set(true) self.currentGPSLocation.setData(position.coords) - self._previousLocationGrant.setData("true") + self._previousLocationGrant.setData(true) }, function (e) { + if(e.code === 2 || e.code === 3){ + console.log("Could not get location with navigator.geolocation due to unavailable or timeout", e) + self._gpsAvailable.set(false) + return + } + self._gpsAvailable.set(true) // We go back to the default assumption that the location is physically available + if(e.code === 1) { + self.permission.set("denied") + self._grantedThisSession.setData(false) + return + } console.warn("Could not get location with navigator.geolocation due to", e) }, { diff --git a/src/UI/Base/MapControlButton.svelte b/src/UI/Base/MapControlButton.svelte index 4a683494e..afd42306a 100644 --- a/src/UI/Base/MapControlButton.svelte +++ b/src/UI/Base/MapControlButton.svelte @@ -2,7 +2,7 @@ import { createEventDispatcher } from "svelte" import { twJoin } from "tailwind-merge" import { Translation } from "../i18n/Translation" - import { ariaLabel } from "../../Utils/ariaLabel" + import { ariaLabel, ariaLabelStore } from "../../Utils/ariaLabel" import { ImmutableStore, Store, UIEventSource } from "../../Logic/UIEventSource" /** @@ -12,18 +12,21 @@ export let cls = "m-0.5 p-0.5 sm:p-1 md:m-1" export let enabled: Store = new ImmutableStore(true) export let arialabel: Translation = undefined + export let arialabelDynamic : Store = new ImmutableStore(arialabel) + let arialabelString = arialabelDynamic.bind(tr => tr?.current) export let htmlElem: UIEventSource = undefined let _htmlElem: HTMLElement $: { htmlElem?.setData(_htmlElem) } +