| 
									
										
										
										
											2022-12-22 04:13:52 +01:00
										 |  |  | import { VariableUiElement } from "../Base/VariableUIElement" | 
					
						
							|  |  |  | import Svg from "../../Svg" | 
					
						
							| 
									
										
										
										
											2023-12-12 17:08:59 +01:00
										 |  |  | import { Store, UIEventSource } from "../../Logic/UIEventSource" | 
					
						
							| 
									
										
										
										
											2022-12-22 04:13:52 +01:00
										 |  |  | import GeoLocationHandler from "../../Logic/Actors/GeoLocationHandler" | 
					
						
							| 
									
										
										
										
											2022-12-24 03:44:21 +01:00
										 |  |  | import Hotkeys from "../Base/Hotkeys" | 
					
						
							| 
									
										
										
										
											2022-12-28 00:37:48 +01:00
										 |  |  | import Translations from "../i18n/Translations" | 
					
						
							| 
									
										
										
										
											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" | 
					
						
							| 
									
										
										
										
											2022-12-22 04:13:52 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							|  |  |  |  * Displays an icon depending on the state of the geolocation. | 
					
						
							|  |  |  |  * Will set the 'lock' if clicked twice | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | export class GeolocationControl extends VariableUiElement { | 
					
						
							| 
									
										
										
										
											2023-12-12 17:08:59 +01:00
										 |  |  |     public readonly lastClick = new UIEventSource<Date>(undefined) | 
					
						
							|  |  |  |     private readonly _geolocationHandler: GeoLocationHandler | 
					
						
							|  |  |  |     private readonly _mapProperties: MapProperties | 
					
						
							|  |  |  |     private readonly _lastClickWithinThreeSecs: Store<boolean> | 
					
						
							|  |  |  |     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) | 
					
						
							|  |  |  |         }) | 
					
						
							| 
									
										
										
										
											2022-12-22 04:13:52 +01:00
										 |  |  |         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 | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         ) | 
					
						
							| 
									
										
										
										
											2023-02-07 02:11:17 +01:00
										 |  |  |         const geolocationState = geolocationHandler?.geolocationState | 
					
						
							| 
									
										
										
										
											2022-12-22 04:13:52 +01:00
										 |  |  |         super( | 
					
						
							| 
									
										
										
										
											2023-02-07 02:11:17 +01:00
										 |  |  |             geolocationState?.permission?.map( | 
					
						
							| 
									
										
										
										
											2022-12-22 04:13:52 +01:00
										 |  |  |                 (permission) => { | 
					
						
							|  |  |  |                     if (permission === "denied") { | 
					
						
							|  |  |  |                         return Svg.location_refused_svg() | 
					
						
							|  |  |  |                     } | 
					
						
							| 
									
										
										
										
											2023-03-24 19:21:15 +01:00
										 |  |  |                     if (!geolocationState.allowMoving.data) { | 
					
						
							| 
									
										
										
										
											2022-12-22 04:13:52 +01:00
										 |  |  |                         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() | 
					
						
							|  |  |  |                         } | 
					
						
							| 
									
										
										
										
											2022-12-22 04:13:52 +01:00
										 |  |  |                         // 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() | 
					
						
							| 
									
										
										
										
											2022-12-22 04:13:52 +01:00
										 |  |  |                         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
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-28 00:37:48 +01:00
										 |  |  |                     if (lastClickWithinThreeSecs.data) { | 
					
						
							| 
									
										
										
										
											2022-12-22 04:13:52 +01:00
										 |  |  |                         return Svg.location_unlocked_svg() | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                     // We have a location, so we show a dot in the center
 | 
					
						
							|  |  |  |                     return Svg.location_svg() | 
					
						
							|  |  |  |                 }, | 
					
						
							|  |  |  |                 [ | 
					
						
							|  |  |  |                     geolocationState.currentGPSLocation, | 
					
						
							| 
									
										
										
										
											2023-03-24 19:21:15 +01:00
										 |  |  |                     geolocationState.allowMoving, | 
					
						
							| 
									
										
										
										
											2022-12-22 04:13:52 +01:00
										 |  |  |                     geolocationHandler.mapHasMoved, | 
					
						
							|  |  |  |                     lastClickWithinThreeSecs, | 
					
						
							| 
									
										
										
										
											2023-02-09 03:12:21 +01:00
										 |  |  |                     lastRequestWithinTimeout, | 
					
						
							| 
									
										
										
										
											2022-12-22 04:13:52 +01:00
										 |  |  |                 ] | 
					
						
							|  |  |  |             ) | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-12-12 17:08:59 +01:00
										 |  |  |         this._geolocationHandler = geolocationHandler | 
					
						
							|  |  |  |         this._mapProperties = state | 
					
						
							| 
									
										
										
										
											2022-12-22 04:13:52 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-12-12 17:08:59 +01:00
										 |  |  |         this.lastClick = lastClick | 
					
						
							|  |  |  |         this._lastClickWithinThreeSecs = lastClickWithinThreeSecs | 
					
						
							| 
									
										
										
										
											2022-12-24 03:44:21 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-12-12 17:08:59 +01:00
										 |  |  |         this.onClick(() => this.handleClick()) | 
					
						
							|  |  |  |         Hotkeys.RegisterHotkey({ nomod: "L" }, Translations.t.hotkeyDocumentation.geolocate, () => | 
					
						
							|  |  |  |             this.handleClick() | 
					
						
							| 
									
										
										
										
											2022-12-24 03:44:21 +01:00
										 |  |  |         ) | 
					
						
							| 
									
										
										
										
											2022-12-22 04:13:52 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |         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) | 
					
						
							|  |  |  |         }) | 
					
						
							| 
									
										
										
										
											2022-12-22 04:13:52 +01:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-12-12 17:08:59 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     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) | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (this._lastClickWithinThreeSecs.data) { | 
					
						
							|  |  |  |             geolocationState.allowMoving.setData(false) | 
					
						
							|  |  |  |             lastClick.setData(undefined) | 
					
						
							|  |  |  |             return | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         lastClick.setData(new Date()) | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-12-22 04:13:52 +01:00
										 |  |  | } |