Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Suggest last answers in fire hydrant diameter quest #4369

Merged
merged 10 commits into from
Nov 1, 2022
Original file line number Diff line number Diff line change
@@ -1,16 +1,25 @@
package de.westnordost.streetcomplete.quests.fire_hydrant_diameter

import android.content.Context
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.EditText
import androidx.appcompat.app.AlertDialog
import androidx.core.widget.doAfterTextChanged
import androidx.preference.PreferenceManager
import androidx.recyclerview.widget.RecyclerView
import de.westnordost.streetcomplete.R
import de.westnordost.streetcomplete.databinding.QuestFireHydrantDiameterBinding
import de.westnordost.streetcomplete.databinding.QuestFireHydrantDiameterLastPickedButtonBinding
import de.westnordost.streetcomplete.quests.AbstractOsmQuestForm
import de.westnordost.streetcomplete.quests.AnswerItem
import de.westnordost.streetcomplete.quests.fire_hydrant_diameter.FireHydrantDiameterMeasurementUnit.INCH
import de.westnordost.streetcomplete.quests.fire_hydrant_diameter.FireHydrantDiameterMeasurementUnit.MILLIMETER
import de.westnordost.streetcomplete.util.LastPickedValuesStore
import de.westnordost.streetcomplete.util.ktx.intOrNull
import de.westnordost.streetcomplete.util.mostCommonWithin

class AddFireHydrantDiameterForm : AbstractOsmQuestForm<FireHydrantDiameterAnswer>() {

Expand All @@ -20,12 +29,43 @@ class AddFireHydrantDiameterForm : AbstractOsmQuestForm<FireHydrantDiameterAnswe

override val contentLayoutResId = R.layout.quest_fire_hydrant_diameter
private val binding by contentViewBinding(QuestFireHydrantDiameterBinding::bind)
private val diameterInput by lazy { binding.root.findViewById<EditText>(R.id.diameterInput) }

private val diameterValue get() = binding.diameterInput.intOrNull ?: 0
private val diameterValue get() = diameterInput.intOrNull ?: 0

private val lastPickedAnswers by lazy {
favs.get()
.mostCommonWithin(target = 5, historyCount = 15, first = 1)
.sorted()
.toList()
}

private lateinit var favs: LastPickedValuesStore<Int>

override fun onAttach(ctx: Context) {
super.onAttach(ctx)
favs = LastPickedValuesStore(
PreferenceManager.getDefaultSharedPreferences(ctx.applicationContext),
key = javaClass.simpleName,
serialize = { it.toString() },
deserialize = { it.toInt() }
)
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding.diameterInput.doAfterTextChanged { checkIsFormComplete() }
layoutInflater.inflate(
getHydrantDiameterSignLayoutResId(countryInfo.countryCode),
view.findViewById(R.id.countrySign),
)

diameterInput.doAfterTextChanged { checkIsFormComplete() }

binding.lastPickedButtons.adapter = LastPickedAdapter(lastPickedAnswers, ::onLastPickedButtonClicked)
}

private fun onLastPickedButtonClicked(position: Int) {
diameterInput.setText(lastPickedAnswers[position].toString())
}

override fun isFormComplete() = diameterValue > 0
Expand All @@ -38,8 +78,12 @@ class AddFireHydrantDiameterForm : AbstractOsmQuestForm<FireHydrantDiameterAnswe
}

if (isUnusualDiameter(diameter)) {
confirmUnusualInput(diameter.unit) { applyAnswer(diameter) }
confirmUnusualInput(diameter.unit) {
favs.add(diameterValue)
applyAnswer(diameter)
}
} else {
favs.add(diameterValue)
applyAnswer(diameter)
}
}
Expand Down Expand Up @@ -80,3 +124,44 @@ class AddFireHydrantDiameterForm : AbstractOsmQuestForm<FireHydrantDiameterAnswe
}
}
}

private fun getHydrantDiameterSignLayoutResId(countryCode: String): Int = when (countryCode) {
"DE" -> R.layout.quest_fire_hydrant_diameter_sign_de
"FI" -> R.layout.quest_fire_hydrant_diameter_sign_fi
"NL" -> R.layout.quest_fire_hydrant_diameter_sign_nl
"PL" -> R.layout.quest_fire_hydrant_diameter_sign_pl
"UK" -> R.layout.quest_fire_hydrant_diameter_sign_uk
FloEdelmann marked this conversation as resolved.
Show resolved Hide resolved
else -> R.layout.quest_fire_hydrant_diameter_sign_generic
}

