| 
									
										
										
										
											2023-09-28 23:50:27 +02:00
										 |  |  | import LayoutConfig from "../../Models/ThemeConfig/LayoutConfig" | 
					
						
							|  |  |  | import { OsmConnection } from "../Osm/OsmConnection" | 
					
						
							|  |  |  | import { MangroveIdentity } from "../Web/MangroveReviews" | 
					
						
							|  |  |  | import { Store, Stores, UIEventSource } from "../UIEventSource" | 
					
						
							|  |  |  | import StaticFeatureSource from "../FeatureSource/Sources/StaticFeatureSource" | 
					
						
							|  |  |  | import { FeatureSource } from "../FeatureSource/FeatureSource" | 
					
						
							|  |  |  | import { Feature } from "geojson" | 
					
						
							|  |  |  | import { Utils } from "../../Utils" | 
					
						
							|  |  |  | import translators from "../../assets/translators.json" | 
					
						
							|  |  |  | import codeContributors from "../../assets/contributors.json" | 
					
						
							|  |  |  | import LayerConfig from "../../Models/ThemeConfig/LayerConfig" | 
					
						
							|  |  |  | import { LayerConfigJson } from "../../Models/ThemeConfig/Json/LayerConfigJson" | 
					
						
							|  |  |  | import usersettings from "../../../src/assets/generated/layers/usersettings.json" | 
					
						
							|  |  |  | import Locale from "../../UI/i18n/Locale" | 
					
						
							|  |  |  | import LinkToWeblate from "../../UI/Base/LinkToWeblate" | 
					
						
							|  |  |  | import FeatureSwitchState from "./FeatureSwitchState" | 
					
						
							|  |  |  | import Constants from "../../Models/Constants" | 
					
						
							|  |  |  | import { QueryParameters } from "../Web/QueryParameters" | 
					
						
							|  |  |  | import { ThemeMetaTagging } from "./UserSettingsMetaTagging" | 
					
						
							|  |  |  | import { MapProperties } from "../../Models/MapProperties" | 
					
						
							| 
									
										
										
										
											2024-08-10 12:09:55 +02:00
										 |  |  | import Showdown from "showdown" | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-15 05:20:02 +02:00
										 |  |  | /** | 
					
						
							|  |  |  |  * The part of the state which keeps track of user-related stuff, e.g. the OSM-connection, | 
					
						
							|  |  |  |  * which layers they enabled, ... | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2023-03-24 19:21:15 +01:00
										 |  |  | export default class UserRelatedState { | 
					
						
							| 
									
										
										
										
											2023-12-26 12:09:48 +01:00
										 |  |  |     public static readonly usersettingsConfig = UserRelatedState.initUserSettingsState() | 
					
						
							| 
									
										
										
										
											2023-05-19 11:22:25 +02:00
										 |  |  |     public static readonly availableUserSettingsIds: string[] = | 
					
						
							|  |  |  |         UserRelatedState.usersettingsConfig?.tagRenderings?.map((tr) => tr.id) ?? [] | 
					
						
							| 
									
										
										
										
											2023-07-17 01:07:01 +02:00
										 |  |  |     public static readonly SHOW_TAGS_VALUES = ["always", "yes", "full"] as const | 
					
						
							| 
									
										
										
										
											2021-10-15 05:20:02 +02:00
										 |  |  |     /** | 
					
						
							|  |  |  |      The user credentials | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     public osmConnection: OsmConnection | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * The key for mangrove | 
					
						
							|  |  |  |      */ | 
					
						
							| 
									
										
										
										
											2023-03-28 05:13:48 +02:00
										 |  |  |     public readonly mangroveIdentity: MangroveIdentity | 
					
						
							| 
									
										
										
										
											2022-06-22 20:18:17 +02:00
										 |  |  |     public readonly installedUserThemes: Store<string[]> | 
					
						
							| 
									
										
										
										
											2023-03-08 01:36:27 +01:00
										 |  |  |     public readonly showAllQuestionsAtOnce: UIEventSource<boolean> | 
					
						
							| 
									
										
										
										
											2023-06-14 20:39:36 +02:00
										 |  |  |     public readonly showTags: UIEventSource<"no" | undefined | "always" | "yes" | "full"> | 
					
						
							| 
									
										
										
										
											2023-12-07 21:57:20 +01:00
										 |  |  |     public readonly showCrosshair: UIEventSource<"yes" | "always" | "no" | undefined> | 
					
						
							| 
									
										
										
										
											2023-07-18 01:26:04 +02:00
										 |  |  |     public readonly fixateNorth: UIEventSource<undefined | "yes"> | 
					
						
							| 
									
										
										
										
											2024-01-01 03:29:57 +01:00
										 |  |  |     public readonly a11y: UIEventSource<undefined | "always" | "never" | "default"> | 
					
						
							| 
									
										
										
										
											2023-03-24 19:21:15 +01:00
										 |  |  |     public readonly homeLocation: FeatureSource | 
					
						
							| 
									
										
										
										
											2024-05-06 18:58:19 +02:00
										 |  |  |     public readonly morePrivacy: UIEventSource<undefined | "yes" | "no"> | 
					
						
							| 
									
										
										
										
											2023-11-19 01:05:15 +01:00
										 |  |  |     /** | 
					
						
							|  |  |  |      * The language as saved into the preferences of the user, if logged in. | 
					
						
							|  |  |  |      * Note that this is _different_ from the languages a user can set via the osm.org interface here: https://www.openstreetmap.org/preferences
 | 
					
						
							|  |  |  |      */ | 
					
						
							| 
									
										
										
										
											2023-06-06 00:03:50 +02:00
										 |  |  |     public readonly language: UIEventSource<string> | 
					
						
							| 
									
										
										
										
											2023-09-28 23:50:27 +02:00
										 |  |  |     public readonly preferredBackgroundLayer: UIEventSource< | 
					
						
							|  |  |  |         string | "photo" | "map" | "osmbasedmap" | undefined | 
					
						
							|  |  |  |     > | 
					
						
							|  |  |  |     public readonly imageLicense: UIEventSource<string> | 
					
						
							| 
									
										
										
										
											2023-03-24 19:21:15 +01:00
										 |  |  |     /** | 
					
						
							|  |  |  |      * The number of seconds that the GPS-locations are stored in memory. | 
					
						
							|  |  |  |      * Time in seconds | 
					
						
							|  |  |  |      */ | 
					
						
							| 
									
										
										
										
											2023-04-07 02:13:57 +02:00
										 |  |  |     public readonly gpsLocationHistoryRetentionTime = new UIEventSource( | 
					
						
							| 
									
										
										
										
											2023-03-24 19:21:15 +01:00
										 |  |  |         7 * 24 * 60 * 60, | 
					
						
							|  |  |  |         "gps_location_retention" | 
					
						
							|  |  |  |     ) | 
					
						
							| 
									
										
										
										
											2024-06-21 02:36:36 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-06-24 13:11:35 +02:00
										 |  |  |     public readonly addNewFeatureMode = new UIEventSource< | 
					
						
							|  |  |  |         "button" | "button_click_right" | "button_click" | "click" | "click_right" | 
					
						
							|  |  |  |     >("button_click_right") | 
					
						
							| 
									
										
										
										
											2024-06-21 02:36:36 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-07 02:13:57 +02:00
										 |  |  |     /** | 
					
						
							|  |  |  |      * Preferences as tags exposes many preferences and state properties as record. | 
					
						
							|  |  |  |      * This is used to bridge the internal state with the usersettings.json layerconfig file | 
					
						
							| 
									
										
										
										
											2023-09-24 16:34:36 +02:00
										 |  |  |      * | 
					
						
							|  |  |  |      * Some metainformation that should not be edited starts with a single underscore | 
					
						
							|  |  |  |      * Constants and query parameters start with two underscores | 
					
						
							|  |  |  |      * Note: these are linked via OsmConnection.preferences which exports all preferences as UIEventSource | 
					
						
							| 
									
										
										
										
											2023-04-07 02:13:57 +02:00
										 |  |  |      */ | 
					
						
							|  |  |  |     public readonly preferencesAsTags: UIEventSource<Record<string, string>> | 
					
						
							| 
									
										
										
										
											2023-09-28 23:50:27 +02:00
										 |  |  |     private readonly _mapProperties: MapProperties | 
					
						
							| 
									
										
										
										
											2023-04-07 02:13:57 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-22 02:54:46 +02:00
										 |  |  |     private readonly _recentlyVisitedThemes: UIEventSource<string[]> | 
					
						
							|  |  |  |     public readonly recentlyVisitedThemes: Store<string[]> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-07 02:13:57 +02:00
										 |  |  |     constructor( | 
					
						
							|  |  |  |         osmConnection: OsmConnection, | 
					
						
							| 
									
										
										
										
											2023-04-14 17:53:08 +02:00
										 |  |  |         layout?: LayoutConfig, | 
					
						
							| 
									
										
										
										
											2023-09-24 16:34:36 +02:00
										 |  |  |         featureSwitches?: FeatureSwitchState, | 
					
						
							|  |  |  |         mapProperties?: MapProperties | 
					
						
							| 
									
										
										
										
											2023-04-07 02:13:57 +02:00
										 |  |  |     ) { | 
					
						
							| 
									
										
										
										
											2023-03-24 19:21:15 +01:00
										 |  |  |         this.osmConnection = osmConnection | 
					
						
							| 
									
										
										
										
											2023-09-28 23:50:27 +02:00
										 |  |  |         this._mapProperties = mapProperties | 
					
						
							| 
									
										
										
										
											2023-02-09 02:45:19 +01:00
										 |  |  |         { | 
					
						
							|  |  |  |             const translationMode: UIEventSource<undefined | "true" | "false" | "mobile" | string> = | 
					
						
							| 
									
										
										
										
											2023-04-07 02:13:57 +02:00
										 |  |  |                 this.osmConnection.GetPreference("translation-mode", "false") | 
					
						
							| 
									
										
										
										
											2023-02-09 02:45:19 +01:00
										 |  |  |             translationMode.addCallbackAndRunD((mode) => { | 
					
						
							|  |  |  |                 mode = mode.toLowerCase() | 
					
						
							|  |  |  |                 if (mode === "true" || mode === "yes") { | 
					
						
							|  |  |  |                     Locale.showLinkOnMobile.setData(false) | 
					
						
							|  |  |  |                     Locale.showLinkToWeblate.setData(true) | 
					
						
							|  |  |  |                 } else if (mode === "false" || mode === "no") { | 
					
						
							|  |  |  |                     Locale.showLinkToWeblate.setData(false) | 
					
						
							|  |  |  |                 } else if (mode === "mobile") { | 
					
						
							|  |  |  |                     Locale.showLinkOnMobile.setData(true) | 
					
						
							|  |  |  |                     Locale.showLinkToWeblate.setData(true) | 
					
						
							|  |  |  |                 } else { | 
					
						
							|  |  |  |                     Locale.showLinkOnMobile.setData(false) | 
					
						
							|  |  |  |                     Locale.showLinkToWeblate.setData(false) | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             }) | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2022-02-16 01:46:55 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-08 01:36:27 +01:00
										 |  |  |         this.showAllQuestionsAtOnce = UIEventSource.asBoolean( | 
					
						
							|  |  |  |             this.osmConnection.GetPreference("show-all-questions", "false", { | 
					
						
							|  |  |  |                 documentation: | 
					
						
							| 
									
										
										
										
											2024-08-22 02:54:46 +02:00
										 |  |  |                     "Either 'true' or 'false'. If set, all questions will be shown all at once" | 
					
						
							| 
									
										
										
										
											2023-03-08 01:36:27 +01:00
										 |  |  |             }) | 
					
						
							|  |  |  |         ) | 
					
						
							| 
									
										
										
										
											2023-06-06 00:03:50 +02:00
										 |  |  |         this.language = this.osmConnection.GetPreference("language") | 
					
						
							| 
									
										
										
										
											2024-05-06 18:58:19 +02:00
										 |  |  |         this.showTags = this.osmConnection.GetPreference("show_tags") | 
					
						
							|  |  |  |         this.showCrosshair = this.osmConnection.GetPreference("show_crosshair") | 
					
						
							|  |  |  |         this.fixateNorth = this.osmConnection.GetPreference("fixate-north") | 
					
						
							|  |  |  |         this.morePrivacy = this.osmConnection.GetPreference("more_privacy", "no") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         this.a11y = this.osmConnection.GetPreference("a11y") | 
					
						
							| 
									
										
										
										
											2024-01-01 03:29:57 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-15 05:20:02 +02:00
										 |  |  |         this.mangroveIdentity = new MangroveIdentity( | 
					
						
							| 
									
										
										
										
											2024-02-20 16:53:26 +01:00
										 |  |  |             this.osmConnection.GetLongPreference("identity", "mangrove"), | 
					
						
							|  |  |  |             this.osmConnection.GetPreference("identity-creation-date", "mangrove") | 
					
						
							| 
									
										
										
										
											2021-10-15 05:20:02 +02:00
										 |  |  |         ) | 
					
						
							| 
									
										
										
										
											2023-09-28 23:50:27 +02:00
										 |  |  |         this.preferredBackgroundLayer = this.osmConnection.GetPreference( | 
					
						
							|  |  |  |             "preferred-background-layer", | 
					
						
							|  |  |  |             undefined, | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 documentation: | 
					
						
							| 
									
										
										
										
											2024-08-22 02:54:46 +02:00
										 |  |  |                     "The ID of a layer or layer category that MapComplete uses by default" | 
					
						
							| 
									
										
										
										
											2023-09-28 23:50:27 +02:00
										 |  |  |             } | 
					
						
							|  |  |  |         ) | 
					
						
							| 
									
										
										
										
											2021-10-15 05:20:02 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-06-21 02:36:36 +02:00
										 |  |  |         this.addNewFeatureMode = this.osmConnection.GetPreference( | 
					
						
							|  |  |  |             "preferences-add-new-mode", | 
					
						
							|  |  |  |             "button_click_right", | 
					
						
							|  |  |  |             { | 
					
						
							| 
									
										
										
										
											2024-08-22 02:54:46 +02:00
										 |  |  |                 documentation: "How adding a new feature is done" | 
					
						
							| 
									
										
										
										
											2024-06-21 02:36:36 +02:00
										 |  |  |             } | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-28 23:50:27 +02:00
										 |  |  |         this.imageLicense = this.osmConnection.GetPreference("pictures-license", "CC0", { | 
					
						
							| 
									
										
										
										
											2024-08-22 02:54:46 +02:00
										 |  |  |             documentation: "The license under which new images are uploaded" | 
					
						
							| 
									
										
										
										
											2023-09-25 02:13:24 +02:00
										 |  |  |         }) | 
					
						
							| 
									
										
										
										
											2022-06-21 18:22:09 +02:00
										 |  |  |         this.installedUserThemes = this.InitInstalledUserThemes() | 
					
						
							| 
									
										
										
										
											2023-03-24 19:21:15 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |         this.homeLocation = this.initHomeLocation() | 
					
						
							| 
									
										
										
										
											2023-04-07 02:13:57 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-14 17:53:08 +02:00
										 |  |  |         this.preferencesAsTags = this.initAmendedPrefs(layout, featureSwitches) | 
					
						
							| 
									
										
										
										
											2023-07-27 01:50:23 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-22 02:54:46 +02:00
										 |  |  |         const prefs = this.osmConnection | 
					
						
							|  |  |  |         this._recentlyVisitedThemes = UIEventSource.asObject(prefs.GetLongPreference("recently-visited-themes"), []) | 
					
						
							|  |  |  |         this.recentlyVisitedThemes = this._recentlyVisitedThemes | 
					
						
							|  |  |  |         if (layout) { | 
					
						
							|  |  |  |             const osmConn =this.osmConnection | 
					
						
							|  |  |  |             const recentlyVisited = this._recentlyVisitedThemes | 
					
						
							|  |  |  |             function update() { | 
					
						
							|  |  |  |                 if (!osmConn.isLoggedIn.data) { | 
					
						
							|  |  |  |                     return | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |                 const previously = recentlyVisited.data | 
					
						
							|  |  |  |                 if (previously[0] === layout.id) { | 
					
						
							|  |  |  |                     return true | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |                 const newThemes = Utils.Dedup([layout.id, ...previously]).slice(0, 30) | 
					
						
							|  |  |  |                 recentlyVisited.set(newThemes) | 
					
						
							|  |  |  |                 return true | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             this._recentlyVisitedThemes.addCallbackAndRun(() => update()) | 
					
						
							|  |  |  |             this.osmConnection.isLoggedIn.addCallbackAndRun(() => update()) | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-27 01:50:23 +02:00
										 |  |  |         this.syncLanguage() | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     private syncLanguage() { | 
					
						
							|  |  |  |         if (QueryParameters.wasInitialized("language")) { | 
					
						
							|  |  |  |             return | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-19 01:05:15 +01:00
										 |  |  |         this.language.syncWith(Locale.language) | 
					
						
							| 
									
										
										
										
											2021-10-15 05:20:02 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-12-26 12:09:48 +01:00
										 |  |  |     private static initUserSettingsState(): LayerConfig { | 
					
						
							| 
									
										
										
										
											2023-06-14 20:39:36 +02:00
										 |  |  |         try { | 
					
						
							|  |  |  |             return new LayerConfig(<LayerConfigJson>usersettings, "userinformationpanel") | 
					
						
							|  |  |  |         } catch (e) { | 
					
						
							| 
									
										
										
										
											2023-05-19 11:22:25 +02:00
										 |  |  |             return undefined | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-21 18:22:09 +02:00
										 |  |  |     public GetUnofficialTheme(id: string): | 
					
						
							|  |  |  |         | { | 
					
						
							| 
									
										
										
										
											2024-08-22 02:54:46 +02:00
										 |  |  |         id: string | 
					
						
							|  |  |  |         icon: string | 
					
						
							|  |  |  |         title: any | 
					
						
							|  |  |  |         shortDescription: any | 
					
						
							|  |  |  |         definition?: any | 
					
						
							|  |  |  |         isOfficial: boolean | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-06-21 18:22:09 +02:00
										 |  |  |         | undefined { | 
					
						
							|  |  |  |         console.log("GETTING UNOFFICIAL THEME") | 
					
						
							|  |  |  |         const pref = this.osmConnection.GetLongPreference("unofficial-theme-" + id) | 
					
						
							|  |  |  |         const str = pref.data | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-21 18:22:09 +02:00
										 |  |  |         if (str === undefined || str === "undefined" || str === "") { | 
					
						
							|  |  |  |             pref.setData(null) | 
					
						
							|  |  |  |             return undefined | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-21 18:22:09 +02:00
										 |  |  |         try { | 
					
						
							|  |  |  |             const value: { | 
					
						
							|  |  |  |                 id: string | 
					
						
							|  |  |  |                 icon: string | 
					
						
							|  |  |  |                 title: any | 
					
						
							|  |  |  |                 shortDescription: any | 
					
						
							|  |  |  |                 definition?: any | 
					
						
							|  |  |  |                 isOfficial: boolean | 
					
						
							|  |  |  |             } = JSON.parse(str) | 
					
						
							|  |  |  |             value.isOfficial = false | 
					
						
							|  |  |  |             return value | 
					
						
							|  |  |  |         } catch (e) { | 
					
						
							|  |  |  |             console.warn( | 
					
						
							|  |  |  |                 "Removing theme " + | 
					
						
							| 
									
										
										
										
											2024-08-22 02:54:46 +02:00
										 |  |  |                 id + | 
					
						
							|  |  |  |                 " as it could not be parsed from the preferences; the content is:", | 
					
						
							| 
									
										
										
										
											2022-06-21 18:22:09 +02:00
										 |  |  |                 str | 
					
						
							|  |  |  |             ) | 
					
						
							|  |  |  |             pref.setData(null) | 
					
						
							|  |  |  |             return undefined | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-02-09 02:45:19 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-24 19:21:15 +01:00
										 |  |  |     public markLayoutAsVisited(layout: LayoutConfig) { | 
					
						
							|  |  |  |         if (!layout) { | 
					
						
							|  |  |  |             console.error("Trying to mark a layout as visited, but ", layout, " got passed") | 
					
						
							|  |  |  |             return | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         if (layout.hideFromOverview) { | 
					
						
							|  |  |  |             this.osmConnection.isLoggedIn.addCallbackAndRunD((loggedIn) => { | 
					
						
							|  |  |  |                 if (loggedIn) { | 
					
						
							|  |  |  |                     this.osmConnection | 
					
						
							|  |  |  |                         .GetPreference("hidden-theme-" + layout?.id + "-enabled") | 
					
						
							|  |  |  |                         .setData("true") | 
					
						
							|  |  |  |                     return true | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             }) | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         if (!layout.official) { | 
					
						
							|  |  |  |             this.osmConnection.GetLongPreference("unofficial-theme-" + layout.id).setData( | 
					
						
							|  |  |  |                 JSON.stringify({ | 
					
						
							|  |  |  |                     id: layout.id, | 
					
						
							|  |  |  |                     icon: layout.icon, | 
					
						
							|  |  |  |                     title: layout.title.translations, | 
					
						
							|  |  |  |                     shortDescription: layout.shortDescription.translations, | 
					
						
							| 
									
										
										
										
											2024-08-22 02:54:46 +02:00
										 |  |  |                     definition: layout["definition"] | 
					
						
							| 
									
										
										
										
											2023-03-24 19:21:15 +01:00
										 |  |  |                 }) | 
					
						
							|  |  |  |             ) | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-07-17 01:07:01 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-09 02:45:19 +01:00
										 |  |  |     private InitInstalledUserThemes(): Store<string[]> { | 
					
						
							|  |  |  |         const prefix = "mapcomplete-unofficial-theme-" | 
					
						
							|  |  |  |         const postfix = "-combined-length" | 
					
						
							|  |  |  |         return this.osmConnection.preferencesHandler.preferences.map((prefs) => | 
					
						
							|  |  |  |             Object.keys(prefs) | 
					
						
							|  |  |  |                 .filter((k) => k.startsWith(prefix) && k.endsWith(postfix)) | 
					
						
							|  |  |  |                 .map((k) => k.substring(prefix.length, k.length - postfix.length)) | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-03-24 19:21:15 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     private initHomeLocation(): FeatureSource { | 
					
						
							|  |  |  |         const empty = [] | 
					
						
							| 
									
										
										
										
											2023-03-25 02:48:24 +01:00
										 |  |  |         const feature: Store<Feature[]> = Stores.ListStabilized( | 
					
						
							| 
									
										
										
										
											2023-03-24 19:21:15 +01:00
										 |  |  |             this.osmConnection.userDetails.map((userDetails) => { | 
					
						
							|  |  |  |                 if (userDetails === undefined) { | 
					
						
							|  |  |  |                     return undefined | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |                 const home = userDetails.home | 
					
						
							|  |  |  |                 if (home === undefined) { | 
					
						
							|  |  |  |                     return undefined | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |                 return [home.lon, home.lat] | 
					
						
							|  |  |  |             }) | 
					
						
							|  |  |  |         ).map((homeLonLat) => { | 
					
						
							|  |  |  |             if (homeLonLat === undefined) { | 
					
						
							|  |  |  |                 return empty | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             return [ | 
					
						
							| 
									
										
										
										
											2023-03-25 02:48:24 +01:00
										 |  |  |                 <Feature>{ | 
					
						
							|  |  |  |                     type: "Feature", | 
					
						
							|  |  |  |                     properties: { | 
					
						
							|  |  |  |                         id: "home", | 
					
						
							|  |  |  |                         "user:home": "yes", | 
					
						
							|  |  |  |                         _lon: homeLonLat[0], | 
					
						
							| 
									
										
										
										
											2024-08-22 02:54:46 +02:00
										 |  |  |                         _lat: homeLonLat[1] | 
					
						
							| 
									
										
										
										
											2023-03-25 02:48:24 +01:00
										 |  |  |                     }, | 
					
						
							|  |  |  |                     geometry: { | 
					
						
							|  |  |  |                         type: "Point", | 
					
						
							| 
									
										
										
										
											2024-08-22 02:54:46 +02:00
										 |  |  |                         coordinates: homeLonLat | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                 } | 
					
						
							| 
									
										
										
										
											2023-03-24 19:21:15 +01:00
										 |  |  |             ] | 
					
						
							|  |  |  |         }) | 
					
						
							|  |  |  |         return new StaticFeatureSource(feature) | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-04-07 02:13:57 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * Initialize the 'amended preferences'. | 
					
						
							| 
									
										
										
										
											2023-12-15 01:46:01 +01:00
										 |  |  |      * This is inherently a dirty and chaotic method, as it shoves many properties into this EventSource | 
					
						
							| 
									
										
										
										
											2023-04-07 02:13:57 +02:00
										 |  |  |      * */ | 
					
						
							| 
									
										
										
										
											2023-04-14 17:53:08 +02:00
										 |  |  |     private initAmendedPrefs( | 
					
						
							|  |  |  |         layout?: LayoutConfig, | 
					
						
							|  |  |  |         featureSwitches?: FeatureSwitchState | 
					
						
							|  |  |  |     ): UIEventSource<Record<string, string>> { | 
					
						
							| 
									
										
										
										
											2023-04-07 02:13:57 +02:00
										 |  |  |         const amendedPrefs = new UIEventSource<Record<string, string>>({ | 
					
						
							|  |  |  |             _theme: layout?.id, | 
					
						
							| 
									
										
										
										
											2023-09-24 18:24:10 +02:00
										 |  |  |             "_theme:backgroundLayer": layout?.defaultBackgroundId, | 
					
						
							| 
									
										
										
										
											2023-04-07 02:13:57 +02:00
										 |  |  |             _backend: this.osmConnection.Backend(), | 
					
						
							| 
									
										
										
										
											2023-04-20 17:42:07 +02:00
										 |  |  |             _applicationOpened: new Date().toISOString(), | 
					
						
							| 
									
										
										
										
											2023-06-14 20:39:36 +02:00
										 |  |  |             _supports_sharing: | 
					
						
							|  |  |  |                 typeof window === "undefined" ? "no" : window.navigator.share ? "yes" : "no", | 
					
						
							| 
									
										
										
										
											2024-08-22 02:54:46 +02:00
										 |  |  |             _iframe: Utils.isIframe ? "yes" : "no" | 
					
						
							| 
									
										
										
										
											2023-04-07 02:13:57 +02:00
										 |  |  |         }) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-11 02:17:41 +02:00
										 |  |  |         for (const key in Constants.userJourney) { | 
					
						
							| 
									
										
										
										
											2023-05-19 11:22:25 +02:00
										 |  |  |             amendedPrefs.data["__userjourney_" + key] = Constants.userJourney[key] | 
					
						
							| 
									
										
										
										
											2023-05-11 02:17:41 +02:00
										 |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-27 01:50:23 +02:00
										 |  |  |         for (const key of QueryParameters.initializedParameters()) { | 
					
						
							|  |  |  |             amendedPrefs.data["__url_parameter_initialized:" + key] = "yes" | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-07 02:13:57 +02:00
										 |  |  |         const osmConnection = this.osmConnection | 
					
						
							|  |  |  |         osmConnection.preferencesHandler.preferences.addCallback((newPrefs) => { | 
					
						
							|  |  |  |             for (const k in newPrefs) { | 
					
						
							| 
									
										
										
										
											2023-07-17 01:07:01 +02:00
										 |  |  |                 const v = newPrefs[k] | 
					
						
							| 
									
										
										
										
											2023-11-23 17:06:30 +01:00
										 |  |  |                 if (v === "undefined" || !v) { | 
					
						
							|  |  |  |                     continue | 
					
						
							|  |  |  |                 } | 
					
						
							| 
									
										
										
										
											2023-07-17 01:07:01 +02:00
										 |  |  |                 if (k.endsWith("-combined-length")) { | 
					
						
							|  |  |  |                     const l = Number(v) | 
					
						
							|  |  |  |                     const key = k.substring(0, k.length - "length".length) | 
					
						
							|  |  |  |                     let combined = "" | 
					
						
							|  |  |  |                     for (let i = 0; i < l; i++) { | 
					
						
							|  |  |  |                         combined += newPrefs[key + i] | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                     amendedPrefs.data[key.substring(0, key.length - "-combined-".length)] = combined | 
					
						
							|  |  |  |                 } else { | 
					
						
							|  |  |  |                     amendedPrefs.data[k] = newPrefs[k] | 
					
						
							|  |  |  |                 } | 
					
						
							| 
									
										
										
										
											2023-04-07 02:13:57 +02:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2023-07-17 01:07:01 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-07 02:13:57 +02:00
										 |  |  |             amendedPrefs.ping() | 
					
						
							|  |  |  |         }) | 
					
						
							|  |  |  |         const translationMode = osmConnection.GetPreference("translation-mode") | 
					
						
							| 
									
										
										
										
											2023-07-27 01:50:23 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-07 02:13:57 +02:00
										 |  |  |         Locale.language.mapD( | 
					
						
							|  |  |  |             (language) => { | 
					
						
							|  |  |  |                 amendedPrefs.data["_language"] = language | 
					
						
							|  |  |  |                 const trmode = translationMode.data | 
					
						
							|  |  |  |                 if ((trmode === "true" || trmode === "mobile") && layout !== undefined) { | 
					
						
							| 
									
										
										
										
											2023-12-26 12:09:48 +01:00
										 |  |  |                     const extraInspection = UserRelatedState.usersettingsConfig | 
					
						
							|  |  |  |                     const missing = layout.missingTranslations(extraInspection) | 
					
						
							| 
									
										
										
										
											2023-04-07 02:13:57 +02:00
										 |  |  |                     const total = missing.total | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                     const untranslated = missing.untranslated.get(language) ?? [] | 
					
						
							|  |  |  |                     const hasMissingTheme = untranslated.some((k) => k.startsWith("themes:")) | 
					
						
							|  |  |  |                     const missingLayers = Utils.Dedup( | 
					
						
							|  |  |  |                         untranslated | 
					
						
							|  |  |  |                             .filter((k) => k.startsWith("layers:")) | 
					
						
							|  |  |  |                             .map((k) => k.slice("layers:".length).split(".")[0]) | 
					
						
							|  |  |  |                     ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                     const zenLinks: { link: string; id: string }[] = Utils.NoNull([ | 
					
						
							|  |  |  |                         hasMissingTheme | 
					
						
							|  |  |  |                             ? { | 
					
						
							| 
									
										
										
										
											2024-08-22 02:54:46 +02:00
										 |  |  |                                 id: "theme:" + layout.id, | 
					
						
							|  |  |  |                                 link: LinkToWeblate.hrefToWeblateZen( | 
					
						
							|  |  |  |                                     language, | 
					
						
							|  |  |  |                                     "themes", | 
					
						
							|  |  |  |                                     layout.id | 
					
						
							|  |  |  |                                 ) | 
					
						
							|  |  |  |                             } | 
					
						
							| 
									
										
										
										
											2023-04-07 02:13:57 +02:00
										 |  |  |                             : undefined, | 
					
						
							|  |  |  |                         ...missingLayers.map((id) => ({ | 
					
						
							|  |  |  |                             id: "layer:" + id, | 
					
						
							| 
									
										
										
										
											2024-08-22 02:54:46 +02:00
										 |  |  |                             link: LinkToWeblate.hrefToWeblateZen(language, "layers", id) | 
					
						
							|  |  |  |                         })) | 
					
						
							| 
									
										
										
										
											2023-04-07 02:13:57 +02:00
										 |  |  |                     ]) | 
					
						
							|  |  |  |                     const untranslated_count = untranslated.length | 
					
						
							|  |  |  |                     amendedPrefs.data["_translation_total"] = "" + total | 
					
						
							|  |  |  |                     amendedPrefs.data["_translation_translated_count"] = | 
					
						
							|  |  |  |                         "" + (total - untranslated_count) | 
					
						
							|  |  |  |                     amendedPrefs.data["_translation_percentage"] = | 
					
						
							|  |  |  |                         "" + Math.floor((100 * (total - untranslated_count)) / total) | 
					
						
							|  |  |  |                     amendedPrefs.data["_translation_links"] = JSON.stringify(zenLinks) | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |                 amendedPrefs.ping() | 
					
						
							|  |  |  |             }, | 
					
						
							|  |  |  |             [translationMode] | 
					
						
							|  |  |  |         ) | 
					
						
							| 
									
										
										
										
											2023-09-22 11:20:22 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-20 13:33:38 +01:00
										 |  |  |         this.mangroveIdentity.getKeyId().addCallbackAndRun((kid) => { | 
					
						
							| 
									
										
										
										
											2024-02-15 03:11:10 +01:00
										 |  |  |             amendedPrefs.data["mangrove_kid"] = kid | 
					
						
							|  |  |  |             amendedPrefs.ping() | 
					
						
							|  |  |  |         }) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-22 11:20:22 +02:00
										 |  |  |         const usersettingMetaTagging = new ThemeMetaTagging() | 
					
						
							| 
									
										
										
										
											2023-04-07 02:13:57 +02:00
										 |  |  |         osmConnection.userDetails.addCallback((userDetails) => { | 
					
						
							|  |  |  |             for (const k in userDetails) { | 
					
						
							|  |  |  |                 amendedPrefs.data["_" + k] = "" + userDetails[k] | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2024-08-22 02:54:46 +02:00
										 |  |  |             if (userDetails.description) { | 
					
						
							| 
									
										
										
										
											2024-08-14 13:53:56 +02:00
										 |  |  |                 amendedPrefs.data["_description_html"] = Utils.purify( | 
					
						
							|  |  |  |                     new Showdown.Converter() | 
					
						
							|  |  |  |                         .makeHtml(userDetails.description) | 
					
						
							|  |  |  |                         ?.replace(/>/g, ">") | 
					
						
							|  |  |  |                         ?.replace(/</g, "<") | 
					
						
							|  |  |  |                         ?.replace(/\n/g, "") | 
					
						
							|  |  |  |                 ) | 
					
						
							| 
									
										
										
										
											2024-08-10 12:09:55 +02:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2023-04-07 02:13:57 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-22 11:20:22 +02:00
										 |  |  |             usersettingMetaTagging.metaTaggging_for_usersettings({ properties: amendedPrefs.data }) | 
					
						
							| 
									
										
										
										
											2023-04-07 02:13:57 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |             const simplifiedName = userDetails.name.toLowerCase().replace(/\s+/g, "") | 
					
						
							|  |  |  |             const isTranslator = translators.contributors.find( | 
					
						
							|  |  |  |                 (c: { contributor: string; commits: number }) => { | 
					
						
							|  |  |  |                     const replaced = c.contributor.toLowerCase().replace(/\s+/g, "") | 
					
						
							|  |  |  |                     return replaced === simplifiedName | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             ) | 
					
						
							|  |  |  |             if (isTranslator) { | 
					
						
							|  |  |  |                 amendedPrefs.data["_translation_contributions"] = "" + isTranslator.commits | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             const isCodeContributor = codeContributors.contributors.find( | 
					
						
							|  |  |  |                 (c: { contributor: string; commits: number }) => { | 
					
						
							|  |  |  |                     const replaced = c.contributor.toLowerCase().replace(/\s+/g, "") | 
					
						
							|  |  |  |                     return replaced === simplifiedName | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             ) | 
					
						
							|  |  |  |             if (isCodeContributor) { | 
					
						
							|  |  |  |                 amendedPrefs.data["_code_contributions"] = "" + isCodeContributor.commits | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             amendedPrefs.ping() | 
					
						
							|  |  |  |         }) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         amendedPrefs.addCallbackD((tags) => { | 
					
						
							|  |  |  |             for (const key in tags) { | 
					
						
							| 
									
										
										
										
											2023-04-20 17:42:07 +02:00
										 |  |  |                 if (key.startsWith("_") || key === "mapcomplete-language") { | 
					
						
							|  |  |  |                     // Language is managed seperately
 | 
					
						
							| 
									
										
										
										
											2023-04-07 02:13:57 +02:00
										 |  |  |                     continue | 
					
						
							|  |  |  |                 } | 
					
						
							| 
									
										
										
										
											2023-07-18 01:26:04 +02:00
										 |  |  |                 if (tags[key + "-combined-0"]) { | 
					
						
							|  |  |  |                     // A combined value exists
 | 
					
						
							|  |  |  |                     this.osmConnection.GetLongPreference(key, "").setData(tags[key]) | 
					
						
							|  |  |  |                 } else { | 
					
						
							|  |  |  |                     this.osmConnection | 
					
						
							|  |  |  |                         .GetPreference(key, undefined, { prefix: "" }) | 
					
						
							|  |  |  |                         .setData(tags[key]) | 
					
						
							|  |  |  |                 } | 
					
						
							| 
									
										
										
										
											2023-04-07 02:13:57 +02:00
										 |  |  |             } | 
					
						
							|  |  |  |         }) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-14 17:53:08 +02:00
										 |  |  |         for (const key in featureSwitches) { | 
					
						
							|  |  |  |             if (featureSwitches[key].addCallbackAndRun) { | 
					
						
							|  |  |  |                 featureSwitches[key].addCallbackAndRun((v) => { | 
					
						
							|  |  |  |                     const oldV = amendedPrefs.data["__" + key] | 
					
						
							|  |  |  |                     if (oldV === v) { | 
					
						
							|  |  |  |                         return | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                     amendedPrefs.data["__" + key] = "" + v | 
					
						
							|  |  |  |                     amendedPrefs.ping() | 
					
						
							|  |  |  |                 }) | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-28 23:50:27 +02:00
										 |  |  |         this._mapProperties?.rasterLayer?.addCallbackAndRun((l) => { | 
					
						
							| 
									
										
										
										
											2023-09-24 16:34:36 +02:00
										 |  |  |             amendedPrefs.data["__current_background"] = l?.properties?.id | 
					
						
							|  |  |  |             amendedPrefs.ping() | 
					
						
							|  |  |  |         }) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-07 02:13:57 +02:00
										 |  |  |         return amendedPrefs | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2021-10-15 05:20:02 +02:00
										 |  |  | } |