diff --git a/app/build.gradle b/app/build.gradle index a99599c608..5b6c4ed3d2 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -109,7 +109,7 @@ android { defaultConfig { multiDexEnabled true versionCode 1500 - version "3.0.0.1-dev-h" + version "3.0.0.1-dev-i" buildConfigField "String", "VERSION", '"' + version + '"' buildConfigField "String", "BUILDVERSION", '"' + generateGitBuild() + '-' + generateDate() + '"' buildConfigField "String", "REMOTE", '"' + generateGitRemote() + '"' diff --git a/app/src/main/java/info/nightscout/androidaps/Widget.kt b/app/src/main/java/info/nightscout/androidaps/Widget.kt index 2d8268626e..aef1b1fd8d 100644 --- a/app/src/main/java/info/nightscout/androidaps/Widget.kt +++ b/app/src/main/java/info/nightscout/androidaps/Widget.kt @@ -13,7 +13,6 @@ import dagger.android.HasAndroidInjector import info.nightscout.androidaps.data.ProfileSealed import info.nightscout.androidaps.database.interfaces.end import info.nightscout.androidaps.extensions.directionToIcon -import info.nightscout.androidaps.extensions.isInProgress import info.nightscout.androidaps.extensions.toVisibility import info.nightscout.androidaps.extensions.valueToUnitsString import info.nightscout.androidaps.interfaces.* @@ -78,7 +77,7 @@ class Widget : AppWidgetProvider() { // Create an Intent to launch MainActivity when clicked val intent = Intent(context, MainActivity::class.java).also { it.action = intentAction } - val pendingIntent = PendingIntent.getActivity(context, 0, intent, 0) + val pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT) // Widgets allow click handlers to only launch pending intents views.setOnClickPendingIntent(R.id.widget_layout, pendingIntent) @@ -105,7 +104,11 @@ class Widget : AppWidgetProvider() { } ) views.setImageViewResource(R.id.arrow, trendCalculator.getTrendArrow(overviewData.lastBg).directionToIcon()) - //binding.infoLayout.arrow.setColorFilter(overviewData.lastBgColor(context)) + views.setInt(R.id.arrow, "setColorFilter", when { + overviewData.isLow -> rh.gc(R.color.low) + overviewData.isHigh -> rh.gc(R.color.high) + else -> rh.gc(R.color.inrange) + }) val glucoseStatus = glucoseStatusProvider.glucoseStatusData if (glucoseStatus != null) { @@ -127,21 +130,21 @@ class Widget : AppWidgetProvider() { } private fun updateTemporaryBasal(views: RemoteViews) { - views.setTextViewText(R.id.base_basal, overviewData.temporaryBasalText) - views.setTextColor(R.id.base_basal, overviewData.temporaryBasalColor) - views.setImageViewResource(R.id.base_basal_icon, overviewData.temporaryBasalIcon) + views.setTextViewText(R.id.base_basal, overviewData.temporaryBasalText(iobCobCalculator)) + views.setTextColor(R.id.base_basal, overviewData.temporaryBasalColor(iobCobCalculator)) + views.setImageViewResource(R.id.base_basal_icon, overviewData.temporaryBasalIcon(iobCobCalculator)) } private fun updateExtendedBolus(views: RemoteViews) { val pump = activePlugin.activePump - views.setTextViewText(R.id.extended_bolus, overviewData.extendedBolusText) + views.setTextViewText(R.id.extended_bolus, overviewData.extendedBolusText(iobCobCalculator)) views.setViewVisibility(R.id.extended_layout, (iobCobCalculator.getExtendedBolus(dateUtil.now()) != null && !pump.isFakingTempsByExtendedBoluses).toVisibility()) } private fun updateIobCob(views: RemoteViews) { - views.setTextViewText(R.id.iob, overviewData.iobText) + views.setTextViewText(R.id.iob, overviewData.iobText(iobCobCalculator)) // cob - var cobText = overviewData.cobInfo?.displayText(rh, dateUtil, isDev = false) ?: rh.gs(R.string.value_unavailable_short) + var cobText = overviewData.cobInfo(iobCobCalculator).displayText(rh, dateUtil, isDev = false) ?: rh.gs(R.string.value_unavailable_short) val constraintsProcessed = loop.lastRun?.constraintsProcessed val lastRun = loop.lastRun @@ -158,7 +161,6 @@ class Widget : AppWidgetProvider() { private fun updateTemporaryTarget(views: RemoteViews) { val units = profileFunction.getUnits() - if (overviewData.temporaryTarget?.isInProgress(dateUtil) == false) overviewData.temporaryTarget = null val tempTarget = overviewData.temporaryTarget if (tempTarget != null) { // this is crashing, use background as text for now @@ -210,12 +212,12 @@ class Widget : AppWidgetProvider() { views.setTextColor(R.id.active_profile, profileTextColor) } - fun updateSensitivity(views: RemoteViews) { + private fun updateSensitivity(views: RemoteViews) { if (sp.getBoolean(R.string.key_openapsama_useautosens, false) && constraintChecker.isAutosensModeEnabled().value()) views.setImageViewResource(R.id.sensitivity_icon, R.drawable.ic_swap_vert_black_48dp_green) else views.setImageViewResource(R.id.sensitivity_icon, R.drawable.ic_x_swap_vert) - views.setTextViewText(R.id.sensitivity, overviewData.lastAutosensData?.let { autosensData -> + views.setTextViewText(R.id.sensitivity, overviewData.lastAutosensData(iobCobCalculator)?.let { autosensData -> String.format(Locale.ENGLISH, "%.0f%%", autosensData.autosensResult.ratio * 100) } ?: "") diff --git a/app/src/main/java/info/nightscout/androidaps/activities/HistoryBrowseActivity.kt b/app/src/main/java/info/nightscout/androidaps/activities/HistoryBrowseActivity.kt index 5dc7e113ca..dde989894a 100644 --- a/app/src/main/java/info/nightscout/androidaps/activities/HistoryBrowseActivity.kt +++ b/app/src/main/java/info/nightscout/androidaps/activities/HistoryBrowseActivity.kt @@ -3,7 +3,6 @@ package info.nightscout.androidaps.activities import android.annotation.SuppressLint import android.app.DatePickerDialog import android.content.Context -import android.graphics.Color import android.os.Bundle import android.util.DisplayMetrics import android.view.ViewGroup @@ -19,21 +18,18 @@ import info.nightscout.androidaps.events.EventAutosensCalculationFinished import info.nightscout.androidaps.events.EventCustomCalculationFinished import info.nightscout.androidaps.events.EventRefreshOverview import info.nightscout.androidaps.extensions.toVisibility +import info.nightscout.androidaps.extensions.toVisibilityKeepSpace import info.nightscout.androidaps.interfaces.ActivePlugin import info.nightscout.androidaps.interfaces.Config import info.nightscout.androidaps.interfaces.Loop import info.nightscout.androidaps.interfaces.ProfileFunction -import info.nightscout.androidaps.plugins.bus.RxBus import info.nightscout.androidaps.plugins.general.nsclient.data.NSDeviceStatus import info.nightscout.androidaps.plugins.general.overview.OverviewData import info.nightscout.androidaps.plugins.general.overview.OverviewMenus +import info.nightscout.androidaps.plugins.general.overview.events.EventUpdateOverviewGraph import info.nightscout.androidaps.plugins.general.overview.graphData.GraphData import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin -import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventBucketedDataCreated import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventIobCalculationProgress -import info.nightscout.androidaps.plugins.sensitivity.SensitivityAAPSPlugin -import info.nightscout.androidaps.plugins.sensitivity.SensitivityOref1Plugin -import info.nightscout.androidaps.plugins.sensitivity.SensitivityWeightedAveragePlugin import info.nightscout.androidaps.receivers.DataWorker import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.DefaultValueHelper @@ -42,6 +38,7 @@ import info.nightscout.androidaps.utils.T import info.nightscout.androidaps.utils.Translator import info.nightscout.androidaps.utils.buildHelper.BuildHelper import info.nightscout.androidaps.utils.rx.AapsSchedulers +import info.nightscout.androidaps.workflow.CalculationWorkflow import info.nightscout.shared.logging.LTag import info.nightscout.shared.sharedPreferences.SP import io.reactivex.rxjava3.disposables.CompositeDisposable @@ -59,9 +56,6 @@ class HistoryBrowseActivity : NoSplashAppCompatActivity() { @Inject lateinit var defaultValueHelper: DefaultValueHelper @Inject lateinit var activePlugin: ActivePlugin @Inject lateinit var buildHelper: BuildHelper - @Inject lateinit var sensitivityOref1Plugin: SensitivityOref1Plugin - @Inject lateinit var sensitivityAAPSPlugin: SensitivityAAPSPlugin - @Inject lateinit var sensitivityWeightedAveragePlugin: SensitivityWeightedAveragePlugin @Inject lateinit var repository: AppRepository @Inject lateinit var fabricPrivacy: FabricPrivacy @Inject lateinit var overviewMenus: OverviewMenus @@ -72,6 +66,7 @@ class HistoryBrowseActivity : NoSplashAppCompatActivity() { @Inject lateinit var translator: Translator @Inject lateinit var context: Context @Inject lateinit var dataWorker: DataWorker + @Inject lateinit var calculationWorkflow: CalculationWorkflow private val disposable = CompositeDisposable() @@ -94,6 +89,17 @@ class HistoryBrowseActivity : NoSplashAppCompatActivity() { setContentView(binding.root) // We don't want to use injected singletons but own instance working on top of different data + overviewData = + OverviewData( + aapsLogger, + rh, + dateUtil, + sp, + activePlugin, + defaultValueHelper, + profileFunction, + repository + ) iobCobCalculator = IobCobCalculatorPlugin( injector, @@ -104,32 +110,11 @@ class HistoryBrowseActivity : NoSplashAppCompatActivity() { rh, profileFunction, activePlugin, - sensitivityOref1Plugin, - sensitivityAAPSPlugin, - sensitivityWeightedAveragePlugin, fabricPrivacy, dateUtil, repository, - context, - dataWorker - ) - overviewData = - OverviewData( - injector, - aapsLogger, - rh, - dateUtil, - sp, - activePlugin, - defaultValueHelper, - profileFunction, - config, - loop, - nsDeviceStatus, - repository, - overviewMenus, - iobCobCalculator, - translator + overviewData, + calculationWorkflow ) binding.left.setOnClickListener { @@ -201,7 +186,7 @@ class HistoryBrowseActivity : NoSplashAppCompatActivity() { axisWidth = if (dm.densityDpi <= 120) 3 else if (dm.densityDpi <= 160) 10 else if (dm.densityDpi <= 320) 35 else if (dm.densityDpi <= 420) 50 else if (dm.densityDpi <= 560) 70 else 80 - binding.bgGraph.gridLabelRenderer?.gridColor = rh.gac(this, R.attr.graphgrid) + binding.bgGraph.gridLabelRenderer?.gridColor = rh.gac(this, R.attr.graphgrid) binding.bgGraph.gridLabelRenderer?.reloadStyles() binding.bgGraph.gridLabelRenderer?.labelVerticalWidth = axisWidth @@ -217,7 +202,7 @@ class HistoryBrowseActivity : NoSplashAppCompatActivity() { override fun onPause() { super.onPause() disposable.clear() - iobCobCalculator.stopCalculation("onPause") + calculationWorkflow.stopCalculation(CalculationWorkflow.HISTORY_CALCULATION, "onPause") } @Synchronized @@ -239,22 +224,11 @@ class HistoryBrowseActivity : NoSplashAppCompatActivity() { disposable += rxBus .toObservable(EventIobCalculationProgress::class.java) .observeOn(aapsSchedulers.main) - .subscribe({ - if (it.cause is EventCustomCalculationFinished) - binding.overviewIobcalculationprogess.text = it.progressPct.toString() + "%" - }, fabricPrivacy::logException) + .subscribe({ updateCalcProgress(it.pass.finalPercent(it.progressPct)) }, fabricPrivacy::logException) disposable += rxBus - .toObservable(EventRefreshOverview::class.java) + .toObservable(EventUpdateOverviewGraph::class.java) .observeOn(aapsSchedulers.main) .subscribe({ updateGUI("EventRefreshOverview") }, fabricPrivacy::logException) - disposable += rxBus - .toObservable(EventBucketedDataCreated::class.java) - .observeOn(aapsSchedulers.io) - .subscribe({ - overviewData.prepareBucketedData("EventBucketedDataCreated") - overviewData.prepareBgData("EventBucketedDataCreated") - rxBus.send(EventRefreshOverview("EventBucketedDataCreated")) - }, fabricPrivacy::logException) if (overviewData.fromTime == 0L) { // set start of current day @@ -285,12 +259,12 @@ class HistoryBrowseActivity : NoSplashAppCompatActivity() { val graph = GraphView(this) graph.layoutParams = LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, rh.dpToPx(100)).also { it.setMargins(0, rh.dpToPx(15), 0, rh.dpToPx(10)) } - graph.gridLabelRenderer?.gridColor = rh.gac( R.attr.graphgrid) + graph.gridLabelRenderer?.gridColor = rh.gac(R.attr.graphgrid) graph.gridLabelRenderer?.reloadStyles() graph.gridLabelRenderer?.isHorizontalLabelsVisible = false graph.gridLabelRenderer?.labelVerticalWidth = axisWidth graph.gridLabelRenderer?.numVerticalLabels = 3 - graph.viewport.backgroundColor =rh.gac(this , R.attr.viewPortbackgroundColor) + graph.viewport.backgroundColor = rh.gac(this, R.attr.viewPortbackgroundColor) relativeLayout.addView(graph) val label = TextView(this) @@ -310,17 +284,7 @@ class HistoryBrowseActivity : NoSplashAppCompatActivity() { @Suppress("SameParameterValue") private fun loadAll(from: String) { updateDate() - Thread { - overviewData.prepareBgData(from) - overviewData.prepareTreatmentsData(from) - rxBus.send(EventRefreshOverview("loadAll_$from")) - overviewData.prepareTemporaryTargetData(from) - rxBus.send(EventRefreshOverview("loadAll_$from")) - overviewData.prepareBasalData(from) - rxBus.send(EventRefreshOverview(from)) - aapsLogger.debug(LTag.UI, "loadAll $from finished") - runCalculation(from) - }.start() + runCalculation(from) } private fun setTime(start: Long) { @@ -341,22 +305,32 @@ class HistoryBrowseActivity : NoSplashAppCompatActivity() { } private fun runCalculation(from: String) { - iobCobCalculator.runCalculation(from, overviewData.toTime, bgDataReload = true, limitDataToOldestAvailable = false, cause = EventCustomCalculationFinished()) + calculationWorkflow.runCalculation( + CalculationWorkflow.HISTORY_CALCULATION, + iobCobCalculator, + overviewData, + from, + overviewData.toTime, + bgDataReload = true, + limitDataToOldestAvailable = false, + cause = EventCustomCalculationFinished(), + runLoop = false + ) } @Volatile var runningRefresh = false + @Suppress("SameParameterValue") private fun refreshLoop(from: String) { if (runningRefresh) return runningRefresh = true - overviewData.prepareIobAutosensData(from) rxBus.send(EventRefreshOverview(from)) aapsLogger.debug(LTag.UI, "refreshLoop finished") runningRefresh = false } - fun updateDate() { + private fun updateDate() { binding.date.text = dateUtil.dateAndTimeString(overviewData.fromTime) binding.zoom.text = rangeToDisplay.toString() } @@ -403,12 +377,12 @@ class HistoryBrowseActivity : NoSplashAppCompatActivity() { var useDSForScale = false var useBGIForScale = false when { - menuChartSettings[g + 1][OverviewMenus.CharType.ABS.ordinal] -> useABSForScale = true - menuChartSettings[g + 1][OverviewMenus.CharType.IOB.ordinal] -> useIobForScale = true - menuChartSettings[g + 1][OverviewMenus.CharType.COB.ordinal] -> useCobForScale = true - menuChartSettings[g + 1][OverviewMenus.CharType.DEV.ordinal] -> useDevForScale = true - menuChartSettings[g + 1][OverviewMenus.CharType.BGI.ordinal] -> useBGIForScale = true - menuChartSettings[g + 1][OverviewMenus.CharType.SEN.ordinal] -> useRatioForScale = true + menuChartSettings[g + 1][OverviewMenus.CharType.ABS.ordinal] -> useABSForScale = true + menuChartSettings[g + 1][OverviewMenus.CharType.IOB.ordinal] -> useIobForScale = true + menuChartSettings[g + 1][OverviewMenus.CharType.COB.ordinal] -> useCobForScale = true + menuChartSettings[g + 1][OverviewMenus.CharType.DEV.ordinal] -> useDevForScale = true + menuChartSettings[g + 1][OverviewMenus.CharType.BGI.ordinal] -> useBGIForScale = true + menuChartSettings[g + 1][OverviewMenus.CharType.SEN.ordinal] -> useRatioForScale = true menuChartSettings[g + 1][OverviewMenus.CharType.DEVSLOPE.ordinal] -> useDSForScale = true } val alignDevBgiScale = menuChartSettings[g + 1][OverviewMenus.CharType.DEV.ordinal] && menuChartSettings[g + 1][OverviewMenus.CharType.BGI.ordinal] @@ -440,4 +414,9 @@ class HistoryBrowseActivity : NoSplashAppCompatActivity() { secondaryGraphsData[g].performUpdate() } } + + private fun updateCalcProgress(percent: Int) { + binding.progressBar.progress = percent + binding.progressBar.visibility = (percent != 100).toVisibilityKeepSpace() + } } \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/androidaps/activities/fragments/TreatmentsBolusCarbsFragment.kt b/app/src/main/java/info/nightscout/androidaps/activities/fragments/TreatmentsBolusCarbsFragment.kt index 8a88149f30..a11badfb22 100644 --- a/app/src/main/java/info/nightscout/androidaps/activities/fragments/TreatmentsBolusCarbsFragment.kt +++ b/app/src/main/java/info/nightscout/androidaps/activities/fragments/TreatmentsBolusCarbsFragment.kt @@ -24,9 +24,7 @@ import info.nightscout.androidaps.database.transactions.InvalidateCarbsTransacti import info.nightscout.androidaps.databinding.TreatmentsBolusCarbsFragmentBinding import info.nightscout.androidaps.databinding.TreatmentsBolusCarbsItemBinding import info.nightscout.androidaps.dialogs.WizardInfoDialog -import info.nightscout.androidaps.events.EventAutosensCalculationFinished import info.nightscout.androidaps.events.EventTreatmentChange -import info.nightscout.androidaps.events.EventTreatmentUpdateGui import info.nightscout.androidaps.extensions.iobCalc import info.nightscout.androidaps.extensions.toVisibility import info.nightscout.androidaps.interfaces.ActivePlugin @@ -170,16 +168,6 @@ class TreatmentsBolusCarbsFragment : DaggerFragment() { .observeOn(aapsSchedulers.main) .debounce(1L, TimeUnit.SECONDS) .subscribe({ swapAdapter() }, fabricPrivacy::logException) - disposable += rxBus - .toObservable(EventTreatmentUpdateGui::class.java) // TODO join with above - .observeOn(aapsSchedulers.io) - .debounce(1L, TimeUnit.SECONDS) - .subscribe({ swapAdapter() }, fabricPrivacy::logException) - disposable += rxBus - .toObservable(EventAutosensCalculationFinished::class.java) - .observeOn(aapsSchedulers.main) - .debounce(1L, TimeUnit.SECONDS) - .subscribe({ swapAdapter() }, fabricPrivacy::logException) } @Synchronized @@ -334,7 +322,7 @@ class TreatmentsBolusCarbsFragment : DaggerFragment() { showInvalidated = true updateMenuVisibility() ToastUtils.showToastInUiThread(context, rh.gs(R.string.show_invalidated_records)) - rxBus.send(EventTreatmentUpdateGui()) + swapAdapter() true } @@ -342,7 +330,7 @@ class TreatmentsBolusCarbsFragment : DaggerFragment() { showInvalidated = false updateMenuVisibility() ToastUtils.showToastInUiThread(context, rh.gs(R.string.hide_invalidated_records)) - rxBus.send(EventTreatmentUpdateGui()) + swapAdapter() true } diff --git a/app/src/main/java/info/nightscout/androidaps/activities/fragments/TreatmentsCareportalFragment.kt b/app/src/main/java/info/nightscout/androidaps/activities/fragments/TreatmentsCareportalFragment.kt index 32732b7ea9..8c7423b80e 100644 --- a/app/src/main/java/info/nightscout/androidaps/activities/fragments/TreatmentsCareportalFragment.kt +++ b/app/src/main/java/info/nightscout/androidaps/activities/fragments/TreatmentsCareportalFragment.kt @@ -19,7 +19,6 @@ import info.nightscout.androidaps.database.transactions.InvalidateTherapyEventTr import info.nightscout.androidaps.databinding.TreatmentsCareportalFragmentBinding import info.nightscout.androidaps.databinding.TreatmentsCareportalItemBinding import info.nightscout.androidaps.events.EventTherapyEventChange -import info.nightscout.androidaps.events.EventTreatmentUpdateGui import info.nightscout.androidaps.extensions.toVisibility import info.nightscout.androidaps.logging.UserEntryLogger import info.nightscout.androidaps.plugins.bus.RxBus @@ -128,11 +127,6 @@ class TreatmentsCareportalFragment : DaggerFragment() { .observeOn(aapsSchedulers.main) .debounce(1L, TimeUnit.SECONDS) .subscribe({ swapAdapter() }, fabricPrivacy::logException) - disposable += rxBus - .toObservable(EventTreatmentUpdateGui::class.java) // TODO join with above - .observeOn(aapsSchedulers.io) - .debounce(1L, TimeUnit.SECONDS) - .subscribe({ swapAdapter() }, fabricPrivacy::logException) } @Synchronized @@ -216,7 +210,7 @@ class TreatmentsCareportalFragment : DaggerFragment() { showInvalidated = true updateMenuVisibility() ToastUtils.showToastInUiThread(context, rh.gs(R.string.show_invalidated_records)) - rxBus.send(EventTreatmentUpdateGui()) + swapAdapter() true } @@ -224,7 +218,7 @@ class TreatmentsCareportalFragment : DaggerFragment() { showInvalidated = false updateMenuVisibility() ToastUtils.showToastInUiThread(context, rh.gs(R.string.hide_invalidated_records)) - rxBus.send(EventTreatmentUpdateGui()) + swapAdapter() true } diff --git a/app/src/main/java/info/nightscout/androidaps/activities/fragments/TreatmentsExtendedBolusesFragment.kt b/app/src/main/java/info/nightscout/androidaps/activities/fragments/TreatmentsExtendedBolusesFragment.kt index fd098e3759..da972809ab 100644 --- a/app/src/main/java/info/nightscout/androidaps/activities/fragments/TreatmentsExtendedBolusesFragment.kt +++ b/app/src/main/java/info/nightscout/androidaps/activities/fragments/TreatmentsExtendedBolusesFragment.kt @@ -20,7 +20,6 @@ import info.nightscout.androidaps.database.transactions.InvalidateExtendedBolusT import info.nightscout.androidaps.databinding.TreatmentsExtendedbolusFragmentBinding import info.nightscout.androidaps.databinding.TreatmentsExtendedbolusItemBinding import info.nightscout.androidaps.events.EventExtendedBolusChange -import info.nightscout.androidaps.events.EventTreatmentUpdateGui import info.nightscout.androidaps.extensions.iobCalc import info.nightscout.androidaps.extensions.isInProgress import info.nightscout.androidaps.extensions.toVisibility @@ -105,11 +104,6 @@ class TreatmentsExtendedBolusesFragment : DaggerFragment() { .observeOn(aapsSchedulers.io) .debounce(1L, TimeUnit.SECONDS) .subscribe({ swapAdapter() }, fabricPrivacy::logException) - disposable += rxBus - .toObservable(EventTreatmentUpdateGui::class.java) // TODO join with above - .observeOn(aapsSchedulers.io) - .debounce(1L, TimeUnit.SECONDS) - .subscribe({ swapAdapter() }, fabricPrivacy::logException) } @Synchronized @@ -203,7 +197,7 @@ class TreatmentsExtendedBolusesFragment : DaggerFragment() { showInvalidated = true updateMenuVisibility() ToastUtils.showToastInUiThread(context, rh.gs(R.string.show_invalidated_records)) - rxBus.send(EventTreatmentUpdateGui()) + swapAdapter() true } @@ -211,7 +205,7 @@ class TreatmentsExtendedBolusesFragment : DaggerFragment() { showInvalidated = false updateMenuVisibility() ToastUtils.showToastInUiThread(context, rh.gs(R.string.hide_invalidated_records)) - rxBus.send(EventTreatmentUpdateGui()) + swapAdapter() true } diff --git a/app/src/main/java/info/nightscout/androidaps/activities/fragments/TreatmentsProfileSwitchFragment.kt b/app/src/main/java/info/nightscout/androidaps/activities/fragments/TreatmentsProfileSwitchFragment.kt index 12193867b2..02b160776a 100644 --- a/app/src/main/java/info/nightscout/androidaps/activities/fragments/TreatmentsProfileSwitchFragment.kt +++ b/app/src/main/java/info/nightscout/androidaps/activities/fragments/TreatmentsProfileSwitchFragment.kt @@ -22,7 +22,6 @@ import info.nightscout.androidaps.databinding.TreatmentsProfileswitchItemBinding import info.nightscout.androidaps.dialogs.ProfileViewerDialog import info.nightscout.androidaps.events.EventEffectiveProfileSwitchChanged import info.nightscout.androidaps.events.EventProfileSwitchChanged -import info.nightscout.androidaps.events.EventTreatmentUpdateGui import info.nightscout.androidaps.extensions.getCustomizedName import info.nightscout.androidaps.extensions.toVisibility import info.nightscout.androidaps.logging.UserEntryLogger @@ -47,7 +46,6 @@ import io.reactivex.rxjava3.core.Completable import io.reactivex.rxjava3.disposables.CompositeDisposable import io.reactivex.rxjava3.kotlin.plusAssign import io.reactivex.rxjava3.kotlin.subscribeBy -import java.util.concurrent.TimeUnit import javax.inject.Inject class TreatmentsProfileSwitchFragment : DaggerFragment() { @@ -162,11 +160,6 @@ class TreatmentsProfileSwitchFragment : DaggerFragment() { .toObservable(EventEffectiveProfileSwitchChanged::class.java) .observeOn(aapsSchedulers.main) .subscribe({ swapAdapter() }, fabricPrivacy::logException) - disposable += rxBus - .toObservable(EventTreatmentUpdateGui::class.java) // TODO join with above - .observeOn(aapsSchedulers.io) - .debounce(1L, TimeUnit.SECONDS) - .subscribe({ swapAdapter() }, fabricPrivacy::logException) } @Synchronized @@ -306,7 +299,7 @@ class TreatmentsProfileSwitchFragment : DaggerFragment() { showInvalidated = true updateMenuVisibility() ToastUtils.showToastInUiThread(context, rh.gs(R.string.show_invalidated_records)) - rxBus.send(EventTreatmentUpdateGui()) + swapAdapter() true } @@ -314,7 +307,7 @@ class TreatmentsProfileSwitchFragment : DaggerFragment() { showInvalidated = false updateMenuVisibility() ToastUtils.showToastInUiThread(context, rh.gs(R.string.hide_invalidated_records)) - rxBus.send(EventTreatmentUpdateGui()) + swapAdapter() true } diff --git a/app/src/main/java/info/nightscout/androidaps/activities/fragments/TreatmentsTempTargetFragment.kt b/app/src/main/java/info/nightscout/androidaps/activities/fragments/TreatmentsTempTargetFragment.kt index 9a28f5a220..b6cb2b2600 100644 --- a/app/src/main/java/info/nightscout/androidaps/activities/fragments/TreatmentsTempTargetFragment.kt +++ b/app/src/main/java/info/nightscout/androidaps/activities/fragments/TreatmentsTempTargetFragment.kt @@ -23,7 +23,6 @@ import info.nightscout.androidaps.databinding.TreatmentsTemptargetItemBinding import info.nightscout.androidaps.events.EventEffectiveProfileSwitchChanged import info.nightscout.androidaps.events.EventProfileSwitchChanged import info.nightscout.androidaps.events.EventTempTargetChange -import info.nightscout.androidaps.events.EventTreatmentUpdateGui import info.nightscout.androidaps.extensions.friendlyDescription import info.nightscout.androidaps.extensions.highValueToUnitsToString import info.nightscout.androidaps.extensions.lowValueToUnitsToString @@ -134,11 +133,6 @@ class TreatmentsTempTargetFragment : DaggerFragment() { .observeOn(aapsSchedulers.io) .debounce(1L, TimeUnit.SECONDS) .subscribe({ swapAdapter() }, fabricPrivacy::logException) - disposable += rxBus - .toObservable(EventTreatmentUpdateGui::class.java) // TODO join with above - .observeOn(aapsSchedulers.io) - .debounce(1L, TimeUnit.SECONDS) - .subscribe({ swapAdapter() }, fabricPrivacy::logException) } @Synchronized @@ -235,7 +229,7 @@ class TreatmentsTempTargetFragment : DaggerFragment() { showInvalidated = true updateMenuVisibility() ToastUtils.showToastInUiThread(context, rh.gs(R.string.show_invalidated_records)) - rxBus.send(EventTreatmentUpdateGui()) + swapAdapter() true } @@ -243,7 +237,7 @@ class TreatmentsTempTargetFragment : DaggerFragment() { showInvalidated = false updateMenuVisibility() ToastUtils.showToastInUiThread(context, rh.gs(R.string.show_invalidated_records)) - rxBus.send(EventTreatmentUpdateGui()) + swapAdapter() true } diff --git a/app/src/main/java/info/nightscout/androidaps/activities/fragments/TreatmentsTemporaryBasalsFragment.kt b/app/src/main/java/info/nightscout/androidaps/activities/fragments/TreatmentsTemporaryBasalsFragment.kt index d867c87ba9..7736d02895 100644 --- a/app/src/main/java/info/nightscout/androidaps/activities/fragments/TreatmentsTemporaryBasalsFragment.kt +++ b/app/src/main/java/info/nightscout/androidaps/activities/fragments/TreatmentsTemporaryBasalsFragment.kt @@ -23,9 +23,7 @@ import info.nightscout.androidaps.database.transactions.InvalidateExtendedBolusT import info.nightscout.androidaps.database.transactions.InvalidateTemporaryBasalTransaction import info.nightscout.androidaps.databinding.TreatmentsTempbasalsFragmentBinding import info.nightscout.androidaps.databinding.TreatmentsTempbasalsItemBinding -import info.nightscout.androidaps.events.EventAutosensCalculationFinished import info.nightscout.androidaps.events.EventTempBasalChange -import info.nightscout.androidaps.events.EventTreatmentUpdateGui import info.nightscout.androidaps.extensions.iobCalc import info.nightscout.androidaps.extensions.toStringFull import info.nightscout.androidaps.extensions.toTemporaryBasal @@ -141,15 +139,6 @@ class TreatmentsTemporaryBasalsFragment : DaggerFragment() { .toObservable(EventTempBasalChange::class.java) .observeOn(aapsSchedulers.main) .subscribe({ swapAdapter() }, fabricPrivacy::logException) - disposable += rxBus - .toObservable(EventAutosensCalculationFinished::class.java) - .observeOn(aapsSchedulers.main) - .subscribe({ swapAdapter() }, fabricPrivacy::logException) - disposable += rxBus - .toObservable(EventTreatmentUpdateGui::class.java) // TODO join with above - .observeOn(aapsSchedulers.io) - .debounce(1L, TimeUnit.SECONDS) - .subscribe({ swapAdapter() }, fabricPrivacy::logException) } @Synchronized @@ -183,7 +172,7 @@ class TreatmentsTemporaryBasalsFragment : DaggerFragment() { holder.binding.date.text = if (newDay) dateUtil.dateStringRelative(tempBasal.timestamp, rh) else "" if (tempBasal.isInProgress) { holder.binding.time.text = dateUtil.timeString(tempBasal.timestamp) - holder.binding.time.setTextColor(rh.gac(context , R.attr.activeColor)) + holder.binding.time.setTextColor(rh.gac(context, R.attr.activeColor)) } else { holder.binding.time.text = dateUtil.timeRangeString(tempBasal.timestamp, tempBasal.end) holder.binding.time.setTextColor(holder.binding.duration.currentTextColor) @@ -200,7 +189,7 @@ class TreatmentsTemporaryBasalsFragment : DaggerFragment() { holder.binding.suspendFlag.visibility = (tempBasal.type == TemporaryBasal.Type.PUMP_SUSPEND).toVisibility() holder.binding.emulatedSuspendFlag.visibility = (tempBasal.type == TemporaryBasal.Type.EMULATED_PUMP_SUSPEND).toVisibility() holder.binding.superBolusFlag.visibility = (tempBasal.type == TemporaryBasal.Type.SUPERBOLUS).toVisibility() - if (abs(iob.basaliob) > 0.01) holder.binding.iob.setTextColor(rh.gac(context , R.attr.activeColor)) else holder.binding.iob.setTextColor(holder.binding.duration.currentTextColor) + if (abs(iob.basaliob) > 0.01) holder.binding.iob.setTextColor(rh.gac(context, R.attr.activeColor)) else holder.binding.iob.setTextColor(holder.binding.duration.currentTextColor) holder.binding.cbRemove.visibility = (tempBasal.isValid && actionHelper.isRemoving).toVisibility() if (actionHelper.isRemoving) { holder.binding.cbRemove.setOnCheckedChangeListener { _, value -> @@ -251,7 +240,7 @@ class TreatmentsTemporaryBasalsFragment : DaggerFragment() { showInvalidated = true updateMenuVisibility() ToastUtils.showToastInUiThread(context, rh.gs(R.string.show_invalidated_records)) - rxBus.send(EventTreatmentUpdateGui()) + swapAdapter() true } @@ -259,7 +248,7 @@ class TreatmentsTemporaryBasalsFragment : DaggerFragment() { showInvalidated = false updateMenuVisibility() ToastUtils.showToastInUiThread(context, rh.gs(R.string.hide_invalidated_records)) - rxBus.send(EventTreatmentUpdateGui()) + swapAdapter() true } @@ -281,41 +270,41 @@ class TreatmentsTemporaryBasalsFragment : DaggerFragment() { private fun removeSelected(selectedItems: SparseArray) { if (selectedItems.size() > 0) activity?.let { activity -> - OKDialog.showConfirmation(activity, rh.gs(R.string.removerecord), getConfirmationText(selectedItems), Runnable { - selectedItems.forEach {_, tempBasal -> - var extendedBolus: ExtendedBolus? = null - val isFakeExtended = tempBasal.type == TemporaryBasal.Type.FAKE_EXTENDED - if (isFakeExtended) { - val eb = repository.getExtendedBolusActiveAt(tempBasal.timestamp).blockingGet() - extendedBolus = if (eb is ValueWrapper.Existing) eb.value else null + OKDialog.showConfirmation(activity, rh.gs(R.string.removerecord), getConfirmationText(selectedItems), Runnable { + selectedItems.forEach { _, tempBasal -> + var extendedBolus: ExtendedBolus? = null + val isFakeExtended = tempBasal.type == TemporaryBasal.Type.FAKE_EXTENDED + if (isFakeExtended) { + val eb = repository.getExtendedBolusActiveAt(tempBasal.timestamp).blockingGet() + extendedBolus = if (eb is ValueWrapper.Existing) eb.value else null + } + if (isFakeExtended && extendedBolus != null) { + uel.log( + Action.EXTENDED_BOLUS_REMOVED, Sources.Treatments, + ValueWithUnit.Timestamp(extendedBolus.timestamp), + ValueWithUnit.Insulin(extendedBolus.amount), + ValueWithUnit.UnitPerHour(extendedBolus.rate), + ValueWithUnit.Minute(TimeUnit.MILLISECONDS.toMinutes(extendedBolus.duration).toInt()) + ) + disposable += repository.runTransactionForResult(InvalidateExtendedBolusTransaction(extendedBolus.id)) + .subscribe( + { aapsLogger.debug(LTag.DATABASE, "Removed extended bolus $extendedBolus") }, + { aapsLogger.error(LTag.DATABASE, "Error while invalidating extended bolus", it) }) + } else if (!isFakeExtended) { + uel.log( + Action.TEMP_BASAL_REMOVED, Sources.Treatments, + ValueWithUnit.Timestamp(tempBasal.timestamp), + if (tempBasal.isAbsolute) ValueWithUnit.UnitPerHour(tempBasal.rate) else ValueWithUnit.Percent(tempBasal.rate.toInt()), + ValueWithUnit.Minute(T.msecs(tempBasal.duration).mins().toInt()) + ) + disposable += repository.runTransactionForResult(InvalidateTemporaryBasalTransaction(tempBasal.id)) + .subscribe( + { aapsLogger.debug(LTag.DATABASE, "Removed temporary basal $tempBasal") }, + { aapsLogger.error(LTag.DATABASE, "Error while invalidating temporary basal", it) }) + } } - if (isFakeExtended && extendedBolus != null) { - uel.log( - Action.EXTENDED_BOLUS_REMOVED, Sources.Treatments, - ValueWithUnit.Timestamp(extendedBolus.timestamp), - ValueWithUnit.Insulin(extendedBolus.amount), - ValueWithUnit.UnitPerHour(extendedBolus.rate), - ValueWithUnit.Minute(TimeUnit.MILLISECONDS.toMinutes(extendedBolus.duration).toInt()) - ) - disposable += repository.runTransactionForResult(InvalidateExtendedBolusTransaction(extendedBolus.id)) - .subscribe( - { aapsLogger.debug(LTag.DATABASE, "Removed extended bolus $extendedBolus") }, - { aapsLogger.error(LTag.DATABASE, "Error while invalidating extended bolus", it) }) - } else if (!isFakeExtended) { - uel.log( - Action.TEMP_BASAL_REMOVED, Sources.Treatments, - ValueWithUnit.Timestamp(tempBasal.timestamp), - if (tempBasal.isAbsolute) ValueWithUnit.UnitPerHour(tempBasal.rate) else ValueWithUnit.Percent(tempBasal.rate.toInt()), - ValueWithUnit.Minute(T.msecs(tempBasal.duration).mins().toInt()) - ) - disposable += repository.runTransactionForResult(InvalidateTemporaryBasalTransaction(tempBasal.id)) - .subscribe( - { aapsLogger.debug(LTag.DATABASE, "Removed temporary basal $tempBasal") }, - { aapsLogger.error(LTag.DATABASE, "Error while invalidating temporary basal", it) }) - } - } - actionHelper.finish() - }) - } + actionHelper.finish() + }) + } } } diff --git a/app/src/main/java/info/nightscout/androidaps/activities/fragments/TreatmentsUserEntryFragment.kt b/app/src/main/java/info/nightscout/androidaps/activities/fragments/TreatmentsUserEntryFragment.kt index 3cbebcee47..e59fa71805 100644 --- a/app/src/main/java/info/nightscout/androidaps/activities/fragments/TreatmentsUserEntryFragment.kt +++ b/app/src/main/java/info/nightscout/androidaps/activities/fragments/TreatmentsUserEntryFragment.kt @@ -13,7 +13,6 @@ import info.nightscout.androidaps.database.entities.UserEntry.Sources import info.nightscout.androidaps.databinding.TreatmentsUserEntryFragmentBinding import info.nightscout.androidaps.databinding.TreatmentsUserEntryItemBinding import info.nightscout.androidaps.events.EventPreferenceChange -import info.nightscout.androidaps.events.EventTreatmentUpdateGui import info.nightscout.androidaps.extensions.toVisibility import info.nightscout.androidaps.interfaces.ImportExportPrefs import info.nightscout.androidaps.interfaces.ProfileFunction @@ -30,7 +29,6 @@ import info.nightscout.androidaps.utils.rx.AapsSchedulers import info.nightscout.androidaps.utils.userEntry.UserEntryPresentationHelper import io.reactivex.rxjava3.disposables.CompositeDisposable import io.reactivex.rxjava3.kotlin.plusAssign -import java.util.concurrent.TimeUnit import javax.inject.Inject class TreatmentsUserEntryFragment : DaggerFragment() { @@ -99,11 +97,6 @@ class TreatmentsUserEntryFragment : DaggerFragment() { .toObservable(EventPreferenceChange::class.java) .observeOn(aapsSchedulers.io) .subscribe({ swapAdapter() }, fabricPrivacy::logException) - disposable += rxBus - .toObservable(EventTreatmentUpdateGui::class.java) - .observeOn(aapsSchedulers.io) - .debounce(1L, TimeUnit.SECONDS) - .subscribe({ swapAdapter() }, fabricPrivacy::logException) } @Synchronized @@ -172,7 +165,7 @@ class TreatmentsUserEntryFragment : DaggerFragment() { showLoop = true updateMenuVisibility() ToastUtils.showToastInUiThread(context, rh.gs(R.string.show_loop_records)) - rxBus.send(EventTreatmentUpdateGui()) + swapAdapter() true } @@ -180,7 +173,7 @@ class TreatmentsUserEntryFragment : DaggerFragment() { showLoop = false updateMenuVisibility() ToastUtils.showToastInUiThread(context, rh.gs(R.string.show_hide_records)) - rxBus.send(EventTreatmentUpdateGui()) + swapAdapter() true } diff --git a/app/src/main/java/info/nightscout/androidaps/db/CompatDBHelper.kt b/app/src/main/java/info/nightscout/androidaps/db/CompatDBHelper.kt index fb1136bc3e..2dcfac933e 100644 --- a/app/src/main/java/info/nightscout/androidaps/db/CompatDBHelper.kt +++ b/app/src/main/java/info/nightscout/androidaps/db/CompatDBHelper.kt @@ -60,6 +60,11 @@ class CompatDBHelper @Inject constructor( rxBus.send(EventExtendedBolusChange()) rxBus.send(EventNewHistoryData(timestamp, false)) } + it.filterIsInstance().firstOrNull()?.let { eps -> + aapsLogger.debug(LTag.DATABASE, "Firing EventEffectiveProfileSwitchChanged $eps") + rxBus.send(EventEffectiveProfileSwitchChanged(eps)) + rxBus.send(EventNewHistoryData(eps.timestamp, false)) + } it.filterIsInstance().firstOrNull()?.let { tt -> aapsLogger.debug(LTag.DATABASE, "Firing EventTempTargetChange $tt") rxBus.send(EventTempTargetChange()) @@ -76,10 +81,6 @@ class CompatDBHelper @Inject constructor( aapsLogger.debug(LTag.DATABASE, "Firing EventProfileSwitchChanged $ps") rxBus.send(EventProfileSwitchChanged()) } - it.filterIsInstance().firstOrNull()?.let { eps -> - aapsLogger.debug(LTag.DATABASE, "Firing EventEffectiveProfileSwitchChanged $eps") - rxBus.send(EventEffectiveProfileSwitchChanged(eps)) - } it.filterIsInstance().firstOrNull()?.let { oe -> aapsLogger.debug(LTag.DATABASE, "Firing EventOfflineChange $oe") rxBus.send(EventOfflineChange()) diff --git a/app/src/main/java/info/nightscout/androidaps/di/APSModule.kt b/app/src/main/java/info/nightscout/androidaps/di/APSModule.kt index 8f5746859f..2fe03ff711 100644 --- a/app/src/main/java/info/nightscout/androidaps/di/APSModule.kt +++ b/app/src/main/java/info/nightscout/androidaps/di/APSModule.kt @@ -8,8 +8,6 @@ import info.nightscout.androidaps.plugins.aps.openAPSAMA.DetermineBasalResultAMA import info.nightscout.androidaps.plugins.aps.openAPSSMB.DetermineBasalAdapterSMBJS import info.nightscout.androidaps.plugins.aps.openAPSSMB.DetermineBasalResultSMB import info.nightscout.androidaps.plugins.aps.openAPSSMBDynamicISF.DetermineBasalAdapterSMBDynamicISFJS -import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobOref1Worker -import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobOrefWorker @Module @Suppress("unused") @@ -21,6 +19,4 @@ abstract class APSModule { @ContributesAndroidInjector abstract fun determineBasalAdapterAMAJSInjector(): DetermineBasalAdapterAMAJS @ContributesAndroidInjector abstract fun determineBasalAdapterSMBJSInjector(): DetermineBasalAdapterSMBJS @ContributesAndroidInjector abstract fun determineBasalAdapterSMBAutoISFJSInjector(): DetermineBasalAdapterSMBDynamicISFJS - @ContributesAndroidInjector abstract fun iobCobWorkerInjector(): IobCobOrefWorker - @ContributesAndroidInjector abstract fun iobCobOref1WorkerInjector(): IobCobOref1Worker } \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/androidaps/di/AppComponent.kt b/app/src/main/java/info/nightscout/androidaps/di/AppComponent.kt index c206de3837..876aa88311 100644 --- a/app/src/main/java/info/nightscout/androidaps/di/AppComponent.kt +++ b/app/src/main/java/info/nightscout/androidaps/di/AppComponent.kt @@ -46,6 +46,7 @@ import javax.inject.Singleton OmnipodDashModule::class, OmnipodErosModule::class, APSModule::class, + WorkflowModule::class, PreferencesModule::class, OverviewModule::class, DataClassesModule::class, diff --git a/app/src/main/java/info/nightscout/androidaps/di/WorkflowModule.kt b/app/src/main/java/info/nightscout/androidaps/di/WorkflowModule.kt new file mode 100644 index 0000000000..620064dc6a --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/di/WorkflowModule.kt @@ -0,0 +1,25 @@ +package info.nightscout.androidaps.di + +import dagger.Module +import dagger.android.ContributesAndroidInjector +import info.nightscout.androidaps.plugins.iob.iobCobCalculator.* +import info.nightscout.androidaps.workflow.* + +@Module +@Suppress("unused") +abstract class WorkflowModule { + + @ContributesAndroidInjector abstract fun iobCobWorkerInjector(): IobCobOrefWorker + @ContributesAndroidInjector abstract fun iobCobOref1WorkerInjector(): IobCobOref1Worker + @ContributesAndroidInjector abstract fun prepareIobAutosensDataWorkerInjector(): PrepareIobAutosensGraphDataWorker + @ContributesAndroidInjector abstract fun prepareBasalDataWorkerInjector(): PrepareBasalDataWorker + @ContributesAndroidInjector abstract fun prepareTemporaryTargetDataWorkerInjector(): PrepareTemporaryTargetDataWorker + @ContributesAndroidInjector abstract fun prepareTreatmentsDataWorkerInjector(): PrepareTreatmentsDataWorker + @ContributesAndroidInjector abstract fun loadIobCobResultsWorkerInjector(): UpdateIobCobSensWorker + @ContributesAndroidInjector abstract fun preparePredictionsWorkerInjector(): PreparePredictionsWorker + @ContributesAndroidInjector abstract fun updateGraphAndIobWorkerInjector(): UpdateGraphWorker + @ContributesAndroidInjector abstract fun prepareBgDataWorkerInjector(): PrepareBgDataWorker + @ContributesAndroidInjector abstract fun prepareBucketedDataWorkerInjector(): PrepareBucketedDataWorker + @ContributesAndroidInjector abstract fun loadBgDataWorkerInjector(): LoadBgDataWorker + @ContributesAndroidInjector abstract fun invokeLoopWorkerInjector(): InvokeLoopWorker +} \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/androidaps/events/EventReloadProfileSwitchData.kt b/app/src/main/java/info/nightscout/androidaps/events/EventReloadProfileSwitchData.kt deleted file mode 100644 index 6f6d848b5e..0000000000 --- a/app/src/main/java/info/nightscout/androidaps/events/EventReloadProfileSwitchData.kt +++ /dev/null @@ -1,3 +0,0 @@ -package info.nightscout.androidaps.events - -class EventReloadProfileSwitchData : Event() diff --git a/app/src/main/java/info/nightscout/androidaps/events/EventTreatmentUpdateGui.kt b/app/src/main/java/info/nightscout/androidaps/events/EventTreatmentUpdateGui.kt deleted file mode 100644 index 4a32b3c659..0000000000 --- a/app/src/main/java/info/nightscout/androidaps/events/EventTreatmentUpdateGui.kt +++ /dev/null @@ -1,3 +0,0 @@ -package info.nightscout.androidaps.events - -class EventTreatmentUpdateGui : EventUpdateGui() \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/aps/events/EventLoopInvoked.kt b/app/src/main/java/info/nightscout/androidaps/plugins/aps/events/EventLoopInvoked.kt deleted file mode 100644 index e90e8cfb88..0000000000 --- a/app/src/main/java/info/nightscout/androidaps/plugins/aps/events/EventLoopInvoked.kt +++ /dev/null @@ -1,5 +0,0 @@ -package info.nightscout.androidaps.plugins.aps.events - -import info.nightscout.androidaps.events.Event - -class EventLoopInvoked : Event() \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/aps/loop/LoopPlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/aps/loop/LoopPlugin.kt index e43c353d87..fa8c085404 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/aps/loop/LoopPlugin.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/aps/loop/LoopPlugin.kt @@ -10,11 +10,13 @@ import android.content.Intent import android.os.SystemClock import androidx.core.app.NotificationCompat import dagger.android.HasAndroidInjector -import info.nightscout.androidaps.* +import info.nightscout.androidaps.BuildConfig +import info.nightscout.androidaps.Constants +import info.nightscout.androidaps.MainActivity +import info.nightscout.androidaps.R import info.nightscout.androidaps.activities.ErrorHelperActivity import info.nightscout.androidaps.annotations.OpenForTesting import info.nightscout.androidaps.data.DetailedBolusInfo -import info.nightscout.androidaps.interfaces.Profile import info.nightscout.androidaps.data.PumpEnactResult import info.nightscout.androidaps.database.AppRepository import info.nightscout.androidaps.database.ValueWrapper @@ -25,13 +27,13 @@ import info.nightscout.androidaps.database.entities.ValueWithUnit import info.nightscout.androidaps.database.transactions.InsertAndCancelCurrentOfflineEventTransaction import info.nightscout.androidaps.database.transactions.InsertTherapyEventAnnouncementTransaction import info.nightscout.androidaps.events.EventAcceptOpenLoopChange -import info.nightscout.androidaps.events.EventAutosensCalculationFinished -import info.nightscout.androidaps.events.EventNewBG import info.nightscout.androidaps.events.EventTempTargetChange +import info.nightscout.androidaps.extensions.buildDeviceStatus +import info.nightscout.androidaps.extensions.convertedToAbsolute +import info.nightscout.androidaps.extensions.convertedToPercent +import info.nightscout.androidaps.extensions.plannedRemainingMinutes import info.nightscout.androidaps.interfaces.* import info.nightscout.androidaps.interfaces.Loop.LastRun -import info.nightscout.shared.logging.AAPSLogger -import info.nightscout.shared.logging.LTag import info.nightscout.androidaps.logging.UserEntryLogger import info.nightscout.androidaps.plugins.aps.loop.events.EventLoopSetLastRunGui import info.nightscout.androidaps.plugins.aps.loop.events.EventLoopUpdateGui @@ -51,13 +53,10 @@ import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.FabricPrivacy import info.nightscout.androidaps.utils.HardLimits import info.nightscout.androidaps.utils.T -import info.nightscout.androidaps.extensions.buildDeviceStatus -import info.nightscout.androidaps.extensions.convertedToAbsolute -import info.nightscout.androidaps.extensions.convertedToPercent -import info.nightscout.androidaps.extensions.plannedRemainingMinutes -import info.nightscout.androidaps.plugins.aps.events.EventLoopInvoked import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.rx.AapsSchedulers +import info.nightscout.shared.logging.AAPSLogger +import info.nightscout.shared.logging.LTag import info.nightscout.shared.sharedPreferences.SP import io.reactivex.rxjava3.disposables.CompositeDisposable import io.reactivex.rxjava3.kotlin.plusAssign @@ -88,20 +87,21 @@ class LoopPlugin @Inject constructor( private val uel: UserEntryLogger, private val repository: AppRepository, private val runningConfiguration: RunningConfiguration -) : PluginBase(PluginDescription() - .mainType(PluginType.LOOP) - .fragmentClass(LoopFragment::class.java.name) - .pluginIcon(R.drawable.ic_loop_closed_white) - .pluginName(R.string.loop) - .shortName(R.string.loop_shortname) - .preferencesId(R.xml.pref_loop) - .enableByDefault(config.APS) - .description(R.string.description_loop), +) : PluginBase( + PluginDescription() + .mainType(PluginType.LOOP) + .fragmentClass(LoopFragment::class.java.name) + .pluginIcon(R.drawable.ic_loop_closed_white) + .pluginName(R.string.loop) + .shortName(R.string.loop_shortname) + .preferencesId(R.xml.pref_loop) + .enableByDefault(config.APS) + .description(R.string.description_loop), aapsLogger, rh, injector ), Loop { private val disposable = CompositeDisposable() - private var lastBgTriggeredRun: Long = 0 + override var lastBgTriggeredRun: Long = 0 private var carbsSuggestionsSuspendedUntil: Long = 0 private var prevCarbsreq = 0 override var lastRun: LastRun? = null @@ -109,39 +109,19 @@ class LoopPlugin @Inject constructor( override fun onStart() { createNotificationChannel() super.onStart() - disposable.add(rxBus + disposable += rxBus .toObservable(EventTempTargetChange::class.java) .observeOn(aapsSchedulers.io) .subscribe({ invoke("EventTempTargetChange", true) }, fabricPrivacy::logException) - ) - /* - This method is triggered once autosens calculation has completed, so the LoopPlugin - has current data to work with. However, autosens calculation can be triggered by multiple - sources and currently only a new BG should trigger a loop run. Hence we return early if - the event causing the calculation is not EventNewBg. -

- */ - disposable.add(rxBus - .toObservable(EventAutosensCalculationFinished::class.java) - .observeOn(aapsSchedulers.io) - .subscribe({ event: EventAutosensCalculationFinished -> - // Autosens calculation not triggered by a new BG - if (event.cause !is EventNewBG) return@subscribe - val glucoseValue = iobCobCalculator.ads.actualBg() ?: return@subscribe - // BG outdated - // already looped with that value - if (glucoseValue.timestamp <= lastBgTriggeredRun) return@subscribe - lastBgTriggeredRun = glucoseValue.timestamp - invoke("AutosenseCalculation for $glucoseValue", true) - }, fabricPrivacy::logException) - ) } private fun createNotificationChannel() { val mNotificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager - @SuppressLint("WrongConstant") val channel = NotificationChannel(CHANNEL_ID, + @SuppressLint("WrongConstant") val channel = NotificationChannel( CHANNEL_ID, - NotificationManager.IMPORTANCE_HIGH) + CHANNEL_ID, + NotificationManager.IMPORTANCE_HIGH + ) mNotificationManager.createNotificationChannel(channel) } @@ -255,7 +235,7 @@ class LoopPlugin @Inject constructor( if (apsResult == null) { rxBus.send(EventLoopSetLastRunGui(rh.gs(R.string.noapsselected))) return - } else rxBus.send(EventLoopInvoked()) + } if (!isEmptyQueue()) { aapsLogger.debug(LTag.APS, rh.gs(R.string.pumpbusy)) @@ -296,9 +276,11 @@ class LoopPlugin @Inject constructor( lastRun.lastTBRRequest = 0 lastRun.lastSMBEnact = 0 lastRun.lastSMBRequest = 0 - buildDeviceStatus(dateUtil, this, iobCobCalculator, profileFunction, + buildDeviceStatus( + dateUtil, this, iobCobCalculator, profileFunction, activePlugin.activePump, receiverStatusStore, runningConfiguration, - BuildConfig.VERSION_NAME + "-" + BuildConfig.BUILDVERSION)?.also { + BuildConfig.VERSION_NAME + "-" + BuildConfig.BUILDVERSION + )?.also { repository.insert(it) } @@ -316,7 +298,11 @@ class LoopPlugin @Inject constructor( if (closedLoopEnabled.value()) { if (allowNotification) { if (resultAfterConstraints.isCarbsRequired - && resultAfterConstraints.carbsReq >= sp.getInt(R.string.key_smb_enable_carbs_suggestions_threshold, 0) && carbsSuggestionsSuspendedUntil < System.currentTimeMillis() && !treatmentTimeThreshold(-15)) { + && resultAfterConstraints.carbsReq >= sp.getInt( + R.string.key_smb_enable_carbs_suggestions_threshold, + 0 + ) && carbsSuggestionsSuspendedUntil < System.currentTimeMillis() && !treatmentTimeThreshold(-15) + ) { if (sp.getBoolean(R.string.key_enable_carbs_required_alert_local, true) && !sp.getBoolean(R.string.key_raise_notifications_as_android_notifications, true)) { val carbReqLocal = Notification(Notification.CARBS_REQUIRED, resultAfterConstraints.carbsRequiredText, Notification.NORMAL) rxBus.send(EventNewNotification(carbReqLocal)) @@ -353,9 +339,11 @@ class LoopPlugin @Inject constructor( // mId allows you to update the notification later on. mNotificationManager.notify(Constants.notificationID, builder.build()) - uel.log(Action.CAREPORTAL, Sources.Loop, rh.gs(R.string.carbsreq, resultAfterConstraints.carbsReq, resultAfterConstraints.carbsReqWithin), - ValueWithUnit.Gram(resultAfterConstraints.carbsReq), - ValueWithUnit.Minute(resultAfterConstraints.carbsReqWithin)) + uel.log( + Action.CAREPORTAL, Sources.Loop, rh.gs(R.string.carbsreq, resultAfterConstraints.carbsReq, resultAfterConstraints.carbsReqWithin), + ValueWithUnit.Gram(resultAfterConstraints.carbsReq), + ValueWithUnit.Minute(resultAfterConstraints.carbsReqWithin) + ) rxBus.send(EventNewOpenLoopNotification()) //only send to wear if Native notifications are turned off @@ -373,7 +361,8 @@ class LoopPlugin @Inject constructor( } } if (resultAfterConstraints.isChangeRequested - && !commandQueue.bolusInQueue()) { + && !commandQueue.bolusInQueue() + ) { val waiting = PumpEnactResult(injector) waiting.queued = true if (resultAfterConstraints.tempBasalRequested) lastRun.tbrSetByPump = waiting @@ -486,9 +475,11 @@ class LoopPlugin @Inject constructor( lastRun.lastTBRRequest = lastRun.lastAPSRun lastRun.lastTBREnact = dateUtil.now() lastRun.lastOpenModeAccept = dateUtil.now() - buildDeviceStatus(dateUtil, this@LoopPlugin, iobCobCalculator, profileFunction, + buildDeviceStatus( + dateUtil, this@LoopPlugin, iobCobCalculator, profileFunction, activePlugin.activePump, receiverStatusStore, runningConfiguration, - BuildConfig.VERSION_NAME + "-" + BuildConfig.BUILDVERSION)?.also { + BuildConfig.VERSION_NAME + "-" + BuildConfig.BUILDVERSION + )?.also { repository.insert(it) } sp.incInt(R.string.key_ObjectivesmanualEnacts) @@ -531,8 +522,10 @@ class LoopPlugin @Inject constructor( commandQueue.cancelTempBasal(false, callback) } else { aapsLogger.debug(LTag.APS, "applyAPSRequest: Basal set correctly") - callback?.result(PumpEnactResult(injector).absolute(request.rate).duration(0) - .enacted(false).success(true).comment(R.string.basal_set_correctly))?.run() + callback?.result( + PumpEnactResult(injector).absolute(request.rate).duration(0) + .enacted(false).success(true).comment(R.string.basal_set_correctly) + )?.run() } } else if (request.usePercent && allowPercentage()) { if (request.percent == 100 && request.duration == 0) { @@ -542,32 +535,52 @@ class LoopPlugin @Inject constructor( commandQueue.cancelTempBasal(false, callback) } else { aapsLogger.debug(LTag.APS, "applyAPSRequest: Basal set correctly") - callback?.result(PumpEnactResult(injector).percent(request.percent).duration(0) - .enacted(false).success(true).comment(R.string.basal_set_correctly))?.run() + callback?.result( + PumpEnactResult(injector).percent(request.percent).duration(0) + .enacted(false).success(true).comment(R.string.basal_set_correctly) + )?.run() } - } else if (activeTemp != null && activeTemp.plannedRemainingMinutes > 5 && request.duration - activeTemp.plannedRemainingMinutes < 30 && request.percent == activeTemp.convertedToPercent(now, profile)) { + } else if (activeTemp != null && activeTemp.plannedRemainingMinutes > 5 && request.duration - activeTemp.plannedRemainingMinutes < 30 && request.percent == activeTemp.convertedToPercent( + now, + profile + ) + ) { aapsLogger.debug(LTag.APS, "applyAPSRequest: Temp basal set correctly") - callback?.result(PumpEnactResult(injector).percent(request.percent) - .enacted(false).success(true).duration(activeTemp.plannedRemainingMinutes) - .comment(R.string.let_temp_basal_run))?.run() + callback?.result( + PumpEnactResult(injector).percent(request.percent) + .enacted(false).success(true).duration(activeTemp.plannedRemainingMinutes) + .comment(R.string.let_temp_basal_run) + )?.run() } else { aapsLogger.debug(LTag.APS, "applyAPSRequest: tempBasalPercent()") - uel.log(Action.TEMP_BASAL, Sources.Loop, + uel.log( + Action.TEMP_BASAL, Sources.Loop, ValueWithUnit.Percent(request.percent), - ValueWithUnit.Minute(request.duration)) + ValueWithUnit.Minute(request.duration) + ) commandQueue.tempBasalPercent(request.percent, request.duration, false, profile, PumpSync.TemporaryBasalType.NORMAL, callback) } } else { - if (activeTemp != null && activeTemp.plannedRemainingMinutes > 5 && request.duration - activeTemp.plannedRemainingMinutes < 30 && abs(request.rate - activeTemp.convertedToAbsolute(now, profile)) < pump.pumpDescription.basalStep) { + if (activeTemp != null && activeTemp.plannedRemainingMinutes > 5 && request.duration - activeTemp.plannedRemainingMinutes < 30 && abs( + request.rate - activeTemp.convertedToAbsolute( + now, + profile + ) + ) < pump.pumpDescription.basalStep + ) { aapsLogger.debug(LTag.APS, "applyAPSRequest: Temp basal set correctly") - callback?.result(PumpEnactResult(injector).absolute(activeTemp.convertedToAbsolute(now, profile)) - .enacted(false).success(true).duration(activeTemp.plannedRemainingMinutes) - .comment(R.string.let_temp_basal_run))?.run() + callback?.result( + PumpEnactResult(injector).absolute(activeTemp.convertedToAbsolute(now, profile)) + .enacted(false).success(true).duration(activeTemp.plannedRemainingMinutes) + .comment(R.string.let_temp_basal_run) + )?.run() } else { aapsLogger.debug(LTag.APS, "applyAPSRequest: setTempBasalAbsolute()") - uel.log(Action.TEMP_BASAL, Sources.Loop, + uel.log( + Action.TEMP_BASAL, Sources.Loop, ValueWithUnit.UnitPerHour(request.rate), - ValueWithUnit.Minute(request.duration)) + ValueWithUnit.Minute(request.duration) + ) commandQueue.tempBasalAbsolute(request.rate, request.duration, false, profile, PumpSync.TemporaryBasalType.NORMAL, callback) } } @@ -581,9 +594,11 @@ class LoopPlugin @Inject constructor( val lastBolusTime = repository.getLastBolusRecord()?.timestamp ?: 0L if (lastBolusTime != 0L && lastBolusTime + 3 * 60 * 1000 > System.currentTimeMillis()) { aapsLogger.debug(LTag.APS, "SMB requested but still in 3 min interval") - callback?.result(PumpEnactResult(injector) - .comment(R.string.smb_frequency_exceeded) - .enacted(false).success(false))?.run() + callback?.result( + PumpEnactResult(injector) + .comment(R.string.smb_frequency_exceeded) + .enacted(false).success(false) + )?.run() return } if (!pump.isInitialized()) { @@ -619,11 +634,11 @@ class LoopPlugin @Inject constructor( val pump = activePlugin.activePump disposable += repository.runTransactionForResult(InsertAndCancelCurrentOfflineEventTransaction(dateUtil.now(), T.mins(durationInMinutes.toLong()).msecs(), reason)) .subscribe({ result -> - result.updated.forEach { aapsLogger.debug(LTag.DATABASE, "Updated OfflineEvent $it") } - result.inserted.forEach { aapsLogger.debug(LTag.DATABASE, "Inserted OfflineEvent $it") } - }, { - aapsLogger.error(LTag.DATABASE, "Error while saving OfflineEvent", it) - }) + result.updated.forEach { aapsLogger.debug(LTag.DATABASE, "Updated OfflineEvent $it") } + result.inserted.forEach { aapsLogger.debug(LTag.DATABASE, "Inserted OfflineEvent $it") } + }, { + aapsLogger.error(LTag.DATABASE, "Error while saving OfflineEvent", it) + }) if (pump.pumpDescription.tempBasalStyle == PumpDescription.ABSOLUTE) { commandQueue.tempBasalAbsolute(0.0, durationInMinutes, true, profile, PumpSync.TemporaryBasalType.EMULATED_PUMP_SUSPEND, object : Callback() { override fun run() { @@ -655,11 +670,11 @@ class LoopPlugin @Inject constructor( override fun suspendLoop(durationInMinutes: Int) { disposable += repository.runTransactionForResult(InsertAndCancelCurrentOfflineEventTransaction(dateUtil.now(), T.mins(durationInMinutes.toLong()).msecs(), OfflineEvent.Reason.SUSPEND)) .subscribe({ result -> - result.updated.forEach { aapsLogger.debug(LTag.DATABASE, "Updated OfflineEvent $it") } - result.inserted.forEach { aapsLogger.debug(LTag.DATABASE, "Inserted OfflineEvent $it") } - }, { - aapsLogger.error(LTag.DATABASE, "Error while saving OfflineEvent", it) - }) + result.updated.forEach { aapsLogger.debug(LTag.DATABASE, "Updated OfflineEvent $it") } + result.inserted.forEach { aapsLogger.debug(LTag.DATABASE, "Inserted OfflineEvent $it") } + }, { + aapsLogger.error(LTag.DATABASE, "Error while saving OfflineEvent", it) + }) commandQueue.cancelTempBasal(true, object : Callback() { override fun run() { if (!result.success) { diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/configBuilder/PluginStore.kt b/app/src/main/java/info/nightscout/androidaps/plugins/configBuilder/PluginStore.kt index 3993606e73..a574219396 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/configBuilder/PluginStore.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/configBuilder/PluginStore.kt @@ -169,6 +169,9 @@ class PluginStore @Inject constructor( override val activeSafety: Safety get() = getSpecificPluginsListByInterface(Safety::class.java).first() as Safety + override val activeIobCobCalculator: IobCobCalculator + get() = getSpecificPluginsListByInterface(IobCobCalculator::class.java).first() as IobCobCalculator + override fun getPluginsList(): ArrayList = ArrayList(plugins) } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/dataBroadcaster/DataBroadcastPlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/dataBroadcaster/DataBroadcastPlugin.kt index 035c3a13a1..4d08f94a4e 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/dataBroadcaster/DataBroadcastPlugin.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/dataBroadcaster/DataBroadcastPlugin.kt @@ -6,12 +6,11 @@ import android.content.pm.ResolveInfo import android.os.Bundle import dagger.android.HasAndroidInjector import info.nightscout.androidaps.R -import info.nightscout.androidaps.events.* +import info.nightscout.androidaps.events.Event +import info.nightscout.androidaps.events.EventAutosensCalculationFinished import info.nightscout.androidaps.extensions.durationInMinutes import info.nightscout.androidaps.extensions.toStringFull import info.nightscout.androidaps.interfaces.* -import info.nightscout.shared.logging.AAPSLogger -import info.nightscout.shared.logging.LTag import info.nightscout.androidaps.plugins.aps.events.EventOpenAPSUpdateGui import info.nightscout.androidaps.plugins.bus.RxBus import info.nightscout.androidaps.plugins.general.nsclient.data.DeviceStatusData @@ -25,6 +24,8 @@ import info.nightscout.androidaps.utils.DefaultValueHelper import info.nightscout.androidaps.utils.FabricPrivacy import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.rx.AapsSchedulers +import info.nightscout.shared.logging.AAPSLogger +import info.nightscout.shared.logging.LTag import io.reactivex.rxjava3.disposables.CompositeDisposable import javax.inject.Inject import javax.inject.Singleton @@ -68,26 +69,6 @@ class DataBroadcastPlugin @Inject constructor( .observeOn(aapsSchedulers.io) .subscribe({ sendData(it) }, fabricPrivacy::logException) ) - disposable.add(rxBus - .toObservable(EventExtendedBolusChange::class.java) - .observeOn(aapsSchedulers.io) - .subscribe({ sendData(it) }, fabricPrivacy::logException) - ) - disposable.add(rxBus - .toObservable(EventTempBasalChange::class.java) - .observeOn(aapsSchedulers.io) - .subscribe({ sendData(it) }, fabricPrivacy::logException) - ) - disposable.add(rxBus - .toObservable(EventTreatmentChange::class.java) - .observeOn(aapsSchedulers.io) - .subscribe({ sendData(it) }, fabricPrivacy::logException) - ) - disposable.add(rxBus - .toObservable(EventEffectiveProfileSwitchChanged::class.java) - .observeOn(aapsSchedulers.io) - .subscribe({ sendData(it) }, fabricPrivacy::logException) - ) disposable.add(rxBus .toObservable(EventAutosensCalculationFinished::class.java) .observeOn(aapsSchedulers.io) diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NSClientPlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NSClientPlugin.kt index d63cf23512..94a2eecbac 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NSClientPlugin.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NSClientPlugin.kt @@ -170,8 +170,7 @@ class NSClientPlugin @Inject constructor( override fun onServiceConnected(name: ComponentName, service: IBinder) { aapsLogger.debug(LTag.NSCLIENT, "Service is connected") - val mLocalBinder = service as NSClientService.LocalBinder - @Suppress("UNNECESSARY_SAFE_CALL") + val mLocalBinder = service as NSClientService.LocalBinder? nsClientService = mLocalBinder?.serviceInstance // is null when running in roboelectric } } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/OverviewData.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/OverviewData.kt index c7b937666e..8648b27428 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/OverviewData.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/OverviewData.kt @@ -1,46 +1,42 @@ package info.nightscout.androidaps.plugins.general.overview import android.content.Context -import android.graphics.DashPathEffect -import android.graphics.Paint import androidx.annotation.ColorInt import com.jjoe64.graphview.series.BarGraphSeries import com.jjoe64.graphview.series.DataPoint import com.jjoe64.graphview.series.LineGraphSeries -import dagger.android.HasAndroidInjector import info.nightscout.androidaps.R import info.nightscout.androidaps.data.IobTotal import info.nightscout.androidaps.database.AppRepository import info.nightscout.androidaps.database.ValueWrapper -import info.nightscout.androidaps.database.entities.Bolus import info.nightscout.androidaps.database.entities.GlucoseValue import info.nightscout.androidaps.database.entities.TemporaryTarget -import info.nightscout.androidaps.database.entities.TherapyEvent -import info.nightscout.androidaps.extensions.* -import info.nightscout.androidaps.interfaces.* -import info.nightscout.shared.logging.AAPSLogger -import info.nightscout.shared.logging.LTag -import info.nightscout.androidaps.plugins.aps.openAPSSMB.SMBDefaults -import info.nightscout.androidaps.plugins.general.nsclient.data.NSDeviceStatus -import info.nightscout.androidaps.plugins.general.overview.graphExtensions.* -import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensResult +import info.nightscout.androidaps.extensions.convertedToPercent +import info.nightscout.androidaps.extensions.isInProgress +import info.nightscout.androidaps.extensions.toStringFull +import info.nightscout.androidaps.extensions.toStringShort +import info.nightscout.androidaps.extensions.valueToUnits +import info.nightscout.androidaps.interfaces.ActivePlugin +import info.nightscout.androidaps.interfaces.IobCobCalculator +import info.nightscout.androidaps.interfaces.ProfileFunction +import info.nightscout.androidaps.plugins.general.overview.graphExtensions.DataPointWithLabelInterface +import info.nightscout.androidaps.plugins.general.overview.graphExtensions.FixedLineGraphSeries +import info.nightscout.androidaps.plugins.general.overview.graphExtensions.PointsWithLabelGraphSeries +import info.nightscout.androidaps.plugins.general.overview.graphExtensions.Scale +import info.nightscout.androidaps.plugins.general.overview.graphExtensions.ScaledDataPoint import info.nightscout.androidaps.plugins.iob.iobCobCalculator.CobInfo -import info.nightscout.androidaps.plugins.iob.iobCobCalculator.data.AutosensData -import info.nightscout.androidaps.utils.* +import info.nightscout.androidaps.utils.DateUtil +import info.nightscout.androidaps.utils.DefaultValueHelper +import info.nightscout.androidaps.utils.T import info.nightscout.androidaps.utils.resources.ResourceHelper +import info.nightscout.shared.logging.AAPSLogger import info.nightscout.shared.sharedPreferences.SP import java.util.* import javax.inject.Inject import javax.inject.Singleton -import kotlin.collections.ArrayList -import kotlin.math.abs -import kotlin.math.ceil -import kotlin.math.max -import kotlin.math.min @Singleton class OverviewData @Inject constructor( - private val injector: HasAndroidInjector, private val aapsLogger: AAPSLogger, private val rh: ResourceHelper, private val dateUtil: DateUtil, @@ -48,13 +44,7 @@ class OverviewData @Inject constructor( private val activePlugin: ActivePlugin, private val defaultValueHelper: DefaultValueHelper, private val profileFunction: ProfileFunction, - private val config: Config, - private val loop: Loop, - private val nsDeviceStatus: NSDeviceStatus, - private val repository: AppRepository, - private val overviewMenus: OverviewMenus, - private val iobCobCalculator: IobCobCalculator, - private val translator: Translator + private val repository: AppRepository ) { var rangeToDisplay = 6 // for graph @@ -65,13 +55,6 @@ class OverviewData @Inject constructor( fun reset() { pumpStatus = "" calcProgressPct = 100 - lastBg = null - bolusIob = null - basalIob = null - cobInfo = null - lastCarbsTime = 0L - temporaryTarget = null - lastAutosensData = null bgReadingsArray = ArrayList() bucketedGraphSeries = PointsWithLabelGraphSeries() bgReadingGraphSeries = PointsWithLabelGraphSeries() @@ -128,7 +111,12 @@ class OverviewData @Inject constructor( * BG */ - var lastBg: GlucoseValue? = null + val lastBg: GlucoseValue? + get() = + repository.getLastGlucoseValueWrapped().blockingGet().let { gvWrapped -> + if (gvWrapped is ValueWrapper.Existing) gvWrapped.value + else null + } val isLow: Boolean get() = lastBg?.let { lastBg -> @@ -165,17 +153,16 @@ class OverviewData @Inject constructor( * TEMPORARY BASAL */ - val temporaryBasalText: String - get() = - profileFunction.getProfile()?.let { profile -> - var temporaryBasal = iobCobCalculator.getTempBasalIncludingConvertedExtended(dateUtil.now()) - if (temporaryBasal?.isInProgress == false) temporaryBasal = null - temporaryBasal?.let { "T:" + it.toStringShort() } - ?: rh.gs(R.string.pump_basebasalrate, profile.getBasal()) - } ?: rh.gs(R.string.notavailable) + fun temporaryBasalText(iobCobCalculator: IobCobCalculator): String = + profileFunction.getProfile()?.let { profile -> + var temporaryBasal = iobCobCalculator.getTempBasalIncludingConvertedExtended(dateUtil.now()) + if (temporaryBasal?.isInProgress == false) temporaryBasal = null + temporaryBasal?.let { "T:" + it.toStringShort() } + ?: rh.gs(R.string.pump_basebasalrate, profile.getBasal()) + } ?: rh.gs(R.string.notavailable) - val temporaryBasalDialogText: String - get() = profileFunction.getProfile()?.let { profile -> + fun temporaryBasalDialogText(iobCobCalculator: IobCobCalculator): String = + profileFunction.getProfile()?.let { profile -> iobCobCalculator.getTempBasalIncludingConvertedExtended(dateUtil.now())?.let { temporaryBasal -> "${rh.gs(R.string.basebasalrate_label)}: ${rh.gs(R.string.pump_basebasalrate, profile.getBasal())}" + "\n" + rh.gs(R.string.tempbasal_label) + ": " + temporaryBasal.toStringFull(profile, dateUtil) @@ -183,76 +170,78 @@ class OverviewData @Inject constructor( ?: "${rh.gs(R.string.basebasalrate_label)}: ${rh.gs(R.string.pump_basebasalrate, profile.getBasal())}" } ?: rh.gs(R.string.notavailable) - val temporaryBasalIcon: Int - get() = - profileFunction.getProfile()?.let { profile -> - iobCobCalculator.getTempBasalIncludingConvertedExtended(dateUtil.now())?.let { temporaryBasal -> - val percentRate = temporaryBasal.convertedToPercent(dateUtil.now(), profile) - when { - percentRate > 100 -> R.drawable.ic_cp_basal_tbr_high - percentRate < 100 -> R.drawable.ic_cp_basal_tbr_low - else -> R.drawable.ic_cp_basal_no_tbr - } + fun temporaryBasalIcon(iobCobCalculator: IobCobCalculator): Int = + profileFunction.getProfile()?.let { profile -> + iobCobCalculator.getTempBasalIncludingConvertedExtended(dateUtil.now())?.let { temporaryBasal -> + val percentRate = temporaryBasal.convertedToPercent(dateUtil.now(), profile) + when { + percentRate > 100 -> R.drawable.ic_cp_basal_tbr_high + percentRate < 100 -> R.drawable.ic_cp_basal_tbr_low + else -> R.drawable.ic_cp_basal_no_tbr } - } ?: R.drawable.ic_cp_basal_no_tbr + } + } ?: R.drawable.ic_cp_basal_no_tbr - val temporaryBasalColor: Int - get() = iobCobCalculator.getTempBasalIncludingConvertedExtended(dateUtil.now())?.let { rh.gc(R.color.basal) } - ?: rh.gc(R.color.defaulttextcolor) + // will be removed if a solution of getting the right color for widget is solved + fun temporaryBasalColor(iobCobCalculator: IobCobCalculator): Int = + iobCobCalculator.getTempBasalIncludingConvertedExtended(dateUtil.now())?.let { rh.gc(R.color.basal) } + ?: rh.gc(R.color.textAppearancemediumDark) + + fun temporaryBasalColor(context: Context?, iobCobCalculator: IobCobCalculator): Int = iobCobCalculator.getTempBasalIncludingConvertedExtended(dateUtil.now())?.let { rh.gac(context , R.attr.basal) } + ?: rh.gac(context, R.attr.textAppearancemediumColor) /* * EXTENDED BOLUS */ - val extendedBolusText: String - get() = - iobCobCalculator.getExtendedBolus(dateUtil.now())?.let { extendedBolus -> - if (!extendedBolus.isInProgress(dateUtil)) "" - else if (!activePlugin.activePump.isFakingTempsByExtendedBoluses) rh.gs(R.string.pump_basebasalrate, extendedBolus.rate) - else "" - } ?: "" + fun extendedBolusText(iobCobCalculator: IobCobCalculator): String = + iobCobCalculator.getExtendedBolus(dateUtil.now())?.let { extendedBolus -> + if (!extendedBolus.isInProgress(dateUtil)) "" + else if (!activePlugin.activePump.isFakingTempsByExtendedBoluses) rh.gs(R.string.pump_basebasalrate, extendedBolus.rate) + else "" + } ?: "" - val extendedBolusDialogText: String - get() = iobCobCalculator.getExtendedBolus(dateUtil.now())?.toStringFull(dateUtil) ?: "" + fun extendedBolusDialogText(iobCobCalculator: IobCobCalculator): String = + iobCobCalculator.getExtendedBolus(dateUtil.now())?.toStringFull(dateUtil) ?: "" /* * IOB, COB */ - var bolusIob: IobTotal? = null - var basalIob: IobTotal? = null - var cobInfo: CobInfo? = null - var lastCarbsTime: Long = 0L + fun bolusIob(iobCobCalculator: IobCobCalculator): IobTotal = iobCobCalculator.calculateIobFromBolus().round() + fun basalIob(iobCobCalculator: IobCobCalculator): IobTotal = iobCobCalculator.calculateIobFromTempBasalsIncludingConvertedExtended().round() + fun cobInfo(iobCobCalculator: IobCobCalculator): CobInfo = iobCobCalculator.getCobInfo(true, "Overview COB") - val iobText: String - get() = - bolusIob?.let { bolusIob -> - basalIob?.let { basalIob -> - rh.gs(R.string.formatinsulinunits, bolusIob.iob + basalIob.basaliob) - } ?: rh.gs(R.string.value_unavailable_short) - } ?: rh.gs(R.string.value_unavailable_short) + val lastCarbsTime: Long + get() = repository.getLastCarbsRecordWrapped().blockingGet().let { lastCarbs -> + if (lastCarbs is ValueWrapper.Existing) lastCarbs.value.timestamp else 0L + } - val iobDialogText: String - get() = - bolusIob?.let { bolusIob -> - basalIob?.let { basalIob -> - rh.gs(R.string.formatinsulinunits, bolusIob.iob + basalIob.basaliob) + "\n" + - rh.gs(R.string.bolus) + ": " + rh.gs(R.string.formatinsulinunits, bolusIob.iob) + "\n" + - rh.gs(R.string.basal) + ": " + rh.gs(R.string.formatinsulinunits, basalIob.basaliob) - } ?: rh.gs(R.string.value_unavailable_short) - } ?: rh.gs(R.string.value_unavailable_short) + fun iobText(iobCobCalculator: IobCobCalculator): String = + rh.gs(R.string.formatinsulinunits, bolusIob(iobCobCalculator).iob + basalIob(iobCobCalculator).basaliob) + + fun iobDialogText(iobCobCalculator: IobCobCalculator): String = + rh.gs(R.string.formatinsulinunits, bolusIob(iobCobCalculator).iob + basalIob(iobCobCalculator).basaliob) + "\n" + + rh.gs(R.string.bolus) + ": " + rh.gs(R.string.formatinsulinunits, bolusIob(iobCobCalculator).iob) + "\n" + + rh.gs(R.string.basal) + ": " + rh.gs(R.string.formatinsulinunits, basalIob(iobCobCalculator).basaliob) /* * TEMP TARGET */ - var temporaryTarget: TemporaryTarget? = null + val temporaryTarget: TemporaryTarget? + get() = + repository.getTemporaryTargetActiveAt(dateUtil.now()).blockingGet().let { tempTarget -> + if (tempTarget is ValueWrapper.Existing) tempTarget.value + else null + } /* * SENSITIVITY */ - var lastAutosensData: AutosensData? = null + fun lastAutosensData(iobCobCalculator: IobCobCalculator) = iobCobCalculator.ads.getLastAutosensData("Overview", aapsLogger, dateUtil) + /* * Graphs */ @@ -312,532 +301,4 @@ class OverviewData @Inject constructor( val dsMinScale = Scale() var dsMaxSeries: LineGraphSeries = LineGraphSeries() var dsMinSeries: LineGraphSeries = LineGraphSeries() - - @Synchronized - @Suppress("SameParameterValue", "UNUSED_PARAMETER") - fun prepareBgData(from: String) { -// val start = dateUtil.now() - maxBgValue = Double.MIN_VALUE - bgReadingsArray = repository.compatGetBgReadingsDataFromTime(fromTime, toTime, false).blockingGet() - val bgListArray: MutableList = java.util.ArrayList() - for (bg in bgReadingsArray) { - if (bg.timestamp < fromTime || bg.timestamp > toTime) continue - if (bg.value > maxBgValue) maxBgValue = bg.value - bgListArray.add(GlucoseValueDataPoint(bg, defaultValueHelper, profileFunction, rh)) - } - bgListArray.sortWith { o1: DataPointWithLabelInterface, o2: DataPointWithLabelInterface -> o1.x.compareTo(o2.x) } - bgReadingGraphSeries = PointsWithLabelGraphSeries(Array(bgListArray.size) { i -> bgListArray[i] }) - maxBgValue = Profile.fromMgdlToUnits(maxBgValue, profileFunction.getUnits()) - if (defaultValueHelper.determineHighLine() > maxBgValue) maxBgValue = defaultValueHelper.determineHighLine() - maxBgValue = addUpperChartMargin(maxBgValue) -// profiler.log(LTag.UI, "prepareBgData() $from", start) - } - - @Suppress("UNUSED_PARAMETER") - @Synchronized - fun preparePredictions(from: String) { -// val start = dateUtil.now() - val apsResult = if (config.APS) loop.lastRun?.constraintsProcessed else nsDeviceStatus.getAPSResult(injector) - val predictionsAvailable = if (config.APS) loop.lastRun?.request?.hasPredictions == true else config.NSCLIENT - val menuChartSettings = overviewMenus.setting - // align to hours - val calendar = Calendar.getInstance().also { - it.timeInMillis = System.currentTimeMillis() - it[Calendar.MILLISECOND] = 0 - it[Calendar.SECOND] = 0 - it[Calendar.MINUTE] = 0 - it.add(Calendar.HOUR, 1) - } - if (predictionsAvailable && apsResult != null && menuChartSettings[0][OverviewMenus.CharType.PRE.ordinal]) { - var predictionHours = (ceil(apsResult.latestPredictionsTime - System.currentTimeMillis().toDouble()) / (60 * 60 * 1000)).toInt() - predictionHours = min(2, predictionHours) - predictionHours = max(0, predictionHours) - val hoursToFetch = rangeToDisplay - predictionHours - toTime = calendar.timeInMillis + 100000 // little bit more to avoid wrong rounding - GraphView specific - fromTime = toTime - T.hours(hoursToFetch.toLong()).msecs() - endTime = toTime + T.hours(predictionHours.toLong()).msecs() - } else { - toTime = calendar.timeInMillis + 100000 // little bit more to avoid wrong rounding - GraphView specific - fromTime = toTime - T.hours(rangeToDisplay.toLong()).msecs() - endTime = toTime - } - - val bgListArray: MutableList = java.util.ArrayList() - val predictions: MutableList? = apsResult?.predictions - ?.map { bg -> GlucoseValueDataPoint(bg, defaultValueHelper, profileFunction, rh) } - ?.toMutableList() - if (predictions != null) { - predictions.sortWith { o1: GlucoseValueDataPoint, o2: GlucoseValueDataPoint -> o1.x.compareTo(o2.x) } - for (prediction in predictions) if (prediction.data.value >= 40) bgListArray.add(prediction) - } - predictionsGraphSeries = PointsWithLabelGraphSeries(Array(bgListArray.size) { i -> bgListArray[i] }) -// profiler.log(LTag.UI, "preparePredictions() $from", start) - } - - @Synchronized - @Suppress("SameParameterValue", "UNUSED_PARAMETER") - fun prepareBucketedData(from: String) { -// val start = dateUtil.now() - val bucketedData = iobCobCalculator.ads.getBucketedDataTableCopy() ?: return - if (bucketedData.isEmpty()) { - aapsLogger.debug("No bucketed data.") - return - } - val bucketedListArray: MutableList = java.util.ArrayList() - for (inMemoryGlucoseValue in bucketedData) { - if (inMemoryGlucoseValue.timestamp < fromTime || inMemoryGlucoseValue.timestamp > toTime) continue - bucketedListArray.add(InMemoryGlucoseValueDataPoint(inMemoryGlucoseValue, profileFunction, rh)) - } - bucketedListArray.sortWith { o1: DataPointWithLabelInterface, o2: DataPointWithLabelInterface -> o1.x.compareTo(o2.x) } - bucketedGraphSeries = PointsWithLabelGraphSeries(Array(bucketedListArray.size) { i -> bucketedListArray[i] }) -// profiler.log(LTag.UI, "prepareBucketedData() $from", start) - } - - @Suppress("UNUSED_PARAMETER") - @Synchronized - fun prepareBasalData(from: String) { -// val start = dateUtil.now() - maxBasalValueFound = 0.0 - val baseBasalArray: MutableList = java.util.ArrayList() - val tempBasalArray: MutableList = java.util.ArrayList() - val basalLineArray: MutableList = java.util.ArrayList() - val absoluteBasalLineArray: MutableList = java.util.ArrayList() - var lastLineBasal = 0.0 - var lastAbsoluteLineBasal = -1.0 - var lastBaseBasal = 0.0 - var lastTempBasal = 0.0 - var time = fromTime - while (time < toTime) { - val profile = profileFunction.getProfile(time) - if (profile == null) { - time += 60 * 1000L - continue - } - val basalData = iobCobCalculator.getBasalData(profile, time) - val baseBasalValue = basalData.basal - var absoluteLineValue = baseBasalValue - var tempBasalValue = 0.0 - var basal = 0.0 - if (basalData.isTempBasalRunning) { - tempBasalValue = basalData.tempBasalAbsolute - absoluteLineValue = tempBasalValue - if (tempBasalValue != lastTempBasal) { - tempBasalArray.add(ScaledDataPoint(time, lastTempBasal, basalScale)) - tempBasalArray.add(ScaledDataPoint(time, tempBasalValue.also { basal = it }, basalScale)) - } - if (lastBaseBasal != 0.0) { - baseBasalArray.add(ScaledDataPoint(time, lastBaseBasal, basalScale)) - baseBasalArray.add(ScaledDataPoint(time, 0.0, basalScale)) - lastBaseBasal = 0.0 - } - } else { - if (baseBasalValue != lastBaseBasal) { - baseBasalArray.add(ScaledDataPoint(time, lastBaseBasal, basalScale)) - baseBasalArray.add(ScaledDataPoint(time, baseBasalValue.also { basal = it }, basalScale)) - lastBaseBasal = baseBasalValue - } - if (lastTempBasal != 0.0) { - tempBasalArray.add(ScaledDataPoint(time, lastTempBasal, basalScale)) - tempBasalArray.add(ScaledDataPoint(time, 0.0, basalScale)) - } - } - if (baseBasalValue != lastLineBasal) { - basalLineArray.add(ScaledDataPoint(time, lastLineBasal, basalScale)) - basalLineArray.add(ScaledDataPoint(time, baseBasalValue, basalScale)) - } - if (absoluteLineValue != lastAbsoluteLineBasal) { - absoluteBasalLineArray.add(ScaledDataPoint(time, lastAbsoluteLineBasal, basalScale)) - absoluteBasalLineArray.add(ScaledDataPoint(time, basal, basalScale)) - } - lastAbsoluteLineBasal = absoluteLineValue - lastLineBasal = baseBasalValue - lastTempBasal = tempBasalValue - maxBasalValueFound = max(maxBasalValueFound, max(tempBasalValue, baseBasalValue)) - time += 60 * 1000L - } - - // final points - basalLineArray.add(ScaledDataPoint(toTime, lastLineBasal, basalScale)) - baseBasalArray.add(ScaledDataPoint(toTime, lastBaseBasal, basalScale)) - tempBasalArray.add(ScaledDataPoint(toTime, lastTempBasal, basalScale)) - absoluteBasalLineArray.add(ScaledDataPoint(toTime, lastAbsoluteLineBasal, basalScale)) - - // create series - baseBasalGraphSeries = LineGraphSeries(Array(baseBasalArray.size) { i -> baseBasalArray[i] }).also { - it.isDrawBackground = true - it.backgroundColor = rh.gc(R.color.basebasal) - it.thickness = 0 - } - tempBasalGraphSeries = LineGraphSeries(Array(tempBasalArray.size) { i -> tempBasalArray[i] }).also { - it.isDrawBackground = true - it.backgroundColor = rh.gc(R.color.tempbasal) - it.thickness = 0 - } - basalLineGraphSeries = LineGraphSeries(Array(basalLineArray.size) { i -> basalLineArray[i] }).also { - it.setCustomPaint(Paint().also { paint -> - paint.style = Paint.Style.STROKE - paint.strokeWidth = rh.getDisplayMetrics().scaledDensity * 2 - paint.pathEffect = DashPathEffect(floatArrayOf(2f, 4f), 0f) - paint.color = rh.gc(R.color.basal) - }) - } - absoluteBasalGraphSeries = LineGraphSeries(Array(absoluteBasalLineArray.size) { i -> absoluteBasalLineArray[i] }).also { - it.setCustomPaint(Paint().also { absolutePaint -> - absolutePaint.style = Paint.Style.STROKE - absolutePaint.strokeWidth = rh.getDisplayMetrics().scaledDensity * 2 - absolutePaint.color = rh.gc(R.color.basal) - }) - } -// profiler.log(LTag.UI, "prepareBasalData() $from", start) - } - - @Suppress("UNUSED_PARAMETER") - @Synchronized - fun prepareTemporaryTargetData(from: String) { -// val start = dateUtil.now() - val profile = profileFunction.getProfile() ?: return - val units = profileFunction.getUnits() - var toTime = toTime - val targetsSeriesArray: MutableList = java.util.ArrayList() - var lastTarget = -1.0 - loop.lastRun?.constraintsProcessed?.let { toTime = max(it.latestPredictionsTime, toTime) } - var time = fromTime - while (time < toTime) { - val tt = repository.getTemporaryTargetActiveAt(time).blockingGet() - val value: Double = if (tt is ValueWrapper.Existing) { - Profile.fromMgdlToUnits(tt.value.target(), units) - } else { - Profile.fromMgdlToUnits((profile.getTargetLowMgdl(time) + profile.getTargetHighMgdl(time)) / 2, units) - } - if (lastTarget != value) { - if (lastTarget != -1.0) targetsSeriesArray.add(DataPoint(time.toDouble(), lastTarget)) - targetsSeriesArray.add(DataPoint(time.toDouble(), value)) - } - lastTarget = value - time += 5 * 60 * 1000L - } - // final point - targetsSeriesArray.add(DataPoint(toTime.toDouble(), lastTarget)) - // create series - temporaryTargetSeries = LineGraphSeries(Array(targetsSeriesArray.size) { i -> targetsSeriesArray[i] }).also { - it.isDrawBackground = false - it.color = rh.gc(R.color.tempTargetBackground) - it.thickness = 2 - } -// profiler.log(LTag.UI, "prepareTemporaryTargetData() $from", start) - } - - @Suppress("UNUSED_PARAMETER") - @Synchronized - fun prepareTreatmentsData(from: String) { -// val start = dateUtil.now() - maxTreatmentsValue = 0.0 - val filteredTreatments: MutableList = java.util.ArrayList() - repository.getBolusesDataFromTimeToTime(fromTime, endTime, true).blockingGet() - .map { BolusDataPoint(it, rh, activePlugin, defaultValueHelper) } - .filter { it.data.type == Bolus.Type.NORMAL || it.data.type == Bolus.Type.SMB } - .forEach { - it.y = getNearestBg(it.x.toLong()) - filteredTreatments.add(it) - } - repository.getCarbsDataFromTimeToTimeExpanded(fromTime, endTime, true).blockingGet() - .map { CarbsDataPoint(it, rh) } - .forEach { - it.y = getNearestBg(it.x.toLong()) - filteredTreatments.add(it) - } - - // ProfileSwitch - repository.getEffectiveProfileSwitchDataFromTimeToTime(fromTime, endTime, true).blockingGet() - .map { EffectiveProfileSwitchDataPoint(it,rh) } - .forEach(filteredTreatments::add) - - // OfflineEvent - repository.getOfflineEventDataFromTimeToTime(fromTime, endTime, true).blockingGet() - .map { - TherapyEventDataPoint( - TherapyEvent(timestamp = it.timestamp, duration = it.duration, type = TherapyEvent.Type.APS_OFFLINE, glucoseUnit = TherapyEvent.GlucoseUnit.MMOL), - rh, - profileFunction, - translator - ) - } - .forEach(filteredTreatments::add) - - // Extended bolus - if (!activePlugin.activePump.isFakingTempsByExtendedBoluses) { - repository.getExtendedBolusDataFromTimeToTime(fromTime, endTime, true).blockingGet() - .map { ExtendedBolusDataPoint(it, rh) } - .filter { it.duration != 0L } - .forEach { - it.y = getNearestBg(it.x.toLong()) - filteredTreatments.add(it) - } - } - - // Careportal - repository.compatGetTherapyEventDataFromToTime(fromTime - T.hours(6).msecs(), endTime).blockingGet() - .map { TherapyEventDataPoint(it, rh, profileFunction, translator) } - .filterTimeframe(fromTime, endTime) - .forEach { - if (it.y == 0.0) it.y = getNearestBg(it.x.toLong()) - filteredTreatments.add(it) - } - - // increase maxY if a treatment forces it's own height that's higher than a BG value - filteredTreatments.map { it.y } - .maxOrNull() - ?.let(::addUpperChartMargin) - ?.let { maxTreatmentsValue = maxOf(maxTreatmentsValue, it) } - - treatmentsSeries = PointsWithLabelGraphSeries(filteredTreatments.toTypedArray()) -// profiler.log(LTag.UI, "prepareTreatmentsData() $from", start) - } - - @Suppress("UNUSED_PARAMETER") - @Synchronized - fun prepareIobAutosensData(from: String) { -// val start = dateUtil.now() - val iobArray: MutableList = java.util.ArrayList() - val absIobArray: MutableList = java.util.ArrayList() - maxIobValueFound = Double.MIN_VALUE - var lastIob = 0.0 - var absLastIob = 0.0 - var time = fromTime - - val minFailOverActiveList: MutableList = java.util.ArrayList() - val cobArray: MutableList = java.util.ArrayList() - maxCobValueFound = Double.MIN_VALUE - var lastCob = 0 - - val actArrayHist: MutableList = java.util.ArrayList() - val actArrayPrediction: MutableList = java.util.ArrayList() - val now = dateUtil.now().toDouble() - maxIAValue = 0.0 - - val bgiArrayHist: MutableList = java.util.ArrayList() - val bgiArrayPrediction: MutableList = java.util.ArrayList() - maxBGIValue = Double.MIN_VALUE - - val devArray: MutableList = java.util.ArrayList() - maxDevValueFound = Double.MIN_VALUE - - val ratioArray: MutableList = java.util.ArrayList() - maxRatioValueFound = 5.0 //even if sens data equals 0 for all the period, minimum scale is between 95% and 105% - minRatioValueFound = -5.0 - - val dsMaxArray: MutableList = java.util.ArrayList() - val dsMinArray: MutableList = java.util.ArrayList() - maxFromMaxValueFound = Double.MIN_VALUE - maxFromMinValueFound = Double.MIN_VALUE - - val adsData = iobCobCalculator.ads.clone() - - while (time <= toTime) { - val profile = profileFunction.getProfile(time) - if (profile == null) { - time += 5 * 60 * 1000L - continue - } - // IOB - val iob = iobCobCalculator.calculateFromTreatmentsAndTemps(time, profile) - val baseBasalIob = iobCobCalculator.calculateAbsoluteIobFromBaseBasals(time) - val absIob = IobTotal.combine(iob, baseBasalIob) - val autosensData = adsData.getAutosensDataAtTime(time) - if (abs(lastIob - iob.iob) > 0.02) { - if (abs(lastIob - iob.iob) > 0.2) iobArray.add(ScaledDataPoint(time, lastIob, iobScale)) - iobArray.add(ScaledDataPoint(time, iob.iob, iobScale)) - maxIobValueFound = maxOf(maxIobValueFound, abs(iob.iob)) - lastIob = iob.iob - } - if (abs(absLastIob - absIob.iob) > 0.02) { - if (abs(absLastIob - absIob.iob) > 0.2) absIobArray.add(ScaledDataPoint(time, absLastIob, iobScale)) - absIobArray.add(ScaledDataPoint(time, absIob.iob, iobScale)) - maxIobValueFound = maxOf(maxIobValueFound, abs(absIob.iob)) - absLastIob = absIob.iob - } - - // COB - if (autosensData != null) { - val cob = autosensData.cob.toInt() - if (cob != lastCob) { - if (autosensData.carbsFromBolus > 0) cobArray.add(ScaledDataPoint(time, lastCob.toDouble(), cobScale)) - cobArray.add(ScaledDataPoint(time, cob.toDouble(), cobScale)) - maxCobValueFound = max(maxCobValueFound, cob.toDouble()) - lastCob = cob - } - if (autosensData.failOverToMinAbsorptionRate) { - autosensData.scale = cobScale - autosensData.chartTime = time - minFailOverActiveList.add(autosensData) - } - } - - // ACTIVITY - if (time <= now) actArrayHist.add(ScaledDataPoint(time, iob.activity, actScale)) - else actArrayPrediction.add(ScaledDataPoint(time, iob.activity, actScale)) - maxIAValue = max(maxIAValue, abs(iob.activity)) - - // BGI - val devBgiScale = overviewMenus.isEnabledIn(OverviewMenus.CharType.DEV) == overviewMenus.isEnabledIn(OverviewMenus.CharType.BGI) - val deviation = if (devBgiScale) autosensData?.deviation ?: 0.0 else 0.0 - val bgi: Double = iob.activity * profile.getIsfMgdl(time) * 5.0 - if (time <= now) bgiArrayHist.add(ScaledDataPoint(time, bgi, bgiScale)) - else bgiArrayPrediction.add(ScaledDataPoint(time, bgi, bgiScale)) - maxBGIValue = max(maxBGIValue, max(abs(bgi), deviation)) - - // DEVIATIONS - if (autosensData != null) { - var color = rh.gc(R.color.deviationblack) // "=" - if (autosensData.type == "" || autosensData.type == "non-meal") { - if (autosensData.pastSensitivity == "C") color = rh.gc(R.color.deviationgrey) - if (autosensData.pastSensitivity == "+") color = rh.gc(R.color.deviationgreen) - if (autosensData.pastSensitivity == "-") color = rh.gc(R.color.deviationred) - } else if (autosensData.type == "uam") { - color = rh.gc(R.color.uam) - } else if (autosensData.type == "csf") { - color = rh.gc(R.color.deviationgrey) - } - devArray.add(OverviewPlugin.DeviationDataPoint(time.toDouble(), autosensData.deviation, color, devScale)) - maxDevValueFound = maxOf(maxDevValueFound, abs(autosensData.deviation), abs(bgi)) - } - - // RATIO - if (autosensData != null) { - ratioArray.add(ScaledDataPoint(time, 100.0 * (autosensData.autosensResult.ratio - 1), ratioScale)) - maxRatioValueFound = max(maxRatioValueFound, 100.0 * (autosensData.autosensResult.ratio - 1)) - minRatioValueFound = min(minRatioValueFound, 100.0 * (autosensData.autosensResult.ratio - 1)) - } - - // DEV SLOPE - if (autosensData != null) { - dsMaxArray.add(ScaledDataPoint(time, autosensData.slopeFromMaxDeviation, dsMaxScale)) - dsMinArray.add(ScaledDataPoint(time, autosensData.slopeFromMinDeviation, dsMinScale)) - maxFromMaxValueFound = max(maxFromMaxValueFound, abs(autosensData.slopeFromMaxDeviation)) - maxFromMinValueFound = max(maxFromMinValueFound, abs(autosensData.slopeFromMinDeviation)) - } - - time += 5 * 60 * 1000L - } - // IOB - iobSeries = FixedLineGraphSeries(Array(iobArray.size) { i -> iobArray[i] }).also { - it.isDrawBackground = true - it.backgroundColor = -0x7f000001 and rh.gc(R.color.iob) //50% - it.color = rh.gc(R.color.iob) - it.thickness = 3 - } - absIobSeries = FixedLineGraphSeries(Array(absIobArray.size) { i -> absIobArray[i] }).also { - it.isDrawBackground = true - it.backgroundColor = -0x7f000001 and rh.gc(R.color.iob) //50% - it.color = rh.gc(R.color.iob) - it.thickness = 3 - } - - if (overviewMenus.setting[0][OverviewMenus.CharType.PRE.ordinal]) { - val autosensData = adsData.getLastAutosensData("GraphData", aapsLogger, dateUtil) - val lastAutosensResult = autosensData?.autosensResult ?: AutosensResult() - val isTempTarget = repository.getTemporaryTargetActiveAt(dateUtil.now()).blockingGet() is ValueWrapper.Existing - val iobPrediction: MutableList = java.util.ArrayList() - val iobPredictionArray = iobCobCalculator.calculateIobArrayForSMB(lastAutosensResult, SMBDefaults.exercise_mode, SMBDefaults.half_basal_exercise_target, isTempTarget) - for (i in iobPredictionArray) { - iobPrediction.add(i.setColor(rh.gc(R.color.iobPredAS))) - maxIobValueFound = max(maxIobValueFound, abs(i.iob)) - } - iobPredictions1Series = PointsWithLabelGraphSeries(Array(iobPrediction.size) { i -> iobPrediction[i] }) - aapsLogger.debug(LTag.AUTOSENS, "IOB prediction for AS=" + DecimalFormatter.to2Decimal(lastAutosensResult.ratio) + ": " + iobCobCalculator.iobArrayToString(iobPredictionArray)) - /* - val iobPrediction2: MutableList = java.util.ArrayList() - val iobPredictionArray2 = iobCobCalculator.calculateIobArrayForSMB(AutosensResult(), SMBDefaults.exercise_mode, SMBDefaults.half_basal_exercise_target, isTempTarget) - for (i in iobPredictionArray2) { - iobPrediction2.add(i.setColor(rh.gc(R.color.iobPred))) - maxIobValueFound = max(maxIobValueFound, abs(i.iob)) - } - iobPredictions2Series = PointsWithLabelGraphSeries(Array(iobPrediction2.size) { i -> iobPrediction2[i] }) - aapsLogger.debug(LTag.AUTOSENS, "IOB prediction for AS=" + DecimalFormatter.to2Decimal(1.0) + ": " + iobCobCalculator.iobArrayToString(iobPredictionArray2)) - */ - } else { - iobPredictions1Series = PointsWithLabelGraphSeries() - //iobPredictions2Series = PointsWithLabelGraphSeries() - } - - // COB - cobSeries = FixedLineGraphSeries(Array(cobArray.size) { i -> cobArray[i] }).also { - it.isDrawBackground = true - it.backgroundColor = -0x7f000001 and rh.gc(R.color.cob) //50% - it.color = rh.gc(R.color.cob) - it.thickness = 3 - } - cobMinFailOverSeries = PointsWithLabelGraphSeries(Array(minFailOverActiveList.size) { i -> minFailOverActiveList[i] }) - - // ACTIVITY - activitySeries = FixedLineGraphSeries(Array(actArrayHist.size) { i -> actArrayHist[i] }).also { - it.isDrawBackground = false - it.color = rh.gc(R.color.activity) - it.thickness = 3 - } - activityPredictionSeries = FixedLineGraphSeries(Array(actArrayPrediction.size) { i -> actArrayPrediction[i] }).also { - it.setCustomPaint(Paint().also { paint -> - paint.style = Paint.Style.STROKE - paint.strokeWidth = 3f - paint.pathEffect = DashPathEffect(floatArrayOf(4f, 4f), 0f) - paint.color = rh.gc(R.color.activity) - }) - } - - // BGI - minusBgiSeries = FixedLineGraphSeries(Array(bgiArrayHist.size) { i -> bgiArrayHist[i] }).also { - it.isDrawBackground = false - it.color = rh.gc(R.color.bgi) - it.thickness = 3 - } - minusBgiHistSeries = FixedLineGraphSeries(Array(bgiArrayPrediction.size) { i -> bgiArrayPrediction[i] }).also { - it.setCustomPaint(Paint().also { paint -> - paint.style = Paint.Style.STROKE - paint.strokeWidth = 3f - paint.pathEffect = DashPathEffect(floatArrayOf(4f, 4f), 0f) - paint.color = rh.gc(R.color.bgi) - }) - } - - // DEVIATIONS - deviationsSeries = BarGraphSeries(Array(devArray.size) { i -> devArray[i] }).also { - it.setValueDependentColor { data: OverviewPlugin.DeviationDataPoint -> data.color } - } - - // RATIO - ratioSeries = LineGraphSeries(Array(ratioArray.size) { i -> ratioArray[i] }).also { - it.color = rh.gc(R.color.ratio) - it.thickness = 3 - } - - // DEV SLOPE - dsMaxSeries = LineGraphSeries(Array(dsMaxArray.size) { i -> dsMaxArray[i] }).also { - it.color = rh.gc(R.color.devslopepos) - it.thickness = 3 - } - dsMinSeries = LineGraphSeries(Array(dsMinArray.size) { i -> dsMinArray[i] }).also { - it.color = rh.gc(R.color.devslopeneg) - it.thickness = 3 - } - -// profiler.log(LTag.UI, "prepareIobAutosensData() $from", start) - } - - private fun addUpperChartMargin(maxBgValue: Double) = - if (profileFunction.getUnits() == GlucoseUnit.MGDL) Round.roundTo(maxBgValue, 40.0) + 80 else Round.roundTo(maxBgValue, 2.0) + 4 - - private fun getNearestBg(date: Long): Double { - bgReadingsArray.let { bgReadingsArray -> - for (reading in bgReadingsArray) { - if (reading.timestamp > date) continue - return Profile.fromMgdlToUnits(reading.value, profileFunction.getUnits()) - } - return if (bgReadingsArray.isNotEmpty()) Profile.fromMgdlToUnits(bgReadingsArray[0].value, profileFunction.getUnits()) - else Profile.fromMgdlToUnits(100.0, profileFunction.getUnits()) - } - } - - private fun List.filterTimeframe(fromTime: Long, endTime: Long): List = - filter { it.x + it.duration >= fromTime && it.x <= endTime } - } 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 c14de709e8..508caefd0d 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 @@ -36,13 +36,9 @@ import info.nightscout.androidaps.database.entities.UserEntry.Sources import info.nightscout.androidaps.database.interfaces.end import info.nightscout.androidaps.databinding.OverviewFragmentBinding import info.nightscout.androidaps.dialogs.* -import info.nightscout.androidaps.events.EventAcceptOpenLoopChange -import info.nightscout.androidaps.events.EventInitializationChanged -import info.nightscout.androidaps.events.EventPreferenceChange -import info.nightscout.androidaps.events.EventPumpStatusChanged -import info.nightscout.androidaps.events.EventRefreshOverview +import info.nightscout.androidaps.events.* import info.nightscout.androidaps.extensions.directionToIcon -import info.nightscout.androidaps.extensions.isInProgress +import info.nightscout.androidaps.extensions.runOnUiThread import info.nightscout.androidaps.extensions.toVisibility import info.nightscout.androidaps.extensions.valueToUnitsString import info.nightscout.androidaps.interfaces.* @@ -188,10 +184,6 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList overviewData.rangeToDisplay += 6 overviewData.rangeToDisplay = if (overviewData.rangeToDisplay > 24) 6 else overviewData.rangeToDisplay sp.putInt(R.string.key_rangetodisplay, overviewData.rangeToDisplay) - overviewData.initRange() - overviewData.prepareBucketedData("EventBucketedDataCreated") - overviewData.prepareBgData("EventBucketedDataCreated") - updateGraph("rangeChange") rxBus.send(EventPreferenceChange(rh, R.string.key_rangetodisplay)) sp.putBoolean(R.string.key_objectiveusescale, true) false @@ -227,113 +219,106 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList @Synchronized override fun onResume() { super.onResume() - disposable += activePlugin.activeOverview.overviewBus - .toObservable(EventUpdateOverviewTime::class.java) - .debounce(1L, TimeUnit.SECONDS) - .observeOn(aapsSchedulers.main) - .subscribe({ updateTime(it.from) }, fabricPrivacy::logException) disposable += activePlugin.activeOverview.overviewBus .toObservable(EventUpdateOverviewCalcProgress::class.java) .observeOn(aapsSchedulers.main) - .subscribe({ updateCalcProgress(it.from) }, fabricPrivacy::logException) - disposable += activePlugin.activeOverview.overviewBus - .toObservable(EventUpdateOverviewProfile::class.java) - .debounce(1L, TimeUnit.SECONDS) - .observeOn(aapsSchedulers.main) - .subscribe({ updateProfile(it.from) }, fabricPrivacy::logException) - disposable += activePlugin.activeOverview.overviewBus - .toObservable(EventUpdateOverviewTemporaryBasal::class.java) - .debounce(1L, TimeUnit.SECONDS) - .observeOn(aapsSchedulers.main) - .subscribe({ updateTemporaryBasal(it.from) }, fabricPrivacy::logException) - disposable += activePlugin.activeOverview.overviewBus - .toObservable(EventUpdateOverviewExtendedBolus::class.java) - .debounce(1L, TimeUnit.SECONDS) - .observeOn(aapsSchedulers.main) - .subscribe({ updateExtendedBolus(it.from) }, fabricPrivacy::logException) - disposable += activePlugin.activeOverview.overviewBus - .toObservable(EventUpdateOverviewTemporaryTarget::class.java) - .debounce(1L, TimeUnit.SECONDS) - .observeOn(aapsSchedulers.main) - .subscribe({ updateTemporaryTarget(it.from) }, fabricPrivacy::logException) - disposable += activePlugin.activeOverview.overviewBus - .toObservable(EventUpdateOverviewBg::class.java) - .debounce(1L, TimeUnit.SECONDS) - .observeOn(aapsSchedulers.main) - .subscribe({ updateBg(it.from) }, fabricPrivacy::logException) + .subscribe({ updateCalcProgress() }, fabricPrivacy::logException) disposable += activePlugin.activeOverview.overviewBus .toObservable(EventUpdateOverviewIobCob::class.java) .debounce(1L, TimeUnit.SECONDS) .observeOn(aapsSchedulers.main) - .subscribe({ updateIobCob(it.from) }, fabricPrivacy::logException) + .subscribe({ updateIobCob() }, fabricPrivacy::logException) disposable += activePlugin.activeOverview.overviewBus .toObservable(EventUpdateOverviewSensitivity::class.java) .debounce(1L, TimeUnit.SECONDS) .observeOn(aapsSchedulers.main) - .subscribe({ updateSensitivity(it.from) }, fabricPrivacy::logException) + .subscribe({ updateSensitivity() }, fabricPrivacy::logException) disposable += activePlugin.activeOverview.overviewBus .toObservable(EventUpdateOverviewGraph::class.java) .debounce(1L, TimeUnit.SECONDS) .observeOn(aapsSchedulers.main) - .subscribe({ updateGraph(it.from) }, fabricPrivacy::logException) + .subscribe({ updateGraph() }, fabricPrivacy::logException) disposable += activePlugin.activeOverview.overviewBus .toObservable(EventUpdateOverviewPumpStatus::class.java) .observeOn(aapsSchedulers.main) - .subscribe({ updatePumpStatus(it.from) }, fabricPrivacy::logException) + .subscribe({ updatePumpStatus() }, fabricPrivacy::logException) disposable += activePlugin.activeOverview.overviewBus .toObservable(EventUpdateOverviewNotification::class.java) .observeOn(aapsSchedulers.main) - .subscribe({ updateNotification(it.from) }, fabricPrivacy::logException) + .subscribe({ updateNotification() }, fabricPrivacy::logException) + disposable += rxBus + .toObservable(EventNewBG::class.java) + .debounce(1L, TimeUnit.SECONDS) + .observeOn(aapsSchedulers.main) + .subscribe({ updateBg() }, fabricPrivacy::logException) disposable += rxBus .toObservable(EventRefreshOverview::class.java) .observeOn(aapsSchedulers.io) .subscribe({ - if (it.now) overviewPlugin.refreshLoop(it.from) - else scheduleUpdateGUI(it.from) + if (it.now) refreshAll() + else scheduleUpdateGUI() }, fabricPrivacy::logException) disposable += rxBus .toObservable(EventAcceptOpenLoopChange::class.java) .observeOn(aapsSchedulers.io) - .subscribe({ scheduleUpdateGUI("EventAcceptOpenLoopChange") }, fabricPrivacy::logException) - disposable += rxBus - .toObservable(EventInitializationChanged::class.java) - .observeOn(aapsSchedulers.main) - .subscribe({ updateTime("EventInitializationChanged") }, fabricPrivacy::logException) + .subscribe({ scheduleUpdateGUI() }, fabricPrivacy::logException) disposable += rxBus .toObservable(EventPreferenceChange::class.java) .observeOn(aapsSchedulers.io) - .subscribe({ scheduleUpdateGUI("EventPreferenceChange") }, fabricPrivacy::logException) + .subscribe({ scheduleUpdateGUI() }, fabricPrivacy::logException) disposable += rxBus .toObservable(EventNewOpenLoopNotification::class.java) .observeOn(aapsSchedulers.io) - .subscribe({ scheduleUpdateGUI("EventNewOpenLoopNotification") }, fabricPrivacy::logException) + .subscribe({ scheduleUpdateGUI() }, fabricPrivacy::logException) disposable += rxBus .toObservable(EventPumpStatusChanged::class.java) .observeOn(aapsSchedulers.main) .delay(30, TimeUnit.MILLISECONDS, aapsSchedulers.main) .subscribe({ overviewData.pumpStatus = it.getStatus(rh) - updatePumpStatus("EventPumpStatusChanged") + updatePumpStatus() }, fabricPrivacy::logException) + disposable += rxBus + .toObservable(EventEffectiveProfileSwitchChanged::class.java) + .observeOn(aapsSchedulers.main) + .subscribe({ updateProfile() }, fabricPrivacy::logException) + disposable += rxBus + .toObservable(EventTempTargetChange::class.java) + .observeOn(aapsSchedulers.main) + .subscribe({ updateTemporaryTarget() }, fabricPrivacy::logException) + disposable += rxBus + .toObservable(EventExtendedBolusChange::class.java) + .observeOn(aapsSchedulers.main) + .subscribe({ updateExtendedBolus() }, fabricPrivacy::logException) + disposable += rxBus + .toObservable(EventTempBasalChange::class.java) + .observeOn(aapsSchedulers.main) + .subscribe({ updateTemporaryBasal() }, fabricPrivacy::logException) refreshLoop = Runnable { - overviewPlugin.refreshLoop("refreshLoop") + refreshAll() handler.postDelayed(refreshLoop, 60 * 1000L) } handler.postDelayed(refreshLoop, 60 * 1000L) - updateTime("onResume") - updateCalcProgress("onResume") - updateProfile("onResume") - updateTemporaryBasal("onResume") - updateExtendedBolus("onResume") - updateTemporaryTarget("onResume") - updateBg("onResume") - updateIobCob("onResume") - updateSensitivity("onResume") - updateGraph("onResume") - updatePumpStatus("onResume") - updateNotification("onResume") + refreshAll() + updatePumpStatus() + updateCalcProgress() + } + + fun refreshAll() { + runOnUiThread { + updateBg() + updateTime() + updateProfile() + updateTemporaryBasal() + updateExtendedBolus() + updateTemporaryTarget() + updateIobCob() + updateSensitivity() + updateGraph() + updateNotification() + } } @Synchronized @@ -563,14 +548,14 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList binding.buttonsLayout.cgmButton.setCompoundDrawablesWithIntrinsicBounds(null, rh.gd(R.drawable.ic_byoda), null, null) for (drawable in binding.buttonsLayout.cgmButton.compoundDrawables) { drawable?.mutate() - drawable?.colorFilter = PorterDuffColorFilter(rh.gac( context,R.attr.cgmdexColor ), PorterDuff.Mode.SRC_IN) + drawable?.colorFilter = PorterDuffColorFilter(rh.gac(context, R.attr.cgmdexColor), PorterDuff.Mode.SRC_IN) } binding.buttonsLayout.cgmButton.setTextColor(rh.gac(context, R.attr.cgmdexColor)) } else if (xDripIsBgSource) { binding.buttonsLayout.cgmButton.setCompoundDrawablesWithIntrinsicBounds(null, rh.gd(R.drawable.ic_xdrip), null, null) for (drawable in binding.buttonsLayout.cgmButton.compoundDrawables) { drawable?.mutate() - drawable?.colorFilter = PorterDuffColorFilter(rh.gac( context,R.attr.cgmxdripColor ), PorterDuff.Mode.SRC_IN) + drawable?.colorFilter = PorterDuffColorFilter(rh.gac(context, R.attr.cgmxdripColor), PorterDuff.Mode.SRC_IN) } binding.buttonsLayout.cgmButton.setTextColor(rh.gac(context, R.attr.cgmxdripColor)) } @@ -752,11 +737,11 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList var task: Runnable? = null - private fun scheduleUpdateGUI(from: String) { + private fun scheduleUpdateGUI() { class UpdateRunnable : Runnable { override fun run() { - overviewPlugin.refreshLoop(from) + refreshAll() task = null } } @@ -766,8 +751,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList } @SuppressLint("SetTextI18n") - @Suppress("UNUSED_PARAMETER") - fun updateBg(from: String) { + fun updateBg() { val units = profileFunction.getUnits() binding.infoLayout.bg.text = overviewData.lastBg?.valueToUnitsString(units) ?: rh.gs(R.string.notavailable) @@ -816,8 +800,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList } } - @Suppress("UNUSED_PARAMETER") - fun updateProfile(from: String) { + fun updateProfile() { val profileBackgroundColor = profileFunction.getProfile()?.let { if (it is ProfileSealed.EPS) { @@ -849,28 +832,25 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList binding.activeProfile.setTextColor(profileTextColor) } - @Suppress("UNUSED_PARAMETER") - fun updateTemporaryBasal(from: String) { - binding.infoLayout.baseBasal.text = overviewData.temporaryBasalText - binding.infoLayout.baseBasal.setTextColor(overviewData.temporaryBasalColor) - binding.infoLayout.baseBasalIcon.setImageResource(overviewData.temporaryBasalIcon) + private fun updateTemporaryBasal() { + binding.infoLayout.baseBasal.text = overviewData.temporaryBasalText(iobCobCalculator) + binding.infoLayout.baseBasal.setTextColor(overviewData.temporaryBasalColor(context, iobCobCalculator)) + binding.infoLayout.baseBasalIcon.setImageResource(overviewData.temporaryBasalIcon(iobCobCalculator)) binding.infoLayout.basalLayout.setOnClickListener { - activity?.let { OKDialog.show(it, rh.gs(R.string.basal), overviewData.temporaryBasalDialogText) } + activity?.let { OKDialog.show(it, rh.gs(R.string.basal), overviewData.temporaryBasalDialogText(iobCobCalculator)) } } } - @Suppress("UNUSED_PARAMETER") - fun updateExtendedBolus(from: String) { + private fun updateExtendedBolus() { val pump = activePlugin.activePump - binding.infoLayout.extendedBolus.text = overviewData.extendedBolusText + binding.infoLayout.extendedBolus.text = overviewData.extendedBolusText(iobCobCalculator) binding.infoLayout.extendedLayout.setOnClickListener { - activity?.let { OKDialog.show(it, rh.gs(R.string.extended_bolus), overviewData.extendedBolusDialogText) } + activity?.let { OKDialog.show(it, rh.gs(R.string.extended_bolus), overviewData.extendedBolusDialogText(iobCobCalculator)) } } binding.infoLayout.extendedLayout.visibility = (iobCobCalculator.getExtendedBolus(dateUtil.now()) != null && !pump.isFakingTempsByExtendedBoluses).toVisibility() } - @Suppress("UNUSED_PARAMETER") - fun updateTime(from: String) { + fun updateTime() { binding.infoLayout.time.text = dateUtil.timeString(dateUtil.now()) // Status lights val pump = activePlugin.activePump @@ -901,14 +881,13 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList processAps() } - @Suppress("UNUSED_PARAMETER") - fun updateIobCob(from: String) { - binding.infoLayout.iob.text = overviewData.iobText + fun updateIobCob() { + binding.infoLayout.iob.text = overviewData.iobText(iobCobCalculator) binding.infoLayout.iobLayout.setOnClickListener { - activity?.let { OKDialog.show(it, rh.gs(R.string.iob), overviewData.iobDialogText) } + activity?.let { OKDialog.show(it, rh.gs(R.string.iob), overviewData.iobDialogText(iobCobCalculator)) } } // cob - var cobText = overviewData.cobInfo?.displayText(rh, dateUtil, buildHelper.isEngineeringMode()) ?: rh.gs(R.string.value_unavailable_short) + var cobText = overviewData.cobInfo(iobCobCalculator).displayText(rh, dateUtil, buildHelper.isEngineeringMode()) ?: rh.gs(R.string.value_unavailable_short) val constraintsProcessed = loop.lastRun?.constraintsProcessed val lastRun = loop.lastRun @@ -929,10 +908,8 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList } @SuppressLint("SetTextI18n") - @Suppress("UNUSED_PARAMETER") - fun updateTemporaryTarget(from: String) { + fun updateTemporaryTarget() { val units = profileFunction.getUnits() - if (overviewData.temporaryTarget?.isInProgress(dateUtil) == false) overviewData.temporaryTarget = null val tempTarget = overviewData.temporaryTarget if (tempTarget != null) { binding.tempTarget.setTextColor(rh.gac(context, R.attr.ribbonTextWarningColor)) @@ -957,8 +934,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList } } - @Suppress("UNUSED_PARAMETER") - fun updateGraph(from: String) { + private fun updateGraph() { val pump = activePlugin.activePump val graphData = GraphData(injector, binding.graphsLayout.bgGraph, overviewData) val menuChartSettings = overviewMenus.setting @@ -1036,14 +1012,12 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList } } - @Suppress("UNUSED_PARAMETER") - fun updateCalcProgress(from: String) { + private fun updateCalcProgress() { binding.progressBar.progress = overviewData.calcProgressPct binding.progressBar.visibility = (overviewData.calcProgressPct != 100).toVisibility() } - @Suppress("UNUSED_PARAMETER") - fun updateSensitivity(from: String) { + private fun updateSensitivity() { if (sp.getBoolean(R.string.key_openapsama_useautosens, false) && constraintChecker.isAutosensModeEnabled().value()) { binding.infoLayout.sensitivityIcon.setImageResource(R.drawable.ic_swap_vert_black_48dp_green) } else { @@ -1051,20 +1025,18 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList } binding.infoLayout.sensitivity.text = - overviewData.lastAutosensData?.let { autosensData -> + overviewData.lastAutosensData(iobCobCalculator)?.let { autosensData -> String.format(Locale.ENGLISH, "%.0f%%", autosensData.autosensResult.ratio * 100) } ?: "" } - @Suppress("UNUSED_PARAMETER") - fun updatePumpStatus(from: String) { + private fun updatePumpStatus() { val status = overviewData.pumpStatus binding.pumpStatus.text = status binding.pumpStatusLayout.visibility = (status != "").toVisibility() } - @Suppress("UNUSED_PARAMETER") - fun updateNotification(from: String) { + private fun updateNotification() { binding.notifications.let { notificationStore.updateNotifications(it) } } } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/OverviewPlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/OverviewPlugin.kt index 3823bb5147..86469e8434 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/OverviewPlugin.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/OverviewPlugin.kt @@ -4,25 +4,26 @@ import androidx.preference.PreferenceFragmentCompat import androidx.preference.SwitchPreference import dagger.android.HasAndroidInjector import info.nightscout.androidaps.R -import info.nightscout.androidaps.database.AppRepository -import info.nightscout.androidaps.database.ValueWrapper -import info.nightscout.androidaps.events.* +import info.nightscout.androidaps.events.EventPumpStatusChanged import info.nightscout.androidaps.extensions.* -import info.nightscout.androidaps.interfaces.* -import info.nightscout.shared.logging.AAPSLogger -import info.nightscout.shared.logging.LTag -import info.nightscout.androidaps.plugins.aps.events.EventLoopInvoked +import info.nightscout.androidaps.interfaces.Config +import info.nightscout.androidaps.interfaces.Overview +import info.nightscout.androidaps.interfaces.PluginBase +import info.nightscout.androidaps.interfaces.PluginDescription +import info.nightscout.androidaps.interfaces.PluginType import info.nightscout.androidaps.plugins.bus.RxBus -import info.nightscout.androidaps.plugins.general.overview.events.* +import info.nightscout.androidaps.plugins.general.overview.events.EventDismissNotification +import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification +import info.nightscout.androidaps.plugins.general.overview.events.EventUpdateOverviewCalcProgress +import info.nightscout.androidaps.plugins.general.overview.events.EventUpdateOverviewNotification import info.nightscout.androidaps.plugins.general.overview.graphExtensions.Scale import info.nightscout.androidaps.plugins.general.overview.graphExtensions.ScaledDataPoint import info.nightscout.androidaps.plugins.general.overview.notifications.NotificationStore -import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventBucketedDataCreated import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventIobCalculationProgress -import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.FabricPrivacy import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.rx.AapsSchedulers +import info.nightscout.shared.logging.AAPSLogger import info.nightscout.shared.sharedPreferences.SP import io.reactivex.rxjava3.disposables.CompositeDisposable import io.reactivex.rxjava3.kotlin.plusAssign @@ -41,9 +42,6 @@ class OverviewPlugin @Inject constructor( private val aapsSchedulers: AapsSchedulers, rh: ResourceHelper, private val config: Config, - private val dateUtil: DateUtil, - private val iobCobCalculator: IobCobCalculator, - private val repository: AppRepository, private val overviewData: OverviewData, private val overviewMenus: OverviewMenus ) : PluginBase( @@ -89,62 +87,9 @@ class OverviewPlugin @Inject constructor( disposable += rxBus .toObservable(EventIobCalculationProgress::class.java) .observeOn(aapsSchedulers.io) - .subscribe({ overviewData.calcProgressPct = it.progressPct; overviewBus.send(EventUpdateOverviewCalcProgress("EventIobCalculationProgress")) }, fabricPrivacy::logException) - disposable += rxBus - .toObservable(EventTempBasalChange::class.java) - .observeOn(aapsSchedulers.io) - .subscribe({ overviewBus.send(EventUpdateOverviewTemporaryBasal("EventTempBasalChange")) }, fabricPrivacy::logException) - disposable += rxBus - .toObservable(EventExtendedBolusChange::class.java) - .observeOn(aapsSchedulers.io) - .subscribe({ overviewBus.send(EventUpdateOverviewExtendedBolus("EventExtendedBolusChange")) }, fabricPrivacy::logException) - disposable += rxBus - .toObservable(EventNewBG::class.java) - .observeOn(aapsSchedulers.io) - .subscribe({ loadBg("EventNewBG") }, fabricPrivacy::logException) - disposable += rxBus - .toObservable(EventTempTargetChange::class.java) - .observeOn(aapsSchedulers.io) - .subscribe({ loadTemporaryTarget("EventTempTargetChange") }, fabricPrivacy::logException) - disposable += rxBus - .toObservable(EventTreatmentChange::class.java) - .observeOn(aapsSchedulers.io) .subscribe({ - loadIobCobResults("EventTreatmentChange") - overviewData.prepareTreatmentsData("EventTreatmentChange") - overviewBus.send(EventUpdateOverviewGraph("EventTreatmentChange")) - }, fabricPrivacy::logException) - disposable += rxBus - .toObservable(EventTherapyEventChange::class.java) - .observeOn(aapsSchedulers.io) - .subscribe({ - overviewData.prepareTreatmentsData("EventTherapyEventChange") - overviewBus.send(EventUpdateOverviewGraph("EventTherapyEventChange")) - }, fabricPrivacy::logException) - disposable += rxBus - .toObservable(EventBucketedDataCreated::class.java) - .observeOn(aapsSchedulers.io) - .subscribe({ - overviewData.prepareBucketedData("EventBucketedDataCreated") - overviewData.prepareBgData("EventBucketedDataCreated") - overviewBus.send(EventUpdateOverviewGraph("EventBucketedDataCreated")) - }, fabricPrivacy::logException) - disposable += rxBus - .toObservable(EventLoopInvoked::class.java) - .observeOn(aapsSchedulers.io) - .subscribe({ overviewData.preparePredictions("EventLoopInvoked") }, fabricPrivacy::logException) - disposable += rxBus - .toObservable(EventEffectiveProfileSwitchChanged::class.java) - .observeOn(aapsSchedulers.io) - .subscribe({ - loadProfile("EventEffectiveProfileSwitchChanged") - overviewData.prepareBasalData("EventEffectiveProfileSwitchChanged") - }, fabricPrivacy::logException) - disposable += rxBus - .toObservable(EventAutosensCalculationFinished::class.java) - .observeOn(aapsSchedulers.io) - .subscribe({ - if (it.cause !is EventCustomCalculationFinished) refreshLoop("EventAutosensCalculationFinished") + overviewData.calcProgressPct = it.pass.finalPercent(it.progressPct) + overviewBus.send(EventUpdateOverviewCalcProgress("EventIobCalculationProgress")) }, fabricPrivacy::logException) disposable += rxBus .toObservable(EventPumpStatusChanged::class.java) @@ -152,20 +97,7 @@ class OverviewPlugin @Inject constructor( .subscribe({ overviewData.pumpStatus = it.getStatus(rh) }, fabricPrivacy::logException) - disposable += rxBus - .toObservable(EventPreferenceChange::class.java) - .observeOn(aapsSchedulers.io) - .subscribe({ event -> - if (event.isChanged(rh, R.string.key_units)) { - overviewData.reset() - overviewData.prepareBucketedData("EventBucketedDataCreated") - overviewData.prepareBgData("EventBucketedDataCreated") - overviewBus.send(EventUpdateOverviewGraph("EventBucketedDataCreated")) - loadAll("EventPreferenceChange") - } - }, fabricPrivacy::logException) - Thread { loadAll("onResume") }.start() } override fun onStop() { @@ -243,7 +175,7 @@ class OverviewPlugin @Inject constructor( .storeDouble(R.string.key_statuslights_bat_critical, sp, rh) .storeInt(R.string.key_boluswizard_percentage, sp, rh) } - +/* @Volatile var runningRefresh = false override fun refreshLoop(from: String) { @@ -284,38 +216,5 @@ class OverviewPlugin @Inject constructor( overviewBus.send(EventUpdateOverviewGraph(from)) aapsLogger.debug(LTag.UI, "loadAll finished") } - - private fun loadProfile(from: String) { - overviewBus.send(EventUpdateOverviewProfile(from)) - } - - private fun loadTemporaryTarget(from: String) { - val tempTarget = repository.getTemporaryTargetActiveAt(dateUtil.now()).blockingGet() - if (tempTarget is ValueWrapper.Existing) overviewData.temporaryTarget = tempTarget.value - else overviewData.temporaryTarget = null - overviewBus.send(EventUpdateOverviewTemporaryTarget(from)) - } - - private fun loadAsData(from: String) { - overviewData.lastAutosensData = iobCobCalculator.ads.getLastAutosensData("Overview", aapsLogger, dateUtil) - overviewBus.send(EventUpdateOverviewSensitivity(from)) - } - - private fun loadBg(from: String) { - val gvWrapped = repository.getLastGlucoseValueWrapped().blockingGet() - if (gvWrapped is ValueWrapper.Existing) overviewData.lastBg = gvWrapped.value - else overviewData.lastBg = null - overviewBus.send(EventUpdateOverviewBg(from)) - } - - private fun loadIobCobResults(from: String) { - overviewData.bolusIob = iobCobCalculator.calculateIobFromBolus().round() - overviewData.basalIob = iobCobCalculator.calculateIobFromTempBasalsIncludingConvertedExtended().round() - overviewData.cobInfo = iobCobCalculator.getCobInfo(true, "Overview COB") - val lastCarbs = repository.getLastCarbsRecordWrapped().blockingGet() - overviewData.lastCarbsTime = if (lastCarbs is ValueWrapper.Existing) lastCarbs.value.timestamp else 0L - - overviewBus.send(EventUpdateOverviewIobCob(from)) - } - +*/ } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/events/EventUpdateOverviewBg.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/events/EventUpdateOverviewBg.kt deleted file mode 100644 index 2bbfb7813c..0000000000 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/events/EventUpdateOverviewBg.kt +++ /dev/null @@ -1,5 +0,0 @@ -package info.nightscout.androidaps.plugins.general.overview.events - -import info.nightscout.androidaps.events.Event - -class EventUpdateOverviewBg(val from: String) : Event() \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/events/EventUpdateOverviewExtendedBolus.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/events/EventUpdateOverviewExtendedBolus.kt deleted file mode 100644 index 51b493acf4..0000000000 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/events/EventUpdateOverviewExtendedBolus.kt +++ /dev/null @@ -1,5 +0,0 @@ -package info.nightscout.androidaps.plugins.general.overview.events - -import info.nightscout.androidaps.events.Event - -class EventUpdateOverviewExtendedBolus(val from: String) : Event() \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/events/EventUpdateOverviewProfile.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/events/EventUpdateOverviewProfile.kt deleted file mode 100644 index 6e4bb95490..0000000000 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/events/EventUpdateOverviewProfile.kt +++ /dev/null @@ -1,5 +0,0 @@ -package info.nightscout.androidaps.plugins.general.overview.events - -import info.nightscout.androidaps.events.Event - -class EventUpdateOverviewProfile(val from: String) : Event() \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/events/EventUpdateOverviewTemporaryBasal.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/events/EventUpdateOverviewTemporaryBasal.kt deleted file mode 100644 index 315bf8d651..0000000000 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/events/EventUpdateOverviewTemporaryBasal.kt +++ /dev/null @@ -1,5 +0,0 @@ -package info.nightscout.androidaps.plugins.general.overview.events - -import info.nightscout.androidaps.events.Event - -class EventUpdateOverviewTemporaryBasal(val from: String) : Event() \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/events/EventUpdateOverviewTemporaryTarget.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/events/EventUpdateOverviewTemporaryTarget.kt deleted file mode 100644 index 83cafcd664..0000000000 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/events/EventUpdateOverviewTemporaryTarget.kt +++ /dev/null @@ -1,5 +0,0 @@ -package info.nightscout.androidaps.plugins.general.overview.events - -import info.nightscout.androidaps.events.Event - -class EventUpdateOverviewTemporaryTarget(val from: String) : Event() \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/events/EventUpdateOverviewTime.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/events/EventUpdateOverviewTime.kt deleted file mode 100644 index 5da5b72136..0000000000 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/events/EventUpdateOverviewTime.kt +++ /dev/null @@ -1,5 +0,0 @@ -package info.nightscout.androidaps.plugins.general.overview.events - -import info.nightscout.androidaps.events.Event - -class EventUpdateOverviewTime(val from: String) : Event() \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/persistentNotification/PersistentNotificationPlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/persistentNotification/PersistentNotificationPlugin.kt index 3bd76dab56..17afcbebd0 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/persistentNotification/PersistentNotificationPlugin.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/persistentNotification/PersistentNotificationPlugin.kt @@ -9,17 +9,20 @@ import androidx.core.app.RemoteInput import dagger.android.HasAndroidInjector import info.nightscout.androidaps.Constants import info.nightscout.androidaps.R -import info.nightscout.androidaps.events.* +import info.nightscout.androidaps.events.EventAutosensCalculationFinished +import info.nightscout.androidaps.events.EventInitializationChanged +import info.nightscout.androidaps.events.EventPreferenceChange +import info.nightscout.androidaps.events.EventRefreshOverview import info.nightscout.androidaps.extensions.toStringShort import info.nightscout.androidaps.extensions.valueToUnitsString import info.nightscout.androidaps.interfaces.* -import info.nightscout.shared.logging.AAPSLogger import info.nightscout.androidaps.plugins.bus.RxBus import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatusProvider import info.nightscout.androidaps.utils.DecimalFormatter import info.nightscout.androidaps.utils.FabricPrivacy import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.rx.AapsSchedulers +import info.nightscout.shared.logging.AAPSLogger import io.reactivex.rxjava3.disposables.CompositeDisposable import io.reactivex.rxjava3.kotlin.plusAssign import javax.inject.Inject @@ -72,26 +75,10 @@ class PersistentNotificationPlugin @Inject constructor( .toObservable(EventRefreshOverview::class.java) .observeOn(aapsSchedulers.io) .subscribe({ triggerNotificationUpdate() }, fabricPrivacy::logException) - disposable += rxBus - .toObservable(EventExtendedBolusChange::class.java) - .observeOn(aapsSchedulers.io) - .subscribe({ triggerNotificationUpdate() }, fabricPrivacy::logException) - disposable += rxBus - .toObservable(EventTempBasalChange::class.java) - .observeOn(aapsSchedulers.io) - .subscribe({ triggerNotificationUpdate() }, fabricPrivacy::logException) - disposable += rxBus - .toObservable(EventTreatmentChange::class.java) - .observeOn(aapsSchedulers.io) - .subscribe({ triggerNotificationUpdate() }, fabricPrivacy::logException) disposable += rxBus .toObservable(EventInitializationChanged::class.java) .observeOn(aapsSchedulers.io) .subscribe({ triggerNotificationUpdate() }, fabricPrivacy::logException) - disposable += rxBus - .toObservable(EventEffectiveProfileSwitchChanged::class.java) - .observeOn(aapsSchedulers.io) - .subscribe({ triggerNotificationUpdate() }, fabricPrivacy::logException) disposable += rxBus .toObservable(EventAutosensCalculationFinished::class.java) .observeOn(aapsSchedulers.io) diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/IobCobCalculatorPlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/IobCobCalculatorPlugin.kt index 46f0323149..cf38b3e857 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/IobCobCalculatorPlugin.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/IobCobCalculatorPlugin.kt @@ -1,12 +1,6 @@ package info.nightscout.androidaps.plugins.iob.iobCobCalculator -import android.content.Context -import android.os.SystemClock import androidx.collection.LongSparseArray -import androidx.work.ExistingWorkPolicy -import androidx.work.OneTimeWorkRequest -import androidx.work.WorkInfo -import androidx.work.WorkManager import dagger.android.HasAndroidInjector import info.nightscout.androidaps.Constants import info.nightscout.androidaps.R @@ -24,21 +18,19 @@ import info.nightscout.androidaps.extensions.convertedToAbsolute import info.nightscout.androidaps.extensions.iobCalc import info.nightscout.androidaps.extensions.toTemporaryBasal import info.nightscout.androidaps.interfaces.* -import info.nightscout.shared.logging.AAPSLogger -import info.nightscout.shared.logging.LTag import info.nightscout.androidaps.plugins.bus.RxBus +import info.nightscout.androidaps.plugins.general.overview.OverviewData import info.nightscout.androidaps.plugins.iob.iobCobCalculator.data.AutosensData import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventNewHistoryData -import info.nightscout.androidaps.plugins.sensitivity.SensitivityAAPSPlugin -import info.nightscout.androidaps.plugins.sensitivity.SensitivityOref1Plugin -import info.nightscout.androidaps.plugins.sensitivity.SensitivityWeightedAveragePlugin -import info.nightscout.androidaps.receivers.DataWorker import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.DecimalFormatter import info.nightscout.androidaps.utils.FabricPrivacy import info.nightscout.androidaps.utils.T import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.rx.AapsSchedulers +import info.nightscout.androidaps.workflow.CalculationWorkflow +import info.nightscout.shared.logging.AAPSLogger +import info.nightscout.shared.logging.LTag import info.nightscout.shared.sharedPreferences.SP import io.reactivex.rxjava3.disposables.CompositeDisposable import io.reactivex.rxjava3.kotlin.plusAssign @@ -63,14 +55,11 @@ class IobCobCalculatorPlugin @Inject constructor( rh: ResourceHelper, private val profileFunction: ProfileFunction, private val activePlugin: ActivePlugin, - private val sensitivityOref1Plugin: SensitivityOref1Plugin, - private val sensitivityAAPSPlugin: SensitivityAAPSPlugin, - private val sensitivityWeightedAveragePlugin: SensitivityWeightedAveragePlugin, private val fabricPrivacy: FabricPrivacy, private val dateUtil: DateUtil, private val repository: AppRepository, - private val context: Context, - private val dataWorker: DataWorker + val overviewData: OverviewData, + private val calculationWorkflow: CalculationWorkflow ) : PluginBase( PluginDescription() .mainType(PluginType.GENERAL) @@ -91,8 +80,6 @@ class IobCobCalculatorPlugin @Inject constructor( private val dataLock = Any() private var thread: Thread? = null - private val jobGroupName = "calculation" - override fun onStart() { super.onStart() // EventConfigBuilderChange @@ -126,14 +113,6 @@ class IobCobCalculatorPlugin @Inject constructor( resetDataAndRunCalculation("onEventPreferenceChange", event) } }, fabricPrivacy::logException) - // EventAppInitialized - disposable += rxBus - .toObservable(EventAppInitialized::class.java) - .observeOn(aapsSchedulers.io) - .subscribe( - { event -> runCalculation("onEventAppInitialized", System.currentTimeMillis(), bgDataReload = true, limitDataToOldestAvailable = true, cause = event) }, - fabricPrivacy::logException - ) // EventNewHistoryData disposable += rxBus .toObservable(EventNewHistoryData::class.java) @@ -147,10 +126,10 @@ class IobCobCalculatorPlugin @Inject constructor( } private fun resetDataAndRunCalculation(reason: String, event: Event?) { - stopCalculation(reason) + calculationWorkflow.stopCalculation(CalculationWorkflow.MAIN_CALCULATION,reason) clearCache() ads.reset() - runCalculation(reason, System.currentTimeMillis(), bgDataReload = false, limitDataToOldestAvailable = true, cause = event) + calculationWorkflow.runCalculation(CalculationWorkflow.MAIN_CALCULATION,this, overviewData, reason, System.currentTimeMillis(), bgDataReload = false, limitDataToOldestAvailable = true, cause = event, runLoop = true) } override fun clearCache() { @@ -310,11 +289,7 @@ class IobCobCalculatorPlugin @Inject constructor( override fun getMealDataWithWaitingForCalculationFinish(): MealData { val result = MealData() val now = System.currentTimeMillis() - val maxAbsorptionHours: Double = if (sensitivityAAPSPlugin.isEnabled() || sensitivityWeightedAveragePlugin.isEnabled()) { - sp.getDouble(R.string.key_absorption_maxtime, Constants.DEFAULT_MAX_ABSORPTION_TIME) - } else { - sp.getDouble(R.string.key_absorption_cutoff, Constants.DEFAULT_MAX_ABSORPTION_TIME) - } + val maxAbsorptionHours: Double = activePlugin.activeSensitivity.maxAbsorptionHours() val absorptionTimeAgo = now - (maxAbsorptionHours * T.hours(1).msecs()).toLong() repository.getCarbsDataFromTimeToTimeExpanded(absorptionTimeAgo + 1, now, true) .blockingGet() @@ -374,34 +349,6 @@ class IobCobCalculatorPlugin @Inject constructor( return sb.toString() } - fun stopCalculation(from: String) { - aapsLogger.debug(LTag.AUTOSENS, "Stopping calculation thread: $from") - WorkManager.getInstance(context).cancelUniqueWork(jobGroupName) - val workStatus = WorkManager.getInstance(context).getWorkInfosForUniqueWork(jobGroupName).get() - while (workStatus.size >= 1 && workStatus[0].state == WorkInfo.State.RUNNING) - SystemClock.sleep(100) - aapsLogger.debug(LTag.AUTOSENS, "Calculation thread stopped: $from") - } - - fun runCalculation(from: String, end: Long, bgDataReload: Boolean, limitDataToOldestAvailable: Boolean, cause: Event?) { - aapsLogger.debug(LTag.AUTOSENS, "Starting calculation worker: $from to ${dateUtil.dateAndTimeAndSecondsString(end)}") - - val iobCalculation = - if (sensitivityOref1Plugin.isEnabled()) - OneTimeWorkRequest.Builder(IobCobOref1Worker::class.java) - .setInputData( - dataWorker.storeInputData(IobCobOref1Worker.IobCobOref1WorkerData(injector, this, from, end, bgDataReload, limitDataToOldestAvailable, cause)) - ).build() - else - OneTimeWorkRequest.Builder(IobCobOref1Worker::class.java) - .setInputData( - dataWorker.storeInputData(IobCobOrefWorker.IobCobOrefWorkerData(injector, this, from, end, bgDataReload, limitDataToOldestAvailable, cause)) - ).build() - - WorkManager.getInstance(context) - .enqueueUniqueWork(jobGroupName, ExistingWorkPolicy.REPLACE, iobCalculation) - } - // Limit rate of EventNewHistoryData private val historyWorker = Executors.newSingleThreadScheduledExecutor() private var scheduledHistoryPost: ScheduledFuture<*>? = null @@ -443,7 +390,7 @@ class IobCobCalculatorPlugin @Inject constructor( // When historical data is changed (coming from NS etc) finished calculations after this date must be invalidated private fun newHistoryData(oldDataTimestamp: Long, bgDataReload: Boolean, event: Event) { //log.debug("Locking onNewHistoryData"); - stopCalculation("onEventNewHistoryData") + calculationWorkflow.stopCalculation(CalculationWorkflow.MAIN_CALCULATION,"onEventNewHistoryData") synchronized(dataLock) { // clear up 5 min back for proper COB calculation @@ -467,7 +414,7 @@ class IobCobCalculatorPlugin @Inject constructor( } ads.newHistoryData(time, aapsLogger, dateUtil) } - runCalculation(event.javaClass.simpleName, System.currentTimeMillis(), bgDataReload, true, event) + calculationWorkflow.runCalculation(CalculationWorkflow.MAIN_CALCULATION,this, overviewData, event.javaClass.simpleName, System.currentTimeMillis(), bgDataReload, true, event, runLoop = true) //log.debug("Releasing onNewHistoryData"); } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/IobCobOref1Worker.kt b/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/IobCobOref1Worker.kt index 446f836576..69a3b58d5c 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/IobCobOref1Worker.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/IobCobOref1Worker.kt @@ -32,6 +32,7 @@ import info.nightscout.androidaps.utils.Profiler import info.nightscout.androidaps.utils.T import info.nightscout.androidaps.utils.buildHelper.BuildHelper import info.nightscout.androidaps.utils.resources.ResourceHelper +import info.nightscout.androidaps.workflow.CalculationWorkflow import info.nightscout.shared.logging.AAPSLogger import info.nightscout.shared.logging.LTag import info.nightscout.shared.sharedPreferences.SP @@ -62,6 +63,7 @@ class IobCobOref1Worker( @Inject lateinit var dateUtil: DateUtil @Inject lateinit var repository: AppRepository @Inject lateinit var dataWorker: DataWorker + @Inject lateinit var calculationWorkflow: CalculationWorkflow init { (context.applicationContext as HasAndroidInjector).androidInjector().inject(this) @@ -69,10 +71,9 @@ class IobCobOref1Worker( class IobCobOref1WorkerData( val injector: HasAndroidInjector, - val iobCobCalculatorPlugin: IobCobCalculator, // cannot be injected : HistoryBrowser uses different instance + val iobCobCalculator: IobCobCalculator, // cannot be injected : HistoryBrowser uses different instance val from: String, val end: Long, - val bgDataReload: Boolean, val limitDataToOldestAvailable: Boolean, val cause: Event? ) @@ -90,13 +91,9 @@ class IobCobOref1Worker( return Result.failure(workDataOf("Error" to "app still initializing")) } //log.debug("Locking calculateSensitivityData"); - val oldestTimeWithData = data.iobCobCalculatorPlugin.calculateDetectionStart(data.end, data.limitDataToOldestAvailable) - if (data.bgDataReload) { - data.iobCobCalculatorPlugin.ads.loadBgData(data.end, repository, aapsLogger, dateUtil, rxBus) - data.iobCobCalculatorPlugin.clearCache() - } + val oldestTimeWithData = data.iobCobCalculator.calculateDetectionStart(data.end, data.limitDataToOldestAvailable) // work on local copy and set back when finished - val ads = data.iobCobCalculatorPlugin.ads.clone() + val ads = data.iobCobCalculator.ads.clone() val bucketedData = ads.bucketedData val autosensDataTable = ads.autosensDataTable if (bucketedData == null || bucketedData.size < 3) { @@ -108,8 +105,7 @@ class IobCobOref1Worker( var previous = autosensDataTable[prevDataTime] // start from oldest to be able sub cob for (i in bucketedData.size - 4 downTo 0) { - val progress = i.toString() + if (buildHelper.isDev()) " (${data.from})" else "" - rxBus.send(EventIobCalculationProgress(100 - (100.0 * i / bucketedData.size).toInt(), data.cause)) + rxBus.send(EventIobCalculationProgress(CalculationWorkflow.ProgressData.IOB_COB_OREF, 100 - (100.0 * i / bucketedData.size).toInt(), data.cause)) if (isStopped) { aapsLogger.debug(LTag.AUTOSENS, "Aborting calculation thread (trigger): ${data.from}") return Result.failure(workDataOf("Error" to "Aborting calculation thread (trigger): ${data.from}")) @@ -145,7 +141,7 @@ class IobCobOref1Worker( autosensData.bg = bg delta = bg - bucketedData[i + 1].value avgDelta = (bg - bucketedData[i + 3].value) / 3 - val iob = data.iobCobCalculatorPlugin.calculateFromTreatmentsAndTemps(bgTime, profile) + val iob = data.iobCobCalculator.calculateFromTreatmentsAndTemps(bgTime, profile) val bgi = -iob.activity * sens * 5 val deviation = delta - bgi val avgDeviation = ((avgDelta - bgi) * 1000).roundToLong() / 1000.0 @@ -332,13 +328,13 @@ class IobCobOref1Worker( autosensData.autosensResult = sensitivity aapsLogger.debug(LTag.AUTOSENS, autosensData.toString()) } - data.iobCobCalculatorPlugin.ads = ads + data.iobCobCalculator.ads = ads Thread { SystemClock.sleep(1000) rxBus.send(EventAutosensCalculationFinished(data.cause)) }.start() } finally { - rxBus.send(EventIobCalculationProgress(100, data.cause)) + rxBus.send(EventIobCalculationProgress(CalculationWorkflow.ProgressData.IOB_COB_OREF, 100, data.cause)) aapsLogger.debug(LTag.AUTOSENS, "AUTOSENSDATA thread ended: ${data.from}") profiler.log(LTag.AUTOSENS, "IobCobOref1Thread", start) } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/IobCobOrefWorker.kt b/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/IobCobOrefWorker.kt index 4bda1f1821..832de3fe58 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/IobCobOrefWorker.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/IobCobOrefWorker.kt @@ -30,6 +30,7 @@ import info.nightscout.androidaps.utils.Profiler import info.nightscout.androidaps.utils.T import info.nightscout.androidaps.utils.buildHelper.BuildHelper import info.nightscout.androidaps.utils.resources.ResourceHelper +import info.nightscout.androidaps.workflow.CalculationWorkflow import info.nightscout.shared.logging.AAPSLogger import info.nightscout.shared.logging.LTag import info.nightscout.shared.sharedPreferences.SP @@ -69,7 +70,6 @@ class IobCobOrefWorker @Inject internal constructor( val iobCobCalculatorPlugin: IobCobCalculator, // cannot be injected : HistoryBrowser uses different instance val from: String, val end: Long, - val bgDataReload: Boolean, val limitDataToOldestAvailable: Boolean, val cause: Event? ) @@ -87,10 +87,6 @@ class IobCobOrefWorker @Inject internal constructor( } //log.debug("Locking calculateSensitivityData"); val oldestTimeWithData = data.iobCobCalculatorPlugin.calculateDetectionStart(data.end, data.limitDataToOldestAvailable) - if (data.bgDataReload) { - data.iobCobCalculatorPlugin.ads.loadBgData(data.end, repository, aapsLogger, dateUtil, rxBus) - data.iobCobCalculatorPlugin.clearCache() - } // work on local copy and set back when finished val ads = data.iobCobCalculatorPlugin.ads.clone() val bucketedData = ads.bucketedData @@ -104,8 +100,7 @@ class IobCobOrefWorker @Inject internal constructor( var previous = autosensDataTable[prevDataTime] // start from oldest to be able sub cob for (i in bucketedData.size - 4 downTo 0) { - val progress = i.toString() + if (buildHelper.isDev()) " (${data.from})" else "" - rxBus.send(EventIobCalculationProgress(100 - (100.0 * i / bucketedData.size).toInt(), data.cause)) + rxBus.send(EventIobCalculationProgress(CalculationWorkflow.ProgressData.IOB_COB_OREF, 100 - (100.0 * i / bucketedData.size).toInt(), data.cause)) if (isStopped) { aapsLogger.debug(LTag.AUTOSENS, "Aborting calculation thread (trigger): ${data.from}") return Result.failure(workDataOf("Error" to "Aborting calculation thread (trigger): ${data.from}")) @@ -282,7 +277,7 @@ class IobCobOrefWorker @Inject internal constructor( rxBus.send(EventAutosensCalculationFinished(data.cause)) }.start() } finally { - rxBus.send(EventIobCalculationProgress(100, data.cause)) + rxBus.send(EventIobCalculationProgress(CalculationWorkflow.ProgressData.IOB_COB_OREF, 100, data.cause)) aapsLogger.debug(LTag.AUTOSENS, "AUTOSENSDATA thread ended: ${data.from}") profiler.log(LTag.AUTOSENS, "IobCobThread", start) } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/events/EventIobCalculationProgress.kt b/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/events/EventIobCalculationProgress.kt index e326b3c750..3da3b8e3bd 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/events/EventIobCalculationProgress.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/events/EventIobCalculationProgress.kt @@ -1,5 +1,6 @@ package info.nightscout.androidaps.plugins.iob.iobCobCalculator.events import info.nightscout.androidaps.events.Event +import info.nightscout.androidaps.workflow.CalculationWorkflow -class EventIobCalculationProgress(val progressPct: Int, val cause: Event?) : Event() \ No newline at end of file +class EventIobCalculationProgress(val pass: CalculationWorkflow.ProgressData, val progressPct: Int, val cause: Event?) : Event() \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/sensitivity/SensitivityAAPSPlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/sensitivity/SensitivityAAPSPlugin.kt index 723905f31f..4902118b8d 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/sensitivity/SensitivityAAPSPlugin.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/sensitivity/SensitivityAAPSPlugin.kt @@ -137,6 +137,8 @@ class SensitivityAAPSPlugin @Inject constructor( return output } + override fun maxAbsorptionHours(): Double = sp.getDouble(R.string.key_absorption_maxtime, Constants.DEFAULT_MAX_ABSORPTION_TIME) + override val id: SensitivityType get() = SensitivityType.SENSITIVITY_AAPS diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/sensitivity/SensitivityOref1Plugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/sensitivity/SensitivityOref1Plugin.kt index 35230bb10b..6d038bf952 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/sensitivity/SensitivityOref1Plugin.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/sensitivity/SensitivityOref1Plugin.kt @@ -204,6 +204,8 @@ class SensitivityOref1Plugin @Inject constructor( return output } + override fun maxAbsorptionHours(): Double = sp.getDouble(R.string.key_absorption_cutoff, Constants.DEFAULT_MAX_ABSORPTION_TIME) + override fun configuration(): JSONObject { val c = JSONObject() try { diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/sensitivity/SensitivityWeightedAveragePlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/sensitivity/SensitivityWeightedAveragePlugin.kt index 639cde7acc..868ac4ac7a 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/sensitivity/SensitivityWeightedAveragePlugin.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/sensitivity/SensitivityWeightedAveragePlugin.kt @@ -157,6 +157,8 @@ class SensitivityWeightedAveragePlugin @Inject constructor( return output } + override fun maxAbsorptionHours(): Double = sp.getDouble(R.string.key_absorption_maxtime, Constants.DEFAULT_MAX_ABSORPTION_TIME) + override val id: SensitivityType get() = SensitivityType.SENSITIVITY_WEIGHTED diff --git a/app/src/main/java/info/nightscout/androidaps/workflow/CalculationWorkflow.kt b/app/src/main/java/info/nightscout/androidaps/workflow/CalculationWorkflow.kt new file mode 100644 index 0000000000..d6a84cf8e5 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/workflow/CalculationWorkflow.kt @@ -0,0 +1,270 @@ +package info.nightscout.androidaps.workflow + +import android.content.Context +import android.os.SystemClock +import androidx.work.* +import dagger.android.HasAndroidInjector +import info.nightscout.androidaps.R +import info.nightscout.androidaps.events.Event +import info.nightscout.androidaps.events.EventAppInitialized +import info.nightscout.androidaps.events.EventOfflineChange +import info.nightscout.androidaps.events.EventPreferenceChange +import info.nightscout.androidaps.events.EventTherapyEventChange +import info.nightscout.androidaps.interfaces.ActivePlugin +import info.nightscout.androidaps.interfaces.IobCobCalculator +import info.nightscout.androidaps.plugins.bus.RxBus +import info.nightscout.androidaps.plugins.general.overview.OverviewData +import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin +import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobOref1Worker +import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobOrefWorker +import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventNewHistoryData +import info.nightscout.androidaps.plugins.sensitivity.SensitivityOref1Plugin +import info.nightscout.androidaps.receivers.DataWorker +import info.nightscout.androidaps.utils.DateUtil +import info.nightscout.androidaps.utils.FabricPrivacy +import info.nightscout.androidaps.utils.resources.ResourceHelper +import info.nightscout.androidaps.utils.rx.AapsSchedulers +import info.nightscout.shared.logging.AAPSLogger +import info.nightscout.shared.logging.LTag +import io.reactivex.rxjava3.disposables.CompositeDisposable +import io.reactivex.rxjava3.kotlin.plusAssign +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +class CalculationWorkflow @Inject constructor( + aapsSchedulers: AapsSchedulers, + rh: ResourceHelper, + rxBus: RxBus, + private val context: Context, + private val injector: HasAndroidInjector, + private val aapsLogger: AAPSLogger, + private val fabricPrivacy: FabricPrivacy, + private val dateUtil: DateUtil, + private val sensitivityOref1Plugin: SensitivityOref1Plugin, + private val dataWorker: DataWorker, + private val activePlugin: ActivePlugin +) { + + companion object { + + const val MAIN_CALCULATION = "calculation" + const val HISTORY_CALCULATION = "history_calculation" + const val JOB = "job" + } + + private var disposable: CompositeDisposable = CompositeDisposable() + + private val iobCobCalculator: IobCobCalculator + get() = activePlugin.activeIobCobCalculator // cross-dependency CalculationWorkflow x IobCobCalculator + private val overviewData: OverviewData + get() = (iobCobCalculator as IobCobCalculatorPlugin).overviewData + + enum class ProgressData(val pass: Int, val percentOfTotal: Int) { + PREPARE_BASAL_DATA(0, 5), + PREPARE_TEMPORARY_TARGET_DATA(1, 5), + PREPARE_TREATMENTS_DATA(2, 5), + IOB_COB_OREF(3, 75), + PREPARE_IOB_AUTOSENS_DATA(4, 10); + + fun finalPercent(progress: Int): Int { + var total = 0 + for (i in values()) if (i.pass < pass) total += i.percentOfTotal + total += (percentOfTotal.toDouble() * progress / 100.0).toInt() + return total + } + } + + init { + // Verify definition + var sumPercent = 0 + for (pass in ProgressData.values()) sumPercent += pass.percentOfTotal + require(sumPercent == 100) + + disposable += rxBus + .toObservable(EventTherapyEventChange::class.java) + .observeOn(aapsSchedulers.io) + .subscribe({ runOnEventTherapyEventChange() }, fabricPrivacy::logException) + disposable += rxBus + .toObservable(EventOfflineChange::class.java) + .observeOn(aapsSchedulers.io) + .subscribe({ runOnEventTherapyEventChange() }, fabricPrivacy::logException) + disposable += rxBus + .toObservable(EventPreferenceChange::class.java) + .observeOn(aapsSchedulers.io) + .subscribe({ event -> + if (event.isChanged(rh, R.string.key_units)) { + overviewData.reset() + rxBus.send(EventNewHistoryData(0, false)) + } + if (event.isChanged(rh, R.string.key_rangetodisplay)) { + overviewData.initRange() + runOnScaleChanged() + rxBus.send(EventNewHistoryData(0, false)) + } + }, fabricPrivacy::logException) + disposable += rxBus + .toObservable(EventAppInitialized::class.java) + .observeOn(aapsSchedulers.io) + .subscribe( + { + runCalculation( + MAIN_CALCULATION, + iobCobCalculator, + overviewData, + "onEventAppInitialized", + System.currentTimeMillis(), + bgDataReload = true, + limitDataToOldestAvailable = true, + cause = it, + runLoop = true + ) + }, + fabricPrivacy::logException + ) + + } + + fun stopCalculation(job: String, from: String) { + aapsLogger.debug(LTag.AUTOSENS, "Stopping calculation thread: $from") + WorkManager.getInstance(context).cancelUniqueWork(job) + val workStatus = WorkManager.getInstance(context).getWorkInfosForUniqueWork(job).get() + while (workStatus.size >= 1 && workStatus[0].state == WorkInfo.State.RUNNING) + SystemClock.sleep(100) + aapsLogger.debug(LTag.AUTOSENS, "Calculation thread stopped: $from") + } + + fun runCalculation( + job: String, + iobCobCalculator: IobCobCalculator, + overviewData: OverviewData, + from: String, + end: Long, + bgDataReload: Boolean, + limitDataToOldestAvailable: Boolean, + cause: Event?, + runLoop: Boolean + ) { + aapsLogger.debug(LTag.AUTOSENS, "Starting calculation worker: $from to ${dateUtil.dateAndTimeAndSecondsString(end)}") + + WorkManager.getInstance(context) + .beginUniqueWork( + job, ExistingWorkPolicy.REPLACE, + if (bgDataReload) OneTimeWorkRequest.Builder(LoadBgDataWorker::class.java).setInputData(dataWorker.storeInputData(LoadBgDataWorker.LoadBgData(iobCobCalculator, end))).build() + else OneTimeWorkRequest.Builder(DummyWorker::class.java).build() + ) + .then( + OneTimeWorkRequest.Builder(PrepareBucketedDataWorker::class.java) + .setInputData(dataWorker.storeInputData(PrepareBucketedDataWorker.PrepareBucketedData(iobCobCalculator, overviewData))) + .build() + ) + .then( + OneTimeWorkRequest.Builder(PrepareBgDataWorker::class.java) + .setInputData(dataWorker.storeInputData(PrepareBgDataWorker.PrepareBgData(iobCobCalculator, overviewData))) + .build() + ) + .then( + OneTimeWorkRequest.Builder(UpdateGraphWorker::class.java) + .setInputData(Data.Builder().putString(JOB, job).build()) + .build() + ) + .then( + OneTimeWorkRequest.Builder(PrepareTreatmentsDataWorker::class.java) + .setInputData(dataWorker.storeInputData(PrepareTreatmentsDataWorker.PrepareTreatmentsData(overviewData))) + .build() + ) + .then( + OneTimeWorkRequest.Builder(PrepareBasalDataWorker::class.java) + .setInputData(dataWorker.storeInputData(PrepareBasalDataWorker.PrepareBasalData(iobCobCalculator, overviewData))) + .build() + ) + .then( + OneTimeWorkRequest.Builder(PrepareTemporaryTargetDataWorker::class.java) + .setInputData(dataWorker.storeInputData(PrepareTemporaryTargetDataWorker.PrepareTemporaryTargetData(overviewData))) + .build() + ) + .then( + OneTimeWorkRequest.Builder(UpdateGraphWorker::class.java) + .setInputData(Data.Builder().putString(JOB, job).build()) + .build() + ) + .then( + if (sensitivityOref1Plugin.isEnabled()) + OneTimeWorkRequest.Builder(IobCobOref1Worker::class.java) + .setInputData(dataWorker.storeInputData(IobCobOref1Worker.IobCobOref1WorkerData(injector, iobCobCalculator, from, end, limitDataToOldestAvailable, cause))) + .build() + else + OneTimeWorkRequest.Builder(IobCobOrefWorker::class.java) + .setInputData(dataWorker.storeInputData(IobCobOrefWorker.IobCobOrefWorkerData(injector, iobCobCalculator, from, end, limitDataToOldestAvailable, cause))) + .build() + ) + .then(OneTimeWorkRequest.Builder(UpdateIobCobSensWorker::class.java).build()) + .then( + OneTimeWorkRequest.Builder(PrepareIobAutosensGraphDataWorker::class.java) + .setInputData(dataWorker.storeInputData(PrepareIobAutosensGraphDataWorker.PrepareIobAutosensData(iobCobCalculator, overviewData))) + .build() + ) + .then( + OneTimeWorkRequest.Builder(UpdateGraphWorker::class.java) + .setInputData(Data.Builder().putString(JOB, job).build()) + .build() + ) + .then( + runLoop, + OneTimeWorkRequest.Builder(InvokeLoopWorker::class.java) + .setInputData(dataWorker.storeInputData(InvokeLoopWorker.InvokeLoopData(cause))) + .build() + ) + .then( + runLoop, + OneTimeWorkRequest.Builder(PreparePredictionsWorker::class.java) + .setInputData(dataWorker.storeInputData(PreparePredictionsWorker.PreparePredictionsData(overviewData))) + .build() + ) + .then( + runLoop, OneTimeWorkRequest.Builder(UpdateGraphWorker::class.java) + .setInputData(Data.Builder().putString(JOB, job).build()) + .build() + ) + .enqueue() + } + + fun WorkContinuation.then(shouldAdd: Boolean, work: OneTimeWorkRequest): WorkContinuation = + if (shouldAdd) then(work) else this + + private fun runOnEventTherapyEventChange() { + WorkManager.getInstance(context) + .beginUniqueWork( + MAIN_CALCULATION, ExistingWorkPolicy.APPEND, + OneTimeWorkRequest.Builder(PrepareTreatmentsDataWorker::class.java) + .setInputData(dataWorker.storeInputData(PrepareTreatmentsDataWorker.PrepareTreatmentsData(overviewData))) + .build() + ) + .then( + OneTimeWorkRequest.Builder(UpdateGraphWorker::class.java) + .build() + ) + .enqueue() + + } + + private fun runOnScaleChanged() { + WorkManager.getInstance(context) + .beginUniqueWork( + MAIN_CALCULATION, ExistingWorkPolicy.APPEND, + OneTimeWorkRequest.Builder(PrepareBucketedDataWorker::class.java) + .setInputData(dataWorker.storeInputData(PrepareBucketedDataWorker.PrepareBucketedData(iobCobCalculator, overviewData))) + .build() + ) + .then( + OneTimeWorkRequest.Builder(PrepareBgDataWorker::class.java) + .setInputData(dataWorker.storeInputData(PrepareBgDataWorker.PrepareBgData(iobCobCalculator, overviewData))) + .build() + ) + .then( + OneTimeWorkRequest.Builder(UpdateGraphWorker::class.java) + .build() + ) + .enqueue() + } +} \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/androidaps/workflow/DummyWorker.kt b/app/src/main/java/info/nightscout/androidaps/workflow/DummyWorker.kt new file mode 100644 index 0000000000..fd30c54dc6 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/workflow/DummyWorker.kt @@ -0,0 +1,13 @@ +package info.nightscout.androidaps.workflow + +import android.content.Context +import androidx.work.Worker +import androidx.work.WorkerParameters + +class DummyWorker( + context: Context, + params: WorkerParameters +) : Worker(context, params) { + + override fun doWork(): Result = Result.success() +} \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/androidaps/workflow/InvokeLoopWorker.kt b/app/src/main/java/info/nightscout/androidaps/workflow/InvokeLoopWorker.kt new file mode 100644 index 0000000000..b6e5fb910d --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/workflow/InvokeLoopWorker.kt @@ -0,0 +1,51 @@ +package info.nightscout.androidaps.workflow + +import android.content.Context +import androidx.work.Worker +import androidx.work.WorkerParameters +import androidx.work.workDataOf +import dagger.android.HasAndroidInjector +import info.nightscout.androidaps.events.Event +import info.nightscout.androidaps.events.EventNewBG +import info.nightscout.androidaps.interfaces.IobCobCalculator +import info.nightscout.androidaps.interfaces.Loop +import info.nightscout.androidaps.receivers.DataWorker +import javax.inject.Inject + +class InvokeLoopWorker( + context: Context, + params: WorkerParameters +) : Worker(context, params) { + + @Inject lateinit var dataWorker: DataWorker + @Inject lateinit var iobCobCalculator: IobCobCalculator + @Inject lateinit var loop: Loop + + init { + (context.applicationContext as HasAndroidInjector).androidInjector().inject(this) + } + + class InvokeLoopData( + val cause: Event? + ) + + /* + This method is triggered once autosens calculation has completed, so the LoopPlugin + has current data to work with. However, autosens calculation can be triggered by multiple + sources and currently only a new BG should trigger a loop run. Hence we return early if + the event causing the calculation is not EventNewBg. +

+ */ + override fun doWork(): Result { + + val data = dataWorker.pickupObject(inputData.getLong(DataWorker.STORE_KEY, -1)) as InvokeLoopData? + ?: return Result.failure(workDataOf("Error" to "missing input data")) + + if (data.cause !is EventNewBG) return Result.success(workDataOf("Result" to "no calculation needed")) + val glucoseValue = iobCobCalculator.ads.actualBg() ?: return Result.success(workDataOf("Result" to "bg outdated")) + if (glucoseValue.timestamp <= loop.lastBgTriggeredRun) return Result.success(workDataOf("Result" to "already looped with that value")) + loop.lastBgTriggeredRun = glucoseValue.timestamp + loop.invoke("Calculation for $glucoseValue", true) + return Result.success() + } +} \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/androidaps/workflow/LoadBgDataWorker.kt b/app/src/main/java/info/nightscout/androidaps/workflow/LoadBgDataWorker.kt new file mode 100644 index 0000000000..67e8290822 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/workflow/LoadBgDataWorker.kt @@ -0,0 +1,45 @@ +package info.nightscout.androidaps.workflow + +import android.content.Context +import androidx.work.Worker +import androidx.work.WorkerParameters +import androidx.work.workDataOf +import dagger.android.HasAndroidInjector +import info.nightscout.androidaps.database.AppRepository +import info.nightscout.androidaps.interfaces.IobCobCalculator +import info.nightscout.androidaps.plugins.bus.RxBus +import info.nightscout.androidaps.receivers.DataWorker +import info.nightscout.androidaps.utils.DateUtil +import info.nightscout.shared.logging.AAPSLogger +import javax.inject.Inject + +class LoadBgDataWorker( + context: Context, + params: WorkerParameters +) : Worker(context, params) { + + @Inject lateinit var dataWorker: DataWorker + @Inject lateinit var aapsLogger: AAPSLogger + @Inject lateinit var dateUtil: DateUtil + @Inject lateinit var rxBus: RxBus + @Inject lateinit var repository: AppRepository + + init { + (context.applicationContext as HasAndroidInjector).androidInjector().inject(this) + } + + class LoadBgData( + val iobCobCalculator: IobCobCalculator, + val end: Long + ) + + override fun doWork(): Result { + + val data = dataWorker.pickupObject(inputData.getLong(DataWorker.STORE_KEY, -1)) as LoadBgData? + ?: return Result.failure(workDataOf("Error" to "missing input data")) + + data.iobCobCalculator.ads.loadBgData(data.end, repository, aapsLogger, dateUtil, rxBus) + data.iobCobCalculator.clearCache() + return Result.success() + } +} \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/androidaps/workflow/PrepareBasalDataWorker.kt b/app/src/main/java/info/nightscout/androidaps/workflow/PrepareBasalDataWorker.kt new file mode 100644 index 0000000000..8d47b1a675 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/workflow/PrepareBasalDataWorker.kt @@ -0,0 +1,145 @@ +package info.nightscout.androidaps.workflow + +import android.content.Context +import android.graphics.DashPathEffect +import android.graphics.Paint +import androidx.work.Worker +import androidx.work.WorkerParameters +import androidx.work.workDataOf +import com.jjoe64.graphview.series.LineGraphSeries +import dagger.android.HasAndroidInjector +import info.nightscout.androidaps.R +import info.nightscout.androidaps.interfaces.IobCobCalculator +import info.nightscout.androidaps.interfaces.ProfileFunction +import info.nightscout.androidaps.plugins.bus.RxBus +import info.nightscout.androidaps.plugins.general.overview.OverviewData +import info.nightscout.androidaps.plugins.general.overview.graphExtensions.ScaledDataPoint +import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventIobCalculationProgress +import info.nightscout.androidaps.receivers.DataWorker +import info.nightscout.androidaps.utils.resources.ResourceHelper +import java.util.ArrayList +import javax.inject.Inject +import kotlin.math.max + +class PrepareBasalDataWorker( + context: Context, + params: WorkerParameters +) : Worker(context, params) { + + @Inject lateinit var dataWorker: DataWorker + @Inject lateinit var profileFunction: ProfileFunction + @Inject lateinit var rh: ResourceHelper + @Inject lateinit var rxBus: RxBus + + init { + (context.applicationContext as HasAndroidInjector).androidInjector().inject(this) + } + + class PrepareBasalData( + val iobCobCalculator: IobCobCalculator, // cannot be injected : HistoryBrowser uses different instance + val overviewData: OverviewData + ) + + override fun doWork(): Result { + + val data = dataWorker.pickupObject(inputData.getLong(DataWorker.STORE_KEY, -1)) as PrepareBasalData? + ?: return Result.failure(workDataOf("Error" to "missing input data")) + + rxBus.send(EventIobCalculationProgress(CalculationWorkflow.ProgressData.PREPARE_BASAL_DATA, 0, null)) + data.overviewData.maxBasalValueFound = 0.0 + val baseBasalArray: MutableList = ArrayList() + val tempBasalArray: MutableList = ArrayList() + val basalLineArray: MutableList = ArrayList() + val absoluteBasalLineArray: MutableList = ArrayList() + var lastLineBasal = 0.0 + var lastAbsoluteLineBasal = -1.0 + var lastBaseBasal = 0.0 + var lastTempBasal = 0.0 + var time = data.overviewData.fromTime + while (time < data.overviewData.toTime) { + val progress = (time - data.overviewData.fromTime).toDouble() / (data.overviewData.toTime - data.overviewData.fromTime) * 100.0 + rxBus.send(EventIobCalculationProgress(CalculationWorkflow.ProgressData.PREPARE_BASAL_DATA, progress.toInt(), null)) + val profile = profileFunction.getProfile(time) + if (profile == null) { + time += 60 * 1000L + continue + } + val basalData = data.iobCobCalculator.getBasalData(profile, time) + val baseBasalValue = basalData.basal + var absoluteLineValue = baseBasalValue + var tempBasalValue = 0.0 + var basal = 0.0 + if (basalData.isTempBasalRunning) { + tempBasalValue = basalData.tempBasalAbsolute + absoluteLineValue = tempBasalValue + if (tempBasalValue != lastTempBasal) { + tempBasalArray.add(ScaledDataPoint(time, lastTempBasal, data.overviewData.basalScale)) + tempBasalArray.add(ScaledDataPoint(time, tempBasalValue.also { basal = it }, data.overviewData.basalScale)) + } + if (lastBaseBasal != 0.0) { + baseBasalArray.add(ScaledDataPoint(time, lastBaseBasal, data.overviewData.basalScale)) + baseBasalArray.add(ScaledDataPoint(time, 0.0, data.overviewData.basalScale)) + lastBaseBasal = 0.0 + } + } else { + if (baseBasalValue != lastBaseBasal) { + baseBasalArray.add(ScaledDataPoint(time, lastBaseBasal, data.overviewData.basalScale)) + baseBasalArray.add(ScaledDataPoint(time, baseBasalValue.also { basal = it }, data.overviewData.basalScale)) + lastBaseBasal = baseBasalValue + } + if (lastTempBasal != 0.0) { + tempBasalArray.add(ScaledDataPoint(time, lastTempBasal, data.overviewData.basalScale)) + tempBasalArray.add(ScaledDataPoint(time, 0.0, data.overviewData.basalScale)) + } + } + if (baseBasalValue != lastLineBasal) { + basalLineArray.add(ScaledDataPoint(time, lastLineBasal, data.overviewData.basalScale)) + basalLineArray.add(ScaledDataPoint(time, baseBasalValue, data.overviewData.basalScale)) + } + if (absoluteLineValue != lastAbsoluteLineBasal) { + absoluteBasalLineArray.add(ScaledDataPoint(time, lastAbsoluteLineBasal, data.overviewData.basalScale)) + absoluteBasalLineArray.add(ScaledDataPoint(time, basal, data.overviewData.basalScale)) + } + lastAbsoluteLineBasal = absoluteLineValue + lastLineBasal = baseBasalValue + lastTempBasal = tempBasalValue + data.overviewData.maxBasalValueFound = max(data.overviewData.maxBasalValueFound, max(tempBasalValue, baseBasalValue)) + time += 60 * 1000L + } + + // final points + basalLineArray.add(ScaledDataPoint(data.overviewData.toTime, lastLineBasal, data.overviewData.basalScale)) + baseBasalArray.add(ScaledDataPoint(data.overviewData.toTime, lastBaseBasal, data.overviewData.basalScale)) + tempBasalArray.add(ScaledDataPoint(data.overviewData.toTime, lastTempBasal, data.overviewData.basalScale)) + absoluteBasalLineArray.add(ScaledDataPoint(data.overviewData.toTime, lastAbsoluteLineBasal, data.overviewData.basalScale)) + + // create series + data.overviewData.baseBasalGraphSeries = LineGraphSeries(Array(baseBasalArray.size) { i -> baseBasalArray[i] }).also { + it.isDrawBackground = true + it.backgroundColor = rh.gc(R.color.basebasal) + it.thickness = 0 + } + data.overviewData.tempBasalGraphSeries = LineGraphSeries(Array(tempBasalArray.size) { i -> tempBasalArray[i] }).also { + it.isDrawBackground = true + it.backgroundColor = rh.gc(R.color.tempbasal) + it.thickness = 0 + } + data.overviewData.basalLineGraphSeries = LineGraphSeries(Array(basalLineArray.size) { i -> basalLineArray[i] }).also { + it.setCustomPaint(Paint().also { paint -> + paint.style = Paint.Style.STROKE + paint.strokeWidth = rh.getDisplayMetrics().scaledDensity * 2 + paint.pathEffect = DashPathEffect(floatArrayOf(2f, 4f), 0f) + paint.color = rh.gc(R.color.basal) + }) + } + data.overviewData.absoluteBasalGraphSeries = LineGraphSeries(Array(absoluteBasalLineArray.size) { i -> absoluteBasalLineArray[i] }).also { + it.setCustomPaint(Paint().also { absolutePaint -> + absolutePaint.style = Paint.Style.STROKE + absolutePaint.strokeWidth = rh.getDisplayMetrics().scaledDensity * 2 + absolutePaint.color = rh.gc(R.color.basal) + }) + } + rxBus.send(EventIobCalculationProgress(CalculationWorkflow.ProgressData.PREPARE_BASAL_DATA, 100, null)) + return Result.success() + } +} \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/androidaps/workflow/PrepareBgDataWorker.kt b/app/src/main/java/info/nightscout/androidaps/workflow/PrepareBgDataWorker.kt new file mode 100644 index 0000000000..eb9941b419 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/workflow/PrepareBgDataWorker.kt @@ -0,0 +1,67 @@ +package info.nightscout.androidaps.workflow + +import android.content.Context +import androidx.work.Worker +import androidx.work.WorkerParameters +import androidx.work.workDataOf +import dagger.android.HasAndroidInjector +import info.nightscout.androidaps.database.AppRepository +import info.nightscout.androidaps.interfaces.GlucoseUnit +import info.nightscout.androidaps.interfaces.IobCobCalculator +import info.nightscout.androidaps.interfaces.Profile +import info.nightscout.androidaps.interfaces.ProfileFunction +import info.nightscout.androidaps.plugins.general.overview.OverviewData +import info.nightscout.androidaps.plugins.general.overview.graphExtensions.DataPointWithLabelInterface +import info.nightscout.androidaps.plugins.general.overview.graphExtensions.GlucoseValueDataPoint +import info.nightscout.androidaps.plugins.general.overview.graphExtensions.PointsWithLabelGraphSeries +import info.nightscout.androidaps.receivers.DataWorker +import info.nightscout.androidaps.utils.DefaultValueHelper +import info.nightscout.androidaps.utils.Round +import info.nightscout.androidaps.utils.resources.ResourceHelper +import java.util.ArrayList +import javax.inject.Inject + +class PrepareBgDataWorker( + context: Context, + params: WorkerParameters +) : Worker(context, params) { + + @Inject lateinit var dataWorker: DataWorker + @Inject lateinit var profileFunction: ProfileFunction + @Inject lateinit var rh: ResourceHelper + @Inject lateinit var defaultValueHelper: DefaultValueHelper + @Inject lateinit var repository: AppRepository + + init { + (context.applicationContext as HasAndroidInjector).androidInjector().inject(this) + } + + class PrepareBgData( + val iobCobCalculator: IobCobCalculator, // cannot be injected : HistoryBrowser uses different instance + val overviewData: OverviewData + ) + + override fun doWork(): Result { + + val data = dataWorker.pickupObject(inputData.getLong(DataWorker.STORE_KEY, -1)) as PrepareBgData? + ?: return Result.failure(workDataOf("Error" to "missing input data")) + + data.overviewData.maxBgValue = Double.MIN_VALUE + data.overviewData.bgReadingsArray = repository.compatGetBgReadingsDataFromTime(data.overviewData.fromTime, data.overviewData.toTime, false).blockingGet() + val bgListArray: MutableList = ArrayList() + for (bg in data.overviewData.bgReadingsArray) { + if (bg.timestamp < data.overviewData.fromTime || bg.timestamp > data.overviewData.toTime) continue + if (bg.value > data.overviewData.maxBgValue) data.overviewData.maxBgValue = bg.value + bgListArray.add(GlucoseValueDataPoint(bg, defaultValueHelper, profileFunction, rh)) + } + bgListArray.sortWith { o1: DataPointWithLabelInterface, o2: DataPointWithLabelInterface -> o1.x.compareTo(o2.x) } + data.overviewData.bgReadingGraphSeries = PointsWithLabelGraphSeries(Array(bgListArray.size) { i -> bgListArray[i] }) + data.overviewData.maxBgValue = Profile.fromMgdlToUnits(data.overviewData.maxBgValue, profileFunction.getUnits()) + if (defaultValueHelper.determineHighLine() > data.overviewData.maxBgValue) data.overviewData.maxBgValue = defaultValueHelper.determineHighLine() + data.overviewData.maxBgValue = addUpperChartMargin(data.overviewData.maxBgValue) + return Result.success() + } + + private fun addUpperChartMargin(maxBgValue: Double) = + if (profileFunction.getUnits() == GlucoseUnit.MGDL) Round.roundTo(maxBgValue, 40.0) + 80 else Round.roundTo(maxBgValue, 2.0) + 4 +} \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/androidaps/workflow/PrepareBucketedDataWorker.kt b/app/src/main/java/info/nightscout/androidaps/workflow/PrepareBucketedDataWorker.kt new file mode 100644 index 0000000000..54e98ec316 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/workflow/PrepareBucketedDataWorker.kt @@ -0,0 +1,57 @@ +package info.nightscout.androidaps.workflow + +import android.content.Context +import androidx.work.Worker +import androidx.work.WorkerParameters +import androidx.work.workDataOf +import dagger.android.HasAndroidInjector +import info.nightscout.androidaps.interfaces.IobCobCalculator +import info.nightscout.androidaps.interfaces.ProfileFunction +import info.nightscout.androidaps.plugins.general.overview.OverviewData +import info.nightscout.androidaps.plugins.general.overview.graphExtensions.DataPointWithLabelInterface +import info.nightscout.androidaps.plugins.general.overview.graphExtensions.InMemoryGlucoseValueDataPoint +import info.nightscout.androidaps.plugins.general.overview.graphExtensions.PointsWithLabelGraphSeries +import info.nightscout.androidaps.receivers.DataWorker +import info.nightscout.androidaps.utils.resources.ResourceHelper +import info.nightscout.shared.logging.AAPSLogger +import javax.inject.Inject + +class PrepareBucketedDataWorker( + context: Context, + params: WorkerParameters +) : Worker(context, params) { + + @Inject lateinit var dataWorker: DataWorker + @Inject lateinit var profileFunction: ProfileFunction + @Inject lateinit var rh: ResourceHelper + @Inject lateinit var aapsLogger: AAPSLogger + + init { + (context.applicationContext as HasAndroidInjector).androidInjector().inject(this) + } + + class PrepareBucketedData( + val iobCobCalculator: IobCobCalculator, // cannot be injected : HistoryBrowser uses different instance + val overviewData: OverviewData + ) + + override fun doWork(): Result { + + val data = dataWorker.pickupObject(inputData.getLong(DataWorker.STORE_KEY, -1)) as PrepareBucketedData? + ?: return Result.failure(workDataOf("Error" to "missing input data")) + + val bucketedData = data.iobCobCalculator.ads.getBucketedDataTableCopy() ?: return Result.success() + if (bucketedData.isEmpty()) { + aapsLogger.debug("No bucketed data.") + return Result.success() + } + val bucketedListArray: MutableList = ArrayList() + for (inMemoryGlucoseValue in bucketedData) { + if (inMemoryGlucoseValue.timestamp < data.overviewData.fromTime || inMemoryGlucoseValue.timestamp > data.overviewData.toTime) continue + bucketedListArray.add(InMemoryGlucoseValueDataPoint(inMemoryGlucoseValue, profileFunction, rh)) + } + bucketedListArray.sortWith { o1: DataPointWithLabelInterface, o2: DataPointWithLabelInterface -> o1.x.compareTo(o2.x) } + data.overviewData.bucketedGraphSeries = PointsWithLabelGraphSeries(Array(bucketedListArray.size) { i -> bucketedListArray[i] }) + return Result.success() + } +} \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/androidaps/workflow/PrepareIobAutosensGraphDataWorker.kt b/app/src/main/java/info/nightscout/androidaps/workflow/PrepareIobAutosensGraphDataWorker.kt new file mode 100644 index 0000000000..606258106c --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/workflow/PrepareIobAutosensGraphDataWorker.kt @@ -0,0 +1,284 @@ +package info.nightscout.androidaps.workflow + +import android.content.Context +import android.graphics.DashPathEffect +import android.graphics.Paint +import androidx.work.Worker +import androidx.work.WorkerParameters +import androidx.work.workDataOf +import com.jjoe64.graphview.series.BarGraphSeries +import com.jjoe64.graphview.series.LineGraphSeries +import dagger.android.HasAndroidInjector +import info.nightscout.androidaps.R +import info.nightscout.androidaps.data.IobTotal +import info.nightscout.androidaps.database.AppRepository +import info.nightscout.androidaps.database.ValueWrapper +import info.nightscout.androidaps.interfaces.IobCobCalculator +import info.nightscout.androidaps.interfaces.ProfileFunction +import info.nightscout.androidaps.plugins.aps.openAPSSMB.SMBDefaults +import info.nightscout.androidaps.plugins.bus.RxBus +import info.nightscout.androidaps.plugins.general.overview.OverviewData +import info.nightscout.androidaps.plugins.general.overview.OverviewMenus +import info.nightscout.androidaps.plugins.general.overview.OverviewPlugin +import info.nightscout.androidaps.plugins.general.overview.graphExtensions.DataPointWithLabelInterface +import info.nightscout.androidaps.plugins.general.overview.graphExtensions.FixedLineGraphSeries +import info.nightscout.androidaps.plugins.general.overview.graphExtensions.PointsWithLabelGraphSeries +import info.nightscout.androidaps.plugins.general.overview.graphExtensions.ScaledDataPoint +import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensResult +import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventIobCalculationProgress +import info.nightscout.androidaps.receivers.DataWorker +import info.nightscout.androidaps.utils.DateUtil +import info.nightscout.androidaps.utils.DecimalFormatter +import info.nightscout.androidaps.utils.resources.ResourceHelper +import info.nightscout.shared.logging.AAPSLogger +import info.nightscout.shared.logging.LTag +import java.util.ArrayList +import javax.inject.Inject +import kotlin.math.abs +import kotlin.math.max +import kotlin.math.min + +class PrepareIobAutosensGraphDataWorker( + context: Context, + params: WorkerParameters +) : Worker(context, params) { + + @Inject lateinit var dataWorker: DataWorker + @Inject lateinit var dateUtil: DateUtil + @Inject lateinit var profileFunction: ProfileFunction + @Inject lateinit var rh: ResourceHelper + @Inject lateinit var overviewMenus: OverviewMenus + @Inject lateinit var aapsLogger: AAPSLogger + @Inject lateinit var repository: AppRepository + @Inject lateinit var rxBus: RxBus + + init { + (context.applicationContext as HasAndroidInjector).androidInjector().inject(this) + } + + class PrepareIobAutosensData( + val iobCobCalculator: IobCobCalculator, // cannot be injected : HistoryBrowser uses different instance + val overviewData: OverviewData + ) + + override fun doWork(): Result { + val data = dataWorker.pickupObject(inputData.getLong(DataWorker.STORE_KEY, -1)) as PrepareIobAutosensData? + ?: return Result.failure(workDataOf("Error" to "missing input data")) + + rxBus.send(EventIobCalculationProgress(CalculationWorkflow.ProgressData.PREPARE_IOB_AUTOSENS_DATA, 0, null)) + val iobArray: MutableList = ArrayList() + val absIobArray: MutableList = ArrayList() + data.overviewData.maxIobValueFound = Double.MIN_VALUE + var lastIob = 0.0 + var absLastIob = 0.0 + var time = data.overviewData.fromTime + + val minFailOverActiveList: MutableList = ArrayList() + val cobArray: MutableList = ArrayList() + data.overviewData.maxCobValueFound = Double.MIN_VALUE + var lastCob = 0 + + val actArrayHist: MutableList = ArrayList() + val actArrayPrediction: MutableList = ArrayList() + val now = dateUtil.now().toDouble() + data.overviewData.maxIAValue = 0.0 + + val bgiArrayHist: MutableList = ArrayList() + val bgiArrayPrediction: MutableList = ArrayList() + data.overviewData.maxBGIValue = Double.MIN_VALUE + + val devArray: MutableList = ArrayList() + data.overviewData.maxDevValueFound = Double.MIN_VALUE + + val ratioArray: MutableList = ArrayList() + data.overviewData.maxRatioValueFound = 5.0 //even if sens data equals 0 for all the period, minimum scale is between 95% and 105% + data.overviewData.minRatioValueFound = -5.0 + + val dsMaxArray: MutableList = ArrayList() + val dsMinArray: MutableList = ArrayList() + data.overviewData.maxFromMaxValueFound = Double.MIN_VALUE + data.overviewData.maxFromMinValueFound = Double.MIN_VALUE + + val adsData = data.iobCobCalculator.ads.clone() + + while (time <= data.overviewData.toTime) { + val progress = (time - data.overviewData.fromTime).toDouble() / (data.overviewData.toTime - data.overviewData.fromTime) * 100.0 + rxBus.send(EventIobCalculationProgress(CalculationWorkflow.ProgressData.PREPARE_IOB_AUTOSENS_DATA, progress.toInt(), null)) + val profile = profileFunction.getProfile(time) + if (profile == null) { + time += 5 * 60 * 1000L + continue + } + // IOB + val iob = data.iobCobCalculator.calculateFromTreatmentsAndTemps(time, profile) + val baseBasalIob = data.iobCobCalculator.calculateAbsoluteIobFromBaseBasals(time) + val absIob = IobTotal.combine(iob, baseBasalIob) + val autosensData = adsData.getAutosensDataAtTime(time) + if (abs(lastIob - iob.iob) > 0.02) { + if (abs(lastIob - iob.iob) > 0.2) iobArray.add(ScaledDataPoint(time, lastIob, data.overviewData.iobScale)) + iobArray.add(ScaledDataPoint(time, iob.iob, data.overviewData.iobScale)) + data.overviewData.maxIobValueFound = maxOf(data.overviewData.maxIobValueFound, abs(iob.iob)) + lastIob = iob.iob + } + if (abs(absLastIob - absIob.iob) > 0.02) { + if (abs(absLastIob - absIob.iob) > 0.2) absIobArray.add(ScaledDataPoint(time, absLastIob, data.overviewData.iobScale)) + absIobArray.add(ScaledDataPoint(time, absIob.iob, data.overviewData.iobScale)) + data.overviewData.maxIobValueFound = maxOf(data.overviewData.maxIobValueFound, abs(absIob.iob)) + absLastIob = absIob.iob + } + + // COB + if (autosensData != null) { + val cob = autosensData.cob.toInt() + if (cob != lastCob) { + if (autosensData.carbsFromBolus > 0) cobArray.add(ScaledDataPoint(time, lastCob.toDouble(), data.overviewData.cobScale)) + cobArray.add(ScaledDataPoint(time, cob.toDouble(), data.overviewData.cobScale)) + data.overviewData.maxCobValueFound = max(data.overviewData.maxCobValueFound, cob.toDouble()) + lastCob = cob + } + if (autosensData.failOverToMinAbsorptionRate) { + autosensData.scale = data.overviewData.cobScale + autosensData.chartTime = time + minFailOverActiveList.add(autosensData) + } + } + + // ACTIVITY + if (time <= now) actArrayHist.add(ScaledDataPoint(time, iob.activity, data.overviewData.actScale)) + else actArrayPrediction.add(ScaledDataPoint(time, iob.activity, data.overviewData.actScale)) + data.overviewData.maxIAValue = max(data.overviewData.maxIAValue, abs(iob.activity)) + + // BGI + val devBgiScale = overviewMenus.isEnabledIn(OverviewMenus.CharType.DEV) == overviewMenus.isEnabledIn(OverviewMenus.CharType.BGI) + val deviation = if (devBgiScale) autosensData?.deviation ?: 0.0 else 0.0 + val bgi: Double = iob.activity * profile.getIsfMgdl(time) * 5.0 + if (time <= now) bgiArrayHist.add(ScaledDataPoint(time, bgi, data.overviewData.bgiScale)) + else bgiArrayPrediction.add(ScaledDataPoint(time, bgi, data.overviewData.bgiScale)) + data.overviewData.maxBGIValue = max(data.overviewData.maxBGIValue, max(abs(bgi), deviation)) + + // DEVIATIONS + if (autosensData != null) { + var color = rh.gc(R.color.deviationblack) // "=" + if (autosensData.type == "" || autosensData.type == "non-meal") { + if (autosensData.pastSensitivity == "C") color = rh.gc(R.color.deviationgrey) + if (autosensData.pastSensitivity == "+") color = rh.gc(R.color.deviationgreen) + if (autosensData.pastSensitivity == "-") color = rh.gc(R.color.deviationred) + } else if (autosensData.type == "uam") { + color = rh.gc(R.color.uam) + } else if (autosensData.type == "csf") { + color = rh.gc(R.color.deviationgrey) + } + devArray.add(OverviewPlugin.DeviationDataPoint(time.toDouble(), autosensData.deviation, color, data.overviewData.devScale)) + data.overviewData.maxDevValueFound = maxOf(data.overviewData.maxDevValueFound, abs(autosensData.deviation), abs(bgi)) + } + + // RATIO + if (autosensData != null) { + ratioArray.add(ScaledDataPoint(time, 100.0 * (autosensData.autosensResult.ratio - 1), data.overviewData.ratioScale)) + data.overviewData.maxRatioValueFound = max(data.overviewData.maxRatioValueFound, 100.0 * (autosensData.autosensResult.ratio - 1)) + data.overviewData.minRatioValueFound = min(data.overviewData.minRatioValueFound, 100.0 * (autosensData.autosensResult.ratio - 1)) + } + + // DEV SLOPE + if (autosensData != null) { + dsMaxArray.add(ScaledDataPoint(time, autosensData.slopeFromMaxDeviation, data.overviewData.dsMaxScale)) + dsMinArray.add(ScaledDataPoint(time, autosensData.slopeFromMinDeviation, data.overviewData.dsMinScale)) + data.overviewData.maxFromMaxValueFound = max(data.overviewData.maxFromMaxValueFound, abs(autosensData.slopeFromMaxDeviation)) + data.overviewData.maxFromMinValueFound = max(data.overviewData.maxFromMinValueFound, abs(autosensData.slopeFromMinDeviation)) + } + + time += 5 * 60 * 1000L + } + // IOB + data.overviewData.iobSeries = FixedLineGraphSeries(Array(iobArray.size) { i -> iobArray[i] }).also { + it.isDrawBackground = true + it.backgroundColor = -0x7f000001 and rh.gc(R.color.iob) //50% + it.color = rh.gc(R.color.iob) + it.thickness = 3 + } + data.overviewData.absIobSeries = FixedLineGraphSeries(Array(absIobArray.size) { i -> absIobArray[i] }).also { + it.isDrawBackground = true + it.backgroundColor = -0x7f000001 and rh.gc(R.color.iob) //50% + it.color = rh.gc(R.color.iob) + it.thickness = 3 + } + + if (overviewMenus.setting[0][OverviewMenus.CharType.PRE.ordinal]) { + val autosensData = adsData.getLastAutosensData("GraphData", aapsLogger, dateUtil) + val lastAutosensResult = autosensData?.autosensResult ?: AutosensResult() + val isTempTarget = repository.getTemporaryTargetActiveAt(dateUtil.now()).blockingGet() is ValueWrapper.Existing + val iobPrediction: MutableList = ArrayList() + val iobPredictionArray = data.iobCobCalculator.calculateIobArrayForSMB(lastAutosensResult, SMBDefaults.exercise_mode, SMBDefaults.half_basal_exercise_target, isTempTarget) + for (i in iobPredictionArray) { + iobPrediction.add(i.setColor(rh.gc(R.color.iobPredAS))) + data.overviewData.maxIobValueFound = max(data.overviewData.maxIobValueFound, abs(i.iob)) + } + data.overviewData.iobPredictions1Series = PointsWithLabelGraphSeries(Array(iobPrediction.size) { i -> iobPrediction[i] }) + aapsLogger.debug(LTag.AUTOSENS, "IOB prediction for AS=" + DecimalFormatter.to2Decimal(lastAutosensResult.ratio) + ": " + data.iobCobCalculator.iobArrayToString(iobPredictionArray)) + } else { + data.overviewData.iobPredictions1Series = PointsWithLabelGraphSeries() + } + + // COB + data.overviewData.cobSeries = FixedLineGraphSeries(Array(cobArray.size) { i -> cobArray[i] }).also { + it.isDrawBackground = true + it.backgroundColor = -0x7f000001 and rh.gc(R.color.cob) //50% + it.color = rh.gc(R.color.cob) + it.thickness = 3 + } + data.overviewData.cobMinFailOverSeries = PointsWithLabelGraphSeries(Array(minFailOverActiveList.size) { i -> minFailOverActiveList[i] }) + + // ACTIVITY + data.overviewData.activitySeries = FixedLineGraphSeries(Array(actArrayHist.size) { i -> actArrayHist[i] }).also { + it.isDrawBackground = false + it.color = rh.gc(R.color.activity) + it.thickness = 3 + } + data.overviewData.activityPredictionSeries = FixedLineGraphSeries(Array(actArrayPrediction.size) { i -> actArrayPrediction[i] }).also { + it.setCustomPaint(Paint().also { paint -> + paint.style = Paint.Style.STROKE + paint.strokeWidth = 3f + paint.pathEffect = DashPathEffect(floatArrayOf(4f, 4f), 0f) + paint.color = rh.gc(R.color.activity) + }) + } + + // BGI + data.overviewData.minusBgiSeries = FixedLineGraphSeries(Array(bgiArrayHist.size) { i -> bgiArrayHist[i] }).also { + it.isDrawBackground = false + it.color = rh.gc(R.color.bgi) + it.thickness = 3 + } + data.overviewData.minusBgiHistSeries = FixedLineGraphSeries(Array(bgiArrayPrediction.size) { i -> bgiArrayPrediction[i] }).also { + it.setCustomPaint(Paint().also { paint -> + paint.style = Paint.Style.STROKE + paint.strokeWidth = 3f + paint.pathEffect = DashPathEffect(floatArrayOf(4f, 4f), 0f) + paint.color = rh.gc(R.color.bgi) + }) + } + + // DEVIATIONS + data.overviewData.deviationsSeries = BarGraphSeries(Array(devArray.size) { i -> devArray[i] }).also { + it.setValueDependentColor { data: OverviewPlugin.DeviationDataPoint -> data.color } + } + + // RATIO + data.overviewData.ratioSeries = LineGraphSeries(Array(ratioArray.size) { i -> ratioArray[i] }).also { + it.color = rh.gc(R.color.ratio) + it.thickness = 3 + } + + // DEV SLOPE + data.overviewData.dsMaxSeries = LineGraphSeries(Array(dsMaxArray.size) { i -> dsMaxArray[i] }).also { + it.color = rh.gc(R.color.devslopepos) + it.thickness = 3 + } + data.overviewData.dsMinSeries = LineGraphSeries(Array(dsMinArray.size) { i -> dsMinArray[i] }).also { + it.color = rh.gc(R.color.devslopeneg) + it.thickness = 3 + } + rxBus.send(EventIobCalculationProgress(CalculationWorkflow.ProgressData.PREPARE_IOB_AUTOSENS_DATA, 100, null)) + return Result.success() + } +} \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/androidaps/workflow/PreparePredictionsWorker.kt b/app/src/main/java/info/nightscout/androidaps/workflow/PreparePredictionsWorker.kt new file mode 100644 index 0000000000..ff57c4260c --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/workflow/PreparePredictionsWorker.kt @@ -0,0 +1,95 @@ +package info.nightscout.androidaps.workflow + +import android.content.Context +import androidx.work.Worker +import androidx.work.WorkerParameters +import androidx.work.workDataOf +import dagger.android.HasAndroidInjector +import info.nightscout.androidaps.database.AppRepository +import info.nightscout.androidaps.interfaces.Config +import info.nightscout.androidaps.interfaces.Loop +import info.nightscout.androidaps.interfaces.ProfileFunction +import info.nightscout.androidaps.plugins.bus.RxBus +import info.nightscout.androidaps.plugins.general.nsclient.data.NSDeviceStatus +import info.nightscout.androidaps.plugins.general.overview.OverviewData +import info.nightscout.androidaps.plugins.general.overview.OverviewMenus +import info.nightscout.androidaps.plugins.general.overview.graphExtensions.DataPointWithLabelInterface +import info.nightscout.androidaps.plugins.general.overview.graphExtensions.GlucoseValueDataPoint +import info.nightscout.androidaps.plugins.general.overview.graphExtensions.PointsWithLabelGraphSeries +import info.nightscout.androidaps.receivers.DataWorker +import info.nightscout.androidaps.utils.DefaultValueHelper +import info.nightscout.androidaps.utils.T +import info.nightscout.androidaps.utils.resources.ResourceHelper +import java.util.* +import javax.inject.Inject +import kotlin.math.ceil +import kotlin.math.max +import kotlin.math.min + +class PreparePredictionsWorker( + context: Context, + params: WorkerParameters +) : Worker(context, params) { + + @Inject lateinit var injector: HasAndroidInjector + @Inject lateinit var overviewData: OverviewData + @Inject lateinit var repository: AppRepository + @Inject lateinit var rxBus: RxBus + @Inject lateinit var config: Config + @Inject lateinit var nsDeviceStatus: NSDeviceStatus + @Inject lateinit var loop: Loop + @Inject lateinit var overviewMenus: OverviewMenus + @Inject lateinit var dataWorker: DataWorker + @Inject lateinit var defaultValueHelper: DefaultValueHelper + @Inject lateinit var profileFunction: ProfileFunction + @Inject lateinit var rh: ResourceHelper + + init { + (context.applicationContext as HasAndroidInjector).androidInjector().inject(this) + } + + class PreparePredictionsData( + val overviewData: OverviewData + ) + + override fun doWork(): Result { + val data = dataWorker.pickupObject(inputData.getLong(DataWorker.STORE_KEY, -1)) as PreparePredictionsData? + ?: return Result.failure(workDataOf("Error" to "missing input data")) + + val apsResult = if (config.APS) loop.lastRun?.constraintsProcessed else nsDeviceStatus.getAPSResult(injector) + val predictionsAvailable = if (config.APS) loop.lastRun?.request?.hasPredictions == true else config.NSCLIENT + val menuChartSettings = overviewMenus.setting + // align to hours + val calendar = Calendar.getInstance().also { + it.timeInMillis = System.currentTimeMillis() + it[Calendar.MILLISECOND] = 0 + it[Calendar.SECOND] = 0 + it[Calendar.MINUTE] = 0 + it.add(Calendar.HOUR, 1) + } + if (predictionsAvailable && apsResult != null && menuChartSettings[0][OverviewMenus.CharType.PRE.ordinal]) { + var predictionHours = (ceil(apsResult.latestPredictionsTime - System.currentTimeMillis().toDouble()) / (60 * 60 * 1000)).toInt() + predictionHours = min(2, predictionHours) + predictionHours = max(0, predictionHours) + val hoursToFetch = data.overviewData.rangeToDisplay - predictionHours + data.overviewData.toTime = calendar.timeInMillis + 100000 // little bit more to avoid wrong rounding - GraphView specific + data.overviewData.fromTime = data.overviewData.toTime - T.hours(hoursToFetch.toLong()).msecs() + data.overviewData.endTime = data.overviewData.toTime + T.hours(predictionHours.toLong()).msecs() + } else { + data.overviewData.toTime = calendar.timeInMillis + 100000 // little bit more to avoid wrong rounding - GraphView specific + data.overviewData.fromTime = data.overviewData.toTime - T.hours(data.overviewData.rangeToDisplay.toLong()).msecs() + data.overviewData.endTime = data.overviewData.toTime + } + + val bgListArray: MutableList = ArrayList() + val predictions: MutableList? = apsResult?.predictions + ?.map { bg -> GlucoseValueDataPoint(bg, defaultValueHelper, profileFunction, rh) } + ?.toMutableList() + if (predictions != null) { + predictions.sortWith { o1: GlucoseValueDataPoint, o2: GlucoseValueDataPoint -> o1.x.compareTo(o2.x) } + for (prediction in predictions) if (prediction.data.value >= 40) bgListArray.add(prediction) + } + data.overviewData.predictionsGraphSeries = PointsWithLabelGraphSeries(Array(bgListArray.size) { i -> bgListArray[i] }) + return Result.success() + } +} \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/androidaps/workflow/PrepareTemporaryTargetDataWorker.kt b/app/src/main/java/info/nightscout/androidaps/workflow/PrepareTemporaryTargetDataWorker.kt new file mode 100644 index 0000000000..4f960fd187 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/workflow/PrepareTemporaryTargetDataWorker.kt @@ -0,0 +1,85 @@ +package info.nightscout.androidaps.workflow + +import android.content.Context +import androidx.work.Worker +import androidx.work.WorkerParameters +import androidx.work.workDataOf +import com.jjoe64.graphview.series.DataPoint +import com.jjoe64.graphview.series.LineGraphSeries +import dagger.android.HasAndroidInjector +import info.nightscout.androidaps.R +import info.nightscout.androidaps.database.AppRepository +import info.nightscout.androidaps.database.ValueWrapper +import info.nightscout.androidaps.extensions.target +import info.nightscout.androidaps.interfaces.Loop +import info.nightscout.androidaps.interfaces.Profile +import info.nightscout.androidaps.interfaces.ProfileFunction +import info.nightscout.androidaps.plugins.bus.RxBus +import info.nightscout.androidaps.plugins.general.overview.OverviewData +import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventIobCalculationProgress +import info.nightscout.androidaps.receivers.DataWorker +import info.nightscout.androidaps.utils.resources.ResourceHelper +import javax.inject.Inject +import kotlin.math.max + +class PrepareTemporaryTargetDataWorker( + context: Context, + params: WorkerParameters +) : Worker(context, params) { + + @Inject lateinit var dataWorker: DataWorker + @Inject lateinit var profileFunction: ProfileFunction + @Inject lateinit var rh: ResourceHelper + @Inject lateinit var repository: AppRepository + @Inject lateinit var loop: Loop + @Inject lateinit var rxBus: RxBus + + init { + (context.applicationContext as HasAndroidInjector).androidInjector().inject(this) + } + + class PrepareTemporaryTargetData( + val overviewData: OverviewData + ) + + override fun doWork(): Result { + + val data = dataWorker.pickupObject(inputData.getLong(DataWorker.STORE_KEY, -1)) as PrepareTemporaryTargetData? + ?: return Result.failure(workDataOf("Error" to "missing input data")) + + rxBus.send(EventIobCalculationProgress(CalculationWorkflow.ProgressData.PREPARE_TEMPORARY_TARGET_DATA, 0, null)) + val profile = profileFunction.getProfile() ?: return Result.failure(workDataOf("Error" to "missing profile")) + val units = profileFunction.getUnits() + var toTime = data.overviewData.toTime + val targetsSeriesArray: MutableList = ArrayList() + var lastTarget = -1.0 + loop.lastRun?.constraintsProcessed?.let { toTime = max(it.latestPredictionsTime, toTime) } + var time = data.overviewData.fromTime + while (time < toTime) { + val progress = (time - data.overviewData.fromTime).toDouble() / (data.overviewData.toTime - data.overviewData.fromTime) * 100.0 + rxBus.send(EventIobCalculationProgress(CalculationWorkflow.ProgressData.PREPARE_TEMPORARY_TARGET_DATA, progress.toInt(), null)) + val tt = repository.getTemporaryTargetActiveAt(time).blockingGet() + val value: Double = if (tt is ValueWrapper.Existing) { + Profile.fromMgdlToUnits(tt.value.target(), units) + } else { + Profile.fromMgdlToUnits((profile.getTargetLowMgdl(time) + profile.getTargetHighMgdl(time)) / 2, units) + } + if (lastTarget != value) { + if (lastTarget != -1.0) targetsSeriesArray.add(DataPoint(time.toDouble(), lastTarget)) + targetsSeriesArray.add(DataPoint(time.toDouble(), value)) + } + lastTarget = value + time += 5 * 60 * 1000L + } + // final point + targetsSeriesArray.add(DataPoint(toTime.toDouble(), lastTarget)) + // create series + data.overviewData.temporaryTargetSeries = LineGraphSeries(Array(targetsSeriesArray.size) { i -> targetsSeriesArray[i] }).also { + it.isDrawBackground = false + it.color = rh.gc(R.color.tempTargetBackground) + it.thickness = 2 + } + rxBus.send(EventIobCalculationProgress(CalculationWorkflow.ProgressData.PREPARE_TEMPORARY_TARGET_DATA, 100, null)) + return Result.success() + } +} \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/androidaps/workflow/PrepareTreatmentsDataWorker.kt b/app/src/main/java/info/nightscout/androidaps/workflow/PrepareTreatmentsDataWorker.kt new file mode 100644 index 0000000000..fb96f2f697 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/workflow/PrepareTreatmentsDataWorker.kt @@ -0,0 +1,136 @@ +package info.nightscout.androidaps.workflow + +import android.content.Context +import androidx.work.Worker +import androidx.work.WorkerParameters +import androidx.work.workDataOf +import dagger.android.HasAndroidInjector +import info.nightscout.androidaps.database.AppRepository +import info.nightscout.androidaps.database.entities.Bolus +import info.nightscout.androidaps.database.entities.TherapyEvent +import info.nightscout.androidaps.interfaces.ActivePlugin +import info.nightscout.androidaps.interfaces.GlucoseUnit +import info.nightscout.androidaps.interfaces.Profile +import info.nightscout.androidaps.interfaces.ProfileFunction +import info.nightscout.androidaps.plugins.bus.RxBus +import info.nightscout.androidaps.plugins.general.overview.OverviewData +import info.nightscout.androidaps.plugins.general.overview.graphExtensions.* +import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventIobCalculationProgress +import info.nightscout.androidaps.receivers.DataWorker +import info.nightscout.androidaps.utils.DefaultValueHelper +import info.nightscout.androidaps.utils.Round +import info.nightscout.androidaps.utils.T +import info.nightscout.androidaps.utils.Translator +import info.nightscout.androidaps.utils.resources.ResourceHelper +import javax.inject.Inject + +class PrepareTreatmentsDataWorker( + context: Context, + params: WorkerParameters +) : Worker(context, params) { + + @Inject lateinit var dataWorker: DataWorker + @Inject lateinit var profileFunction: ProfileFunction + @Inject lateinit var rh: ResourceHelper + @Inject lateinit var rxBus: RxBus + @Inject lateinit var translator: Translator + @Inject lateinit var activePlugin: ActivePlugin + @Inject lateinit var repository: AppRepository + @Inject lateinit var defaultValueHelper: DefaultValueHelper + + init { + (context.applicationContext as HasAndroidInjector).androidInjector().inject(this) + } + + class PrepareTreatmentsData( + val overviewData: OverviewData + ) + + override fun doWork(): Result { + + val data = dataWorker.pickupObject(inputData.getLong(DataWorker.STORE_KEY, -1)) as PrepareTreatmentsData? + ?: return Result.failure(workDataOf("Error" to "missing input data")) + + rxBus.send(EventIobCalculationProgress(CalculationWorkflow.ProgressData.PREPARE_TREATMENTS_DATA, 0, null)) + data.overviewData.maxTreatmentsValue = 0.0 + val filteredTreatments: MutableList = ArrayList() + repository.getBolusesDataFromTimeToTime(data.overviewData.fromTime, data.overviewData.endTime, true).blockingGet() + .map { BolusDataPoint(it, rh, activePlugin, defaultValueHelper) } + .filter { it.data.type == Bolus.Type.NORMAL || it.data.type == Bolus.Type.SMB } + .forEach { + it.y = getNearestBg(data.overviewData, it.x.toLong()) + filteredTreatments.add(it) + } + repository.getCarbsDataFromTimeToTimeExpanded(data.overviewData.fromTime, data.overviewData.endTime, true).blockingGet() + .map { CarbsDataPoint(it, rh) } + .forEach { + it.y = getNearestBg(data.overviewData, it.x.toLong()) + filteredTreatments.add(it) + } + + // ProfileSwitch + repository.getEffectiveProfileSwitchDataFromTimeToTime(data.overviewData.fromTime, data.overviewData.endTime, true).blockingGet() + .map { EffectiveProfileSwitchDataPoint(it, rh) } + .forEach(filteredTreatments::add) + + // OfflineEvent + repository.getOfflineEventDataFromTimeToTime(data.overviewData.fromTime, data.overviewData.endTime, true).blockingGet() + .map { + TherapyEventDataPoint( + TherapyEvent(timestamp = it.timestamp, duration = it.duration, type = TherapyEvent.Type.APS_OFFLINE, glucoseUnit = TherapyEvent.GlucoseUnit.MMOL), + rh, + profileFunction, + translator + ) + } + .forEach(filteredTreatments::add) + + // Extended bolus + if (!activePlugin.activePump.isFakingTempsByExtendedBoluses) { + repository.getExtendedBolusDataFromTimeToTime(data.overviewData.fromTime, data.overviewData.endTime, true).blockingGet() + .map { ExtendedBolusDataPoint(it, rh) } + .filter { it.duration != 0L } + .forEach { + it.y = getNearestBg(data.overviewData, it.x.toLong()) + filteredTreatments.add(it) + } + } + + // Careportal + repository.compatGetTherapyEventDataFromToTime(data.overviewData.fromTime - T.hours(6).msecs(), data.overviewData.endTime).blockingGet() + .map { TherapyEventDataPoint(it, rh, profileFunction, translator) } + .filterTimeframe(data.overviewData.fromTime, data.overviewData.endTime) + .forEach { + if (it.y == 0.0) it.y = getNearestBg(data.overviewData, it.x.toLong()) + filteredTreatments.add(it) + } + + // increase maxY if a treatment forces it's own height that's higher than a BG value + filteredTreatments.map { it.y } + .maxOrNull() + ?.let(::addUpperChartMargin) + ?.let { data.overviewData.maxTreatmentsValue = maxOf(data.overviewData.maxTreatmentsValue, it) } + + data.overviewData.treatmentsSeries = PointsWithLabelGraphSeries(filteredTreatments.toTypedArray()) + + rxBus.send(EventIobCalculationProgress(CalculationWorkflow.ProgressData.PREPARE_TREATMENTS_DATA, 100, null)) + return Result.success() + } + + private fun addUpperChartMargin(maxBgValue: Double) = + if (profileFunction.getUnits() == GlucoseUnit.MGDL) Round.roundTo(maxBgValue, 40.0) + 80 else Round.roundTo(maxBgValue, 2.0) + 4 + + private fun getNearestBg(overviewData: OverviewData, date: Long): Double { + overviewData.bgReadingsArray.let { bgReadingsArray -> + for (reading in bgReadingsArray) { + if (reading.timestamp > date) continue + return Profile.fromMgdlToUnits(reading.value, profileFunction.getUnits()) + } + return if (bgReadingsArray.isNotEmpty()) Profile.fromMgdlToUnits(bgReadingsArray[0].value, profileFunction.getUnits()) + else Profile.fromMgdlToUnits(100.0, profileFunction.getUnits()) + } + } + + private fun List.filterTimeframe(fromTime: Long, endTime: Long): List = + filter { it.x + it.duration >= fromTime && it.x <= endTime } +} \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/androidaps/workflow/UpdateGraphWorker.kt b/app/src/main/java/info/nightscout/androidaps/workflow/UpdateGraphWorker.kt new file mode 100644 index 0000000000..3038afcd6b --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/workflow/UpdateGraphWorker.kt @@ -0,0 +1,31 @@ +package info.nightscout.androidaps.workflow + +import android.content.Context +import androidx.work.Worker +import androidx.work.WorkerParameters +import dagger.android.HasAndroidInjector +import info.nightscout.androidaps.plugins.bus.RxBus +import info.nightscout.androidaps.plugins.general.overview.OverviewPlugin +import info.nightscout.androidaps.plugins.general.overview.events.EventUpdateOverviewGraph +import javax.inject.Inject + +class UpdateGraphWorker( + context: Context, + params: WorkerParameters +) : Worker(context, params) { + + @Inject lateinit var rxBus: RxBus + @Inject lateinit var overviewPlugin: OverviewPlugin + + init { + (context.applicationContext as HasAndroidInjector).androidInjector().inject(this) + } + + override fun doWork(): Result { + if (inputData.getString(CalculationWorkflow.JOB) == CalculationWorkflow.MAIN_CALCULATION) + overviewPlugin.overviewBus.send(EventUpdateOverviewGraph("UpdateGraphWorker")) + else + rxBus.send(EventUpdateOverviewGraph("UpdateGraphWorker")) + return Result.success() + } +} \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/androidaps/workflow/UpdateIobCobSensWorker.kt b/app/src/main/java/info/nightscout/androidaps/workflow/UpdateIobCobSensWorker.kt new file mode 100644 index 0000000000..5f611e130c --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/workflow/UpdateIobCobSensWorker.kt @@ -0,0 +1,30 @@ +package info.nightscout.androidaps.workflow + +import android.content.Context +import androidx.work.Worker +import androidx.work.WorkerParameters +import dagger.android.HasAndroidInjector +import info.nightscout.androidaps.plugins.bus.RxBus +import info.nightscout.androidaps.plugins.general.overview.OverviewPlugin +import info.nightscout.androidaps.plugins.general.overview.events.EventUpdateOverviewIobCob +import info.nightscout.androidaps.plugins.general.overview.events.EventUpdateOverviewSensitivity +import javax.inject.Inject + +class UpdateIobCobSensWorker( + context: Context, + params: WorkerParameters +) : Worker(context, params) { + + @Inject lateinit var rxBus: RxBus + @Inject lateinit var overviewPlugin: OverviewPlugin + + init { + (context.applicationContext as HasAndroidInjector).androidInjector().inject(this) + } + + override fun doWork(): Result { + overviewPlugin.overviewBus.send(EventUpdateOverviewIobCob("UpdateIobCobSensWorker")) + overviewPlugin.overviewBus.send(EventUpdateOverviewSensitivity("UpdateIobCobSensWorker")) + return Result.success() + } +} \ No newline at end of file diff --git a/app/src/main/res/layout/activity_historybrowse.xml b/app/src/main/res/layout/activity_historybrowse.xml index 4e73fabec5..f3792b7e91 100644 --- a/app/src/main/res/layout/activity_historybrowse.xml +++ b/app/src/main/res/layout/activity_historybrowse.xml @@ -63,6 +63,17 @@ + + - - (automationEvents).iterator() + val iterator = ArrayList(automationEvents).iterator() try { while (iterator.hasNext()) { val event = iterator.next() diff --git a/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionsTestBase.kt b/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionsTestBase.kt index 5f52cac608..d1abc821dc 100644 --- a/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionsTestBase.kt +++ b/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionsTestBase.kt @@ -38,6 +38,7 @@ ActionsTestBase : TestBaseWithProfile() { override var enabled: Boolean get() = true set(_) {} + override var lastBgTriggeredRun: Long = 0 override fun invoke(initiator: String, allowNotification: Boolean, tempBasalFallback: Boolean) {} override fun acceptChangeRequest() {} diff --git a/core/src/main/java/info/nightscout/androidaps/events/EventAutosensCalculationFinished.kt b/core/src/main/java/info/nightscout/androidaps/events/EventAutosensCalculationFinished.kt index 32eff6350f..d6bcb8bde9 100644 --- a/core/src/main/java/info/nightscout/androidaps/events/EventAutosensCalculationFinished.kt +++ b/core/src/main/java/info/nightscout/androidaps/events/EventAutosensCalculationFinished.kt @@ -1,6 +1,3 @@ package info.nightscout.androidaps.events -import info.nightscout.androidaps.events.Event -import info.nightscout.androidaps.events.EventLoop - class EventAutosensCalculationFinished(val cause: Event?) : EventLoop() diff --git a/core/src/main/java/info/nightscout/androidaps/events/EventDanaRSyncStatus.kt b/core/src/main/java/info/nightscout/androidaps/events/EventDanaRSyncStatus.kt index 152a45491f..d30180eeb1 100644 --- a/core/src/main/java/info/nightscout/androidaps/events/EventDanaRSyncStatus.kt +++ b/core/src/main/java/info/nightscout/androidaps/events/EventDanaRSyncStatus.kt @@ -1,5 +1,3 @@ package info.nightscout.androidaps.events -import info.nightscout.androidaps.events.Event - class EventDanaRSyncStatus(var message: String) : Event() \ No newline at end of file diff --git a/core/src/main/java/info/nightscout/androidaps/extensions/UIUtils.kt b/core/src/main/java/info/nightscout/androidaps/extensions/UIUtils.kt index fcde955752..874ce798e6 100644 --- a/core/src/main/java/info/nightscout/androidaps/extensions/UIUtils.kt +++ b/core/src/main/java/info/nightscout/androidaps/extensions/UIUtils.kt @@ -5,6 +5,7 @@ import android.os.Looper import android.view.View fun Boolean.toVisibility() = if (this) View.VISIBLE else View.GONE +fun Boolean.toVisibilityKeepSpace() = if (this) View.VISIBLE else View.INVISIBLE fun runOnUiThread(theRunnable: Runnable?) = theRunnable?.let { Handler(Looper.getMainLooper()).post(it) diff --git a/core/src/main/java/info/nightscout/androidaps/interfaces/ActivePlugin.kt b/core/src/main/java/info/nightscout/androidaps/interfaces/ActivePlugin.kt index da514c7dd9..74db9b2635 100644 --- a/core/src/main/java/info/nightscout/androidaps/interfaces/ActivePlugin.kt +++ b/core/src/main/java/info/nightscout/androidaps/interfaces/ActivePlugin.kt @@ -52,6 +52,12 @@ interface ActivePlugin { */ val activeSafety: Safety + /** + * Currently selected Safety plugin + * Always IobCobCalculatorPlugin + */ + val activeIobCobCalculator: IobCobCalculator + /** * List of all registered plugins */ diff --git a/core/src/main/java/info/nightscout/androidaps/interfaces/Loop.kt b/core/src/main/java/info/nightscout/androidaps/interfaces/Loop.kt index 80e43e7e94..fdf44f4661 100644 --- a/core/src/main/java/info/nightscout/androidaps/interfaces/Loop.kt +++ b/core/src/main/java/info/nightscout/androidaps/interfaces/Loop.kt @@ -28,6 +28,8 @@ interface Loop { val isDisconnected: Boolean var enabled: Boolean + var lastBgTriggeredRun: Long + fun invoke(initiator: String, allowNotification: Boolean, tempBasalFallback: Boolean = false) fun acceptChangeRequest() diff --git a/core/src/main/java/info/nightscout/androidaps/interfaces/Overview.kt b/core/src/main/java/info/nightscout/androidaps/interfaces/Overview.kt index 729a855ae8..ac2e321155 100644 --- a/core/src/main/java/info/nightscout/androidaps/interfaces/Overview.kt +++ b/core/src/main/java/info/nightscout/androidaps/interfaces/Overview.kt @@ -4,6 +4,5 @@ import info.nightscout.androidaps.plugins.bus.RxBus interface Overview : ConfigExportImport { - fun refreshLoop(from: String) val overviewBus: RxBus } \ No newline at end of file diff --git a/core/src/main/java/info/nightscout/androidaps/interfaces/Sensitivity.kt b/core/src/main/java/info/nightscout/androidaps/interfaces/Sensitivity.kt index b15d2a976c..9ad4e15330 100644 --- a/core/src/main/java/info/nightscout/androidaps/interfaces/Sensitivity.kt +++ b/core/src/main/java/info/nightscout/androidaps/interfaces/Sensitivity.kt @@ -20,6 +20,7 @@ interface Sensitivity : ConfigExportImport { val id: SensitivityType fun detectSensitivity(ads: AutosensDataStore, fromTime: Long, toTime: Long): AutosensResult + fun maxAbsorptionHours(): Double companion object { diff --git a/core/src/main/res/values-night/colors.xml b/core/src/main/res/values-night/colors.xml index f4b913e290..b12d342936 100644 --- a/core/src/main/res/values-night/colors.xml +++ b/core/src/main/res/values-night/colors.xml @@ -234,6 +234,9 @@ #33969696 #EBEBEA + #000000 + #B3FFFFFF + #FFFF00 #00FFFF diff --git a/core/src/main/res/values-night/styles.xml b/core/src/main/res/values-night/styles.xml index b0b4a086b6..67d8b27049 100644 --- a/core/src/main/res/values-night/styles.xml +++ b/core/src/main/res/values-night/styles.xml @@ -225,6 +225,7 @@ @color/activity @color/plastic_grey + @color/textAppearancemediumDark