MapComplete/src/UI/BigComponents/GeolocationControl.ts

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

109 lines
3.9 KiB
TypeScript
Raw Normal View History

import { Store, UIEventSource } from "../../Logic/UIEventSource"
import GeoLocationHandler from "../../Logic/Actors/GeoLocationHandler"
2023-02-09 03:12:21 +01:00
import Constants from "../../Models/Constants"
2023-03-24 19:21:15 +01:00
import { MapProperties } from "../../Models/MapProperties"
/**
2024-08-10 12:44:23 +02:00
* Does the user interaction state with a geolocation button, such as keeping track of the last click,
* and lock status + moving the map when clicked
*/
2023-12-18 01:30:02 +01:00
export class GeolocationControlState {
public readonly lastClick = new UIEventSource<Date>(undefined)
2023-12-18 01:30:02 +01:00
public readonly lastClickWithinThreeSecs: Store<boolean>
private readonly _geolocationHandler: GeoLocationHandler
private readonly _mapProperties: MapProperties
2023-12-18 01:30:02 +01:00
constructor(
geolocationHandler: GeoLocationHandler,
state: MapProperties,
lastGeolocationRequestByUser: UIEventSource<Date> = undefined
) {
const lastClick = lastGeolocationRequestByUser ?? new UIEventSource<Date>(undefined)
2023-02-09 03:12:21 +01:00
lastClick.addCallbackD((date) => {
geolocationHandler.geolocationState.requestMoment.setData(date)
})
const lastClickWithinThreeSecs = lastClick.map((lastClick) => {
if (lastClick === undefined) {
return false
}
const timeDiff = (new Date().getTime() - lastClick.getTime()) / 1000
return timeDiff <= 3
})
2023-02-09 03:12:21 +01:00
const lastRequestWithinTimeout = geolocationHandler.geolocationState.requestMoment.map(
(date) => {
if (date === undefined) {
return false
}
const timeDiff = (new Date().getTime() - date.getTime()) / 1000
return timeDiff <= Constants.zoomToLocationTimeout
}
)
this._geolocationHandler = geolocationHandler
this._mapProperties = state
this.lastClick = lastClick
2023-12-18 01:30:02 +01:00
this.lastClickWithinThreeSecs = lastClickWithinThreeSecs
lastClick.addCallbackAndRunD((_) => {
window.setTimeout(() => {
if (lastClickWithinThreeSecs.data) {
lastClick.ping()
}
}, 500)
})
2023-02-09 03:12:21 +01:00
geolocationHandler.geolocationState.requestMoment.addCallbackAndRunD((_) => {
window.setTimeout(() => {
if (lastRequestWithinTimeout.data) {
geolocationHandler.geolocationState.requestMoment.ping()
}
}, 500)
})
}
public async handleClick() {
const geolocationHandler = this._geolocationHandler
const geolocationState = this._geolocationHandler.geolocationState
const lastClick = this.lastClick
const state = this._mapProperties
if (
geolocationState.permission.data !== "granted" &&
geolocationState.currentGPSLocation.data === undefined
) {
lastClick.setData(new Date())
geolocationState.requestMoment.setData(new Date())
await geolocationState.requestPermission()
}
if (geolocationState.allowMoving.data === false) {
// Unlock
geolocationState.allowMoving.setData(true)
return
}
// A location _is_ known! Let's move to this location
const currentLocation = geolocationState.currentGPSLocation.data
if (currentLocation === undefined) {
// No location is known yet, not much we can do
lastClick.setData(new Date())
return
}
const inBounds = state.bounds.data.contains([
currentLocation.longitude,
currentLocation.latitude,
])
geolocationHandler.MoveMapToCurrentLocation()
if (inBounds) {
state.zoom.update((z) => z + 3)
}
2023-12-18 01:30:02 +01:00
if (this.lastClickWithinThreeSecs.data) {
geolocationState.allowMoving.setData(false)
lastClick.setData(undefined)
return
}
lastClick.setData(new Date())
}
}