Skip to content

Commit

Permalink
Merge branch 'mnalis-v38b1-smoothness' into mnalis-v38-smoothness
Browse files Browse the repository at this point in the history
  • Loading branch information
mnalis committed Nov 25, 2021
2 parents 8267fb5 + 89a0278 commit d40aba1
Show file tree
Hide file tree
Showing 38 changed files with 716 additions and 4 deletions.
13 changes: 11 additions & 2 deletions CHANGES-mnalis.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
## Changes in mnalis-v38b1 branch
## Changes in mnalis-v38b1-smoothness branch

This file details changes made in https://github.com/mnalis/StreetComplete/tree/mnalis-v38b1
This file details changes made in https://github.com/mnalis/StreetComplete/tree/mnalis-v38b1-smoothness
as modified from upstream https://github.com/streetcomplete/StreetComplete

From `mnalis-v38b1` branch:
Expand All @@ -13,6 +13,15 @@ From `mnalis-v38b1` branch:
* ask for backrest on leisure=picnic_table too
from `picnic-backrest` branch

From `helium314/smoothness`:
* Surface smoothness quest, W.I.P.
https://github.com/westnordost/StreetComplete/issues/1630
https://github.com/streetcomplete/StreetComplete/pull/3257
* manually try to fix OtherAnswer() refactoring
* try to fix duplicate "quest_presets_delete_message" ?
* try to fix style renames
* QuestTypeAchievement compile error

## TODO
* update APK build code, and put date/version/last commit in filename.
Also, is it possible to download apk directly from actions, or must it be packed in debug.zip ?
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ import de.westnordost.streetcomplete.quests.self_service.AddSelfServiceLaundry
import de.westnordost.streetcomplete.quests.shop_type.CheckShopType
import de.westnordost.streetcomplete.quests.shop_type.SpecifyShopType
import de.westnordost.streetcomplete.quests.sidewalk.AddSidewalk
import de.westnordost.streetcomplete.quests.smoothness.*
import de.westnordost.streetcomplete.quests.sport.AddSport
import de.westnordost.streetcomplete.quests.steps_incline.AddStepsIncline
import de.westnordost.streetcomplete.quests.steps_ramp.AddStepsRamp
Expand Down Expand Up @@ -352,6 +353,8 @@ import javax.inject.Singleton
AddTracktype(), // widely used in map rendering - OSM Carto, OsmAnd...
AddCycleway(countryInfos), // for any cyclist routers (and cyclist maps)
AddLanes(), // abstreet, certainly most routing engines - often requires way to be split
AddRoadSmoothness(),
AddPathSmoothness(),

// footways
AddPathSurface(), // used by OSM Carto, BRouter, OsmAnd, OSRM, graphhopper...
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package de.westnordost.streetcomplete.quests.smoothness

import de.westnordost.streetcomplete.R
import de.westnordost.streetcomplete.data.meta.ALL_ROADS
import de.westnordost.streetcomplete.data.meta.ANYTHING_PAVED
import de.westnordost.streetcomplete.data.meta.updateWithCheckDate
import de.westnordost.streetcomplete.data.osm.osmquests.OsmFilterQuestType
import de.westnordost.streetcomplete.data.osm.edits.update_tags.StringMapChangesBuilder
import de.westnordost.streetcomplete.ktx.arrayOfNotNull
import de.westnordost.streetcomplete.quests.surface.Surface
import de.westnordost.streetcomplete.data.user.achievements.QuestTypeAchievement.BICYCLIST
import de.westnordost.streetcomplete.data.user.achievements.QuestTypeAchievement.BLIND
import de.westnordost.streetcomplete.data.user.achievements.QuestTypeAchievement.WHEELCHAIR
import de.westnordost.streetcomplete.quests.surface.asItem

