diff --git a/app/src/main/java/de/westnordost/streetcomplete/osm/sidewalk_surface/LeftAndRightSidewalkSurface.kt b/app/src/main/java/de/westnordost/streetcomplete/osm/sidewalk_surface/LeftAndRightSidewalkSurface.kt index 6ac87fabc3..82c788528b 100644 --- a/app/src/main/java/de/westnordost/streetcomplete/osm/sidewalk_surface/LeftAndRightSidewalkSurface.kt +++ b/app/src/main/java/de/westnordost/streetcomplete/osm/sidewalk_surface/LeftAndRightSidewalkSurface.kt @@ -1,8 +1,5 @@ package de.westnordost.streetcomplete.osm.sidewalk_surface -import de.westnordost.streetcomplete.osm.surface.SurfaceAndNote +import de.westnordost.streetcomplete.osm.surface.Surface -data class LeftAndRightSidewalkSurface( - val left: SurfaceAndNote?, - val right: SurfaceAndNote?, -) +data class LeftAndRightSidewalkSurface(val left: Surface?, val right: Surface?) diff --git a/app/src/main/java/de/westnordost/streetcomplete/osm/sidewalk_surface/SidewalkSurfaceParser.kt b/app/src/main/java/de/westnordost/streetcomplete/osm/sidewalk_surface/SidewalkSurfaceParser.kt index bee45d703c..fe43cb0e78 100644 --- a/app/src/main/java/de/westnordost/streetcomplete/osm/sidewalk_surface/SidewalkSurfaceParser.kt +++ b/app/src/main/java/de/westnordost/streetcomplete/osm/sidewalk_surface/SidewalkSurfaceParser.kt @@ -1,22 +1,16 @@ package de.westnordost.streetcomplete.osm.sidewalk_surface import de.westnordost.streetcomplete.osm.expandSidesTags -import de.westnordost.streetcomplete.osm.surface.parseSurfaceAndNote +import de.westnordost.streetcomplete.osm.surface.parseSurface fun parseSidewalkSurface(tags: Map): LeftAndRightSidewalkSurface? { - val expandedTags = expandRelevantSidesTags(tags) + val expandedTags = tags.toMutableMap() + expandedTags.expandSidesTags("sidewalk", "surface", true) - val left = parseSurfaceAndNote(expandedTags, "sidewalk:left") - val right = parseSurfaceAndNote(expandedTags, "sidewalk:right") + val left = parseSurface(expandedTags["sidewalk:left:surface"]) + val right = parseSurface(expandedTags["sidewalk:right:surface"]) if (left == null && right == null) return null return LeftAndRightSidewalkSurface(left, right) } - -private fun expandRelevantSidesTags(tags: Map): Map { - val result = tags.toMutableMap() - result.expandSidesTags("sidewalk", "surface", true) - result.expandSidesTags("sidewalk", "surface:note", true) - return result -} diff --git a/app/src/main/java/de/westnordost/streetcomplete/osm/surface/Surface.kt b/app/src/main/java/de/westnordost/streetcomplete/osm/surface/Surface.kt index 01e72b1e8f..80440036fc 100644 --- a/app/src/main/java/de/westnordost/streetcomplete/osm/surface/Surface.kt +++ b/app/src/main/java/de/westnordost/streetcomplete/osm/surface/Surface.kt @@ -2,8 +2,6 @@ package de.westnordost.streetcomplete.osm.surface import de.westnordost.streetcomplete.osm.surface.Surface.* -data class SurfaceAndNote(val surface: Surface?, val note: String? = null) - enum class Surface(val osmValue: String?) { ASPHALT("asphalt"), CONCRETE("concrete"), @@ -80,10 +78,3 @@ val SELECTABLE_WAY_SURFACES = listOf( // generic surfaces PAVED, UNPAVED, GROUND ) - -private val UNDERSPECIFED_SURFACES = setOf(PAVED, UNPAVED) - -val Surface.shouldBeDescribed: Boolean get() = this in UNDERSPECIFED_SURFACES - -val SurfaceAndNote.isComplete: Boolean get() = - surface != null && (!surface.shouldBeDescribed || note != null) diff --git a/app/src/main/java/de/westnordost/streetcomplete/osm/surface/SurfaceCreator.kt b/app/src/main/java/de/westnordost/streetcomplete/osm/surface/SurfaceCreator.kt index 0ed8acb998..6775472e32 100644 --- a/app/src/main/java/de/westnordost/streetcomplete/osm/surface/SurfaceCreator.kt +++ b/app/src/main/java/de/westnordost/streetcomplete/osm/surface/SurfaceCreator.kt @@ -4,19 +4,19 @@ import de.westnordost.streetcomplete.osm.Tags import de.westnordost.streetcomplete.osm.removeCheckDatesForKey import de.westnordost.streetcomplete.osm.updateWithCheckDate -/** Apply the surface and note to the given [tags], with optional [prefix], e.g. "footway" for +/** Apply the surface to the given [tags], with optional [prefix], e.g. "footway" for * "footway:surface. * By default the check date is also updated if the surface did not change, specified * [updateCheckDate] = false if this should not be done. */ -fun SurfaceAndNote.applyTo(tags: Tags, prefix: String? = null, updateCheckDate: Boolean = true) { - val osmValue = surface?.osmValue +fun Surface.applyTo(tags: Tags, prefix: String? = null, updateCheckDate: Boolean = true) { requireNotNull(osmValue) { "Surface must be valid and not null" } val pre = if (prefix != null) "$prefix:" else "" val key = "${pre}surface" val previousOsmValue = tags[key] + val hasChanged = previousOsmValue != null && previousOsmValue != osmValue - if (previousOsmValue != null && previousOsmValue != osmValue) { + if (hasChanged) { // category of surface changed -> likely that tracktype is not correct anymore if (prefix == null && parseSurfaceCategory(osmValue) != parseSurfaceCategory(previousOsmValue)) { tags.remove("tracktype") @@ -33,10 +33,8 @@ fun SurfaceAndNote.applyTo(tags: Tags, prefix: String? = null, updateCheckDate: tags[key] = osmValue } - // add/remove note - used to describe generic surfaces - if (note != null) { - tags["$key:note"] = note - } else { + // remove note if surface has changed + if (hasChanged) { tags.remove("$key:note") } diff --git a/app/src/main/java/de/westnordost/streetcomplete/osm/surface/SurfaceParser.kt b/app/src/main/java/de/westnordost/streetcomplete/osm/surface/SurfaceParser.kt index c98dd70290..89822283b2 100644 --- a/app/src/main/java/de/westnordost/streetcomplete/osm/surface/SurfaceParser.kt +++ b/app/src/main/java/de/westnordost/streetcomplete/osm/surface/SurfaceParser.kt @@ -1,16 +1,5 @@ package de.westnordost.streetcomplete.osm.surface -/** Parse the surface and optional associated note from the given [tags]. - * Specify a [prefix] if you want for example the surface of the "footway" (then looks for - * "footway:surface") */ -fun parseSurfaceAndNote(tags: Map, prefix: String? = null): SurfaceAndNote? { - val pre = if (prefix != null) "$prefix:" else "" - val note = tags["${pre}surface:note"] - val surface = parseSurface(tags["${pre}surface"]) - if (surface == null && note == null) return null - return SurfaceAndNote(surface, note) -} - fun parseSurface(surface: String?): Surface? { if (surface == null) return null if (surface in INVALID_SURFACES) return null diff --git a/app/src/main/java/de/westnordost/streetcomplete/osm/surface/SurfaceUtils.kt b/app/src/main/java/de/westnordost/streetcomplete/osm/surface/SurfaceUtils.kt index 7971fb79f2..7f43096b40 100644 --- a/app/src/main/java/de/westnordost/streetcomplete/osm/surface/SurfaceUtils.kt +++ b/app/src/main/java/de/westnordost/streetcomplete/osm/surface/SurfaceUtils.kt @@ -60,7 +60,7 @@ fun updateCommonSurfaceFromFootAndCyclewaySurface(tags: Tags) { if (cyclewaySurface != null && footwaySurface != null) { val commonSurface = getCommonSurface(footwaySurface, cyclewaySurface) if (commonSurface != null) { - SurfaceAndNote(parseSurface(commonSurface), tags["surface:note"]).applyTo(tags) + parseSurface(commonSurface)?.applyTo(tags) } else { tags.remove("surface") tags.remove("surface:note") diff --git a/app/src/main/java/de/westnordost/streetcomplete/overlays/surface/SurfaceAndNoteViewController.kt b/app/src/main/java/de/westnordost/streetcomplete/overlays/surface/SurfaceAndNoteViewController.kt deleted file mode 100644 index 041c09b762..0000000000 --- a/app/src/main/java/de/westnordost/streetcomplete/overlays/surface/SurfaceAndNoteViewController.kt +++ /dev/null @@ -1,104 +0,0 @@ -package de.westnordost.streetcomplete.overlays.surface - -import android.view.LayoutInflater -import android.view.ViewGroup -import android.widget.EditText -import android.widget.TextView -import androidx.core.view.children -import androidx.core.view.isGone -import androidx.core.widget.doAfterTextChanged -import de.westnordost.streetcomplete.R -import de.westnordost.streetcomplete.osm.surface.Surface -import de.westnordost.streetcomplete.osm.surface.SurfaceAndNote -import de.westnordost.streetcomplete.osm.surface.asItem -import de.westnordost.streetcomplete.osm.surface.shouldBeDescribed -import de.westnordost.streetcomplete.osm.surface.toItems -import de.westnordost.streetcomplete.quests.surface.DescribeGenericSurfaceDialog -import de.westnordost.streetcomplete.util.ktx.nonBlankTextOrNull -import de.westnordost.streetcomplete.view.image_select.DisplayItem -import de.westnordost.streetcomplete.view.image_select.ImageListPickerDialog -import de.westnordost.streetcomplete.view.image_select.ItemViewHolder - -/** Manages UI for inputting the surface and conditionally the surface description / note. - * Tapping on the [selectButton] opens a chooser dialog for the [selectableSurfaces]. The selected - * surface is shown in the [selectedCellView] and if nothing is selected (so far), the - * [selectTextView] is shown. - * If the user chose a generic surface or there is already a note, the [noteInput] is shown. */ -class SurfaceAndNoteViewController( - private val selectButton: ViewGroup, - private val noteInput: EditText, - private val selectedCellView: ViewGroup, - private val selectTextView: TextView, - selectableSurfaces: List -) { - var value: SurfaceAndNote? - set(value) { - selectedSurfaceItem = value?.surface?.asItem() - noteText = value?.note - } - get() { - val surface = selectedSurfaceItem?.value - val note = noteText - return if (surface == null && note == null) null else SurfaceAndNote(surface, note) - } - - private var selectedSurfaceItem: DisplayItem? = null - set(value) { - field = value - updateSelectedCell() - updateNoteVisibility() - } - - private var noteText: String? - set(value) { - noteInput.setText(value) - updateNoteVisibility() - } - get() = noteInput.nonBlankTextOrNull - - private val cellLayoutId: Int = R.layout.cell_labeled_icon_select - private val items: List> = selectableSurfaces.toItems() - - var onInputChanged: (() -> Unit)? = null - - init { - noteInput.doAfterTextChanged { onInputChanged?.invoke() } - - selectButton.setOnClickListener { - collectSurfaceData { surface: Surface, note: String? -> - selectedSurfaceItem = surface.asItem() - noteText = note - onInputChanged?.invoke() - } - } - - LayoutInflater.from(selectButton.context).inflate(cellLayoutId, selectedCellView, true) - selectButton.children.first().background = null - } - - private fun updateSelectedCell() { - val item = selectedSurfaceItem - selectTextView.isGone = item != null - selectedCellView.isGone = item == null - if (item != null) { - ItemViewHolder(selectedCellView).bind(item) - } - } - - private fun updateNoteVisibility() { - noteInput.isGone = noteInput.nonBlankTextOrNull == null && selectedSurfaceItem?.value?.shouldBeDescribed != true - } - - private fun collectSurfaceData(callback: (Surface, String?) -> Unit) { - ImageListPickerDialog(selectButton.context, items, cellLayoutId, 2) { item -> - val value = item.value - if (value != null && value.shouldBeDescribed) { - DescribeGenericSurfaceDialog(selectButton.context) { description -> - callback(item.value!!, description) - }.show() - } else { - callback(item.value!!, null) - } - }.show() - } -} diff --git a/app/src/main/java/de/westnordost/streetcomplete/overlays/surface/SurfaceColorMapping.kt b/app/src/main/java/de/westnordost/streetcomplete/overlays/surface/SurfaceColorMapping.kt deleted file mode 100644 index f359965d59..0000000000 --- a/app/src/main/java/de/westnordost/streetcomplete/overlays/surface/SurfaceColorMapping.kt +++ /dev/null @@ -1,86 +0,0 @@ -package de.westnordost.streetcomplete.overlays.surface - -import de.westnordost.streetcomplete.data.osm.mapdata.Element -import de.westnordost.streetcomplete.osm.isPrivateOnFoot -import de.westnordost.streetcomplete.osm.surface.Surface -import de.westnordost.streetcomplete.osm.surface.Surface.* -import de.westnordost.streetcomplete.osm.surface.SurfaceAndNote -import de.westnordost.streetcomplete.osm.surface.isComplete -import de.westnordost.streetcomplete.overlays.Color - -/* - * Design considerations: - * - use standard colour set, for consistency and for better support for colour-blind people - * - it is OK to use some extra colours if absolutely needed - * - * - red is reserved for missing data - * - black is reserved for generic surface with note tag - * - * - similar surface should have similar colours - * - all paved ones are one such group - * - all unpaved ones are another - * - grass paver and compacted being high quality unpaved, unhewn cobblestone being low quality unpaved - * should be on border between these two groups - * - * - asphalt, concrete, paving stones are associated with grey - * but colouring these surfaces as grey resulted in really depressing, unfunny - * and soul-crushing display in cities where everything is well paved. - * Blue is more fun and less sad (while it will not convince anyone - * that concrete desert is a good thing). - * - * - highly unusual (for roads and paths) surfaces also got black colour - * - due to running out of colors all well paved surfaces get the same colour - * - due to running out of colours fine gravel, gravel, pebbles, rock got gray surface - * - dashes were tested but due to limitation of Tangram were not working well and were - * incapable of replacing colour coding - * - * - ideally, sand would have colour close to yellow and grass colour close to green caused - * by extremely strong association between surface and colour - */ -val Surface.color get() = when (this) { - ASPHALT, CHIPSEAL, CONCRETE - -> Color.BLUE - PAVING_STONES, PAVING_STONES_WITH_WEIRD_SUFFIX, BRICK, BRICKS - -> Color.SKY - CONCRETE_PLATES, CONCRETE_LANES, SETT, COBBLESTONE_FLATTENED - -> Color.CYAN - UNHEWN_COBBLESTONE, GRASS_PAVER - -> Color.AQUAMARINE - COMPACTED, FINE_GRAVEL - -> Color.TEAL - DIRT, SOIL, EARTH, MUD, GROUND, WOODCHIPS - -> Color.ORANGE - GRASS -> Color.LIME // greenish colour for grass is deliberate - SAND -> Color.GOLD // yellowish color for sand is deliberate - // sand and grass are strongly associated with - // this colors - GRAVEL, PEBBLES, ROCK, - // very different from above but unlikely to be used in same places, i.e. below are usually on bridges - WOOD, METAL, METAL_GRID - -> Color.GRAY - UNKNOWN, - PAVED, UNPAVED, // overriden in getColor of note is note is not present - // not encountered in normal situations, get the same as surface with surface:note - CLAY, ARTIFICIAL_TURF, TARTAN, RUBBER, ACRYLIC, HARD - -> Color.BLACK -} - -fun SurfaceAndNote?.getColor(element: Element): String = - if (this?.isComplete != true) { - // not set but indoor, private or just a "virtual" link -> do not highlight as missing - if (isIndoor(element.tags) || isPrivateOnFoot(element) || isLink(element.tags)) { - Color.INVISIBLE - } else { - Color.DATA_REQUESTED - } - } else { - surface!!.color - } - -private fun isIndoor(tags: Map): Boolean = tags["indoor"] == "yes" - -private fun isLink(tags: Map): Boolean = - tags["path"] == "link" - || tags["footway"] == "link" - || tags["cycleway"] == "link" - || tags["bridleway"] == "link" diff --git a/app/src/main/java/de/westnordost/streetcomplete/overlays/surface/SurfaceOverlay.kt b/app/src/main/java/de/westnordost/streetcomplete/overlays/surface/SurfaceOverlay.kt index 1aee665fdf..4181cfb64c 100644 --- a/app/src/main/java/de/westnordost/streetcomplete/overlays/surface/SurfaceOverlay.kt +++ b/app/src/main/java/de/westnordost/streetcomplete/overlays/surface/SurfaceOverlay.kt @@ -7,7 +7,10 @@ import de.westnordost.streetcomplete.data.osm.mapdata.filter import de.westnordost.streetcomplete.data.user.achievements.EditTypeAchievement.* import de.westnordost.streetcomplete.osm.ALL_PATHS import de.westnordost.streetcomplete.osm.ALL_ROADS -import de.westnordost.streetcomplete.osm.surface.parseSurfaceAndNote +import de.westnordost.streetcomplete.osm.isPrivateOnFoot +import de.westnordost.streetcomplete.osm.surface.Surface +import de.westnordost.streetcomplete.osm.surface.Surface.* +import de.westnordost.streetcomplete.osm.surface.parseSurface import de.westnordost.streetcomplete.overlays.Color import de.westnordost.streetcomplete.overlays.Overlay import de.westnordost.streetcomplete.overlays.PolygonStyle @@ -33,7 +36,7 @@ class SurfaceOverlay : Overlay { AddCyclewayPartSurface::class.simpleName!!, ) - override fun getStyledElements(mapData: MapDataWithGeometry): Sequence> = + override fun getStyledElements(mapData: MapDataWithGeometry) = mapData.filter(""" ways, relations with highway ~ ${(ALL_PATHS + ALL_ROADS).joinToString("|")} @@ -43,13 +46,14 @@ class SurfaceOverlay : Overlay { } private fun getStyle(element: Element): Style { - val isArea = element.tags["area"] == "yes" - val isSegregated = element.tags["segregated"] == "yes" - val isPath = element.tags["highway"] in ALL_PATHS + val tags = element.tags + val isArea = tags["area"] == "yes" + val isSegregated = tags["segregated"] == "yes" + val isPath = tags["highway"] in ALL_PATHS val color = if (isPath && isSegregated) { - val footwayColor = parseSurfaceAndNote(element.tags, "footway").getColor(element) - val cyclewayColor = parseSurfaceAndNote(element.tags, "cycleway").getColor(element) + val footwayColor = parseSurface(tags["footway:surface"]).getColor(element) + val cyclewayColor = parseSurface(tags["cycleway:surface"]).getColor(element) // take worst case for showing listOf(footwayColor, cyclewayColor).minBy { color -> when (color) { @@ -60,10 +64,73 @@ private fun getStyle(element: Element): Style { } } } else { - parseSurfaceAndNote(element.tags).getColor(element) + parseSurface(tags["surface"]).getColor(element) } return if (isArea) PolygonStyle(color) else PolylineStyle(StrokeStyle(color)) } -private fun isMotorway(tags: Map): Boolean = - tags["highway"] == "motorway" || tags["highway"] == "motorway_link" +private fun Surface?.getColor(element: Element): String = + this?.color ?: if (surfaceTaggingNotExpected(element)) Color.INVISIBLE else Color.DATA_REQUESTED + +/* + * Design considerations: + * - black is reserved for generic surface with note tag + * + * - similar surface should have similar colours + * - all paved ones are one such group + * - all unpaved ones are another + * - grass paver and compacted being high quality unpaved, unhewn cobblestone being low quality unpaved + * should be on border between these two groups + * + * - asphalt, concrete, paving stones are associated with grey + * but colouring these surfaces as grey resulted in really depressing, unfunny + * and soul-crushing display in cities where everything is well paved. + * Blue is more fun and less sad (while it will not convince anyone + * that concrete desert is a good thing). + * + * - highly unusual (for roads and paths) surfaces also got black colour + * - due to running out of colors all well paved surfaces get the same colour + * - due to running out of colours fine gravel, gravel, pebbles, rock got gray surface + * - dashes were tested but due to limitation of Tangram were not working well and were + * incapable of replacing colour coding + * + * - ideally, sand would have colour close to yellow and grass colour close to green caused + * by extremely strong association between surface and colour + */ +private val Surface.color get() = when (this) { + ASPHALT, CHIPSEAL, CONCRETE + -> Color.BLUE + PAVING_STONES, PAVING_STONES_WITH_WEIRD_SUFFIX, BRICK, BRICKS + -> Color.SKY + CONCRETE_PLATES, CONCRETE_LANES, SETT, COBBLESTONE_FLATTENED + -> Color.CYAN + UNHEWN_COBBLESTONE, GRASS_PAVER + -> Color.AQUAMARINE + COMPACTED, FINE_GRAVEL + -> Color.TEAL + DIRT, SOIL, EARTH, MUD, GROUND, WOODCHIPS + -> Color.ORANGE + GRASS + -> Color.LIME // greenish colour for grass is deliberate + SAND + -> Color.GOLD // yellowish color for sand is deliberate + GRAVEL, PEBBLES, ROCK, + // very different from above but unlikely to be used in same places, i.e. below are usually on bridges + WOOD, METAL, METAL_GRID + -> Color.GRAY + UNKNOWN, PAVED, UNPAVED, + // not encountered in normal situations, get the same as generic surface + CLAY, ARTIFICIAL_TURF, TARTAN, RUBBER, ACRYLIC, HARD + -> Color.BLACK +} + +private fun surfaceTaggingNotExpected(element: Element) = + isIndoor(element.tags) || isPrivateOnFoot(element) || isLink(element.tags) + +private fun isIndoor(tags: Map): Boolean = tags["indoor"] == "yes" + +private fun isLink(tags: Map): Boolean = + tags["path"] == "link" + || tags["footway"] == "link" + || tags["cycleway"] == "link" + || tags["bridleway"] == "link" diff --git a/app/src/main/java/de/westnordost/streetcomplete/overlays/surface/SurfaceOverlayForm.kt b/app/src/main/java/de/westnordost/streetcomplete/overlays/surface/SurfaceOverlayForm.kt index 5efea849d7..22b412d7fe 100644 --- a/app/src/main/java/de/westnordost/streetcomplete/overlays/surface/SurfaceOverlayForm.kt +++ b/app/src/main/java/de/westnordost/streetcomplete/overlays/surface/SurfaceOverlayForm.kt @@ -1,7 +1,9 @@ package de.westnordost.streetcomplete.overlays.surface import android.os.Bundle +import android.view.LayoutInflater import android.view.View +import androidx.core.view.children import androidx.core.view.isGone import de.westnordost.streetcomplete.R import de.westnordost.streetcomplete.data.elementfilter.toElementFilterExpression @@ -10,16 +12,14 @@ import de.westnordost.streetcomplete.data.osm.edits.update_tags.UpdateElementTag import de.westnordost.streetcomplete.data.osm.mapdata.Element import de.westnordost.streetcomplete.data.preferences.Preferences import de.westnordost.streetcomplete.databinding.FragmentOverlaySurfaceSelectBinding +import de.westnordost.streetcomplete.databinding.ViewImageSelectBinding import de.westnordost.streetcomplete.osm.ALL_PATHS import de.westnordost.streetcomplete.osm.changeToSteps import de.westnordost.streetcomplete.osm.surface.SELECTABLE_WAY_SURFACES import de.westnordost.streetcomplete.osm.surface.Surface -import de.westnordost.streetcomplete.osm.surface.SurfaceAndNote import de.westnordost.streetcomplete.osm.surface.applyTo import de.westnordost.streetcomplete.osm.surface.asItem -import de.westnordost.streetcomplete.osm.surface.isComplete import de.westnordost.streetcomplete.osm.surface.parseSurface -import de.westnordost.streetcomplete.osm.surface.parseSurfaceAndNote import de.westnordost.streetcomplete.osm.surface.updateCommonSurfaceFromFootAndCyclewaySurface import de.westnordost.streetcomplete.overlays.AbstractOverlayForm import de.westnordost.streetcomplete.overlays.AnswerItem @@ -27,6 +27,9 @@ import de.westnordost.streetcomplete.overlays.IAnswerItem import de.westnordost.streetcomplete.util.getLanguagesForFeatureDictionary import de.westnordost.streetcomplete.util.ktx.couldBeSteps import de.westnordost.streetcomplete.util.ktx.valueOfOrNull +import de.westnordost.streetcomplete.view.image_select.DisplayItem +import de.westnordost.streetcomplete.view.image_select.ImageListPickerDialog +import de.westnordost.streetcomplete.view.image_select.ItemViewHolder import de.westnordost.streetcomplete.view.setImage import org.koin.android.ext.android.inject @@ -36,18 +39,35 @@ class SurfaceOverlayForm : AbstractOverlayForm() { private val prefs: Preferences by inject() + private val selectableItems: List> get() = + SELECTABLE_WAY_SURFACES.map { it.asItem() } + private val lastPickedSurface: Surface? get() = prefs.getLastPicked(this::class.simpleName!!) .map { valueOfOrNull(it) } .firstOrNull() - private lateinit var surfaceCtrl: SurfaceAndNoteViewController - private lateinit var cyclewaySurfaceCtrl: SurfaceAndNoteViewController - private lateinit var footwaySurfaceCtrl: SurfaceAndNoteViewController + private var originalSurface: Surface? = null + private var originalFootwaySurface: Surface? = null + private var originalCyclewaySurface: Surface? = null + + private var selectedSurface: Surface? = null + set(value) { + field = value + updateSelectedCell(binding.main, value) + } + private var selectedFootwaySurface: Surface? = null + set(value) { + field = value + updateSelectedCell(binding.footway, value) + } + private var selectedCyclewaySurface: Surface? = null + set(value) { + field = value + updateSelectedCell(binding.cycleway, value) + } - private var originalSurface: SurfaceAndNote? = null - private var originalFootwaySurface: SurfaceAndNote? = null - private var originalCyclewaySurface: SurfaceAndNote? = null + private val cellLayoutId: Int = R.layout.cell_labeled_image_select private var isSegregatedLayout = false @@ -77,40 +97,56 @@ class SurfaceOverlayForm : AbstractOverlayForm() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - originalSurface = parseSurfaceAndNote(element!!.tags) - originalCyclewaySurface = parseSurfaceAndNote(element!!.tags, "cycleway") - originalFootwaySurface = parseSurfaceAndNote(element!!.tags, "footway") + val tags = element!!.tags + originalSurface = parseSurface(tags["surface"]) + originalCyclewaySurface = parseSurface(tags["cycleway:surface"]) + originalFootwaySurface = parseSurface(tags["footway:surface"]) + } + + + private fun updateSelectedCell(cellBinding: ViewImageSelectBinding, item: Surface?) { + cellBinding.selectTextView.isGone = item != null + cellBinding.selectedCellView.isGone = item == null + if (item != null) { + ItemViewHolder(cellBinding.selectedCellView).bind(item.asItem()) + } } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - surfaceCtrl = SurfaceAndNoteViewController( - binding.main.selectButton.root, - binding.main.explanationInput, - binding.main.selectButton.selectedCellView, - binding.main.selectButton.selectTextView, - SELECTABLE_WAY_SURFACES - ) - surfaceCtrl.onInputChanged = { checkIsFormComplete() } - - cyclewaySurfaceCtrl = SurfaceAndNoteViewController( - binding.cycleway.selectButton.root, - binding.cycleway.explanationInput, - binding.cycleway.selectButton.selectedCellView, - binding.cycleway.selectButton.selectTextView, - SELECTABLE_WAY_SURFACES - ) - cyclewaySurfaceCtrl.onInputChanged = { checkIsFormComplete() } - - footwaySurfaceCtrl = SurfaceAndNoteViewController( - binding.footway.selectButton.root, - binding.footway.explanationInput, - binding.footway.selectButton.selectedCellView, - binding.footway.selectButton.selectTextView, - SELECTABLE_WAY_SURFACES - ) - footwaySurfaceCtrl.onInputChanged = { checkIsFormComplete() } + LayoutInflater.from(requireContext()).inflate(cellLayoutId, binding.main.selectedCellView, true) + binding.main.selectedCellView.children.first().background = null + binding.main.selectButton.setOnClickListener { + ImageListPickerDialog(requireContext(), selectableItems, cellLayoutId) { item -> + if (item.value != selectedSurface) { + selectedSurface = item.value + checkIsFormComplete() + } + }.show() + } + + LayoutInflater.from(requireContext()).inflate(cellLayoutId, binding.cycleway.selectedCellView, true) + binding.cycleway.selectedCellView.children.first().background = null + binding.cycleway.selectButton.setOnClickListener { + ImageListPickerDialog(requireContext(), selectableItems, cellLayoutId) { item -> + if (item.value != selectedCyclewaySurface) { + selectedCyclewaySurface = item.value + checkIsFormComplete() + } + }.show() + } + + LayoutInflater.from(requireContext()).inflate(cellLayoutId, binding.footway.selectedCellView, true) + binding.footway.selectedCellView.children.first().background = null + binding.footway.selectButton.setOnClickListener { + ImageListPickerDialog(requireContext(), selectableItems, cellLayoutId) { item -> + if (item.value != selectedFootwaySurface) { + selectedFootwaySurface = item.value + checkIsFormComplete() + } + }.show() + } if (savedInstanceState != null) { onLoadInstanceState(savedInstanceState) @@ -121,7 +157,7 @@ class SurfaceOverlayForm : AbstractOverlayForm() { binding.lastPickedButton.isGone = lastPickedSurface == null binding.lastPickedButton.setImage(lastPickedSurface?.asItem()?.image) binding.lastPickedButton.setOnClickListener { - surfaceCtrl.value = SurfaceAndNote(lastPickedSurface) + selectedSurface = lastPickedSurface binding.lastPickedButton.isGone = true checkIsFormComplete() } @@ -142,69 +178,51 @@ class SurfaceOverlayForm : AbstractOverlayForm() { } private fun initStateFromTags() { - surfaceCtrl.value = originalSurface - cyclewaySurfaceCtrl.value = originalCyclewaySurface - footwaySurfaceCtrl.value = originalFootwaySurface + selectedSurface = originalSurface + selectedCyclewaySurface = originalCyclewaySurface + selectedFootwaySurface = originalFootwaySurface } /* ------------------------------------- instance state ------------------------------------- */ private fun onLoadInstanceState(inState: Bundle) { - surfaceCtrl.value = SurfaceAndNote( - parseSurface(inState.getString(SURFACE)), - inState.getString(NOTE) - ) - cyclewaySurfaceCtrl.value = SurfaceAndNote( - parseSurface(inState.getString(CYCLEWAY_SURFACE)), - inState.getString(CYCLEWAY_NOTE) - ) - footwaySurfaceCtrl.value = SurfaceAndNote( - parseSurface(inState.getString(FOOTWAY_SURFACE)), - inState.getString(FOOTWAY_NOTE) - ) + selectedSurface = parseSurface(inState.getString(SURFACE)) + selectedCyclewaySurface = parseSurface(inState.getString(CYCLEWAY_SURFACE)) + selectedFootwaySurface = parseSurface(inState.getString(FOOTWAY_SURFACE)) } override fun onSaveInstanceState(outState: Bundle) { super.onSaveInstanceState(outState) - - outState.putString(SURFACE, surfaceCtrl.value?.surface?.osmValue) - outState.putString(NOTE, surfaceCtrl.value?.note) - - outState.putString(CYCLEWAY_SURFACE, cyclewaySurfaceCtrl.value?.surface?.osmValue) - outState.putString(CYCLEWAY_NOTE, cyclewaySurfaceCtrl.value?.note) - - outState.putString(FOOTWAY_SURFACE, footwaySurfaceCtrl.value?.surface?.osmValue) - outState.putString(FOOTWAY_NOTE, footwaySurfaceCtrl.value?.note) + outState.putString(SURFACE, selectedSurface?.osmValue) + outState.putString(CYCLEWAY_SURFACE, selectedCyclewaySurface?.osmValue) + outState.putString(FOOTWAY_SURFACE, selectedFootwaySurface?.osmValue) } /* -------------------------------------- apply answer -------------------------------------- */ override fun isFormComplete(): Boolean = if (isSegregatedLayout) { - cyclewaySurfaceCtrl.value?.isComplete == true - && footwaySurfaceCtrl.value?.isComplete == true + selectedCyclewaySurface != null && selectedFootwaySurface != null } else { - surfaceCtrl.value?.isComplete == true + selectedSurface != null } override fun hasChanges(): Boolean = - surfaceCtrl.value != originalSurface || - cyclewaySurfaceCtrl.value != originalCyclewaySurface || - footwaySurfaceCtrl.value != originalFootwaySurface + selectedSurface != originalSurface || + selectedCyclewaySurface != originalCyclewaySurface || + selectedFootwaySurface != originalFootwaySurface override fun onClickOk() { val changesBuilder = StringMapChangesBuilder(element!!.tags) if (isSegregatedLayout) { changesBuilder["segregated"] = "yes" - cyclewaySurfaceCtrl.value!!.applyTo(changesBuilder, "cycleway") - footwaySurfaceCtrl.value!!.applyTo(changesBuilder, "footway") + selectedCyclewaySurface?.applyTo(changesBuilder, "cycleway") + selectedFootwaySurface?.applyTo(changesBuilder, "footway") updateCommonSurfaceFromFootAndCyclewaySurface(changesBuilder) } else { - if (surfaceCtrl.value!!.note == null && surfaceCtrl.value!!.surface != null) { - prefs.addLastPicked(this::class.simpleName!!, surfaceCtrl.value!!.surface!!.name) - } - surfaceCtrl.value!!.applyTo(changesBuilder) + selectedSurface?.let { prefs.addLastPicked(this::class.simpleName!!, it.name) } + selectedSurface?.applyTo(changesBuilder) } applyEdit(UpdateElementTagsAction(element!!, changesBuilder.create())) @@ -237,7 +255,7 @@ class SurfaceOverlayForm : AbstractOverlayForm() { */ AnswerItem(R.string.overlay_path_surface_segregated) { // reset previous data - surfaceCtrl.value = originalSurface + selectedSurface = originalSurface switchToFootwayCyclewaySurfaceLayout() } } else { @@ -259,10 +277,7 @@ class SurfaceOverlayForm : AbstractOverlayForm() { companion object { private const val SURFACE = "selected_surface" - private const val NOTE = "note" private const val CYCLEWAY_SURFACE = "cycleway_surface" - private const val CYCLEWAY_NOTE = "cycleway_note" private const val FOOTWAY_SURFACE = "footway_surface" - private const val FOOTWAY_NOTE = "footway_note" } } diff --git a/app/src/main/java/de/westnordost/streetcomplete/quests/surface/AddCyclewayPartSurface.kt b/app/src/main/java/de/westnordost/streetcomplete/quests/surface/AddCyclewayPartSurface.kt index 517382a0bf..f86a4d696a 100644 --- a/app/src/main/java/de/westnordost/streetcomplete/quests/surface/AddCyclewayPartSurface.kt +++ b/app/src/main/java/de/westnordost/streetcomplete/quests/surface/AddCyclewayPartSurface.kt @@ -6,11 +6,12 @@ import de.westnordost.streetcomplete.data.osm.osmquests.OsmFilterQuestType import de.westnordost.streetcomplete.data.user.achievements.EditTypeAchievement.BICYCLIST import de.westnordost.streetcomplete.data.user.achievements.EditTypeAchievement.OUTDOORS import de.westnordost.streetcomplete.osm.Tags -import de.westnordost.streetcomplete.osm.surface.SurfaceAndNote +import de.westnordost.streetcomplete.osm.surface.INVALID_SURFACES +import de.westnordost.streetcomplete.osm.surface.Surface import de.westnordost.streetcomplete.osm.surface.applyTo import de.westnordost.streetcomplete.osm.surface.updateCommonSurfaceFromFootAndCyclewaySurface -class AddCyclewayPartSurface : OsmFilterQuestType() { +class AddCyclewayPartSurface : OsmFilterQuestType() { override val elementFilter = """ ways with ( @@ -22,14 +23,19 @@ class AddCyclewayPartSurface : OsmFilterQuestType() { and !(sidewalk or sidewalk:left or sidewalk:right or sidewalk:both) and ( !cycleway:surface - or cycleway:surface older today -8 years + or cycleway:surface ~ ${INVALID_SURFACES.joinToString("|")} or ( cycleway:surface ~ paved|unpaved and !cycleway:surface:note - and !note:cycleway:surface + and !check_date:cycleway:surface ) + or cycleway:surface older today -8 years + ) + and ( + access !~ private|no + or (foot and foot !~ private|no) + or (bicycle and bicycle !~ private|no) ) - and (access !~ private|no or (foot and foot !~ private|no) or (bicycle and bicycle !~ private|no)) and ~path|footway|cycleway|bridleway !~ link """ override val changesetComment = "Specify cycleway path surfaces" @@ -41,7 +47,7 @@ class AddCyclewayPartSurface : OsmFilterQuestType() { override fun createForm() = AddPathPartSurfaceForm() - override fun applyAnswerTo(answer: SurfaceAndNote, tags: Tags, geometry: ElementGeometry, timestampEdited: Long) { + override fun applyAnswerTo(answer: Surface, tags: Tags, geometry: ElementGeometry, timestampEdited: Long) { answer.applyTo(tags, "cycleway") updateCommonSurfaceFromFootAndCyclewaySurface(tags) } diff --git a/app/src/main/java/de/westnordost/streetcomplete/quests/surface/AddFootwayPartSurface.kt b/app/src/main/java/de/westnordost/streetcomplete/quests/surface/AddFootwayPartSurface.kt index 4e63d6bf15..cab5933675 100644 --- a/app/src/main/java/de/westnordost/streetcomplete/quests/surface/AddFootwayPartSurface.kt +++ b/app/src/main/java/de/westnordost/streetcomplete/quests/surface/AddFootwayPartSurface.kt @@ -7,11 +7,12 @@ import de.westnordost.streetcomplete.data.user.achievements.EditTypeAchievement. import de.westnordost.streetcomplete.data.user.achievements.EditTypeAchievement.PEDESTRIAN import de.westnordost.streetcomplete.data.user.achievements.EditTypeAchievement.WHEELCHAIR import de.westnordost.streetcomplete.osm.Tags -import de.westnordost.streetcomplete.osm.surface.SurfaceAndNote +import de.westnordost.streetcomplete.osm.surface.INVALID_SURFACES +import de.westnordost.streetcomplete.osm.surface.Surface import de.westnordost.streetcomplete.osm.surface.applyTo import de.westnordost.streetcomplete.osm.surface.updateCommonSurfaceFromFootAndCyclewaySurface -class AddFootwayPartSurface : OsmFilterQuestType() { +class AddFootwayPartSurface : OsmFilterQuestType() { override val elementFilter = """ ways with ( @@ -23,14 +24,18 @@ class AddFootwayPartSurface : OsmFilterQuestType() { and !(sidewalk or sidewalk:left or sidewalk:right or sidewalk:both) and ( !footway:surface - or footway:surface older today -8 years + or footway:surface ~ ${INVALID_SURFACES.joinToString("|")} or ( footway:surface ~ paved|unpaved and !footway:surface:note - and !note:footway:surface + and !check_date:footway:surface ) + or footway:surface older today -8 years + ) + and ( + access !~ private|no + or (foot and foot !~ private|no) ) - and (access !~ private|no or (foot and foot !~ private|no)) and ~path|footway|cycleway|bridleway !~ link """ override val changesetComment = "Add footway path surfaces" @@ -42,7 +47,7 @@ class AddFootwayPartSurface : OsmFilterQuestType() { override fun createForm() = AddPathPartSurfaceForm() - override fun applyAnswerTo(answer: SurfaceAndNote, tags: Tags, geometry: ElementGeometry, timestampEdited: Long) { + override fun applyAnswerTo(answer: Surface, tags: Tags, geometry: ElementGeometry, timestampEdited: Long) { answer.applyTo(tags, "footway") updateCommonSurfaceFromFootAndCyclewaySurface(tags) } diff --git a/app/src/main/java/de/westnordost/streetcomplete/quests/surface/AddPathPartSurfaceForm.kt b/app/src/main/java/de/westnordost/streetcomplete/quests/surface/AddPathPartSurfaceForm.kt index a6de21f369..24b91a0104 100644 --- a/app/src/main/java/de/westnordost/streetcomplete/quests/surface/AddPathPartSurfaceForm.kt +++ b/app/src/main/java/de/westnordost/streetcomplete/quests/surface/AddPathPartSurfaceForm.kt @@ -2,20 +2,15 @@ package de.westnordost.streetcomplete.quests.surface import de.westnordost.streetcomplete.osm.surface.SELECTABLE_WAY_SURFACES import de.westnordost.streetcomplete.osm.surface.Surface -import de.westnordost.streetcomplete.osm.surface.SurfaceAndNote import de.westnordost.streetcomplete.osm.surface.toItems import de.westnordost.streetcomplete.quests.AImageListQuestForm -class AddPathPartSurfaceForm : AImageListQuestForm() { +class AddPathPartSurfaceForm : AImageListQuestForm() { override val items get() = SELECTABLE_WAY_SURFACES.toItems() override val itemsPerRow = 3 override fun onClickOk(selectedItems: List) { - val value = selectedItems.single() - - collectSurfaceDescriptionIfNecessary(requireContext(), value) { - applyAnswer(SurfaceAndNote(value, it)) - } + applyAnswer(selectedItems.single()) } } diff --git a/app/src/main/java/de/westnordost/streetcomplete/quests/surface/AddPathSurface.kt b/app/src/main/java/de/westnordost/streetcomplete/quests/surface/AddPathSurface.kt index 11b392d0d2..cb35917f99 100644 --- a/app/src/main/java/de/westnordost/streetcomplete/quests/surface/AddPathSurface.kt +++ b/app/src/main/java/de/westnordost/streetcomplete/quests/surface/AddPathSurface.kt @@ -22,16 +22,17 @@ class AddPathSurface : OsmFilterQuestType() { and (!indoor or indoor = no) and ( !surface - or surface older today -8 years + or surface ~ ${INVALID_SURFACES.joinToString("|")} or ( - surface ~ paved|unpaved|${INVALID_SURFACES.joinToString("|")} + surface ~ paved|unpaved and !surface:note and !note:surface + and !check_date:surface ) + or surface older today -8 years ) and ~path|footway|cycleway|bridleway !~ link """ - // ~paved ways are less likely to change the surface type override val changesetComment = "Specify path surfaces" override val wikiLink = "Key:surface" diff --git a/app/src/main/java/de/westnordost/streetcomplete/quests/surface/AddPathSurfaceForm.kt b/app/src/main/java/de/westnordost/streetcomplete/quests/surface/AddPathSurfaceForm.kt index 083871f460..44d6395d9e 100644 --- a/app/src/main/java/de/westnordost/streetcomplete/quests/surface/AddPathSurfaceForm.kt +++ b/app/src/main/java/de/westnordost/streetcomplete/quests/surface/AddPathSurfaceForm.kt @@ -4,7 +4,6 @@ import de.westnordost.streetcomplete.R import de.westnordost.streetcomplete.data.osm.mapdata.Way import de.westnordost.streetcomplete.osm.surface.SELECTABLE_WAY_SURFACES import de.westnordost.streetcomplete.osm.surface.Surface -import de.westnordost.streetcomplete.osm.surface.SurfaceAndNote import de.westnordost.streetcomplete.osm.surface.toItems import de.westnordost.streetcomplete.quests.AImageListQuestForm import de.westnordost.streetcomplete.quests.AnswerItem @@ -21,10 +20,7 @@ class AddPathSurfaceForm : AImageListQuestForm( override val itemsPerRow = 3 override fun onClickOk(selectedItems: List) { - val value = selectedItems.single() - collectSurfaceDescriptionIfNecessary(requireContext(), value) { - applyAnswer(SurfaceAnswer(SurfaceAndNote(value, it))) - } + applyAnswer(SurfaceAnswer(selectedItems.single())) } private fun createConvertToStepsAnswer(): AnswerItem? = diff --git a/app/src/main/java/de/westnordost/streetcomplete/quests/surface/AddPitchSurface.kt b/app/src/main/java/de/westnordost/streetcomplete/quests/surface/AddPitchSurface.kt index 8ddf14e31e..7969f526be 100644 --- a/app/src/main/java/de/westnordost/streetcomplete/quests/surface/AddPitchSurface.kt +++ b/app/src/main/java/de/westnordost/streetcomplete/quests/surface/AddPitchSurface.kt @@ -5,10 +5,11 @@ import de.westnordost.streetcomplete.data.osm.geometry.ElementGeometry import de.westnordost.streetcomplete.data.osm.osmquests.OsmFilterQuestType import de.westnordost.streetcomplete.data.user.achievements.EditTypeAchievement.OUTDOORS import de.westnordost.streetcomplete.osm.Tags -import de.westnordost.streetcomplete.osm.surface.SurfaceAndNote +import de.westnordost.streetcomplete.osm.surface.INVALID_SURFACES +import de.westnordost.streetcomplete.osm.surface.Surface import de.westnordost.streetcomplete.osm.surface.applyTo -class AddPitchSurface : OsmFilterQuestType() { +class AddPitchSurface : OsmFilterQuestType() { private val sportValuesWherePitchSurfaceQuestionIsInteresting = listOf( // #2377 "multi", "soccer", "tennis", "basketball", "equestrian", "athletics", "volleyball", @@ -32,12 +33,14 @@ class AddPitchSurface : OsmFilterQuestType() { and (athletics !~ high_jump|pole_vault) and ( !surface - or surface older today -12 years + or surface ~ ${INVALID_SURFACES.joinToString("|")} or ( - surface ~ paved|unpaved - and !surface:note - and !note:surface + surface ~ paved|unpaved + and !surface:note + and !note:surface + and !check_date:surface ) + or surface older today -12 years ) """ @@ -50,7 +53,7 @@ class AddPitchSurface : OsmFilterQuestType() { override fun createForm() = AddPitchSurfaceForm() - override fun applyAnswerTo(answer: SurfaceAndNote, tags: Tags, geometry: ElementGeometry, timestampEdited: Long) { + override fun applyAnswerTo(answer: Surface, tags: Tags, geometry: ElementGeometry, timestampEdited: Long) { answer.applyTo(tags) } } diff --git a/app/src/main/java/de/westnordost/streetcomplete/quests/surface/AddPitchSurfaceForm.kt b/app/src/main/java/de/westnordost/streetcomplete/quests/surface/AddPitchSurfaceForm.kt index e6034cb79d..01989eb350 100644 --- a/app/src/main/java/de/westnordost/streetcomplete/quests/surface/AddPitchSurfaceForm.kt +++ b/app/src/main/java/de/westnordost/streetcomplete/quests/surface/AddPitchSurfaceForm.kt @@ -2,19 +2,15 @@ package de.westnordost.streetcomplete.quests.surface import de.westnordost.streetcomplete.osm.surface.SELECTABLE_PITCH_SURFACES import de.westnordost.streetcomplete.osm.surface.Surface -import de.westnordost.streetcomplete.osm.surface.SurfaceAndNote import de.westnordost.streetcomplete.osm.surface.toItems import de.westnordost.streetcomplete.quests.AImageListQuestForm -class AddPitchSurfaceForm : AImageListQuestForm() { +class AddPitchSurfaceForm : AImageListQuestForm() { override val items get() = SELECTABLE_PITCH_SURFACES.toItems() override val itemsPerRow = 3 override fun onClickOk(selectedItems: List) { - val value = selectedItems.single() - collectSurfaceDescriptionIfNecessary(requireContext(), value) { - applyAnswer(SurfaceAndNote(value, it)) - } + applyAnswer(selectedItems.single()) } } diff --git a/app/src/main/java/de/westnordost/streetcomplete/quests/surface/AddRoadSurface.kt b/app/src/main/java/de/westnordost/streetcomplete/quests/surface/AddRoadSurface.kt index 24aa3f61b9..f68a4c311d 100644 --- a/app/src/main/java/de/westnordost/streetcomplete/quests/surface/AddRoadSurface.kt +++ b/app/src/main/java/de/westnordost/streetcomplete/quests/surface/AddRoadSurface.kt @@ -8,11 +8,11 @@ import de.westnordost.streetcomplete.data.user.achievements.EditTypeAchievement. import de.westnordost.streetcomplete.osm.Tags import de.westnordost.streetcomplete.osm.surface.INVALID_SURFACES import de.westnordost.streetcomplete.osm.surface.INVALID_SURFACES_FOR_TRACKTYPES -import de.westnordost.streetcomplete.osm.surface.SurfaceAndNote +import de.westnordost.streetcomplete.osm.surface.Surface import de.westnordost.streetcomplete.osm.surface.UNPAVED_SURFACES import de.westnordost.streetcomplete.osm.surface.applyTo -class AddRoadSurface : OsmFilterQuestType() { +class AddRoadSurface : OsmFilterQuestType() { override val elementFilter = """ ways with ( @@ -25,13 +25,15 @@ class AddRoadSurface : OsmFilterQuestType() { ) and ( !surface - or surface ~ ${UNPAVED_SURFACES.joinToString("|")} and surface older today -6 years - or surface older today -12 years + or surface ~ ${INVALID_SURFACES.joinToString("|")} or ( - surface ~ paved|unpaved|${INVALID_SURFACES.joinToString("|")} + surface ~ paved|unpaved and !surface:note and !note:surface + and !check_date:surface ) + or surface ~ ${UNPAVED_SURFACES.joinToString("|")} and surface older today -6 years + or surface older today -12 years ${INVALID_SURFACES_FOR_TRACKTYPES.entries.joinToString("\n") { (tracktype, surfaces) -> "or tracktype = $tracktype and surface ~ ${surfaces.joinToString("|")}" }} @@ -53,7 +55,7 @@ class AddRoadSurface : OsmFilterQuestType() { override fun createForm() = AddRoadSurfaceForm() - override fun applyAnswerTo(answer: SurfaceAndNote, tags: Tags, geometry: ElementGeometry, timestampEdited: Long) { + override fun applyAnswerTo(answer: Surface, tags: Tags, geometry: ElementGeometry, timestampEdited: Long) { answer.applyTo(tags) } } diff --git a/app/src/main/java/de/westnordost/streetcomplete/quests/surface/AddRoadSurfaceForm.kt b/app/src/main/java/de/westnordost/streetcomplete/quests/surface/AddRoadSurfaceForm.kt index 54fdb12b99..8276ae2f18 100644 --- a/app/src/main/java/de/westnordost/streetcomplete/quests/surface/AddRoadSurfaceForm.kt +++ b/app/src/main/java/de/westnordost/streetcomplete/quests/surface/AddRoadSurfaceForm.kt @@ -2,19 +2,16 @@ package de.westnordost.streetcomplete.quests.surface import de.westnordost.streetcomplete.osm.surface.SELECTABLE_WAY_SURFACES import de.westnordost.streetcomplete.osm.surface.Surface -import de.westnordost.streetcomplete.osm.surface.SurfaceAndNote import de.westnordost.streetcomplete.osm.surface.toItems import de.westnordost.streetcomplete.quests.AImageListQuestForm -class AddRoadSurfaceForm : AImageListQuestForm() { +class AddRoadSurfaceForm : AImageListQuestForm() { override val items get() = SELECTABLE_WAY_SURFACES.toItems() override val itemsPerRow = 3 override fun onClickOk(selectedItems: List) { val surface = selectedItems.single() - collectSurfaceDescriptionIfNecessary(requireContext(), surface) { description -> - applyAnswer(SurfaceAndNote(surface, description)) - } + applyAnswer(surface) } } diff --git a/app/src/main/java/de/westnordost/streetcomplete/quests/surface/AddSidewalkSurface.kt b/app/src/main/java/de/westnordost/streetcomplete/quests/surface/AddSidewalkSurface.kt index ee7a4868ae..19ed845769 100644 --- a/app/src/main/java/de/westnordost/streetcomplete/quests/surface/AddSidewalkSurface.kt +++ b/app/src/main/java/de/westnordost/streetcomplete/quests/surface/AddSidewalkSurface.kt @@ -14,18 +14,18 @@ class AddSidewalkSurface : OsmFilterQuestType() { // Only roads with 'complete' sidewalk tagging (at least one side has sidewalk, other side specified) override val elementFilter = """ ways with - highway ~ motorway|motorway_link|trunk|trunk_link|primary|primary_link|secondary|secondary_link|tertiary|tertiary_link|unclassified|residential|service|living_street|busway - and area != yes - and ( - sidewalk ~ both|left|right or - sidewalk:both = yes or - (sidewalk:left = yes and sidewalk:right ~ yes|no|separate) or - (sidewalk:right = yes and sidewalk:left ~ yes|no|separate) - ) - and ( - !sidewalk:both:surface and !sidewalk:left:surface and !sidewalk:right:surface - or sidewalk:surface older today -8 years - ) + highway ~ motorway|motorway_link|trunk|trunk_link|primary|primary_link|secondary|secondary_link|tertiary|tertiary_link|unclassified|residential|service|living_street|busway + and area != yes + and ( + sidewalk ~ both|left|right + or sidewalk:both = yes + or (sidewalk:left = yes and sidewalk:right ~ yes|no|separate) + or (sidewalk:right = yes and sidewalk:left ~ yes|no|separate) + ) + and ( + !sidewalk:both:surface and !sidewalk:left:surface and !sidewalk:right:surface + or sidewalk:surface older today -8 years + ) """ override val changesetComment = "Specify sidewalk surfaces" override val wikiLink = "Key:sidewalk" diff --git a/app/src/main/java/de/westnordost/streetcomplete/quests/surface/AddSidewalkSurfaceForm.kt b/app/src/main/java/de/westnordost/streetcomplete/quests/surface/AddSidewalkSurfaceForm.kt index c755f0dcbc..870a9ebfc2 100644 --- a/app/src/main/java/de/westnordost/streetcomplete/quests/surface/AddSidewalkSurfaceForm.kt +++ b/app/src/main/java/de/westnordost/streetcomplete/quests/surface/AddSidewalkSurfaceForm.kt @@ -2,16 +2,13 @@ package de.westnordost.streetcomplete.quests.surface import android.os.Bundle import android.view.View -import androidx.appcompat.app.AlertDialog import de.westnordost.streetcomplete.R import de.westnordost.streetcomplete.osm.sidewalk.Sidewalk import de.westnordost.streetcomplete.osm.sidewalk.parseSidewalkSides import de.westnordost.streetcomplete.osm.sidewalk_surface.LeftAndRightSidewalkSurface import de.westnordost.streetcomplete.osm.surface.SELECTABLE_WAY_SURFACES import de.westnordost.streetcomplete.osm.surface.Surface -import de.westnordost.streetcomplete.osm.surface.SurfaceAndNote import de.westnordost.streetcomplete.osm.surface.asStreetSideItem -import de.westnordost.streetcomplete.osm.surface.shouldBeDescribed import de.westnordost.streetcomplete.osm.surface.toItems import de.westnordost.streetcomplete.quests.AStreetSideSelectForm import de.westnordost.streetcomplete.quests.AnswerItem @@ -23,22 +20,12 @@ import de.westnordost.streetcomplete.view.image_select.ImageListPickerDialog class AddSidewalkSurfaceForm : AStreetSideSelectForm() { - private var leftNote: String? = null - private var rightNote: String? = null - private val items: List> = SELECTABLE_WAY_SURFACES.toItems() override val otherAnswers = listOf( AnswerItem(R.string.quest_sidewalk_answer_different) { applyAnswer(SidewalkIsDifferent) } ) - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - if (savedInstanceState != null) { - onLoadInstanceState(savedInstanceState) - } - } - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) if (savedInstanceState == null) { @@ -60,61 +47,22 @@ class AddSidewalkSurfaceForm : AStreetSideSelectForm - val surface = item.value!! - if (surface.shouldBeDescribed) { - showDescribeSurfaceDialog(isRight, surface) - } else { - replaceSurfaceSide(isRight, surface, null) - } + ImageListPickerDialog(requireContext(), items, R.layout.cell_labeled_icon_select, 2) { + val surface = it.value!! + replaceSurfaceSide(isRight, surface) }.show() } - private fun showDescribeSurfaceDialog(isRight: Boolean, surface: Surface) { - AlertDialog.Builder(requireContext()) - .setMessage(R.string.quest_surface_detailed_answer_impossible_confirmation) - .setPositiveButton(R.string.quest_generic_confirmation_yes) { _, _ -> - DescribeGenericSurfaceDialog(requireContext()) { description -> - replaceSurfaceSide(isRight, surface, description) - }.show() - } - .setNegativeButton(android.R.string.cancel, null) - .show() - } - - private fun replaceSurfaceSide(isRight: Boolean, surface: Surface, description: String?) { + private fun replaceSurfaceSide(isRight: Boolean, surface: Surface) { val streetSideItem = surface.asStreetSideItem(requireContext().resources) - if (isRight) { - rightNote = description - } else { - leftNote = description - } streetSideSelect.replacePuzzleSide(streetSideItem, isRight) } override fun onClickOk() { val left = streetSideSelect.left?.value val right = streetSideSelect.right?.value - if (left?.shouldBeDescribed != true && right?.shouldBeDescribed != true) { - streetSideSelect.saveLastSelection() - } - applyAnswer(SidewalkSurface(LeftAndRightSidewalkSurface( - left?.let { SurfaceAndNote(it, leftNote) }, - right?.let { SurfaceAndNote(it, rightNote) } - ))) - } - - /* ------------------------------------- instance state ------------------------------------- */ - - private fun onLoadInstanceState(savedInstanceState: Bundle) { - leftNote = savedInstanceState.getString(LEFT_NOTE, null) - rightNote = savedInstanceState.getString(RIGHT_NOTE, null) - } - - override fun onSaveInstanceState(outState: Bundle) { - super.onSaveInstanceState(outState) - outState.putString(LEFT_NOTE, leftNote) - outState.putString(RIGHT_NOTE, rightNote) + streetSideSelect.saveLastSelection() + applyAnswer(SidewalkSurface(LeftAndRightSidewalkSurface(left, right))) } /* ------------------------------------------------------------------------------------------ */ @@ -123,9 +71,4 @@ class AddSidewalkSurfaceForm : AStreetSideSelectForm Unit -) : AlertDialog(context) { - init { - val binding = QuestSurfaceDetailedAnswerImpossibleBinding.inflate(LayoutInflater.from(context)) - - setTitle(context.resources.getString(R.string.quest_surface_detailed_answer_impossible_title)) - - setButton(DialogInterface.BUTTON_POSITIVE, context.getString(android.R.string.ok)) { _, _ -> - val txt = binding.explanationInput.nonBlankTextOrNull - - if (txt == null) { - Builder(context) - .setMessage(R.string.quest_surface_detailed_answer_impossible_description) - .setPositiveButton(android.R.string.ok, null) - .show() - } else { - onSurfaceDescribed(txt) - } - } - - setButton( - DialogInterface.BUTTON_NEGATIVE, - context.getString(android.R.string.cancel), - null as DialogInterface.OnClickListener? - ) - binding.explanationInput.requestFocus() - binding.explanationInput.showKeyboard() - setView(binding.root) - } -} diff --git a/app/src/main/java/de/westnordost/streetcomplete/quests/surface/SurfaceDescriptionUtils.kt b/app/src/main/java/de/westnordost/streetcomplete/quests/surface/SurfaceDescriptionUtils.kt deleted file mode 100644 index 3e88fc0265..0000000000 --- a/app/src/main/java/de/westnordost/streetcomplete/quests/surface/SurfaceDescriptionUtils.kt +++ /dev/null @@ -1,25 +0,0 @@ -package de.westnordost.streetcomplete.quests.surface - -import android.content.Context -import androidx.appcompat.app.AlertDialog -import de.westnordost.streetcomplete.R -import de.westnordost.streetcomplete.osm.surface.Surface -import de.westnordost.streetcomplete.osm.surface.shouldBeDescribed - -fun collectSurfaceDescriptionIfNecessary( - context: Context, - surface: Surface, - onDescribed: (description: String?) -> Unit -) { - if (!surface.shouldBeDescribed) { - onDescribed(null) - } else { - AlertDialog.Builder(context) - .setMessage(R.string.quest_surface_detailed_answer_impossible_confirmation) - .setPositiveButton(R.string.quest_generic_confirmation_yes) { _, _ -> - DescribeGenericSurfaceDialog(context, onDescribed).show() - } - .setNegativeButton(android.R.string.cancel, null) - .show() - } -} diff --git a/app/src/main/java/de/westnordost/streetcomplete/quests/surface/SurfaceOrIsStepsAnswer.kt b/app/src/main/java/de/westnordost/streetcomplete/quests/surface/SurfaceOrIsStepsAnswer.kt index a521b0b1f8..b32d971947 100644 --- a/app/src/main/java/de/westnordost/streetcomplete/quests/surface/SurfaceOrIsStepsAnswer.kt +++ b/app/src/main/java/de/westnordost/streetcomplete/quests/surface/SurfaceOrIsStepsAnswer.kt @@ -1,8 +1,8 @@ package de.westnordost.streetcomplete.quests.surface -import de.westnordost.streetcomplete.osm.surface.SurfaceAndNote +import de.westnordost.streetcomplete.osm.surface.Surface sealed interface SurfaceOrIsStepsAnswer data object IsActuallyStepsAnswer : SurfaceOrIsStepsAnswer data object IsIndoorsAnswer : SurfaceOrIsStepsAnswer -data class SurfaceAnswer(val value: SurfaceAndNote) : SurfaceOrIsStepsAnswer +data class SurfaceAnswer(val value: Surface) : SurfaceOrIsStepsAnswer diff --git a/app/src/main/res/layout/fragment_overlay_surface_select.xml b/app/src/main/res/layout/fragment_overlay_surface_select.xml index 8f1d3aee78..ef7e7a397d 100644 --- a/app/src/main/res/layout/fragment_overlay_surface_select.xml +++ b/app/src/main/res/layout/fragment_overlay_surface_select.xml @@ -10,10 +10,9 @@ + layout="@layout/view_image_select" /> @@ -78,7 +77,7 @@ android:id="@+id/footway" android:layout_width="match_parent" android:layout_height="wrap_content" - layout="@layout/view_image_select_plus_text" /> + layout="@layout/view_image_select" /> - - - - - - diff --git a/app/src/main/res/layout/view_image_select_plus_text.xml b/app/src/main/res/layout/view_image_select_plus_text.xml deleted file mode 100644 index 45082c00e7..0000000000 --- a/app/src/main/res/layout/view_image_select_plus_text.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - - diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 4c7b125264..f37bc79940 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1619,10 +1619,6 @@ Otherwise, you can download another keyboard in the app store. Popular keyboards Artificial turf Rubber granules Synthetic resin - Multiple surfaces… - Are you sure that it is impossible to specify the surface? Note the “Differs along the way” answer option that allows you to cut the way where the surface changes. Please use “Can’t say” if there is a single surface but it is not available as an answer. - Please briefly specify the nature of the surface here, for example “sandy with patches of cobblestone”. The text length is limited to 255 characters. - Describe surface "Does this crosswalk have tactile paving on both ends?" "Only on one side" diff --git a/app/src/test/java/de/westnordost/streetcomplete/osm/sidewalk_surface/SidewalkSurfaceCreatorKtTest.kt b/app/src/test/java/de/westnordost/streetcomplete/osm/sidewalk_surface/SidewalkSurfaceCreatorKtTest.kt index 77117b749c..66b50ade27 100644 --- a/app/src/test/java/de/westnordost/streetcomplete/osm/sidewalk_surface/SidewalkSurfaceCreatorKtTest.kt +++ b/app/src/test/java/de/westnordost/streetcomplete/osm/sidewalk_surface/SidewalkSurfaceCreatorKtTest.kt @@ -7,7 +7,6 @@ import de.westnordost.streetcomplete.data.osm.edits.update_tags.StringMapEntryDe import de.westnordost.streetcomplete.data.osm.edits.update_tags.StringMapEntryModify import de.westnordost.streetcomplete.osm.nowAsCheckDateString import de.westnordost.streetcomplete.osm.surface.Surface.* -import de.westnordost.streetcomplete.osm.surface.SurfaceAndNote import kotlin.test.Test import kotlin.test.assertEquals @@ -18,7 +17,7 @@ internal class SidewalkSurfaceCreatorKtTest { setOf( StringMapEntryAdd("sidewalk:both:surface", "asphalt") ), - LeftAndRightSidewalkSurface(SurfaceAndNote(ASPHALT), SurfaceAndNote(ASPHALT)).appliedTo( + LeftAndRightSidewalkSurface(ASPHALT, ASPHALT).appliedTo( mapOf() ), ) @@ -30,32 +29,19 @@ internal class SidewalkSurfaceCreatorKtTest { StringMapEntryAdd("sidewalk:left:surface", "asphalt"), StringMapEntryAdd("sidewalk:right:surface", "paving_stones") ), - LeftAndRightSidewalkSurface(SurfaceAndNote(ASPHALT), SurfaceAndNote(PAVING_STONES)).appliedTo( + LeftAndRightSidewalkSurface(ASPHALT, PAVING_STONES).appliedTo( mapOf() ), ) } - @Test fun `apply generic surface on both sides`() { - assertEquals( - setOf( - StringMapEntryAdd("sidewalk:both:surface", "paved"), - StringMapEntryAdd("sidewalk:both:surface:note", "note") - ), - LeftAndRightSidewalkSurface( - SurfaceAndNote(PAVED, "note"), - SurfaceAndNote(PAVED, "note") - ).appliedTo(mapOf()) - ) - } - @Test fun `updates check_date`() { assertEquals( setOf( StringMapEntryModify("sidewalk:both:surface", "asphalt", "asphalt"), StringMapEntryModify("check_date:sidewalk:surface", "2000-10-10", nowAsCheckDateString()), ), - LeftAndRightSidewalkSurface(SurfaceAndNote(ASPHALT), SurfaceAndNote(ASPHALT)).appliedTo(mapOf( + LeftAndRightSidewalkSurface(ASPHALT, ASPHALT).appliedTo(mapOf( "sidewalk:both:surface" to "asphalt", "check_date:sidewalk:surface" to "2000-10-10" )) @@ -69,7 +55,7 @@ internal class SidewalkSurfaceCreatorKtTest { StringMapEntryDelete("sidewalk:right:surface", "paving_stones"), StringMapEntryAdd("sidewalk:both:surface", "concrete") ), - LeftAndRightSidewalkSurface(SurfaceAndNote(CONCRETE), SurfaceAndNote(CONCRETE)).appliedTo(mapOf( + LeftAndRightSidewalkSurface(CONCRETE, CONCRETE).appliedTo(mapOf( "sidewalk:left:surface" to "asphalt", "sidewalk:right:surface" to "paving_stones" )) @@ -82,7 +68,7 @@ internal class SidewalkSurfaceCreatorKtTest { StringMapEntryModify("sidewalk:left:surface", "asphalt", "concrete"), StringMapEntryModify("sidewalk:right:surface", "paving_stones", "gravel"), ), - LeftAndRightSidewalkSurface(SurfaceAndNote(CONCRETE), SurfaceAndNote(GRAVEL)).appliedTo(mapOf( + LeftAndRightSidewalkSurface(CONCRETE, GRAVEL).appliedTo(mapOf( "sidewalk:left:surface" to "asphalt", "sidewalk:right:surface" to "paving_stones" )) @@ -95,7 +81,7 @@ internal class SidewalkSurfaceCreatorKtTest { StringMapEntryDelete("sidewalk:both:smoothness", "excellent"), StringMapEntryModify("sidewalk:both:surface", "asphalt", "paving_stones") ), - LeftAndRightSidewalkSurface(SurfaceAndNote(PAVING_STONES), SurfaceAndNote(PAVING_STONES)).appliedTo(mapOf( + LeftAndRightSidewalkSurface(PAVING_STONES, PAVING_STONES).appliedTo(mapOf( "sidewalk:both:surface" to "asphalt", "sidewalk:both:smoothness" to "excellent" )) @@ -111,7 +97,7 @@ internal class SidewalkSurfaceCreatorKtTest { StringMapEntryDelete("sidewalk:right:smoothness", "good"), StringMapEntryAdd("sidewalk:both:surface", "paving_stones") ), - LeftAndRightSidewalkSurface(SurfaceAndNote(PAVING_STONES), SurfaceAndNote(PAVING_STONES)).appliedTo(mapOf( + LeftAndRightSidewalkSurface(PAVING_STONES, PAVING_STONES).appliedTo(mapOf( "sidewalk:left:surface" to "asphalt", "sidewalk:right:surface" to "concrete", "sidewalk:left:smoothness" to "excellent", @@ -125,7 +111,7 @@ internal class SidewalkSurfaceCreatorKtTest { setOf( StringMapEntryAdd("sidewalk:both:surface", "paving_stones") ), - LeftAndRightSidewalkSurface(SurfaceAndNote(PAVING_STONES), SurfaceAndNote(PAVING_STONES)).appliedTo(mapOf( + LeftAndRightSidewalkSurface(PAVING_STONES, PAVING_STONES).appliedTo(mapOf( "sidewalk" to "both", "surface" to "concrete", "smoothness" to "excellent", diff --git a/app/src/test/java/de/westnordost/streetcomplete/osm/surface/SurfaceCreatorKtTest.kt b/app/src/test/java/de/westnordost/streetcomplete/osm/surface/SurfaceCreatorKtTest.kt index 93f57f3477..d5d473707f 100644 --- a/app/src/test/java/de/westnordost/streetcomplete/osm/surface/SurfaceCreatorKtTest.kt +++ b/app/src/test/java/de/westnordost/streetcomplete/osm/surface/SurfaceCreatorKtTest.kt @@ -6,6 +6,7 @@ import de.westnordost.streetcomplete.data.osm.edits.update_tags.StringMapEntryCh import de.westnordost.streetcomplete.data.osm.edits.update_tags.StringMapEntryDelete import de.westnordost.streetcomplete.data.osm.edits.update_tags.StringMapEntryModify import de.westnordost.streetcomplete.osm.nowAsCheckDateString +import de.westnordost.streetcomplete.osm.surface.Surface.* import kotlin.test.Test import kotlin.test.assertEquals @@ -14,14 +15,14 @@ class SurfaceCreatorKtTest { @Test fun `apply surface`() { assertEquals( setOf(StringMapEntryAdd("surface", "asphalt")), - SurfaceAndNote(Surface.ASPHALT).appliedTo(mapOf()), + ASPHALT.appliedTo(mapOf()), ) } @Test fun `apply surface with prefix`() { assertEquals( setOf(StringMapEntryAdd("footway:surface", "asphalt")), - SurfaceAndNote(Surface.ASPHALT).appliedTo(mapOf(), "footway"), + ASPHALT.appliedTo(mapOf(), "footway"), ) } @@ -31,7 +32,7 @@ class SurfaceCreatorKtTest { StringMapEntryModify("surface", "asphalt", "asphalt"), StringMapEntryAdd("check_date:surface", nowAsCheckDateString()) ), - SurfaceAndNote(Surface.ASPHALT).appliedTo(mapOf("surface" to "asphalt")) + ASPHALT.appliedTo(mapOf("surface" to "asphalt")) ) } @@ -41,7 +42,7 @@ class SurfaceCreatorKtTest { StringMapEntryModify("footway:surface", "asphalt", "asphalt"), StringMapEntryAdd("check_date:footway:surface", nowAsCheckDateString()) ), - SurfaceAndNote(Surface.ASPHALT).appliedTo(mapOf("footway:surface" to "asphalt"), "footway") + ASPHALT.appliedTo(mapOf("footway:surface" to "asphalt"), "footway") ) } @@ -52,7 +53,7 @@ class SurfaceCreatorKtTest { StringMapEntryDelete("tracktype", "grade5"), StringMapEntryDelete("check_date:tracktype", "2011-11-11"), ), - SurfaceAndNote(Surface.ASPHALT).appliedTo(mapOf( + ASPHALT.appliedTo(mapOf( "surface" to "compacted", "tracktype" to "grade5", "check_date:tracktype" to "2011-11-11" @@ -63,14 +64,14 @@ class SurfaceCreatorKtTest { @Test fun `don't remove tracktype when surface was added`() { assertEquals( setOf(StringMapEntryAdd("surface", "asphalt")), - SurfaceAndNote(Surface.ASPHALT).appliedTo(mapOf("tracktype" to "grade5",)) + ASPHALT.appliedTo(mapOf("tracktype" to "grade5",)) ) } @Test fun `don't remove tracktype when surface category didn't change`() { assertEquals( setOf(StringMapEntryModify("surface", "concrete", "asphalt")), - SurfaceAndNote(Surface.ASPHALT).appliedTo(mapOf( + ASPHALT.appliedTo(mapOf( "surface" to "concrete", "tracktype" to "grade5", )) @@ -80,7 +81,7 @@ class SurfaceCreatorKtTest { @Test fun `remove mismatching tracktype not done with prefix`() { assertEquals( setOf(StringMapEntryModify("footway:surface", "compacted", "asphalt")), - SurfaceAndNote(Surface.ASPHALT).appliedTo(mapOf( + ASPHALT.appliedTo(mapOf( "footway:surface" to "compacted", "tracktype" to "grade5", "check_date:tracktype" to "2011-11-11" @@ -93,15 +94,17 @@ class SurfaceCreatorKtTest { setOf( StringMapEntryModify("surface", "compacted", "asphalt"), StringMapEntryDelete("surface:grade", "3"), + StringMapEntryDelete("surface:note", "hey"), StringMapEntryDelete("surface:colour", "pink"), StringMapEntryDelete("smoothness", "well"), StringMapEntryDelete("smoothness:date", "2011-11-11"), StringMapEntryDelete("check_date:smoothness", "2011-11-11"), StringMapEntryDelete("tracktype", "grade5"), ), - SurfaceAndNote(Surface.ASPHALT).appliedTo(mapOf( + ASPHALT.appliedTo(mapOf( "surface" to "compacted", "surface:grade" to "3", + "surface:note" to "hey", "smoothness" to "well", "smoothness:date" to "2011-11-11", "check_date:smoothness" to "2011-11-11", @@ -116,9 +119,10 @@ class SurfaceCreatorKtTest { setOf( StringMapEntryAdd("footway:surface", "asphalt") ), - SurfaceAndNote(Surface.ASPHALT).appliedTo(mapOf( + ASPHALT.appliedTo(mapOf( "surface" to "compacted", "surface:grade" to "3", + "surface:note" to "hey", "smoothness" to "well", "smoothness:date" to "2011-11-11", "check_date:smoothness" to "2011-11-11", @@ -133,14 +137,16 @@ class SurfaceCreatorKtTest { setOf( StringMapEntryModify("footway:surface", "compacted", "asphalt"), StringMapEntryDelete("footway:surface:grade", "3"), + StringMapEntryDelete("footway:surface:note", "hey"), StringMapEntryDelete("footway:surface:colour", "pink"), StringMapEntryDelete("footway:smoothness", "well"), StringMapEntryDelete("footway:smoothness:date", "2011-11-11"), StringMapEntryDelete("check_date:footway:smoothness", "2011-11-11"), ), - SurfaceAndNote(Surface.ASPHALT).appliedTo(mapOf( + ASPHALT.appliedTo(mapOf( "footway:surface" to "compacted", "footway:surface:grade" to "3", + "footway:surface:note" to "hey", "footway:smoothness" to "well", "footway:smoothness:date" to "2011-11-11", "check_date:footway:smoothness" to "2011-11-11", @@ -155,9 +161,10 @@ class SurfaceCreatorKtTest { StringMapEntryModify("surface", "asphalt", "asphalt"), StringMapEntryAdd("check_date:surface", nowAsCheckDateString()), ), - SurfaceAndNote(Surface.ASPHALT).appliedTo(mapOf( + ASPHALT.appliedTo(mapOf( "surface" to "asphalt", "surface:grade" to "3", + "surface:note" to "hey", "smoothness" to "well", "smoothness:date" to "2011-11-11", "check_date:smoothness" to "2011-11-11", @@ -173,9 +180,10 @@ class SurfaceCreatorKtTest { StringMapEntryModify("footway:surface", "asphalt", "asphalt"), StringMapEntryAdd("check_date:footway:surface", nowAsCheckDateString()), ), - SurfaceAndNote(Surface.ASPHALT).appliedTo(mapOf( + ASPHALT.appliedTo(mapOf( "footway:surface" to "asphalt", "footway:surface:grade" to "3", + "footway:surface:note" to "hey", "footway:smoothness" to "well", "footway:smoothness:date" to "2011-11-11", "check_date:footway:smoothness" to "2011-11-11", @@ -190,62 +198,19 @@ class SurfaceCreatorKtTest { StringMapEntryAdd("surface", "asphalt"), StringMapEntryDelete("source:surface", "bing"), ), - SurfaceAndNote(Surface.ASPHALT).appliedTo(mapOf( + ASPHALT.appliedTo(mapOf( "highway" to "residential", "source:surface" to "bing" )), ) } - @Test fun `add note when specified`() { - assertEquals( - setOf( - StringMapEntryAdd("surface", "asphalt"), - StringMapEntryAdd("surface:note", "gurgle"), - ), - SurfaceAndNote(Surface.ASPHALT, "gurgle").appliedTo(mapOf()), - ) - } - - @Test fun `add note with prefix when specified`() { - assertEquals( - setOf( - StringMapEntryAdd("footway:surface", "asphalt"), - StringMapEntryAdd("footway:surface:note", "gurgle"), - ), - SurfaceAndNote(Surface.ASPHALT, "gurgle").appliedTo(mapOf(), "footway"), - ) - } - - @Test fun `remove note when not specified`() { - assertEquals( - setOf( - StringMapEntryAdd("surface", "asphalt"), - StringMapEntryDelete("surface:note", "nurgle"), - ), - SurfaceAndNote(Surface.ASPHALT).appliedTo(mapOf("surface:note" to "nurgle")), - ) - } - - @Test fun `remove note with prefix when not specified`() { - assertEquals( - setOf( - StringMapEntryAdd("footway:surface", "asphalt"), - StringMapEntryDelete("footway:surface:note", "nurgle"), - ), - SurfaceAndNote(Surface.ASPHALT).appliedTo( - mapOf("footway:surface:note" to "nurgle"), - "footway" - ), - ) - } - @Test fun `sidewalk surface marked as tag on road is not touched`() { assertEquals( setOf( StringMapEntryAdd("surface", "asphalt"), ), - SurfaceAndNote(Surface.ASPHALT).appliedTo(mapOf( + ASPHALT.appliedTo(mapOf( "highway" to "tertiary", "sidewalk:surface" to "paving_stones" )) @@ -253,7 +218,7 @@ class SurfaceCreatorKtTest { } } -private fun SurfaceAndNote.appliedTo( +private fun Surface.appliedTo( tags: Map, prefix: String? = null ): Set { diff --git a/app/src/test/java/de/westnordost/streetcomplete/osm/surface/SurfaceKtTest.kt b/app/src/test/java/de/westnordost/streetcomplete/osm/surface/SurfaceKtTest.kt deleted file mode 100644 index 0b954639a7..0000000000 --- a/app/src/test/java/de/westnordost/streetcomplete/osm/surface/SurfaceKtTest.kt +++ /dev/null @@ -1,21 +0,0 @@ -package de.westnordost.streetcomplete.osm.surface - -import kotlin.test.* -import kotlin.test.Test - -class SurfaceKtTest { - - @Test fun `surface=unpaved is underspecified and must be described`() { - assertTrue(Surface.UNPAVED.shouldBeDescribed) - assertTrue(Surface.UNPAVED.shouldBeDescribed) - } - - @Test fun `surface=asphalt is well specified and does not need description`() { - assertFalse(Surface.ASPHALT.shouldBeDescribed) - } - - @Test fun `surface=ground is underspecified and does not need description`() { - assertFalse(Surface.GROUND.shouldBeDescribed) - assertFalse(Surface.GROUND.shouldBeDescribed) - } -} diff --git a/app/src/test/java/de/westnordost/streetcomplete/osm/surface/SurfaceParserKtTest.kt b/app/src/test/java/de/westnordost/streetcomplete/osm/surface/SurfaceParserKtTest.kt index b8c335bed9..65e039b674 100644 --- a/app/src/test/java/de/westnordost/streetcomplete/osm/surface/SurfaceParserKtTest.kt +++ b/app/src/test/java/de/westnordost/streetcomplete/osm/surface/SurfaceParserKtTest.kt @@ -6,49 +6,23 @@ import kotlin.test.Test class SurfaceParserKtTest { @Test fun `parse surface`() { - assertEquals( - parseSurfaceAndNote(mapOf("surface" to "asphalt")), - SurfaceAndNote(Surface.ASPHALT, null) - ) - assertEquals( - parseSurfaceAndNote(mapOf("surface" to "earth")), - SurfaceAndNote(Surface.EARTH, null) - ) - assertEquals( - parseSurfaceAndNote(mapOf("surface" to "soil")), - SurfaceAndNote(Surface.SOIL, null) - ) + assertEquals(parseSurface("asphalt"), Surface.ASPHALT) + assertEquals(parseSurface("earth"), Surface.EARTH) + assertEquals(parseSurface("soil"), Surface.SOIL) } @Test fun `parse unknown surface`() { - assertEquals( - parseSurfaceAndNote(mapOf("surface" to "wobbly_goo")), - SurfaceAndNote(Surface.UNKNOWN, null) - ) + assertEquals(parseSurface("wobbly_goo"), Surface.UNKNOWN) } @Test fun `parse invalid surface`() { - assertNull(parseSurfaceAndNote(mapOf("surface" to "cobblestone"))) - assertNull(parseSurfaceAndNote(mapOf("surface" to "cement"))) - assertNull(parseSurfaceAndNote(mapOf("surface" to "paved;unpaved"))) - assertNull(parseSurfaceAndNote(mapOf("surface" to ""))) - } - - @Test fun `parse surface and note`() { - assertEquals( - parseSurfaceAndNote(mapOf("surface" to "asphalt", "surface:note" to "blurgl")), - SurfaceAndNote(Surface.ASPHALT, "blurgl") - ) + assertNull(parseSurface("cobblestone")) + assertNull(parseSurface("cement")) + assertNull(parseSurface("paved;unpaved")) + assertNull(parseSurface("")) } @Test fun `parse no surface`() { - assertNull(parseSurfaceAndNote(mapOf())) - } - - @Test fun `parse surface with prefix`() { - assertEquals( - parseSurfaceAndNote(mapOf("footway:surface" to "asphalt", "footway:surface:note" to "hey"), "footway"), - SurfaceAndNote(Surface.ASPHALT, "hey") - ) + assertNull(parseSurface(null)) } } diff --git a/app/src/test/java/de/westnordost/streetcomplete/osm/surface/SurfaceUtilsKtTest.kt b/app/src/test/java/de/westnordost/streetcomplete/osm/surface/SurfaceUtilsKtTest.kt index e518711a0f..cfe8129f8c 100644 --- a/app/src/test/java/de/westnordost/streetcomplete/osm/surface/SurfaceUtilsKtTest.kt +++ b/app/src/test/java/de/westnordost/streetcomplete/osm/surface/SurfaceUtilsKtTest.kt @@ -23,8 +23,7 @@ class SurfaceUtilsKtTest { @Test fun `update foot and cycleway with common paved surface`() { assertEquals( setOf( - StringMapEntryAdd("surface", "paved"), - StringMapEntryModify("surface:note", "asphalt but also paving stones", "asphalt but also paving stones"), + StringMapEntryAdd("surface", "paved") ), appliedCommonSurfaceFromFootAndCyclewaySurface(mapOf( "footway:surface" to "asphalt", diff --git a/app/src/test/java/de/westnordost/streetcomplete/overlays/surface/SurfaceColorMappingKtTest.kt b/app/src/test/java/de/westnordost/streetcomplete/overlays/surface/SurfaceColorMappingKtTest.kt deleted file mode 100644 index 1e27e70d35..0000000000 --- a/app/src/test/java/de/westnordost/streetcomplete/overlays/surface/SurfaceColorMappingKtTest.kt +++ /dev/null @@ -1,63 +0,0 @@ -package de.westnordost.streetcomplete.overlays.surface - -import de.westnordost.streetcomplete.osm.surface.Surface -import de.westnordost.streetcomplete.osm.surface.parseSurfaceAndNote -import de.westnordost.streetcomplete.overlays.Color -import de.westnordost.streetcomplete.testutils.way -import kotlin.test.* -import kotlin.test.Test - -class SurfaceColorMappingKtTest { - - @Test fun `return color for normal surfaces`() { - val road = way(tags = mapOf("surface" to "asphalt")) - assertEquals(Surface.ASPHALT.color, parseSurfaceAndNote(road.tags).getColor(road)) - } - - @Test fun `return missing-data color for unpaved without note`() { - val road = way(tags = mapOf("surface" to "unpaved")) - assertEquals(Color.DATA_REQUESTED, parseSurfaceAndNote(road.tags).getColor(road)) - } - - @Test fun `return missing-data color for paved without note`() { - val road = way(tags = mapOf("surface" to "paved")) - assertEquals(Color.DATA_REQUESTED, parseSurfaceAndNote(road.tags).getColor(road)) - } - - @Test fun `return missing-data color for missing surface`() { - val road = way(tags = mapOf()) - assertEquals(Color.DATA_REQUESTED, parseSurfaceAndNote(road.tags).getColor(road)) - } - - @Test fun `return black for unpaved with note`() { - val road = way(tags = mapOf( - "surface" to "unpaved", - "surface:note" to "note text", - )) - assertEquals(Color.BLACK, parseSurfaceAndNote(road.tags).getColor(road)) - } - - @Test fun `return black for paved with note`() { - val road = way(tags = mapOf( - "surface" to "paved", - "surface:note" to "note text", - )) - assertEquals(Color.BLACK, parseSurfaceAndNote(road.tags).getColor(road)) - } - - @Test fun `return invisible for unpaved with restricted access`() { - val road = way(tags = mapOf( - "access" to "private", - "surface" to "unpaved", - )) - assertEquals(Color.INVISIBLE, parseSurfaceAndNote(road.tags).getColor(road)) - } - - @Test fun `return invisible for paved with restricted access`() { - val road = way(tags = mapOf( - "access" to "private", - "surface" to "paved", - )) - assertEquals(Color.INVISIBLE, parseSurfaceAndNote(road.tags).getColor(road)) - } -} diff --git a/app/src/test/java/de/westnordost/streetcomplete/quests/surface/AddCyclewayPartSurfaceTest.kt b/app/src/test/java/de/westnordost/streetcomplete/quests/surface/AddCyclewayPartSurfaceTest.kt index bf59b9b4f5..4e94e9fde3 100644 --- a/app/src/test/java/de/westnordost/streetcomplete/quests/surface/AddCyclewayPartSurfaceTest.kt +++ b/app/src/test/java/de/westnordost/streetcomplete/quests/surface/AddCyclewayPartSurfaceTest.kt @@ -2,8 +2,8 @@ package de.westnordost.streetcomplete.quests.surface import de.westnordost.streetcomplete.data.osm.edits.update_tags.StringMapEntryAdd import de.westnordost.streetcomplete.data.osm.edits.update_tags.StringMapEntryModify +import de.westnordost.streetcomplete.osm.nowAsCheckDateString import de.westnordost.streetcomplete.osm.surface.Surface -import de.westnordost.streetcomplete.osm.surface.SurfaceAndNote import de.westnordost.streetcomplete.quests.TestMapDataWithGeometry import de.westnordost.streetcomplete.quests.answerApplied import de.westnordost.streetcomplete.quests.answerAppliedTo @@ -44,14 +44,31 @@ class AddCyclewayPartSurfaceTest { assertIsNotApplicable("highway" to "cycleway", "segregated" to "yes", "sidewalk" to "yes") } + @Test fun `applicable to cycleway with invalid surface`() { + assertIsApplicable("highway" to "cycleway", "segregated" to "yes", "cycleway:surface" to "cobblestone") + } + @Test fun `applicable to cycleway with unspecific surface without note`() { assertIsApplicable("highway" to "cycleway", "segregated" to "yes", "cycleway:surface" to "paved") assertIsApplicable("highway" to "path", "bicycle" to "designated", "segregated" to "yes", "cycleway:surface" to "unpaved") } @Test fun `not applicable to cycleway with unspecific surface and note`() { - assertIsNotApplicable("highway" to "cycleway", "segregated" to "yes", "cycleway:surface" to "paved", "cycleway:surface:note" to "it's complicated") - assertIsNotApplicable("highway" to "path", "bicycle" to "designated", "segregated" to "yes", "cycleway:surface" to "unpaved", "note:cycleway:surface" to "it's complicated") + assertIsNotApplicable( + "highway" to "cycleway", + "segregated" to "yes", + "cycleway:surface" to "paved", + "cycleway:surface:note" to "it's complicated" + ) + } + + @Test fun `not applicable to cycleway with unspecific surface and recent check date`() { + assertIsNotApplicable( + "highway" to "cycleway", + "segregated" to "yes", + "cycleway:surface" to "unpaved", + "check_date:cycleway:surface" to nowAsCheckDateString() + ) } @Test fun `not applicable to private cycleways`() { @@ -87,7 +104,7 @@ class AddCyclewayPartSurfaceTest { @Test fun `apply asphalt surface`() { assertEquals( setOf(StringMapEntryAdd("cycleway:surface", "asphalt")), - questType.answerApplied(SurfaceAndNote(Surface.ASPHALT)) + questType.answerApplied(Surface.ASPHALT) ) } @@ -98,7 +115,7 @@ class AddCyclewayPartSurfaceTest { StringMapEntryModify("surface", "paving_stones", "concrete") ), questType.answerAppliedTo( - SurfaceAndNote(Surface.CONCRETE), + Surface.CONCRETE, mapOf( "surface" to "paving_stones", "footway:surface" to "concrete", diff --git a/app/src/test/java/de/westnordost/streetcomplete/quests/surface/AddFootwayPartSurfaceTest.kt b/app/src/test/java/de/westnordost/streetcomplete/quests/surface/AddFootwayPartSurfaceTest.kt index a0e7f50595..fc56c7dd43 100644 --- a/app/src/test/java/de/westnordost/streetcomplete/quests/surface/AddFootwayPartSurfaceTest.kt +++ b/app/src/test/java/de/westnordost/streetcomplete/quests/surface/AddFootwayPartSurfaceTest.kt @@ -2,8 +2,8 @@ package de.westnordost.streetcomplete.quests.surface import de.westnordost.streetcomplete.data.osm.edits.update_tags.StringMapEntryAdd import de.westnordost.streetcomplete.data.osm.edits.update_tags.StringMapEntryModify +import de.westnordost.streetcomplete.osm.nowAsCheckDateString import de.westnordost.streetcomplete.osm.surface.Surface -import de.westnordost.streetcomplete.osm.surface.SurfaceAndNote import de.westnordost.streetcomplete.quests.TestMapDataWithGeometry import de.westnordost.streetcomplete.quests.answerApplied import de.westnordost.streetcomplete.quests.answerAppliedTo @@ -45,14 +45,31 @@ class AddFootwayPartSurfaceTest { assertIsNotApplicable("highway" to "footway", "segregated" to "yes", "sidewalk" to "yes") } + @Test fun `applicable to footway with invalid surface`() { + assertIsApplicable("highway" to "footway", "segregated" to "yes", "footway:surface" to "cobblestone") + } + @Test fun `applicable to footway with unspecific surface without note`() { assertIsApplicable("highway" to "footway", "segregated" to "yes", "footway:surface" to "paved") assertIsApplicable("highway" to "path", "foot" to "designated", "segregated" to "yes", "footway:surface" to "unpaved") } @Test fun `not applicable to footway with unspecific surface and note`() { - assertIsNotApplicable("highway" to "footway", "segregated" to "yes", "footway:surface" to "paved", "footway:surface:note" to "it's complicated") - assertIsNotApplicable("highway" to "path", "foot" to "designated", "segregated" to "yes", "footway:surface" to "unpaved", "note:footway:surface" to "it's complicated") + assertIsNotApplicable( + "highway" to "footway", + "segregated" to "yes", + "footway:surface" to "paved", + "footway:surface:note" to "it's complicated" + ) + } + + @Test fun `not applicable to footway with unspecific surface and recent check date`() { + assertIsNotApplicable( + "highway" to "footway", + "segregated" to "yes", + "footway:surface" to "unpaved", + "check_date:footway:surface" to nowAsCheckDateString() + ) } @Test fun `not applicable to private footways`() { @@ -88,7 +105,7 @@ class AddFootwayPartSurfaceTest { @Test fun `apply asphalt surface`() { assertEquals( setOf(StringMapEntryAdd("footway:surface", "asphalt")), - questType.answerApplied(SurfaceAndNote(Surface.ASPHALT)) + questType.answerApplied(Surface.ASPHALT) ) } @@ -99,7 +116,7 @@ class AddFootwayPartSurfaceTest { StringMapEntryModify("surface", "paving_stones", "concrete") ), questType.answerAppliedTo( - SurfaceAndNote(Surface.CONCRETE), + Surface.CONCRETE, mapOf( "surface" to "paving_stones", "footway:surface" to "paving_stones", diff --git a/app/src/test/java/de/westnordost/streetcomplete/quests/surface/AddPitchSurfaceTest.kt b/app/src/test/java/de/westnordost/streetcomplete/quests/surface/AddPitchSurfaceTest.kt index e10604dec9..989a94db78 100644 --- a/app/src/test/java/de/westnordost/streetcomplete/quests/surface/AddPitchSurfaceTest.kt +++ b/app/src/test/java/de/westnordost/streetcomplete/quests/surface/AddPitchSurfaceTest.kt @@ -1,5 +1,6 @@ package de.westnordost.streetcomplete.quests.surface +import de.westnordost.streetcomplete.osm.nowAsCheckDateString import de.westnordost.streetcomplete.testutils.way import kotlin.test.Test import kotlin.test.assertFalse @@ -40,6 +41,36 @@ class AddPitchSurfaceTest { assertIsNotApplicable("leisure" to "pitch", "sport" to "table_soccer") } + + @Test fun `applicable to surface tags not providing proper info`() { + assertIsApplicable("leisure" to "pitch", "sport" to "soccer", "surface" to "paved") + assertIsApplicable("leisure" to "pitch", "sport" to "soccer", "surface" to "trail") + assertIsApplicable("leisure" to "pitch", "sport" to "soccer", "surface" to "cement") + } + + @Test fun `applicable to generic surface`() { + assertIsApplicable("leisure" to "pitch", "sport" to "soccer", "surface" to "paved") + assertIsApplicable("leisure" to "pitch", "sport" to "soccer", "surface" to "unpaved") + } + + @Test fun `not applicable to generic surface with note`() { + assertIsNotApplicable( + "leisure" to "pitch", + "sport" to "soccer", + "surface" to "paved", + "surface:note" to "wildly mixed asphalt, concrete, paving stones and sett" + ) + } + + @Test fun `not applicable to generic surface with recent check date`() { + assertIsNotApplicable( + "leisure" to "pitch", + "sport" to "soccer", + "surface" to "unpaved", + "check_date:surface" to nowAsCheckDateString() + ) + } + private fun assertIsApplicable(vararg pairs: Pair) { assertTrue(questType.isApplicableTo(way(nodes = listOf(1, 2, 3), tags = mapOf(*pairs)))) } diff --git a/app/src/test/java/de/westnordost/streetcomplete/quests/surface/AddRoadSurfaceTest.kt b/app/src/test/java/de/westnordost/streetcomplete/quests/surface/AddRoadSurfaceTest.kt index b6ce22abbe..229a999d1c 100644 --- a/app/src/test/java/de/westnordost/streetcomplete/quests/surface/AddRoadSurfaceTest.kt +++ b/app/src/test/java/de/westnordost/streetcomplete/quests/surface/AddRoadSurfaceTest.kt @@ -1,5 +1,6 @@ package de.westnordost.streetcomplete.quests.surface +import de.westnordost.streetcomplete.osm.nowAsCheckDateString import de.westnordost.streetcomplete.testutils.way import kotlin.test.Test import kotlin.test.assertFalse @@ -30,11 +31,31 @@ class AddRoadSurfaceTest { @Test fun `applicable to surface tags not providing proper info`() { assertIsApplicable("highway" to "residential", "surface" to "paved") - assertIsNotApplicable("highway" to "residential", "surface" to "paved", "surface:note" to "wildly mixed asphalt, concrete, paving stones and sett") - assertIsApplicable("highway" to "residential", "surface" to "cobblestone") + assertIsApplicable("highway" to "residential", "surface" to "trail") assertIsApplicable("highway" to "residential", "surface" to "cement") } + @Test fun `applicable to generic surface`() { + assertIsApplicable("highway" to "residential", "surface" to "paved") + assertIsApplicable("highway" to "residential", "surface" to "unpaved") + } + + @Test fun `not applicable to generic surface with note`() { + assertIsNotApplicable( + "highway" to "residential", + "surface" to "paved", + "surface:note" to "wildly mixed asphalt, concrete, paving stones and sett" + ) + } + + @Test fun `not applicable to generic surface with recent check date`() { + assertIsNotApplicable( + "highway" to "residential", + "surface" to "unpaved", + "check_date:surface" to nowAsCheckDateString() + ) + } + private fun assertIsApplicable(vararg pairs: Pair) { assertTrue(questType.isApplicableTo(way(nodes = listOf(1, 2, 3), tags = mapOf(*pairs)))) }