forked from MapComplete/MapComplete
Merge develop
This commit is contained in:
commit
b5669f6bf8
786 changed files with 42904 additions and 35985 deletions
|
@ -1,4 +1,4 @@
|
|||
import LayoutConfig, { MinimalLayoutInformation } from "../../Models/ThemeConfig/LayoutConfig"
|
||||
import ThemeConfig, { MinimalThemeInformation } from "../../Models/ThemeConfig/ThemeConfig"
|
||||
import { OsmConnection } from "../Osm/OsmConnection"
|
||||
import { MangroveIdentity } from "../Web/MangroveReviews"
|
||||
import { Store, Stores, UIEventSource } from "../UIEventSource"
|
||||
|
@ -22,9 +22,7 @@ import Showdown from "showdown"
|
|||
import { LocalStorageSource } from "../Web/LocalStorageSource"
|
||||
import { GeocodeResult } from "../Search/GeocodingProvider"
|
||||
|
||||
|
||||
export class OptionallySyncedHistory<T> {
|
||||
|
||||
public readonly syncPreference: UIEventSource<"sync" | "local" | "no">
|
||||
public readonly value: Store<T[]>
|
||||
private readonly synced: UIEventSource<T[]>
|
||||
|
@ -34,18 +32,26 @@ export class OptionallySyncedHistory<T> {
|
|||
private readonly _isSame: (a: T, b: T) => boolean
|
||||
private osmconnection: OsmConnection
|
||||
|
||||
constructor(key: string, osmconnection: OsmConnection, maxHistory: number = 20, isSame?: (a: T, b: T) => boolean) {
|
||||
constructor(
|
||||
key: string,
|
||||
osmconnection: OsmConnection,
|
||||
maxHistory: number = 20,
|
||||
isSame?: (a: T, b: T) => boolean
|
||||
) {
|
||||
this.osmconnection = osmconnection
|
||||
this._maxHistory = maxHistory
|
||||
this._isSame = isSame
|
||||
this.syncPreference = osmconnection.getPreference(
|
||||
"preference-" + key + "-history",
|
||||
"sync",
|
||||
)
|
||||
const synced = this.synced = UIEventSource.asObject<T[]>(osmconnection.getPreference(key + "-history"), [])
|
||||
const local = this.local = LocalStorageSource.GetParsed<T[]>(key + "-history", [])
|
||||
const thisSession = this.thisSession = new UIEventSource<T[]>([], "optionally-synced:"+key+"(session only)")
|
||||
this.syncPreference.addCallback(syncmode => {
|
||||
this.syncPreference = osmconnection.getPreference("preference-" + key + "-history", "sync")
|
||||
const synced = (this.synced = UIEventSource.asObject<T[]>(
|
||||
osmconnection.getPreference(key + "-history"),
|
||||
[]
|
||||
))
|
||||
const local = (this.local = LocalStorageSource.getParsed<T[]>(key + "-history", []))
|
||||
const thisSession = (this.thisSession = new UIEventSource<T[]>(
|
||||
[],
|
||||
"optionally-synced:" + key + "(session only)"
|
||||
))
|
||||
this.syncPreference.addCallback((syncmode) => {
|
||||
if (syncmode === "sync") {
|
||||
let list = [...thisSession.data, ...synced.data].slice(0, maxHistory)
|
||||
if (this._isSame) {
|
||||
|
@ -67,9 +73,7 @@ export class OptionallySyncedHistory<T> {
|
|||
}
|
||||
})
|
||||
|
||||
this.value = this.syncPreference.bind(syncPref => this.getAppropriateStore(syncPref))
|
||||
|
||||
|
||||
this.value = this.syncPreference.bind((syncPref) => this.getAppropriateStore(syncPref))
|
||||
}
|
||||
|
||||
private getAppropriateStore(syncPref?: string) {
|
||||
|
@ -87,7 +91,7 @@ export class OptionallySyncedHistory<T> {
|
|||
const store = this.getAppropriateStore()
|
||||
let oldList = store.data ?? []
|
||||
if (this._isSame) {
|
||||
oldList = oldList.filter(x => !this._isSame(t, x))
|
||||
oldList = oldList.filter((x) => !this._isSame(t, x))
|
||||
}
|
||||
store.set([t, ...oldList].slice(0, this._maxHistory))
|
||||
}
|
||||
|
@ -100,14 +104,13 @@ export class OptionallySyncedHistory<T> {
|
|||
if (t === undefined) {
|
||||
return
|
||||
}
|
||||
this.osmconnection.isLoggedIn.addCallbackAndRun(loggedIn => {
|
||||
this.osmconnection.isLoggedIn.addCallbackAndRun((loggedIn) => {
|
||||
if (!loggedIn) {
|
||||
return
|
||||
}
|
||||
this.add(t)
|
||||
return true
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
clear() {
|
||||
|
@ -157,14 +160,14 @@ export default class UserRelatedState {
|
|||
*/
|
||||
public readonly gpsLocationHistoryRetentionTime = new UIEventSource(
|
||||
7 * 24 * 60 * 60,
|
||||
"gps_location_retention",
|
||||
"gps_location_retention"
|
||||
)
|
||||
|
||||
public readonly addNewFeatureMode = new UIEventSource<
|
||||
"button" | "button_click_right" | "button_click" | "click" | "click_right"
|
||||
>("button_click_right")
|
||||
|
||||
public readonly showScale : UIEventSource<boolean>
|
||||
public readonly showScale: UIEventSource<boolean>
|
||||
|
||||
/**
|
||||
* Preferences as tags exposes many preferences and state properties as record.
|
||||
|
@ -180,18 +183,17 @@ export default class UserRelatedState {
|
|||
public readonly recentlyVisitedThemes: OptionallySyncedHistory<string>
|
||||
public readonly recentlyVisitedSearch: OptionallySyncedHistory<GeocodeResult>
|
||||
|
||||
|
||||
constructor(
|
||||
osmConnection: OsmConnection,
|
||||
layout?: LayoutConfig,
|
||||
layout?: ThemeConfig,
|
||||
featureSwitches?: FeatureSwitchState,
|
||||
mapProperties?: MapProperties,
|
||||
mapProperties?: MapProperties
|
||||
) {
|
||||
this.osmConnection = osmConnection
|
||||
this._mapProperties = mapProperties
|
||||
|
||||
this.showAllQuestionsAtOnce = UIEventSource.asBoolean(
|
||||
this.osmConnection.getPreference("show-all-questions", "false"),
|
||||
this.osmConnection.getPreference("show-all-questions", "false")
|
||||
)
|
||||
this.language = this.osmConnection.getPreference("language")
|
||||
this.showTags = this.osmConnection.getPreference("show_tags")
|
||||
|
@ -202,16 +204,20 @@ export default class UserRelatedState {
|
|||
this.a11y = this.osmConnection.getPreference("a11y")
|
||||
|
||||
this.mangroveIdentity = new MangroveIdentity(
|
||||
this.osmConnection.getPreference("identity", undefined,"mangrove"),
|
||||
this.osmConnection.getPreference("identity-creation-date", undefined,"mangrove"),
|
||||
this.osmConnection.getPreference("identity", undefined, "mangrove"),
|
||||
this.osmConnection.getPreference("identity-creation-date", undefined, "mangrove")
|
||||
)
|
||||
this.preferredBackgroundLayer = this.osmConnection.getPreference(
|
||||
"preferred-background-layer"
|
||||
)
|
||||
this.preferredBackgroundLayer = this.osmConnection.getPreference("preferred-background-layer")
|
||||
|
||||
this.addNewFeatureMode = this.osmConnection.getPreference(
|
||||
"preferences-add-new-mode",
|
||||
"button_click_right",
|
||||
"button_click_right"
|
||||
)
|
||||
this.showScale = UIEventSource.asBoolean(
|
||||
this.osmConnection.GetPreference("preference-show-scale", "false")
|
||||
)
|
||||
this.showScale = UIEventSource.asBoolean(this.osmConnection.GetPreference("preference-show-scale","false"))
|
||||
|
||||
this.imageLicense = this.osmConnection.getPreference("pictures-license", "CC0")
|
||||
this.installedUserThemes = UserRelatedState.initInstalledUserThemes(osmConnection)
|
||||
|
@ -224,12 +230,13 @@ export default class UserRelatedState {
|
|||
"theme",
|
||||
this.osmConnection,
|
||||
10,
|
||||
(a, b) => a === b,
|
||||
(a, b) => a === b
|
||||
)
|
||||
this.recentlyVisitedSearch = new OptionallySyncedHistory<GeocodeResult>("places",
|
||||
this.recentlyVisitedSearch = new OptionallySyncedHistory<GeocodeResult>(
|
||||
"places",
|
||||
this.osmConnection,
|
||||
15,
|
||||
(a, b) => a.osm_id === b.osm_id && a.osm_type === b.osm_type,
|
||||
(a, b) => a.osm_id === b.osm_id && a.osm_type === b.osm_type
|
||||
)
|
||||
this.syncLanguage()
|
||||
this.recentlyVisitedThemes.addDefferred(layout?.id)
|
||||
|
@ -272,7 +279,17 @@ export default class UserRelatedState {
|
|||
}
|
||||
}
|
||||
|
||||
public getUnofficialTheme(id: string): (MinimalLayoutInformation & { definition }) | undefined {
|
||||
/**
|
||||
* Adds a newly visited unofficial theme (or update the info).
|
||||
*
|
||||
* @param themeInfo note that themeInfo.id should be the URL where it was found
|
||||
*/
|
||||
public addUnofficialTheme(themeInfo: MinimalThemeInformation) {
|
||||
const pref = this.osmConnection.getPreference("unofficial-theme-" + themeInfo.id)
|
||||
this.osmConnection.isLoggedIn.when(() => pref.set(JSON.stringify(themeInfo)))
|
||||
}
|
||||
|
||||
public getUnofficialTheme(id: string): MinimalThemeInformation | undefined {
|
||||
const pref = this.osmConnection.getPreference("unofficial-theme-" + id)
|
||||
const str = pref.data
|
||||
|
||||
|
@ -282,20 +299,20 @@ export default class UserRelatedState {
|
|||
}
|
||||
|
||||
try {
|
||||
return <MinimalLayoutInformation & { definition: string }>JSON.parse(str)
|
||||
return JSON.parse(str)
|
||||
} catch (e) {
|
||||
console.warn(
|
||||
"Removing theme " +
|
||||
id +
|
||||
" as it could not be parsed from the preferences; the content is:",
|
||||
str,
|
||||
id +
|
||||
" as it could not be parsed from the preferences; the content is:",
|
||||
str
|
||||
)
|
||||
pref.setData(null)
|
||||
return undefined
|
||||
}
|
||||
}
|
||||
|
||||
public markLayoutAsVisited(layout: LayoutConfig) {
|
||||
public markLayoutAsVisited(layout: ThemeConfig) {
|
||||
if (!layout) {
|
||||
console.error("Trying to mark a layout as visited, but ", layout, " got passed")
|
||||
return
|
||||
|
@ -318,7 +335,7 @@ export default class UserRelatedState {
|
|||
title: layout.title.translations,
|
||||
shortDescription: layout.shortDescription.translations,
|
||||
definition: layout["definition"],
|
||||
}),
|
||||
})
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -328,7 +345,7 @@ export default class UserRelatedState {
|
|||
return osmConnection.preferencesHandler.allPreferences.map((prefs) =>
|
||||
Object.keys(prefs)
|
||||
.filter((k) => k.startsWith(prefix))
|
||||
.map((k) => k.substring(prefix.length)),
|
||||
.map((k) => k.substring(prefix.length))
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -342,7 +359,7 @@ export default class UserRelatedState {
|
|||
return userPreferences.map((preferences) =>
|
||||
Object.keys(preferences)
|
||||
.filter((key) => key.startsWith(prefix))
|
||||
.map((key) => key.substring(prefix.length, key.length - "-enabled".length)),
|
||||
.map((key) => key.substring(prefix.length, key.length - "-enabled".length))
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -358,7 +375,7 @@ export default class UserRelatedState {
|
|||
return undefined
|
||||
}
|
||||
return [home.lon, home.lat]
|
||||
}),
|
||||
})
|
||||
).map((homeLonLat) => {
|
||||
if (homeLonLat === undefined) {
|
||||
return empty
|
||||
|
@ -387,8 +404,8 @@ export default class UserRelatedState {
|
|||
* This is inherently a dirty and chaotic method, as it shoves many properties into this EventSource
|
||||
* */
|
||||
private initAmendedPrefs(
|
||||
layout?: LayoutConfig,
|
||||
featureSwitches?: FeatureSwitchState,
|
||||
layout?: ThemeConfig,
|
||||
featureSwitches?: FeatureSwitchState
|
||||
): UIEventSource<Record<string, string>> {
|
||||
const amendedPrefs = new UIEventSource<Record<string, string>>({
|
||||
_theme: layout?.id,
|
||||
|
@ -434,19 +451,19 @@ export default class UserRelatedState {
|
|||
const missingLayers = Utils.Dedup(
|
||||
untranslated
|
||||
.filter((k) => k.startsWith("layers:"))
|
||||
.map((k) => k.slice("layers:".length).split(".")[0]),
|
||||
.map((k) => k.slice("layers:".length).split(".")[0])
|
||||
)
|
||||
|
||||
const zenLinks: { link: string; id: string }[] = Utils.NoNull([
|
||||
hasMissingTheme
|
||||
? {
|
||||
id: "theme:" + layout.id,
|
||||
link: LinkToWeblate.hrefToWeblateZen(
|
||||
language,
|
||||
"themes",
|
||||
layout.id,
|
||||
),
|
||||
}
|
||||
id: "theme:" + layout.id,
|
||||
link: LinkToWeblate.hrefToWeblateZen(
|
||||
language,
|
||||
"themes",
|
||||
layout.id
|
||||
),
|
||||
}
|
||||
: undefined,
|
||||
...missingLayers.map((id) => ({
|
||||
id: "layer:" + id,
|
||||
|
@ -463,7 +480,7 @@ export default class UserRelatedState {
|
|||
}
|
||||
amendedPrefs.ping()
|
||||
},
|
||||
[this.translationMode],
|
||||
[this.translationMode]
|
||||
)
|
||||
|
||||
this.mangroveIdentity.getKeyId().addCallbackAndRun((kid) => {
|
||||
|
@ -482,7 +499,7 @@ export default class UserRelatedState {
|
|||
.makeHtml(userDetails.description)
|
||||
?.replace(/>/g, ">")
|
||||
?.replace(/</g, "<")
|
||||
?.replace(/\n/g, ""),
|
||||
?.replace(/\n/g, "")
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -493,7 +510,7 @@ export default class UserRelatedState {
|
|||
(c: { contributor: string; commits: number }) => {
|
||||
const replaced = c.contributor.toLowerCase().replace(/\s+/g, "")
|
||||
return replaced === simplifiedName
|
||||
},
|
||||
}
|
||||
)
|
||||
if (isTranslator) {
|
||||
amendedPrefs.data["_translation_contributions"] = "" + isTranslator.commits
|
||||
|
@ -502,7 +519,7 @@ export default class UserRelatedState {
|
|||
(c: { contributor: string; commits: number }) => {
|
||||
const replaced = c.contributor.toLowerCase().replace(/\s+/g, "")
|
||||
return replaced === simplifiedName
|
||||
},
|
||||
}
|
||||
)
|
||||
if (isCodeContributor) {
|
||||
amendedPrefs.data["_code_contributions"] = "" + isCodeContributor.commits
|
||||
|
@ -516,10 +533,10 @@ export default class UserRelatedState {
|
|||
// Language is managed separately
|
||||
continue
|
||||
}
|
||||
if(tags[key] === null){
|
||||
if (tags[key] === null) {
|
||||
continue
|
||||
}
|
||||
let pref = this.osmConnection.GetPreference(key, undefined, {prefix: ""})
|
||||
let pref = this.osmConnection.GetPreference(key, undefined, { prefix: "" })
|
||||
|
||||
pref.set(tags[key])
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue