chore: implement view binding adapter number picker

This commit is contained in:
Andries Smit 2022-04-11 14:22:12 +02:00
parent 9670e8971a
commit 025147e118
19 changed files with 120 additions and 87 deletions

View file

@ -241,10 +241,10 @@ class ProfileHelperActivity : NoSplashAppCompatActivity() {
}
ToastUtils.showToastInUiThread(this, R.string.invalidinput)
}
binding.age.editText?.id?.let { binding.ageLabel.labelFor = it }
binding.tdd.editText?.id?.let { binding.tddLabel.labelFor = it }
binding.weight.editText?.id?.let { binding.weightLabel.labelFor = it }
binding.basalPctFromTdd.editText?.id?.let { binding.basalPctFromTddLabel.labelFor = it }
binding.ageLabel.labelFor = binding.age.editTextId
binding.tddLabel.labelFor = binding.tdd.editTextId
binding.weightLabel.labelFor = binding.weight.editTextId
binding.basalPctFromTddLabel.labelFor = binding.basalPctFromTdd.editTextId
switchTab(0, typeSelected[0], false)
}

View file

@ -64,7 +64,7 @@ class CalibrationDialog : DialogFragmentWithDate() {
binding.bg.setParams(savedInstanceState?.getDouble("bg")
?: bg, 36.0, 500.0, 1.0, DecimalFormat("0"), false, binding.okcancel.ok)
binding.units.text = if (units == GlucoseUnit.MMOL) rh.gs(R.string.mmol) else rh.gs(R.string.mgdl)
binding.bg.editText?.id?.let { binding.bgLabel.labelFor = it }
binding.bgLabel.labelFor = binding.bg.editTextId
}
override fun onDestroyView() {

View file

@ -199,9 +199,9 @@ class CarbsDialog : DialogFragmentWithDate() {
binding.hypoTt.isChecked = false
binding.activityTt.isChecked = false
}
binding.duration.editText?.id?.let { binding.durationLabel.labelFor = it }
binding.time.editText?.id?.let { binding.timeLabel.labelFor = it }
binding.carbs.editText?.id?.let { binding.carbsLabel.labelFor = it }
binding.durationLabel.labelFor = binding.duration.editTextId
binding.timeLabel.labelFor = binding.time.editTextId
binding.carbsLabel.labelFor = binding.carbs.editTextId
}
override fun onDestroyView() {

View file

@ -165,8 +165,8 @@ class CareDialog : DialogFragmentWithDate() {
?: 0.0, 0.0, Constants.MAX_PROFILE_SWITCH_DURATION, 10.0, DecimalFormat("0"), false, binding.okcancel.ok)
if (options == EventType.NOTE || options == EventType.QUESTION || options == EventType.ANNOUNCEMENT || options == EventType.EXERCISE)
binding.notesLayout.root.visibility = View.VISIBLE // independent to preferences
binding.bg.editText?.id?.let { binding.bgLabel.labelFor = it }
binding.duration.editText?.id?.let { binding.durationLabel.labelFor = it }
binding.bgLabel.labelFor = binding.bg.editTextId
binding.durationLabel.labelFor = binding.duration.editTextId
}
override fun onDestroyView() {

View file

@ -75,8 +75,8 @@ class ExtendedBolusDialog : DialogFragmentWithDate() {
val extendedMaxDuration = pumpDescription.extendedBolusMaxDuration
binding.duration.setParams(savedInstanceState?.getDouble("duration")
?: extendedDurationStep, extendedDurationStep, extendedMaxDuration, extendedDurationStep, DecimalFormat("0"), false, binding.okcancel.ok)
binding.insulin.editText?.id?.let { binding.insulinLabel.labelFor = it }
binding.duration.editText?.id?.let { binding.durationLabel.labelFor = it }
binding.insulinLabel.labelFor = binding.insulin.editTextId
binding.durationLabel.labelFor = binding.duration.editTextId
}
override fun onDestroyView() {

View file

@ -99,7 +99,7 @@ class FillDialog : DialogFragmentWithDate() {
} else {
binding.fillPresetButton3.visibility = View.GONE
}
binding.fillInsulinamount.editText?.id?.let { binding.fillLabel.labelFor = it }
binding.fillLabel.labelFor = binding.fillInsulinamount.editTextId
}
override fun onDestroyView() {

View file

@ -150,8 +150,8 @@ class InsulinDialog : DialogFragmentWithDate() {
binding.recordOnly.setOnCheckedChangeListener { _, isChecked: Boolean ->
binding.timeLayout.visibility = isChecked.toVisibility()
}
binding.amount.editText?.id?.let { binding.insulinLabel.labelFor = it }
binding.time.editText?.id?.let { binding.timeLabel.labelFor = it }
binding.insulinLabel.labelFor = binding.amount.editTextId
binding.timeLabel.labelFor = binding.time.editTextId
}
override fun onDestroyView() {

View file

@ -152,9 +152,9 @@ class ProfileSwitchDialog : DialogFragmentWithDate() {
}
}
binding.ttLayout.visibility = View.GONE
binding.duration.editText?.id?.let { binding.durationLabel.labelFor = it }
binding.percentage.editText?.id?.let { binding.percentageLabel.labelFor = it }
binding.timeshift.editText?.id?.let { binding.timeshiftLabel.labelFor = it }
binding.durationLabel.labelFor = binding.duration.editTextId
binding.percentageLabel.labelFor = binding.percentage.editTextId
binding.timeshiftLabel.labelFor = binding.timeshift.editTextId
}
override fun onDestroyView() {

View file

@ -89,9 +89,9 @@ class TempBasalDialog : DialogFragmentWithDate() {
binding.percentLayout.visibility = View.GONE
binding.absoluteLayout.visibility = View.VISIBLE
}
binding.basalPercentInput.editText?.id?.let { binding.basalPercentLabel.labelFor = it }
binding.basalAbsoluteInput.editText?.id?.let { binding.basalAbsoluteLabel.labelFor = it }
binding.duration.editText?.id?.let { binding.durationLabel.labelFor = it }
binding.basalPercentLabel.labelFor = binding.basalPercentInput.editTextId
binding.basalAbsoluteLabel.labelFor = binding.basalAbsoluteInput.editTextId
binding.durationLabel.labelFor = binding.duration.editTextId
}
override fun onDestroyView() {

View file

@ -123,8 +123,8 @@ class TempTargetDialog : DialogFragmentWithDate() {
longClick(it)
return@setOnLongClickListener true
}
binding.duration.editText?.id?.let { binding.durationLabel.labelFor = it }
binding.temptarget.editText?.id?.let { binding.temptargetLabel.labelFor = it }
binding.durationLabel.labelFor = binding.duration.editTextId
binding.temptargetLabel.labelFor = binding.temptarget.editTextId
}
}

