Wear: add explain message quickwizard
This commit is contained in:
parent
0233db8226
commit
2013332d70
8 changed files with 260 additions and 135 deletions
|
@ -45,7 +45,6 @@ import info.nightscout.shared.SafeParse
|
||||||
import io.reactivex.disposables.CompositeDisposable
|
import io.reactivex.disposables.CompositeDisposable
|
||||||
import io.reactivex.rxkotlin.plusAssign
|
import io.reactivex.rxkotlin.plusAssign
|
||||||
import java.text.DateFormat
|
import java.text.DateFormat
|
||||||
import java.text.DecimalFormat
|
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
|
@ -111,9 +110,11 @@ class ActionStringHandler @Inject constructor(
|
||||||
|
|
||||||
@Synchronized
|
@Synchronized
|
||||||
private fun handleInitiate(actionString: String) {
|
private fun handleInitiate(actionString: String) {
|
||||||
|
//TODO: i18n
|
||||||
|
Log.i("ActionStringHandler", "handleInitiate actionString=" + actionString)
|
||||||
if (!sp.getBoolean(R.string.key_wear_control, false)) return
|
if (!sp.getBoolean(R.string.key_wear_control, false)) return
|
||||||
lastBolusWizard = null
|
lastBolusWizard = null
|
||||||
var rTitle = "CONFIRM" //TODO: i18n
|
var rTitle = rh.gs(R.string.confirm).uppercase()
|
||||||
var rMessage = ""
|
var rMessage = ""
|
||||||
var rAction = ""
|
var rAction = ""
|
||||||
// do the parsing and check constraints
|
// do the parsing and check constraints
|
||||||
|
@ -140,6 +141,11 @@ class ActionStringHandler @Inject constructor(
|
||||||
val carbs = SafeParse.stringToInt(act[2])
|
val carbs = SafeParse.stringToInt(act[2])
|
||||||
val insulinAfterConstraints = constraintChecker.applyBolusConstraints(Constraint(insulin)).value()
|
val insulinAfterConstraints = constraintChecker.applyBolusConstraints(Constraint(insulin)).value()
|
||||||
val carbsAfterConstraints = constraintChecker.applyCarbsConstraints(Constraint(carbs)).value()
|
val carbsAfterConstraints = constraintChecker.applyCarbsConstraints(Constraint(carbs)).value()
|
||||||
|
val pump = activePlugin.activePump
|
||||||
|
if (insulinAfterConstraints > 0 && (!pump.isInitialized() || pump.isSuspended() || loop.isDisconnected)) {
|
||||||
|
sendError(rh.gs(R.string.wizard_pump_not_available))
|
||||||
|
return
|
||||||
|
}
|
||||||
rMessage += rh.gs(R.string.bolus) + ": " + insulinAfterConstraints + "U\n"
|
rMessage += rh.gs(R.string.bolus) + ": " + insulinAfterConstraints + "U\n"
|
||||||
rMessage += rh.gs(R.string.carbs) + ": " + carbsAfterConstraints + "g"
|
rMessage += rh.gs(R.string.carbs) + ": " + carbsAfterConstraints + "g"
|
||||||
if (insulinAfterConstraints - insulin != 0.0 || carbsAfterConstraints - carbs != 0) {
|
if (insulinAfterConstraints - insulin != 0.0 || carbsAfterConstraints - carbs != 0) {
|
||||||
|
@ -162,6 +168,7 @@ class ActionStringHandler @Inject constructor(
|
||||||
rMessage += rh.gs(R.string.wear_action_tempt_preset_message, reason, activityTT, activityTTDuration)
|
rMessage += rh.gs(R.string.wear_action_tempt_preset_message, reason, activityTT, activityTTDuration)
|
||||||
rAction = "temptarget $presetIsMGDL $activityTTDuration $activityTT $activityTT"
|
rAction = "temptarget $presetIsMGDL $activityTTDuration $activityTT $activityTT"
|
||||||
}
|
}
|
||||||
|
|
||||||
"hypo" -> {
|
"hypo" -> {
|
||||||
val hypoTTDuration = defaultValueHelper.determineHypoTTDuration()
|
val hypoTTDuration = defaultValueHelper.determineHypoTTDuration()
|
||||||
val hypoTT = defaultValueHelper.determineHypoTT()
|
val hypoTT = defaultValueHelper.determineHypoTT()
|
||||||
|
@ -169,6 +176,7 @@ class ActionStringHandler @Inject constructor(
|
||||||
rMessage += rh.gs(R.string.wear_action_tempt_preset_message, reason, hypoTT, hypoTTDuration)
|
rMessage += rh.gs(R.string.wear_action_tempt_preset_message, reason, hypoTT, hypoTTDuration)
|
||||||
rAction = "temptarget $presetIsMGDL $hypoTTDuration $hypoTT $hypoTT"
|
rAction = "temptarget $presetIsMGDL $hypoTTDuration $hypoTT $hypoTT"
|
||||||
}
|
}
|
||||||
|
|
||||||
"eating" -> {
|
"eating" -> {
|
||||||
val eatingSoonTTDuration = defaultValueHelper.determineEatingSoonTTDuration()
|
val eatingSoonTTDuration = defaultValueHelper.determineEatingSoonTTDuration()
|
||||||
val eatingSoonTT = defaultValueHelper.determineEatingSoonTT()
|
val eatingSoonTT = defaultValueHelper.determineEatingSoonTT()
|
||||||
|
@ -176,6 +184,7 @@ class ActionStringHandler @Inject constructor(
|
||||||
rMessage += rh.gs(R.string.wear_action_tempt_preset_message, reason, eatingSoonTT, eatingSoonTTDuration)
|
rMessage += rh.gs(R.string.wear_action_tempt_preset_message, reason, eatingSoonTT, eatingSoonTTDuration)
|
||||||
rAction = "temptarget $presetIsMGDL $eatingSoonTTDuration $eatingSoonTT $eatingSoonTT"
|
rAction = "temptarget $presetIsMGDL $eatingSoonTTDuration $eatingSoonTT $eatingSoonTT"
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> {
|
else -> {
|
||||||
sendError(rh.gs(R.string.wear_action_tempt_preset_error, preset))
|
sendError(rh.gs(R.string.wear_action_tempt_preset_error, preset))
|
||||||
return
|
return
|
||||||
|
@ -227,10 +236,15 @@ class ActionStringHandler @Inject constructor(
|
||||||
sendError("Update APP on Watch!")
|
sendError("Update APP on Watch!")
|
||||||
return
|
return
|
||||||
} else if ("wizard2" == act[0]) { ////////////////////////////////////////////// WIZARD
|
} else if ("wizard2" == act[0]) { ////////////////////////////////////////////// WIZARD
|
||||||
|
val pump = activePlugin.activePump
|
||||||
|
if (!pump.isInitialized() || pump.isSuspended() || loop.isDisconnected) {
|
||||||
|
sendError(rh.gs(R.string.wizard_pump_not_available))
|
||||||
|
return
|
||||||
|
}
|
||||||
val carbsBeforeConstraints = SafeParse.stringToInt(act[1])
|
val carbsBeforeConstraints = SafeParse.stringToInt(act[1])
|
||||||
val carbsAfterConstraints = constraintChecker.applyCarbsConstraints(Constraint(carbsBeforeConstraints)).value()
|
val carbsAfterConstraints = constraintChecker.applyCarbsConstraints(Constraint(carbsBeforeConstraints)).value()
|
||||||
if (carbsAfterConstraints - carbsBeforeConstraints != 0) {
|
if (carbsAfterConstraints - carbsBeforeConstraints != 0) {
|
||||||
sendError("Carb constraint violation!")
|
sendError(rh.gs(R.string.wizard_carbs_constraint))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
val useBG = sp.getBoolean(R.string.key_wearwizard_bg, true)
|
val useBG = sp.getBoolean(R.string.key_wearwizard_bg, true)
|
||||||
|
@ -243,80 +257,94 @@ class ActionStringHandler @Inject constructor(
|
||||||
val profile = profileFunction.getProfile()
|
val profile = profileFunction.getProfile()
|
||||||
val profileName = profileFunction.getProfileName()
|
val profileName = profileFunction.getProfileName()
|
||||||
if (profile == null) {
|
if (profile == null) {
|
||||||
sendError("No profile found!")
|
sendError(rh.gs(R.string.wizard_no_active_profile))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
val bgReading = iobCobCalculator.ads.actualBg()
|
val bgReading = iobCobCalculator.ads.actualBg()
|
||||||
if (bgReading == null) {
|
if (bgReading == null) {
|
||||||
sendError("No recent BG to base calculation on!")
|
sendError(rh.gs(R.string.wizard_no_actual_bg))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
val cobInfo = iobCobCalculator.getCobInfo(false, "Wizard wear")
|
val cobInfo = iobCobCalculator.getCobInfo(false, "Wizard wear")
|
||||||
if (cobInfo.displayCob == null) {
|
if (cobInfo.displayCob == null) {
|
||||||
sendError("Unknown COB! BG reading missing or recent app restart?")
|
sendError(rh.gs(R.string.wizard_no_cob))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
val format = DecimalFormat("0.00")
|
|
||||||
val formatInt = DecimalFormat("0")
|
|
||||||
val dbRecord = repository.getTemporaryTargetActiveAt(dateUtil.now()).blockingGet()
|
val dbRecord = repository.getTemporaryTargetActiveAt(dateUtil.now()).blockingGet()
|
||||||
val tempTarget = if (dbRecord is ValueWrapper.Existing) dbRecord.value else null
|
val tempTarget = if (dbRecord is ValueWrapper.Existing) dbRecord.value else null
|
||||||
|
|
||||||
val bolusWizard = BolusWizard(injector).doCalc(profile, profileName, tempTarget,
|
val bolusWizard = BolusWizard(injector).doCalc(
|
||||||
carbsAfterConstraints, if (cobInfo.displayCob != null) cobInfo.displayCob!! else 0.0, bgReading.valueToUnits(profileFunction.getUnits()),
|
profile, profileName, tempTarget,
|
||||||
0.0, percentage, useBG, useCOB, useBolusIOB, useBasalIOB, false, useTT, useTrend, false)
|
carbsAfterConstraints, cobInfo.displayCob!!, bgReading.valueToUnits(profileFunction.getUnits()),
|
||||||
if (abs(bolusWizard.insulinAfterConstraints - bolusWizard.calculatedTotalInsulin) >= 0.01) {
|
0.0, percentage, useBG, useCOB, useBolusIOB, useBasalIOB, false, useTT, useTrend, false
|
||||||
sendError("Insulin constraint violation!" +
|
)
|
||||||
"\nCannot deliver " + format.format(bolusWizard.calculatedTotalInsulin) + "!")
|
val insulinAfterConstraints = bolusWizard.insulinAfterConstraints
|
||||||
|
val minStep = pump.pumpDescription.pumpType.determineCorrectBolusStepSize(insulinAfterConstraints)
|
||||||
|
if (abs(insulinAfterConstraints - bolusWizard.calculatedTotalInsulin) >= minStep) {
|
||||||
|
sendError(rh.gs(R.string.wizard_constraint_bolus_size, bolusWizard.calculatedTotalInsulin))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (bolusWizard.calculatedTotalInsulin <= 0 && bolusWizard.carbs <= 0) {
|
if (bolusWizard.calculatedTotalInsulin <= 0 && bolusWizard.carbs <= 0) {
|
||||||
rAction = "info"
|
rAction = "info"
|
||||||
rTitle = "INFO"
|
rTitle = rh.gs(R.string.info)
|
||||||
} else {
|
} else {
|
||||||
rAction = actionString
|
rAction = actionString
|
||||||
}
|
}
|
||||||
rMessage += "Carbs: " + bolusWizard.carbs + "g"
|
rMessage += rh.gs(R.string.wizard_result, bolusWizard.calculatedTotalInsulin, bolusWizard.carbs)
|
||||||
rMessage += "\nBolus: " + format.format(bolusWizard.calculatedTotalInsulin) + "U"
|
|
||||||
rMessage += "\n_____________"
|
rMessage += "\n_____________"
|
||||||
rMessage += "\nCalc (IC:" + DecimalFormatter.to1Decimal(bolusWizard.ic) + ", " + "ISF:" + DecimalFormatter.to1Decimal(bolusWizard.sens) + "): "
|
rMessage += "\n" + bolusWizard.explainShort()
|
||||||
rMessage += "\nFrom Carbs: " + format.format(bolusWizard.insulinFromCarbs) + "U"
|
|
||||||
if (useCOB) rMessage += "\nFrom" + formatInt.format(cobInfo.displayCob) + "g COB : " + format.format(bolusWizard.insulinFromCOB) + "U"
|
|
||||||
if (useBG) rMessage += "\nFrom BG: " + format.format(bolusWizard.insulinFromBG) + "U"
|
|
||||||
if (useBolusIOB) rMessage += "\nBolus IOB: " + format.format(bolusWizard.insulinFromBolusIOB) + "U"
|
|
||||||
if (useBasalIOB) rMessage += "\nBasal IOB: " + format.format(bolusWizard.insulinFromBasalIOB) + "U"
|
|
||||||
if (useTrend) rMessage += "\nFrom 15' trend: " + format.format(bolusWizard.insulinFromTrend) + "U"
|
|
||||||
if (percentage != 100) {
|
|
||||||
rMessage += "\nPercentage: " + format.format(bolusWizard.totalBeforePercentageAdjustment) + "U * " + percentage + "% -> ~" + format.format(bolusWizard.calculatedTotalInsulin) + "U"
|
|
||||||
}
|
|
||||||
lastBolusWizard = bolusWizard
|
lastBolusWizard = bolusWizard
|
||||||
} else if ("quick_wizard" == act[0]) {
|
} else if ("quick_wizard" == act[0]) {
|
||||||
val guid = act[1]
|
val guid = act[1]
|
||||||
val actualBg = iobCobCalculator.ads.actualBg()
|
val actualBg = iobCobCalculator.ads.actualBg()
|
||||||
val profile = profileFunction.getProfile()
|
val profile = profileFunction.getProfile()
|
||||||
val profileName = profileFunction.getProfileName()
|
val profileName = profileFunction.getProfileName()
|
||||||
val pump = activePlugin.activePump
|
|
||||||
val quickWizardEntry = quickWizard.get(guid)
|
val quickWizardEntry = quickWizard.get(guid)
|
||||||
Log.i("QuickWizard", "handleInitiate: quick_wizard " + quickWizardEntry?.buttonText() + " c " + quickWizardEntry?.carbs())
|
Log.i("QuickWizard", "handleInitiate: quick_wizard " + quickWizardEntry?.buttonText() + " c " + quickWizardEntry?.carbs())
|
||||||
if (quickWizardEntry != null && actualBg != null && profile != null) {
|
if (quickWizardEntry == null) {
|
||||||
// Logic related from Overview.kt
|
sendError(rh.gs(R.string.quick_wizard_not_available))
|
||||||
val wizard = quickWizardEntry.doCalc(profile, profileName, actualBg, true)
|
|
||||||
if (wizard.calculatedTotalInsulin > 0.0 && quickWizardEntry.carbs() > 0.0) {
|
|
||||||
val carbsAfterConstraints = constraintChecker.applyCarbsConstraints(Constraint(quickWizardEntry.carbs())).value()
|
|
||||||
val insulinAfterConstraints = wizard.insulinAfterConstraints
|
|
||||||
if (abs(insulinAfterConstraints - wizard.calculatedTotalInsulin) >= pump.pumpDescription.pumpType.determineCorrectBolusStepSize(insulinAfterConstraints) || carbsAfterConstraints != quickWizardEntry.carbs()) {
|
|
||||||
// TODO check error is correct
|
|
||||||
sendError(rh.gs(R.string.constraints_violation) + "\n" + rh.gs(R.string.changeyourinput))
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if (actualBg == null) {
|
||||||
|
sendError(rh.gs(R.string.wizard_no_actual_bg))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (profile == null) {
|
||||||
|
sendError(rh.gs(R.string.wizard_no_active_profile))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
val cobInfo = iobCobCalculator.getCobInfo(false, "QuickWizard wear")
|
||||||
|
if (cobInfo.displayCob == null) {
|
||||||
|
sendError(rh.gs(R.string.wizard_no_cob))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
val pump = activePlugin.activePump
|
||||||
|
if (!pump.isInitialized() || pump.isSuspended() || loop.isDisconnected) {
|
||||||
|
sendError(rh.gs(R.string.wizard_pump_not_available))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
val wizard = quickWizardEntry.doCalc(profile, profileName, actualBg, true)
|
||||||
|
|
||||||
|
val carbsAfterConstraints = constraintChecker.applyCarbsConstraints(Constraint(quickWizardEntry.carbs())).value()
|
||||||
|
if (carbsAfterConstraints != quickWizardEntry.carbs()) {
|
||||||
|
sendError(rh.gs(R.string.wizard_carbs_constraint))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
val insulinAfterConstraints = wizard.insulinAfterConstraints
|
||||||
|
val minStep = pump.pumpDescription.pumpType.determineCorrectBolusStepSize(insulinAfterConstraints)
|
||||||
|
if (abs(insulinAfterConstraints - wizard.calculatedTotalInsulin) >= minStep) {
|
||||||
|
sendError(rh.gs(R.string.wizard_constraint_bolus_size, wizard.calculatedTotalInsulin))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
rMessage = rh.gs(R.string.quick_wizard_message, quickWizardEntry.buttonText(), wizard.calculatedTotalInsulin, quickWizardEntry.carbs())
|
rMessage = rh.gs(R.string.quick_wizard_message, quickWizardEntry.buttonText(), wizard.calculatedTotalInsulin, quickWizardEntry.carbs())
|
||||||
rAction = "bolus $insulinAfterConstraints $carbsAfterConstraints"
|
rAction = "bolus $insulinAfterConstraints $carbsAfterConstraints"
|
||||||
Log.i("QuickWizard", "handleInitiate: quick_wizard action=$rAction")
|
Log.i("QuickWizard", "handleInitiate: quick_wizard action=$rAction")
|
||||||
} else {
|
|
||||||
sendError(rh.gs(R.string.quick_wizard_no_action))
|
rMessage += "\n_____________"
|
||||||
}
|
rMessage += "\n" + wizard.explainShort()
|
||||||
} else {
|
|
||||||
sendError(rh.gs(R.string.quick_wizard_can_not_calculate))
|
|
||||||
}
|
|
||||||
} else if ("opencpp" == act[0]) {
|
} else if ("opencpp" == act[0]) {
|
||||||
val activeProfileSwitch = repository.getEffectiveProfileSwitchActiveAt(dateUtil.now()).blockingGet()
|
val activeProfileSwitch = repository.getEffectiveProfileSwitchActiveAt(dateUtil.now()).blockingGet()
|
||||||
if (activeProfileSwitch is ValueWrapper.Existing) { // read CPP values
|
if (activeProfileSwitch is ValueWrapper.Existing) { // read CPP values
|
||||||
|
@ -401,7 +429,7 @@ class ActionStringHandler @Inject constructor(
|
||||||
wearPlugin.requestNotificationCancel(rAction)
|
wearPlugin.requestNotificationCancel(rAction)
|
||||||
return
|
return
|
||||||
} else {
|
} else {
|
||||||
sendError("Unknown action command: " + act[0] )
|
sendError(rh.gs(R.string.wear_unknown_action_string) + act[0])
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// send result
|
// send result
|
||||||
|
@ -639,23 +667,27 @@ class ActionStringHandler @Inject constructor(
|
||||||
|
|
||||||
private fun generateTempTarget(duration: Int, low: Double, high: Double) {
|
private fun generateTempTarget(duration: Int, low: Double, high: Double) {
|
||||||
if (duration != 0) {
|
if (duration != 0) {
|
||||||
disposable += repository.runTransactionForResult(InsertAndCancelCurrentTemporaryTargetTransaction(
|
disposable += repository.runTransactionForResult(
|
||||||
|
InsertAndCancelCurrentTemporaryTargetTransaction(
|
||||||
timestamp = System.currentTimeMillis(),
|
timestamp = System.currentTimeMillis(),
|
||||||
duration = TimeUnit.MINUTES.toMillis(duration.toLong()),
|
duration = TimeUnit.MINUTES.toMillis(duration.toLong()),
|
||||||
reason = TemporaryTarget.Reason.WEAR,
|
reason = TemporaryTarget.Reason.WEAR,
|
||||||
lowTarget = Profile.toMgdl(low, profileFunction.getUnits()),
|
lowTarget = Profile.toMgdl(low, profileFunction.getUnits()),
|
||||||
highTarget = Profile.toMgdl(high, profileFunction.getUnits())
|
highTarget = Profile.toMgdl(high, profileFunction.getUnits())
|
||||||
)).subscribe({ result ->
|
)
|
||||||
|
).subscribe({ result ->
|
||||||
result.inserted.forEach { aapsLogger.debug(LTag.DATABASE, "Inserted temp target $it") }
|
result.inserted.forEach { aapsLogger.debug(LTag.DATABASE, "Inserted temp target $it") }
|
||||||
result.updated.forEach { aapsLogger.debug(LTag.DATABASE, "Updated temp target $it") }
|
result.updated.forEach { aapsLogger.debug(LTag.DATABASE, "Updated temp target $it") }
|
||||||
}, {
|
}, {
|
||||||
aapsLogger.error(LTag.DATABASE, "Error while saving temporary target", it)
|
aapsLogger.error(LTag.DATABASE, "Error while saving temporary target", it)
|
||||||
})
|
})
|
||||||
uel.log(Action.TT, Sources.Wear,
|
uel.log(
|
||||||
|
Action.TT, Sources.Wear,
|
||||||
ValueWithUnit.TherapyEventTTReason(TemporaryTarget.Reason.WEAR),
|
ValueWithUnit.TherapyEventTTReason(TemporaryTarget.Reason.WEAR),
|
||||||
ValueWithUnit.fromGlucoseUnit(low, profileFunction.getUnits().asText),
|
ValueWithUnit.fromGlucoseUnit(low, profileFunction.getUnits().asText),
|
||||||
ValueWithUnit.fromGlucoseUnit(high, profileFunction.getUnits().asText).takeIf { low != high },
|
ValueWithUnit.fromGlucoseUnit(high, profileFunction.getUnits().asText).takeIf { low != high },
|
||||||
ValueWithUnit.Minute(duration))
|
ValueWithUnit.Minute(duration)
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
disposable += repository.runTransactionForResult(CancelCurrentTemporaryTargetIfAnyTransaction(System.currentTimeMillis()))
|
disposable += repository.runTransactionForResult(CancelCurrentTemporaryTargetIfAnyTransaction(System.currentTimeMillis()))
|
||||||
.subscribe({ result ->
|
.subscribe({ result ->
|
||||||
|
@ -663,8 +695,10 @@ class ActionStringHandler @Inject constructor(
|
||||||
}, {
|
}, {
|
||||||
aapsLogger.error(LTag.DATABASE, "Error while saving temporary target", it)
|
aapsLogger.error(LTag.DATABASE, "Error while saving temporary target", it)
|
||||||
})
|
})
|
||||||
uel.log(Action.CANCEL_TT, Sources.Wear,
|
uel.log(
|
||||||
ValueWithUnit.TherapyEventTTReason(TemporaryTarget.Reason.WEAR))
|
Action.CANCEL_TT, Sources.Wear,
|
||||||
|
ValueWithUnit.TherapyEventTTReason(TemporaryTarget.Reason.WEAR)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -677,9 +711,11 @@ class ActionStringHandler @Inject constructor(
|
||||||
commandQueue.bolus(detailedBolusInfo, object : Callback() {
|
commandQueue.bolus(detailedBolusInfo, object : Callback() {
|
||||||
override fun run() {
|
override fun run() {
|
||||||
if (!result.success) {
|
if (!result.success) {
|
||||||
sendError(rh.gs(R.string.treatmentdeliveryerror) +
|
sendError(
|
||||||
|
rh.gs(R.string.treatmentdeliveryerror) +
|
||||||
"\n" +
|
"\n" +
|
||||||
result.comment)
|
result.comment
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -714,9 +750,11 @@ class ActionStringHandler @Inject constructor(
|
||||||
commandQueue.bolus(detailedBolusInfo, object : Callback() {
|
commandQueue.bolus(detailedBolusInfo, object : Callback() {
|
||||||
override fun run() {
|
override fun run() {
|
||||||
if (!result.success) {
|
if (!result.success) {
|
||||||
sendError(rh.gs(R.string.treatmentdeliveryerror) +
|
sendError(
|
||||||
|
rh.gs(R.string.treatmentdeliveryerror) +
|
||||||
"\n" +
|
"\n" +
|
||||||
result.comment)
|
result.comment
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -18,6 +18,8 @@ import info.nightscout.androidaps.database.entities.ValueWithUnit
|
||||||
import info.nightscout.androidaps.database.transactions.InsertOrUpdateBolusCalculatorResultTransaction
|
import info.nightscout.androidaps.database.transactions.InsertOrUpdateBolusCalculatorResultTransaction
|
||||||
import info.nightscout.androidaps.events.EventRefreshOverview
|
import info.nightscout.androidaps.events.EventRefreshOverview
|
||||||
import info.nightscout.androidaps.extensions.formatColor
|
import info.nightscout.androidaps.extensions.formatColor
|
||||||
|
import info.nightscout.androidaps.extensions.highValueToUnitsToString
|
||||||
|
import info.nightscout.androidaps.extensions.lowValueToUnitsToString
|
||||||
import info.nightscout.androidaps.interfaces.*
|
import info.nightscout.androidaps.interfaces.*
|
||||||
import info.nightscout.shared.logging.AAPSLogger
|
import info.nightscout.shared.logging.AAPSLogger
|
||||||
import info.nightscout.shared.logging.LTag
|
import info.nightscout.shared.logging.LTag
|
||||||
|
@ -135,7 +137,8 @@ class BolusWizard @Inject constructor(
|
||||||
private var quickWizard: Boolean = true
|
private var quickWizard: Boolean = true
|
||||||
var usePercentage: Boolean = false
|
var usePercentage: Boolean = false
|
||||||
|
|
||||||
fun doCalc(profile: Profile,
|
fun doCalc(
|
||||||
|
profile: Profile,
|
||||||
profileName: String,
|
profileName: String,
|
||||||
tempTarget: TemporaryTarget?,
|
tempTarget: TemporaryTarget?,
|
||||||
carbs: Int,
|
carbs: Int,
|
||||||
|
@ -314,7 +317,9 @@ class BolusWizard @Inject constructor(
|
||||||
actions.add(rh.gs(R.string.carbs) + ": " + rh.gs(R.string.format_carbs, carbs).formatColor(rh, R.color.carbs) + timeShift)
|
actions.add(rh.gs(R.string.carbs) + ": " + rh.gs(R.string.format_carbs, carbs).formatColor(rh, R.color.carbs) + timeShift)
|
||||||
}
|
}
|
||||||
if (insulinFromCOB > 0) {
|
if (insulinFromCOB > 0) {
|
||||||
actions.add(rh.gs(R.string.cobvsiob) + ": " + rh.gs(R.string.formatsignedinsulinunits, insulinFromBolusIOB + insulinFromBasalIOB + insulinFromCOB + insulinFromBG).formatColor(rh, R.color.cobAlert))
|
actions.add(
|
||||||
|
rh.gs(R.string.cobvsiob) + ": " + rh.gs(R.string.formatsignedinsulinunits, insulinFromBolusIOB + insulinFromBasalIOB + insulinFromCOB + insulinFromBG).formatColor(rh, R.color.cobAlert)
|
||||||
|
)
|
||||||
val absorptionRate = iobCobCalculator.ads.slowAbsorptionPercentage(60)
|
val absorptionRate = iobCobCalculator.ads.slowAbsorptionPercentage(60)
|
||||||
if (absorptionRate > .25)
|
if (absorptionRate > .25)
|
||||||
actions.add(rh.gs(R.string.slowabsorptiondetected, rh.gc(R.color.cobAlert), (absorptionRate * 100).toInt()))
|
actions.add(rh.gs(R.string.slowabsorptiondetected, rh.gc(R.color.cobAlert), (absorptionRate * 100).toInt()))
|
||||||
|
@ -367,10 +372,13 @@ class BolusWizard @Inject constructor(
|
||||||
carbTime = 0
|
carbTime = 0
|
||||||
bolusCalculatorResult = createBolusCalculatorResult()
|
bolusCalculatorResult = createBolusCalculatorResult()
|
||||||
notes = this@BolusWizard.notes
|
notes = this@BolusWizard.notes
|
||||||
uel.log(Action.BOLUS_ADVISOR, if (quickWizard) Sources.QuickWizard else Sources.WizardDialog,
|
uel.log(
|
||||||
|
Action.BOLUS_ADVISOR,
|
||||||
|
if (quickWizard) Sources.QuickWizard else Sources.WizardDialog,
|
||||||
notes,
|
notes,
|
||||||
ValueWithUnit.TherapyEventType(eventType.toDBbEventType()),
|
ValueWithUnit.TherapyEventType(eventType.toDBbEventType()),
|
||||||
ValueWithUnit.Insulin(insulinAfterConstraints))
|
ValueWithUnit.Insulin(insulinAfterConstraints)
|
||||||
|
)
|
||||||
if (insulin > 0) {
|
if (insulin > 0) {
|
||||||
commandQueue.bolus(this, object : Callback() {
|
commandQueue.bolus(this, object : Callback() {
|
||||||
override fun run() {
|
override fun run() {
|
||||||
|
@ -385,6 +393,26 @@ class BolusWizard @Inject constructor(
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun explainShort(): String {
|
||||||
|
var message = rh.gs(R.string.wizard_explain_calc, ic, sens)
|
||||||
|
message += "\n" + rh.gs(R.string.wizard_explain_carbs, insulinFromCarbs)
|
||||||
|
if (useTT && tempTarget != null) {
|
||||||
|
val tt = if (tempTarget?.lowTarget == tempTarget?.highTarget) tempTarget?.lowValueToUnitsToString(profile.units)
|
||||||
|
else rh.gs(R.string.wizard_explain_tt_to, tempTarget?.lowValueToUnitsToString(profile.units), tempTarget?.highValueToUnitsToString(profile.units))
|
||||||
|
message += "\n" + rh.gs(R.string.wizard_explain_tt, tt)
|
||||||
|
}
|
||||||
|
if (useCob) message += "\n" + rh.gs(R.string.wizard_explain_cob, cob, insulinFromCOB)
|
||||||
|
if (useBg) message += "\n" + rh.gs(R.string.wizard_explain_bg, insulinFromBG)
|
||||||
|
if (includeBolusIOB) message += "\n" + rh.gs(R.string.wizard_explain_bolus_iob, insulinFromBolusIOB)
|
||||||
|
if (includeBasalIOB) message += "\n" + rh.gs(R.string.wizard_explain_basal_iob, insulinFromBasalIOB)
|
||||||
|
if (usePercentage) message += "\n" + rh.gs(R.string.wizard_explain_trend, insulinFromTrend)
|
||||||
|
if (useSuperBolus) message += "\n" + rh.gs(R.string.wizard_explain_superbolus, insulinFromSuperBolus)
|
||||||
|
if (usePercentage) {
|
||||||
|
message += "\n" + rh.gs(R.string.wizard_explain_percent, totalBeforePercentageAdjustment, percentageCorrection, calculatedTotalInsulin)
|
||||||
|
}
|
||||||
|
return message
|
||||||
|
}
|
||||||
|
|
||||||
private fun commonProcessing(ctx: Context) {
|
private fun commonProcessing(ctx: Context) {
|
||||||
val profile = profileFunction.getProfile() ?: return
|
val profile = profileFunction.getProfile() ?: return
|
||||||
val pump = activePlugin.activePump
|
val pump = activePlugin.activePump
|
||||||
|
|
|
@ -1175,9 +1175,26 @@
|
||||||
<string name="wear_action_tempt_manual_range_message">Temptarget:\nMin: %1$s\nMax: %2$s\nDuration: %3$s</string>
|
<string name="wear_action_tempt_manual_range_message">Temptarget:\nMin: %1$s\nMax: %2$s\nDuration: %3$s</string>
|
||||||
<string name="wear_action_tempt_manual_message">Temptarget:\nTarget: %1$s\nDuration: %2$s</string>
|
<string name="wear_action_tempt_manual_message">Temptarget:\nTarget: %1$s\nDuration: %2$s</string>
|
||||||
<string name="wear_action_tempt_preset_message">Temptarget:\Reason: %1$s\nTarget: %2$s\nDuration: %3$s</string>
|
<string name="wear_action_tempt_preset_message">Temptarget:\Reason: %1$s\nTarget: %2$s\nDuration: %3$s</string>
|
||||||
<string name="quick_wizard_no_action">No insulin needed nor are carbs added.</string>
|
|
||||||
<string name="quick_wizard_can_not_calculate">Can not calculate wizard, requires actual blood glucose and active profile.</string>
|
|
||||||
<string name="quick_wizard_message">QuickWizard: %1$s\nInsulin: %2$.2fU\nCarbs: %3$dg</string>
|
<string name="quick_wizard_message">QuickWizard: %1$s\nInsulin: %2$.2fU\nCarbs: %3$dg</string>
|
||||||
|
<string name="wizard_result">Calc. Wizard:\nInsulin: %1$.2fU\nCarbs: %2$dg</string>
|
||||||
<string name="overview_editquickwizard_show_on_device">Show entry on device:</string>
|
<string name="overview_editquickwizard_show_on_device">Show entry on device:</string>
|
||||||
|
<string name="quick_wizard_not_available">Selected quickwizard no longer available, please refresh your tile</string>
|
||||||
|
<string name="wizard_no_actual_bg">No recent BG to base calculation on!</string>
|
||||||
|
<string name="wizard_no_active_profile">No active profile set!</string>
|
||||||
|
<string name="wizard_no_cob">Unknown COB! BG reading missing or recent app restart?</string>
|
||||||
|
<string name="wizard_carbs_constraint">Carb constraint violation!</string>
|
||||||
|
<string name="wizard_explain_calc">Calc (IC: %2$.1f, ISF: %2$.1f) from:"</string>
|
||||||
|
<string name="wizard_explain_carbs">Carbs: %1$.2fU</string>
|
||||||
|
<string name="wizard_explain_cob">COB: %1$.0fg %2$.2fU</string>
|
||||||
|
<string name="wizard_explain_bg">BG: %1$.2fU</string>
|
||||||
|
<string name="wizard_explain_basal_iob">Basal IOB: %1$.2fU</string>
|
||||||
|
<string name="wizard_explain_bolus_iob">Bolus IOB: %1$.2fU</string>
|
||||||
|
<string name="wizard_explain_superbolus">Superbolus: %1$.2fU</string>
|
||||||
|
<string name="wizard_explain_trend">15\' trend: %1$.2fU</string>
|
||||||
|
<string name="wizard_explain_percent">Perctage: %1$.2fU x %2$d% = %3$.2fU</string>
|
||||||
|
<string name="wizard_constraint_bolus_size">Insulin constraint violation!\nCannot deliver %1$.2fU</string>
|
||||||
|
<string name="wizard_explain_tt">TempT: %1$s</string>
|
||||||
|
<string name="wizard_explain_tt_to">%1$s to %2$s</string>
|
||||||
|
<string name="wizard_pump_not_available">No pump available!</string>
|
||||||
|
<string name="wear_unknown_action_string">Unknown action command:</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -8,7 +8,7 @@ import info.nightscout.androidaps.interaction.actions.ECarbActivity
|
||||||
import info.nightscout.androidaps.interaction.actions.TempTargetActivity
|
import info.nightscout.androidaps.interaction.actions.TempTargetActivity
|
||||||
import info.nightscout.androidaps.interaction.actions.WizardActivity
|
import info.nightscout.androidaps.interaction.actions.WizardActivity
|
||||||
|
|
||||||
object ActionSource : StaticTileSource(), TileSource {
|
object ActionSource : StaticTileSource() {
|
||||||
|
|
||||||
override val preferencePrefix = "tile_action_"
|
override val preferencePrefix = "tile_action_"
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,6 @@ object QuickWizardSource : TileSource {
|
||||||
val validFrom = quick.getInt("from", 0)
|
val validFrom = quick.getInt("from", 0)
|
||||||
val validTo = quick.getInt("to", 0)
|
val validTo = quick.getInt("to", 0)
|
||||||
val isActive = sfm in validFrom..validTo
|
val isActive = sfm in validFrom..validTo
|
||||||
// use from and to to schedule new update for timeline, for now just refresh every minute
|
|
||||||
val guid = quick.getString("guid", "")
|
val guid = quick.getString("guid", "")
|
||||||
if (isActive && guid != "") {
|
if (isActive && guid != "") {
|
||||||
quickList.add(
|
quickList.add(
|
||||||
|
@ -44,6 +43,36 @@ object QuickWizardSource : TileSource {
|
||||||
return quickList
|
return quickList
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun getValidFor(context: Context): Long? {
|
||||||
|
val quickMap = getDataMap(context)
|
||||||
|
if (quickMap.size == 0) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
val sfm = secondsFromMidnight()
|
||||||
|
var validTill = 24 * 60 * 60
|
||||||
|
|
||||||
|
for (quick in quickMap) {
|
||||||
|
val validFrom = quick.getInt("from", 0)
|
||||||
|
val validTo = quick.getInt("to", 0)
|
||||||
|
val isActive = sfm in validFrom..validTo
|
||||||
|
val guid = quick.getString("guid", "")
|
||||||
|
Log.i(TAG, "valid: " + validFrom + "-" + validTo)
|
||||||
|
if (guid != "") {
|
||||||
|
if (isActive && validTill > validTo) {
|
||||||
|
validTill = validTo
|
||||||
|
}
|
||||||
|
if (validFrom > sfm && validTill > validFrom) {
|
||||||
|
validTill = validFrom
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val validWithin = 60
|
||||||
|
val delta = (validTill - sfm + validWithin) * 1000L
|
||||||
|
Log.i(TAG, "getValidTill: sfm" + sfm + " till" + validTill + " d=" + delta)
|
||||||
|
return delta
|
||||||
|
}
|
||||||
|
|
||||||
private fun getDataMap(context: Context): ArrayList<DataMap> {
|
private fun getDataMap(context: Context): ArrayList<DataMap> {
|
||||||
val sharedPrefs = PreferenceManager.getDefaultSharedPreferences(context)
|
val sharedPrefs = PreferenceManager.getDefaultSharedPreferences(context)
|
||||||
val key = context.resources.getString(R.string.key_quick_wizard_data_map)
|
val key = context.resources.getString(R.string.key_quick_wizard_data_map)
|
||||||
|
|
|
@ -16,14 +16,14 @@ class StaticAction(
|
||||||
message: String? = null,
|
message: String? = null,
|
||||||
) : Action(buttonText, buttonTextSub, activityClass, iconRes, actionString, message)
|
) : Action(buttonText, buttonTextSub, activityClass, iconRes, actionString, message)
|
||||||
|
|
||||||
abstract class StaticTileSource {
|
abstract class StaticTileSource : TileSource {
|
||||||
|
|
||||||
abstract fun getActions(resources: Resources): List<StaticAction>
|
abstract fun getActions(resources: Resources): List<StaticAction>
|
||||||
|
|
||||||
abstract val preferencePrefix: String
|
abstract val preferencePrefix: String
|
||||||
abstract fun getDefaultConfig(): Map<String, String>
|
abstract fun getDefaultConfig(): Map<String, String>
|
||||||
|
|
||||||
open fun getSelectedActions(context: Context): List<Action> {
|
override fun getSelectedActions(context: Context): List<Action> {
|
||||||
val sharedPrefs = PreferenceManager.getDefaultSharedPreferences(context)
|
val sharedPrefs = PreferenceManager.getDefaultSharedPreferences(context)
|
||||||
setDefaultSettings(sharedPrefs)
|
setDefaultSettings(sharedPrefs)
|
||||||
|
|
||||||
|
@ -40,12 +40,14 @@ abstract class StaticTileSource {
|
||||||
return actionList
|
return actionList
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun getValidFor(context: Context): Long? = null
|
||||||
|
|
||||||
private fun getActionFromPreference(resources: Resources, sharedPrefs: SharedPreferences, index: Int): Action? {
|
private fun getActionFromPreference(resources: Resources, sharedPrefs: SharedPreferences, index: Int): Action? {
|
||||||
val actionPref = sharedPrefs.getString(preferencePrefix + index, "none")
|
val actionPref = sharedPrefs.getString(preferencePrefix + index, "none")
|
||||||
return getActions(resources).find { action -> action.settingName == actionPref }
|
return getActions(resources).find { action -> action.settingName == actionPref }
|
||||||
}
|
}
|
||||||
|
|
||||||
open fun setDefaultSettings(sharedPrefs: SharedPreferences) {
|
private fun setDefaultSettings(sharedPrefs: SharedPreferences) {
|
||||||
val defaults = getDefaultConfig()
|
val defaults = getDefaultConfig()
|
||||||
val firstKey = defaults.firstNotNullOf { settings -> settings.key }
|
val firstKey = defaults.firstNotNullOf { settings -> settings.key }
|
||||||
if (!sharedPrefs.contains(firstKey)) {
|
if (!sharedPrefs.contains(firstKey)) {
|
||||||
|
@ -56,4 +58,5 @@ abstract class StaticTileSource {
|
||||||
editor.apply()
|
editor.apply()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,8 @@ import info.nightscout.androidaps.R
|
||||||
import info.nightscout.androidaps.interaction.actions.BackgroundActionActivity
|
import info.nightscout.androidaps.interaction.actions.BackgroundActionActivity
|
||||||
import info.nightscout.androidaps.interaction.actions.TempTargetActivity
|
import info.nightscout.androidaps.interaction.actions.TempTargetActivity
|
||||||
|
|
||||||
object TempTargetSource : StaticTileSource(), TileSource {
|
object TempTargetSource : StaticTileSource() {
|
||||||
|
|
||||||
override val preferencePrefix = "tile_tempt_"
|
override val preferencePrefix = "tile_tempt_"
|
||||||
|
|
||||||
override fun getActions(resources: Resources): List<StaticAction> {
|
override fun getActions(resources: Resources): List<StaticAction> {
|
||||||
|
|
|
@ -45,6 +45,7 @@ interface TileSource {
|
||||||
|
|
||||||
fun getResourceReferences(resources: android.content.res.Resources): List<Int>
|
fun getResourceReferences(resources: android.content.res.Resources): List<Int>
|
||||||
fun getSelectedActions(context: Context): List<Action>
|
fun getSelectedActions(context: Context): List<Action>
|
||||||
|
fun getValidFor(context: Context): Long?
|
||||||
}
|
}
|
||||||
|
|
||||||
open class Action(
|
open class Action(
|
||||||
|
@ -73,8 +74,7 @@ abstract class TileBase : TileService() {
|
||||||
): ListenableFuture<Tile> = serviceScope.future {
|
): ListenableFuture<Tile> = serviceScope.future {
|
||||||
val actionsSelected = getSelectedActions()
|
val actionsSelected = getSelectedActions()
|
||||||
val wearControl = getWearControl()
|
val wearControl = getWearControl()
|
||||||
|
val tile = Tile.Builder()
|
||||||
Tile.Builder()
|
|
||||||
.setResourcesVersion(resourceVersion)
|
.setResourcesVersion(resourceVersion)
|
||||||
.setTimeline(
|
.setTimeline(
|
||||||
Timeline.Builder().addTimelineEntry(
|
Timeline.Builder().addTimelineEntry(
|
||||||
|
@ -83,7 +83,12 @@ abstract class TileBase : TileService() {
|
||||||
).build()
|
).build()
|
||||||
).build()
|
).build()
|
||||||
)
|
)
|
||||||
.build()
|
|
||||||
|
val validFor = validFor()
|
||||||
|
if (validFor != null) {
|
||||||
|
tile.setFreshnessIntervalMillis(validFor)
|
||||||
|
}
|
||||||
|
tile.build()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getSelectedActions(): List<Action> {
|
private fun getSelectedActions(): List<Action> {
|
||||||
|
@ -91,6 +96,10 @@ abstract class TileBase : TileService() {
|
||||||
return source.getSelectedActions(this)
|
return source.getSelectedActions(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun validFor(): Long? {
|
||||||
|
return source.getValidFor(this)
|
||||||
|
}
|
||||||
|
|
||||||
@RequiresApi(Build.VERSION_CODES.N)
|
@RequiresApi(Build.VERSION_CODES.N)
|
||||||
override fun onResourcesRequest(
|
override fun onResourcesRequest(
|
||||||
requestParams: ResourcesRequest
|
requestParams: ResourcesRequest
|
||||||
|
|
Loading…
Reference in a new issue