class AddPathSmoothness : OsmFilterQuestType<SmoothnessAnswer>() {

// maybe exclude service roads? or driveways?
override val elementFilter = """
ways with highway
and highway ~ ${ALL_PATHS_EXCEPT_STEPS.joinToString("|")}
and surface ~ ${SURFACES_FOR_SMOOTHNESS.joinToString("|")}
and access !~ private|no
and segregated != yes
and (!conveying or conveying = no)
and (!indoor or indoor = no)
and !cycleway:surface and !footway:surface
and (
!smoothness
or smoothness older today -4 years
)
"""

override val commitMessage = "Add path smoothness"
override val wikiLink = "Key:smoothness"
override val icon = R.drawable.ic_quest_path_surface_detail
override val isSplitWayEnabled = true

override val questTypeAchievements = listOf(BLIND, WHEELCHAIR, BICYCLIST)

override fun getTitle(tags: Map<String, String>): Int {
val hasName = tags.containsKey("name")
val isSquare = tags["area"] == "yes"
return when {
hasName -> R.string.quest_smoothness_name_title
isSquare -> R.string.quest_smoothness_square_title
else -> R.string.quest_smoothness_path_title
}
}

override fun getTitleArgs(tags: Map<String, String>, featureName: Lazy<String?>): Array<String> {
val surface = Surface.values().find { it.osmValue == tags["surface"] }!!
val surfaceString = surface.asItem().title.toString()
return if (tags.containsKey("name"))
arrayOf(tags["name"]!!, surfaceString)
else
arrayOf(surfaceString)
}

override fun createForm() = AddSmoothnessForm()

override fun applyAnswerTo(answer: SmoothnessAnswer, changes: StringMapChangesBuilder) {
when (answer) {
is SmoothnessValueAnswer -> changes.updateWithCheckDate("smoothness", answer.osmValue)
is WrongSurfaceAnswer -> changes.delete("surface")
}
}
}

// smoothness is not asked for steps
// "pedestrian" is in here so the path answers are shown instead of road answers (which focus on cars)
val ALL_PATHS_EXCEPT_STEPS = listOf("footway", "cycleway", "path", "bridleway", "pedestrian")
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@

package de.westnordost.streetcomplete.quests.smoothness

import de.westnordost.streetcomplete.R
import de.westnordost.streetcomplete.data.meta.ALL_ROADS
import de.westnordost.streetcomplete.data.meta.ANYTHING_PAVED
import de.westnordost.streetcomplete.data.meta.updateWithCheckDate
import de.westnordost.streetcomplete.data.osm.osmquests.OsmFilterQuestType
import de.westnordost.streetcomplete.data.osm.edits.update_tags.StringMapChangesBuilder
import de.westnordost.streetcomplete.quests.surface.Surface
import de.westnordost.streetcomplete.data.user.achievements.QuestTypeAchievement.BICYCLIST
import de.westnordost.streetcomplete.data.user.achievements.QuestTypeAchievement.BLIND
import de.westnordost.streetcomplete.data.user.achievements.QuestTypeAchievement.WHEELCHAIR
import de.westnordost.streetcomplete.quests.surface.asItem

class AddRoadSmoothness : OsmFilterQuestType<SmoothnessAnswer>() {

// maybe exclude service roads? or driveways?
override val elementFilter = """
ways with highway
and highway ~ ${ALL_ROADS.joinToString("|")}
and surface ~ ${SURFACES_FOR_SMOOTHNESS.joinToString("|")}
and access !~ private|no
and (
!smoothness
or smoothness older today -4 years
)
"""

override val commitMessage = "Add road smoothness"
override val wikiLink = "Key:smoothness"
override val icon = R.drawable.ic_quest_street_surface_detail
override val isSplitWayEnabled = true

override val questTypeAchievements = listOf(BLIND, WHEELCHAIR, BICYCLIST)

override fun getTitle(tags: Map<String, String>): Int {
val hasName = tags.containsKey("name")
val isSquare = tags["area"] == "yes"
return when {
hasName -> R.string.quest_smoothness_name_title
isSquare -> R.string.quest_smoothness_square_title
else -> R.string.quest_smoothness_road_title
}
}

override fun getTitleArgs(tags: Map<String, String>, featureName: Lazy<String?>): Array<String> {
val surface = Surface.values().find { it.osmValue == tags["surface"] }!!
val surfaceString = surface.asItem().title.toString()
return if (tags.containsKey("name"))
arrayOf(tags["name"]!!, surfaceString)
else
arrayOf(surfaceString)
}

override fun createForm() = AddSmoothnessForm()

override fun applyAnswerTo(answer: SmoothnessAnswer, changes: StringMapChangesBuilder) {
when (answer) {
is SmoothnessValueAnswer -> changes.updateWithCheckDate("smoothness", answer.osmValue)
is WrongSurfaceAnswer -> changes.delete("surface")
}
}
}

