Bolus advisor

This commit is contained in:
Milos Kozak 2020-12-28 16:42:00 +01:00
parent 4238e9cab3
commit c8f7dae2c8
17 changed files with 602 additions and 310 deletions

View file

@ -18,6 +18,7 @@ import info.nightscout.androidaps.Constants
import info.nightscout.androidaps.MainApp import info.nightscout.androidaps.MainApp
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.data.Profile import info.nightscout.androidaps.data.Profile
import info.nightscout.androidaps.databinding.DialogWizardBinding
import info.nightscout.androidaps.db.BgReading import info.nightscout.androidaps.db.BgReading
import info.nightscout.androidaps.interfaces.ActivePluginProvider import info.nightscout.androidaps.interfaces.ActivePluginProvider
import info.nightscout.androidaps.interfaces.Constraint import info.nightscout.androidaps.interfaces.Constraint
@ -39,7 +40,6 @@ import info.nightscout.androidaps.utils.sharedPreferences.SP
import info.nightscout.androidaps.utils.wizard.BolusWizard import info.nightscout.androidaps.utils.wizard.BolusWizard
import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable import io.reactivex.disposables.CompositeDisposable
import kotlinx.android.synthetic.main.dialog_wizard.*
import java.text.DecimalFormat import java.text.DecimalFormat
import java.util.* import java.util.*
import javax.inject.Inject import javax.inject.Inject
@ -72,8 +72,23 @@ class WizardDialog : DaggerDialogFragment() {
} }
} }
private val timeTextWatcher = object : TextWatcher {
override fun afterTextChanged(s: Editable) {}
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {}
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
calculateInsulin()
binding.alarm.isChecked = binding.carbTimeInput.value > 0
}
}
private var disposable: CompositeDisposable = CompositeDisposable() private var disposable: CompositeDisposable = CompositeDisposable()
private var _binding: DialogWizardBinding? = null
// This property is only valid between onCreateView and
// onDestroyView.
private val binding get() = _binding!!
override fun onStart() { override fun onStart() {
super.onStart() super.onStart()
dialog?.window?.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT) dialog?.window?.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
@ -81,49 +96,50 @@ class WizardDialog : DaggerDialogFragment() {
override fun onSaveInstanceState(savedInstanceState: Bundle) { override fun onSaveInstanceState(savedInstanceState: Bundle) {
super.onSaveInstanceState(savedInstanceState) super.onSaveInstanceState(savedInstanceState)
savedInstanceState.putDouble("treatments_wizard_bg_input", treatments_wizard_bg_input.value) savedInstanceState.putDouble("bg_input", binding.bgInput.value)
savedInstanceState.putDouble("treatments_wizard_carbs_input", treatments_wizard_carbs_input.value) savedInstanceState.putDouble("carbs_input", binding.carbsInput.value)
savedInstanceState.putDouble("treatments_wizard_correction_input", treatments_wizard_correction_input.value) savedInstanceState.putDouble("correction_input", binding.correctionInput.value)
savedInstanceState.putDouble("treatments_wizard_carb_time_input", treatments_wizard_carb_time_input.value) savedInstanceState.putDouble("carb_time_input", binding.carbTimeInput.value)
} }
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? { savedInstanceState: Bundle?): View {
dialog?.window?.requestFeature(Window.FEATURE_NO_TITLE) dialog?.window?.requestFeature(Window.FEATURE_NO_TITLE)
dialog?.window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN) dialog?.window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN)
isCancelable = true isCancelable = true
dialog?.setCanceledOnTouchOutside(false) dialog?.setCanceledOnTouchOutside(false)
return inflater.inflate(R.layout.dialog_wizard, container, false) _binding = DialogWizardBinding.inflate(inflater, container, false)
return binding.root
} }
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
loadCheckedStates() loadCheckedStates()
processCobCheckBox() processCobCheckBox()
treatments_wizard_sbcheckbox.visibility = sp.getBoolean(R.string.key_usesuperbolus, false).toVisibility() binding.sbcheckbox.visibility = sp.getBoolean(R.string.key_usesuperbolus, false).toVisibility()
treatments_wizard_notes_layout.visibility = sp.getBoolean(R.string.key_show_notes_entry_dialogs, false).toVisibility() binding.notesLayout.visibility = sp.getBoolean(R.string.key_show_notes_entry_dialogs, false).toVisibility()
val maxCarbs = constraintChecker.getMaxCarbsAllowed().value() val maxCarbs = constraintChecker.getMaxCarbsAllowed().value()
val maxCorrection = constraintChecker.getMaxBolusAllowed().value() val maxCorrection = constraintChecker.getMaxBolusAllowed().value()
if (profileFunction.getUnits() == Constants.MGDL) if (profileFunction.getUnits() == Constants.MGDL)
treatments_wizard_bg_input.setParams(savedInstanceState?.getDouble("treatments_wizard_bg_input") binding.bgInput.setParams(savedInstanceState?.getDouble("bg_input")
?: 0.0, 0.0, 500.0, 1.0, DecimalFormat("0"), false, ok, textWatcher) ?: 0.0, 0.0, 500.0, 1.0, DecimalFormat("0"), false, binding.ok, timeTextWatcher)
else else
treatments_wizard_bg_input.setParams(savedInstanceState?.getDouble("treatments_wizard_bg_input") binding.bgInput.setParams(savedInstanceState?.getDouble("bg_input")
?: 0.0, 0.0, 30.0, 0.1, DecimalFormat("0.0"), false, ok, textWatcher) ?: 0.0, 0.0, 30.0, 0.1, DecimalFormat("0.0"), false, binding.ok, textWatcher)
treatments_wizard_carbs_input.setParams(savedInstanceState?.getDouble("treatments_wizard_carbs_input") binding.carbsInput.setParams(savedInstanceState?.getDouble("carbs_input")
?: 0.0, 0.0, maxCarbs.toDouble(), 1.0, DecimalFormat("0"), false, 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
treatments_wizard_correction_input.setParams(savedInstanceState?.getDouble("treatments_wizard_correction_input") binding.correctionInput.setParams(savedInstanceState?.getDouble("correction_input")
?: 0.0, -maxCorrection, maxCorrection, bolusStep, DecimalFormatter.pumpSupportedBolusFormat(activePlugin.activePump), false, ok, textWatcher) ?: 0.0, -maxCorrection, maxCorrection, bolusStep, DecimalFormatter.pumpSupportedBolusFormat(activePlugin.activePump), false, binding.ok, textWatcher)
treatments_wizard_carb_time_input.setParams(savedInstanceState?.getDouble("treatments_wizard_carb_time_input") binding.carbTimeInput.setParams(savedInstanceState?.getDouble("carb_time_input")
?: 0.0, -60.0, 60.0, 5.0, DecimalFormat("0"), false, ok, textWatcher) ?: 0.0, -60.0, 60.0, 5.0, DecimalFormat("0"), false, binding.ok, timeTextWatcher)
initDialog() initDialog()
treatments_wizard_percent_used.text = resourceHelper.gs(R.string.format_percent, sp.getInt(R.string.key_boluswizard_percentage, 100)) binding.percentUsed.text = resourceHelper.gs(R.string.format_percent, sp.getInt(R.string.key_boluswizard_percentage, 100))
// ok button // ok button
ok.setOnClickListener { binding.ok.setOnClickListener {
if (okClicked) { if (okClicked) {
aapsLogger.debug(LTag.UI, "guarding: ok already clicked") aapsLogger.debug(LTag.UI, "guarding: ok already clicked")
} else { } else {
@ -136,37 +152,37 @@ class WizardDialog : DaggerDialogFragment() {
dismiss() dismiss()
} }
// cancel button // cancel button
cancel.setOnClickListener { dismiss() } binding.cancel.setOnClickListener { dismiss() }
// checkboxes // checkboxes
treatments_wizard_bgcheckbox.setOnCheckedChangeListener(::onCheckedChanged) binding.bgcheckbox.setOnCheckedChangeListener(::onCheckedChanged)
treatments_wizard_ttcheckbox.setOnCheckedChangeListener(::onCheckedChanged) binding.ttcheckbox.setOnCheckedChangeListener(::onCheckedChanged)
treatments_wizard_cobcheckbox.setOnCheckedChangeListener(::onCheckedChanged) binding.cobcheckbox.setOnCheckedChangeListener(::onCheckedChanged)
treatments_wizard_basaliobcheckbox.setOnCheckedChangeListener(::onCheckedChanged) binding.basaliobcheckbox.setOnCheckedChangeListener(::onCheckedChanged)
treatments_wizard_bolusiobcheckbox.setOnCheckedChangeListener(::onCheckedChanged) binding.bolusiobcheckbox.setOnCheckedChangeListener(::onCheckedChanged)
treatments_wizard_bgtrendcheckbox.setOnCheckedChangeListener(::onCheckedChanged) binding.bgtrendcheckbox.setOnCheckedChangeListener(::onCheckedChanged)
treatments_wizard_sbcheckbox.setOnCheckedChangeListener(::onCheckedChanged) binding.sbcheckbox.setOnCheckedChangeListener(::onCheckedChanged)
val showCalc = sp.getBoolean(R.string.key_wizard_calculation_visible, false) val showCalc = sp.getBoolean(R.string.key_wizard_calculation_visible, false)
treatments_wizard_delimiter.visibility = showCalc.toVisibility() binding.delimiter.visibility = showCalc.toVisibility()
treatments_wizard_resulttable.visibility = showCalc.toVisibility() binding.resulttable.visibility = showCalc.toVisibility()
treatments_wizard_calculationcheckbox.isChecked = showCalc binding.calculationcheckbox.isChecked = showCalc
treatments_wizard_calculationcheckbox.setOnCheckedChangeListener { _, isChecked -> binding.calculationcheckbox.setOnCheckedChangeListener { _, isChecked ->
run { run {
sp.putBoolean(resourceHelper.gs(R.string.key_wizard_calculation_visible), isChecked) sp.putBoolean(resourceHelper.gs(R.string.key_wizard_calculation_visible), isChecked)
treatments_wizard_delimiter.visibility = isChecked.toVisibility() binding.delimiter.visibility = isChecked.toVisibility()
treatments_wizard_resulttable.visibility = isChecked.toVisibility() binding.resulttable.visibility = isChecked.toVisibility()
} }
} }
// profile spinner // profile spinner
treatments_wizard_profile.onItemSelectedListener = object : OnItemSelectedListener { binding.profile.onItemSelectedListener = object : OnItemSelectedListener {
override fun onNothingSelected(parent: AdapterView<*>?) { override fun onNothingSelected(parent: AdapterView<*>?) {
ToastUtils.showToastInUiThread(mainApp, resourceHelper.gs(R.string.noprofileselected)) ToastUtils.showToastInUiThread(mainApp, resourceHelper.gs(R.string.noprofileselected))
ok.visibility = View.GONE binding.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()
ok.visibility = View.VISIBLE binding.ok.visibility = View.VISIBLE
} }
} }
// bus // bus
@ -183,36 +199,37 @@ class WizardDialog : DaggerDialogFragment() {
override fun onDestroyView() { override fun onDestroyView() {
super.onDestroyView() super.onDestroyView()
disposable.clear() disposable.clear()
_binding = null
} }
private fun onCheckedChanged(buttonView: CompoundButton, @Suppress("UNUSED_PARAMETER") state: Boolean) { private fun onCheckedChanged(buttonView: CompoundButton, @Suppress("UNUSED_PARAMETER") state: Boolean) {
saveCheckedStates() saveCheckedStates()
treatments_wizard_ttcheckbox.isEnabled = treatments_wizard_bgcheckbox.isChecked && treatmentsPlugin.tempTargetFromHistory != null binding.ttcheckbox.isEnabled = binding.bgcheckbox.isChecked && treatmentsPlugin.tempTargetFromHistory != null
if (buttonView.id == treatments_wizard_cobcheckbox.id) if (buttonView.id == binding.cobcheckbox.id)
processCobCheckBox() processCobCheckBox()
calculateInsulin() calculateInsulin()
} }
private fun processCobCheckBox() { private fun processCobCheckBox() {
if (treatments_wizard_cobcheckbox.isChecked) { if (binding.cobcheckbox.isChecked) {
treatments_wizard_bolusiobcheckbox.isEnabled = false binding.bolusiobcheckbox.isEnabled = false
treatments_wizard_basaliobcheckbox.isEnabled = false binding.basaliobcheckbox.isEnabled = false
treatments_wizard_bolusiobcheckbox.isChecked = true binding.bolusiobcheckbox.isChecked = true
treatments_wizard_basaliobcheckbox.isChecked = true binding.basaliobcheckbox.isChecked = true
} else { } else {
treatments_wizard_bolusiobcheckbox.isEnabled = true binding.bolusiobcheckbox.isEnabled = true
treatments_wizard_basaliobcheckbox.isEnabled = true binding.basaliobcheckbox.isEnabled = true
} }
} }
private fun saveCheckedStates() { private fun saveCheckedStates() {
sp.putBoolean(resourceHelper.gs(R.string.key_wizard_include_cob), treatments_wizard_cobcheckbox.isChecked) sp.putBoolean(R.string.key_wizard_include_cob, binding.cobcheckbox.isChecked)
sp.putBoolean(resourceHelper.gs(R.string.key_wizard_include_trend_bg), treatments_wizard_bgtrendcheckbox.isChecked) sp.putBoolean(R.string.key_wizard_include_trend_bg, binding.bgtrendcheckbox.isChecked)
} }
private fun loadCheckedStates() { private fun loadCheckedStates() {
treatments_wizard_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)
treatments_wizard_cobcheckbox.isChecked = sp.getBoolean(R.string.key_wizard_include_cob, false) binding.cobcheckbox.isChecked = sp.getBoolean(R.string.key_wizard_include_cob, false)
} }
private fun initDialog() { private fun initDialog() {
@ -230,25 +247,25 @@ class WizardDialog : DaggerDialogFragment() {
profileList.add(0, resourceHelper.gs(R.string.active)) profileList.add(0, resourceHelper.gs(R.string.active))
context?.let { context -> context?.let { context ->
val adapter = ArrayAdapter(context, R.layout.spinner_centered, profileList) val adapter = ArrayAdapter(context, R.layout.spinner_centered, profileList)
treatments_wizard_profile.adapter = adapter binding.profile.adapter = adapter
} ?: return } ?: return
val units = profileFunction.getUnits() val units = profileFunction.getUnits()
treatments_wizard_bgunits.text = units binding.bgunits.text = units
if (units == Constants.MGDL) if (units == Constants.MGDL)
treatments_wizard_bg_input.setStep(1.0) binding.bgInput.setStep(1.0)
else else
treatments_wizard_bg_input.setStep(0.1) binding.bgInput.setStep(0.1)
// Set BG if not old // Set BG if not old
val lastBg = iobCobCalculatorPlugin.actualBg() val lastBg = iobCobCalculatorPlugin.actualBg()
if (lastBg != null) { if (lastBg != null) {
treatments_wizard_bg_input.value = lastBg.valueToUnits(units) binding.bgInput.value = lastBg.valueToUnits(units)
} else { } else {
treatments_wizard_bg_input.value = 0.0 binding.bgInput.value = 0.0
} }
treatments_wizard_ttcheckbox.isEnabled = treatmentsPlugin.tempTargetFromHistory != null binding.ttcheckbox.isEnabled = treatmentsPlugin.tempTargetFromHistory != null
// IOB calculation // IOB calculation
treatmentsPlugin.updateTotalIOBTreatments() treatmentsPlugin.updateTotalIOBTreatments()
@ -256,19 +273,19 @@ class WizardDialog : DaggerDialogFragment() {
treatmentsPlugin.updateTotalIOBTempBasals() treatmentsPlugin.updateTotalIOBTempBasals()
val basalIob = treatmentsPlugin.lastCalculationTempBasals.round() val basalIob = treatmentsPlugin.lastCalculationTempBasals.round()
treatments_wizard_bolusiobinsulin.text = resourceHelper.gs(R.string.formatinsulinunits, -bolusIob.iob) binding.bolusiobinsulin.text = resourceHelper.gs(R.string.formatinsulinunits, -bolusIob.iob)
treatments_wizard_basaliobinsulin.text = resourceHelper.gs(R.string.formatinsulinunits, -basalIob.basaliob) binding.basaliobinsulin.text = resourceHelper.gs(R.string.formatinsulinunits, -basalIob.basaliob)
calculateInsulin() calculateInsulin()
treatments_wizard_percent_used.visibility = (sp.getInt(R.string.key_boluswizard_percentage, 100) != 100).toVisibility() binding.percentUsed.visibility = (sp.getInt(R.string.key_boluswizard_percentage, 100) != 100).toVisibility()
} }
private fun calculateInsulin() { private fun calculateInsulin() {
val profileStore = activePlugin.activeProfileInterface.profile val profileStore = activePlugin.activeProfileInterface.profile
if (treatments_wizard_profile?.selectedItem == null || profileStore == null) if (binding.profile.selectedItem == null || profileStore == null)
return // not initialized yet return // not initialized yet
var profileName = treatments_wizard_profile.selectedItem.toString() var profileName = binding.profile.selectedItem.toString()
val specificProfile: Profile? val specificProfile: Profile?
if (profileName == resourceHelper.gs(R.string.active)) { if (profileName == resourceHelper.gs(R.string.active)) {
specificProfile = profileFunction.getProfile() specificProfile = profileFunction.getProfile()
@ -279,82 +296,83 @@ class WizardDialog : DaggerDialogFragment() {
if (specificProfile == null) return if (specificProfile == null) return
// Entered values // Entered values
var bg = SafeParse.stringToDouble(treatments_wizard_bg_input.text) var bg = SafeParse.stringToDouble(binding.bgInput.text)
val carbs = SafeParse.stringToInt(treatments_wizard_carbs_input.text) val carbs = SafeParse.stringToInt(binding.carbsInput.text)
val correction = SafeParse.stringToDouble(treatments_wizard_correction_input.text) val correction = SafeParse.stringToDouble(binding.correctionInput.text)
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) {
treatments_wizard_carbs_input.value = 0.0 binding.carbsInput.value = 0.0
ToastUtils.showToastInUiThread(mainApp, resourceHelper.gs(R.string.carbsconstraintapplied)) ToastUtils.showToastInUiThread(mainApp, resourceHelper.gs(R.string.carbsconstraintapplied))
return return
} }
bg = if (treatments_wizard_bgcheckbox.isChecked) bg else 0.0 bg = if (binding.bgcheckbox.isChecked) bg else 0.0
val tempTarget = if (treatments_wizard_ttcheckbox.isChecked) treatmentsPlugin.tempTargetFromHistory else null val tempTarget = if (binding.ttcheckbox.isChecked) treatmentsPlugin.tempTargetFromHistory else null
// COB // COB
var cob = 0.0 var cob = 0.0
if (treatments_wizard_cobcheckbox.isChecked) { if (binding.cobcheckbox.isChecked) {
val cobInfo = iobCobCalculatorPlugin.getCobInfo(false, "Wizard COB") val cobInfo = iobCobCalculatorPlugin.getCobInfo(false, "Wizard COB")
cobInfo.displayCob?.let { cob = it } cobInfo.displayCob?.let { cob = it }
} }
val carbTime = SafeParse.stringToInt(treatments_wizard_carb_time_input.text) val carbTime = SafeParse.stringToInt(binding.carbTimeInput.text)
wizard = BolusWizard(mainApp).doCalc(specificProfile, profileName, tempTarget, carbsAfterConstraint, cob, bg, correction, wizard = BolusWizard(mainApp).doCalc(specificProfile, profileName, tempTarget, carbsAfterConstraint, cob, bg, correction,
sp.getInt(R.string.key_boluswizard_percentage, 100).toDouble(), sp.getInt(R.string.key_boluswizard_percentage, 100).toDouble(),
treatments_wizard_bgcheckbox.isChecked, binding.bgcheckbox.isChecked,
treatments_wizard_cobcheckbox.isChecked, binding.cobcheckbox.isChecked,
treatments_wizard_bolusiobcheckbox.isChecked, binding.bolusiobcheckbox.isChecked,
treatments_wizard_basaliobcheckbox.isChecked, binding.basaliobcheckbox.isChecked,
treatments_wizard_sbcheckbox.isChecked, binding.sbcheckbox.isChecked,
treatments_wizard_ttcheckbox.isChecked, binding.ttcheckbox.isChecked,
treatments_wizard_bgtrendcheckbox.isChecked, binding.bgtrendcheckbox.isChecked,
treatment_wizard_notes.text.toString(), carbTime) binding.alarm.isChecked,
binding.notes.text.toString(), carbTime)
wizard?.let { wizard -> wizard?.let { wizard ->
treatments_wizard_bg.text = String.format(resourceHelper.gs(R.string.format_bg_isf), BgReading().value(Profile.toMgdl(bg, profileFunction.getUnits())).valueToUnitsToString(profileFunction.getUnits()), wizard.sens) binding.bg.text = String.format(resourceHelper.gs(R.string.format_bg_isf), BgReading().value(Profile.toMgdl(bg, profileFunction.getUnits())).valueToUnitsToString(profileFunction.getUnits()), wizard.sens)
treatments_wizard_bginsulin.text = resourceHelper.gs(R.string.formatinsulinunits, wizard.insulinFromBG) binding.bginsulin.text = resourceHelper.gs(R.string.formatinsulinunits, wizard.insulinFromBG)
treatments_wizard_carbs.text = String.format(resourceHelper.gs(R.string.format_carbs_ic), carbs.toDouble(), wizard.ic) binding.carbs.text = String.format(resourceHelper.gs(R.string.format_carbs_ic), carbs.toDouble(), wizard.ic)
treatments_wizard_carbsinsulin.text = resourceHelper.gs(R.string.formatinsulinunits, wizard.insulinFromCarbs) binding.carbsinsulin.text = resourceHelper.gs(R.string.formatinsulinunits, wizard.insulinFromCarbs)
treatments_wizard_bolusiobinsulin.text = resourceHelper.gs(R.string.formatinsulinunits, wizard.insulinFromBolusIOB) binding.bolusiobinsulin.text = resourceHelper.gs(R.string.formatinsulinunits, wizard.insulinFromBolusIOB)
treatments_wizard_basaliobinsulin.text = resourceHelper.gs(R.string.formatinsulinunits, wizard.insulinFromBasalsIOB) binding.basaliobinsulin.text = resourceHelper.gs(R.string.formatinsulinunits, wizard.insulinFromBasalIOB)
treatments_wizard_correctioninsulin.text = resourceHelper.gs(R.string.formatinsulinunits, wizard.insulinFromCorrection) binding.correctioninsulin.text = resourceHelper.gs(R.string.formatinsulinunits, wizard.insulinFromCorrection)
// Superbolus // Superbolus
treatments_wizard_sb.text = if (treatments_wizard_sbcheckbox.isChecked) resourceHelper.gs(R.string.twohours) else "" binding.sb.text = if (binding.sbcheckbox.isChecked) resourceHelper.gs(R.string.twohours) else ""
treatments_wizard_sbinsulin.text = resourceHelper.gs(R.string.formatinsulinunits, wizard.insulinFromSuperBolus) binding.sbinsulin.text = resourceHelper.gs(R.string.formatinsulinunits, wizard.insulinFromSuperBolus)
// Trend // Trend
if (treatments_wizard_bgtrendcheckbox.isChecked && wizard.glucoseStatus != null) { if (binding.bgtrendcheckbox.isChecked && wizard.glucoseStatus != null) {
treatments_wizard_bgtrend.text = ((if (wizard.trend > 0) "+" else "") binding.bgtrend.text = ((if (wizard.trend > 0) "+" else "")
+ Profile.toUnitsString(wizard.trend * 3, wizard.trend * 3 / Constants.MMOLL_TO_MGDL, profileFunction.getUnits()) + Profile.toUnitsString(wizard.trend * 3, wizard.trend * 3 / Constants.MMOLL_TO_MGDL, profileFunction.getUnits())
+ " " + profileFunction.getUnits()) + " " + profileFunction.getUnits())
} else { } else {
treatments_wizard_bgtrend.text = "" binding.bgtrend.text = ""
} }
treatments_wizard_bgtrendinsulin.text = resourceHelper.gs(R.string.formatinsulinunits, wizard.insulinFromTrend) binding.bgtrendinsulin.text = resourceHelper.gs(R.string.formatinsulinunits, wizard.insulinFromTrend)
// COB // COB
if (treatments_wizard_cobcheckbox.isChecked) { if (binding.cobcheckbox.isChecked) {
treatments_wizard_cob.text = String.format(resourceHelper.gs(R.string.format_cob_ic), cob, wizard.ic) binding.cob.text = String.format(resourceHelper.gs(R.string.format_cob_ic), cob, wizard.ic)
treatments_wizard_cobinsulin.text = resourceHelper.gs(R.string.formatinsulinunits, wizard.insulinFromCOB) binding.cobinsulin.text = resourceHelper.gs(R.string.formatinsulinunits, wizard.insulinFromCOB)
} else { } else {
treatments_wizard_cob.text = "" binding.cob.text = ""
treatments_wizard_cobinsulin.text = "" binding.cobinsulin.text = ""
} }
if (wizard.calculatedTotalInsulin > 0.0 || carbsAfterConstraint > 0.0) { if (wizard.calculatedTotalInsulin > 0.0 || carbsAfterConstraint > 0.0) {
val insulinText = if (wizard.calculatedTotalInsulin > 0.0) resourceHelper.gs(R.string.formatinsulinunits, wizard.calculatedTotalInsulin) else "" val insulinText = if (wizard.calculatedTotalInsulin > 0.0) resourceHelper.gs(R.string.formatinsulinunits, wizard.calculatedTotalInsulin) else ""
val carbsText = if (carbsAfterConstraint > 0.0) resourceHelper.gs(R.string.format_carbs, carbsAfterConstraint) else "" val carbsText = if (carbsAfterConstraint > 0.0) resourceHelper.gs(R.string.format_carbs, carbsAfterConstraint) else ""
treatments_wizard_total.text = resourceHelper.gs(R.string.result_insulin_carbs, insulinText, carbsText) binding.total.text = resourceHelper.gs(R.string.result_insulin_carbs, insulinText, carbsText)
ok.visibility = View.VISIBLE binding.ok.visibility = View.VISIBLE
} else { } else {
treatments_wizard_total.text = resourceHelper.gs(R.string.missing_carbs, wizard.carbsEquivalent.toInt()) binding.total.text = resourceHelper.gs(R.string.missing_carbs, wizard.carbsEquivalent.toInt())
ok.visibility = View.INVISIBLE binding.ok.visibility = View.INVISIBLE
} }
} }

View file

@ -15,8 +15,8 @@ import androidx.annotation.DrawableRes
import androidx.recyclerview.widget.ItemTouchHelper import androidx.recyclerview.widget.ItemTouchHelper
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import dagger.android.HasAndroidInjector
import dagger.android.support.DaggerFragment import dagger.android.support.DaggerFragment
import info.nightscout.androidaps.MainApp
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.databinding.AutomationEventItemBinding import info.nightscout.androidaps.databinding.AutomationEventItemBinding
import info.nightscout.androidaps.databinding.AutomationFragmentBinding import info.nightscout.androidaps.databinding.AutomationFragmentBinding
@ -46,7 +46,7 @@ class AutomationFragment : DaggerFragment(), OnStartDragListener {
@Inject lateinit var rxBus: RxBusWrapper @Inject lateinit var rxBus: RxBusWrapper
@Inject lateinit var fabricPrivacy: FabricPrivacy @Inject lateinit var fabricPrivacy: FabricPrivacy
@Inject lateinit var automationPlugin: AutomationPlugin @Inject lateinit var automationPlugin: AutomationPlugin
@Inject lateinit var mainApp: MainApp @Inject lateinit var injector: HasAndroidInjector
private var disposable: CompositeDisposable = CompositeDisposable() private var disposable: CompositeDisposable = CompositeDisposable()
private lateinit var eventListAdapter: EventListAdapter private lateinit var eventListAdapter: EventListAdapter
@ -76,7 +76,7 @@ class AutomationFragment : DaggerFragment(), OnStartDragListener {
binding.fabAddEvent.setOnClickListener { binding.fabAddEvent.setOnClickListener {
val dialog = EditEventDialog() val dialog = EditEventDialog()
val args = Bundle() val args = Bundle()
args.putString("event", AutomationEvent(mainApp).toJSON()) args.putString("event", AutomationEvent(injector).toJSON())
args.putInt("position", -1) // New event args.putInt("position", -1) // New event
dialog.arguments = args dialog.arguments = args
dialog.show(childFragmentManager, "EditEventDialog") dialog.show(childFragmentManager, "EditEventDialog")
@ -159,7 +159,7 @@ class AutomationFragment : DaggerFragment(), OnStartDragListener {
@SuppressLint("ClickableViewAccessibility") @SuppressLint("ClickableViewAccessibility")
override fun onBindViewHolder(holder: ViewHolder, position: Int) { override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val event = automationPlugin.automationEvents[position] val event = automationPlugin.at(position)
holder.binding.eventTitle.text = event.title holder.binding.eventTitle.text = event.title
holder.binding.enabled.isChecked = event.isEnabled holder.binding.enabled.isChecked = event.isEnabled
holder.binding.enabled.isEnabled = !event.readOnly holder.binding.enabled.isEnabled = !event.readOnly
@ -190,15 +190,14 @@ class AutomationFragment : DaggerFragment(), OnStartDragListener {
rxBus.send(EventAutomationDataChanged()) rxBus.send(EventAutomationDataChanged())
} }
// edit event // edit event
if (!event.readOnly) holder.binding.rootLayout.setOnClickListener {
holder.binding.rootLayout.setOnClickListener { val dialog = EditEventDialog()
val dialog = EditEventDialog() val args = Bundle()
val args = Bundle() args.putString("event", event.toJSON())
args.putString("event", event.toJSON()) args.putInt("position", position)
args.putInt("position", position) dialog.arguments = args
dialog.arguments = args dialog.show(childFragmentManager, "EditEventDialog")
dialog.show(childFragmentManager, "EditEventDialog") }
}
// Start a drag whenever the handle view it touched // Start a drag whenever the handle view it touched
holder.binding.iconSort.setOnTouchListener { v: View, motionEvent: MotionEvent -> holder.binding.iconSort.setOnTouchListener { v: View, motionEvent: MotionEvent ->
if (motionEvent.action == MotionEvent.ACTION_DOWN) { if (motionEvent.action == MotionEvent.ACTION_DOWN) {
@ -209,36 +208,33 @@ class AutomationFragment : DaggerFragment(), OnStartDragListener {
} }
// remove event // remove event
holder.binding.iconTrash.setOnClickListener { holder.binding.iconTrash.setOnClickListener {
showConfirmation(requireContext(), resourceHelper.gs(R.string.removerecord) + " " + automationPlugin.automationEvents[position].title, showConfirmation(requireContext(), resourceHelper.gs(R.string.removerecord) + " " + automationPlugin.at(position).title,
Runnable { Runnable {
automationPlugin.automationEvents.removeAt(position) automationPlugin.removeAt(position)
notifyItemRemoved(position) notifyItemRemoved(position)
rxBus.send(EventAutomationDataChanged())
rxBus.send(EventAutomationUpdateGui())
}, Runnable { }, Runnable {
rxBus.send(EventAutomationUpdateGui()) rxBus.send(EventAutomationUpdateGui())
}) })
} }
holder.binding.iconTrash.visibility = (!event.readOnly).toVisibility() holder.binding.iconTrash.visibility = (!event.readOnly).toVisibility()
holder.binding.aapsLogo.visibility = (event.systemAction).toVisibility()
} }
override fun getItemCount(): Int = automationPlugin.automationEvents.size override fun getItemCount(): Int = automationPlugin.size()
override fun onItemMove(fromPosition: Int, toPosition: Int): Boolean { override fun onItemMove(fromPosition: Int, toPosition: Int): Boolean {
Collections.swap(automationPlugin.automationEvents, fromPosition, toPosition) automationPlugin.swap(fromPosition, toPosition)
notifyItemMoved(fromPosition, toPosition) notifyItemMoved(fromPosition, toPosition)
rxBus.send(EventAutomationDataChanged())
return true return true
} }
override fun onItemDismiss(position: Int) { override fun onItemDismiss(position: Int) {
activity?.let { activity -> activity?.let { activity ->
showConfirmation(activity, resourceHelper.gs(R.string.removerecord) + " " + automationPlugin.automationEvents[position].title, showConfirmation(activity, resourceHelper.gs(R.string.removerecord) + " " + automationPlugin.at(position).title,
Runnable { Runnable {
automationPlugin.automationEvents.removeAt(position) automationPlugin.removeAt(position)
notifyItemRemoved(position) notifyItemRemoved(position)
rxBus.send(EventAutomationDataChanged()) rxBus.send(EventAutomationDataChanged())
rxBus.send(EventAutomationUpdateGui())
}, Runnable { rxBus.send(EventAutomationUpdateGui()) }) }, Runnable { rxBus.send(EventAutomationUpdateGui()) })
} }
} }

View file

@ -39,8 +39,10 @@ import io.reactivex.schedulers.Schedulers
import org.json.JSONArray import org.json.JSONArray
import org.json.JSONException import org.json.JSONException
import org.json.JSONObject import org.json.JSONObject
import java.util.*
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
import kotlin.collections.ArrayList
@Singleton @Singleton
class AutomationPlugin @Inject constructor( class AutomationPlugin @Inject constructor(
@ -69,7 +71,7 @@ class AutomationPlugin @Inject constructor(
private val keyAutomationEvents = "AUTOMATION_EVENTS" private val keyAutomationEvents = "AUTOMATION_EVENTS"
val automationEvents = ArrayList<AutomationEvent>() private val automationEvents = ArrayList<AutomationEvent>()
var executionLog: MutableList<String> = ArrayList() var executionLog: MutableList<String> = ArrayList()
var btConnects: MutableList<EventBTChange> = ArrayList() var btConnects: MutableList<EventBTChange> = ArrayList()
@ -77,6 +79,7 @@ class AutomationPlugin @Inject constructor(
private lateinit var refreshLoop: Runnable private lateinit var refreshLoop: Runnable
companion object { companion object {
const val event = "{\"title\":\"Low\",\"enabled\":true,\"trigger\":\"{\\\"type\\\":\\\"info.nightscout.androidaps.plugins.general.automation.triggers.TriggerConnector\\\",\\\"data\\\":{\\\"connectorType\\\":\\\"AND\\\",\\\"triggerList\\\":[\\\"{\\\\\\\"type\\\\\\\":\\\\\\\"info.nightscout.androidaps.plugins.general.automation.triggers.TriggerBg\\\\\\\",\\\\\\\"data\\\\\\\":{\\\\\\\"bg\\\\\\\":4,\\\\\\\"comparator\\\\\\\":\\\\\\\"IS_LESSER\\\\\\\",\\\\\\\"units\\\\\\\":\\\\\\\"mmol\\\\\\\"}}\\\",\\\"{\\\\\\\"type\\\\\\\":\\\\\\\"info.nightscout.androidaps.plugins.general.automation.triggers.TriggerDelta\\\\\\\",\\\\\\\"data\\\\\\\":{\\\\\\\"value\\\\\\\":-0.1,\\\\\\\"units\\\\\\\":\\\\\\\"mmol\\\\\\\",\\\\\\\"deltaType\\\\\\\":\\\\\\\"DELTA\\\\\\\",\\\\\\\"comparator\\\\\\\":\\\\\\\"IS_LESSER\\\\\\\"}}\\\"]}}\",\"actions\":[\"{\\\"type\\\":\\\"info.nightscout.androidaps.plugins.general.automation.actions.ActionStartTempTarget\\\",\\\"data\\\":{\\\"value\\\":8,\\\"units\\\":\\\"mmol\\\",\\\"durationInMinutes\\\":60}}\"]}" const val event = "{\"title\":\"Low\",\"enabled\":true,\"trigger\":\"{\\\"type\\\":\\\"info.nightscout.androidaps.plugins.general.automation.triggers.TriggerConnector\\\",\\\"data\\\":{\\\"connectorType\\\":\\\"AND\\\",\\\"triggerList\\\":[\\\"{\\\\\\\"type\\\\\\\":\\\\\\\"info.nightscout.androidaps.plugins.general.automation.triggers.TriggerBg\\\\\\\",\\\\\\\"data\\\\\\\":{\\\\\\\"bg\\\\\\\":4,\\\\\\\"comparator\\\\\\\":\\\\\\\"IS_LESSER\\\\\\\",\\\\\\\"units\\\\\\\":\\\\\\\"mmol\\\\\\\"}}\\\",\\\"{\\\\\\\"type\\\\\\\":\\\\\\\"info.nightscout.androidaps.plugins.general.automation.triggers.TriggerDelta\\\\\\\",\\\\\\\"data\\\\\\\":{\\\\\\\"value\\\\\\\":-0.1,\\\\\\\"units\\\\\\\":\\\\\\\"mmol\\\\\\\",\\\\\\\"deltaType\\\\\\\":\\\\\\\"DELTA\\\\\\\",\\\\\\\"comparator\\\\\\\":\\\\\\\"IS_LESSER\\\\\\\"}}\\\"]}}\",\"actions\":[\"{\\\"type\\\":\\\"info.nightscout.androidaps.plugins.general.automation.actions.ActionStartTempTarget\\\",\\\"data\\\":{\\\"value\\\":8,\\\"units\\\":\\\"mmol\\\",\\\"durationInMinutes\\\":60}}\"]}"
} }
@ -184,42 +187,46 @@ class AutomationPlugin @Inject constructor(
@Synchronized @Synchronized
private fun processActions() { private fun processActions() {
var userEventsEnabled = true
if (loopPlugin.isSuspended || !loopPlugin.isEnabled()) { if (loopPlugin.isSuspended || !loopPlugin.isEnabled()) {
aapsLogger.debug(LTag.AUTOMATION, "Loop deactivated") aapsLogger.debug(LTag.AUTOMATION, "Loop deactivated")
executionLog.add(resourceHelper.gs(R.string.smscommunicator_loopisdisabled)) executionLog.add(resourceHelper.gs(R.string.smscommunicator_loopisdisabled))
return userEventsEnabled = false
} }
val enabled = constraintChecker.isAutomationEnabled() val enabled = constraintChecker.isAutomationEnabled()
if (!enabled.value()) { if (!enabled.value()) {
executionLog.add(enabled.getMostLimitedReasons(aapsLogger)) executionLog.add(enabled.getMostLimitedReasons(aapsLogger))
return userEventsEnabled = false
} }
aapsLogger.debug(LTag.AUTOMATION, "processActions") aapsLogger.debug(LTag.AUTOMATION, "processActions")
for (event in automationEvents) { for (event in automationEvents) {
if (event.isEnabled && event.shouldRun() && event.trigger.shouldRun() && event.getPreconditions().shouldRun()) { if (event.isEnabled && event.shouldRun() && event.trigger.shouldRun() && event.getPreconditions().shouldRun()) {
val actions = event.actions if (event.systemAction || userEventsEnabled) {
for (action in actions) { val actions = event.actions
action.doAction(object : Callback() { for (action in actions) {
override fun run() { action.doAction(object : Callback() {
val sb = StringBuilder() override fun run() {
sb.append(dateUtil.timeString(DateUtil.now())) val sb = StringBuilder()
sb.append(" ") sb.append(dateUtil.timeString(DateUtil.now()))
sb.append(if (result.success) "" else "") sb.append(" ")
sb.append(" <b>") sb.append(if (result.success) "" else "")
sb.append(event.title) sb.append(" <b>")
sb.append(":</b> ") sb.append(event.title)
sb.append(action.shortDescription()) sb.append(":</b> ")
sb.append(": ") sb.append(action.shortDescription())
sb.append(result.comment) sb.append(": ")
executionLog.add(sb.toString()) sb.append(result.comment)
aapsLogger.debug(LTag.AUTOMATION, "Executed: $sb") executionLog.add(sb.toString())
rxBus.send(EventAutomationUpdateGui()) aapsLogger.debug(LTag.AUTOMATION, "Executed: $sb")
} rxBus.send(EventAutomationUpdateGui())
}) }
})
}
SystemClock.sleep(1100)
event.lastRun = DateUtil.now()
if (event.autoRemove) automationEvents.remove(event)
} }
SystemClock.sleep(1100)
event.lastRun = DateUtil.now()
} }
} }
// we cannot detect connected BT devices // we cannot detect connected BT devices
@ -231,6 +238,38 @@ class AutomationPlugin @Inject constructor(
storeToSP() // save last run time storeToSP() // save last run time
} }
fun add(event: AutomationEvent) {
automationEvents.add(event)
rxBus.send(EventAutomationDataChanged())
}
fun addIfNotExists(event: AutomationEvent) {
for (e in automationEvents) {
if (event.title == e.title) return
}
automationEvents.add(event)
rxBus.send(EventAutomationDataChanged())
}
fun set(event: AutomationEvent, index: Int) {
automationEvents[index] = event
rxBus.send(EventAutomationDataChanged())
}
fun removeAt(index: Int) {
automationEvents.removeAt(index)
rxBus.send(EventAutomationDataChanged())
}
fun at(index: Int) = automationEvents[index]
fun size() = automationEvents.size
fun swap(fromPosition: Int, toPosition: Int) {
Collections.swap(automationEvents, fromPosition, toPosition)
rxBus.send(EventAutomationDataChanged())
}
fun getActionDummyObjects(): List<Action> { fun getActionDummyObjects(): List<Action> {
return listOf( return listOf(
//ActionLoopDisable(injector), //ActionLoopDisable(injector),

View file

@ -33,6 +33,9 @@ class ActionAlarm(injector: HasAndroidInjector) : Action(injector) {
var text = InputString(injector) var text = InputString(injector)
constructor(injector: HasAndroidInjector, text: String) : this(injector) {
this.text = InputString(injector, text)
}
override fun friendlyName(): Int = R.string.alarm override fun friendlyName(): Int = R.string.alarm
override fun shortDescription(): String = resourceHelper.gs(R.string.alarm_message, text.value) override fun shortDescription(): String = resourceHelper.gs(R.string.alarm_message, text.value)
@DrawableRes override fun icon(): Int = R.drawable.ic_access_alarm_24dp @DrawableRes override fun icon(): Int = R.drawable.ic_access_alarm_24dp

View file

@ -26,6 +26,7 @@ import info.nightscout.androidaps.plugins.general.automation.triggers.TriggerCon
import info.nightscout.androidaps.utils.FabricPrivacy import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.ToastUtils import info.nightscout.androidaps.utils.ToastUtils
import info.nightscout.androidaps.utils.extensions.plusAssign import info.nightscout.androidaps.utils.extensions.plusAssign
import info.nightscout.androidaps.utils.extensions.toVisibility
import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable import io.reactivex.disposables.CompositeDisposable
import javax.inject.Inject import javax.inject.Inject
@ -66,9 +67,13 @@ class EditEventDialog : DialogFragmentWithDate() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
binding.okcancel.ok.visibility = (!event.readOnly).toVisibility()
binding.inputEventTitle.setText(event.title) binding.inputEventTitle.setText(event.title)
binding.inputEventTitle.isFocusable = false
binding.triggerDescription.text = event.trigger.friendlyDescription() binding.triggerDescription.text = event.trigger.friendlyDescription()
binding.editTrigger.visibility = (!event.readOnly).toVisibility()
binding.editTrigger.setOnClickListener { binding.editTrigger.setOnClickListener {
val args = Bundle() val args = Bundle()
args.putString("trigger", event.trigger.toJSON()) args.putString("trigger", event.trigger.toJSON())
@ -82,6 +87,7 @@ class EditEventDialog : DialogFragmentWithDate() {
binding.actionListView.layoutManager = LinearLayoutManager(context) binding.actionListView.layoutManager = LinearLayoutManager(context)
binding.actionListView.adapter = actionListAdapter binding.actionListView.adapter = actionListAdapter
binding.addAction.visibility = (!event.readOnly).toVisibility()
binding.addAction.setOnClickListener { ChooseActionDialog().show(childFragmentManager, "ChooseActionDialog") } binding.addAction.setOnClickListener { ChooseActionDialog().show(childFragmentManager, "ChooseActionDialog") }
showPreconditions() showPreconditions()
@ -140,9 +146,9 @@ class EditEventDialog : DialogFragmentWithDate() {
} }
// store // store
if (position == -1) if (position == -1)
automationPlugin.automationEvents.add(event) automationPlugin.add(event)
else else
automationPlugin.automationEvents[position] = event automationPlugin.set(event, position)
rxBus.send(EventAutomationDataChanged()) rxBus.send(EventAutomationDataChanged())
return true return true
@ -189,20 +195,24 @@ class EditEventDialog : DialogFragmentWithDate() {
inner class ViewHolder(val view: View) : RecyclerView.ViewHolder(view) { inner class ViewHolder(val view: View) : RecyclerView.ViewHolder(view) {
fun bind(action: Action, recyclerView: RecyclerView.Adapter<ViewHolder>, position: Int) { fun bind(action: Action, recyclerView: RecyclerView.Adapter<ViewHolder>, position: Int) {
view.findViewById<LinearLayout>(R.id.automation_layoutText).setOnClickListener { if (!event.readOnly)
if (action.hasDialog()) { view.findViewById<LinearLayout>(R.id.automation_layoutText).setOnClickListener {
val args = Bundle() if (action.hasDialog()) {
args.putInt("actionPosition", position) val args = Bundle()
args.putString("action", action.toJSON()) args.putInt("actionPosition", position)
val dialog = EditActionDialog() args.putString("action", action.toJSON())
dialog.arguments = args val dialog = EditActionDialog()
dialog.show(childFragmentManager, "EditActionDialog") dialog.arguments = args
dialog.show(childFragmentManager, "EditActionDialog")
}
}
view.findViewById<ImageView>(R.id.automation_iconTrash).run {
visibility = (!event.readOnly).toVisibility()
setOnClickListener {
event.actions.remove(action)
recyclerView.notifyDataSetChanged()
rxBus.send(EventAutomationUpdateGui())
} }
}
view.findViewById<ImageView>(R.id.automation_iconTrash).setOnClickListener {
event.actions.remove(action)
recyclerView.notifyDataSetChanged()
rxBus.send(EventAutomationUpdateGui())
} }
view.findViewById<ImageView>(R.id.automation_action_image).setImageResource(action.icon()) view.findViewById<ImageView>(R.id.automation_action_image).setImageResource(action.icon())
view.findViewById<TextView>(R.id.automation_viewActionTitle).text = action.shortDescription() view.findViewById<TextView>(R.id.automation_viewActionTitle).text = action.shortDescription()

View file

@ -35,6 +35,12 @@ class TriggerDelta(injector: HasAndroidInjector) : Trigger(injector) {
else InputDelta(injector, 0.0, (-MGDL_MAX), MGDL_MAX, 1.0, DecimalFormat("1"), DeltaType.DELTA) else InputDelta(injector, 0.0, (-MGDL_MAX), MGDL_MAX, 1.0, DecimalFormat("1"), DeltaType.DELTA)
} }
constructor(injector: HasAndroidInjector, inputDelta: InputDelta, units: String, comparator: Comparator.Compare) : this(injector) {
this.units = units
this.delta = inputDelta
this.comparator.value = comparator
}
private constructor(injector: HasAndroidInjector, triggerDelta: TriggerDelta) : this(injector) { private constructor(injector: HasAndroidInjector, triggerDelta: TriggerDelta) : this(injector) {
units = triggerDelta.units units = triggerDelta.units
delta = InputDelta(injector, triggerDelta.delta) delta = InputDelta(injector, triggerDelta.delta)

View file

@ -195,7 +195,7 @@ class ActionStringHandler @Inject constructor(
val formatInt = DecimalFormat("0") val formatInt = DecimalFormat("0")
val bolusWizard = BolusWizard(injector).doCalc(profile, profileName, activePlugin.activeTreatments.tempTargetFromHistory, val bolusWizard = BolusWizard(injector).doCalc(profile, profileName, activePlugin.activeTreatments.tempTargetFromHistory,
carbsAfterConstraints, cobInfo.displayCob!!, bgReading!!.valueToUnits(profileFunction.getUnits()), carbsAfterConstraints, cobInfo.displayCob!!, bgReading!!.valueToUnits(profileFunction.getUnits()),
0.0, percentage.toDouble(), useBG, useCOB, useBolusIOB, useBasalIOB, false, useTT, useTrend) 0.0, percentage.toDouble(), useBG, useCOB, useBolusIOB, useBasalIOB, false, useTT, useTrend, false)
if (Math.abs(bolusWizard.insulinAfterConstraints - bolusWizard.calculatedTotalInsulin) >= 0.01) { if (Math.abs(bolusWizard.insulinAfterConstraints - bolusWizard.calculatedTotalInsulin) >= 0.01) {
sendError("Insulin constraint violation!" + sendError("Insulin constraint violation!" +
"\nCannot deliver " + format.format(bolusWizard.calculatedTotalInsulin) + "!") "\nCannot deliver " + format.format(bolusWizard.calculatedTotalInsulin) + "!")
@ -215,7 +215,7 @@ class ActionStringHandler @Inject constructor(
if (useCOB) rMessage += "\nFrom" + formatInt.format(cobInfo.displayCob) + "g COB : " + format.format(bolusWizard.insulinFromCOB) + "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 (useBG) rMessage += "\nFrom BG: " + format.format(bolusWizard.insulinFromBG) + "U"
if (useBolusIOB) rMessage += "\nBolus IOB: " + format.format(bolusWizard.insulinFromBolusIOB) + "U" if (useBolusIOB) rMessage += "\nBolus IOB: " + format.format(bolusWizard.insulinFromBolusIOB) + "U"
if (useBasalIOB) rMessage += "\nBasal IOB: " + format.format(bolusWizard.insulinFromBasalsIOB) + "U" if (useBasalIOB) rMessage += "\nBasal IOB: " + format.format(bolusWizard.insulinFromBasalIOB) + "U"
if (useTrend) rMessage += "\nFrom 15' trend: " + format.format(bolusWizard.insulinFromTrend) + "U" if (useTrend) rMessage += "\nFrom 15' trend: " + format.format(bolusWizard.insulinFromTrend) + "U"
if (percentage != 100) { if (percentage != 100) {
rMessage += "\nPercentage: " + format.format(bolusWizard.totalBeforePercentageAdjustment) + "U * " + percentage + "% -> ~" + format.format(bolusWizard.calculatedTotalInsulin) + "U" rMessage += "\nPercentage: " + format.format(bolusWizard.totalBeforePercentageAdjustment) + "U * " + percentage + "% -> ~" + format.format(bolusWizard.calculatedTotalInsulin) + "U"

View file

@ -6,6 +6,7 @@ import android.text.Spanned
import com.google.common.base.Joiner import com.google.common.base.Joiner
import dagger.android.HasAndroidInjector import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.Config import info.nightscout.androidaps.Config
import info.nightscout.androidaps.Constants
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.activities.ErrorHelperActivity import info.nightscout.androidaps.activities.ErrorHelperActivity
import info.nightscout.androidaps.data.DetailedBolusInfo import info.nightscout.androidaps.data.DetailedBolusInfo
@ -20,6 +21,15 @@ import info.nightscout.androidaps.logging.LTag
import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin
import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
import info.nightscout.androidaps.plugins.general.automation.AutomationEvent
import info.nightscout.androidaps.plugins.general.automation.AutomationPlugin
import info.nightscout.androidaps.plugins.general.automation.actions.ActionAlarm
import info.nightscout.androidaps.plugins.general.automation.elements.Comparator
import info.nightscout.androidaps.plugins.general.automation.elements.InputDelta
import info.nightscout.androidaps.plugins.general.automation.triggers.TriggerBg
import info.nightscout.androidaps.plugins.general.automation.triggers.TriggerConnector
import info.nightscout.androidaps.plugins.general.automation.triggers.TriggerDelta
import info.nightscout.androidaps.plugins.general.automation.triggers.TriggerTime
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin
import info.nightscout.androidaps.queue.Callback import info.nightscout.androidaps.queue.Callback
@ -30,8 +40,10 @@ import info.nightscout.androidaps.utils.T
import info.nightscout.androidaps.utils.alertDialogs.OKDialog import info.nightscout.androidaps.utils.alertDialogs.OKDialog
import info.nightscout.androidaps.utils.extensions.formatColor import info.nightscout.androidaps.utils.extensions.formatColor
import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.sharedPreferences.SP
import org.json.JSONException import org.json.JSONException
import org.json.JSONObject import org.json.JSONObject
import java.text.DecimalFormat
import java.util.* import java.util.*
import javax.inject.Inject import javax.inject.Inject
import kotlin.math.abs import kotlin.math.abs
@ -43,13 +55,15 @@ class BolusWizard @Inject constructor(
@Inject lateinit var aapsLogger: AAPSLogger @Inject lateinit var aapsLogger: AAPSLogger
@Inject lateinit var resourceHelper: ResourceHelper @Inject lateinit var resourceHelper: ResourceHelper
@Inject lateinit var rxBus: RxBusWrapper @Inject lateinit var rxBus: RxBusWrapper
@Inject lateinit var sp: SP
@Inject lateinit var profileFunction: ProfileFunction @Inject lateinit var profileFunction: ProfileFunction
@Inject lateinit var constraintChecker: ConstraintChecker @Inject lateinit var constraintChecker: ConstraintChecker
@Inject lateinit var context: Context
@Inject lateinit var activePlugin: ActivePluginProvider @Inject lateinit var activePlugin: ActivePluginProvider
@Inject lateinit var commandQueue: CommandQueueProvider @Inject lateinit var commandQueue: CommandQueueProvider
@Inject lateinit var loopPlugin: LoopPlugin @Inject lateinit var loopPlugin: LoopPlugin
@Inject lateinit var iobCobCalculatorPlugin: IobCobCalculatorPlugin @Inject lateinit var iobCobCalculatorPlugin: IobCobCalculatorPlugin
@Inject lateinit var automationPlugin: AutomationPlugin
@Inject lateinit var dateUtil: DateUtil
@Inject lateinit var config: Config @Inject lateinit var config: Config
init { init {
@ -72,7 +86,7 @@ class BolusWizard @Inject constructor(
private set private set
var insulinFromBolusIOB = 0.0 var insulinFromBolusIOB = 0.0
private set private set
var insulinFromBasalsIOB = 0.0 var insulinFromBasalIOB = 0.0
private set private set
var insulinFromCorrection = 0.0 var insulinFromCorrection = 0.0
private set private set
@ -104,7 +118,7 @@ class BolusWizard @Inject constructor(
var carbs: Int = 0 var carbs: Int = 0
var cob: Double = 0.0 var cob: Double = 0.0
var bg: Double = 0.0 var bg: Double = 0.0
var correction: Double = 0.0 private var correction: Double = 0.0
private var percentageCorrection: Double = 0.0 private var percentageCorrection: Double = 0.0
private var useBg: Boolean = false private var useBg: Boolean = false
private var useCob: Boolean = false private var useCob: Boolean = false
@ -113,8 +127,9 @@ class BolusWizard @Inject constructor(
private var useSuperBolus: Boolean = false private var useSuperBolus: Boolean = false
private var useTT: Boolean = false private var useTT: Boolean = false
private var useTrend: Boolean = false private var useTrend: Boolean = false
private var useAlarm = false
var notes: String = "" var notes: String = ""
var carbTime: Int = 0 private var carbTime: Int = 0
@JvmOverloads @JvmOverloads
fun doCalc(profile: Profile, fun doCalc(profile: Profile,
@ -132,6 +147,7 @@ class BolusWizard @Inject constructor(
useSuperBolus: Boolean, useSuperBolus: Boolean,
useTT: Boolean, useTT: Boolean,
useTrend: Boolean, useTrend: Boolean,
useAlarm: Boolean,
notes: String = "", notes: String = "",
carbTime: Int = 0 carbTime: Int = 0
): BolusWizard { ): BolusWizard {
@ -151,6 +167,7 @@ class BolusWizard @Inject constructor(
this.useSuperBolus = useSuperBolus this.useSuperBolus = useSuperBolus
this.useTT = useTT this.useTT = useTT
this.useTrend = useTrend this.useTrend = useTrend
this.useAlarm = useAlarm
this.notes = notes this.notes = notes
this.carbTime = carbTime this.carbTime = carbTime
@ -193,7 +210,7 @@ class BolusWizard @Inject constructor(
val basalIob = activePlugin.activeTreatments.lastCalculationTempBasals.round() val basalIob = activePlugin.activeTreatments.lastCalculationTempBasals.round()
insulinFromBolusIOB = if (includeBolusIOB) -bolusIob.iob else 0.0 insulinFromBolusIOB = if (includeBolusIOB) -bolusIob.iob else 0.0
insulinFromBasalsIOB = if (includeBasalIOB) -basalIob.basaliob else 0.0 insulinFromBasalIOB = if (includeBasalIOB) -basalIob.basaliob else 0.0
// Insulin from correction // Insulin from correction
insulinFromCorrection = correction insulinFromCorrection = correction
@ -207,7 +224,7 @@ class BolusWizard @Inject constructor(
} }
// Total // Total
calculatedTotalInsulin = insulinFromBG + insulinFromTrend + insulinFromCarbs + insulinFromBolusIOB + insulinFromBasalsIOB + insulinFromCorrection + insulinFromSuperBolus + insulinFromCOB calculatedTotalInsulin = insulinFromBG + insulinFromTrend + insulinFromCarbs + insulinFromBolusIOB + insulinFromBasalIOB + insulinFromCorrection + insulinFromSuperBolus + insulinFromCOB
// Percentage adjustment // Percentage adjustment
totalBeforePercentageAdjustment = calculatedTotalInsulin totalBeforePercentageAdjustment = calculatedTotalInsulin
@ -229,6 +246,7 @@ class BolusWizard @Inject constructor(
return this return this
} }
@Suppress("SpellCheckingInspection")
private fun nsJSON(): JSONObject { private fun nsJSON(): JSONObject {
val bolusCalcJSON = JSONObject() val bolusCalcJSON = JSONObject()
try { try {
@ -239,9 +257,9 @@ class BolusWizard @Inject constructor(
bolusCalcJSON.put("targetBGHigh", targetBGHigh) bolusCalcJSON.put("targetBGHigh", targetBGHigh)
bolusCalcJSON.put("isf", sens) bolusCalcJSON.put("isf", sens)
bolusCalcJSON.put("ic", ic) bolusCalcJSON.put("ic", ic)
bolusCalcJSON.put("iob", -(insulinFromBolusIOB + insulinFromBasalsIOB)) bolusCalcJSON.put("iob", -(insulinFromBolusIOB + insulinFromBasalIOB))
bolusCalcJSON.put("bolusiob", insulinFromBolusIOB) bolusCalcJSON.put("bolusiob", insulinFromBolusIOB)
bolusCalcJSON.put("basaliob", insulinFromBasalsIOB) bolusCalcJSON.put("basaliob", insulinFromBasalIOB)
bolusCalcJSON.put("bolusiobused", includeBolusIOB) bolusCalcJSON.put("bolusiobused", includeBolusIOB)
bolusCalcJSON.put("basaliobused", includeBasalIOB) bolusCalcJSON.put("basaliobused", includeBasalIOB)
bolusCalcJSON.put("bg", bg) bolusCalcJSON.put("bg", bg)
@ -270,14 +288,14 @@ class BolusWizard @Inject constructor(
return bolusCalcJSON return bolusCalcJSON
} }
private fun confirmMessageAfterConstraints(pump: PumpInterface): Spanned { private fun confirmMessageAfterConstraints(advisor: Boolean): Spanned {
val actions: LinkedList<String> = LinkedList() val actions: LinkedList<String> = LinkedList()
if (insulinAfterConstraints > 0) { if (insulinAfterConstraints > 0) {
val pct = if (percentageCorrection != 100.0) " (" + percentageCorrection.toInt() + "%)" else "" val pct = if (percentageCorrection != 100.0) " (" + percentageCorrection.toInt() + "%)" else ""
actions.add(resourceHelper.gs(R.string.bolus) + ": " + resourceHelper.gs(R.string.formatinsulinunits, insulinAfterConstraints).formatColor(resourceHelper, R.color.bolus) + pct) actions.add(resourceHelper.gs(R.string.bolus) + ": " + resourceHelper.gs(R.string.formatinsulinunits, insulinAfterConstraints).formatColor(resourceHelper, R.color.bolus) + pct)
} }
if (carbs > 0) { if (carbs > 0 && !advisor) {
var timeShift = "" var timeShift = ""
if (carbTime > 0) { if (carbTime > 0) {
timeShift += " (+" + resourceHelper.gs(R.string.mins, carbTime) + ")" timeShift += " (+" + resourceHelper.gs(R.string.mins, carbTime) + ")"
@ -287,23 +305,24 @@ class BolusWizard @Inject constructor(
actions.add(resourceHelper.gs(R.string.carbs) + ": " + resourceHelper.gs(R.string.format_carbs, carbs).formatColor(resourceHelper, R.color.carbs) + timeShift) actions.add(resourceHelper.gs(R.string.carbs) + ": " + resourceHelper.gs(R.string.format_carbs, carbs).formatColor(resourceHelper, R.color.carbs) + timeShift)
} }
if (insulinFromCOB > 0) { if (insulinFromCOB > 0) {
actions.add(resourceHelper.gs(R.string.cobvsiob) + ": " + resourceHelper.gs(R.string.formatsignedinsulinunits, insulinFromBolusIOB + insulinFromBasalsIOB + insulinFromCOB + insulinFromBG).formatColor(resourceHelper, R.color.cobAlert)) actions.add(resourceHelper.gs(R.string.cobvsiob) + ": " + resourceHelper.gs(R.string.formatsignedinsulinunits, insulinFromBolusIOB + insulinFromBasalIOB + insulinFromCOB + insulinFromBG).formatColor(resourceHelper, R.color.cobAlert))
val absorptionRate = iobCobCalculatorPlugin.slowAbsorptionPercentage(60) val absorptionRate = iobCobCalculatorPlugin.slowAbsorptionPercentage(60)
if (absorptionRate > .25) if (absorptionRate > .25)
actions.add(resourceHelper.gs(R.string.slowabsorptiondetected, resourceHelper.gc(R.color.cobAlert), (absorptionRate * 100).toInt())) actions.add(resourceHelper.gs(R.string.slowabsorptiondetected, resourceHelper.gc(R.color.cobAlert), (absorptionRate * 100).toInt()))
} }
if (abs(insulinAfterConstraints - calculatedTotalInsulin) > pump.pumpDescription.pumpType.determineCorrectBolusStepSize(insulinAfterConstraints)) if (abs(insulinAfterConstraints - calculatedTotalInsulin) > activePlugin.activePump.pumpDescription.pumpType.determineCorrectBolusStepSize(insulinAfterConstraints))
actions.add(resourceHelper.gs(R.string.bolusconstraintappliedwarn, calculatedTotalInsulin, insulinAfterConstraints).formatColor(resourceHelper, R.color.warning)) actions.add(resourceHelper.gs(R.string.bolusconstraintappliedwarn, calculatedTotalInsulin, insulinAfterConstraints).formatColor(resourceHelper, R.color.warning))
if (config.NSCLIENT) if (config.NSCLIENT && insulinAfterConstraints > 0)
actions.add(resourceHelper.gs(R.string.bolusrecordedonly).formatColor(resourceHelper, R.color.warning)) actions.add(resourceHelper.gs(R.string.bolusrecordedonly).formatColor(resourceHelper, R.color.warning))
if (useAlarm && !advisor && carbs > 0 && carbTime > 0)
actions.add(resourceHelper.gs(R.string.alarminxmin, carbTime).formatColor(resourceHelper, R.color.info))
if (advisor)
actions.add(resourceHelper.gs(R.string.advisoralarm).formatColor(resourceHelper, R.color.info))
return HtmlHelper.fromHtml(Joiner.on("<br/>").join(actions)) return HtmlHelper.fromHtml(Joiner.on("<br/>").join(actions))
} }
fun confirmAndExecute(context: Context) { fun confirmAndExecute(ctx: Context) {
val profile = profileFunction.getProfile() ?: return
val pump = activePlugin.activePump
if (calculatedTotalInsulin > 0.0 || carbs > 0.0) { if (calculatedTotalInsulin > 0.0 || carbs > 0.0) {
if (accepted) { if (accepted) {
aapsLogger.debug(LTag.UI, "guarding: already accepted") aapsLogger.debug(LTag.UI, "guarding: already accepted")
@ -311,76 +330,174 @@ class BolusWizard @Inject constructor(
} }
accepted = true accepted = true
val confirmMessage = confirmMessageAfterConstraints(pump) if (sp.getBoolean(R.string.key_usebolusadvisor, false) && Profile.toMgdl(bg, profile.units) > 180 && carbs > 0 && carbTime >= 0)
OKDialog.showYesNoCancel(ctx, resourceHelper.gs(R.string.bolusadvisor), resourceHelper.gs(R.string.bolusadvisormessage),
{ bolusAdvisorProcessing(ctx) },
{ commonProcessing(ctx) }
)
else
commonProcessing(ctx)
}
}
OKDialog.showConfirmation(context, resourceHelper.gs(R.string.boluswizard), confirmMessage, Runnable { private fun bolusAdvisorProcessing(ctx: Context) {
if (insulinAfterConstraints > 0 || carbs > 0) { val confirmMessage = confirmMessageAfterConstraints(advisor = true)
if (useSuperBolus) { OKDialog.showConfirmation(ctx, resourceHelper.gs(R.string.boluswizard), confirmMessage, {
aapsLogger.debug("USER ENTRY: SUPERBOLUS TBR") DetailedBolusInfo().apply {
if (loopPlugin.isEnabled(PluginType.LOOP)) { eventType = CareportalEvent.CORRECTIONBOLUS
loopPlugin.superBolusTo(System.currentTimeMillis() + 2 * 60L * 60 * 1000) insulin = insulinAfterConstraints
rxBus.send(EventRefreshOverview("WizardDialog")) carbs = 0.0
context = ctx
glucose = bg
glucoseType = "Manual"
carbTime = 0
boluscalc = nsJSON()
source = Source.USER
notes = this@BolusWizard.notes
aapsLogger.debug("USER ENTRY: BOLUS ADVISOR insulin $insulinAfterConstraints")
if (insulin > 0) {
commandQueue.bolus(this, object : Callback() {
override fun run() {
if (!result.success) {
val i = Intent(ctx, ErrorHelperActivity::class.java)
i.putExtra("soundid", R.raw.boluserror)
i.putExtra("status", result.comment)
i.putExtra("title", resourceHelper.gs(R.string.treatmentdeliveryerror))
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
ctx.startActivity(i)
} else
scheduleEatReminder()
} }
})
}
}
})
}
if (pump.pumpDescription.tempBasalStyle == PumpDescription.ABSOLUTE) { private fun commonProcessing(ctx: Context) {
commandQueue.tempBasalAbsolute(0.0, 120, true, profile, object : Callback() { val profile = profileFunction.getProfile() ?: return
override fun run() { val pump = activePlugin.activePump
if (!result.success) {
val i = Intent(context, ErrorHelperActivity::class.java)
i.putExtra("soundid", R.raw.boluserror)
i.putExtra("status", result.comment)
i.putExtra("title", resourceHelper.gs(R.string.tempbasaldeliveryerror))
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
context.startActivity(i)
}
}
})
} else {
commandQueue.tempBasalPercent(0, 120, true, profile, object : Callback() { val confirmMessage = confirmMessageAfterConstraints(advisor = false)
override fun run() { OKDialog.showConfirmation(ctx, resourceHelper.gs(R.string.boluswizard), confirmMessage, {
if (!result.success) { if (insulinAfterConstraints > 0 || carbs > 0) {
val i = Intent(context, ErrorHelperActivity::class.java) if (useSuperBolus) {
i.putExtra("soundid", R.raw.boluserror) aapsLogger.debug("USER ENTRY: SUPERBOLUS TBR")
i.putExtra("status", result.comment) if (loopPlugin.isEnabled(PluginType.LOOP)) {
i.putExtra("title", resourceHelper.gs(R.string.tempbasaldeliveryerror)) loopPlugin.superBolusTo(System.currentTimeMillis() + 2 * 60L * 60 * 1000)
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) rxBus.send(EventRefreshOverview("WizardDialog"))
context.startActivity(i)
}
}
})
}
} }
val detailedBolusInfo = DetailedBolusInfo()
detailedBolusInfo.eventType = CareportalEvent.BOLUSWIZARD if (pump.pumpDescription.tempBasalStyle == PumpDescription.ABSOLUTE) {
detailedBolusInfo.insulin = insulinAfterConstraints commandQueue.tempBasalAbsolute(0.0, 120, true, profile, object : Callback() {
detailedBolusInfo.carbs = carbs.toDouble()
detailedBolusInfo.context = context
detailedBolusInfo.glucose = bg
detailedBolusInfo.glucoseType = "Manual"
detailedBolusInfo.carbTime = carbTime
detailedBolusInfo.boluscalc = nsJSON()
detailedBolusInfo.source = Source.USER
detailedBolusInfo.notes = notes
aapsLogger.debug("USER ENTRY: BOLUS insulin $insulinAfterConstraints carbs: $carbs")
if (detailedBolusInfo.insulin > 0 || pump.pumpDescription.storesCarbInfo) {
commandQueue.bolus(detailedBolusInfo, object : Callback() {
override fun run() { override fun run() {
if (!result.success) { if (!result.success) {
val i = Intent(context, ErrorHelperActivity::class.java) val i = Intent(ctx, ErrorHelperActivity::class.java)
i.putExtra("soundid", R.raw.boluserror) i.putExtra("soundid", R.raw.boluserror)
i.putExtra("status", result.comment) i.putExtra("status", result.comment)
i.putExtra("title", resourceHelper.gs(R.string.treatmentdeliveryerror)) i.putExtra("title", resourceHelper.gs(R.string.tempbasaldeliveryerror))
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
context.startActivity(i) ctx.startActivity(i)
} }
} }
}) })
} else { } else {
activePlugin.activeTreatments.addToHistoryTreatment(detailedBolusInfo, false)
commandQueue.tempBasalPercent(0, 120, true, profile, object : Callback() {
override fun run() {
if (!result.success) {
val i = Intent(ctx, ErrorHelperActivity::class.java)
i.putExtra("soundid", R.raw.boluserror)
i.putExtra("status", result.comment)
i.putExtra("title", resourceHelper.gs(R.string.tempbasaldeliveryerror))
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
ctx.startActivity(i)
}
}
})
} }
} }
}) DetailedBolusInfo().apply {
eventType = CareportalEvent.BOLUSWIZARD
insulin = insulinAfterConstraints
carbs = this@BolusWizard.carbs.toDouble()
context = ctx
glucose = bg
glucoseType = "Manual"
carbTime = this@BolusWizard.carbTime
boluscalc = nsJSON()
source = Source.USER
notes = this@BolusWizard.notes
aapsLogger.debug("USER ENTRY: BOLUS WIZARD insulin $insulinAfterConstraints carbs: $carbs")
if (insulin > 0 || pump.pumpDescription.storesCarbInfo) {
commandQueue.bolus(this, object : Callback() {
override fun run() {
if (!result.success) {
val i = Intent(ctx, ErrorHelperActivity::class.java)
i.putExtra("soundid", R.raw.boluserror)
i.putExtra("status", result.comment)
i.putExtra("title", resourceHelper.gs(R.string.treatmentdeliveryerror))
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
ctx.startActivity(i)
}
}
})
} else {
activePlugin.activeTreatments.addToHistoryTreatment(this, false)
}
}
if (useAlarm && carbs > 0 && carbTime > 0) {
scheduleReminder(dateUtil._now() + T.mins(carbTime.toLong()).msecs())
}
}
})
}
private fun scheduleEatReminder() {
val event = AutomationEvent(injector).apply {
title = resourceHelper.gs(R.string.bolusadvisor)
readOnly = true
systemAction = true
autoRemove = true
trigger = TriggerConnector(injector, TriggerConnector.Type.OR).apply {
// Bg under 180 mgdl and dropping by 15 mgdl
list.add(TriggerConnector(injector, TriggerConnector.Type.AND).apply {
list.add(TriggerBg(injector, 180.0, Constants.MGDL, Comparator.Compare.IS_LESSER))
list.add(TriggerDelta(injector, InputDelta(injector, -15.0, -360.0, 360.0, 1.0, DecimalFormat("0"), InputDelta.DeltaType.DELTA), Constants.MGDL, Comparator.Compare.IS_EQUAL_OR_LESSER))
list.add(TriggerDelta(injector, InputDelta(injector, -8.0, -360.0, 360.0, 1.0, DecimalFormat("0"), InputDelta.DeltaType.SHORT_AVERAGE), Constants.MGDL, Comparator.Compare.IS_EQUAL_OR_LESSER))
})
// Bg under 160 mgdl and dropping by 9 mgdl
list.add(TriggerConnector(injector, TriggerConnector.Type.AND).apply {
list.add(TriggerBg(injector, 160.0, Constants.MGDL, Comparator.Compare.IS_LESSER))
list.add(TriggerDelta(injector, InputDelta(injector, -9.0, -360.0, 360.0, 1.0, DecimalFormat("0"), InputDelta.DeltaType.DELTA), Constants.MGDL, Comparator.Compare.IS_EQUAL_OR_LESSER))
list.add(TriggerDelta(injector, InputDelta(injector, -5.0, -360.0, 360.0, 1.0, DecimalFormat("0"), InputDelta.DeltaType.SHORT_AVERAGE), Constants.MGDL, Comparator.Compare.IS_EQUAL_OR_LESSER))
})
// Bg under 145 mgdl and dropping
list.add(TriggerConnector(injector, TriggerConnector.Type.AND).apply {
list.add(TriggerBg(injector, 145.0, Constants.MGDL, Comparator.Compare.IS_LESSER))
list.add(TriggerDelta(injector, InputDelta(injector, 0.0, -360.0, 360.0, 1.0, DecimalFormat("0"), InputDelta.DeltaType.DELTA), Constants.MGDL, Comparator.Compare.IS_EQUAL_OR_LESSER))
list.add(TriggerDelta(injector, InputDelta(injector, 0.0, -360.0, 360.0, 1.0, DecimalFormat("0"), InputDelta.DeltaType.SHORT_AVERAGE), Constants.MGDL, Comparator.Compare.IS_EQUAL_OR_LESSER))
})
}
actions.add(ActionAlarm(injector, resourceHelper.gs(R.string.time_to_eat)))
} }
automationPlugin.addIfNotExists(event)
}
private fun scheduleReminder(time: Long) {
val event = AutomationEvent(injector).apply {
title = resourceHelper.gs(R.string.timetoeat)
readOnly = true
systemAction = true
autoRemove = true
trigger = TriggerConnector(injector, TriggerConnector.Type.AND).apply {
list.add(TriggerTime(injector, time))
}
actions.add(ActionAlarm(injector, resourceHelper.gs(R.string.timetoeat)))
}
automationPlugin.addIfNotExists(event)
} }
} }

View file

@ -117,7 +117,7 @@ class QuickWizardEntry @Inject constructor(private val injector: HasAndroidInjec
trend = true trend = true
} }
val percentage = sp.getDouble(R.string.key_boluswizard_percentage, 100.0) val percentage = sp.getDouble(R.string.key_boluswizard_percentage, 100.0)
return BolusWizard(injector).doCalc(profile, profileName, tempTarget, carbs(), cob, bg, 0.0, percentage, true, useCOB() == YES, bolusIOB, basalIOB, superBolus, useTempTarget() == YES, trend, "QuickWizard") return BolusWizard(injector).doCalc(profile, profileName, tempTarget, carbs(), cob, bg, 0.0, percentage, true, useCOB() == YES, bolusIOB, basalIOB, superBolus, useTempTarget() == YES, trend, false, "QuickWizard")
} }
fun buttonText(): String = safeGetString(storage, "buttonText", "") fun buttonText(): String = safeGetString(storage, "buttonText", "")

View file

@ -51,8 +51,8 @@
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:padding="10dp" android:orientation="vertical"
android:orientation="vertical"> android:padding="10dp">
<com.google.android.material.textfield.TextInputEditText <com.google.android.material.textfield.TextInputEditText
android:id="@+id/inputEventTitle" android:id="@+id/inputEventTitle"
@ -163,7 +163,9 @@
android:layout_marginTop="10dp" android:layout_marginTop="10dp"
android:layout_marginBottom="10dp" /> android:layout_marginBottom="10dp" />
<include layout="@layout/okcancel" /> <include
android:id="@+id/okcancel"
layout="@layout/okcancel" />
</LinearLayout> </LinearLayout>

View file

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/rootLayout" android:id="@+id/rootLayout"
android:layout_width="match_parent" android:layout_width="match_parent"
@ -8,59 +8,79 @@
android:layout_marginTop="8dp" android:layout_marginTop="8dp"
android:layout_marginEnd="8dp" android:layout_marginEnd="8dp"
android:layout_marginBottom="8dp" android:layout_marginBottom="8dp"
android:clickable="true"
android:focusable="true"
android:background="@color/ribbonDefault" android:background="@color/ribbonDefault"
android:padding="8dp"> android:clickable="true"
android:focusable="true">
<CheckBox <CheckBox
android:id="@+id/enabled" android:id="@+id/enabled"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_alignParentStart="true" app:layout_constraintBottom_toTopOf="@+id/iconLayout"
android:layout_alignParentTop="true" /> app:layout_constraintEnd_toStartOf="@+id/aapsLogo"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ImageView
android:id="@+id/aapsLogo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="5dp"
android:contentDescription="@string/remove_label"
android:scaleX="0.9"
android:scaleY="0.9"
android:src="@drawable/ic_notif_aaps"
app:layout_constraintBottom_toTopOf="@+id/iconLayout"
app:layout_constraintEnd_toStartOf="@+id/eventTitle"
app:layout_constraintStart_toEndOf="@+id/enabled"
app:layout_constraintTop_toTopOf="@+id/enabled" />
<TextView <TextView
android:id="@+id/eventTitle" android:id="@+id/eventTitle"
android:layout_width="wrap_content" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_alignTop="@+id/enabled"
android:layout_alignBottom="@+id/enabled"
android:layout_centerVertical="true"
android:layout_marginTop="6dp"
android:layout_toStartOf="@+id/iconTrash"
android:layout_toEndOf="@id/enabled"
android:text="Title"
android:textAlignment="viewStart" android:textAlignment="viewStart"
android:textStyle="bold" /> android:textStyle="bold"
app:layout_constraintBottom_toTopOf="@+id/iconLayout"
app:layout_constraintEnd_toStartOf="@+id/iconTrash"
app:layout_constraintStart_toEndOf="@+id/aapsLogo"
app:layout_constraintTop_toTopOf="parent" />
<ImageView <ImageView
android:id="@+id/iconTrash" android:id="@+id/iconTrash"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_marginEnd="20dp" android:layout_marginEnd="20dp"
android:layout_toStartOf="@+id/iconSort"
android:contentDescription="@string/remove_label" android:contentDescription="@string/remove_label"
android:orientation="horizontal" android:orientation="horizontal"
android:src="@drawable/ic_trash_outline" /> android:src="@drawable/ic_trash_outline"
app:layout_constraintBottom_toTopOf="@+id/iconLayout"
app:layout_constraintEnd_toStartOf="@+id/iconSort"
app:layout_constraintStart_toEndOf="@+id/eventTitle"
app:layout_constraintTop_toTopOf="parent" />
<ImageView <ImageView
android:id="@+id/iconSort" android:id="@+id/iconSort"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_alignParentEnd="true"
android:contentDescription="@string/reorder_label" android:contentDescription="@string/reorder_label"
android:orientation="horizontal" android:orientation="horizontal"
app:layout_constraintBottom_toTopOf="@+id/iconLayout"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/iconTrash"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/ic_reorder_gray_24dp" /> app:srcCompat="@drawable/ic_reorder_gray_24dp" />
<LinearLayout <LinearLayout
android:id="@+id/iconLayout" android:id="@+id/iconLayout"
android:layout_width="match_parent" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_below="@id/enabled" android:layout_marginStart="16dp"
android:orientation="horizontal" /> android:orientation="horizontal"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/iconSort" />
</RelativeLayout> </androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -49,9 +49,9 @@
android:padding="5dp" /> android:padding="5dp" />
<TableLayout <TableLayout
android:paddingEnd="5dp"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent"
android:paddingEnd="5dp">
<TableRow <TableRow
android:layout_width="match_parent" android:layout_width="match_parent"
@ -67,12 +67,12 @@
android:textStyle="bold" /> android:textStyle="bold" />
<info.nightscout.androidaps.utils.ui.NumberPicker <info.nightscout.androidaps.utils.ui.NumberPicker
android:id="@+id/treatments_wizard_bg_input" android:id="@+id/bg_input"
android:layout_width="130dp" android:layout_width="130dp"
android:layout_height="40dp" /> android:layout_height="40dp" />
<TextView <TextView
android:id="@+id/treatments_wizard_bgunits" android:id="@+id/bgunits"
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"
@ -97,7 +97,7 @@
android:textStyle="bold" /> android:textStyle="bold" />
<info.nightscout.androidaps.utils.ui.NumberPicker <info.nightscout.androidaps.utils.ui.NumberPicker
android:id="@+id/treatments_wizard_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" />
@ -128,7 +128,7 @@
android:textStyle="bold" /> android:textStyle="bold" />
<info.nightscout.androidaps.utils.ui.NumberPicker <info.nightscout.androidaps.utils.ui.NumberPicker
android:id="@+id/treatments_wizard_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" />
@ -148,17 +148,43 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent">
<TextView <LinearLayout
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:padding="10dp" android:orientation="horizontal">
android:text="@string/careportal_newnstreatment_carbtime_label"
android:textAppearance="@style/TextAppearance.AppCompat.Small" <TextView
android:textStyle="bold" /> android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="10dp"
android:text="@string/careportal_newnstreatment_carbtime_label"
android:textAppearance="@style/TextAppearance.AppCompat.Small"
android:textStyle="bold" />
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"/>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:src="@drawable/ic_access_alarm_24dp" />
<CheckBox
android:id="@+id/alarm"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:checked="false"
android:padding="5dp" />
</LinearLayout>
<info.nightscout.androidaps.utils.ui.NumberPicker <info.nightscout.androidaps.utils.ui.NumberPicker
android:id="@+id/treatments_wizard_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_horizontal" /> android:layout_gravity="center_horizontal" />
@ -191,7 +217,7 @@
android:textStyle="bold" /> android:textStyle="bold" />
<Spinner <Spinner
android:id="@+id/treatments_wizard_profile" android:id="@+id/profile"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="center_vertical|center_horizontal" android:layout_gravity="center_vertical|center_horizontal"
@ -199,13 +225,13 @@
<CheckBox <CheckBox
android:id="@+id/treatments_wizard_sbcheckbox" android:id="@+id/sbcheckbox"
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:layout_marginStart="10dp" android:layout_marginStart="10dp"
android:padding="5dp"
android:checked="false" android:checked="false"
android:padding="5dp"
android:text="@string/superbolus" /> android:text="@string/superbolus" />
</LinearLayout> </LinearLayout>
@ -217,7 +243,7 @@
android:orientation="horizontal"> android:orientation="horizontal">
<TextView <TextView
android:id="@+id/treatments_wizard_total" android:id="@+id/total"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:background="@drawable/background_darkgray" android:background="@drawable/background_darkgray"
@ -227,7 +253,7 @@
android:textAppearance="?android:attr/textAppearanceLarge" /> android:textAppearance="?android:attr/textAppearanceLarge" />
<TextView <TextView
android:id="@+id/treatments_wizard_percent_used" android:id="@+id/percent_used"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginStart="10dp" android:layout_marginStart="10dp"
@ -241,7 +267,7 @@
</LinearLayout> </LinearLayout>
<LinearLayout <LinearLayout
android:id="@+id/treatments_wizard_notes_layout" android:id="@+id/notes_layout"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="horizontal"> android:orientation="horizontal">
@ -250,14 +276,14 @@
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="center_horizontal" android:layout_gravity="center_horizontal"
android:labelFor="@+id/treatment_wizard_notes" android:labelFor="@+id/notes"
android:padding="10dp" android:padding="10dp"
android:text="@string/careportal_newnstreatment_notes_label" android:text="@string/careportal_newnstreatment_notes_label"
android:textAppearance="@style/TextAppearance.AppCompat.Small" android:textAppearance="@style/TextAppearance.AppCompat.Small"
android:textStyle="bold" /> android:textStyle="bold" />
<EditText <EditText
android:id="@+id/treatment_wizard_notes" android:id="@+id/notes"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="center_vertical" android:layout_gravity="center_vertical"
@ -279,7 +305,7 @@
android:padding="5dp"> android:padding="5dp">
<CheckBox <CheckBox
android:id="@+id/treatments_wizard_calculationcheckbox" android:id="@+id/calculationcheckbox"
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"
@ -288,8 +314,8 @@
<ImageView <ImageView
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:contentDescription="@string/show_calculation"
android:layout_gravity="center_vertical" android:layout_gravity="center_vertical"
android:contentDescription="@string/show_calculation"
app:srcCompat="@drawable/ic_visibility" /> app:srcCompat="@drawable/ic_visibility" />
<Button <Button
@ -312,7 +338,7 @@
</LinearLayout> </LinearLayout>
<View <View
android:id="@+id/treatments_wizard_delimiter" android:id="@+id/delimiter"
android:layout_width="fill_parent" android:layout_width="fill_parent"
android:layout_height="2dip" android:layout_height="2dip"
android:layout_marginStart="20dp" android:layout_marginStart="20dp"
@ -321,7 +347,7 @@
android:background="@color/listdelimiter" /> android:background="@color/listdelimiter" />
<TableLayout <TableLayout
android:id="@+id/treatments_wizard_resulttable" android:id="@+id/resulttable"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:padding="5dp"> android:padding="5dp">
@ -331,7 +357,7 @@
android:layout_height="match_parent"> android:layout_height="match_parent">
<CheckBox <CheckBox
android:id="@+id/treatments_wizard_bgcheckbox" android:id="@+id/bgcheckbox"
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"
@ -350,7 +376,7 @@
android:textAppearance="?android:attr/textAppearanceSmall" /> android:textAppearance="?android:attr/textAppearanceSmall" />
<CheckBox <CheckBox
android:id="@+id/treatments_wizard_ttcheckbox" android:id="@+id/ttcheckbox"
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"
@ -366,7 +392,7 @@
</LinearLayout> </LinearLayout>
<TextView <TextView
android:id="@+id/treatments_wizard_bg" android:id="@+id/bg"
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"
@ -374,7 +400,7 @@
android:textAppearance="?android:attr/textAppearanceSmall" /> android:textAppearance="?android:attr/textAppearanceSmall" />
<TextView <TextView
android:id="@+id/treatments_wizard_bginsulin" android:id="@+id/bginsulin"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:width="50dp" android:width="50dp"
@ -388,7 +414,7 @@
android:layout_height="match_parent"> android:layout_height="match_parent">
<CheckBox <CheckBox
android:id="@+id/treatments_wizard_bgtrendcheckbox" android:id="@+id/bgtrendcheckbox"
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"
@ -402,7 +428,7 @@
android:textAppearance="?android:attr/textAppearanceSmall" /> android:textAppearance="?android:attr/textAppearanceSmall" />
<TextView <TextView
android:id="@+id/treatments_wizard_bgtrend" android:id="@+id/bgtrend"
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"
@ -410,7 +436,7 @@
android:textAppearance="?android:attr/textAppearanceSmall" /> android:textAppearance="?android:attr/textAppearanceSmall" />
<TextView <TextView
android:id="@+id/treatments_wizard_bgtrendinsulin" android:id="@+id/bgtrendinsulin"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:width="50dp" android:width="50dp"
@ -424,7 +450,7 @@
android:layout_height="match_parent"> android:layout_height="match_parent">
<CheckBox <CheckBox
android:id="@+id/treatments_wizard_cobcheckbox" android:id="@+id/cobcheckbox"
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"
@ -438,7 +464,7 @@
android:textAppearance="?android:attr/textAppearanceSmall" /> android:textAppearance="?android:attr/textAppearanceSmall" />
<TextView <TextView
android:id="@+id/treatments_wizard_cob" android:id="@+id/cob"
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"
@ -446,7 +472,7 @@
android:textAppearance="?android:attr/textAppearanceSmall" /> android:textAppearance="?android:attr/textAppearanceSmall" />
<TextView <TextView
android:id="@+id/treatments_wizard_cobinsulin" android:id="@+id/cobinsulin"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:width="50dp" android:width="50dp"
@ -460,7 +486,7 @@
android:layout_height="match_parent"> android:layout_height="match_parent">
<CheckBox <CheckBox
android:id="@+id/treatments_wizard_bolusiobcheckbox" android:id="@+id/bolusiobcheckbox"
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"
@ -481,7 +507,7 @@
android:textAppearance="?android:attr/textAppearanceSmall" /> android:textAppearance="?android:attr/textAppearanceSmall" />
<TextView <TextView
android:id="@+id/treatments_wizard_bolusiobinsulin" android:id="@+id/bolusiobinsulin"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:width="50dp" android:width="50dp"
@ -495,7 +521,7 @@
android:layout_height="match_parent"> android:layout_height="match_parent">
<CheckBox <CheckBox
android:id="@+id/treatments_wizard_basaliobcheckbox" android:id="@+id/basaliobcheckbox"
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"
@ -516,7 +542,7 @@
android:textAppearance="?android:attr/textAppearanceSmall" /> android:textAppearance="?android:attr/textAppearanceSmall" />
<TextView <TextView
android:id="@+id/treatments_wizard_basaliobinsulin" android:id="@+id/basaliobinsulin"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:width="50dp" android:width="50dp"
@ -542,7 +568,7 @@
android:textAppearance="?android:attr/textAppearanceSmall" /> android:textAppearance="?android:attr/textAppearanceSmall" />
<TextView <TextView
android:id="@+id/treatments_wizard_carbs" android:id="@+id/carbs"
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"
@ -550,7 +576,7 @@
android:textAppearance="?android:attr/textAppearanceSmall" /> android:textAppearance="?android:attr/textAppearanceSmall" />
<TextView <TextView
android:id="@+id/treatments_wizard_carbsinsulin" android:id="@+id/carbsinsulin"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:width="50dp" android:width="50dp"
@ -576,7 +602,7 @@
android:textAppearance="?android:attr/textAppearanceSmall" /> android:textAppearance="?android:attr/textAppearanceSmall" />
<TextView <TextView
android:id="@+id/treatments_wizard_sb" android:id="@+id/sb"
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"
@ -584,7 +610,7 @@
android:textAppearance="?android:attr/textAppearanceSmall" /> android:textAppearance="?android:attr/textAppearanceSmall" />
<TextView <TextView
android:id="@+id/treatments_wizard_sbinsulin" android:id="@+id/sbinsulin"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:width="50dp" android:width="50dp"
@ -617,7 +643,7 @@
android:textAppearance="?android:attr/textAppearanceSmall" /> android:textAppearance="?android:attr/textAppearanceSmall" />
<TextView <TextView
android:id="@+id/treatments_wizard_correctioninsulin" android:id="@+id/correctioninsulin"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:width="50dp" android:width="50dp"

View file

@ -16,6 +16,7 @@
<color name="basebasal">#C83F51B5</color> <color name="basebasal">#C83F51B5</color>
<color name="graphgrid">#757575</color> <color name="graphgrid">#757575</color>
<color name="warning">#ff1a1a</color> <color name="warning">#ff1a1a</color>
<color name="info">#77dd77</color>
<color name="error_background">#66FC0000</color> <color name="error_background">#66FC0000</color>
<color name="ok_background">#323232</color> <color name="ok_background">#323232</color>

View file

@ -680,8 +680,6 @@
<string name="overview_editquickwizard_usebasaliob">Basal IOB calculation</string> <string name="overview_editquickwizard_usebasaliob">Basal IOB calculation</string>
<string name="overview_editquickwizard_usetrend">Trend calculation</string> <string name="overview_editquickwizard_usetrend">Trend calculation</string>
<string name="overview_editquickwizard_usesuperbolus">Superbolus calculation</string> <string name="overview_editquickwizard_usesuperbolus">Superbolus calculation</string>
<string name="yes">Yes</string>
<string name="no">No</string>
<string name="positiveonly">Positive only</string> <string name="positiveonly">Positive only</string>
<string name="negativeonly">Negative only</string> <string name="negativeonly">Negative only</string>
<string name="overview_editquickwizard_usecob">COB calculation</string> <string name="overview_editquickwizard_usecob">COB calculation</string>
@ -1425,5 +1423,14 @@
<string name="key_smscommunicator_report_pump_ureachable" translatable="false">smscommunicator_report_pump_ureachable</string> <string name="key_smscommunicator_report_pump_ureachable" translatable="false">smscommunicator_report_pump_ureachable</string>
<string name="smscommunicator_report_pump_ureachable_summary">Send SMS if unreachable pump event is triggered</string> <string name="smscommunicator_report_pump_ureachable_summary">Send SMS if unreachable pump event is triggered</string>
<string name="smscommunicator_pump_ureachable">Report pump ureachable</string> <string name="smscommunicator_pump_ureachable">Report pump ureachable</string>
<string name="advisoralarm">Run alarm when is time to eat</string>
<string name="alarminxmin">Run alarm in %1$d min</string>
<string name="bolusadvisor">Bolus advisor</string>
<string name="bolusadvisormessage">You have high glycemia. Instead of eating now it\'s recommended to wait for better glycemia. Do you want to do a correction bolus now and remind you when it\'s time to eat? In this case no carbs will be recorded and you must use wizard again when we remind you.</string>
<string name="key_usebolusadvisor" translatable="false">use_bolus_advisor</string>
<string name="enablebolusadvisor">Enable bolus advisor</string>
<string name="enablebolusadvisor_summary">Use reminder to start eating instead of wizard during high glycemia</string>
<string name="time_to_eat">Time to eat!\nRun Bolus wizard and do calculation again.</string>
<string name="timetoeat">Time to eat</string>
</resources> </resources>

View file

@ -489,6 +489,18 @@
validate:minNumber="10" validate:minNumber="10"
validate:testType="numericRange" /> validate:testType="numericRange" />
<SwitchPreference
android:defaultValue="true"
android:key="@string/key_usebolusadvisor"
android:summary="@string/enablebolusadvisor_summary"
android:title="@string/enablebolusadvisor" />
<SwitchPreference
android:defaultValue="false"
android:key="@string/key_usebolusadvisor"
android:summary="@string/enablebolusadvisor_summary"
android:title="@string/enablebolusadvisor" />
<SwitchPreference <SwitchPreference
android:defaultValue="false" android:defaultValue="false"
android:key="@string/key_usesuperbolus" android:key="@string/key_usesuperbolus"

View file

@ -10,6 +10,7 @@ import info.nightscout.androidaps.core.R
import info.nightscout.androidaps.utils.extensions.runOnUiThread import info.nightscout.androidaps.utils.extensions.runOnUiThread
object OKDialog { object OKDialog {
@SuppressLint("InflateParams") @SuppressLint("InflateParams")
fun show(context: Context, title: String, message: String, runnable: Runnable? = null) { fun show(context: Context, title: String, message: String, runnable: Runnable? = null) {
var okClicked = false var okClicked = false
@ -217,4 +218,36 @@ object OKDialog {
.show() .show()
.setCanceledOnTouchOutside(false) .setCanceledOnTouchOutside(false)
} }
@SuppressLint("InflateParams")
fun showYesNoCancel(context: Context, title: String, message: String, yes: Runnable?, no: Runnable? = null) {
var okClicked = false
AlertDialogHelper.Builder(context)
.setMessage(message)
.setCustomTitle(AlertDialogHelper.buildCustomTitle(context, title))
.setPositiveButton(R.string.yes) { dialog: DialogInterface, _: Int ->
if (okClicked) return@setPositiveButton
else {
okClicked = true
dialog.dismiss()
SystemClock.sleep(100)
runOnUiThread(yes)
}
}
.setNegativeButton(R.string.no) { dialog: DialogInterface, _: Int ->
if (okClicked) return@setNegativeButton
else {
okClicked = true
dialog.dismiss()
SystemClock.sleep(100)
runOnUiThread(no)
}
}
.setNeutralButton(R.string.cancel) { dialog: DialogInterface, _: Int ->
dialog.dismiss()
}
.show()
.setCanceledOnTouchOutside(false)
}
} }

View file

@ -95,6 +95,8 @@
<string name="btwatchdog_title">BT Watchdog</string> <string name="btwatchdog_title">BT Watchdog</string>
<string name="btwatchdog_summary">Switches off the phone\'s bluetooth for one second if no connection to the pump is possible. This may help on some phones where the bluetooth stack freezes.</string> <string name="btwatchdog_summary">Switches off the phone\'s bluetooth for one second if no connection to the pump is possible. This may help on some phones where the bluetooth stack freezes.</string>
<string name="pairing">Pairing</string> <string name="pairing">Pairing</string>
<string name="yes">Yes</string>
<string name="no">No</string>
<!-- Constraints--> <!-- Constraints-->
<string name="limitingbasalratio">Limiting max basal rate to %1$.2f U/h because of %2$s</string> <string name="limitingbasalratio">Limiting max basal rate to %1$.2f U/h because of %2$s</string>