View file

@ -108,8 +108,8 @@ class TreatmentDialog : DialogFragmentWithDate() {
binding.insulin.setParams(savedInstanceState?.getDouble("insulin")
?: 0.0, 0.0, maxInsulin, pumpDescription.bolusStep, DecimalFormatter.pumpSupportedBolusFormat(activePlugin.activePump), false, binding.okcancel.ok, textWatcher)
binding.recordOnlyLayout.visibility = View.GONE
binding.insulin.editText?.id?.let { binding.insulinLabel.labelFor = it }
binding.carbs.editText?.id?.let { binding.carbsLabel.labelFor = it }
binding.insulinLabel.labelFor = binding.insulin.editTextId
binding.carbsLabel.labelFor = binding.carbs.editTextId
}
override fun onDestroyView() {

View file

@ -248,10 +248,10 @@ class WizardDialog : DaggerDialogFragment() {
}
private fun setA11yLabels() {
binding.bgInput.editText?.id?.let { binding.bgInputLabel.labelFor = it }
binding.carbsInput.editText?.id?.let { binding.carbsInputLabel.labelFor = it }
binding.correctionInput.editText?.id?.let { binding.correctionInputLabel.labelFor = it }
binding.carbTimeInput.editText?.id?.let { binding.carbTimeInputLabel.labelFor = it }
binding.bgInputLabel.labelFor = binding.bgInput.editTextId
binding.carbsInputLabel.labelFor = binding.carbsInput.editTextId
binding.correctionInputLabel.labelFor = binding.correctionInput.editTextId
binding.carbTimeInputLabel.labelFor = binding.carbTimeInput.editTextId
}
override fun onDestroyView() {

View file

@ -115,9 +115,7 @@ class LocalProfileFragment : DaggerFragment() {
override fun onTabUnselected(tab: TabLayout.Tab) {}
override fun onTabReselected(tab: TabLayout.Tab) {}
})
binding.dia.editText?.id?.let { binding.diaLabel.labelFor = it }
binding.diaLabel.labelFor = binding.dia.editTextId
binding.unlock.setOnClickListener { queryProtection() }
}

View file

@ -13,18 +13,18 @@ class MinutesNumberPicker constructor(context: Context, attrs: AttributeSet? = n
}
override fun updateEditText() {
if (currentValue == 0.0 && !allowZero) editText?.setText("")
if (currentValue == 0.0 && !allowZero) binding.editText.setText("")
else {
if (focused) editText?.setText(DecimalFormat("0").format(currentValue))
if (focused) binding.editText.setText(DecimalFormat("0").format(currentValue))
else {
val hours = (currentValue / 60).toInt()
val minutes = (currentValue - hours * 60).toInt()
val formatted =
if (hours != 0) String.format(context.getString(R.string.format_hour_minute), hours, minutes)
else DecimalFormat("0").format(currentValue)
editText?.setText(formatted)
binding.editText.setText(formatted)
}
}
}
}
}

View file

@ -19,11 +19,9 @@ import android.view.accessibility.AccessibilityEvent
import android.view.accessibility.AccessibilityManager
import android.view.inputmethod.InputMethodManager
import android.widget.Button
import android.widget.ImageButton
import android.widget.LinearLayout
import com.google.android.material.textfield.TextInputEditText
import com.google.android.material.textfield.TextInputLayout
import info.nightscout.androidaps.core.R
import info.nightscout.androidaps.core.databinding.NumberPickerLayoutBinding
import info.nightscout.androidaps.extensions.toVisibility
import info.nightscout.androidaps.utils.ToastUtils
import info.nightscout.shared.SafeParse
@ -41,10 +39,6 @@ open class NumberPicker(context: Context, attrs: AttributeSet? = null) : LinearL
fun onValueChanged(value: Double)
}
var editText: TextInputEditText? = null
private var minusButton: ImageButton? = null
private var plusButton: ImageButton? = null
var textInputLayout: TextInputLayout? = null
var currentValue = 0.0
var minValue = 0.0
var maxValue = 1.0
@ -57,6 +51,7 @@ open class NumberPicker(context: Context, attrs: AttributeSet? = null) : LinearL
private var mUpdater: ScheduledExecutorService? = null
private var mOnValueChangedListener: OnValueChangedListener? = null
private var mCustomContentDescription: String? = null
protected lateinit var binding: NumberPickerViewAdapter
private var mHandler: Handler = Handler(Looper.getMainLooper(), Handler.Callback { msg: Message ->
when (msg.what) {
@ -93,6 +88,8 @@ open class NumberPicker(context: Context, attrs: AttributeSet? = null) : LinearL
}
}
val editTextId get() = binding.editText.id
var customContentDescription: String?
get() = mCustomContentDescription
set(value) {
@ -101,39 +98,36 @@ open class NumberPicker(context: Context, attrs: AttributeSet? = null) : LinearL
}
protected open fun inflate(context: Context) {
LayoutInflater.from(context).inflate(R.layout.number_picker_layout, this, true)
val inflater = LayoutInflater.from(context)
val bindLayout = NumberPickerLayoutBinding.inflate(inflater, this, true)
binding = NumberPickerViewAdapter.getBinding(bindLayout)
}
protected fun initialize(context: Context) {
// set layout view
inflate(context)
// init ui components
minusButton = findViewById(R.id.decrement)
minusButton?.id = generateViewId()
plusButton = findViewById(R.id.increment)
plusButton?.id = generateViewId()
textInputLayout = findViewById(R.id.textInputLayout)
editText = findViewById(R.id.display)
editText?.id = generateViewId()
minusButton?.setOnTouchListener(this)
minusButton?.setOnKeyListener(this)
minusButton?.setOnClickListener(this)
plusButton?.setOnTouchListener(this)
plusButton?.setOnKeyListener(this)
plusButton?.setOnClickListener(this)
binding.minusButton.id = generateViewId()
binding.plusButton.id = generateViewId()
binding.editText.id = generateViewId()
binding.minusButton.setOnTouchListener(this)
binding.minusButton.setOnKeyListener(this)
binding.minusButton.setOnClickListener(this)
binding.plusButton.setOnTouchListener(this)
binding.plusButton.setOnKeyListener(this)
binding.plusButton.setOnClickListener(this)
setTextWatcher(object : TextWatcher {
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {}
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {}
override fun afterTextChanged(s: Editable) {
if (focused) currentValue = SafeParse.stringToDouble(editText?.text.toString())
if (focused) currentValue = SafeParse.stringToDouble(binding.editText.text.toString())
callValueChangedListener()
val inValid = currentValue > maxValue || currentValue < minValue
okButton?.visibility = inValid.not().toVisibility()
textInputLayout?.error = if (inValid) "invalid" else null
binding.textInputLayout.error = if (inValid) "invalid" else null
}
})
editText?.setOnFocusChangeListener { _: View?, hasFocus: Boolean ->
binding.editText.setOnFocusChangeListener { _: View?, hasFocus: Boolean ->
focused = hasFocus
if (!focused) value // check min/max
updateEditText()
@ -143,8 +137,8 @@ open class NumberPicker(context: Context, attrs: AttributeSet? = null) : LinearL
fun updateA11yDescription() {
val description = if (mCustomContentDescription != null) mCustomContentDescription else ""
minusButton?.contentDescription = context.getString(R.string.a11y_min_button_description, description, formatter?.format(this.step))
plusButton?.contentDescription = context.getString(R.string.a11y_plus_button_description, description, formatter?.format(this.step))
binding.minusButton.contentDescription = context.getString(R.string.a11y_min_button_description, description, formatter?.format(this.step))
binding.plusButton.contentDescription = context.getString(R.string.a11y_plus_button_description, description, formatter?.format(this.step))
}
fun announceValue() {
@ -164,7 +158,7 @@ open class NumberPicker(context: Context, attrs: AttributeSet? = null) : LinearL
}
override fun setTag(tag: Any) {
editText?.tag = tag
binding.editText.tag = tag
}
fun setOnValueChangedListener(onValueChangedListener: OnValueChangedListener?) {
@ -173,10 +167,10 @@ open class NumberPicker(context: Context, attrs: AttributeSet? = null) : LinearL
fun setTextWatcher(textWatcher: TextWatcher) {
watcher = textWatcher
editText?.addTextChangedListener(textWatcher)
editText?.onFocusChangeListener = OnFocusChangeListener { _: View?, hasFocus: Boolean ->
binding.editText.addTextChangedListener(textWatcher)
binding.editText.onFocusChangeListener = OnFocusChangeListener { _: View?, hasFocus: Boolean ->
if (!hasFocus) {
currentValue = SafeParse.stringToDouble(editText?.text.toString())
currentValue = SafeParse.stringToDouble(binding.editText.text.toString())
if (currentValue > maxValue) {
currentValue = maxValue
ToastUtils.showToastInUiThread(context, context.getString(R.string.youareonallowedlimit))
@ -195,11 +189,11 @@ open class NumberPicker(context: Context, attrs: AttributeSet? = null) : LinearL
fun setParams(initValue: Double, minValue: Double, maxValue: Double, step: Double, formatter: NumberFormat?, allowZero: Boolean, okButton: Button?, textWatcher: TextWatcher?) {
if (watcher != null) {
editText?.removeTextChangedListener(watcher)
binding.editText.removeTextChangedListener(watcher)
}
setParams(initValue, minValue, maxValue, step, formatter, allowZero, okButton)
watcher = textWatcher
if (textWatcher != null) editText?.addTextChangedListener(textWatcher)
if (textWatcher != null) binding.editText.addTextChangedListener(textWatcher)
}
fun setParams(initValue: Double, minValue: Double, maxValue: Double, step: Double, formatter: NumberFormat?, allowZero: Boolean, okButton: Button?) {
@ -211,11 +205,11 @@ open class NumberPicker(context: Context, attrs: AttributeSet? = null) : LinearL
this.allowZero = allowZero
callValueChangedListener()
this.okButton = okButton
editText?.keyListener = DigitsKeyListenerWithComma.getInstance(minValue < 0, step != round(step))
if (watcher != null) editText?.removeTextChangedListener(watcher)
binding.editText.keyListener = DigitsKeyListenerWithComma.getInstance(minValue < 0, step != round(step))
if (watcher != null) binding.editText.removeTextChangedListener(watcher)
updateA11yDescription()
updateEditText()
if (watcher != null) editText?.addTextChangedListener(watcher)
if (watcher != null) binding.editText.addTextChangedListener(watcher)
}
var value: Double
@ -231,7 +225,7 @@ open class NumberPicker(context: Context, attrs: AttributeSet? = null) : LinearL
return currentValue
}
set(value) {
if (watcher != null) editText?.removeTextChangedListener(watcher)
if (watcher != null) binding.editText.removeTextChangedListener(watcher)
currentValue = value
if (currentValue > maxValue) {
currentValue = maxValue
@ -243,11 +237,11 @@ open class NumberPicker(context: Context, attrs: AttributeSet? = null) : LinearL
}
callValueChangedListener()
updateEditText()
if (watcher != null) editText?.addTextChangedListener(watcher)
if (watcher != null) binding.editText.addTextChangedListener(watcher)
}
val text: String
get() = editText?.text.toString()
get() = binding.editText.text.toString()
private fun inc(multiplier: Int) {
currentValue += step * multiplier
@ -272,7 +266,7 @@ open class NumberPicker(context: Context, attrs: AttributeSet? = null) : LinearL
}
protected open fun updateEditText() {
if (currentValue == 0.0 && !allowZero) editText?.setText("") else editText?.setText(formatter?.format(currentValue))
if (currentValue == 0.0 && !allowZero) binding.editText.setText("") else binding.editText.setText(formatter?.format(currentValue))
}
private fun callValueChangedListener() {
@ -300,9 +294,9 @@ open class NumberPicker(context: Context, attrs: AttributeSet? = null) : LinearL
override fun onClick(v: View) {
if (mUpdater == null) {
val imm = context.getSystemService(Service.INPUT_METHOD_SERVICE) as InputMethodManager
imm.hideSoftInputFromWindow(editText?.windowToken, 0)
editText?.clearFocus()
if (v === plusButton) {
imm.hideSoftInputFromWindow(binding.editText.windowToken, 0)
binding.editText.clearFocus()
if (v === binding.plusButton) {
inc(1)
} else {
dec(1)
@ -318,7 +312,7 @@ open class NumberPicker(context: Context, attrs: AttributeSet? = null) : LinearL
if (isKeyOfInterest && isReleased) {
stopUpdating()
} else if (isKeyOfInterest && isPressed) {
startUpdating(v === plusButton)
startUpdating(v === binding.plusButton)
}
return false
}
@ -329,7 +323,7 @@ open class NumberPicker(context: Context, attrs: AttributeSet? = null) : LinearL
if (isReleased) {
stopUpdating()
} else if (isPressed) {
startUpdating(v === plusButton)
startUpdating(v === binding.plusButton)
}
return false
}
@ -345,7 +339,8 @@ open class NumberPicker(context: Context, attrs: AttributeSet? = null) : LinearL
context.theme.obtainStyledAttributes(
attrs,
R.styleable.NumberPicker,
0, 0).apply {
0, 0
).apply {
try {
mCustomContentDescription = getString(R.styleable.NumberPicker_customContentDescription)

View file

@ -3,11 +3,13 @@ package info.nightscout.androidaps.utils.ui
import android.content.Context
import android.util.AttributeSet
import android.view.LayoutInflater
import info.nightscout.androidaps.R
import info.nightscout.androidaps.core.databinding.NumberPickerLayoutVerticalBinding
class NumberPickerVertical(context: Context, attrs: AttributeSet? = null) : NumberPicker(context, attrs) {
override fun inflate(context: Context) {
LayoutInflater.from(context).inflate(R.layout.number_picker_layout_vertical, this, true)
val inflater = LayoutInflater.from(context)
val bindLayout = NumberPickerLayoutVerticalBinding.inflate(inflater, this, true)
binding = NumberPickerViewAdapter(null, bindLayout)
}
}
}

View file

@ -0,0 +1,36 @@
package info.nightscout.androidaps.utils.ui
import info.nightscout.androidaps.core.databinding.NumberPickerLayoutBinding
import info.nightscout.androidaps.core.databinding.NumberPickerLayoutVerticalBinding
/**
* NumberPickerViewAdapter binds both NumberPickerLayoutBinding and NumberPickerLayoutVerticalBinding shared attributes to one common view adapter.
* Requires at least one of the ViewBinding as a parameter. Recommended to use the factory object to create the binding.
*/
class NumberPickerViewAdapter(
val nH: NumberPickerLayoutBinding?,
val nV: NumberPickerLayoutVerticalBinding?,
) {
init {
if (nH == null && nV == null) {
throw IllegalArgumentException("Require at least on Binding parameter")
}
}
val editText = nH?.display ?: nV?.display ?: throw IllegalArgumentException("Missing require View Binding parameter display")
val minusButton = nH?.decrement ?: nV?.decrement ?: throw IllegalArgumentException("require at least on Binding parameter decrement")
val plusButton = nH?.increment ?: nV?.increment ?: throw IllegalArgumentException("require at least on Binding parameter increment")
var textInputLayout = nH?.textInputLayout ?: nV?.textInputLayout ?: throw IllegalArgumentException("require at least on Binding parameter textInputLayout")
companion object {
fun getBinding(bindLayout: NumberPickerLayoutBinding): NumberPickerViewAdapter {
return NumberPickerViewAdapter(bindLayout, null)
}
fun getBinding(bindLayout: NumberPickerLayoutVerticalBinding): NumberPickerViewAdapter {
return NumberPickerViewAdapter(null, bindLayout)
}
}
}

View file

@ -3,7 +3,8 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="130dp"
android:layout_height="40dp">
android:layout_height="40dp"
tools:context="info.nightscout.androidaps.utils.ui.NumberPicker">
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/textInputLayout"

View file

@ -3,7 +3,8 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="60dp"
android:layout_height="100dp">
android:layout_height="100dp"
tools:context="info.nightscout.androidaps.utils.ui.NumberPickerVertical">
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/textInputLayout"