// surfaces that are actually used in AddSmoothnessForm
// should only contain values that are in the Surface class
val SURFACES_FOR_SMOOTHNESS = listOf(
"asphalt", "sett", "paving_stones", "compacted", "gravel"
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package de.westnordost.streetcomplete.quests.smoothness

import android.os.Bundle
import android.view.LayoutInflater
import androidx.appcompat.app.AlertDialog
import de.westnordost.streetcomplete.R
import de.westnordost.streetcomplete.quests.AImageListQuestAnswerFragment
import de.westnordost.streetcomplete.quests.AnswerItem
import de.westnordost.streetcomplete.quests.surface.Surface
import de.westnordost.streetcomplete.quests.surface.asItem
import de.westnordost.streetcomplete.view.image_select.Item
import de.westnordost.streetcomplete.view.image_select.ItemViewHolder

class AddSmoothnessForm : AImageListQuestAnswerFragment<Smoothness, SmoothnessAnswer>() {

override val otherAnswers = listOf(
AnswerItem(R.string.quest_smoothness_wrong_surface) { surfaceWrong() },
AnswerItem(R.string.quest_smoothness_obstacle) { showObstacleHint() }
)

private val surfaceTag get() = osmElement!!.tags["surface"]

private val highwayTag get() = osmElement!!.tags["highway"]

override val items get() = Smoothness.values().toItems(surfaceTag!!, highwayTag!!)

override val itemsPerRow = 1

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
imageSelector.cellLayoutId = R.layout.cell_labeled_icon_select_smoothness
}

override val moveFavoritesToFront = false

override fun onClickOk(selectedItems: List<Smoothness>) {
applyAnswer(SmoothnessValueAnswer(selectedItems.single().osmValue))
}

private fun showObstacleHint() {
activity?.let { AlertDialog.Builder(it)
.setMessage(R.string.quest_smoothness_obstacle_hint)
.setPositiveButton(android.R.string.ok, null)
.show()
}
}

private fun surfaceWrong() {
val surfaceType = Surface.values().find { it.osmValue == surfaceTag }!!
showWrongSurfaceDialog(surfaceType)
}

private fun showWrongSurfaceDialog(surface: Surface) {
val inflater = LayoutInflater.from(requireContext())
val inner = inflater.inflate(R.layout.dialog_quest_smoothness_wrong_surface, null, false)
ItemViewHolder(inner.findViewById(R.id.item_view)).bind(surface.asItem())

AlertDialog.Builder(requireContext())
.setView(inner)
.setPositiveButton(R.string.quest_generic_hasFeature_yes_leave_note) { _, _ -> composeNote() }
.setNegativeButton(R.string.quest_generic_hasFeature_no) { _, _ -> applyAnswer(WrongSurfaceAnswer) }
.show()
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package de.westnordost.streetcomplete.quests.smoothness

enum class Smoothness(val osmValue: String) {
EXCELLENT("excellent"),
GOOD("good"),
INTERMEDIATE("intermediate"),
BAD("bad"),
VERY_BAD("very_bad"),
HORRIBLE("horrible"),
VERY_HORRIBLE("very_horrible"),
IMPASSABLE("impassable"),
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package de.westnordost.streetcomplete.quests.smoothness

sealed class SmoothnessAnswer

data class SmoothnessValueAnswer(val osmValue: String): SmoothnessAnswer()

object WrongSurfaceAnswer: SmoothnessAnswer()
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
package de.westnordost.streetcomplete.quests.smoothness

import de.westnordost.streetcomplete.R
import de.westnordost.streetcomplete.quests.smoothness.Smoothness.*
import de.westnordost.streetcomplete.view.image_select.Item

fun Array<Smoothness>.toItems(surface: String, highway: String) = this.mapNotNull { it.asItem(surface, highway) }

// return null if not a valid combination
fun Smoothness.asItem(surface: String, highway: String): Item<Smoothness>? {
val imageResId = getImageResId(surface) ?: return null
val descriptionResId = getDescriptionResId(surface, highway) ?: return null
return Item(this, imageResId, getTitleResId(), descriptionResId)
}

fun Smoothness.getTitleResId() = when (this) {
EXCELLENT -> R.string.quest_smoothness_title_excellent
GOOD -> R.string.quest_smoothness_title_good
INTERMEDIATE -> R.string.quest_smoothness_title_intermediate
BAD -> R.string.quest_smoothness_title_bad
VERY_BAD -> R.string.quest_smoothness_title_very_bad
HORRIBLE -> R.string.quest_smoothness_title_horrible
VERY_HORRIBLE -> R.string.quest_smoothness_title_very_horrible
IMPASSABLE -> R.string.quest_smoothness_title_impassable
}

fun Smoothness.getDescriptionResId(surface: String, highway: String) = when (this) {
EXCELLENT -> when (surface) {
// no "excellent" for roads with paving stones
"paving_stones" -> R.string.quest_smoothness_description_excellent_paving_stones
"asphalt" -> R.string.quest_smoothness_description_excellent
else -> null
}
GOOD -> when (surface) {
"paving_stones" -> R.string.quest_smoothness_description_good_paving_stones
"sett" -> R.string.quest_smoothness_description_good_sett
"asphalt" -> R.string.quest_smoothness_description_good
else -> null
}
INTERMEDIATE -> when (surface) {
"paving_stones" -> R.string.quest_smoothness_description_intermediate_paving_stones
"sett" -> R.string.quest_smoothness_description_intermediate_sett
"compacted", "gravel" -> R.string.quest_smoothness_description_intermediate_compacted_gravel
"asphalt" -> when (highway) {
in ALL_PATHS_EXCEPT_STEPS -> R.string.quest_smoothness_description_intermediate_path
else -> R.string.quest_smoothness_description_intermediate_road
}
else -> null
}
BAD -> when (surface) {
"sett" -> R.string.quest_smoothness_description_bad_sett
"paving_stones" -> R.string.quest_smoothness_description_bad_paving_stones
"asphalt", "compacted", "gravel" -> when (highway) {
in ALL_PATHS_EXCEPT_STEPS -> R.string.quest_smoothness_description_bad_path
else -> R.string.quest_smoothness_description_bad_road
}
else -> null
}
VERY_BAD -> when (surface) {
"sett" -> R.string.quest_smoothness_description_very_bad_sett
else -> when (highway) {
in ALL_PATHS_EXCEPT_STEPS -> R.string.quest_smoothness_description_very_bad_path
else -> R.string.quest_smoothness_description_very_bad_road
}
}
// split up?
HORRIBLE -> R.string.quest_smoothness_description_horrible
VERY_HORRIBLE -> R.string.quest_smoothness_description_very_horrible
IMPASSABLE -> R.string.quest_smoothness_description_impassable
}

// should contain all surfaces in AddRoadSmoothness.SURFACES_FOR_SMOOTHNESS
fun Smoothness.getImageResId(surface: String): Int? = when(surface) {
"asphalt" -> getAsphaltImageResId()
"sett" -> getSettImageResId()
"paving_stones" -> getPavingStonesImageResId()
"compacted" -> getCompactedImageResId()
"gravel" -> getGravelImageResId()
else -> throw IllegalStateException()
}

fun Smoothness.getAsphaltImageResId() = when (this) {
EXCELLENT -> R.drawable.surface_asphalt_excellent
GOOD -> R.drawable.surface_asphalt_good
INTERMEDIATE -> R.drawable.surface_asphalt_intermediate
BAD -> R.drawable.surface_asphalt_bad
VERY_BAD -> R.drawable.surface_asphalt_very_bad
else -> null
}

fun Smoothness.getSettImageResId() = when (this) {
GOOD -> R.drawable.surface_sett_good
INTERMEDIATE -> R.drawable.surface_sett_intermediate
BAD -> R.drawable.surface_sett_bad
VERY_BAD -> R.drawable.surface_sett_very_bad
else -> null
}

fun Smoothness.getPavingStonesImageResId() = when (this) {
EXCELLENT -> R.drawable.surface_paving_stones_excellent
GOOD -> R.drawable.surface_paving_stones_good
INTERMEDIATE -> R.drawable.surface_paving_stones_intermediate
BAD -> R.drawable.surface_paving_stones_bad
else -> null
}

fun Smoothness.getCompactedImageResId() = when (this) {
INTERMEDIATE -> R.drawable.surface_compacted_intermediate
BAD -> R.drawable.surface_compacted_bad
VERY_BAD -> R.drawable.surface_compacted_very_bad
HORRIBLE -> R.drawable.surface_unpaved_horrible
VERY_HORRIBLE -> R.drawable.surface_unpaved_very_horrible
IMPASSABLE -> R.drawable.surface_unpaved_impassable
else -> null
}

fun Smoothness.getGravelImageResId() = when (this) {
INTERMEDIATE -> R.drawable.surface_gravel_intermediate
BAD -> R.drawable.surface_gravel_bad
VERY_BAD -> R.drawable.surface_gravel_very_bad
HORRIBLE -> R.drawable.surface_gravel_horrible
VERY_HORRIBLE -> R.drawable.surface_unpaved_very_horrible
IMPASSABLE -> R.drawable.surface_unpaved_impassable
else -> null
}
Loading

0 comments on commit d40aba1

Please sign in to comment.