forked from MapComplete/MapComplete
UX: finetune 'go to your geolocation' interaction on theme introduction panel, fix #1583
This commit is contained in:
parent
c8df0170cc
commit
17b85195a2
4 changed files with 154 additions and 91 deletions
|
@ -1,13 +1,13 @@
|
|||
import { UIEventSource } from "../UIEventSource"
|
||||
import { LocalStorageSource } from "../Web/LocalStorageSource"
|
||||
import { QueryParameters } from "../Web/QueryParameters"
|
||||
import { UIEventSource } from "../UIEventSource";
|
||||
import { LocalStorageSource } from "../Web/LocalStorageSource";
|
||||
import { QueryParameters } from "../Web/QueryParameters";
|
||||
|
||||
export type GeolocationPermissionState = "prompt" | "requested" | "granted" | "denied"
|
||||
|
||||
export interface GeoLocationPointProperties extends GeolocationCoordinates {
|
||||
id: "gps"
|
||||
"user:location": "yes"
|
||||
date: string
|
||||
id: "gps";
|
||||
"user:location": "yes";
|
||||
date: string;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -23,22 +23,22 @@ export class GeoLocationState {
|
|||
*/
|
||||
public readonly permission: UIEventSource<GeolocationPermissionState> = new UIEventSource(
|
||||
"prompt"
|
||||
)
|
||||
);
|
||||
|
||||
/**
|
||||
* Important to determine e.g. if we move automatically on fix or not
|
||||
*/
|
||||
public readonly requestMoment: UIEventSource<Date | undefined> = new UIEventSource(undefined)
|
||||
public readonly requestMoment: UIEventSource<Date | undefined> = new UIEventSource(undefined);
|
||||
/**
|
||||
* If true: the map will center (and re-center) to this location
|
||||
*/
|
||||
public readonly allowMoving: UIEventSource<boolean> = new UIEventSource<boolean>(true)
|
||||
public readonly allowMoving: UIEventSource<boolean> = new UIEventSource<boolean>(true);
|
||||
|
||||
/**
|
||||
* The latest GeoLocationCoordinates, as given by the WebAPI
|
||||
*/
|
||||
public readonly currentGPSLocation: UIEventSource<GeolocationCoordinates | undefined> =
|
||||
new UIEventSource<GeolocationCoordinates | undefined>(undefined)
|
||||
new UIEventSource<GeolocationCoordinates | undefined>(undefined);
|
||||
|
||||
/**
|
||||
* A small flag on localstorage. If the user previously granted the geolocation, it will be set.
|
||||
|
@ -50,69 +50,50 @@ export class GeoLocationState {
|
|||
*/
|
||||
private readonly _previousLocationGrant: UIEventSource<"true" | "false"> = <any>(
|
||||
LocalStorageSource.Get("geolocation-permissions")
|
||||
)
|
||||
);
|
||||
|
||||
/**
|
||||
* Used to detect a permission retraction
|
||||
*/
|
||||
private readonly _grantedThisSession: UIEventSource<boolean> = new UIEventSource<boolean>(false)
|
||||
private readonly _grantedThisSession: UIEventSource<boolean> = new UIEventSource<boolean>(false);
|
||||
|
||||
constructor() {
|
||||
const self = this
|
||||
const self = this;
|
||||
|
||||
this.permission.addCallbackAndRunD(async (state) => {
|
||||
console.trace("GEOPERMISSION", state)
|
||||
if (state === "granted") {
|
||||
self._previousLocationGrant.setData("true")
|
||||
self._grantedThisSession.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.permission.setData("denied")
|
||||
self._previousLocationGrant.setData("false")
|
||||
self.permission.setData("denied")
|
||||
self.currentGPSLocation.setData(undefined)
|
||||
console.warn("Detected a downgrade in permissions!")
|
||||
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)
|
||||
});
|
||||
console.log("Previous location grant:", this._previousLocationGrant.data);
|
||||
if (this._previousLocationGrant.data === "true") {
|
||||
// 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")
|
||||
console.log("Requesting access to GPS as this was previously granted")
|
||||
this._previousLocationGrant.setData("false");
|
||||
console.log("Requesting access to GPS as this was previously granted");
|
||||
const latLonGivenViaUrl =
|
||||
QueryParameters.wasInitialized("lat") || QueryParameters.wasInitialized("lon")
|
||||
QueryParameters.wasInitialized("lat") || QueryParameters.wasInitialized("lon");
|
||||
if (!latLonGivenViaUrl) {
|
||||
this.requestMoment.setData(new Date())
|
||||
this.requestMoment.setData(new Date());
|
||||
}
|
||||
this.requestPermission()
|
||||
this.requestPermission();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Installs the listener for updates
|
||||
* @private
|
||||
*/
|
||||
private async startWatching() {
|
||||
const self = this
|
||||
navigator.geolocation.watchPosition(
|
||||
function (position) {
|
||||
self.currentGPSLocation.setData(position.coords)
|
||||
self._previousLocationGrant.setData("true")
|
||||
},
|
||||
function () {
|
||||
console.warn("Could not get location with navigator.geolocation")
|
||||
},
|
||||
{
|
||||
enableHighAccuracy: true,
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Requests the user to allow access to their position.
|
||||
* When granted, will be written to the 'geolocationState'.
|
||||
|
@ -121,33 +102,57 @@ export class GeoLocationState {
|
|||
public requestPermission() {
|
||||
if (typeof navigator === "undefined") {
|
||||
// Not compatible with this browser
|
||||
this.permission.setData("denied")
|
||||
return
|
||||
this.permission.setData("denied");
|
||||
return;
|
||||
}
|
||||
if (this.permission.data !== "prompt" && this.permission.data !== "requested") {
|
||||
// If the user denies the first prompt, revokes the deny and then tries again, we have to run the flow as well
|
||||
// Hence that we continue the flow if it is "requested"
|
||||
return
|
||||
return;
|
||||
}
|
||||
|
||||
this.permission.setData("requested")
|
||||
this.permission.setData("requested");
|
||||
try {
|
||||
navigator?.permissions
|
||||
?.query({ name: "geolocation" })
|
||||
.then((status) => {
|
||||
console.log("Status update: received geolocation permission is ", status.state)
|
||||
this.permission.setData(status.state)
|
||||
const self = this
|
||||
status.onchange = function () {
|
||||
const self = this;
|
||||
if(status.state === "granted" || status.state === "denied"){
|
||||
self.permission.setData(status.state)
|
||||
return
|
||||
}
|
||||
status.addEventListener("change", (e) => {
|
||||
self.permission.setData(status.state);
|
||||
|
||||
});
|
||||
// The code above might have reset it to 'prompt', but we _did_ request permission!
|
||||
this.permission.setData("requested")
|
||||
// We _must_ call 'startWatching', as that is the actual trigger for the popup...
|
||||
self.startWatching()
|
||||
self.startWatching();
|
||||
})
|
||||
.catch((e) => console.error("Could not get geopermission", e))
|
||||
.catch((e) => console.error("Could not get geopermission", e));
|
||||
} catch (e) {
|
||||
console.error("Could not get permission:", e)
|
||||
console.error("Could not get permission:", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Installs the listener for updates
|
||||
* @private
|
||||
*/
|
||||
private async startWatching() {
|
||||
const self = this;
|
||||
navigator.geolocation.watchPosition(
|
||||
function(position) {
|
||||
self.currentGPSLocation.setData(position.coords);
|
||||
self._previousLocationGrant.setData("true");
|
||||
},
|
||||
function() {
|
||||
console.warn("Could not get location with navigator.geolocation");
|
||||
},
|
||||
{
|
||||
enableHighAccuracy: true
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue