Refactor geolocation handler into multiple parts, fix lock behaviour

This commit is contained in:
Pieter Vander Vennet 2022-12-22 04:13:52 +01:00
parent e10c9e87ca
commit 4de76136de
7 changed files with 362 additions and 372 deletions

View file

@ -0,0 +1,99 @@
import { VariableUiElement } from "../Base/VariableUIElement"
import Svg from "../../Svg"
import { UIEventSource } from "../../Logic/UIEventSource"
import GeoLocationHandler from "../../Logic/Actors/GeoLocationHandler"
/**
* 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) {
const lastClick = new UIEventSource<Date>(undefined)
const lastClickWithinThreeSecs = lastClick.map((lastClick) => {
if (lastClick === undefined) {
return false
}
const timeDiff = (new Date().getTime() - lastClick.getTime()) / 1000
return timeDiff <= 3
})
const geolocationState = geolocationHandler.geolocationState
super(
geolocationState.permission.map(
(permission) => {
if (permission === "denied") {
return Svg.location_refused_svg()
}
if (geolocationState.isLocked.data) {
return Svg.location_locked_svg()
}
if (permission === "prompt") {
return Svg.location_empty_svg()
}
if (geolocationState.currentGPSLocation === undefined) {
// Position not yet found, but permission is either requested or granted: we spin to indicate activity
const icon = !geolocationHandler.mapHasMoved.data
? Svg.location_svg()
: Svg.location_empty_svg()
return icon
.SetClass("cursor-wait")
.SetStyle("animation: spin 4s linear infinite;")
}
if (
lastClickWithinThreeSecs.data &&
geolocationState.permission.data === "granted"
) {
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,
]
)
)
this.onClick(async () => {
if (geolocationState.permission.data !== "granted") {
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
return
}
// A location _is_ known! Let's zoom to this location
geolocationHandler.MoveMapToCurrentLocation()
if (lastClickWithinThreeSecs.data && geolocationState.permission.data === "granted") {
geolocationState.isLocked.setData(true)
lastClick.setData(undefined)
return
}
lastClick.setData(new Date())
})
lastClick.addCallbackAndRunD((_) => {
window.setTimeout(() => {
if (lastClickWithinThreeSecs.data) {
lastClick.ping()
}
}, 500)
})
}
}

View file

@ -5,18 +5,16 @@ import GeoLocationHandler from "../../Logic/Actors/GeoLocationHandler"
import Svg from "../../Svg"
import MapState from "../../Logic/State/MapState"
import FeaturePipeline from "../../Logic/FeatureSource/FeaturePipeline"
import { Utils } from "../../Utils"
import { TagUtils } from "../../Logic/Tags/TagUtils"
import { BBox } from "../../Logic/BBox"
import { OsmFeature } from "../../Models/OsmFeature"
import LevelSelector from "./LevelSelector"
import { GeolocationControl } from "./GeolocationControl"
export default class RightControls extends Combine {
constructor(state: MapState & { featurePipeline: FeaturePipeline }) {
const geolocatioHandler = new GeoLocationHandler(state)
constructor(
state: MapState & { featurePipeline: FeaturePipeline },
geolocationHandler: GeoLocationHandler
) {
const geolocationButton = new Toggle(
new MapControlButton(geolocatioHandler, {
new MapControlButton(new GeolocationControl(geolocationHandler), {
dontStyle: true,
}).SetClass("p-1"),
undefined,

View file

@ -29,6 +29,8 @@ import Img from "./Base/Img"
import UserInformationPanel from "./BigComponents/UserInformation"
import { LoginToggle } from "./Popup/LoginButton"
import { FixedUiElement } from "./Base/FixedUiElement"
import GeoLocationHandler from "../Logic/Actors/GeoLocationHandler"
import { GeoLocationState } from "../Logic/State/GeoLocationState"
/**
* The default MapComplete GUI initializer
@ -38,10 +40,14 @@ import { FixedUiElement } from "./Base/FixedUiElement"
export default class DefaultGUI {
private readonly guiState: DefaultGuiState
private readonly state: FeaturePipelineState
private readonly geolocationHandler: GeoLocationHandler | undefined
constructor(state: FeaturePipelineState, guiState: DefaultGuiState) {
this.state = state
this.guiState = guiState
if (this.state.featureSwitchGeolocation.data) {
this.geolocationHandler = new GeoLocationHandler(new GeoLocationState(), state)
}
}
public setup() {
@ -231,15 +237,16 @@ export default class DefaultGUI {
.SetClass("flex items-center justify-center normal-background h-full")
.AttachTo("on-small-screen")
new Combine([Toggle.If(state.featureSwitchSearch, () =>
new SearchAndGo(state).SetClass(
"shadow rounded-full h-min w-full overflow-hidden sm:max-w-sm pointer-events-auto"
)
)])
.AttachTo("top-right")
new Combine([
Toggle.If(state.featureSwitchSearch, () =>
new SearchAndGo(state).SetClass(
"shadow rounded-full h-min w-full overflow-hidden sm:max-w-sm pointer-events-auto"
)
),
]).AttachTo("top-right")
new LeftControls(state, guiState).AttachTo("bottom-left")
new RightControls(state).AttachTo("bottom-right")
new RightControls(state, this.geolocationHandler).AttachTo("bottom-right")
new CenterMessageBox(state).AttachTo("centermessage")
document.getElementById("centermessage").classList.add("pointer-events-none")

View file

@ -1,7 +1,7 @@
import { Utils } from "../../Utils"
import { Feature } from "geojson"
import { Point } from "@turf/turf"
import { GeoLocationPointProperties } from "../../Logic/Actors/GeoLocationHandler"
import { GeoLocationPointProperties } from "../../Logic/State/GeoLocationState"
import UploadTraceToOsmUI from "../BigComponents/UploadTraceToOsmUI"
import { SpecialVisualization } from "../SpecialVisualization"