From 88b2a8d0d78ec2d1a5329484dd773a28f5298456 Mon Sep 17 00:00:00 2001 From: Philoul Date: Tue, 7 Dec 2021 21:38:05 +0100 Subject: [PATCH] Add selector to allow correction in percentage --- .../androidaps/dialogs/WizardDialog.kt | 66 +++++++++++++++---- .../androidaps/utils/wizard/BolusWizard.kt | 51 ++++++++++++-- app/src/main/res/layout/dialog_wizard.xml | 39 +++++++++-- app/src/main/res/values/strings.xml | 1 + 4 files changed, 132 insertions(+), 25 deletions(-) diff --git a/app/src/main/java/info/nightscout/androidaps/dialogs/WizardDialog.kt b/app/src/main/java/info/nightscout/androidaps/dialogs/WizardDialog.kt index 92afb1141e..ee18a17818 100644 --- a/app/src/main/java/info/nightscout/androidaps/dialogs/WizardDialog.kt +++ b/app/src/main/java/info/nightscout/androidaps/dialogs/WizardDialog.kt @@ -27,14 +27,10 @@ import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.plugins.bus.RxBus 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.valueToUnits import info.nightscout.androidaps.interfaces.* +import info.nightscout.androidaps.utils.* import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.rx.AapsSchedulers import info.nightscout.androidaps.utils.sharedPreferences.SP @@ -63,6 +59,9 @@ class WizardDialog : DaggerDialogFragment() { @Inject lateinit var dateUtil: DateUtil private var wizard: BolusWizard? = null + private var calculatedPercentage = 100.0 + private var calculatedCorrection = 0.0 + private var correctionPercent = false //one shot guards private var okClicked: Boolean = false @@ -134,12 +133,22 @@ class WizardDialog : DaggerDialogFragment() { binding.carbsInput.setParams(savedInstanceState?.getDouble("carbs_input") ?: 0.0, 0.0, maxCarbs.toDouble(), 1.0, DecimalFormat("0"), false, binding.ok, textWatcher) val bolusStep = activePlugin.activePump.pumpDescription.bolusStep - binding.correctionInput.setParams(savedInstanceState?.getDouble("correction_input") - ?: 0.0, -maxCorrection, maxCorrection, bolusStep, DecimalFormatter.pumpSupportedBolusFormat(activePlugin.activePump), false, binding.ok, textWatcher) + + 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) + binding.correctionUnit.text = rh.gs(R.string.insulin_unit_shortname) + } binding.carbTimeInput.setParams(savedInstanceState?.getDouble("carb_time_input") ?: 0.0, -60.0, 60.0, 5.0, DecimalFormat("0"), false, binding.ok, timeTextWatcher) 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)) // ok button binding.ok.setOnClickListener { @@ -176,6 +185,21 @@ class WizardDialog : DaggerDialogFragment() { 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 binding.profile.onItemSelectedListener = object : OnItemSelectedListener { override fun onNothingSelected(parent: AdapterView<*>?) { @@ -228,11 +252,14 @@ class WizardDialog : DaggerDialogFragment() { private fun saveCheckedStates() { 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_correction_percent, binding.correctionPercent.isChecked) } private fun loadCheckedStates() { 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) + correctionPercent = sp.getBoolean(R.string.key_wizard_correction_percent,false) + binding.correctionPercent.isChecked = correctionPercent } private fun valueToUnitsToString(value: Double, units: String): String = @@ -273,7 +300,7 @@ class WizardDialog : DaggerDialogFragment() { 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() { @@ -291,9 +318,16 @@ class WizardDialog : DaggerDialogFragment() { if (specificProfile == null) return // Entered values + val usePercentage = binding.correctionPercent.isChecked var bg = SafeParse.stringToDouble(binding.bgInput.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() if (abs(carbs - carbsAfterConstraint) > 0.01) { binding.carbsInput.value = 0.0 @@ -314,8 +348,7 @@ class WizardDialog : DaggerDialogFragment() { val carbTime = SafeParse.stringToInt(binding.carbTimeInput.text) - wizard = BolusWizard(injector).doCalc(specificProfile, profileName, tempTarget, carbsAfterConstraint, cob, bg, correction, - sp.getInt(R.string.key_boluswizard_percentage, 100), + wizard = BolusWizard(injector).doCalc(specificProfile, profileName, tempTarget, carbsAfterConstraint, cob, bg, correction, sp.getInt(R.string.key_boluswizard_percentage, 100), binding.bgcheckbox.isChecked, binding.cobcheckbox.isChecked, binding.bolusiobcheckbox.isChecked, @@ -324,7 +357,11 @@ class WizardDialog : DaggerDialogFragment() { binding.ttcheckbox.isChecked, binding.bgtrendcheckbox.isChecked, binding.alarm.isChecked, - binding.notes.text.toString(), carbTime) + binding.notes.text.toString(), + carbTime, + usePercentage = usePercentage, + totalPercentage = percentageCorrection + ) 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) @@ -370,6 +407,9 @@ class WizardDialog : DaggerDialogFragment() { binding.total.text = rh.gs(R.string.missing_carbs, wizard.carbsEquivalent.toInt()) binding.ok.visibility = View.INVISIBLE } + binding.percentUsed.text = rh.gs(R.string.format_percent, wizard.percentageCorrection) + calculatedPercentage = wizard.calculatedPercentage + calculatedCorrection = wizard.calculatedCorrection } } diff --git a/app/src/main/java/info/nightscout/androidaps/utils/wizard/BolusWizard.kt b/app/src/main/java/info/nightscout/androidaps/utils/wizard/BolusWizard.kt index 74950918f5..c9443e17b6 100644 --- a/app/src/main/java/info/nightscout/androidaps/utils/wizard/BolusWizard.kt +++ b/app/src/main/java/info/nightscout/androidaps/utils/wizard/BolusWizard.kt @@ -36,6 +36,8 @@ import io.reactivex.rxkotlin.plusAssign import java.util.* import javax.inject.Inject import kotlin.math.abs +import kotlin.math.max +import kotlin.math.min class BolusWizard @Inject constructor( val injector: HasAndroidInjector @@ -105,6 +107,10 @@ class BolusWizard @Inject constructor( private set var insulinAfterConstraints: Double = 0.0 private set + var calculatedPercentage: Double = 100.0 + private set + var calculatedCorrection: Double = 0.0 + private set // Input lateinit var profile: Profile @@ -114,7 +120,8 @@ class BolusWizard @Inject constructor( var cob: Double = 0.0 var bg: 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 useCob: Boolean = false private var includeBolusIOB: Boolean = false @@ -126,6 +133,7 @@ class BolusWizard @Inject constructor( var notes: String = "" private var carbTime: Int = 0 private var quickWizard: Boolean = true + var usePercentage: Boolean = false fun doCalc(profile: Profile, profileName: String, @@ -145,6 +153,8 @@ class BolusWizard @Inject constructor( useAlarm: Boolean, notes: String = "", carbTime: Int = 0, + usePercentage: Boolean = false, + totalPercentage: Double = 100.0, quickWizard: Boolean = false ): BolusWizard { @@ -167,6 +177,8 @@ class BolusWizard @Inject constructor( this.notes = notes this.carbTime = carbTime this.quickWizard = quickWizard + this.usePercentage = usePercentage + this.totalPercentage = totalPercentage // Insulin from BG sens = Profile.fromMgdlToUnits(profile.getIsfMgdl(), profileFunction.getUnits()) @@ -208,7 +220,7 @@ class BolusWizard @Inject constructor( insulinFromBasalIOB = if (includeBasalIOB) -basalIob.basaliob else 0.0 // Insulin from correction - insulinFromCorrection = correction + insulinFromCorrection = if (usePercentage) 0.0 else correction // Insulin from superbolus for 2h. Get basal rate now and after 1h if (useSuperBolus) { @@ -221,15 +233,23 @@ class BolusWizard @Inject constructor( // Total calculatedTotalInsulin = insulinFromBG + insulinFromTrend + insulinFromCarbs + insulinFromBolusIOB + insulinFromBasalIOB + insulinFromCorrection + insulinFromSuperBolus + insulinFromCOB + var percentage = if (usePercentage) totalPercentage else percentageCorrection.toDouble() + // Percentage adjustment totalBeforePercentageAdjustment = calculatedTotalInsulin - if (calculatedTotalInsulin > 0) { - calculatedTotalInsulin = calculatedTotalInsulin * percentageCorrection / 100.0 - } - - if (calculatedTotalInsulin < 0) { + if (calculatedTotalInsulin >= 0) { + calculatedTotalInsulin = calculatedTotalInsulin * percentage / 100.0 + if (usePercentage) + calcCorrectionWithConstraints() + 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 calculatedTotalInsulin = 0.0 + calculatedPercentage = percentageCorrection.toDouble() + calculatedCorrection = 0.0 } 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) + } + } \ No newline at end of file diff --git a/app/src/main/res/layout/dialog_wizard.xml b/app/src/main/res/layout/dialog_wizard.xml index ce32053308..635ff30447 100644 --- a/app/src/main/res/layout/dialog_wizard.xml +++ b/app/src/main/res/layout/dialog_wizard.xml @@ -118,14 +118,42 @@ android:layout_width="match_parent" android:layout_height="match_parent"> - + android:orientation="horizontal"> + + + + + + + + + + + Units Do you want to switch profile and discard changes made to current profile? wizard_calculation_visible + wizard_correction_percent Clear finished Clear started Do you want reset objective start? You may lose your progress.