Add selector to allow correction in percentage

This commit is contained in:
Philoul 2021-12-07 21:38:05 +01:00
parent a83eb1c456
commit 88b2a8d0d7
4 changed files with 132 additions and 25 deletions

View file

@ -27,14 +27,10 @@ import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.logging.LTag
import info.nightscout.androidaps.plugins.bus.RxBus import info.nightscout.androidaps.plugins.bus.RxBus
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.DecimalFormatter
import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.SafeParse
import info.nightscout.androidaps.utils.ToastUtils
import info.nightscout.androidaps.extensions.toVisibility import info.nightscout.androidaps.extensions.toVisibility
import info.nightscout.androidaps.extensions.valueToUnits import info.nightscout.androidaps.extensions.valueToUnits
import info.nightscout.androidaps.interfaces.* import info.nightscout.androidaps.interfaces.*
import info.nightscout.androidaps.utils.*
import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.rx.AapsSchedulers import info.nightscout.androidaps.utils.rx.AapsSchedulers
import info.nightscout.androidaps.utils.sharedPreferences.SP import info.nightscout.androidaps.utils.sharedPreferences.SP
@ -63,6 +59,9 @@ class WizardDialog : DaggerDialogFragment() {
@Inject lateinit var dateUtil: DateUtil @Inject lateinit var dateUtil: DateUtil
private var wizard: BolusWizard? = null private var wizard: BolusWizard? = null
private var calculatedPercentage = 100.0
private var calculatedCorrection = 0.0
private var correctionPercent = false
//one shot guards //one shot guards
private var okClicked: Boolean = false private var okClicked: Boolean = false
@ -134,12 +133,22 @@ class WizardDialog : DaggerDialogFragment() {
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.ok, textWatcher)
val bolusStep = activePlugin.activePump.pumpDescription.bolusStep val bolusStep = activePlugin.activePump.pumpDescription.bolusStep
binding.correctionInput.setParams(savedInstanceState?.getDouble("correction_input")
if (correctionPercent) {
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.value = calculatedPercentage
binding.correctionUnit.text = "%"
} else {
binding.correctionInput.setParams(
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.ok, textWatcher)
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.ok, timeTextWatcher)
initDialog() initDialog()
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.ok.setOnClickListener {
@ -176,6 +185,21 @@ class WizardDialog : DaggerDialogFragment() {
binding.resulttable.visibility = isChecked.toVisibility() binding.resulttable.visibility = isChecked.toVisibility()
} }
} }
binding.correctionPercent.setOnCheckedChangeListener {_, isChecked ->
run {
sp.putBoolean(rh.gs(R.string.key_wizard_correction_percent), isChecked)
binding.correctionUnit.text = if (isChecked) "%" else rh.gs(R.string.insulin_unit_shortname)
correctionPercent = binding.correctionPercent.isChecked
if (correctionPercent)
binding.correctionInput.setParams(calculatedPercentage.toDouble(), 10.0, 200.0, 1.0, DecimalFormat("0"), false, binding.ok, textWatcher)
else
binding.correctionInput.setParams(savedInstanceState?.getDouble("correction_input")
?: 0.0, -maxCorrection, maxCorrection, bolusStep, DecimalFormatter.pumpSupportedBolusFormat(activePlugin.activePump), false, binding.ok, textWatcher)
binding.correctionInput.value = if (correctionPercent) calculatedPercentage.toDouble() else calculatedCorrection
}
}
// profile spinner // profile spinner
binding.profile.onItemSelectedListener = object : OnItemSelectedListener { binding.profile.onItemSelectedListener = object : OnItemSelectedListener {
override fun onNothingSelected(parent: AdapterView<*>?) { override fun onNothingSelected(parent: AdapterView<*>?) {
@ -228,11 +252,14 @@ class WizardDialog : DaggerDialogFragment() {
private fun saveCheckedStates() { private fun saveCheckedStates() {
sp.putBoolean(R.string.key_wizard_include_cob, binding.cobcheckbox.isChecked) sp.putBoolean(R.string.key_wizard_include_cob, binding.cobcheckbox.isChecked)
sp.putBoolean(R.string.key_wizard_include_trend_bg, binding.bgtrendcheckbox.isChecked) sp.putBoolean(R.string.key_wizard_include_trend_bg, binding.bgtrendcheckbox.isChecked)
sp.putBoolean(R.string.key_wizard_correction_percent, binding.correctionPercent.isChecked)
} }
private fun loadCheckedStates() { private fun loadCheckedStates() {
binding.bgtrendcheckbox.isChecked = sp.getBoolean(R.string.key_wizard_include_trend_bg, false) binding.bgtrendcheckbox.isChecked = sp.getBoolean(R.string.key_wizard_include_trend_bg, false)
binding.cobcheckbox.isChecked = sp.getBoolean(R.string.key_wizard_include_cob, false) binding.cobcheckbox.isChecked = sp.getBoolean(R.string.key_wizard_include_cob, false)
correctionPercent = sp.getBoolean(R.string.key_wizard_correction_percent,false)
binding.correctionPercent.isChecked = correctionPercent
} }
private fun valueToUnitsToString(value: Double, units: String): String = private fun valueToUnitsToString(value: Double, units: String): String =
@ -273,7 +300,7 @@ class WizardDialog : DaggerDialogFragment() {
calculateInsulin() calculateInsulin()
binding.percentUsed.visibility = (sp.getInt(R.string.key_boluswizard_percentage, 100) != 100).toVisibility() binding.percentUsed.visibility = (sp.getInt(R.string.key_boluswizard_percentage, 100) != 100 || correctionPercent).toVisibility()
} }
private fun calculateInsulin() { private fun calculateInsulin() {
@ -291,9 +318,16 @@ class WizardDialog : DaggerDialogFragment() {
if (specificProfile == null) return if (specificProfile == null) return
// Entered values // Entered values
val usePercentage = binding.correctionPercent.isChecked
var bg = SafeParse.stringToDouble(binding.bgInput.text) var bg = SafeParse.stringToDouble(binding.bgInput.text)
val carbs = SafeParse.stringToInt(binding.carbsInput.text) val carbs = SafeParse.stringToInt(binding.carbsInput.text)
val correction = SafeParse.stringToDouble(binding.correctionInput.text) val correction = if (usePercentage) 0.0 else SafeParse.stringToDouble(binding.correctionInput.text)
val percentageCorrection = if (usePercentage) {
if (Round.roundTo(calculatedPercentage,1.0) == SafeParse.stringToDouble(binding.correctionInput.text))
calculatedPercentage
else
SafeParse.stringToDouble(binding.correctionInput.text)
} else sp.getInt(R.string.key_boluswizard_percentage, 100).toDouble()
val carbsAfterConstraint = constraintChecker.applyCarbsConstraints(Constraint(carbs)).value() val carbsAfterConstraint = constraintChecker.applyCarbsConstraints(Constraint(carbs)).value()
if (abs(carbs - carbsAfterConstraint) > 0.01) { if (abs(carbs - carbsAfterConstraint) > 0.01) {
binding.carbsInput.value = 0.0 binding.carbsInput.value = 0.0
@ -314,8 +348,7 @@ class WizardDialog : DaggerDialogFragment() {
val carbTime = SafeParse.stringToInt(binding.carbTimeInput.text) val carbTime = SafeParse.stringToInt(binding.carbTimeInput.text)
wizard = BolusWizard(injector).doCalc(specificProfile, profileName, tempTarget, carbsAfterConstraint, cob, bg, correction, wizard = BolusWizard(injector).doCalc(specificProfile, profileName, tempTarget, carbsAfterConstraint, cob, bg, correction, sp.getInt(R.string.key_boluswizard_percentage, 100),
sp.getInt(R.string.key_boluswizard_percentage, 100),
binding.bgcheckbox.isChecked, binding.bgcheckbox.isChecked,
binding.cobcheckbox.isChecked, binding.cobcheckbox.isChecked,
binding.bolusiobcheckbox.isChecked, binding.bolusiobcheckbox.isChecked,
@ -324,7 +357,11 @@ class WizardDialog : DaggerDialogFragment() {
binding.ttcheckbox.isChecked, binding.ttcheckbox.isChecked,
binding.bgtrendcheckbox.isChecked, binding.bgtrendcheckbox.isChecked,
binding.alarm.isChecked, binding.alarm.isChecked,
binding.notes.text.toString(), carbTime) binding.notes.text.toString(),
carbTime,
usePercentage = usePercentage,
totalPercentage = percentageCorrection
)
wizard?.let { wizard -> wizard?.let { wizard ->
binding.bg.text = String.format(rh.gs(R.string.format_bg_isf), valueToUnitsToString(Profile.toMgdl(bg, profileFunction.getUnits()), profileFunction.getUnits().asText), wizard.sens) binding.bg.text = String.format(rh.gs(R.string.format_bg_isf), valueToUnitsToString(Profile.toMgdl(bg, profileFunction.getUnits()), profileFunction.getUnits().asText), wizard.sens)
@ -370,6 +407,9 @@ class WizardDialog : DaggerDialogFragment() {
binding.total.text = rh.gs(R.string.missing_carbs, wizard.carbsEquivalent.toInt()) binding.total.text = rh.gs(R.string.missing_carbs, wizard.carbsEquivalent.toInt())
binding.ok.visibility = View.INVISIBLE binding.ok.visibility = View.INVISIBLE
} }
binding.percentUsed.text = rh.gs(R.string.format_percent, wizard.percentageCorrection)
calculatedPercentage = wizard.calculatedPercentage
calculatedCorrection = wizard.calculatedCorrection
} }
} }

View file

@ -36,6 +36,8 @@ import io.reactivex.rxkotlin.plusAssign
import java.util.* import java.util.*
import javax.inject.Inject import javax.inject.Inject
import kotlin.math.abs import kotlin.math.abs
import kotlin.math.max
import kotlin.math.min
class BolusWizard @Inject constructor( class BolusWizard @Inject constructor(
val injector: HasAndroidInjector val injector: HasAndroidInjector
@ -105,6 +107,10 @@ class BolusWizard @Inject constructor(
private set private set
var insulinAfterConstraints: Double = 0.0 var insulinAfterConstraints: Double = 0.0
private set private set
var calculatedPercentage: Double = 100.0
private set
var calculatedCorrection: Double = 0.0
private set
// Input // Input
lateinit var profile: Profile lateinit var profile: Profile
@ -114,7 +120,8 @@ class BolusWizard @Inject constructor(
var cob: Double = 0.0 var cob: Double = 0.0
var bg: Double = 0.0 var bg: Double = 0.0
private var correction: Double = 0.0 private var correction: Double = 0.0
private var percentageCorrection: Int = 0 var percentageCorrection: Int = 100
private var totalPercentage: Double = 100.0
private var useBg: Boolean = false private var useBg: Boolean = false
private var useCob: Boolean = false private var useCob: Boolean = false
private var includeBolusIOB: Boolean = false private var includeBolusIOB: Boolean = false
@ -126,6 +133,7 @@ class BolusWizard @Inject constructor(
var notes: String = "" var notes: String = ""
private var carbTime: Int = 0 private var carbTime: Int = 0
private var quickWizard: Boolean = true private var quickWizard: Boolean = true
var usePercentage: Boolean = false
fun doCalc(profile: Profile, fun doCalc(profile: Profile,
profileName: String, profileName: String,
@ -145,6 +153,8 @@ class BolusWizard @Inject constructor(
useAlarm: Boolean, useAlarm: Boolean,
notes: String = "", notes: String = "",
carbTime: Int = 0, carbTime: Int = 0,
usePercentage: Boolean = false,
totalPercentage: Double = 100.0,
quickWizard: Boolean = false quickWizard: Boolean = false
): BolusWizard { ): BolusWizard {
@ -167,6 +177,8 @@ class BolusWizard @Inject constructor(
this.notes = notes this.notes = notes
this.carbTime = carbTime this.carbTime = carbTime
this.quickWizard = quickWizard this.quickWizard = quickWizard
this.usePercentage = usePercentage
this.totalPercentage = totalPercentage
// Insulin from BG // Insulin from BG
sens = Profile.fromMgdlToUnits(profile.getIsfMgdl(), profileFunction.getUnits()) sens = Profile.fromMgdlToUnits(profile.getIsfMgdl(), profileFunction.getUnits())
@ -208,7 +220,7 @@ class BolusWizard @Inject constructor(
insulinFromBasalIOB = if (includeBasalIOB) -basalIob.basaliob else 0.0 insulinFromBasalIOB = if (includeBasalIOB) -basalIob.basaliob else 0.0
// Insulin from correction // Insulin from correction
insulinFromCorrection = correction insulinFromCorrection = if (usePercentage) 0.0 else correction
// Insulin from superbolus for 2h. Get basal rate now and after 1h // Insulin from superbolus for 2h. Get basal rate now and after 1h
if (useSuperBolus) { if (useSuperBolus) {
@ -221,15 +233,23 @@ class BolusWizard @Inject constructor(
// Total // Total
calculatedTotalInsulin = insulinFromBG + insulinFromTrend + insulinFromCarbs + insulinFromBolusIOB + insulinFromBasalIOB + insulinFromCorrection + insulinFromSuperBolus + insulinFromCOB calculatedTotalInsulin = insulinFromBG + insulinFromTrend + insulinFromCarbs + insulinFromBolusIOB + insulinFromBasalIOB + insulinFromCorrection + insulinFromSuperBolus + insulinFromCOB
var percentage = if (usePercentage) totalPercentage else percentageCorrection.toDouble()
// Percentage adjustment // Percentage adjustment
totalBeforePercentageAdjustment = calculatedTotalInsulin totalBeforePercentageAdjustment = calculatedTotalInsulin
if (calculatedTotalInsulin > 0) { if (calculatedTotalInsulin >= 0) {
calculatedTotalInsulin = calculatedTotalInsulin * percentageCorrection / 100.0 calculatedTotalInsulin = calculatedTotalInsulin * percentage / 100.0
} if (usePercentage)
calcCorrectionWithConstraints()
if (calculatedTotalInsulin < 0) { else
calcPercentageWithConstraints()
if (usePercentage) //Should be updated after calcCorrectionWithConstraints and calcPercentageWithConstraints to have correct synthesis in WizardInfo
this.percentageCorrection = Round.roundTo(totalPercentage, 1.0).toInt()
} else {
carbsEquivalent = (-calculatedTotalInsulin) * ic carbsEquivalent = (-calculatedTotalInsulin) * ic
calculatedTotalInsulin = 0.0 calculatedTotalInsulin = 0.0
calculatedPercentage = percentageCorrection.toDouble()
calculatedCorrection = 0.0
} }
val bolusStep = activePlugin.activePump.pumpDescription.bolusStep val bolusStep = activePlugin.activePump.pumpDescription.bolusStep
@ -441,4 +461,21 @@ class BolusWizard @Inject constructor(
} }
}) })
} }
private fun calcPercentageWithConstraints() {
calculatedPercentage = 100.0
if (totalBeforePercentageAdjustment != insulinFromCorrection)
calculatedPercentage = calculatedTotalInsulin/(totalBeforePercentageAdjustment-insulinFromCorrection)*100
calculatedPercentage = max(calculatedPercentage, 10.0)
calculatedPercentage = min(calculatedPercentage,250.0)
}
private fun calcCorrectionWithConstraints() {
val bolusStep = activePlugin.activePump.pumpDescription.bolusStep
calculatedCorrection = Round.roundTo(totalBeforePercentageAdjustment * totalPercentage / percentageCorrection - totalBeforePercentageAdjustment, bolusStep)
//Apply constraints
calculatedCorrection = min(constraintChecker.getMaxBolusAllowed().value(), calculatedCorrection)
calculatedCorrection = max(-constraintChecker.getMaxBolusAllowed().value(), calculatedCorrection)
}
} }

View file

@ -118,6 +118,13 @@
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="wrap_content"
android:gravity="center_vertical"
android:layout_weight="1"
android:orientation="horizontal">
<TextView <TextView
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
@ -127,6 +134,27 @@
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" />
<CheckBox
android:id="@+id/correction_percent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:checked="false"
android:padding="2dp" />
</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"
@ -134,6 +162,7 @@
android:layout_gravity="center_horizontal" /> android:layout_gravity="center_horizontal" />
<TextView <TextView
android:id="@+id/correction_unit"
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"

View file

@ -934,6 +934,7 @@
<string name="unitsnosemicolon">Units</string> <string name="unitsnosemicolon">Units</string>
<string name="doyouwantswitchprofile">Do you want to switch profile and discard changes made to current profile?</string> <string name="doyouwantswitchprofile">Do you want to switch profile and discard changes made to current profile?</string>
<string name="key_wizard_calculation_visible" translatable="false">wizard_calculation_visible</string> <string name="key_wizard_calculation_visible" translatable="false">wizard_calculation_visible</string>
<string name="key_wizard_correction_percent" translatable="false">wizard_correction_percent</string>
<string name="objectives_button_unfinish">Clear finished</string> <string name="objectives_button_unfinish">Clear finished</string>
<string name="objectives_button_unstart">Clear started</string> <string name="objectives_button_unstart">Clear started</string>
<string name="doyouwantresetstart">Do you want reset objective start? You may lose your progress.</string> <string name="doyouwantresetstart">Do you want reset objective start? You may lose your progress.</string>