mirror of
https://github.com/iSoron/uhabits.git
synced 2025-12-06 09:08:52 -06:00
Merge pull request #1082 from hiqua/improve_number_picker
Make numpad work better in number picker dialog
This commit is contained in:
@@ -19,9 +19,11 @@
|
|||||||
|
|
||||||
package org.isoron.uhabits.activities.common.dialogs
|
package org.isoron.uhabits.activities.common.dialogs
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.DialogInterface
|
import android.content.DialogInterface
|
||||||
import android.text.InputFilter
|
import android.text.InputFilter
|
||||||
|
import android.text.Spanned
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE
|
import android.view.WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE
|
||||||
import android.view.inputmethod.EditorInfo
|
import android.view.inputmethod.EditorInfo
|
||||||
@@ -33,6 +35,7 @@ import org.isoron.uhabits.R
|
|||||||
import org.isoron.uhabits.core.ui.screens.habits.list.ListHabitsBehavior
|
import org.isoron.uhabits.core.ui.screens.habits.list.ListHabitsBehavior
|
||||||
import org.isoron.uhabits.inject.ActivityContext
|
import org.isoron.uhabits.inject.ActivityContext
|
||||||
import org.isoron.uhabits.utils.InterfaceUtils
|
import org.isoron.uhabits.utils.InterfaceUtils
|
||||||
|
import java.text.DecimalFormatSymbols
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import kotlin.math.roundToLong
|
import kotlin.math.roundToLong
|
||||||
|
|
||||||
@@ -40,18 +43,27 @@ class NumberPickerFactory
|
|||||||
@Inject constructor(
|
@Inject constructor(
|
||||||
@ActivityContext private val context: Context
|
@ActivityContext private val context: Context
|
||||||
) {
|
) {
|
||||||
|
|
||||||
fun create(
|
fun create(
|
||||||
value: Double,
|
value: Double,
|
||||||
unit: String,
|
unit: String,
|
||||||
callback: ListHabitsBehavior.NumberPickerCallback
|
callback: ListHabitsBehavior.NumberPickerCallback
|
||||||
): AlertDialog {
|
): AlertDialog {
|
||||||
|
|
||||||
val inflater = LayoutInflater.from(context)
|
val inflater = LayoutInflater.from(context)
|
||||||
val view = inflater.inflate(R.layout.number_picker_dialog, null)
|
val view = inflater.inflate(R.layout.number_picker_dialog, null)
|
||||||
|
|
||||||
val picker = view.findViewById<NumberPicker>(R.id.picker)
|
val picker = view.findViewById<NumberPicker>(R.id.picker)
|
||||||
val picker2 = view.findViewById<NumberPicker>(R.id.picker2)
|
val picker2 = view.findViewById<NumberPicker>(R.id.picker2)
|
||||||
val tvUnit = view.findViewById<TextView>(R.id.tvUnit)
|
|
||||||
|
val watcherFilter: InputFilter = SeparatorWatcherInputFilter(picker2)
|
||||||
|
val numberPickerInputText = getNumberPickerInputText(picker)
|
||||||
|
|
||||||
|
// watch the unfiltered input before the filters remove a possible separator from it
|
||||||
|
numberPickerInputText.filters = arrayOf(watcherFilter).plus(numberPickerInputText.filters)
|
||||||
|
|
||||||
|
view.findViewById<TextView>(R.id.tvUnit).text = unit
|
||||||
|
view.findViewById<TextView>(R.id.tvSeparator).text =
|
||||||
|
DecimalFormatSymbols.getInstance().decimalSeparator.toString()
|
||||||
|
|
||||||
val intValue = (value * 100).roundToLong().toInt()
|
val intValue = (value * 100).roundToLong().toInt()
|
||||||
|
|
||||||
@@ -61,19 +73,16 @@ class NumberPickerFactory
|
|||||||
picker.wrapSelectorWheel = false
|
picker.wrapSelectorWheel = false
|
||||||
|
|
||||||
picker2.minValue = 0
|
picker2.minValue = 0
|
||||||
picker2.maxValue = 19
|
picker2.maxValue = 99
|
||||||
picker2.setFormatter { v -> String.format("%02d", 5 * v) }
|
picker2.setFormatter { v -> String.format("%02d", v) }
|
||||||
picker2.value = intValue % 100 / 5
|
picker2.value = intValue % 100
|
||||||
refreshInitialValue(picker2)
|
|
||||||
|
|
||||||
tvUnit.text = unit
|
|
||||||
|
|
||||||
val dialog = AlertDialog.Builder(context)
|
val dialog = AlertDialog.Builder(context)
|
||||||
.setView(view)
|
.setView(view)
|
||||||
.setTitle(R.string.change_value)
|
.setTitle(R.string.change_value)
|
||||||
.setPositiveButton(android.R.string.ok) { _, _ ->
|
.setPositiveButton(android.R.string.ok) { _, _ ->
|
||||||
picker.clearFocus()
|
picker.clearFocus()
|
||||||
val v = picker.value + 0.05 * picker2.value
|
val v = picker.value + 0.01 * picker2.value
|
||||||
callback.onNumberPicked(v)
|
callback.onNumberPicked(v)
|
||||||
}
|
}
|
||||||
.setOnDismissListener {
|
.setOnDismissListener {
|
||||||
@@ -89,20 +98,50 @@ class NumberPickerFactory
|
|||||||
InterfaceUtils.setupEditorAction(
|
InterfaceUtils.setupEditorAction(
|
||||||
picker
|
picker
|
||||||
) { _, actionId, _ ->
|
) { _, actionId, _ ->
|
||||||
if (actionId == EditorInfo.IME_ACTION_DONE)
|
if (actionId == EditorInfo.IME_ACTION_DONE) {
|
||||||
dialog.getButton(DialogInterface.BUTTON_POSITIVE).performClick()
|
dialog.getButton(DialogInterface.BUTTON_POSITIVE).performClick()
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
InterfaceUtils.setupEditorAction(
|
||||||
|
picker2
|
||||||
|
) { _, actionId, _ ->
|
||||||
|
if (actionId == EditorInfo.IME_ACTION_DONE) {
|
||||||
|
dialog.getButton(DialogInterface.BUTTON_POSITIVE).performClick()
|
||||||
|
}
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
return dialog
|
return dialog
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun refreshInitialValue(picker: NumberPicker) {
|
@SuppressLint("DiscouragedPrivateApi")
|
||||||
// Workaround for Android bug:
|
private fun getNumberPickerInputText(picker: NumberPicker): EditText {
|
||||||
// https://code.google.com/p/android/issues/detail?id=35482
|
|
||||||
val f = NumberPicker::class.java.getDeclaredField("mInputText")
|
val f = NumberPicker::class.java.getDeclaredField("mInputText")
|
||||||
f.isAccessible = true
|
f.isAccessible = true
|
||||||
val inputText = f.get(picker) as EditText
|
return f.get(picker) as EditText
|
||||||
inputText.filters = arrayOfNulls<InputFilter>(0)
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class SeparatorWatcherInputFilter(private val nextPicker: NumberPicker) : InputFilter {
|
||||||
|
override fun filter(
|
||||||
|
source: CharSequence?,
|
||||||
|
start: Int,
|
||||||
|
end: Int,
|
||||||
|
dest: Spanned?,
|
||||||
|
dstart: Int,
|
||||||
|
dend: Int
|
||||||
|
): CharSequence {
|
||||||
|
if (source == null || source.isEmpty()) {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
for (c in source) {
|
||||||
|
if (c == DecimalFormatSymbols.getInstance().decimalSeparator || c == '.' || c == ',') {
|
||||||
|
nextPicker.performLongClick()
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return source
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,14 +34,13 @@
|
|||||||
android:id="@+id/tvSeparator"
|
android:id="@+id/tvSeparator"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="."/>
|
/>
|
||||||
|
|
||||||
<NumberPicker
|
<NumberPicker
|
||||||
android:id="@+id/picker2"
|
android:id="@+id/picker2"
|
||||||
android:layout_gravity="center"
|
android:layout_gravity="center"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:descendantFocusability="blocksDescendants"
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
|
|||||||
Reference in New Issue
Block a user