mapcomplete/UI/BigComponents/GeolocationControl.ts

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

157 lines
5.8 KiB
TypeScript
Raw Normal View History

import { VariableUiElement } from "../Base/VariableUIElement"
import Svg from "../../Svg"
import { UIEventSource } from "../../Logic/UIEventSource"
import GeoLocationHandler from "../../Logic/Actors/GeoLocationHandler"
import { BBox } from "../../Logic/BBox"
import Loc from "../../Models/Loc"
import Hotkeys from "../Base/Hotkeys"
import Translations from "../i18n/Translations"
2023-02-09 03:12:21 +01:00
import Constants from "../../Models/Constants"
/**
* Displays an icon depending on the state of the geolocation.
* Will set the 'lock' if clicked twice
*/
export class GeolocationControl extends VariableUiElement {
constructor(
geolocationHandler: GeoLocationHandler,
state: {
locationControl: UIEventSource<Loc>
currentBounds: UIEventSource<BBox>
}
) {
const lastClick = 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
console.log("Timediff", timeDiff)
return timeDiff <= Constants.zoomToLocationTimeout
}
)
2023-02-07 02:11:17 +01:00
const geolocationState = geolocationHandler?.geolocationState
super(
2023-02-07 02:11:17 +01:00
geolocationState?.permission?.map(
(permission) => {
if (permission === "denied") {
return Svg.location_refused_svg()
}
if (geolocationState.isLocked.data) {
return Svg.location_locked_svg()
}
2022-12-23 15:52:22 +01:00
if (geolocationState.currentGPSLocation.data === undefined) {
if (permission === "prompt") {
return Svg.location_empty_svg()
}
// Position not yet found, but permission is either requested or granted: we spin to indicate activity
2023-02-09 03:12:21 +01:00
const icon =
!geolocationHandler.mapHasMoved.data || lastRequestWithinTimeout.data
? Svg.location_svg()
: Svg.location_empty_svg()
return icon
.SetClass("cursor-wait")
.SetStyle("animation: spin 4s linear infinite;")
}
2022-12-23 15:52:22 +01:00
// We have a location, so we show a dot in the center
if (lastClickWithinThreeSecs.data) {
return Svg.location_unlocked_svg()
}
// We have a location, so we show a dot in the center
return Svg.location_svg()
},
[
geolocationState.currentGPSLocation,
geolocationState.isLocked,
geolocationHandler.mapHasMoved,
lastClickWithinThreeSecs,
2023-02-09 03:12:21 +01:00
lastRequestWithinTimeout,
]
)
)
async function handleClick() {
if (
geolocationState.permission.data !== "granted" &&
geolocationState.currentGPSLocation.data === undefined
) {
2023-02-09 03:12:21 +01:00
lastClick.setData(new Date())
geolocationState.requestMoment.setData(new Date())
await geolocationState.requestPermission()
}
if (geolocationState.isLocked.data === true) {
// Unlock
geolocationState.isLocked.setData(false)
return
}
if (geolocationState.currentGPSLocation.data === undefined) {
// No location is known yet, not much we can do
2023-02-09 03:12:21 +01:00
lastClick.setData(new Date())
return
}
// A location _is_ known! Let's move to this location
const currentLocation = geolocationState.currentGPSLocation.data
const inBounds = state.currentBounds.data.contains([
currentLocation.longitude,
currentLocation.latitude,
])
geolocationHandler.MoveMapToCurrentLocation()
if (inBounds) {
const lc = state.locationControl.data
state.locationControl.setData({
...lc,
zoom: lc.zoom + 3,
})
}
if (lastClickWithinThreeSecs.data) {
geolocationState.isLocked.setData(true)
lastClick.setData(undefined)
return
}
lastClick.setData(new Date())
}
this.onClick(handleClick)
Hotkeys.RegisterHotkey(
{ nomod: "L" },
Translations.t.hotkeyDocumentation.geolocate,
handleClick
)
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)
})
}
}