forked from MapComplete/MapComplete
Move license picker into usersettings, add possibility to highlight a setting
This commit is contained in:
parent
9202cbe8e2
commit
4ed88609e5
16 changed files with 204 additions and 103 deletions
|
@ -15,15 +15,13 @@ import { Store } from "../../Logic/UIEventSource"
|
|||
import { SubtleButton } from "../Base/SubtleButton"
|
||||
import Svg from "../../Svg"
|
||||
import * as native_languages from "../../assets/language_native.json"
|
||||
import * as used_languages from "../../assets/generated/used_languages.json"
|
||||
import BaseUIElement from "../BaseUIElement"
|
||||
|
||||
class TranslatorsPanelContent extends Combine {
|
||||
constructor(layout: LayoutConfig, isTranslator: Store<boolean>) {
|
||||
const t = Translations.t.translations
|
||||
|
||||
const { completeness, untranslated, total } =
|
||||
TranslatorsPanel.MissingTranslationsFor(layout)
|
||||
const { completeness, untranslated, total } = layout.missingTranslations()
|
||||
|
||||
const seed = t.completeness
|
||||
for (const ln of Array.from(completeness.keys())) {
|
||||
|
@ -147,52 +145,4 @@ export default class TranslatorsPanel extends Toggle {
|
|||
)
|
||||
this.SetClass("hidden-on-mobile")
|
||||
}
|
||||
|
||||
public static MissingTranslationsFor(layout: LayoutConfig): {
|
||||
completeness: Map<string, number>
|
||||
untranslated: Map<string, string[]>
|
||||
total: number
|
||||
} {
|
||||
let total = 0
|
||||
const completeness = new Map<string, number>()
|
||||
const untranslated = new Map<string, string[]>()
|
||||
|
||||
Utils.WalkObject(
|
||||
layout,
|
||||
(o) => {
|
||||
const translation = <Translation>(<any>o)
|
||||
if (translation.translations["*"] !== undefined) {
|
||||
return
|
||||
}
|
||||
if (translation.context === undefined || translation.context.indexOf(":") < 0) {
|
||||
// no source given - lets ignore
|
||||
return
|
||||
}
|
||||
|
||||
total++
|
||||
used_languages.languages.forEach((ln) => {
|
||||
const trans = translation.translations
|
||||
if (trans["*"] !== undefined) {
|
||||
return
|
||||
}
|
||||
if (trans[ln] === undefined) {
|
||||
if (!untranslated.has(ln)) {
|
||||
untranslated.set(ln, [])
|
||||
}
|
||||
untranslated.get(ln).push(translation.context)
|
||||
} else {
|
||||
completeness.set(ln, 1 + (completeness.get(ln) ?? 0))
|
||||
}
|
||||
})
|
||||
},
|
||||
(o) => {
|
||||
if (o === undefined || o === null) {
|
||||
return false
|
||||
}
|
||||
return o instanceof Translation
|
||||
}
|
||||
)
|
||||
|
||||
return { completeness, untranslated, total }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ import { TagUtils } from "../../Logic/Tags/TagUtils"
|
|||
import * as usersettings from "../../assets/generated/layers/usersettings.json"
|
||||
import { LoginToggle } from "../Popup/LoginButton"
|
||||
import LayerConfig from "../../Models/ThemeConfig/LayerConfig"
|
||||
|
||||
import * as translators from "../../assets/translators.json"
|
||||
export class ImportViewerLinks extends VariableUiElement {
|
||||
constructor(osmConnection: OsmConnection) {
|
||||
super(
|
||||
|
@ -44,24 +44,27 @@ export class ImportViewerLinks extends VariableUiElement {
|
|||
}
|
||||
|
||||
class SingleUserSettingsPanel extends EditableTagRendering {
|
||||
constructor(config: TagRenderingConfig, osmConnection: OsmConnection) {
|
||||
constructor(
|
||||
config: TagRenderingConfig,
|
||||
osmConnection: OsmConnection,
|
||||
amendedPrefs: UIEventSource<any>,
|
||||
userInfoFocusedQuestion?: UIEventSource<string>
|
||||
) {
|
||||
const editMode = new UIEventSource(false)
|
||||
// Isolate the preferences. THey'll be updated explicitely later on anyway
|
||||
super(
|
||||
osmConnection.preferencesHandler.preferences,
|
||||
amendedPrefs,
|
||||
config,
|
||||
[],
|
||||
{ osmConnection },
|
||||
{
|
||||
answerElementClasses: "p-2",
|
||||
editMode,
|
||||
createSaveButton: (store) =>
|
||||
new SaveButton(
|
||||
osmConnection.preferencesHandler.preferences,
|
||||
osmConnection
|
||||
).onClick(() => {
|
||||
const prefs = osmConnection.preferencesHandler.preferences
|
||||
new SaveButton(amendedPrefs, osmConnection).onClick(() => {
|
||||
const selection = TagUtils.FlattenMultiAnswer(
|
||||
TagUtils.FlattenAnd(store.data, prefs.data)
|
||||
).asChange(prefs.data)
|
||||
TagUtils.FlattenAnd(store.data, amendedPrefs.data)
|
||||
).asChange(amendedPrefs.data)
|
||||
for (const kv of selection) {
|
||||
osmConnection.GetPreference(kv.k, "", "").setData(kv.v)
|
||||
}
|
||||
|
@ -70,6 +73,16 @@ class SingleUserSettingsPanel extends EditableTagRendering {
|
|||
}),
|
||||
}
|
||||
)
|
||||
const self = this
|
||||
this.SetClass("rounded-xl")
|
||||
userInfoFocusedQuestion.addCallbackAndRun((selected) => {
|
||||
if (config.id !== selected) {
|
||||
console.log("Removing the glowingshadow...")
|
||||
self.RemoveClass("glowing-shadow")
|
||||
} else {
|
||||
self.SetClass("glowing-shadow")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -78,11 +91,35 @@ class UserInformationMainPanel extends VariableUiElement {
|
|||
osmConnection: OsmConnection,
|
||||
locationControl: UIEventSource<Loc>,
|
||||
layout: LayoutConfig,
|
||||
isOpened: UIEventSource<boolean>
|
||||
isOpened: UIEventSource<boolean>,
|
||||
userInfoFocusedQuestion?: UIEventSource<string>
|
||||
) {
|
||||
const t = Translations.t.userinfo
|
||||
const imgSize = "h-6 w-6"
|
||||
const ud = osmConnection.userDetails
|
||||
|
||||
const amendedPrefs = new UIEventSource<any>({})
|
||||
osmConnection.preferencesHandler.preferences.addCallback((newPrefs) => {
|
||||
for (const k in newPrefs) {
|
||||
amendedPrefs.data[k] = newPrefs[k]
|
||||
}
|
||||
amendedPrefs.ping()
|
||||
})
|
||||
osmConnection.userDetails.addCallback((userDetails) => {
|
||||
for (const k in userDetails) {
|
||||
amendedPrefs.data["_" + k] = "" + userDetails[k]
|
||||
}
|
||||
const simplifiedName = userDetails.name.toLowerCase().replace(/\s+/g, "")
|
||||
const isTranslator = translators.contributors.some(
|
||||
(c: { contributor: string; commits: number }) => {
|
||||
const replaced = c.contributor.toLowerCase().replace(/\s+/g, "")
|
||||
return replaced === simplifiedName
|
||||
}
|
||||
)
|
||||
amendedPrefs.data["_is_translator"] = "" + isTranslator
|
||||
amendedPrefs.ping()
|
||||
})
|
||||
|
||||
super(
|
||||
ud.map((ud) => {
|
||||
let img: BaseUIElement = Svg.person_ui().SetClass("block")
|
||||
|
@ -138,7 +175,12 @@ class UserInformationMainPanel extends VariableUiElement {
|
|||
const usersettingsConfig = new LayerConfig(usersettings, "userinformationpanel")
|
||||
|
||||
const questions = usersettingsConfig.tagRenderings.map((c) =>
|
||||
new SingleUserSettingsPanel(c, osmConnection).SetClass("block my-4")
|
||||
new SingleUserSettingsPanel(
|
||||
c,
|
||||
osmConnection,
|
||||
amendedPrefs,
|
||||
userInfoFocusedQuestion
|
||||
).SetClass("block my-4")
|
||||
)
|
||||
|
||||
return new Combine([
|
||||
|
@ -187,6 +229,7 @@ export default class UserInformationPanel extends ScrollableFullScreen {
|
|||
},
|
||||
options?: {
|
||||
isOpened?: UIEventSource<boolean>
|
||||
userInfoFocusedQuestion?: UIEventSource<string>
|
||||
}
|
||||
) {
|
||||
const isOpened = options?.isOpened ?? new UIEventSource<boolean>(false)
|
||||
|
@ -207,7 +250,8 @@ export default class UserInformationPanel extends ScrollableFullScreen {
|
|||
state.osmConnection,
|
||||
state.locationControl,
|
||||
state.layoutToUse,
|
||||
isOpened
|
||||
isOpened,
|
||||
options?.userInfoFocusedQuestion
|
||||
),
|
||||
Translations.t.general.getStartedLogin,
|
||||
state
|
||||
|
|
|
@ -205,9 +205,9 @@ export default class DefaultGUI {
|
|||
const self = this
|
||||
|
||||
const userInfoMapControl = Toggle.If(state.featureSwitchUserbadge, () => {
|
||||
console.log("Guistate is", guiState)
|
||||
new UserInformationPanel(state, {
|
||||
isOpened: guiState.userInfoIsOpened,
|
||||
userInfoFocusedQuestion: guiState.userInfoFocusedQuestion,
|
||||
})
|
||||
|
||||
const mapControl = new MapControlButton(
|
||||
|
|
|
@ -19,6 +19,9 @@ export class DefaultGuiState {
|
|||
false
|
||||
)
|
||||
public readonly userInfoIsOpened: UIEventSource<boolean> = new UIEventSource<boolean>(false)
|
||||
public readonly userInfoFocusedQuestion: UIEventSource<string> = new UIEventSource<string>(
|
||||
undefined
|
||||
)
|
||||
public readonly welcomeMessageOpenedTab: UIEventSource<number>
|
||||
|
||||
constructor() {
|
||||
|
@ -38,6 +41,14 @@ export class DefaultGuiState {
|
|||
userinfo: this.userInfoIsOpened,
|
||||
}
|
||||
|
||||
const self = this
|
||||
this.userInfoIsOpened.addCallback((isOpen) => {
|
||||
if (!isOpen) {
|
||||
console.log("Resetting focused question")
|
||||
self.userInfoFocusedQuestion.setData(undefined)
|
||||
}
|
||||
})
|
||||
|
||||
sources[Hash.hash.data?.toLowerCase()]?.setData(true)
|
||||
|
||||
if (Hash.hash.data === "" || Hash.hash.data === undefined) {
|
||||
|
|
|
@ -17,6 +17,8 @@ import { Changes } from "../../Logic/Osm/Changes"
|
|||
import Loading from "../Base/Loading"
|
||||
import { LoginToggle } from "../Popup/LoginButton"
|
||||
import Constants from "../../Models/Constants"
|
||||
import { DefaultGuiState } from "../DefaultGuiState"
|
||||
import ScrollableFullScreen from "../Base/ScrollableFullScreen"
|
||||
|
||||
export class ImageUploadFlow extends Toggle {
|
||||
private static readonly uploadCountsPerId = new Map<string, UIEventSource<number>>()
|
||||
|
@ -80,6 +82,10 @@ export class ImageUploadFlow extends Toggle {
|
|||
]).SetClass(
|
||||
"p-2 border-4 border-detail rounded-full font-bold h-full align-middle w-full flex justify-center"
|
||||
)
|
||||
const licenseStore = state?.osmConnection?.GetPreference(
|
||||
Constants.OsmPreferenceKeyPicturesLicense,
|
||||
"CC0"
|
||||
)
|
||||
|
||||
const fileSelector = new FileSelectorButton(label)
|
||||
fileSelector.GetValue().addCallback((filelist) => {
|
||||
|
@ -101,12 +107,7 @@ export class ImageUploadFlow extends Toggle {
|
|||
}
|
||||
}
|
||||
|
||||
console.log("Received images from the user, starting upload")
|
||||
const license =
|
||||
state?.osmConnection?.GetPreference(
|
||||
Constants.OsmPreferenceKeyPicturesLicense,
|
||||
"CC0"
|
||||
)?.data ?? "CC0"
|
||||
const license = licenseStore?.data ?? "CC0"
|
||||
|
||||
const tags = tagsSource.data
|
||||
|
||||
|
@ -174,7 +175,21 @@ export class ImageUploadFlow extends Toggle {
|
|||
),
|
||||
|
||||
fileSelector,
|
||||
Translations.t.image.respectPrivacy.Clone().SetStyle("font-size:small;"),
|
||||
new Combine([
|
||||
Translations.t.image.respectPrivacy,
|
||||
new VariableUiElement(
|
||||
licenseStore.map((license) =>
|
||||
Translations.t.image.currentLicense.Subs({ license })
|
||||
)
|
||||
)
|
||||
.onClick(() => {
|
||||
console.log("Opening the license settings... ")
|
||||
ScrollableFullScreen.collapse()
|
||||
DefaultGuiState.state.userInfoIsOpened.setData(true)
|
||||
DefaultGuiState.state.userInfoFocusedQuestion.setData("picture-license")
|
||||
})
|
||||
.SetClass("underline"),
|
||||
]).SetStyle("font-size:small;"),
|
||||
]).SetClass("flex flex-col image-upload-flow mt-4 mb-8 text-center")
|
||||
|
||||
super(
|
||||
|
|
|
@ -21,6 +21,8 @@ export default class EditableTagRendering extends Toggle {
|
|||
options: {
|
||||
editMode?: UIEventSource<boolean>
|
||||
innerElementClasses?: string
|
||||
/* Classes applied _only_ on the rendered element, not on the question*/
|
||||
answerElementClasses?: string
|
||||
/* Default will apply the tags to the relevant object, only use in special cases */
|
||||
createSaveButton?: (src: Store<UploadableTag>) => BaseUIElement
|
||||
}
|
||||
|
@ -43,7 +45,10 @@ export default class EditableTagRendering extends Toggle {
|
|||
configuration,
|
||||
units,
|
||||
editMode,
|
||||
{ saveButtonConstructor: options?.createSaveButton }
|
||||
{
|
||||
saveButtonConstructor: options?.createSaveButton,
|
||||
answerElementClasses: options?.answerElementClasses,
|
||||
}
|
||||
)
|
||||
rendering.SetClass(options.innerElementClasses)
|
||||
if (state?.featureSwitchIsDebugging?.data || state?.featureSwitchIsTesting?.data) {
|
||||
|
@ -73,6 +78,7 @@ export default class EditableTagRendering extends Toggle {
|
|||
editMode: UIEventSource<boolean>,
|
||||
options?: {
|
||||
saveButtonConstructor?: (src: Store<UploadableTag>) => BaseUIElement
|
||||
answerElementClasses?: string
|
||||
}
|
||||
): BaseUIElement {
|
||||
const answer: BaseUIElement = new TagRenderingAnswer(tags, configuration, state)
|
||||
|
@ -107,7 +113,7 @@ export default class EditableTagRendering extends Toggle {
|
|||
onlyIfPartiallyHidden: true,
|
||||
})
|
||||
}),
|
||||
]).SetClass("flex justify-between w-full")
|
||||
]).SetClass("flex justify-between w-full " + (options?.answerElementClasses ?? ""))
|
||||
rendering = new Toggle(question, answerWithEditButton, editMode)
|
||||
}
|
||||
return rendering
|
||||
|
|
|
@ -155,14 +155,13 @@ export class Translation extends BaseUIElement {
|
|||
return el
|
||||
}
|
||||
|
||||
const linkToWeblate = new LinkToWeblate(self.context, self.translations)
|
||||
|
||||
const wrapper = document.createElement("span")
|
||||
wrapper.appendChild(el)
|
||||
Locale.showLinkToWeblate.addCallbackAndRun((doShow) => {
|
||||
if (!doShow) {
|
||||
return
|
||||
}
|
||||
const linkToWeblate = new LinkToWeblate(self.context, self.translations)
|
||||
wrapper.appendChild(linkToWeblate.ConstructElement())
|
||||
return true
|
||||
})
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue