Merge pull request #1253 from Andries-Smit/a11y/treatment-dialog

Improve a11y wizard dialog
This commit is contained in:
Milos Kozak 2022-02-11 08:41:28 +01:00 committed by GitHub
commit 6499fe053f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 292 additions and 201 deletions

View file

@ -4,11 +4,7 @@ import android.content.Context
import android.os.Bundle import android.os.Bundle
import android.text.Editable import android.text.Editable
import android.text.TextWatcher import android.text.TextWatcher
import android.view.LayoutInflater import android.view.*
import android.view.View
import android.view.ViewGroup
import android.view.Window
import android.view.WindowManager
import android.widget.AdapterView import android.widget.AdapterView
import android.widget.AdapterView.OnItemSelectedListener import android.widget.AdapterView.OnItemSelectedListener
import android.widget.ArrayAdapter import android.widget.ArrayAdapter
@ -136,33 +132,36 @@ class WizardDialog : DaggerDialogFragment() {
val maxCorrection = constraintChecker.getMaxBolusAllowed().value() val maxCorrection = constraintChecker.getMaxBolusAllowed().value()
bolusStep = activePlugin.activePump.pumpDescription.bolusStep bolusStep = activePlugin.activePump.pumpDescription.bolusStep
if (profileFunction.getUnits() == GlucoseUnit.MGDL) if (profileFunction.getUnits() == GlucoseUnit.MGDL) {
binding.bgInput.setParams(savedInstanceState?.getDouble("bg_input") binding.bgInput.setParams(
?: 0.0, 0.0, 500.0, 1.0, DecimalFormat("0"), false, binding.ok, timeTextWatcher) savedInstanceState?.getDouble("bg_input")
else ?: 0.0, 0.0, 500.0, 1.0, DecimalFormat("0"), false, binding.okcancel.ok, timeTextWatcher)
binding.bgInput.setParams(savedInstanceState?.getDouble("bg_input") } else {
?: 0.0, 0.0, 30.0, 0.1, DecimalFormat("0.0"), false, binding.ok, textWatcher) binding.bgInput.setParams(
savedInstanceState?.getDouble("bg_input")
?: 0.0, 0.0, 30.0, 0.1, DecimalFormat("0.0"), false, binding.okcancel.ok, textWatcher)
}
binding.carbsInput.setParams(savedInstanceState?.getDouble("carbs_input") binding.carbsInput.setParams(savedInstanceState?.getDouble("carbs_input")
?: 0.0, 0.0, maxCarbs.toDouble(), 1.0, DecimalFormat("0"), false, binding.ok, textWatcher) ?: 0.0, 0.0, maxCarbs.toDouble(), 1.0, DecimalFormat("0"), false, binding.okcancel.ok, textWatcher)
if (correctionPercent) { if (correctionPercent) {
calculatedPercentage = sp.getInt(R.string.key_boluswizard_percentage, 100).toDouble() calculatedPercentage = sp.getInt(R.string.key_boluswizard_percentage, 100).toDouble()
binding.correctionInput.setParams(calculatedPercentage, 10.0, 200.0, 1.0, DecimalFormat("0"), false, binding.ok, textWatcher) binding.correctionInput.setParams(calculatedPercentage, 10.0, 200.0, 1.0, DecimalFormat("0"), false, binding.okcancel.ok, textWatcher)
binding.correctionInput.value = calculatedPercentage binding.correctionInput.value = calculatedPercentage
binding.correctionUnit.text = "%" binding.correctionUnit.text = "%"
} else { } else {
binding.correctionInput.setParams( binding.correctionInput.setParams(
savedInstanceState?.getDouble("correction_input") savedInstanceState?.getDouble("correction_input")
?: 0.0, -maxCorrection, maxCorrection, bolusStep, DecimalFormatter.pumpSupportedBolusFormat(activePlugin.activePump), false, binding.ok, textWatcher) ?: 0.0, -maxCorrection, maxCorrection, bolusStep, DecimalFormatter.pumpSupportedBolusFormat(activePlugin.activePump), false, binding.okcancel.ok, textWatcher)
binding.correctionUnit.text = rh.gs(R.string.insulin_unit_shortname) binding.correctionUnit.text = rh.gs(R.string.insulin_unit_shortname)
} }
binding.carbTimeInput.setParams(savedInstanceState?.getDouble("carb_time_input") binding.carbTimeInput.setParams(savedInstanceState?.getDouble("carb_time_input")
?: 0.0, -60.0, 60.0, 5.0, DecimalFormat("0"), false, binding.ok, timeTextWatcher) ?: 0.0, -60.0, 60.0, 5.0, DecimalFormat("0"), false, binding.okcancel.ok, timeTextWatcher)
initDialog() initDialog()
calculatedPercentage = sp.getInt(R.string.key_boluswizard_percentage, 100).toDouble() calculatedPercentage = sp.getInt(R.string.key_boluswizard_percentage, 100).toDouble()
binding.percentUsed.text = rh.gs(R.string.format_percent, sp.getInt(R.string.key_boluswizard_percentage, 100)) binding.percentUsed.text = rh.gs(R.string.format_percent, sp.getInt(R.string.key_boluswizard_percentage, 100))
// ok button // ok button
binding.ok.setOnClickListener { binding.okcancel.ok.setOnClickListener {
if (okClicked) { if (okClicked) {
aapsLogger.debug(LTag.UI, "guarding: ok already clicked") aapsLogger.debug(LTag.UI, "guarding: ok already clicked")
} else { } else {
@ -175,12 +174,12 @@ class WizardDialog : DaggerDialogFragment() {
} }
dismiss() dismiss()
} }
binding.bgEnabledIcon.setOnClickListener { binding.bgCheckbox.isChecked = !binding.bgCheckbox.isChecked } binding.bgCheckboxIcon.setOnClickListener { binding.bgCheckbox.isChecked = !binding.bgCheckbox.isChecked }
binding.trendEnabledIcon.setOnClickListener { binding.bgTrendCheckbox.isChecked = !binding.bgTrendCheckbox.isChecked } binding.trendCheckboxIcon.setOnClickListener { binding.bgTrendCheckbox.isChecked = !binding.bgTrendCheckbox.isChecked }
binding.cobEnabledIcon.setOnClickListener { binding.cobCheckbox.isChecked = !binding.cobCheckbox.isChecked; processCobCheckBox(); } binding.cobCheckboxIcon.setOnClickListener { binding.cobCheckbox.isChecked = !binding.cobCheckbox.isChecked; processCobCheckBox(); }
binding.iobEnabledIcon.setOnClickListener { if (!binding.cobCheckbox.isChecked) binding.iobCheckbox.isChecked = !binding.iobCheckbox.isChecked } binding.iobCheckboxIcon.setOnClickListener { if (!binding.cobCheckbox.isChecked) binding.iobCheckbox.isChecked = !binding.iobCheckbox.isChecked }
// cancel button // cancel button
binding.cancel.setOnClickListener { binding.okcancel.cancel.setOnClickListener {
aapsLogger.debug(LTag.APS, "Dialog canceled: ${this.javaClass.name}") aapsLogger.debug(LTag.APS, "Dialog canceled: ${this.javaClass.name}")
dismiss() dismiss()
} }
@ -212,11 +211,17 @@ class WizardDialog : DaggerDialogFragment() {
sp.putBoolean(rh.gs(R.string.key_wizard_correction_percent), isChecked) sp.putBoolean(rh.gs(R.string.key_wizard_correction_percent), isChecked)
binding.correctionUnit.text = if (isChecked) "%" else rh.gs(R.string.insulin_unit_shortname) binding.correctionUnit.text = if (isChecked) "%" else rh.gs(R.string.insulin_unit_shortname)
correctionPercent = binding.correctionPercent.isChecked correctionPercent = binding.correctionPercent.isChecked
if (correctionPercent) if (correctionPercent) {
binding.correctionInput.setParams(calculatedPercentage, 10.0, 200.0, 1.0, DecimalFormat("0"), false, binding.ok, textWatcher) binding.correctionInput.setParams(calculatedPercentage, 10.0, 200.0, 1.0, DecimalFormat("0"), false, binding.okcancel.ok, textWatcher)
else binding.correctionInput.customContentDescription = rh.gs(R.string.a11_correction_percentage)
binding.correctionInput.setParams(savedInstanceState?.getDouble("correction_input") } else {
?: 0.0, -maxCorrection, maxCorrection, bolusStep, DecimalFormatter.pumpSupportedBolusFormat(activePlugin.activePump), false, binding.ok, textWatcher) binding.correctionInput.setParams(
savedInstanceState?.getDouble("correction_input")
?: 0.0, -maxCorrection, maxCorrection, bolusStep, DecimalFormatter.pumpSupportedBolusFormat(activePlugin.activePump), false, binding.okcancel.ok, textWatcher
)
binding.correctionInput.customContentDescription = rh.gs(R.string.a11_correction_units)
}
binding.correctionInput.updateA11yDescription()
binding.correctionInput.value = if (correctionPercent) calculatedPercentage else Round.roundTo(calculatedCorrection, bolusStep) binding.correctionInput.value = if (correctionPercent) calculatedPercentage else Round.roundTo(calculatedCorrection, bolusStep)
} }
} }
@ -224,12 +229,12 @@ class WizardDialog : DaggerDialogFragment() {
binding.profile.onItemSelectedListener = object : OnItemSelectedListener { binding.profile.onItemSelectedListener = object : OnItemSelectedListener {
override fun onNothingSelected(parent: AdapterView<*>?) { override fun onNothingSelected(parent: AdapterView<*>?) {
ToastUtils.showToastInUiThread(ctx, rh.gs(R.string.noprofileset)) ToastUtils.showToastInUiThread(ctx, rh.gs(R.string.noprofileset))
binding.ok.visibility = View.GONE binding.okcancel.ok.visibility = View.GONE
} }
override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) { override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
calculateInsulin() calculateInsulin()
binding.ok.visibility = View.VISIBLE binding.okcancel.ok.visibility = View.VISIBLE
} }
} }
// bus // bus
@ -241,6 +246,14 @@ class WizardDialog : DaggerDialogFragment() {
}, fabricPrivacy::logException) }, fabricPrivacy::logException)
) )
setA11yLabels()
}
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 }
} }
override fun onDestroyView() { override fun onDestroyView() {
@ -268,14 +281,14 @@ class WizardDialog : DaggerDialogFragment() {
} }
private fun processEnabledIcons() { private fun processEnabledIcons() {
binding.bgEnabledIcon.alpha = if (binding.bgCheckbox.isChecked) 1.0f else 0.2f binding.bgCheckboxIcon.alpha = if (binding.bgCheckbox.isChecked) 1.0f else 0.2f
binding.trendEnabledIcon.alpha = if (binding.bgTrendCheckbox.isChecked) 1.0f else 0.2f binding.trendCheckboxIcon.alpha = if (binding.bgTrendCheckbox.isChecked) 1.0f else 0.2f
binding.iobEnabledIcon.alpha = if (binding.iobCheckbox.isChecked) 1.0f else 0.2f binding.iobCheckboxIcon.alpha = if (binding.iobCheckbox.isChecked) 1.0f else 0.2f
binding.cobEnabledIcon.alpha = if (binding.cobCheckbox.isChecked) 1.0f else 0.2f binding.cobCheckboxIcon.alpha = if (binding.cobCheckbox.isChecked) 1.0f else 0.2f
binding.bgEnabledIcon.visibility = binding.calculationCheckbox.isChecked.not().toVisibility() binding.bgCheckboxIcon.visibility = binding.calculationCheckbox.isChecked.not().toVisibility()
binding.trendEnabledIcon.visibility = binding.calculationCheckbox.isChecked.not().toVisibility() binding.trendCheckboxIcon.visibility = binding.calculationCheckbox.isChecked.not().toVisibility()
binding.iobEnabledIcon.visibility = binding.calculationCheckbox.isChecked.not().toVisibility() binding.iobCheckboxIcon.visibility = binding.calculationCheckbox.isChecked.not().toVisibility()
binding.cobEnabledIcon.visibility = binding.calculationCheckbox.isChecked.not().toVisibility() binding.cobCheckboxIcon.visibility = binding.calculationCheckbox.isChecked.not().toVisibility()
} }
private fun saveCheckedStates() { private fun saveCheckedStates() {
@ -442,10 +455,10 @@ class WizardDialog : DaggerDialogFragment() {
val insulinText = if (wizard.calculatedTotalInsulin > 0.0) rh.gs(R.string.formatinsulinunits, wizard.calculatedTotalInsulin).formatColor(rh, R.color.bolus) else "" val insulinText = if (wizard.calculatedTotalInsulin > 0.0) rh.gs(R.string.formatinsulinunits, wizard.calculatedTotalInsulin).formatColor(rh, R.color.bolus) else ""
val carbsText = if (carbsAfterConstraint > 0.0) rh.gs(R.string.format_carbs, carbsAfterConstraint).formatColor(rh, R.color.carbs) else "" val carbsText = if (carbsAfterConstraint > 0.0) rh.gs(R.string.format_carbs, carbsAfterConstraint).formatColor(rh, R.color.carbs) else ""
binding.total.text = HtmlHelper.fromHtml(rh.gs(R.string.result_insulin_carbs, insulinText, carbsText)) binding.total.text = HtmlHelper.fromHtml(rh.gs(R.string.result_insulin_carbs, insulinText, carbsText))
binding.ok.visibility = View.VISIBLE binding.okcancel.ok.visibility = View.VISIBLE
} else { } else {
binding.total.text = HtmlHelper.fromHtml(rh.gs(R.string.missing_carbs, wizard.carbsEquivalent.toInt()).formatColor(rh, R.color.carbs)) binding.total.text = HtmlHelper.fromHtml(rh.gs(R.string.missing_carbs, wizard.carbsEquivalent.toInt()).formatColor(rh, R.color.carbs))
binding.ok.visibility = View.INVISIBLE binding.okcancel.ok.visibility = View.INVISIBLE
} }
binding.percentUsed.text = rh.gs(R.string.format_percent, wizard.percentageCorrection) binding.percentUsed.text = rh.gs(R.string.format_percent, wizard.percentageCorrection)
calculatedPercentage = wizard.calculatedPercentage calculatedPercentage = wizard.calculatedPercentage

View file

@ -347,6 +347,8 @@ class BolusWizard @Inject constructor(
) )
else else
commonProcessing(ctx) commonProcessing(ctx)
} else {
OKDialog.show(ctx, rh.gs(R.string.boluswizard), rh.gs(R.string.no_action_selected))
} }
} }

View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:width="26dp"
android:height="26dp"
android:drawable="@drawable/ic_xdrip" />
</layer-list>

View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:width="26dp"
android:height="26dp"
android:drawable="@drawable/ic_cp_bolus_carbs" />
</layer-list>

View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:width="26dp"
android:height="26dp"
android:drawable="@drawable/ic_bolus" />
</layer-list>

View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:width="26dp"
android:height="26dp"
android:drawable="@drawable/ic_fortyfiveup" />
</layer-list>

View file

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:drawable="@drawable/cb_backgroud_bg" />
</selector>

View file

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:drawable="@drawable/cb_backgroud_cob" />
</selector>

View file

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:drawable="@drawable/cb_backgroud_iob" />
</selector>

View file

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:drawable="@drawable/cb_backgroud_trend" />
</selector>

View file

@ -59,6 +59,7 @@
android:layout_height="match_parent"> android:layout_height="match_parent">
<TextView <TextView
android:id="@+id/bg_input_label"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_weight="1" android:layout_weight="1"
@ -70,7 +71,8 @@
<info.nightscout.androidaps.utils.ui.NumberPicker <info.nightscout.androidaps.utils.ui.NumberPicker
android:id="@+id/bg_input" android:id="@+id/bg_input"
android:layout_width="130dp" android:layout_width="130dp"
android:layout_height="40dp" /> android:layout_height="40dp"
app:customContentDescription="@string/a11y_current_bg" />
<TextView <TextView
android:id="@+id/bg_units" android:id="@+id/bg_units"
@ -89,9 +91,11 @@
android:layout_height="match_parent"> android:layout_height="match_parent">
<TextView <TextView
android:id="@+id/carbs_input_label"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_weight="1" android:layout_weight="1"
android:labelFor="@id/carbs_input"
android:padding="10dp" android:padding="10dp"
android:text="@string/treatments_wizard_carbs_label" android:text="@string/treatments_wizard_carbs_label"
android:textAppearance="@style/TextAppearance.AppCompat.Small" android:textAppearance="@style/TextAppearance.AppCompat.Small"
@ -101,8 +105,8 @@
android:id="@+id/carbs_input" android:id="@+id/carbs_input"
android:layout_width="130dp" android:layout_width="130dp"
android:layout_height="40dp" android:layout_height="40dp"
android:layout_gravity="center_horizontal" /> android:layout_gravity="center_horizontal"
app:customContentDescription="@string/treatments_wizard_carbs_label" />
<TextView <TextView
android:layout_width="wrap_content" android:layout_width="wrap_content"
@ -127,6 +131,7 @@
android:orientation="horizontal"> android:orientation="horizontal">
<TextView <TextView
android:id="@+id/correction_input_label"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_weight="1" android:layout_weight="1"
@ -135,32 +140,26 @@
android:textAppearance="@style/TextAppearance.AppCompat.Small" android:textAppearance="@style/TextAppearance.AppCompat.Small"
android:textStyle="bold" /> android:textStyle="bold" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text=" %"
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
android:textStyle="bold"
tools:ignore="HardcodedText" />
<CheckBox <CheckBox
android:id="@+id/correction_percent" android:id="@+id/correction_percent"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="center_vertical" android:layout_gravity="center_vertical"
android:checked="false" android:checked="false"
android:padding="2dp" /> android:layoutDirection="rtl"
android:padding="2dp"
android:text="%"
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
android:textStyle="bold" />
</LinearLayout> </LinearLayout>
<info.nightscout.androidaps.utils.ui.NumberPicker <info.nightscout.androidaps.utils.ui.NumberPicker
android:id="@+id/correction_input" android:id="@+id/correction_input"
android:layout_width="130dp" android:layout_width="130dp"
android:layout_height="40dp" android:layout_height="40dp"
android:layout_gravity="center_horizontal" /> android:layout_gravity="center_horizontal"
app:customContentDescription="@string/a11_correction_units" />
<TextView <TextView
android:id="@+id/correction_unit" android:id="@+id/correction_unit"
@ -255,77 +254,48 @@
<CheckBox <CheckBox
android:id="@+id/calculation_checkbox" android:id="@+id/calculation_checkbox"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="fill_parent"
android:layout_gravity="center_vertical"
android:checked="false" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical" android:layout_gravity="center_vertical"
android:checked="false"
android:contentDescription="@string/show_calculation" android:contentDescription="@string/show_calculation"
app:srcCompat="@drawable/ic_visibility" /> android:drawableEnd="@drawable/ic_visibility" />
<ImageView <CheckBox
android:id="@+id/bg_enabled_icon" android:id="@+id/bg_checkbox_icon"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="fill_parent"
android:layout_gravity="center_vertical" android:button="@drawable/checkbox_bg_icon"
android:paddingStart="-11dp" android:checked="true"
android:paddingEnd="-11dp" android:contentDescription="@string/treatments_wizard_bg_label" />
android:scaleX="0.5"
android:scaleY="0.5"
app:srcCompat="@drawable/ic_xdrip"/>
<ImageView <CheckBox
android:id="@+id/trend_enabled_icon" android:id="@+id/trend_checkbox_icon"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="fill_parent"
android:layout_gravity="center_vertical" android:button="@drawable/checkbox_trend_icon"
android:paddingStart="-11dp" android:checked="true"
android:paddingEnd="-11dp" android:contentDescription="@string/bg_trend_label" />
android:scaleX="0.5"
android:scaleY="0.5"
app:srcCompat="@drawable/ic_fortyfiveup" />
<ImageView <CheckBox
android:id="@+id/iob_enabled_icon" android:id="@+id/iob_checkbox_icon"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="fill_parent"
android:layout_gravity="center_vertical" android:button="@drawable/checkbox_iob_icon"
android:paddingStart="-11dp" android:checked="true"
android:paddingEnd="-11dp" android:contentDescription="@string/iob" />
android:scaleX="0.5"
android:scaleY="0.5"
app:srcCompat="@drawable/ic_bolus" />
<ImageView <CheckBox
android:id="@+id/cob_enabled_icon" android:id="@+id/cob_checkbox_icon"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="fill_parent"
android:layout_gravity="center_vertical" android:button="@drawable/checkbox_cob_icon"
android:paddingStart="-11dp" android:checked="true"
android:paddingEnd="-11dp" android:contentDescription="@string/treatments_wizard_cob_label" />
android:scaleX="0.5"
android:scaleY="0.5"
app:srcCompat="@drawable/ic_cp_bolus_carbs" />
<Button <include
android:id="@+id/cancel" android:id="@+id/okcancel"
style="@style/mdtp_ActionButton.Text" layout="@layout/okcancel" />
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/mdtp_cancel"
android:textAlignment="textEnd" />
<Button
android:id="@+id/ok"
style="@style/mdtp_ActionButton.Text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:text="@string/mdtp_ok" />
</LinearLayout> </LinearLayout>
<View <View
@ -350,6 +320,7 @@
android:orientation="horizontal"> android:orientation="horizontal">
<TextView <TextView
android:id="@+id/carb_time_input_label"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_weight="1" android:layout_weight="1"
@ -360,27 +331,23 @@
android:textAppearance="@style/TextAppearance.AppCompat.Small" android:textAppearance="@style/TextAppearance.AppCompat.Small"
android:textStyle="bold" /> android:textStyle="bold" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:contentDescription="@string/alarm"
android:src="@drawable/ic_access_alarm_24dp" />
<CheckBox <CheckBox
android:id="@+id/alarm" android:id="@+id/alarm"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="center_vertical" android:layout_gravity="center_vertical"
android:checked="false" android:checked="false"
android:contentDescription="set carb timer alarm"
android:drawableEnd="@drawable/ic_access_alarm_24dp"
android:layoutDirection="rtl"
android:padding="2dp" /> android:padding="2dp" />
<info.nightscout.androidaps.utils.ui.NumberPicker <info.nightscout.androidaps.utils.ui.NumberPicker
android:id="@+id/carb_time_input" android:id="@+id/carb_time_input"
android:layout_width="130dp" android:layout_width="130dp"
android:layout_height="40dp" android:layout_height="40dp"
android:layout_gravity="center" /> android:layout_gravity="center"
app:contentDescription="carb time" />
<TextView <TextView
android:layout_width="wrap_content" android:layout_width="wrap_content"
@ -402,6 +369,7 @@
<TextView <TextView
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:labelFor="@id/profile"
android:padding="10dp" android:padding="10dp"
android:text="@string/profile_label" android:text="@string/profile_label"
android:textAppearance="@style/TextAppearance.AppCompat.Small" android:textAppearance="@style/TextAppearance.AppCompat.Small"
@ -414,7 +382,6 @@
android:layout_gravity="center_vertical|center_horizontal" android:layout_gravity="center_vertical|center_horizontal"
android:layout_weight="0.5" /> android:layout_weight="0.5" />
<CheckBox <CheckBox
android:id="@+id/sb_checkbox" android:id="@+id/sb_checkbox"
android:layout_width="wrap_content" android:layout_width="wrap_content"
@ -445,38 +412,24 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="horizontal">
<CheckBox <CheckBox
android:id="@+id/bg_checkbox" android:id="@+id/bg_checkbox"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:width="32dp" android:checked="true"
android:checked="true" /> android:text="@string/treatments_wizard_bg_label" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:width="24dp"
android:text="@string/treatments_wizard_bg_label"
android:textAppearance="?android:attr/textAppearanceSmall" />
<CheckBox <CheckBox
android:id="@+id/tt_checkbox" android:id="@+id/tt_checkbox"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:width="32dp" android:checked="false"
android:checked="false" /> android:text="@string/treatments_wizard_tt_label" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:width="30dp"
android:text="@string/treatments_wizard_tt_label"
android:textAppearance="?android:attr/textAppearanceSmall" />
</LinearLayout> </LinearLayout>
@ -506,15 +459,9 @@
android:id="@+id/bg_trend_checkbox" android:id="@+id/bg_trend_checkbox"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:width="32dp" android:checked="false"
android:checked="false" /> android:text="@string/bg_trend_label" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:width="86dp"
android:text="@string/bg_trend_label"
android:textAppearance="?android:attr/textAppearanceSmall" />
<TextView <TextView
android:id="@+id/bg_trend" android:id="@+id/bg_trend"
@ -542,15 +489,8 @@
android:id="@+id/iob_checkbox" android:id="@+id/iob_checkbox"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:width="32dp" android:checked="true"
android:checked="true" /> android:text="@string/iob" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:width="130dp"
android:text="@string/iob"
android:textAppearance="?android:attr/textAppearanceSmall" />
<TextView <TextView
android:layout_width="wrap_content" android:layout_width="wrap_content"
@ -578,14 +518,8 @@
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:width="32dp" android:width="32dp"
android:checked="false" /> android:checked="false"
android:text="@string/treatments_wizard_cob_label" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:width="86dp"
android:text="@string/treatments_wizard_cob_label"
android:textAppearance="?android:attr/textAppearanceSmall" />
<TextView <TextView
android:id="@+id/cob" android:id="@+id/cob"
@ -607,7 +541,13 @@
<TableRow <TableRow
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent"
android:focusable="true">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="horizontal">
<TextView <TextView
android:layout_width="wrap_content" android:layout_width="wrap_content"
@ -621,6 +561,8 @@
android:text="@string/treatments_wizard_carbs_label" android:text="@string/treatments_wizard_carbs_label"
android:textAppearance="?android:attr/textAppearanceSmall" /> android:textAppearance="?android:attr/textAppearanceSmall" />
</LinearLayout>
<TextView <TextView
android:id="@+id/carbs" android:id="@+id/carbs"
android:layout_width="wrap_content" android:layout_width="wrap_content"
@ -642,7 +584,13 @@
<TableRow <TableRow
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent"
android:focusable="true">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="horizontal">
<TextView <TextView
android:layout_width="wrap_content" android:layout_width="wrap_content"
@ -656,6 +604,8 @@
android:text="@string/superbolus" android:text="@string/superbolus"
android:textAppearance="?android:attr/textAppearanceSmall" /> android:textAppearance="?android:attr/textAppearanceSmall" />
</LinearLayout>
<TextView <TextView
android:id="@+id/sb" android:id="@+id/sb"
android:layout_width="wrap_content" android:layout_width="wrap_content"
@ -676,7 +626,13 @@
<TableRow <TableRow
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent"
android:focusable="true">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="horizontal">
<TextView <TextView
android:layout_width="wrap_content" android:layout_width="wrap_content"
@ -690,6 +646,8 @@
android:text="@string/treatments_wizard_correction_label" android:text="@string/treatments_wizard_correction_label"
android:textAppearance="?android:attr/textAppearanceSmall" /> android:textAppearance="?android:attr/textAppearanceSmall" />
</LinearLayout>
<TextView <TextView
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
@ -704,6 +662,7 @@
android:width="50dp" android:width="50dp"
android:gravity="end" android:gravity="end"
android:textAppearance="?android:attr/textAppearanceSmall" /> android:textAppearance="?android:attr/textAppearanceSmall" />
</TableRow> </TableRow>
</TableLayout> </TableLayout>

View file

@ -1141,6 +1141,27 @@
<string name="key_last_processed_glunovo_timestamp" translatable="false">last_processed_glunovo_timestamp</string> <string name="key_last_processed_glunovo_timestamp" translatable="false">last_processed_glunovo_timestamp</string>
<string name="identification">Identification (email, FB or Discord nick etc)</string> <string name="identification">Identification (email, FB or Discord nick etc)</string>
<string name="identification_not_set">Identification not set in dev mode</string> <string name="identification_not_set">Identification not set in dev mode</string>
<string name="a11y_high">heigh</string>
<string name="a11y_inrange">in range</string>
<string name="a11y_low">low</string>
<string name="a11y_arrow_double_down">down fast</string>
<string name="a11y_arrow_single_down">down</string>
<string name="a11y_arrow_forty_five_down">down trending</string>
<string name="a11y_arrow_flat">flat</string>
<string name="a11y_arrow_forty_five_up">up trending</string>
<string name="a11y_arrow_single_up">up</string>
<string name="a11y_arrow_double_up">up fast</string>
<string name="a11y_arrow_none">none</string>
<string name="a11y_arrow_unknown">unknown</string>
<string name="a11y_graph">graph</string>
<string name="a11y_bg_quality">Blood glucose quality</string>
<string name="a11_bg_quality_recalculated">recalculated</string>
<string name="a11_bg_quality_doubles">double entries</string>
<string name="a11y_insulin_label">insulin</string>
<string name="a11y_dialog">dialog</string>
<string name="a11y_current_bg">current blood glucode</string>
<string name="a11_correction_percentage">correct outcome with %</string>
<string name="a11_correction_units">correct outcome with units</string>
<string name="not_available_full">Not available</string> <string name="not_available_full">Not available</string>
</resources> </resources>

View file

@ -15,6 +15,8 @@ import android.view.MotionEvent
import android.view.View import android.view.View
import android.view.View.OnFocusChangeListener import android.view.View.OnFocusChangeListener
import android.view.View.OnTouchListener import android.view.View.OnTouchListener
import android.view.accessibility.AccessibilityEvent
import android.view.accessibility.AccessibilityManager
import android.view.inputmethod.InputMethodManager import android.view.inputmethod.InputMethodManager
import android.widget.Button import android.widget.Button
import android.widget.EditText import android.widget.EditText
@ -50,6 +52,7 @@ open class NumberPicker(context: Context, attrs: AttributeSet? = null) : LinearL
protected var focused = false protected var focused = false
private var mUpdater: ScheduledExecutorService? = null private var mUpdater: ScheduledExecutorService? = null
private var mOnValueChangedListener: OnValueChangedListener? = null private var mOnValueChangedListener: OnValueChangedListener? = null
private var mCustomContentDescription: String? = null
private var mHandler: Handler = Handler(Looper.getMainLooper(), Handler.Callback { msg: Message -> private var mHandler: Handler = Handler(Looper.getMainLooper(), Handler.Callback { msg: Message ->
when (msg.what) { when (msg.what) {
@ -86,6 +89,13 @@ open class NumberPicker(context: Context, attrs: AttributeSet? = null) : LinearL
} }
} }
var customContentDescription: String?
get() = mCustomContentDescription
set(value) {
mCustomContentDescription = value
updateA11yDescription()
}
protected open fun inflate(context: Context) { protected open fun inflate(context: Context) {
LayoutInflater.from(context).inflate(R.layout.number_picker_layout, this, true) LayoutInflater.from(context).inflate(R.layout.number_picker_layout, this, true)
} }
@ -121,6 +131,29 @@ open class NumberPicker(context: Context, attrs: AttributeSet? = null) : LinearL
if (!focused) value // check min/max if (!focused) value // check min/max
updateEditText() updateEditText()
} }
updateA11yDescription()
}
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))
}
fun announceValue() {
val manager: AccessibilityManager = context
.getSystemService(Context.ACCESSIBILITY_SERVICE) as AccessibilityManager
if (manager.isEnabled) {
val valueDescription = formatter?.format(currentValue)
AccessibilityEvent.obtain().apply {
eventType = AccessibilityEvent.TYPE_ANNOUNCEMENT
className = javaClass.name
packageName = context.packageName
text.add(valueDescription)
}.also {
manager.sendAccessibilityEvent(it)
}
}
} }
override fun setTag(tag: Any) { override fun setTag(tag: Any) {
@ -173,6 +206,7 @@ open class NumberPicker(context: Context, attrs: AttributeSet? = null) : LinearL
this.okButton = okButton this.okButton = okButton
editText?.keyListener = DigitsKeyListenerWithComma.getInstance(minValue < 0, step != round(step)) editText?.keyListener = DigitsKeyListenerWithComma.getInstance(minValue < 0, step != round(step))
if (watcher != null) editText?.removeTextChangedListener(watcher) if (watcher != null) editText?.removeTextChangedListener(watcher)
updateA11yDescription()
updateEditText() updateEditText()
if (watcher != null) editText?.addTextChangedListener(watcher) if (watcher != null) editText?.addTextChangedListener(watcher)
} }
@ -253,6 +287,7 @@ open class NumberPicker(context: Context, attrs: AttributeSet? = null) : LinearL
private fun stopUpdating() { private fun stopUpdating() {
mUpdater?.shutdownNow() mUpdater?.shutdownNow()
mUpdater = null mUpdater = null
announceValue()
} }
override fun onClick(v: View) { override fun onClick(v: View) {
@ -265,6 +300,7 @@ open class NumberPicker(context: Context, attrs: AttributeSet? = null) : LinearL
} else { } else {
dec(1) dec(1)
} }
announceValue()
} }
} }
@ -299,5 +335,16 @@ open class NumberPicker(context: Context, attrs: AttributeSet? = null) : LinearL
init { init {
initialize(context) initialize(context)
context.theme.obtainStyledAttributes(
attrs,
R.styleable.NumberPicker,
0, 0).apply {
try {
mCustomContentDescription = getString(R.styleable.NumberPicker_customContentDescription)
} finally {
recycle()
}
}
} }
} }

View file

@ -4,4 +4,7 @@
<attr name="dialogTitleColor" format="reference" /> <attr name="dialogTitleColor" format="reference" />
<attr name="dialogTitleIconTint" format="reference" /> <attr name="dialogTitleIconTint" format="reference" />
<declare-styleable name="NumberPicker">
<attr name="customContentDescription" format="string" />
</declare-styleable>
</resources> </resources>

View file

@ -540,6 +540,8 @@
<string name="bolus_ok" comment="26 characters max for translation">Bolus OK</string> <string name="bolus_ok" comment="26 characters max for translation">Bolus OK</string>
<string name="pump_paired" comment="26 characters max for translation">Pump paired</string> <string name="pump_paired" comment="26 characters max for translation">Pump paired</string>
<string name="insight_refresh_button" comment="26 characters max for translation">Insight Refresh Button</string> <string name="insight_refresh_button" comment="26 characters max for translation">Insight Refresh Button</string>
<string name="a11y_min_button_description">decrement %1$s by %2$s</string>
<string name="a11y_plus_button_description">increment %1$s by %2$s</string>
<plurals name="days"> <plurals name="days">
<item quantity="one">%1$d day</item> <item quantity="one">%1$d day</item>