private class LastPickedAdapter(
private val lastPickedAnswers: List<Int>,
private val onItemClicked: (position: Int) -> Unit
) : RecyclerView.Adapter<LastPickedAdapter.ViewHolder>() {

class ViewHolder(
private val binding: QuestFireHydrantDiameterLastPickedButtonBinding,
private val onItemClicked: (position: Int) -> Unit
) : RecyclerView.ViewHolder(binding.root) {

init {
itemView.setOnClickListener { onItemClicked(bindingAdapterPosition) }
}

fun onBind(item: Int) {
binding.lastDiameterLabel.text = item.toString()
}
}

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val inflater = LayoutInflater.from(parent.context)
val binding = QuestFireHydrantDiameterLastPickedButtonBinding.inflate(inflater, parent, false)
return ViewHolder(binding, onItemClicked)
}

override fun onBindViewHolder(viewHolder: ViewHolder, position: Int) {
viewHolder.onBind(lastPickedAnswers[position])
}

override fun getItemCount() = lastPickedAnswers.size
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,12 @@ class LastPickedValuesStore<T : Any>(
private fun getKey() = Prefs.LAST_PICKED_PREFIX + key
}

/* Returns the `target` most-common non-null items in the first `historyCount`
/**
* Returns the [target] most-common non-null items in the first [historyCount]
* items of the sequence, in their original order.
* If there are fewer than `target` unique items, continues counting items
* If there are fewer than [target] unique items, continues counting items
* until that many are found, or the end of the sequence is reached.
* If the `first` most recent items are not null, they are always included,
* If the [first] most recent items are not null, they are always included,
* displacing the least-common of the other items if necessary.
*/
fun <T : Any> Sequence<T?>.mostCommonWithin(target: Int, historyCount: Int, first: Int): Sequence<T> {
Expand Down
37 changes: 0 additions & 37 deletions app/src/main/res/layout-mcc206/quest_fire_hydrant_diameter.xml

This file was deleted.

39 changes: 0 additions & 39 deletions app/src/main/res/layout-mcc272/quest_fire_hydrant_diameter.xml

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@
style="@style/Widget.AppCompat.Button.Small"
android:layout_width="wrap_content"
android:layout_height="51dp"
android:layout_alignBottom="@id/buildingImage"
android:layout_alignParentRight="true"
tools:ignore="RtlHardcoded">

<ImageView
Expand Down
33 changes: 14 additions & 19 deletions app/src/main/res/layout/quest_fire_hydrant_diameter.xml
Original file line number Diff line number Diff line change
@@ -1,30 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center">
android:orientation="vertical">

<EditText
android:id="@+id/diameterInput"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="monospace"
android:gravity="center_horizontal"
android:inputType="number"
android:maxLength="4"
android:ems="4"
android:textSize="@dimen/x_large_input"
tools:text="1600" />
<FrameLayout
android:id="@+id/countrySign"
android:layout_width="match_parent"
android:layout_height="wrap_content" />

<TextView
android:id="@+id/diameterInputUnit"
android:layout_width="wrap_content"
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/lastPickedButtons"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="mm"
android:textSize="@dimen/x_large_input"
tools:ignore="HardcodedText" />
android:orientation="horizontal"
android:padding="4dp"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
tools:itemCount="6"
tools:listitem="@layout/quest_fire_hydrant_diameter_last_picked_button" />

</LinearLayout>
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
style="@style/Widget.AppCompat.Button.Small"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Independently of the rest, I wonder if there is a reason why we do not use material design theme here? In particular, I guess the material-style to choose here would be the "outlined button"

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess there is no reason, I just used the default style that the android layout designer suggested.

android:layout_width="wrap_content"
android:layout_height="51dp"
tools:ignore="RtlHardcoded">

<TextView
android:id="@+id/last_diameter_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="16sp"
tools:text="150" />

</LinearLayout>
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="horizontal">

<EditText
android:id="@+id/diameterInput"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="monospace"
android:gravity="center_horizontal"
android:inputType="number"
android:maxLength="4"
android:ems="4"
android:textSize="@dimen/x_large_input"
tools:text="1600" />

<TextView
android:id="@+id/diameterInputUnit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="mm"
android:textSize="@dimen/x_large_input"
tools:ignore="HardcodedText" />

</LinearLayout>