From 554b14e9ef7efd94c9a73f65e4075d3f49852b3c Mon Sep 17 00:00:00 2001 From: Philoul Date: Thu, 24 Dec 2020 11:06:50 +0100 Subject: [PATCH 01/10] Increase height of Compact Tab and Profile/TT row --- .../java/info/nightscout/androidaps/MainActivity.kt | 6 +++++- .../res/layout/overview_loop_pumpstatus_layout.xml | 12 ++++++------ 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/info/nightscout/androidaps/MainActivity.kt b/app/src/main/java/info/nightscout/androidaps/MainActivity.kt index 951638d9ae..71ead679db 100644 --- a/app/src/main/java/info/nightscout/androidaps/MainActivity.kt +++ b/app/src/main/java/info/nightscout/androidaps/MainActivity.kt @@ -225,7 +225,11 @@ class MainActivity : NoSplashAppCompatActivity() { if (sp.getBoolean(R.string.key_short_tabtitles, false)) { tabs_normal.visibility = View.GONE tabs_compact.visibility = View.VISIBLE - toolbar.layoutParams = LinearLayout.LayoutParams(Toolbar.LayoutParams.MATCH_PARENT, resources.getDimension(R.dimen.compact_height).toInt()) + val typedValue = TypedValue() + if (theme.resolveAttribute(R.attr.actionBarSize, typedValue, true)) { + toolbar.layoutParams = LinearLayout.LayoutParams(Toolbar.LayoutParams.MATCH_PARENT, + TypedValue.complexToDimensionPixelSize(typedValue.data, resources.displayMetrics)) + } TabLayoutMediator(tabs_compact, main_pager) { tab, position -> tab.text = (main_pager.adapter as TabPageAdapter).getPluginAt(position).nameShort }.attach() diff --git a/app/src/main/res/layout/overview_loop_pumpstatus_layout.xml b/app/src/main/res/layout/overview_loop_pumpstatus_layout.xml index 98c0d0bd62..d52d6007b9 100644 --- a/app/src/main/res/layout/overview_loop_pumpstatus_layout.xml +++ b/app/src/main/res/layout/overview_loop_pumpstatus_layout.xml @@ -19,8 +19,8 @@ android:layout_marginEnd="5dp" android:layout_weight="1" android:gravity="center_vertical|center_horizontal" - android:paddingTop="3dp" - android:paddingBottom="3dp" + android:paddingTop="6dp" + android:paddingBottom="6dp" android:text="Profile" android:textAppearance="?android:attr/textAppearanceSmall" /> @@ -31,8 +31,8 @@ android:layout_gravity="end" android:layout_weight="1" android:gravity="center_vertical|center_horizontal" - android:paddingTop="3dp" - android:paddingBottom="3dp" + android:paddingTop="6dp" + android:paddingBottom="6dp" android:text="TempTarget" android:textAppearance="?android:attr/textAppearanceSmall" android:textColor="@color/mdtp_white" /> @@ -53,8 +53,8 @@ android:layout_marginLeft="5dp" android:layout_marginRight="5dp" android:gravity="center_vertical|center_horizontal" - android:paddingTop="3dp" - android:paddingBottom="3dp" + android:paddingTop="6dp" + android:paddingBottom="6dp" android:text="@string/initializing" android:textAppearance="?android:attr/textAppearanceSmall" /> From 47fe4d83be14c75e5f5716ff0e3eaaa8fe16c01e Mon Sep 17 00:00:00 2001 From: Philoul Date: Fri, 25 Dec 2020 16:47:42 +0100 Subject: [PATCH 02/10] First draft --- .../androidaps/dialogs/LoopDialog.kt | 373 ++++++++++++++++++ app/src/main/res/layout/dialog_loop.xml | 240 +++++++++++ 2 files changed, 613 insertions(+) create mode 100644 app/src/main/java/info/nightscout/androidaps/dialogs/LoopDialog.kt create mode 100644 app/src/main/res/layout/dialog_loop.xml diff --git a/app/src/main/java/info/nightscout/androidaps/dialogs/LoopDialog.kt b/app/src/main/java/info/nightscout/androidaps/dialogs/LoopDialog.kt new file mode 100644 index 0000000000..1ee243b72b --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/dialogs/LoopDialog.kt @@ -0,0 +1,373 @@ +package info.nightscout.androidaps.dialogs + +import android.os.Bundle +import android.text.Editable +import android.text.TextWatcher +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.view.Window +import android.view.WindowManager +import android.widget.AdapterView +import android.widget.AdapterView.OnItemSelectedListener +import android.widget.ArrayAdapter +import android.widget.CompoundButton +import androidx.fragment.app.FragmentManager +import dagger.android.support.DaggerDialogFragment +import info.nightscout.androidaps.Constants +import info.nightscout.androidaps.MainApp +import info.nightscout.androidaps.R +import info.nightscout.androidaps.data.Profile +import info.nightscout.androidaps.db.BgReading +import info.nightscout.androidaps.interfaces.ActivePluginProvider +import info.nightscout.androidaps.interfaces.Constraint +import info.nightscout.androidaps.interfaces.ProfileFunction +import info.nightscout.androidaps.logging.AAPSLogger +import info.nightscout.androidaps.logging.LTag +import info.nightscout.androidaps.plugins.bus.RxBusWrapper +import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker +import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin +import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventAutosensCalculationFinished +import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin +import info.nightscout.androidaps.utils.DecimalFormatter +import info.nightscout.androidaps.utils.FabricPrivacy +import info.nightscout.androidaps.utils.SafeParse +import info.nightscout.androidaps.utils.ToastUtils +import info.nightscout.androidaps.utils.extensions.toVisibility +import info.nightscout.androidaps.utils.resources.ResourceHelper +import info.nightscout.androidaps.utils.sharedPreferences.SP +import info.nightscout.androidaps.utils.wizard.BolusWizard +import io.reactivex.android.schedulers.AndroidSchedulers +import io.reactivex.disposables.CompositeDisposable +import kotlinx.android.synthetic.main.dialog_wizard.* +import java.text.DecimalFormat +import java.util.* +import javax.inject.Inject +import kotlin.math.abs + +class LoopDialog : DaggerDialogFragment() { + + @Inject lateinit var aapsLogger: AAPSLogger + @Inject lateinit var constraintChecker: ConstraintChecker + @Inject lateinit var mainApp: MainApp + @Inject lateinit var sp: SP + @Inject lateinit var rxBus: RxBusWrapper + @Inject lateinit var fabricPrivacy: FabricPrivacy + @Inject lateinit var resourceHelper: ResourceHelper + @Inject lateinit var profileFunction: ProfileFunction + @Inject lateinit var treatmentsPlugin: TreatmentsPlugin + @Inject lateinit var activePlugin: ActivePluginProvider + @Inject lateinit var iobCobCalculatorPlugin: IobCobCalculatorPlugin + + private var wizard: BolusWizard? = null + + //one shot guards + private var okClicked: Boolean = false + + private val textWatcher = 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() + } + } + + private var disposable: CompositeDisposable = CompositeDisposable() + + override fun onStart() { + super.onStart() + dialog?.window?.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT) + } + + override fun onSaveInstanceState(savedInstanceState: Bundle) { + super.onSaveInstanceState(savedInstanceState) + savedInstanceState.putDouble("treatments_wizard_bg_input", treatments_wizard_bg_input.value) + savedInstanceState.putDouble("treatments_wizard_carbs_input", treatments_wizard_carbs_input.value) + savedInstanceState.putDouble("treatments_wizard_correction_input", treatments_wizard_correction_input.value) + savedInstanceState.putDouble("treatments_wizard_carb_time_input", treatments_wizard_carb_time_input.value) + } + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle?): View? { + dialog?.window?.requestFeature(Window.FEATURE_NO_TITLE) + dialog?.window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN) + isCancelable = true + dialog?.setCanceledOnTouchOutside(false) + + return inflater.inflate(R.layout.dialog_wizard, container, false) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + loadCheckedStates() + processCobCheckBox() + treatments_wizard_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() + + val maxCarbs = constraintChecker.getMaxCarbsAllowed().value() + val maxCorrection = constraintChecker.getMaxBolusAllowed().value() + + if (profileFunction.getUnits() == Constants.MGDL) + treatments_wizard_bg_input.setParams(savedInstanceState?.getDouble("treatments_wizard_bg_input") + ?: 0.0, 0.0, 500.0, 1.0, DecimalFormat("0"), false, ok, textWatcher) + else + treatments_wizard_bg_input.setParams(savedInstanceState?.getDouble("treatments_wizard_bg_input") + ?: 0.0, 0.0, 30.0, 0.1, DecimalFormat("0.0"), false, ok, textWatcher) + treatments_wizard_carbs_input.setParams(savedInstanceState?.getDouble("treatments_wizard_carbs_input") + ?: 0.0, 0.0, maxCarbs.toDouble(), 1.0, DecimalFormat("0"), false, ok, textWatcher) + val bolusStep = activePlugin.activePump.pumpDescription.bolusStep + treatments_wizard_correction_input.setParams(savedInstanceState?.getDouble("treatments_wizard_correction_input") + ?: 0.0, -maxCorrection, maxCorrection, bolusStep, DecimalFormatter.pumpSupportedBolusFormat(activePlugin.activePump), false, ok, textWatcher) + treatments_wizard_carb_time_input.setParams(savedInstanceState?.getDouble("treatments_wizard_carb_time_input") + ?: 0.0, -60.0, 60.0, 5.0, DecimalFormat("0"), false, ok, textWatcher) + initDialog() + + treatments_wizard_percent_used.text = resourceHelper.gs(R.string.format_percent, sp.getInt(R.string.key_boluswizard_percentage, 100)) + // ok button + ok.setOnClickListener { + if (okClicked) { + aapsLogger.debug(LTag.UI, "guarding: ok already clicked") + } else { + okClicked = true + calculateInsulin() + context?.let { context -> + wizard?.confirmAndExecute(context) + } + } + dismiss() + } + // cancel button + cancel.setOnClickListener { dismiss() } + // checkboxes + treatments_wizard_bgcheckbox.setOnCheckedChangeListener(::onCheckedChanged) + treatments_wizard_ttcheckbox.setOnCheckedChangeListener(::onCheckedChanged) + treatments_wizard_cobcheckbox.setOnCheckedChangeListener(::onCheckedChanged) + treatments_wizard_basaliobcheckbox.setOnCheckedChangeListener(::onCheckedChanged) + treatments_wizard_bolusiobcheckbox.setOnCheckedChangeListener(::onCheckedChanged) + treatments_wizard_bgtrendcheckbox.setOnCheckedChangeListener(::onCheckedChanged) + treatments_wizard_sbcheckbox.setOnCheckedChangeListener(::onCheckedChanged) + + val showCalc = sp.getBoolean(resourceHelper.gs(R.string.key_wizard_calculation_visible), false) + treatments_wizard_delimiter.visibility = showCalc.toVisibility() + treatments_wizard_resulttable.visibility = showCalc.toVisibility() + treatments_wizard_calculationcheckbox.isChecked = showCalc + treatments_wizard_calculationcheckbox.setOnCheckedChangeListener { _, isChecked -> + run { + sp.putBoolean(resourceHelper.gs(R.string.key_wizard_calculation_visible), isChecked) + treatments_wizard_delimiter.visibility = isChecked.toVisibility() + treatments_wizard_resulttable.visibility = isChecked.toVisibility() + } + } + // profile spinner + treatments_wizard_profile.onItemSelectedListener = object : OnItemSelectedListener { + override fun onNothingSelected(parent: AdapterView<*>?) { + ToastUtils.showToastInUiThread(mainApp, resourceHelper.gs(R.string.noprofileselected)) + ok.visibility = View.GONE + } + + override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) { + calculateInsulin() + ok.visibility = View.VISIBLE + } + } + // bus + disposable.add(rxBus + .toObservable(EventAutosensCalculationFinished::class.java) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe({ + activity?.runOnUiThread { calculateInsulin() } + }, { fabricPrivacy.logException(it) }) + ) + + } + + override fun onDestroyView() { + super.onDestroyView() + disposable.clear() + } + + private fun onCheckedChanged(buttonView: CompoundButton, @Suppress("UNUSED_PARAMETER") state: Boolean) { + saveCheckedStates() + treatments_wizard_ttcheckbox.isEnabled = treatments_wizard_bgcheckbox.isChecked && treatmentsPlugin.tempTargetFromHistory != null + if (buttonView.id == treatments_wizard_cobcheckbox.id) + processCobCheckBox() + calculateInsulin() + } + + private fun processCobCheckBox() { + if (treatments_wizard_cobcheckbox.isChecked) { + treatments_wizard_bolusiobcheckbox.isEnabled = false + treatments_wizard_basaliobcheckbox.isEnabled = false + treatments_wizard_bolusiobcheckbox.isChecked = true + treatments_wizard_basaliobcheckbox.isChecked = true + } else { + treatments_wizard_bolusiobcheckbox.isEnabled = true + treatments_wizard_basaliobcheckbox.isEnabled = true + } + } + + private fun saveCheckedStates() { + sp.putBoolean(resourceHelper.gs(R.string.key_wizard_include_cob), treatments_wizard_cobcheckbox.isChecked) + sp.putBoolean(resourceHelper.gs(R.string.key_wizard_include_trend_bg), treatments_wizard_bgtrendcheckbox.isChecked) + } + + private fun loadCheckedStates() { + treatments_wizard_bgtrendcheckbox.isChecked = sp.getBoolean(resourceHelper.gs(R.string.key_wizard_include_trend_bg), false) + treatments_wizard_cobcheckbox.isChecked = sp.getBoolean(resourceHelper.gs(R.string.key_wizard_include_cob), false) + } + + private fun initDialog() { + val profile = profileFunction.getProfile() + val profileStore = activePlugin.activeProfileInterface.profile + + if (profile == null || profileStore == null) { + ToastUtils.showToastInUiThread(mainApp, resourceHelper.gs(R.string.noprofile)) + dismiss() + return + } + + val profileList: ArrayList + profileList = profileStore.getProfileList() + profileList.add(0, resourceHelper.gs(R.string.active)) + context?.let { context -> + val adapter = ArrayAdapter(context, R.layout.spinner_centered, profileList) + treatments_wizard_profile.adapter = adapter + } ?: return + + val units = profileFunction.getUnits() + treatments_wizard_bgunits.text = units + if (units == Constants.MGDL) + treatments_wizard_bg_input.setStep(1.0) + else + treatments_wizard_bg_input.setStep(0.1) + + // Set BG if not old + val lastBg = iobCobCalculatorPlugin.actualBg() + + if (lastBg != null) { + treatments_wizard_bg_input.value = lastBg.valueToUnits(units) + } else { + treatments_wizard_bg_input.value = 0.0 + } + treatments_wizard_ttcheckbox.isEnabled = treatmentsPlugin.tempTargetFromHistory != null + + // IOB calculation + treatmentsPlugin.updateTotalIOBTreatments() + val bolusIob = treatmentsPlugin.lastCalculationTreatments.round() + treatmentsPlugin.updateTotalIOBTempBasals() + val basalIob = treatmentsPlugin.lastCalculationTempBasals.round() + + treatments_wizard_bolusiobinsulin.text = resourceHelper.gs(R.string.formatinsulinunits, -bolusIob.iob) + treatments_wizard_basaliobinsulin.text = resourceHelper.gs(R.string.formatinsulinunits, -basalIob.basaliob) + + calculateInsulin() + + treatments_wizard_percent_used.visibility = (sp.getInt(R.string.key_boluswizard_percentage, 100) != 100).toVisibility() + } + + private fun calculateInsulin() { + val profileStore = activePlugin.activeProfileInterface.profile + if (treatments_wizard_profile?.selectedItem == null || profileStore == null) + return // not initialized yet + var profileName = treatments_wizard_profile.selectedItem.toString() + val specificProfile: Profile? + if (profileName == resourceHelper.gs(R.string.active)) { + specificProfile = profileFunction.getProfile() + profileName = profileFunction.getProfileName() + } else + specificProfile = profileStore.getSpecificProfile(profileName) + + if (specificProfile == null) return + + // Entered values + var bg = SafeParse.stringToDouble(treatments_wizard_bg_input.text) + val carbs = SafeParse.stringToInt(treatments_wizard_carbs_input.text) + val correction = SafeParse.stringToDouble(treatments_wizard_correction_input.text) + val carbsAfterConstraint = constraintChecker.applyCarbsConstraints(Constraint(carbs)).value() + if (abs(carbs - carbsAfterConstraint) > 0.01) { + treatments_wizard_carbs_input.value = 0.0 + ToastUtils.showToastInUiThread(mainApp, resourceHelper.gs(R.string.carbsconstraintapplied)) + return + } + + bg = if (treatments_wizard_bgcheckbox.isChecked) bg else 0.0 + val tempTarget = if (treatments_wizard_ttcheckbox.isChecked) treatmentsPlugin.tempTargetFromHistory else null + + // COB + var cob = 0.0 + if (treatments_wizard_cobcheckbox.isChecked) { + val cobInfo = iobCobCalculatorPlugin.getCobInfo(false, "Wizard COB") + cobInfo.displayCob?.let { cob = it } + } + + val carbTime = SafeParse.stringToInt(treatments_wizard_carb_time_input.text) + + wizard = BolusWizard(mainApp).doCalc(specificProfile, profileName, tempTarget, carbsAfterConstraint, cob, bg, correction, + sp.getInt(R.string.key_boluswizard_percentage, 100).toDouble(), + treatments_wizard_bgcheckbox.isChecked, + treatments_wizard_cobcheckbox.isChecked, + treatments_wizard_bolusiobcheckbox.isChecked, + treatments_wizard_basaliobcheckbox.isChecked, + treatments_wizard_sbcheckbox.isChecked, + treatments_wizard_ttcheckbox.isChecked, + treatments_wizard_bgtrendcheckbox.isChecked, + treatment_wizard_notes.text.toString(), carbTime) + + 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) + treatments_wizard_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) + treatments_wizard_carbsinsulin.text = resourceHelper.gs(R.string.formatinsulinunits, wizard.insulinFromCarbs) + + treatments_wizard_bolusiobinsulin.text = resourceHelper.gs(R.string.formatinsulinunits, wizard.insulinFromBolusIOB) + treatments_wizard_basaliobinsulin.text = resourceHelper.gs(R.string.formatinsulinunits, wizard.insulinFromBasalsIOB) + + treatments_wizard_correctioninsulin.text = resourceHelper.gs(R.string.formatinsulinunits, wizard.insulinFromCorrection) + + // Superbolus + treatments_wizard_sb.text = if (treatments_wizard_sbcheckbox.isChecked) resourceHelper.gs(R.string.twohours) else "" + treatments_wizard_sbinsulin.text = resourceHelper.gs(R.string.formatinsulinunits, wizard.insulinFromSuperBolus) + + // Trend + if (treatments_wizard_bgtrendcheckbox.isChecked && wizard.glucoseStatus != null) { + treatments_wizard_bgtrend.text = ((if (wizard.trend > 0) "+" else "") + + Profile.toUnitsString(wizard.trend * 3, wizard.trend * 3 / Constants.MMOLL_TO_MGDL, profileFunction.getUnits()) + + " " + profileFunction.getUnits()) + } else { + treatments_wizard_bgtrend.text = "" + } + treatments_wizard_bgtrendinsulin.text = resourceHelper.gs(R.string.formatinsulinunits, wizard.insulinFromTrend) + + // COB + if (treatments_wizard_cobcheckbox.isChecked) { + treatments_wizard_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) + } else { + treatments_wizard_cob.text = "" + treatments_wizard_cobinsulin.text = "" + } + + if (wizard.calculatedTotalInsulin > 0.0 || carbsAfterConstraint > 0.0) { + 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 "" + treatments_wizard_total.text = resourceHelper.gs(R.string.result_insulin_carbs, insulinText, carbsText) + ok.visibility = View.VISIBLE + } else { + treatments_wizard_total.text = resourceHelper.gs(R.string.missing_carbs, wizard.carbsEquivalent.toInt()) + ok.visibility = View.INVISIBLE + } + } + + } + + override fun show(manager: FragmentManager, tag: String?) { + try { + manager.beginTransaction().let { + it.add(this, tag) + it.commitAllowingStateLoss() + } + } catch (e: IllegalStateException) { + aapsLogger.debug(e.localizedMessage) + } + } +} diff --git a/app/src/main/res/layout/dialog_loop.xml b/app/src/main/res/layout/dialog_loop.xml new file mode 100644 index 0000000000..8fd4028ccd --- /dev/null +++ b/app/src/main/res/layout/dialog_loop.xml @@ -0,0 +1,240 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From 363fe638af71417d3b2b581a2811d6d2a6390c84 Mon Sep 17 00:00:00 2001 From: Philoul Date: Fri, 25 Dec 2020 17:05:41 +0100 Subject: [PATCH 03/10] Second verion (only increase a little bit Compact height) --- .../main/java/info/nightscout/androidaps/MainActivity.kt | 6 +----- core/src/main/res/values/dimens.xml | 2 +- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/info/nightscout/androidaps/MainActivity.kt b/app/src/main/java/info/nightscout/androidaps/MainActivity.kt index 71ead679db..951638d9ae 100644 --- a/app/src/main/java/info/nightscout/androidaps/MainActivity.kt +++ b/app/src/main/java/info/nightscout/androidaps/MainActivity.kt @@ -225,11 +225,7 @@ class MainActivity : NoSplashAppCompatActivity() { if (sp.getBoolean(R.string.key_short_tabtitles, false)) { tabs_normal.visibility = View.GONE tabs_compact.visibility = View.VISIBLE - val typedValue = TypedValue() - if (theme.resolveAttribute(R.attr.actionBarSize, typedValue, true)) { - toolbar.layoutParams = LinearLayout.LayoutParams(Toolbar.LayoutParams.MATCH_PARENT, - TypedValue.complexToDimensionPixelSize(typedValue.data, resources.displayMetrics)) - } + toolbar.layoutParams = LinearLayout.LayoutParams(Toolbar.LayoutParams.MATCH_PARENT, resources.getDimension(R.dimen.compact_height).toInt()) TabLayoutMediator(tabs_compact, main_pager) { tab, position -> tab.text = (main_pager.adapter as TabPageAdapter).getPluginAt(position).nameShort }.attach() diff --git a/core/src/main/res/values/dimens.xml b/core/src/main/res/values/dimens.xml index b650a33ce6..0afd239ee6 100644 --- a/core/src/main/res/values/dimens.xml +++ b/core/src/main/res/values/dimens.xml @@ -2,7 +2,7 @@ 16dp 16dp - 30dp + 42dp 16dp 8dp From 7ad84bbdec927e333337ebb29d9ae86aa981ba4d Mon Sep 17 00:00:00 2001 From: Bart Sopers Date: Fri, 25 Dec 2020 19:38:45 +0100 Subject: [PATCH 04/10] Revert "Update version for Omnipod" This reverts commit 302622bf699a05b7dd896ad97c857c4a0562459c. --- app/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle b/app/build.gradle index af78525894..c9e31881d3 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -120,7 +120,7 @@ android { targetSdkVersion 28 multiDexEnabled true versionCode 1500 - version "2.8.0-dev-omnipod" + version "2.7.2-dev" buildConfigField "String", "VERSION", '"' + version + '"' buildConfigField "String", "BUILDVERSION", '"' + generateGitBuild() + '-' + generateDate() + '"' buildConfigField "String", "REMOTE", '"' + generateGitRemote() + '"' From cefdaa471db1ad42e60bed87c2c41777f4ceefe9 Mon Sep 17 00:00:00 2001 From: Philoul Date: Sat, 26 Dec 2020 17:40:16 +0100 Subject: [PATCH 05/10] Replace Loop Menu by Loop Dialog --- .../dependencyInjection/FragmentsModule.kt | 1 + .../androidaps/dialogs/LoopDialog.kt | 487 ++++++++---------- .../general/overview/OverviewFragment.kt | 23 +- .../main/res/drawable/ic_loop_reconnect.xml | 12 + app/src/main/res/drawable/ic_loop_resume.xml | 12 + app/src/main/res/layout/dialog_loop.xml | 329 +++++++----- app/src/main/res/values/strings.xml | 7 + icons/loop_reconnect.svg | 13 + icons/loop_resume.svg | 12 + 9 files changed, 502 insertions(+), 394 deletions(-) create mode 100644 app/src/main/res/drawable/ic_loop_reconnect.xml create mode 100644 app/src/main/res/drawable/ic_loop_resume.xml create mode 100644 icons/loop_reconnect.svg create mode 100644 icons/loop_resume.svg diff --git a/app/src/main/java/info/nightscout/androidaps/dependencyInjection/FragmentsModule.kt b/app/src/main/java/info/nightscout/androidaps/dependencyInjection/FragmentsModule.kt index 42dd3e2972..c7cfec45eb 100644 --- a/app/src/main/java/info/nightscout/androidaps/dependencyInjection/FragmentsModule.kt +++ b/app/src/main/java/info/nightscout/androidaps/dependencyInjection/FragmentsModule.kt @@ -109,6 +109,7 @@ abstract class FragmentsModule { @ContributesAndroidInjector abstract fun contributesChooseActionDialog(): ChooseActionDialog @ContributesAndroidInjector abstract fun contributesChooseTriggerDialog(): ChooseTriggerDialog @ContributesAndroidInjector abstract fun contributesInsulinDialog(): InsulinDialog + @ContributesAndroidInjector abstract fun contributesLoopDialog(): LoopDialog @ContributesAndroidInjector abstract fun contributesObjectivesExamDialog(): ObjectivesExamDialog @ContributesAndroidInjector abstract fun contributesProfileSwitchDialog(): ProfileSwitchDialog @ContributesAndroidInjector abstract fun contributesTempBasalDialog(): TempBasalDialog diff --git a/app/src/main/java/info/nightscout/androidaps/dialogs/LoopDialog.kt b/app/src/main/java/info/nightscout/androidaps/dialogs/LoopDialog.kt index 1ee243b72b..a21d96f56c 100644 --- a/app/src/main/java/info/nightscout/androidaps/dialogs/LoopDialog.kt +++ b/app/src/main/java/info/nightscout/androidaps/dialogs/LoopDialog.kt @@ -1,79 +1,49 @@ package info.nightscout.androidaps.dialogs +import android.content.Intent import android.os.Bundle -import android.text.Editable -import android.text.TextWatcher -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import android.view.Window -import android.view.WindowManager -import android.widget.AdapterView -import android.widget.AdapterView.OnItemSelectedListener -import android.widget.ArrayAdapter -import android.widget.CompoundButton +import android.view.* import androidx.fragment.app.FragmentManager import dagger.android.support.DaggerDialogFragment -import info.nightscout.androidaps.Constants import info.nightscout.androidaps.MainApp import info.nightscout.androidaps.R -import info.nightscout.androidaps.data.Profile -import info.nightscout.androidaps.db.BgReading -import info.nightscout.androidaps.interfaces.ActivePluginProvider -import info.nightscout.androidaps.interfaces.Constraint -import info.nightscout.androidaps.interfaces.ProfileFunction +import info.nightscout.androidaps.activities.ErrorHelperActivity +import info.nightscout.androidaps.events.EventRefreshOverview +import info.nightscout.androidaps.interfaces.* import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.LTag +import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin +import info.nightscout.androidaps.plugins.aps.loop.events.EventNewOpenLoopNotification import info.nightscout.androidaps.plugins.bus.RxBusWrapper -import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker -import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin -import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventAutosensCalculationFinished -import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin -import info.nightscout.androidaps.utils.DecimalFormatter -import info.nightscout.androidaps.utils.FabricPrivacy -import info.nightscout.androidaps.utils.SafeParse -import info.nightscout.androidaps.utils.ToastUtils -import info.nightscout.androidaps.utils.extensions.toVisibility +import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin +import info.nightscout.androidaps.queue.Callback +import info.nightscout.androidaps.utils.* +import info.nightscout.androidaps.utils.alertDialogs.OKDialog import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.sharedPreferences.SP -import info.nightscout.androidaps.utils.wizard.BolusWizard import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.disposables.CompositeDisposable -import kotlinx.android.synthetic.main.dialog_wizard.* -import java.text.DecimalFormat -import java.util.* +import kotlinx.android.synthetic.main.dialog_loop.* import javax.inject.Inject -import kotlin.math.abs class LoopDialog : DaggerDialogFragment() { @Inject lateinit var aapsLogger: AAPSLogger - @Inject lateinit var constraintChecker: ConstraintChecker @Inject lateinit var mainApp: MainApp @Inject lateinit var sp: SP @Inject lateinit var rxBus: RxBusWrapper @Inject lateinit var fabricPrivacy: FabricPrivacy @Inject lateinit var resourceHelper: ResourceHelper @Inject lateinit var profileFunction: ProfileFunction - @Inject lateinit var treatmentsPlugin: TreatmentsPlugin + @Inject lateinit var loopPlugin: LoopPlugin @Inject lateinit var activePlugin: ActivePluginProvider - @Inject lateinit var iobCobCalculatorPlugin: IobCobCalculatorPlugin - - private var wizard: BolusWizard? = null - - //one shot guards - private var okClicked: Boolean = false - - private val textWatcher = 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() - } - } + @Inject lateinit var commandQueue: CommandQueueProvider + @Inject lateinit var configBuilderPlugin: ConfigBuilderPlugin private var disposable: CompositeDisposable = CompositeDisposable() + private var showOkCancel: Boolean = true + override fun onStart() { super.onStart() dialog?.window?.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT) @@ -81,103 +51,51 @@ class LoopDialog : DaggerDialogFragment() { override fun onSaveInstanceState(savedInstanceState: Bundle) { super.onSaveInstanceState(savedInstanceState) - savedInstanceState.putDouble("treatments_wizard_bg_input", treatments_wizard_bg_input.value) - savedInstanceState.putDouble("treatments_wizard_carbs_input", treatments_wizard_carbs_input.value) - savedInstanceState.putDouble("treatments_wizard_correction_input", treatments_wizard_correction_input.value) - savedInstanceState.putDouble("treatments_wizard_carb_time_input", treatments_wizard_carb_time_input.value) + savedInstanceState.putInt("showOkCancel", if (showOkCancel) 1 else 0) } override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { + // load data from bundle + (savedInstanceState ?: arguments)?.let { bundle -> + showOkCancel = bundle.getInt("showOkCancel", 1) == 1 + } dialog?.window?.requestFeature(Window.FEATURE_NO_TITLE) dialog?.window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN) isCancelable = true dialog?.setCanceledOnTouchOutside(false) - return inflater.inflate(R.layout.dialog_wizard, container, false) + return inflater.inflate(R.layout.dialog_loop, container, false) } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - loadCheckedStates() - processCobCheckBox() - treatments_wizard_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() + updateGUI("LoopDialogOnViewCreated") - val maxCarbs = constraintChecker.getMaxCarbsAllowed().value() - val maxCorrection = constraintChecker.getMaxBolusAllowed().value() + overview_disable?.setOnClickListener { if(showOkCancel) onClick_OkCancelEnabled(it) else onClick(it); dismiss() } + overview_enable?.setOnClickListener { if(showOkCancel) onClick_OkCancelEnabled(it) else onClick(it); dismiss() } + overview_resume?.setOnClickListener { if(showOkCancel) onClick_OkCancelEnabled(it) else onClick(it); dismiss() } + overview_reconnect?.setOnClickListener { if(showOkCancel) onClick_OkCancelEnabled(it) else onClick(it); dismiss() } + overview_suspend_1h?.setOnClickListener { if(showOkCancel) onClick_OkCancelEnabled(it) else onClick(it); dismiss() } + overview_suspend_2h?.setOnClickListener { if(showOkCancel) onClick_OkCancelEnabled(it) else onClick(it); dismiss() } + overview_suspend_3h?.setOnClickListener { if(showOkCancel) onClick_OkCancelEnabled(it) else onClick(it); dismiss() } + overview_suspend_10h?.setOnClickListener { if(showOkCancel) onClick_OkCancelEnabled(it) else onClick(it); dismiss() } + overview_disconnect_15m?.setOnClickListener { if(showOkCancel) onClick_OkCancelEnabled(it) else onClick(it); dismiss() } + overview_disconnect_30m?.setOnClickListener { if(showOkCancel) onClick_OkCancelEnabled(it) else onClick(it); dismiss() } + overview_disconnect_1h?.setOnClickListener { if(showOkCancel) onClick_OkCancelEnabled(it) else onClick(it); dismiss() } + overview_disconnect_2h?.setOnClickListener { if(showOkCancel) onClick_OkCancelEnabled(it) else onClick(it); dismiss() } + overview_disconnect_3h?.setOnClickListener { if(showOkCancel) onClick_OkCancelEnabled(it) else onClick(it); dismiss() } - if (profileFunction.getUnits() == Constants.MGDL) - treatments_wizard_bg_input.setParams(savedInstanceState?.getDouble("treatments_wizard_bg_input") - ?: 0.0, 0.0, 500.0, 1.0, DecimalFormat("0"), false, ok, textWatcher) - else - treatments_wizard_bg_input.setParams(savedInstanceState?.getDouble("treatments_wizard_bg_input") - ?: 0.0, 0.0, 30.0, 0.1, DecimalFormat("0.0"), false, ok, textWatcher) - treatments_wizard_carbs_input.setParams(savedInstanceState?.getDouble("treatments_wizard_carbs_input") - ?: 0.0, 0.0, maxCarbs.toDouble(), 1.0, DecimalFormat("0"), false, ok, textWatcher) - val bolusStep = activePlugin.activePump.pumpDescription.bolusStep - treatments_wizard_correction_input.setParams(savedInstanceState?.getDouble("treatments_wizard_correction_input") - ?: 0.0, -maxCorrection, maxCorrection, bolusStep, DecimalFormatter.pumpSupportedBolusFormat(activePlugin.activePump), false, ok, textWatcher) - treatments_wizard_carb_time_input.setParams(savedInstanceState?.getDouble("treatments_wizard_carb_time_input") - ?: 0.0, -60.0, 60.0, 5.0, DecimalFormat("0"), false, ok, textWatcher) - initDialog() - - treatments_wizard_percent_used.text = resourceHelper.gs(R.string.format_percent, sp.getInt(R.string.key_boluswizard_percentage, 100)) - // ok button - ok.setOnClickListener { - if (okClicked) { - aapsLogger.debug(LTag.UI, "guarding: ok already clicked") - } else { - okClicked = true - calculateInsulin() - context?.let { context -> - wizard?.confirmAndExecute(context) - } - } - dismiss() - } // cancel button - cancel.setOnClickListener { dismiss() } - // checkboxes - treatments_wizard_bgcheckbox.setOnCheckedChangeListener(::onCheckedChanged) - treatments_wizard_ttcheckbox.setOnCheckedChangeListener(::onCheckedChanged) - treatments_wizard_cobcheckbox.setOnCheckedChangeListener(::onCheckedChanged) - treatments_wizard_basaliobcheckbox.setOnCheckedChangeListener(::onCheckedChanged) - treatments_wizard_bolusiobcheckbox.setOnCheckedChangeListener(::onCheckedChanged) - treatments_wizard_bgtrendcheckbox.setOnCheckedChangeListener(::onCheckedChanged) - treatments_wizard_sbcheckbox.setOnCheckedChangeListener(::onCheckedChanged) + cancel?.setOnClickListener { dismiss() } - val showCalc = sp.getBoolean(resourceHelper.gs(R.string.key_wizard_calculation_visible), false) - treatments_wizard_delimiter.visibility = showCalc.toVisibility() - treatments_wizard_resulttable.visibility = showCalc.toVisibility() - treatments_wizard_calculationcheckbox.isChecked = showCalc - treatments_wizard_calculationcheckbox.setOnCheckedChangeListener { _, isChecked -> - run { - sp.putBoolean(resourceHelper.gs(R.string.key_wizard_calculation_visible), isChecked) - treatments_wizard_delimiter.visibility = isChecked.toVisibility() - treatments_wizard_resulttable.visibility = isChecked.toVisibility() - } - } - // profile spinner - treatments_wizard_profile.onItemSelectedListener = object : OnItemSelectedListener { - override fun onNothingSelected(parent: AdapterView<*>?) { - ToastUtils.showToastInUiThread(mainApp, resourceHelper.gs(R.string.noprofileselected)) - ok.visibility = View.GONE - } - - override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) { - calculateInsulin() - ok.visibility = View.VISIBLE - } - } // bus disposable.add(rxBus - .toObservable(EventAutosensCalculationFinished::class.java) + .toObservable(EventNewOpenLoopNotification::class.java) .observeOn(AndroidSchedulers.mainThread()) .subscribe({ - activity?.runOnUiThread { calculateInsulin() } + activity?.runOnUiThread { updateGUI("EventNewOpenLoopNotification") } }, { fabricPrivacy.logException(it) }) ) - } override fun onDestroyView() { @@ -185,37 +103,44 @@ class LoopDialog : DaggerDialogFragment() { disposable.clear() } - private fun onCheckedChanged(buttonView: CompoundButton, @Suppress("UNUSED_PARAMETER") state: Boolean) { - saveCheckedStates() - treatments_wizard_ttcheckbox.isEnabled = treatments_wizard_bgcheckbox.isChecked && treatmentsPlugin.tempTargetFromHistory != null - if (buttonView.id == treatments_wizard_cobcheckbox.id) - processCobCheckBox() - calculateInsulin() - } - - private fun processCobCheckBox() { - if (treatments_wizard_cobcheckbox.isChecked) { - treatments_wizard_bolusiobcheckbox.isEnabled = false - treatments_wizard_basaliobcheckbox.isEnabled = false - treatments_wizard_bolusiobcheckbox.isChecked = true - treatments_wizard_basaliobcheckbox.isChecked = true - } else { - treatments_wizard_bolusiobcheckbox.isEnabled = true - treatments_wizard_basaliobcheckbox.isEnabled = true + fun updateGUI(from: String) { + aapsLogger.debug("UpdateGUI from $from") + val pumpDescription: PumpDescription = activePlugin.activePump.pumpDescription + if (profileFunction.isProfileValid("LoopDialogUpdateGUI")) { + if (loopPlugin.isEnabled(PluginType.LOOP)) { + overview_enable?.visibility = View.GONE //sp.getBoolean(R.string.key_usesuperbolus, false).toVisibility() + overview_disable?.visibility = View.VISIBLE + if (!loopPlugin.isSuspended) { + overview_suspend_header?.text=resourceHelper.gs(R.string.suspendloop) + overview_resume?.visibility = View.GONE + overview_suspend_buttons?.visibility=View.VISIBLE + overview_suspend?.visibility=View.VISIBLE + } else { + if (!loopPlugin.isDisconnected) { + overview_suspend_header?.text = resourceHelper.gs(R.string.resumeloop) + overview_resume?.visibility = View.VISIBLE + overview_suspend_buttons?.visibility=View.GONE + overview_suspend?.visibility=View.VISIBLE + } else + overview_suspend?.visibility = View.GONE + } + } else { + overview_enable?.visibility = View.VISIBLE + overview_disable?.visibility = View.GONE + overview_suspend?.visibility = View.GONE + } + if (!loopPlugin.isDisconnected) { + overview_pump_header?.text = resourceHelper.gs(R.string.disconnectpump) + overview_disconnect_15m?.visibility = if (pumpDescription.tempDurationStep15mAllowed) View.VISIBLE else View.GONE + overview_disconnect_15m?.visibility = if (pumpDescription.tempDurationStep30mAllowed) View.VISIBLE else View.GONE + overview_disconnect_buttons?.visibility = View.VISIBLE + overview_reconnect?.visibility = View.GONE + } else { + overview_pump_header?.text = resourceHelper.gs(R.string.reconnect) + overview_disconnect_buttons?.visibility = View.GONE + overview_reconnect?.visibility = View.VISIBLE + } } - } - - private fun saveCheckedStates() { - sp.putBoolean(resourceHelper.gs(R.string.key_wizard_include_cob), treatments_wizard_cobcheckbox.isChecked) - sp.putBoolean(resourceHelper.gs(R.string.key_wizard_include_trend_bg), treatments_wizard_bgtrendcheckbox.isChecked) - } - - private fun loadCheckedStates() { - treatments_wizard_bgtrendcheckbox.isChecked = sp.getBoolean(resourceHelper.gs(R.string.key_wizard_include_trend_bg), false) - treatments_wizard_cobcheckbox.isChecked = sp.getBoolean(resourceHelper.gs(R.string.key_wizard_include_cob), false) - } - - private fun initDialog() { val profile = profileFunction.getProfile() val profileStore = activePlugin.activeProfileInterface.profile @@ -225,139 +150,149 @@ class LoopDialog : DaggerDialogFragment() { return } - val profileList: ArrayList - profileList = profileStore.getProfileList() - profileList.add(0, resourceHelper.gs(R.string.active)) - context?.let { context -> - val adapter = ArrayAdapter(context, R.layout.spinner_centered, profileList) - treatments_wizard_profile.adapter = adapter - } ?: return - - val units = profileFunction.getUnits() - treatments_wizard_bgunits.text = units - if (units == Constants.MGDL) - treatments_wizard_bg_input.setStep(1.0) - else - treatments_wizard_bg_input.setStep(0.1) - - // Set BG if not old - val lastBg = iobCobCalculatorPlugin.actualBg() - - if (lastBg != null) { - treatments_wizard_bg_input.value = lastBg.valueToUnits(units) - } else { - treatments_wizard_bg_input.value = 0.0 - } - treatments_wizard_ttcheckbox.isEnabled = treatmentsPlugin.tempTargetFromHistory != null - - // IOB calculation - treatmentsPlugin.updateTotalIOBTreatments() - val bolusIob = treatmentsPlugin.lastCalculationTreatments.round() - treatmentsPlugin.updateTotalIOBTempBasals() - val basalIob = treatmentsPlugin.lastCalculationTempBasals.round() - - treatments_wizard_bolusiobinsulin.text = resourceHelper.gs(R.string.formatinsulinunits, -bolusIob.iob) - treatments_wizard_basaliobinsulin.text = resourceHelper.gs(R.string.formatinsulinunits, -basalIob.basaliob) - - calculateInsulin() - - treatments_wizard_percent_used.visibility = (sp.getInt(R.string.key_boluswizard_percentage, 100) != 100).toVisibility() } - private fun calculateInsulin() { - val profileStore = activePlugin.activeProfileInterface.profile - if (treatments_wizard_profile?.selectedItem == null || profileStore == null) - return // not initialized yet - var profileName = treatments_wizard_profile.selectedItem.toString() - val specificProfile: Profile? - if (profileName == resourceHelper.gs(R.string.active)) { - specificProfile = profileFunction.getProfile() - profileName = profileFunction.getProfileName() - } else - specificProfile = profileStore.getSpecificProfile(profileName) - - if (specificProfile == null) return - - // Entered values - var bg = SafeParse.stringToDouble(treatments_wizard_bg_input.text) - val carbs = SafeParse.stringToInt(treatments_wizard_carbs_input.text) - val correction = SafeParse.stringToDouble(treatments_wizard_correction_input.text) - val carbsAfterConstraint = constraintChecker.applyCarbsConstraints(Constraint(carbs)).value() - if (abs(carbs - carbsAfterConstraint) > 0.01) { - treatments_wizard_carbs_input.value = 0.0 - ToastUtils.showToastInUiThread(mainApp, resourceHelper.gs(R.string.carbsconstraintapplied)) - return + fun onClick_OkCancelEnabled(v: View): Boolean { + var description = "" + when(v.id) { + R.id.overview_disable -> description = resourceHelper.gs(R.string.disableloop) + R.id.overview_enable -> description = resourceHelper.gs(R.string.enableloop) + R.id.overview_resume -> description = resourceHelper.gs(R.string.resume) + R.id.overview_reconnect -> description = resourceHelper.gs(R.string.reconnect) + R.id.overview_suspend_1h -> description = resourceHelper.gs(R.string.suspendloopfor1h) + R.id.overview_suspend_2h -> description = resourceHelper.gs(R.string.suspendloopfor2h) + R.id.overview_suspend_3h -> description = resourceHelper.gs(R.string.suspendloopfor3h) + R.id.overview_suspend_10h -> description = resourceHelper.gs(R.string.suspendloopfor10h) + R.id.overview_disconnect_15m -> description = resourceHelper.gs(R.string.disconnectpumpfor15m) + R.id.overview_disconnect_30m -> description = resourceHelper.gs(R.string.disconnectpumpfor30m) + R.id.overview_disconnect_1h -> description = resourceHelper.gs(R.string.disconnectpumpfor1h) + R.id.overview_disconnect_2h -> description = resourceHelper.gs(R.string.disconnectpumpfor2h) + R.id.overview_disconnect_3h -> description = resourceHelper.gs(R.string.disconnectpumpfor3h) } - - bg = if (treatments_wizard_bgcheckbox.isChecked) bg else 0.0 - val tempTarget = if (treatments_wizard_ttcheckbox.isChecked) treatmentsPlugin.tempTargetFromHistory else null - - // COB - var cob = 0.0 - if (treatments_wizard_cobcheckbox.isChecked) { - val cobInfo = iobCobCalculatorPlugin.getCobInfo(false, "Wizard COB") - cobInfo.displayCob?.let { cob = it } + activity?.let { activity -> + OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.confirm), description, Runnable { + onClick(v) + }) } + return true + } - val carbTime = SafeParse.stringToInt(treatments_wizard_carb_time_input.text) - - wizard = BolusWizard(mainApp).doCalc(specificProfile, profileName, tempTarget, carbsAfterConstraint, cob, bg, correction, - sp.getInt(R.string.key_boluswizard_percentage, 100).toDouble(), - treatments_wizard_bgcheckbox.isChecked, - treatments_wizard_cobcheckbox.isChecked, - treatments_wizard_bolusiobcheckbox.isChecked, - treatments_wizard_basaliobcheckbox.isChecked, - treatments_wizard_sbcheckbox.isChecked, - treatments_wizard_ttcheckbox.isChecked, - treatments_wizard_bgtrendcheckbox.isChecked, - treatment_wizard_notes.text.toString(), carbTime) - - 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) - treatments_wizard_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) - treatments_wizard_carbsinsulin.text = resourceHelper.gs(R.string.formatinsulinunits, wizard.insulinFromCarbs) - - treatments_wizard_bolusiobinsulin.text = resourceHelper.gs(R.string.formatinsulinunits, wizard.insulinFromBolusIOB) - treatments_wizard_basaliobinsulin.text = resourceHelper.gs(R.string.formatinsulinunits, wizard.insulinFromBasalsIOB) - - treatments_wizard_correctioninsulin.text = resourceHelper.gs(R.string.formatinsulinunits, wizard.insulinFromCorrection) - - // Superbolus - treatments_wizard_sb.text = if (treatments_wizard_sbcheckbox.isChecked) resourceHelper.gs(R.string.twohours) else "" - treatments_wizard_sbinsulin.text = resourceHelper.gs(R.string.formatinsulinunits, wizard.insulinFromSuperBolus) - - // Trend - if (treatments_wizard_bgtrendcheckbox.isChecked && wizard.glucoseStatus != null) { - treatments_wizard_bgtrend.text = ((if (wizard.trend > 0) "+" else "") - + Profile.toUnitsString(wizard.trend * 3, wizard.trend * 3 / Constants.MMOLL_TO_MGDL, profileFunction.getUnits()) - + " " + profileFunction.getUnits()) - } else { - treatments_wizard_bgtrend.text = "" - } - treatments_wizard_bgtrendinsulin.text = resourceHelper.gs(R.string.formatinsulinunits, wizard.insulinFromTrend) - - // COB - if (treatments_wizard_cobcheckbox.isChecked) { - treatments_wizard_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) - } else { - treatments_wizard_cob.text = "" - treatments_wizard_cobinsulin.text = "" + fun onClick(v: View): Boolean { + val profile = profileFunction.getProfile() ?: return true + when (v.id) { + R.id.overview_disable -> { + aapsLogger.debug("USER ENTRY: LOOP DISABLED") + loopPlugin.setPluginEnabled(PluginType.LOOP, false) + loopPlugin.setFragmentVisible(PluginType.LOOP, false) + configBuilderPlugin.storeSettings("DisablingLoop") + rxBus.send(EventRefreshOverview("suspendmenu")) + commandQueue.cancelTempBasal(true, object : Callback() { + override fun run() { + if (!result.success) { + ToastUtils.showToastInUiThread(context, resourceHelper.gs(R.string.tempbasaldeliveryerror)) + } + } + }) + loopPlugin.createOfflineEvent(24 * 60) // upload 24h, we don't know real duration + return true } - if (wizard.calculatedTotalInsulin > 0.0 || carbsAfterConstraint > 0.0) { - 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 "" - treatments_wizard_total.text = resourceHelper.gs(R.string.result_insulin_carbs, insulinText, carbsText) - ok.visibility = View.VISIBLE - } else { - treatments_wizard_total.text = resourceHelper.gs(R.string.missing_carbs, wizard.carbsEquivalent.toInt()) - ok.visibility = View.INVISIBLE + R.id.overview_enable -> { + aapsLogger.debug("USER ENTRY: LOOP ENABLED") + loopPlugin.setPluginEnabled(PluginType.LOOP, true) + loopPlugin.setFragmentVisible(PluginType.LOOP, true) + configBuilderPlugin.storeSettings("EnablingLoop") + rxBus.send(EventRefreshOverview("suspendmenu")) + loopPlugin.createOfflineEvent(0) + return true + } + + R.id.overview_resume, R.id.overview_reconnect -> { + aapsLogger.debug("USER ENTRY: RESUME") + loopPlugin.suspendTo(0L) + rxBus.send(EventRefreshOverview("suspendmenu")) + commandQueue.cancelTempBasal(true, object : Callback() { + override fun run() { + 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) + } + } + }) + sp.putBoolean(R.string.key_objectiveusereconnect, true) + loopPlugin.createOfflineEvent(0) + return true + } + + R.id.overview_suspend_1h -> { + aapsLogger.debug("USER ENTRY: SUSPEND 1h") + loopPlugin.suspendLoop(60) + rxBus.send(EventRefreshOverview("suspendmenu")) + return true + } + + R.id.overview_suspend_2h -> { + aapsLogger.debug("USER ENTRY: SUSPEND 2h") + loopPlugin.suspendLoop(120) + rxBus.send(EventRefreshOverview("suspendmenu")) + return true + } + + R.id.overview_suspend_3h -> { + aapsLogger.debug("USER ENTRY: SUSPEND 3h") + loopPlugin.suspendLoop(180) + rxBus.send(EventRefreshOverview("suspendmenu")) + return true + } + + R.id.overview_suspend_10h -> { + aapsLogger.debug("USER ENTRY: SUSPEND 10h") + loopPlugin.suspendLoop(600) + rxBus.send(EventRefreshOverview("suspendmenu")) + return true + } + + R.id.overview_disconnect_15m -> { + aapsLogger.debug("USER ENTRY: DISCONNECT 15m") + loopPlugin.disconnectPump(15, profile) + rxBus.send(EventRefreshOverview("suspendmenu")) + return true + } + + R.id.overview_disconnect_30m -> { + aapsLogger.debug("USER ENTRY: DISCONNECT 30m") + loopPlugin.disconnectPump(30, profile) + rxBus.send(EventRefreshOverview("suspendmenu")) + return true + } + + R.id.overview_disconnect_1h -> { + aapsLogger.debug("USER ENTRY: DISCONNECT 1h") + loopPlugin.disconnectPump(60, profile) + sp.putBoolean(R.string.key_objectiveusedisconnect, true) + rxBus.send(EventRefreshOverview("suspendmenu")) + return true + } + + R.id.overview_disconnect_2h -> { + aapsLogger.debug("USER ENTRY: DISCONNECT 2h") + loopPlugin.disconnectPump(120, profile) + rxBus.send(EventRefreshOverview("suspendmenu")) + return true + } + + R.id.overview_disconnect_3h -> { + aapsLogger.debug("USER ENTRY: DISCONNECT 3h") + loopPlugin.disconnectPump(180, profile) + rxBus.send(EventRefreshOverview("suspendmenu")) + return true } } - + return false } override fun show(manager: FragmentManager, tag: String?) { diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/OverviewFragment.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/OverviewFragment.kt index 31ea77b280..e9ac00be44 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/OverviewFragment.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/OverviewFragment.kt @@ -183,7 +183,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList overviewMenus.setupChartMenu(overview_chartMenuButton) prepareGraphs() - overviewMenus.setupPopupMenu(overview_apsmode, requireContext(), childFragmentManager) + //overviewMenus.setupPopupMenu(overview_apsmode, requireContext(), childFragmentManager) //overviewMenus.setupPopupMenu(overview_activeprofile, requireContext(), childFragmentManager) overview_activeprofile?.setOnClickListener(this) overview_activeprofile?.setOnLongClickListener(this) @@ -198,6 +198,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList overview_carbsbutton?.setOnClickListener(this) overview_quickwizardbutton?.setOnClickListener(this) overview_quickwizardbutton?.setOnLongClickListener(this) + overview_apsmode?.setOnClickListener(this) overview_apsmode?.setOnLongClickListener(this) overview_activeprofile?.setOnLongClickListener(this) } @@ -344,6 +345,14 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList } } } + + R.id.overview_apsmode -> { + val args = Bundle() + args.putInt("showOkCancel", 1) // 1-> true + val pvd = LoopDialog() + pvd.arguments = args + pvd.show(childFragmentManager, "Overview") + } } } } @@ -368,10 +377,22 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList startActivity(Intent(v.context, QuickWizardListActivity::class.java)) return true } + // R.id.overview_apsmode -> activity?.let { activity -> protectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, UIRunnable { LoopDialog().show(childFragmentManager, "Overview") })} + R.id.overview_apsmode -> { + val args = Bundle() + args.putInt("showOkCancel", 0) // 0-> false + val pvd = LoopDialog() + pvd.arguments = args + pvd.show(childFragmentManager, "Overview") + } + + /* R.id.overview_apsmode -> { OverviewMenus.showOKCancel = false v.performClick() } + + */ R.id.overview_temptarget -> v.performClick() R.id.overview_activeprofile -> activity?.let { activity -> protectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, UIRunnable { ProfileSwitchDialog().show(childFragmentManager, "Overview") })} diff --git a/app/src/main/res/drawable/ic_loop_reconnect.xml b/app/src/main/res/drawable/ic_loop_reconnect.xml new file mode 100644 index 0000000000..dd3592f2b0 --- /dev/null +++ b/app/src/main/res/drawable/ic_loop_reconnect.xml @@ -0,0 +1,12 @@ + + + + diff --git a/app/src/main/res/drawable/ic_loop_resume.xml b/app/src/main/res/drawable/ic_loop_resume.xml new file mode 100644 index 0000000000..9b3a842486 --- /dev/null +++ b/app/src/main/res/drawable/ic_loop_resume.xml @@ -0,0 +1,12 @@ + + + + diff --git a/app/src/main/res/layout/dialog_loop.xml b/app/src/main/res/layout/dialog_loop.xml index 8fd4028ccd..101959240d 100644 --- a/app/src/main/res/layout/dialog_loop.xml +++ b/app/src/main/res/layout/dialog_loop.xml @@ -23,6 +23,7 @@ android:padding="5dp"> @@ -63,15 +64,32 @@ android:text="@string/loop" android:textAppearance="?android:attr/textAppearanceLarge" /> + + + android:orientation="vertical"> - - - + + android:textSize="11sp" + android:visibility="gone" /> + + + + + + - + + + + + + - + android:orientation="vertical"> + + + android:textSize="11sp" + android:visibility="gone" /> - + - + - + - + + + + + + + @@ -235,6 +320,16 @@ android:background="@color/listdelimiter" /> - +