diff --git a/Logic/ElementStorage.ts b/Logic/ElementStorage.ts index a142ef71b1..581e8a12ec 100644 --- a/Logic/ElementStorage.ts +++ b/Logic/ElementStorage.ts @@ -3,9 +3,11 @@ */ import { UIEventSource } from "./UIEventSource" import { GeoJSONObject } from "@turf/turf" +import {Feature, Point} from "geojson"; +import {OsmTags} from "../Models/OsmFeature"; export class ElementStorage { - public ContainingFeatures = new Map() + public ContainingFeatures = new Map>() private _elements = new Map>() constructor() {} diff --git a/Logic/Tags/Tag.ts b/Logic/Tags/Tag.ts index f9cb2ff87b..b4ae1e5ddb 100644 --- a/Logic/Tags/Tag.ts +++ b/Logic/Tags/Tag.ts @@ -4,6 +4,7 @@ import { TagsFilter } from "./TagsFilter" export class Tag extends TagsFilter { public key: string public value: string + public static newlyCreated = new Tag("_newly_created","yes") ; constructor(key: string, value: string) { super() this.key = key @@ -63,7 +64,7 @@ export class Tag extends TagsFilter { } /** - + const t = new Tag("key", "value") t.asHumanString() // => "key=value" t.asHumanString(true) // => "key=value" diff --git a/UI/BigComponents/SimpleAddUI.ts b/UI/BigComponents/SimpleAddUI.ts index 24865c4da7..9e3e9c3a3f 100644 --- a/UI/BigComponents/SimpleAddUI.ts +++ b/UI/BigComponents/SimpleAddUI.ts @@ -27,6 +27,7 @@ import Loading from "../Base/Loading" import Hash from "../../Logic/Web/Hash" import { GlobalFilter } from "../../Logic/State/MapState" import { WayId } from "../../Models/OsmFeature" +import {Tag} from "../../Logic/Tags/Tag"; /* * The SimpleAddUI is a single panel, which can have multiple states: @@ -97,10 +98,11 @@ export default class SimpleAddUI extends Toggle { const presetsOverview = SimpleAddUI.CreateAllPresetsPanel(selectedPreset, state) async function createNewPoint( - tags: any[], + tags: Tag[], location: { lat: number; lon: number }, snapOntoWay?: OsmWay ): Promise { + tags.push(Tag.newlyCreated) const newElementAction = new CreateNewNodeAction(tags, location.lat, location.lon, { theme: state.layoutToUse?.id ?? "unkown", changeType: "create", @@ -109,9 +111,8 @@ export default class SimpleAddUI extends Toggle { await state.changes.applyAction(newElementAction) selectedPreset.setData(undefined) isShown.setData(false) - state.selectedElement.setData( - state.allElements.ContainingFeatures.get(newElementAction.newElementId) - ) + const selectedFeature = state.allElements.ContainingFeatures.get(newElementAction.newElementId) + state.selectedElement.setData(selectedFeature) Hash.hash.setData(newElementAction.newElementId) } diff --git a/UI/NewPoint/ConfirmLocationOfPoint.ts b/UI/NewPoint/ConfirmLocationOfPoint.ts index 76429a0071..2d8194e6d8 100644 --- a/UI/NewPoint/ConfirmLocationOfPoint.ts +++ b/UI/NewPoint/ConfirmLocationOfPoint.ts @@ -1,24 +1,24 @@ -import { UIEventSource } from "../../Logic/UIEventSource" -import { OsmConnection } from "../../Logic/Osm/OsmConnection" +import {UIEventSource} from "../../Logic/UIEventSource" +import {OsmConnection} from "../../Logic/Osm/OsmConnection" import FeaturePipeline from "../../Logic/FeatureSource/FeaturePipeline" import BaseUIElement from "../BaseUIElement" import LocationInput from "../Input/LocationInput" import AvailableBaseLayers from "../../Logic/Actors/AvailableBaseLayers" -import { BBox } from "../../Logic/BBox" -import { TagUtils } from "../../Logic/Tags/TagUtils" -import { SubtleButton } from "../Base/SubtleButton" +import {BBox} from "../../Logic/BBox" +import {TagUtils} from "../../Logic/Tags/TagUtils" +import {SubtleButton} from "../Base/SubtleButton" import Combine from "../Base/Combine" import Translations from "../i18n/Translations" import Svg from "../../Svg" import Toggle from "../Input/Toggle" -import SimpleAddUI, { PresetInfo } from "../BigComponents/SimpleAddUI" +import SimpleAddUI, {PresetInfo} from "../BigComponents/SimpleAddUI" import BaseLayer from "../../Models/BaseLayer" import Img from "../Base/Img" import Title from "../Base/Title" -import { GlobalFilter } from "../../Logic/State/MapState" -import { VariableUiElement } from "../Base/VariableUIElement" -import { Tag } from "../../Logic/Tags/Tag" -import { WayId } from "../../Models/OsmFeature" +import {GlobalFilter} from "../../Logic/State/MapState" +import {VariableUiElement} from "../Base/VariableUIElement" +import {Tag} from "../../Logic/Tags/Tag" +import {WayId} from "../../Models/OsmFeature" export default class ConfirmLocationOfPoint extends Combine { constructor( @@ -46,7 +46,7 @@ export default class ConfirmLocationOfPoint extends Combine { // Create location input // We uncouple the event source - const zloc = { ...loc, zoom: 19 } + const zloc = {...loc, zoom: 19} const locationSrc = new UIEventSource(zloc) let backgroundLayer = new UIEventSource( @@ -105,7 +105,7 @@ export default class ConfirmLocationOfPoint extends Combine { state.featurePipeline .GetFeaturesWithin(layerId, bbox) ?.forEach((feats) => - allFeatures.push(...feats.map((f) => ({ feature: f }))) + allFeatures.push(...feats.map((f) => ({feature: f}))) ) }) console.log("Snapping to", allFeatures) @@ -118,7 +118,6 @@ export default class ConfirmLocationOfPoint extends Combine { preset.icon(), new Combine([ confirmText, - Translations.t.general.add.warnVisibleForEveryone.Clone().SetClass("alert"), ]).SetClass("flex flex-col") ) .SetClass("font-bold break-words") @@ -139,15 +138,18 @@ export default class ConfirmLocationOfPoint extends Combine { ) }) + const warn = Translations.t.general.add.warnVisibleForEveryone.Clone().SetClass("alert w-full block"); if (preciseInput !== undefined) { - confirmButton = new Combine([preciseInput, confirmButton]) + confirmButton = new Combine([preciseInput, warn, confirmButton]) + } else { + confirmButton = new Combine([warn, confirmButton]) } const openLayerControl = new SubtleButton( Svg.layers_ui(), new Combine([ Translations.t.general.add.layerNotEnabled - .Subs({ layer: preset.layerToAddTo.layerDef.name }) + .Subs({layer: preset.layerToAddTo.layerDef.name}) .SetClass("alert"), Translations.t.general.add.openLayerControl, ]) @@ -183,7 +185,7 @@ export default class ConfirmLocationOfPoint extends Combine { const filterConfirmPanel = new VariableUiElement( state.globalFilters.map((gfs) => { const gf = gfs[i] - const confirm = gf.onNewPoint?.confirmAddNew?.Subs({ preset: preset.title }) + const confirm = gf.onNewPoint?.confirmAddNew?.Subs({preset: preset.title}) return new Combine([ gf.onNewPoint?.safetyCheck, new SubtleButton(Svg.confirm_svg(), confirm).onClick(() => diff --git a/UI/Popup/FeatureInfoBox.ts b/UI/Popup/FeatureInfoBox.ts index 399b706406..f39dc0a3f1 100644 --- a/UI/Popup/FeatureInfoBox.ts +++ b/UI/Popup/FeatureInfoBox.ts @@ -1,4 +1,4 @@ -import { UIEventSource } from "../../Logic/UIEventSource" +import {UIEventSource} from "../../Logic/UIEventSource" import EditableTagRendering from "./EditableTagRendering" import QuestionBox from "./QuestionBox" import Combine from "../Base/Combine" @@ -7,16 +7,19 @@ import ScrollableFullScreen from "../Base/ScrollableFullScreen" import Constants from "../../Models/Constants" import SharedTagRenderings from "../../Customizations/SharedTagRenderings" import BaseUIElement from "../BaseUIElement" -import { VariableUiElement } from "../Base/VariableUIElement" +import {VariableUiElement} from "../Base/VariableUIElement" import DeleteWizard from "./DeleteWizard" import SplitRoadWizard from "./SplitRoadWizard" import TagRenderingConfig from "../../Models/ThemeConfig/TagRenderingConfig" import LayerConfig from "../../Models/ThemeConfig/LayerConfig" -import { Utils } from "../../Utils" +import {Utils} from "../../Utils" import MoveWizard from "./MoveWizard" import Toggle from "../Input/Toggle" import Lazy from "../Base/Lazy" import FeaturePipelineState from "../../Logic/State/FeaturePipelineState" +import {Tag} from "../../Logic/Tags/Tag"; +import Svg from "../../Svg"; +import Translations from "../i18n/Translations"; export default class FeatureInfoBox extends ScrollableFullScreen { public constructor( @@ -79,7 +82,7 @@ export default class FeatureInfoBox extends ScrollableFullScreen { state: FeaturePipelineState ): BaseUIElement { let questionBoxes: Map = new Map() - + const t = Translations.t.general const allGroupNames = Utils.Dedup(layerConfig.tagRenderings.map((tr) => tr.group)) if (state?.featureSwitchUserbadge?.data ?? true) { const questionSpecs = layerConfig.tagRenderings.filter((tr) => tr.id === "questions") @@ -98,7 +101,29 @@ export default class FeatureInfoBox extends ScrollableFullScreen { } } - const allRenderings = [] + const withQuestion = layerConfig.tagRenderings.filter(tr => tr.question !== undefined).length + + const allRenderings: BaseUIElement[] = [ + new VariableUiElement( + tags.map(data => data[Tag.newlyCreated.key]).map(isCreated => { + if (isCreated !== Tag.newlyCreated.value) { + return undefined + } + const els = [] + const thanks = + new Combine([ + Svg.party_svg().SetClass("w-12 h-12 shrink-0 p-1 m-1 bg-white rounded-full block"), + t.newlyCreated + ]).SetClass("flex w-full thanks content-center") + els.push(thanks) + if (withQuestion > 0) { + els.push(t.feelFreeToSkip) + } + + return new Combine(els).SetClass("pb-4 mb-4 border-b block border-black") + }) + ) + ] for (let i = 0; i < allGroupNames.length; i++) { const groupName = allGroupNames[i] @@ -250,15 +275,15 @@ export default class FeatureInfoBox extends ScrollableFullScreen { editElements.push( Toggle.If(state.featureSwitchIsDebugging, () => { const config_all_tags: TagRenderingConfig = new TagRenderingConfig( - { render: "{all_tags()}" }, + {render: "{all_tags()}"}, "" ) const config_download: TagRenderingConfig = new TagRenderingConfig( - { render: "{export_as_geojson()}" }, + {render: "{export_as_geojson()}"}, "" ) const config_id: TagRenderingConfig = new TagRenderingConfig( - { render: "{open_in_iD()}" }, + {render: "{open_in_iD()}"}, "" ) diff --git a/langs/en.json b/langs/en.json index 384da50b3f..0c7bbd4e34 100644 --- a/langs/en.json +++ b/langs/en.json @@ -170,6 +170,7 @@ "error": "Something went wrong", "example": "Example", "examples": "Examples", + "feelFreeToSkip": "You can add or update more information below, but feel free to skip questions you don't know the answer to.", "fewChangesBefore": "Please, answer a few questions of existing features before adding a new feature.", "getStartedLogin": "Log in with OpenStreetMap to get started", "getStartedNewAccount": " or create a new account", @@ -204,6 +205,7 @@ "streetcomplete": "Another, similar application is StreetComplete." }, "nameInlineQuestion": "The name of this {category} is $$$", + "newlyCreated": "You just created this element! Thanks for sharing this info with the world and helping people worldwide.", "next": "Next", "noMatchingMapping": "No entries mapped your search…", "noNameCategory": "{category} without a name",