diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index e837d2ce87..77b68adf4a 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -68,7 +68,7 @@ - + () + private val secondaryGraphsLabel = ArrayList() + + private var axisWidth: Int = 0 + private var rangeToDisplay = 24 // for graph +// private var start: Long = 0 + + private lateinit var iobCobCalculator: IobCobCalculatorPlugin + private lateinit var overviewData: OverviewData + + private lateinit var binding: ActivityHistorybrowseBinding + private var destroyed = false + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + binding = ActivityHistorybrowseBinding.inflate(layoutInflater) + setContentView(binding.root) + + // We don't want to use injected singletons but own instance working on top of different data + iobCobCalculator = IobCobCalculatorPlugin(injector, aapsLogger, aapsSchedulers, rxBus, sp, resourceHelper, profileFunction, activePlugin, sensitivityOref1Plugin, sensitivityAAPSPlugin, sensitivityWeightedAveragePlugin, fabricPrivacy, dateUtil, repository) + overviewData = OverviewData(injector, aapsLogger, resourceHelper, dateUtil, sp, activePlugin, defaultValueHelper, profileFunction, config, loopPlugin, nsDeviceStatus, repository, overviewMenus, iobCobCalculator, translator) + + binding.left.setOnClickListener { + setTime(overviewData.fromTime - T.hours(rangeToDisplay.toLong()).msecs()) + loadAll("onClickLeft") + } + binding.right.setOnClickListener { + setTime(overviewData.fromTime + T.hours(rangeToDisplay.toLong()).msecs()) + loadAll("onClickRight") + } + binding.end.setOnClickListener { + setTime(dateUtil.now()) + loadAll("onClickEnd") + } + binding.zoom.setOnClickListener { + rangeToDisplay += 6 + rangeToDisplay = if (rangeToDisplay > 24) 6 else rangeToDisplay + setTime(overviewData.fromTime) + loadAll("rangeChange") + } + binding.zoom.setOnLongClickListener { + Calendar.getInstance().also { calendar -> + calendar.timeInMillis = overviewData.fromTime + calendar[Calendar.MILLISECOND] = 0 + calendar[Calendar.SECOND] = 0 + calendar[Calendar.MINUTE] = 0 + calendar[Calendar.HOUR_OF_DAY] = 0 + setTime(calendar.timeInMillis) + } + loadAll("onLongClickZoom") + true + } + + // create an OnDateSetListener + val dateSetListener = DatePickerDialog.OnDateSetListener { _, year, monthOfYear, dayOfMonth -> + Calendar.getInstance().also { calendar -> + calendar.timeInMillis = overviewData.fromTime + calendar[Calendar.YEAR] = year + calendar[Calendar.MONTH] = monthOfYear + calendar[Calendar.DAY_OF_MONTH] = dayOfMonth + calendar[Calendar.MILLISECOND] = 0 + calendar[Calendar.SECOND] = 0 + calendar[Calendar.MINUTE] = 0 + calendar[Calendar.HOUR_OF_DAY] = 0 + setTime(calendar.timeInMillis) + binding.date.text = dateUtil.dateAndTimeString(overviewData.fromTime) + } + loadAll("onClickDate") + } + + binding.date.setOnClickListener { + val cal = Calendar.getInstance() + cal.timeInMillis = overviewData.fromTime + DatePickerDialog(this, dateSetListener, + cal.get(Calendar.YEAR), + cal.get(Calendar.MONTH), + cal.get(Calendar.DAY_OF_MONTH) + ).show() + } + + val dm = DisplayMetrics() + windowManager?.defaultDisplay?.getMetrics(dm) + + 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 = resourceHelper.gc(R.color.graphgrid) + binding.bgGraph.gridLabelRenderer?.reloadStyles() + binding.bgGraph.gridLabelRenderer?.labelVerticalWidth = axisWidth + + overviewMenus.setupChartMenu(binding.chartMenuButton) + prepareGraphsIfNeeded(overviewMenus.setting.size) + savedInstanceState?.let { bundle -> + rangeToDisplay = bundle.getInt("rangeToDisplay", 0) + overviewData.fromTime = bundle.getLong("start", 0) + overviewData.toTime = bundle.getLong("end", 0) + } + } + + public override fun onPause() { + super.onPause() + disposable.clear() + iobCobCalculator.stopCalculation("onPause") + } + + @Synchronized + override fun onDestroy() { + destroyed = true + super.onDestroy() + } + + public override fun onResume() { + super.onResume() + disposable.add(rxBus + .toObservable(EventAutosensCalculationFinished::class.java) + .observeOn(aapsSchedulers.io) + .subscribe({ + // catch only events from iobCobCalculator + if (it.cause is EventCustomCalculationFinished) + refreshLoop("EventAutosensCalculationFinished") + }, fabricPrivacy::logException) + ) + disposable.add(rxBus + .toObservable(EventIobCalculationProgress::class.java) + .observeOn(aapsSchedulers.main) + .subscribe({ + if (it.cause is EventCustomCalculationFinished) + binding.overviewIobcalculationprogess.text = it.progress + }, fabricPrivacy::logException) + ) + disposable.add(rxBus + .toObservable(EventRefreshOverview::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 + setTime(dateUtil.now()) + loadAll("onResume") + } else { + updateGUI("onResume") + } + } + + override fun onSaveInstanceState(outState: Bundle) { + super.onSaveInstanceState(outState) + outState.putInt("rangeToDisplay", rangeToDisplay) + outState.putLong("start", overviewData.fromTime) + outState.putLong("end", overviewData.toTime) + + } + + private fun prepareGraphsIfNeeded(numOfGraphs: Int) { + if (numOfGraphs != secondaryGraphs.size - 1) { + //aapsLogger.debug("New secondary graph count ${numOfGraphs-1}") + // rebuild needed + secondaryGraphs.clear() + secondaryGraphsLabel.clear() + binding.iobGraph.removeAllViews() + for (i in 1 until numOfGraphs) { + val relativeLayout = RelativeLayout(this) + relativeLayout.layoutParams = RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT) + + val graph = GraphView(this) + graph.layoutParams = LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, resourceHelper.dpToPx(100)).also { it.setMargins(0, resourceHelper.dpToPx(15), 0, resourceHelper.dpToPx(10)) } + graph.gridLabelRenderer?.gridColor = resourceHelper.gc(R.color.graphgrid) + graph.gridLabelRenderer?.reloadStyles() + graph.gridLabelRenderer?.isHorizontalLabelsVisible = false + graph.gridLabelRenderer?.labelVerticalWidth = axisWidth + graph.gridLabelRenderer?.numVerticalLabels = 3 + graph.viewport.backgroundColor = Color.argb(20, 255, 255, 255) // 8% of gray + relativeLayout.addView(graph) + + val label = TextView(this) + val layoutParams = RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT).also { it.setMargins(resourceHelper.dpToPx(30), resourceHelper.dpToPx(25), 0, 0) } + layoutParams.addRule(RelativeLayout.ALIGN_PARENT_TOP) + layoutParams.addRule(RelativeLayout.ALIGN_PARENT_LEFT) + label.layoutParams = layoutParams + relativeLayout.addView(label) + secondaryGraphsLabel.add(label) + + binding.iobGraph.addView(relativeLayout) + secondaryGraphs.add(graph) + } + } + } + + @Suppress("SameParameterValue") + private fun loadAll(from: String) { + Thread { + overviewData.prepareBasalData(from) + overviewData.prepareTemporaryTargetData(from) + overviewData.prepareTreatmentsData(from) + rxBus.send(EventRefreshOverview(from)) + aapsLogger.debug(LTag.UI, "loadAll $from finished") + runCalculation(from) + }.start() + } + + private fun setTime(start: Long) { + Calendar.getInstance().also { calendar -> + calendar.timeInMillis = start + calendar[Calendar.MILLISECOND] = 0 + calendar[Calendar.SECOND] = 0 + calendar[Calendar.MINUTE] = 0 + calendar[Calendar.HOUR_OF_DAY] = 0 + overviewData.fromTime = calendar.timeInMillis + overviewData.toTime = overviewData.fromTime + T.hours(rangeToDisplay.toLong()).msecs() + overviewData.endTime = overviewData.toTime + } + } + + private fun runCalculation(from: String) { + Thread { + iobCobCalculator.stopCalculation(from) + iobCobCalculator.stopCalculationTrigger = false + iobCobCalculator.runCalculation(from, overviewData.toTime, bgDataReload = true, limitDataToOldestAvailable = false, cause = EventCustomCalculationFinished()) + }.start() + } + + @Volatile + var runningRefresh = false + 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 + } + + @Suppress("UNUSED_PARAMETER") + @SuppressLint("SetTextI18n") + fun updateGUI(from: String) { + aapsLogger.debug(LTag.UI, "updateGui $from") + + binding.date.text = dateUtil.dateAndTimeString(overviewData.fromTime) + binding.zoom.text = rangeToDisplay.toString() + + val pump = activePlugin.activePump + val graphData = GraphData(injector, binding.bgGraph, overviewData) + val menuChartSettings = overviewMenus.setting + graphData.addInRangeArea(overviewData.fromTime, overviewData.endTime, defaultValueHelper.determineLowLine(), defaultValueHelper.determineHighLine()) + graphData.addBgReadings(menuChartSettings[0][OverviewMenus.CharType.PRE.ordinal]) + if (buildHelper.isDev()) graphData.addBucketedData() + graphData.addTreatments() + if (menuChartSettings[0][OverviewMenus.CharType.ACT.ordinal]) + graphData.addActivity(0.8) + if (pump.pumpDescription.isTempBasalCapable && menuChartSettings[0][OverviewMenus.CharType.BAS.ordinal]) + graphData.addBasals() + graphData.addTargetLine() + graphData.addNowLine(dateUtil.now()) + + // set manual x bounds to have nice steps + graphData.setNumVerticalLabels() + graphData.formatAxis(overviewData.fromTime, overviewData.endTime) + + graphData.performUpdate() + + // 2nd graphs + prepareGraphsIfNeeded(menuChartSettings.size) + val secondaryGraphsData: ArrayList = ArrayList() + + val now = System.currentTimeMillis() + for (g in 0 until min(secondaryGraphs.size, menuChartSettings.size + 1)) { + val secondGraphData = GraphData(injector, secondaryGraphs[g], overviewData) + var useABSForScale = false + var useIobForScale = false + var useCobForScale = false + var useDevForScale = false + var useRatioForScale = false + 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.DEVSLOPE.ordinal] -> useDSForScale = true + } + val alignDevBgiScale = menuChartSettings[g + 1][OverviewMenus.CharType.DEV.ordinal] && menuChartSettings[g + 1][OverviewMenus.CharType.BGI.ordinal] + + if (menuChartSettings[g + 1][OverviewMenus.CharType.ABS.ordinal]) secondGraphData.addAbsIob(useABSForScale, 1.0) + if (menuChartSettings[g + 1][OverviewMenus.CharType.IOB.ordinal]) secondGraphData.addIob(useIobForScale, 1.0) + if (menuChartSettings[g + 1][OverviewMenus.CharType.COB.ordinal]) secondGraphData.addCob(useCobForScale, if (useCobForScale) 1.0 else 0.5) + if (menuChartSettings[g + 1][OverviewMenus.CharType.DEV.ordinal]) secondGraphData.addDeviations(useDevForScale, 1.0) + if (menuChartSettings[g + 1][OverviewMenus.CharType.BGI.ordinal]) secondGraphData.addMinusBGI(useBGIForScale, if (alignDevBgiScale) 1.0 else 0.8) + if (menuChartSettings[g + 1][OverviewMenus.CharType.SEN.ordinal]) secondGraphData.addRatio(useRatioForScale, if (useRatioForScale) 1.0 else 0.8) + if (menuChartSettings[g + 1][OverviewMenus.CharType.DEVSLOPE.ordinal] && buildHelper.isDev()) secondGraphData.addDeviationSlope(useDSForScale, 1.0) + + // set manual x bounds to have nice steps + secondGraphData.formatAxis(overviewData.fromTime, overviewData.endTime) + secondGraphData.addNowLine(now) + secondaryGraphsData.add(secondGraphData) + } + for (g in 0 until min(secondaryGraphs.size, menuChartSettings.size + 1)) { + secondaryGraphsLabel[g].text = overviewMenus.enabledTypes(g + 1) + secondaryGraphs[g].visibility = ( + menuChartSettings[g + 1][OverviewMenus.CharType.ABS.ordinal] || + menuChartSettings[g + 1][OverviewMenus.CharType.IOB.ordinal] || + menuChartSettings[g + 1][OverviewMenus.CharType.COB.ordinal] || + menuChartSettings[g + 1][OverviewMenus.CharType.DEV.ordinal] || + menuChartSettings[g + 1][OverviewMenus.CharType.BGI.ordinal] || + menuChartSettings[g + 1][OverviewMenus.CharType.SEN.ordinal] || + menuChartSettings[g + 1][OverviewMenus.CharType.DEVSLOPE.ordinal] + ).toVisibility() + secondaryGraphsData[g].performUpdate() + } + } +} \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/androidaps/dependencyInjection/ActivitiesModule.kt b/app/src/main/java/info/nightscout/androidaps/dependencyInjection/ActivitiesModule.kt index fa8bfa0598..08e25f456f 100644 --- a/app/src/main/java/info/nightscout/androidaps/dependencyInjection/ActivitiesModule.kt +++ b/app/src/main/java/info/nightscout/androidaps/dependencyInjection/ActivitiesModule.kt @@ -4,7 +4,7 @@ import dagger.Module import dagger.android.ContributesAndroidInjector import info.nightscout.androidaps.MainActivity import info.nightscout.androidaps.activities.* -import info.nightscout.androidaps.historyBrowser.HistoryBrowseActivity +import info.nightscout.androidaps.activities.HistoryBrowseActivity import info.nightscout.androidaps.plugins.general.maintenance.activities.LogSettingActivity import info.nightscout.androidaps.plugins.general.openhumans.OpenHumansLoginActivity import info.nightscout.androidaps.plugins.general.overview.activities.QuickWizardListActivity diff --git a/app/src/main/java/info/nightscout/androidaps/dialogs/CarbsDialog.kt b/app/src/main/java/info/nightscout/androidaps/dialogs/CarbsDialog.kt index 9d4e34a89b..214847aff9 100644 --- a/app/src/main/java/info/nightscout/androidaps/dialogs/CarbsDialog.kt +++ b/app/src/main/java/info/nightscout/androidaps/dialogs/CarbsDialog.kt @@ -27,7 +27,6 @@ import info.nightscout.androidaps.interfaces.ProfileFunction import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.logging.UserEntryLogger import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker -import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin import info.nightscout.androidaps.queue.Callback import info.nightscout.androidaps.queue.CommandQueue import info.nightscout.androidaps.utils.* @@ -47,7 +46,6 @@ class CarbsDialog : DialogFragmentWithDate() { @Inject lateinit var resourceHelper: ResourceHelper @Inject lateinit var constraintChecker: ConstraintChecker @Inject lateinit var defaultValueHelper: DefaultValueHelper - @Inject lateinit var treatmentsPlugin: TreatmentsPlugin @Inject lateinit var profileFunction: ProfileFunction @Inject lateinit var iobCobCalculator: IobCobCalculator @Inject lateinit var uel: UserEntryLogger diff --git a/app/src/main/java/info/nightscout/androidaps/historyBrowser/HistoryBrowseActivity.kt b/app/src/main/java/info/nightscout/androidaps/historyBrowser/HistoryBrowseActivity.kt deleted file mode 100644 index 1abda3295f..0000000000 --- a/app/src/main/java/info/nightscout/androidaps/historyBrowser/HistoryBrowseActivity.kt +++ /dev/null @@ -1,379 +0,0 @@ -package info.nightscout.androidaps.historyBrowser - -import android.app.DatePickerDialog -import android.graphics.Color -import android.os.Bundle -import android.util.DisplayMetrics -import android.view.ViewGroup -import android.widget.LinearLayout -import android.widget.RelativeLayout -import android.widget.TextView -import androidx.lifecycle.lifecycleScope -import com.jjoe64.graphview.GraphView -import dagger.android.HasAndroidInjector -import info.nightscout.androidaps.R -import info.nightscout.androidaps.activities.NoSplashAppCompatActivity -import info.nightscout.androidaps.databinding.ActivityHistorybrowseBinding -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.interfaces.ActivePlugin -import info.nightscout.androidaps.interfaces.ProfileFunction -import info.nightscout.androidaps.logging.AAPSLogger -import info.nightscout.androidaps.logging.LTag -import info.nightscout.androidaps.plugins.bus.RxBusWrapper -import info.nightscout.androidaps.plugins.general.overview.OverviewMenus -import info.nightscout.androidaps.plugins.general.overview.graphData.GraphData -import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventIobCalculationProgress -import info.nightscout.androidaps.utils.DateUtil -import info.nightscout.androidaps.utils.DefaultValueHelper -import info.nightscout.androidaps.utils.FabricPrivacy -import info.nightscout.androidaps.utils.T -import info.nightscout.androidaps.utils.buildHelper.BuildHelper -import info.nightscout.androidaps.utils.rx.AapsSchedulers -import info.nightscout.androidaps.utils.sharedPreferences.SP -import io.reactivex.disposables.CompositeDisposable -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.launch -import kotlinx.coroutines.withContext -import java.util.* -import javax.inject.Inject - -class HistoryBrowseActivity : NoSplashAppCompatActivity() { - - @Inject lateinit var injector: HasAndroidInjector - @Inject lateinit var aapsLogger: AAPSLogger - @Inject lateinit var aapsSchedulers: AapsSchedulers - @Inject lateinit var rxBus: RxBusWrapper - @Inject lateinit var sp: SP - @Inject lateinit var profileFunction: ProfileFunction - @Inject lateinit var defaultValueHelper: DefaultValueHelper - @Inject lateinit var iobCobCalculatorPluginHistory: IobCobCalculatorPluginHistory - @Inject lateinit var activePlugin: ActivePlugin - @Inject lateinit var buildHelper: BuildHelper - @Inject lateinit var fabricPrivacy: FabricPrivacy - @Inject lateinit var overviewMenus: OverviewMenus - @Inject lateinit var dateUtil: DateUtil - - private val disposable = CompositeDisposable() - - private val secondaryGraphs = ArrayList() - private val secondaryGraphsLabel = ArrayList() - - private var axisWidth: Int = 0 - private var rangeToDisplay = 24 // for graph - private var start: Long = 0 - - private val graphLock = Object() - - private var eventCustomCalculationFinished = EventCustomCalculationFinished() - - private lateinit var binding: ActivityHistorybrowseBinding - private var destroyed = false - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - binding = ActivityHistorybrowseBinding.inflate(layoutInflater) - setContentView(binding.root) - - binding.left.setOnClickListener { - start -= T.hours(rangeToDisplay.toLong()).msecs() - runCalculation("onClickLeft") - } - binding.right.setOnClickListener { - start += T.hours(rangeToDisplay.toLong()).msecs() - runCalculation("onClickRight") - } - binding.end.setOnClickListener { - val calendar = Calendar.getInstance() - calendar.timeInMillis = System.currentTimeMillis() - calendar[Calendar.MILLISECOND] = 0 - calendar[Calendar.SECOND] = 0 - calendar[Calendar.MINUTE] = 0 - calendar[Calendar.HOUR_OF_DAY] = 0 - start = calendar.timeInMillis - runCalculation("onClickEnd") - } - binding.zoom.setOnClickListener { - rangeToDisplay += 6 - rangeToDisplay = if (rangeToDisplay > 24) 6 else rangeToDisplay - updateGUI("rangeChange", false) - } - binding.zoom.setOnLongClickListener { - val calendar = Calendar.getInstance() - calendar.timeInMillis = start - calendar[Calendar.MILLISECOND] = 0 - calendar[Calendar.SECOND] = 0 - calendar[Calendar.MINUTE] = 0 - calendar[Calendar.HOUR_OF_DAY] = 0 - start = calendar.timeInMillis - runCalculation("onLongClickZoom") - true - } - - // create an OnDateSetListener - val dateSetListener = DatePickerDialog.OnDateSetListener { _, year, monthOfYear, dayOfMonth -> - val cal = Calendar.getInstance() - cal.timeInMillis = start - cal[Calendar.YEAR] = year - cal[Calendar.MONTH] = monthOfYear - cal[Calendar.DAY_OF_MONTH] = dayOfMonth - cal[Calendar.MILLISECOND] = 0 - cal[Calendar.SECOND] = 0 - cal[Calendar.MINUTE] = 0 - cal[Calendar.HOUR_OF_DAY] = 0 - start = cal.timeInMillis - binding.date.text = dateUtil.dateAndTimeString(start) - runCalculation("onClickDate") - } - - binding.date.setOnClickListener { - val cal = Calendar.getInstance() - cal.timeInMillis = start - DatePickerDialog(this, dateSetListener, - cal.get(Calendar.YEAR), - cal.get(Calendar.MONTH), - cal.get(Calendar.DAY_OF_MONTH) - ).show() - } - - val dm = DisplayMetrics() - windowManager?.defaultDisplay?.getMetrics(dm) - - 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 = resourceHelper.gc(R.color.graphgrid) - binding.bggraph.gridLabelRenderer?.reloadStyles() - binding.bggraph.gridLabelRenderer?.labelVerticalWidth = axisWidth - - overviewMenus.setupChartMenu(binding.chartMenuButton) - prepareGraphsIfNeeded(overviewMenus.setting.size) - savedInstanceState?.let { bundle -> - rangeToDisplay = bundle.getInt("rangeToDisplay", 0) - start = bundle.getLong("start", 0) - } - - } - - public override fun onPause() { - super.onPause() - disposable.clear() - iobCobCalculatorPluginHistory.stopCalculation("onPause") - } - - @Synchronized - override fun onDestroy() { - destroyed = true - super.onDestroy() - } - - public override fun onResume() { - super.onResume() - disposable.add(rxBus - .toObservable(EventAutosensCalculationFinished::class.java) - .observeOn(aapsSchedulers.io) - .subscribe({ - // catch only events from iobCobCalculatorPluginHistory - if (it.cause is EventCustomCalculationFinished) { - updateGUI("EventAutosensCalculationFinished", bgOnly = false) - } - }, fabricPrivacy::logException) - ) - disposable.add(rxBus - .toObservable(EventIobCalculationProgress::class.java) - .observeOn(aapsSchedulers.main) - .subscribe({ binding.overviewIobcalculationprogess.text = it.progress }, fabricPrivacy::logException) - ) - disposable.add(rxBus - .toObservable(EventRefreshOverview::class.java) - .observeOn(aapsSchedulers.main) - .subscribe({ - if (it.now) { - updateGUI("EventRefreshOverview", bgOnly = false) - } - }, fabricPrivacy::logException) - ) - if (start == 0L) { - // set start of current day - val calendar = Calendar.getInstance() - calendar.timeInMillis = System.currentTimeMillis() - calendar[Calendar.MILLISECOND] = 0 - calendar[Calendar.SECOND] = 0 - calendar[Calendar.MINUTE] = 0 - calendar[Calendar.HOUR_OF_DAY] = 0 - start = calendar.timeInMillis - runCalculation("onResume") - } else { - updateGUI("onResume", bgOnly = false) - } - } - - override fun onSaveInstanceState(outState: Bundle) { - super.onSaveInstanceState(outState) - outState.putInt("rangeToDisplay", rangeToDisplay) - outState.putLong("start", start) - - } - - private fun prepareGraphsIfNeeded(numOfGraphs: Int) { - synchronized(graphLock) { - if (numOfGraphs != secondaryGraphs.size - 1) { - //aapsLogger.debug("New secondary graph count ${numOfGraphs-1}") - // rebuild needed - secondaryGraphs.clear() - secondaryGraphsLabel.clear() - binding.iobGraph.removeAllViews() - for (i in 1 until numOfGraphs) { - val relativeLayout = RelativeLayout(this) - relativeLayout.layoutParams = RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT) - - val graph = GraphView(this) - graph.layoutParams = LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, resourceHelper.dpToPx(100)).also { it.setMargins(0, resourceHelper.dpToPx(15), 0, resourceHelper.dpToPx(10)) } - graph.gridLabelRenderer?.gridColor = resourceHelper.gc(R.color.graphgrid) - graph.gridLabelRenderer?.reloadStyles() - graph.gridLabelRenderer?.isHorizontalLabelsVisible = false - graph.gridLabelRenderer?.labelVerticalWidth = axisWidth - graph.gridLabelRenderer?.numVerticalLabels = 3 - graph.viewport.backgroundColor = Color.argb(20, 255, 255, 255) // 8% of gray - relativeLayout.addView(graph) - - val label = TextView(this) - val layoutParams = RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT).also { it.setMargins(resourceHelper.dpToPx(30), resourceHelper.dpToPx(25), 0, 0) } - layoutParams.addRule(RelativeLayout.ALIGN_PARENT_TOP) - layoutParams.addRule(RelativeLayout.ALIGN_PARENT_LEFT) - label.layoutParams = layoutParams - relativeLayout.addView(label) - secondaryGraphsLabel.add(label) - - binding.iobGraph.addView(relativeLayout) - secondaryGraphs.add(graph) - } - } - } - } - - private fun runCalculation(from: String) { - lifecycleScope.launch(Dispatchers.Default) { - val end = start + T.hours(rangeToDisplay.toLong()).msecs() - iobCobCalculatorPluginHistory.stopCalculation(from) - iobCobCalculatorPluginHistory.clearCache() - iobCobCalculatorPluginHistory.runCalculation(from, end, bgDataReload = true, limitDataToOldestAvailable = false, cause = eventCustomCalculationFinished) - } - } - - @Synchronized - fun updateGUI(from: String, bgOnly: Boolean) { - val menuChartSettings = overviewMenus.setting - prepareGraphsIfNeeded(menuChartSettings.size) - aapsLogger.debug(LTag.UI, "updateGUI from: $from") - val pump = activePlugin.activePump - val profile = profileFunction.getProfile() - - val lowLine = defaultValueHelper.determineLowLine() - val highLine = defaultValueHelper.determineHighLine() - - lifecycleScope.launch(Dispatchers.Main) { - binding.noprofile.visibility = (profile == null).toVisibility() - profile ?: return@launch - - if (destroyed) return@launch - binding.date.text = dateUtil.dateAndTimeString(start) - binding.zoom.text = rangeToDisplay.toString() - val graphData = GraphData(injector, binding.bggraph) - val secondaryGraphsData: ArrayList = ArrayList() - - // do preparation in different thread - withContext(Dispatchers.Default) { - val fromTime: Long = start + T.secs(100).msecs() - val toTime: Long = start + T.hours(rangeToDisplay.toLong()).msecs() + T.secs(100).msecs() - aapsLogger.debug(LTag.UI, "Period: " + dateUtil.dateAndTimeString(fromTime) + " - " + dateUtil.dateAndTimeString(toTime)) - val pointer = System.currentTimeMillis() - - // **** In range Area **** - graphData.addInRangeArea(fromTime, toTime, lowLine, highLine) - - // **** BG **** -// graphData.addBgReadings(fromTime, toTime, highLine, null) -// if (buildHelper.isDev()) graphData.addBucketedData(fromTime, toTime) - - // add target line -// graphData.addTargetLine(fromTime, toTime, profile, null) - - // **** NOW line **** - graphData.addNowLine(pointer) - - if (!bgOnly) { - // Treatments -// graphData.addTreatments(fromTime, toTime) - if (menuChartSettings[0][OverviewMenus.CharType.ACT.ordinal]) -// graphData.addActivity(fromTime, toTime, false, 0.8) - - // add basal data - if (pump.pumpDescription.isTempBasalCapable && menuChartSettings[0][OverviewMenus.CharType.BAS.ordinal]) { -// graphData.addBasals(fromTime, toTime, lowLine / graphData.maxY / 1.2) - } - // ------------------ 2nd graph - synchronized(graphLock) { - for (g in 0 until secondaryGraphs.size) { - val secondGraphData = GraphData(injector, secondaryGraphs[g]) - var useIobForScale = false - var useCobForScale = false - var useDevForScale = false - var useRatioForScale = false - var useDSForScale = false - var useBGIForScale = false - var useABSForScale = false - when { - 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.SEN.ordinal] -> useRatioForScale = true - menuChartSettings[g + 1][OverviewMenus.CharType.BGI.ordinal] -> useBGIForScale = true - menuChartSettings[g + 1][OverviewMenus.CharType.ABS.ordinal] -> useABSForScale = true - menuChartSettings[g + 1][OverviewMenus.CharType.DEVSLOPE.ordinal] -> useDSForScale = true - } - - val alignIobScale = menuChartSettings[g + 1][OverviewMenus.CharType.ABS.ordinal] && menuChartSettings[g + 1][OverviewMenus.CharType.IOB.ordinal] - val alignDevBgiScale = menuChartSettings[g + 1][OverviewMenus.CharType.DEV.ordinal] && menuChartSettings[g + 1][OverviewMenus.CharType.BGI.ordinal] - -// if (menuChartSettings[g + 1][OverviewMenus.CharType.ABS.ordinal]) secondGraphData.addAbsIob(fromTime, toTime, useABSForScale, 1.0) -// if (menuChartSettings[g + 1][OverviewMenus.CharType.IOB.ordinal]) secondGraphData.addIob(fromTime, toTime, useIobForScale, 1.0, menuChartSettings[g + 1][OverviewMenus.CharType.PRE.ordinal], alignIobScale) -// if (menuChartSettings[g + 1][OverviewMenus.CharType.COB.ordinal]) secondGraphData.addCob(fromTime, toTime, useCobForScale, if (useCobForScale) 1.0 else 0.5) -// if (menuChartSettings[g + 1][OverviewMenus.CharType.DEV.ordinal]) secondGraphData.addDeviations(fromTime, toTime, useDevForScale, 1.0, alignDevBgiScale) -// if (menuChartSettings[g + 1][OverviewMenus.CharType.SEN.ordinal]) secondGraphData.addRatio(fromTime, toTime, useRatioForScale, 1.0) -// if (menuChartSettings[g + 1][OverviewMenus.CharType.BGI.ordinal]) secondGraphData.addMinusBGI(fromTime, toTime, useBGIForScale, if (alignDevBgiScale) 1.0 else 0.8, alignDevBgiScale) -// if (menuChartSettings[g + 1][OverviewMenus.CharType.DEVSLOPE.ordinal] && buildHelper.isDev()) secondGraphData.addDeviationSlope(fromTime, toTime, useDSForScale, 1.0) - - // set manual x bounds to have nice steps - secondGraphData.formatAxis(fromTime, toTime) - secondGraphData.addNowLine(pointer) - secondaryGraphsData.add(secondGraphData) - } - } - } - - // set manual x bounds to have nice steps - graphData.setNumVerticalLabels() - graphData.formatAxis(fromTime, toTime) - } - // finally enforce drawing of graphs in UI thread - graphData.performUpdate() - if (!bgOnly) - synchronized(graphLock) { - for (g in 0 until secondaryGraphs.size) { - secondaryGraphsLabel[g].text = overviewMenus.enabledTypes(g + 1) - secondaryGraphs[g].visibility = (!bgOnly && ( - menuChartSettings[g + 1][OverviewMenus.CharType.IOB.ordinal] || - menuChartSettings[g + 1][OverviewMenus.CharType.COB.ordinal] || - menuChartSettings[g + 1][OverviewMenus.CharType.DEV.ordinal] || - menuChartSettings[g + 1][OverviewMenus.CharType.SEN.ordinal] || - menuChartSettings[g + 1][OverviewMenus.CharType.ACT.ordinal] || - menuChartSettings[g + 1][OverviewMenus.CharType.ABS.ordinal] || - menuChartSettings[g + 1][OverviewMenus.CharType.DEVSLOPE.ordinal] - )).toVisibility() - secondaryGraphsData[g].performUpdate() - } - } - } - } -} \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/androidaps/historyBrowser/IobCobCalculatorPluginHistory.kt b/app/src/main/java/info/nightscout/androidaps/historyBrowser/IobCobCalculatorPluginHistory.kt deleted file mode 100644 index 1dfc35f70a..0000000000 --- a/app/src/main/java/info/nightscout/androidaps/historyBrowser/IobCobCalculatorPluginHistory.kt +++ /dev/null @@ -1,42 +0,0 @@ -package info.nightscout.androidaps.historyBrowser - -import dagger.android.HasAndroidInjector -import info.nightscout.androidaps.database.AppRepository -import info.nightscout.androidaps.interfaces.ActivePlugin -import info.nightscout.androidaps.interfaces.ProfileFunction -import info.nightscout.androidaps.logging.AAPSLogger -import info.nightscout.androidaps.plugins.bus.RxBusWrapper -import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin -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.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.androidaps.utils.sharedPreferences.SP -import javax.inject.Inject -import javax.inject.Singleton - -@Singleton -class IobCobCalculatorPluginHistory @Inject constructor( - injector: HasAndroidInjector, - aapsLogger: AAPSLogger, - aapsSchedulers: AapsSchedulers, - rxBus: RxBusWrapper, - sp: SP, - resourceHelper: ResourceHelper, - profileFunction: ProfileFunction, - activePlugin: ActivePlugin, - sensitivityOref1Plugin: SensitivityOref1Plugin, - sensitivityAAPSPlugin: SensitivityAAPSPlugin, - sensitivityWeightedAveragePlugin: SensitivityWeightedAveragePlugin, - fabricPrivacy: FabricPrivacy, - dateUtil: DateUtil, - repository: AppRepository -) : IobCobCalculatorPlugin(injector, aapsLogger, aapsSchedulers, rxBus, sp, resourceHelper, profileFunction, - activePlugin, sensitivityOref1Plugin, sensitivityAAPSPlugin, sensitivityWeightedAveragePlugin, fabricPrivacy, dateUtil, repository) { - - override fun onStart() { // do not attach to rxbus - } -} \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/actions/ActionsFragment.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/actions/ActionsFragment.kt index 1e18a5f54f..8ffbd696ee 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/actions/ActionsFragment.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/actions/ActionsFragment.kt @@ -28,7 +28,7 @@ import info.nightscout.androidaps.events.EventTherapyEventChange import info.nightscout.androidaps.extensions.toStringMedium import info.nightscout.androidaps.extensions.toStringShort import info.nightscout.androidaps.extensions.toVisibility -import info.nightscout.androidaps.historyBrowser.HistoryBrowseActivity +import info.nightscout.androidaps.activities.HistoryBrowseActivity import info.nightscout.androidaps.interfaces.ActivePlugin import info.nightscout.androidaps.interfaces.CommandQueueProvider import info.nightscout.androidaps.interfaces.Config 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 d5f64cc96e..026cb6e766 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,64 @@ package info.nightscout.androidaps.plugins.general.overview +import android.graphics.DashPathEffect +import android.graphics.Paint 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.ExtendedBolus import info.nightscout.androidaps.database.entities.GlucoseValue import info.nightscout.androidaps.database.entities.TemporaryBasal import info.nightscout.androidaps.database.entities.TemporaryTarget import info.nightscout.androidaps.extensions.convertedToPercent +import info.nightscout.androidaps.extensions.target 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.Profile -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.interfaces.* +import info.nightscout.androidaps.logging.AAPSLogger +import info.nightscout.androidaps.logging.LTag +import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin +import info.nightscout.androidaps.plugins.aps.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.plugins.iob.iobCobCalculator.CobInfo import info.nightscout.androidaps.plugins.iob.iobCobCalculator.data.AutosensData -import info.nightscout.androidaps.utils.DateUtil -import info.nightscout.androidaps.utils.DefaultValueHelper -import info.nightscout.androidaps.utils.T +import info.nightscout.androidaps.utils.* import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.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 resourceHelper: ResourceHelper, private val dateUtil: DateUtil, private val sp: SP, private val activePlugin: ActivePlugin, private val defaultValueHelper: DefaultValueHelper, - private val profileFunction: ProfileFunction + private val profileFunction: ProfileFunction, + private val config: Config, + private val loopPlugin: LoopPlugin, + private val nsDeviceStatus: NSDeviceStatus, + private val repository: AppRepository, + private val overviewMenus: OverviewMenus, + private val iobCobCalculator: IobCobCalculator, + private val translator: Translator ) { enum class Property { @@ -84,7 +102,7 @@ class OverviewData @Inject constructor( var profileName: String? = null var profileNameWithRemainingTime: String? = null - val profileBackgroudColor: Int + val profileBackgroundColor: Int get() = profile?.let { profile -> if (profile.percentage != 100 || profile.timeshift != 0) resourceHelper.gc(R.color.ribbonWarning) @@ -211,7 +229,7 @@ class OverviewData @Inject constructor( * TEMP TARGET */ - var temporarytarget: TemporaryTarget? = null + var temporaryTarget: TemporaryTarget? = null /* * SENSITIVITY @@ -278,4 +296,515 @@ class OverviewData @Inject constructor( 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, resourceHelper)) + } + 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) loopPlugin.lastRun?.constraintsProcessed else nsDeviceStatus.getAPSResult(injector) + val predictionsAvailable = if (config.APS) loopPlugin.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, resourceHelper) } + ?.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, resourceHelper)) + } + 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 = resourceHelper.gc(R.color.basebasal) + it.thickness = 0 + } + tempBasalGraphSeries = LineGraphSeries(Array(tempBasalArray.size) { i -> tempBasalArray[i] }).also { + it.isDrawBackground = true + it.backgroundColor = resourceHelper.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 = resourceHelper.getDisplayMetrics().scaledDensity * 2 + paint.pathEffect = DashPathEffect(floatArrayOf(2f, 4f), 0f) + paint.color = resourceHelper.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 = resourceHelper.getDisplayMetrics().scaledDensity * 2 + absolutePaint.color = resourceHelper.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 = profile ?: return + val units = profileFunction.getUnits() + var toTime = toTime + val targetsSeriesArray: MutableList = java.util.ArrayList() + var lastTarget = -1.0 + loopPlugin.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 = resourceHelper.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.getBolusesIncludingInvalidFromTimeToTime(fromTime, endTime, true).blockingGet() + .map { BolusDataPoint(it, resourceHelper, activePlugin, defaultValueHelper) } + .filter { it.data.type != Bolus.Type.SMB || it.data.isValid } + .forEach { + it.y = getNearestBg(it.x.toLong()) + filteredTreatments.add(it) + } + repository.getCarbsIncludingInvalidFromTimeToTimeExpanded(fromTime, endTime, true).blockingGet() + .map { CarbsDataPoint(it, resourceHelper) } + .forEach { + it.y = getNearestBg(it.x.toLong()) + filteredTreatments.add(it) + } + + // ProfileSwitch + repository.getEffectiveProfileSwitchDataFromTimeToTime(fromTime, endTime, true).blockingGet() + .map { EffectiveProfileSwitchDataPoint(it) } + .forEach(filteredTreatments::add) + + // Extended bolus + if (!activePlugin.activePump.isFakingTempsByExtendedBoluses) { + repository.getExtendedBolusDataFromTimeToTime(fromTime, endTime, true).blockingGet() + .map { ExtendedBolusDataPoint(it) } + .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, resourceHelper, 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.failoverToMinAbsorbtionRate) { + autosensData.setScale(cobScale) + autosensData.setChartTime(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 = resourceHelper.gc(R.color.deviationblack) // "=" + if (autosensData.type == "" || autosensData.type == "non-meal") { + if (autosensData.pastSensitivity == "C") color = resourceHelper.gc(R.color.deviationgrey) + if (autosensData.pastSensitivity == "+") color = resourceHelper.gc(R.color.deviationgreen) + if (autosensData.pastSensitivity == "-") color = resourceHelper.gc(R.color.deviationred) + } else if (autosensData.type == "uam") { + color = resourceHelper.gc(R.color.uam) + } else if (autosensData.type == "csf") { + color = resourceHelper.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 resourceHelper.gc(R.color.iob) //50% + it.color = resourceHelper.gc(R.color.iob) + it.thickness = 3 + } + absIobSeries = FixedLineGraphSeries(Array(absIobArray.size) { i -> absIobArray[i] }).also { + it.isDrawBackground = true + it.backgroundColor = -0x7f000001 and resourceHelper.gc(R.color.iob) //50% + it.color = resourceHelper.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(resourceHelper.gc(R.color.iobPredAS))) + maxIobValueFound = max(maxIobValueFound, abs(i.iob)) + } + iobPredictions1Series = PointsWithLabelGraphSeries(Array(iobPrediction.size) { i -> iobPrediction[i] }) + 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(resourceHelper.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(lastAutosensResult.ratio) + ": " + iobCobCalculator.iobArrayToString(iobPredictionArray)) + 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 resourceHelper.gc(R.color.cob) //50% + it.color = resourceHelper.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 = resourceHelper.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 = resourceHelper.gc(R.color.activity) + }) + } + + // BGI + minusBgiSeries = FixedLineGraphSeries(Array(bgiArrayHist.size) { i -> bgiArrayHist[i] }).also { + it.isDrawBackground = false + it.color = resourceHelper.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 = resourceHelper.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 = resourceHelper.gc(R.color.ratio) + it.thickness = 3 + } + + // DEV SLOPE + dsMaxSeries = LineGraphSeries(Array(dsMaxArray.size) { i -> dsMaxArray[i] }).also { + it.color = resourceHelper.gc(R.color.devslopepos) + it.thickness = 3 + } + dsMinSeries = LineGraphSeries(Array(dsMinArray.size) { i -> dsMinArray[i] }).also { + it.color = resourceHelper.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 d4b9d90774..08f7e073cf 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 @@ -57,7 +57,6 @@ import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatusProv import info.nightscout.androidaps.plugins.pump.common.defs.PumpType import info.nightscout.androidaps.plugins.source.DexcomPlugin import info.nightscout.androidaps.plugins.source.XdripPlugin -import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin import info.nightscout.androidaps.queue.CommandQueue import info.nightscout.androidaps.skins.SkinProvider import info.nightscout.androidaps.utils.* @@ -92,7 +91,6 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList @Inject lateinit var nsDeviceStatus: NSDeviceStatus @Inject lateinit var loopPlugin: LoopPlugin @Inject lateinit var activePlugin: ActivePlugin - @Inject lateinit var treatmentsPlugin: TreatmentsPlugin @Inject lateinit var iobCobCalculator: IobCobCalculator @Inject lateinit var dexcomPlugin: DexcomPlugin @Inject lateinit var dexcomMediator: DexcomPlugin.DexcomMediator @@ -108,7 +106,6 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList @Inject lateinit var trendCalculator: TrendCalculator @Inject lateinit var config: Config @Inject lateinit var dateUtil: DateUtil - @Inject lateinit var databaseHelper: DatabaseHelperInterface @Inject lateinit var uel: UserEntryLogger @Inject lateinit var repository: AppRepository @Inject lateinit var glucoseStatusProvider: GlucoseStatusProvider @@ -640,7 +637,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList OverviewData.Property.PROFILE -> { binding.loopPumpStatusLayout.activeProfile.text = overviewData.profileNameWithRemainingTime ?: "" - binding.loopPumpStatusLayout.activeProfile.setBackgroundColor(overviewData.profileBackgroudColor) + binding.loopPumpStatusLayout.activeProfile.setBackgroundColor(overviewData.profileBackgroundColor) binding.loopPumpStatusLayout.activeProfile.setTextColor(overviewData.profileTextColor) } @@ -705,7 +702,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList OverviewData.Property.TEMPORARY_TARGET -> { // temp target - val tempTarget = overviewData.temporarytarget + val tempTarget = overviewData.temporaryTarget if (tempTarget != null) { binding.loopPumpStatusLayout.tempTarget.setTextColor(resourceHelper.gc(R.color.ribbonTextWarning)) binding.loopPumpStatusLayout.tempTarget.setBackgroundColor(resourceHelper.gc(R.color.ribbonWarning)) @@ -730,7 +727,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList } OverviewData.Property.GRAPH -> { - val graphData = GraphData(injector, binding.graphsLayout.bgGraph) + val graphData = GraphData(injector, binding.graphsLayout.bgGraph, overviewData) val menuChartSettings = overviewMenus.setting graphData.addInRangeArea(overviewData.fromTime, overviewData.endTime, defaultValueHelper.determineLowLine(), defaultValueHelper.determineHighLine()) graphData.addBgReadings(menuChartSettings[0][OverviewMenus.CharType.PRE.ordinal]) @@ -755,7 +752,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList val now = System.currentTimeMillis() for (g in 0 until min(secondaryGraphs.size, menuChartSettings.size + 1)) { - val secondGraphData = GraphData(injector, secondaryGraphs[g]) + val secondGraphData = GraphData(injector, secondaryGraphs[g], overviewData) var useABSForScale = false var useIobForScale = false var useCobForScale = false 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 39c51ac5a2..fe5a30dbb4 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 @@ -1,85 +1,68 @@ package info.nightscout.androidaps.plugins.general.overview -import android.graphics.DashPathEffect -import android.graphics.Paint import androidx.preference.PreferenceFragmentCompat import androidx.preference.SwitchPreference -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.events.* import info.nightscout.androidaps.extensions.* import info.nightscout.androidaps.interfaces.* import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.plugins.aps.events.EventLoopInvoked -import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin -import info.nightscout.androidaps.plugins.aps.openAPSSMB.SMBDefaults import info.nightscout.androidaps.plugins.bus.RxBusWrapper -import info.nightscout.androidaps.plugins.general.nsclient.data.NSDeviceStatus 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.EventUpdateOverview -import info.nightscout.androidaps.plugins.general.overview.graphExtensions.* +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.AutosensResult import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventBucketedDataCreated import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventIobCalculationProgress -import info.nightscout.androidaps.utils.* +import info.nightscout.androidaps.utils.DateUtil +import info.nightscout.androidaps.utils.FabricPrivacy +import info.nightscout.androidaps.utils.Translator import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.rx.AapsSchedulers import info.nightscout.androidaps.utils.sharedPreferences.SP import io.reactivex.disposables.CompositeDisposable import io.reactivex.rxkotlin.plusAssign import org.json.JSONObject -import java.util.* import javax.inject.Inject import javax.inject.Singleton -import kotlin.math.abs -import kotlin.math.ceil -import kotlin.math.max -import kotlin.math.min @Singleton class OverviewPlugin @Inject constructor( - injector: HasAndroidInjector, - private val notificationStore: NotificationStore, - private val fabricPrivacy: FabricPrivacy, - private val rxBus: RxBusWrapper, - private val sp: SP, - aapsLogger: AAPSLogger, - private val aapsSchedulers: AapsSchedulers, - resourceHelper: ResourceHelper, - private val config: Config, - private val dateUtil: DateUtil, - private val translator: Translator, + injector: HasAndroidInjector, + private val notificationStore: NotificationStore, + private val fabricPrivacy: FabricPrivacy, + private val rxBus: RxBusWrapper, + private val sp: SP, + aapsLogger: AAPSLogger, + private val aapsSchedulers: AapsSchedulers, + resourceHelper: ResourceHelper, + private val config: Config, + private val dateUtil: DateUtil, + private val translator: Translator, // private val profiler: Profiler, - private val profileFunction: ProfileFunction, - private val iobCobCalculator: IobCobCalculator, - private val repository: AppRepository, - private val defaultValueHelper: DefaultValueHelper, - private val loopPlugin: LoopPlugin, - private val activePlugin: ActivePlugin, - private val nsDeviceStatus: NSDeviceStatus, - private val overviewData: OverviewData, - private val overviewMenus: OverviewMenus + private val profileFunction: ProfileFunction, + private val iobCobCalculator: IobCobCalculator, + private val repository: AppRepository, + private val overviewData: OverviewData, + private val overviewMenus: OverviewMenus ) : PluginBase(PluginDescription() - .mainType(PluginType.GENERAL) - .fragmentClass(OverviewFragment::class.qualifiedName) - .alwaysVisible(true) - .alwaysEnabled(true) - .pluginIcon(R.drawable.ic_home) - .pluginName(R.string.overview) - .shortName(R.string.overview_shortname) - .preferencesId(R.xml.pref_overview) - .description(R.string.description_overview), - aapsLogger, resourceHelper, injector + .mainType(PluginType.GENERAL) + .fragmentClass(OverviewFragment::class.qualifiedName) + .alwaysVisible(true) + .alwaysEnabled(true) + .pluginIcon(R.drawable.ic_home) + .pluginName(R.string.overview) + .shortName(R.string.overview_shortname) + .preferencesId(R.xml.pref_overview) + .description(R.string.description_overview), + aapsLogger, resourceHelper, injector ), Overview { private var disposable: CompositeDisposable = CompositeDisposable() @@ -95,74 +78,76 @@ class OverviewPlugin @Inject constructor( notificationStore.createNotificationChannel() disposable += rxBus - .toObservable(EventNewNotification::class.java) - .observeOn(aapsSchedulers.io) - .subscribe({ n -> - if (notificationStore.add(n.notification)) - rxBus.send(EventRefreshOverview("EventNewNotification")) - }, fabricPrivacy::logException) + .toObservable(EventNewNotification::class.java) + .observeOn(aapsSchedulers.io) + .subscribe({ n -> + if (notificationStore.add(n.notification)) + rxBus.send(EventRefreshOverview("EventNewNotification")) + }, fabricPrivacy::logException) disposable += rxBus - .toObservable(EventDismissNotification::class.java) - .observeOn(aapsSchedulers.io) - .subscribe({ n -> - if (notificationStore.remove(n.id)) - rxBus.send(EventRefreshOverview("EventDismissNotification")) - }, fabricPrivacy::logException) + .toObservable(EventDismissNotification::class.java) + .observeOn(aapsSchedulers.io) + .subscribe({ n -> + if (notificationStore.remove(n.id)) + rxBus.send(EventRefreshOverview("EventDismissNotification")) + }, fabricPrivacy::logException) disposable += rxBus - .toObservable(EventIobCalculationProgress::class.java) - .observeOn(aapsSchedulers.main) - .subscribe({ overviewData.calcProgress = it.progress; overviewBus.send(EventUpdateOverview("EventIobCalculationProgress", OverviewData.Property.CALC_PROGRESS)) }, fabricPrivacy::logException) + .toObservable(EventIobCalculationProgress::class.java) + .observeOn(aapsSchedulers.main) + .subscribe({ overviewData.calcProgress = it.progress; overviewBus.send(EventUpdateOverview("EventIobCalculationProgress", OverviewData.Property.CALC_PROGRESS)) }, fabricPrivacy::logException) disposable += rxBus - .toObservable(EventTempBasalChange::class.java) - .observeOn(aapsSchedulers.io) - .subscribe({ loadTemporaryBasal("EventTempBasalChange") }, fabricPrivacy::logException) + .toObservable(EventTempBasalChange::class.java) + .observeOn(aapsSchedulers.io) + .subscribe({ loadTemporaryBasal("EventTempBasalChange") }, fabricPrivacy::logException) disposable += rxBus - .toObservable(EventExtendedBolusChange::class.java) - .observeOn(aapsSchedulers.io) - .subscribe({ loadExtendedBolus("EventExtendedBolusChange") }, fabricPrivacy::logException) + .toObservable(EventExtendedBolusChange::class.java) + .observeOn(aapsSchedulers.io) + .subscribe({ loadExtendedBolus("EventExtendedBolusChange") }, fabricPrivacy::logException) disposable += rxBus - .toObservable(EventNewBG::class.java) - .observeOn(aapsSchedulers.io) - .subscribe({ loadBg("EventNewBG") }, fabricPrivacy::logException) + .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) + .toObservable(EventTempTargetChange::class.java) + .observeOn(aapsSchedulers.io) + .subscribe({ loadTemporaryTarget("EventTempTargetChange") }, fabricPrivacy::logException) disposable += rxBus - .toObservable(EventTreatmentChange::class.java) - .observeOn(aapsSchedulers.io) - .subscribe({ - loadIobCobResults("EventTreatmentChange") - prepareTreatmentsData("EventTreatmentChange") - overviewBus.send(EventUpdateOverview("EventTreatmentChange", OverviewData.Property.GRAPH)) - }, fabricPrivacy::logException) + .toObservable(EventTreatmentChange::class.java) + .observeOn(aapsSchedulers.io) + .subscribe({ + loadIobCobResults("EventTreatmentChange") + overviewData.prepareTreatmentsData("EventTreatmentChange") + overviewBus.send(EventUpdateOverview("EventTreatmentChange", OverviewData.Property.GRAPH)) + }, fabricPrivacy::logException) disposable += rxBus - .toObservable(EventTherapyEventChange::class.java) - .observeOn(aapsSchedulers.io) - .subscribe({ - prepareTreatmentsData("EventTherapyEventChange") - overviewBus.send(EventUpdateOverview("EventTherapyEventChange", OverviewData.Property.GRAPH)) - }, fabricPrivacy::logException) + .toObservable(EventTherapyEventChange::class.java) + .observeOn(aapsSchedulers.io) + .subscribe({ + overviewData.prepareTreatmentsData("EventTherapyEventChange") + overviewBus.send(EventUpdateOverview("EventTherapyEventChange", OverviewData.Property.GRAPH)) + }, fabricPrivacy::logException) disposable += rxBus - .toObservable(EventBucketedDataCreated::class.java) - .observeOn(aapsSchedulers.io) - .subscribe({ - prepareBucketedData("EventBucketedDataCreated") - prepareBgData("EventBucketedDataCreated") - overviewBus.send(EventUpdateOverview("EventBucketedDataCreated", OverviewData.Property.GRAPH)) - }, fabricPrivacy::logException) + .toObservable(EventBucketedDataCreated::class.java) + .observeOn(aapsSchedulers.io) + .subscribe({ + overviewData.prepareBucketedData("EventBucketedDataCreated") + overviewData.prepareBgData("EventBucketedDataCreated") + overviewBus.send(EventUpdateOverview("EventBucketedDataCreated", OverviewData.Property.GRAPH)) + }, fabricPrivacy::logException) disposable += rxBus - .toObservable(EventLoopInvoked::class.java) - .observeOn(aapsSchedulers.io) - .subscribe({ preparePredictions("EventLoopInvoked") }, fabricPrivacy::logException) + .toObservable(EventLoopInvoked::class.java) + .observeOn(aapsSchedulers.io) + .subscribe({ overviewData.preparePredictions("EventLoopInvoked") }, fabricPrivacy::logException) disposable.add(rxBus - .toObservable(EventProfileSwitchChanged::class.java) - .observeOn(aapsSchedulers.io) - .subscribe({ loadProfile("EventProfileSwitchChanged") }, fabricPrivacy::logException)) + .toObservable(EventProfileSwitchChanged::class.java) + .observeOn(aapsSchedulers.io) + .subscribe({ loadProfile("EventProfileSwitchChanged") }, fabricPrivacy::logException)) disposable.add(rxBus - .toObservable(EventAutosensCalculationFinished::class.java) - .observeOn(aapsSchedulers.io) - .subscribe({ refreshLoop("EventAutosensCalculationFinished") }, fabricPrivacy::logException)) + .toObservable(EventAutosensCalculationFinished::class.java) + .observeOn(aapsSchedulers.io) + .subscribe({ + if (it.cause !is EventCustomCalculationFinished) refreshLoop("EventAutosensCalculationFinished") + }, fabricPrivacy::logException)) Thread { loadAll("onResume") }.start() } @@ -187,59 +172,60 @@ class OverviewPlugin @Inject constructor( } override fun configuration(): JSONObject = - JSONObject() - .putString(R.string.key_quickwizard, sp, resourceHelper) - .putInt(R.string.key_eatingsoon_duration, sp, resourceHelper) - .putDouble(R.string.key_eatingsoon_target, sp, resourceHelper) - .putInt(R.string.key_activity_duration, sp, resourceHelper) - .putDouble(R.string.key_activity_target, sp, resourceHelper) - .putInt(R.string.key_hypo_duration, sp, resourceHelper) - .putDouble(R.string.key_hypo_target, sp, resourceHelper) - .putDouble(R.string.key_low_mark, sp, resourceHelper) - .putDouble(R.string.key_high_mark, sp, resourceHelper) - .putDouble(R.string.key_statuslights_cage_warning, sp, resourceHelper) - .putDouble(R.string.key_statuslights_cage_critical, sp, resourceHelper) - .putDouble(R.string.key_statuslights_iage_warning, sp, resourceHelper) - .putDouble(R.string.key_statuslights_iage_critical, sp, resourceHelper) - .putDouble(R.string.key_statuslights_sage_warning, sp, resourceHelper) - .putDouble(R.string.key_statuslights_sage_critical, sp, resourceHelper) - .putDouble(R.string.key_statuslights_sbat_warning, sp, resourceHelper) - .putDouble(R.string.key_statuslights_sbat_critical, sp, resourceHelper) - .putDouble(R.string.key_statuslights_bage_warning, sp, resourceHelper) - .putDouble(R.string.key_statuslights_bage_critical, sp, resourceHelper) - .putDouble(R.string.key_statuslights_res_warning, sp, resourceHelper) - .putDouble(R.string.key_statuslights_res_critical, sp, resourceHelper) - .putDouble(R.string.key_statuslights_bat_warning, sp, resourceHelper) - .putDouble(R.string.key_statuslights_bat_critical, sp, resourceHelper) + JSONObject() + .putString(R.string.key_quickwizard, sp, resourceHelper) + .putInt(R.string.key_eatingsoon_duration, sp, resourceHelper) + .putDouble(R.string.key_eatingsoon_target, sp, resourceHelper) + .putInt(R.string.key_activity_duration, sp, resourceHelper) + .putDouble(R.string.key_activity_target, sp, resourceHelper) + .putInt(R.string.key_hypo_duration, sp, resourceHelper) + .putDouble(R.string.key_hypo_target, sp, resourceHelper) + .putDouble(R.string.key_low_mark, sp, resourceHelper) + .putDouble(R.string.key_high_mark, sp, resourceHelper) + .putDouble(R.string.key_statuslights_cage_warning, sp, resourceHelper) + .putDouble(R.string.key_statuslights_cage_critical, sp, resourceHelper) + .putDouble(R.string.key_statuslights_iage_warning, sp, resourceHelper) + .putDouble(R.string.key_statuslights_iage_critical, sp, resourceHelper) + .putDouble(R.string.key_statuslights_sage_warning, sp, resourceHelper) + .putDouble(R.string.key_statuslights_sage_critical, sp, resourceHelper) + .putDouble(R.string.key_statuslights_sbat_warning, sp, resourceHelper) + .putDouble(R.string.key_statuslights_sbat_critical, sp, resourceHelper) + .putDouble(R.string.key_statuslights_bage_warning, sp, resourceHelper) + .putDouble(R.string.key_statuslights_bage_critical, sp, resourceHelper) + .putDouble(R.string.key_statuslights_res_warning, sp, resourceHelper) + .putDouble(R.string.key_statuslights_res_critical, sp, resourceHelper) + .putDouble(R.string.key_statuslights_bat_warning, sp, resourceHelper) + .putDouble(R.string.key_statuslights_bat_critical, sp, resourceHelper) override fun applyConfiguration(configuration: JSONObject) { configuration - .storeString(R.string.key_quickwizard, sp, resourceHelper) - .storeInt(R.string.key_eatingsoon_duration, sp, resourceHelper) - .storeDouble(R.string.key_eatingsoon_target, sp, resourceHelper) - .storeInt(R.string.key_activity_duration, sp, resourceHelper) - .storeDouble(R.string.key_activity_target, sp, resourceHelper) - .storeInt(R.string.key_hypo_duration, sp, resourceHelper) - .storeDouble(R.string.key_hypo_target, sp, resourceHelper) - .storeDouble(R.string.key_low_mark, sp, resourceHelper) - .storeDouble(R.string.key_high_mark, sp, resourceHelper) - .storeDouble(R.string.key_statuslights_cage_warning, sp, resourceHelper) - .storeDouble(R.string.key_statuslights_cage_critical, sp, resourceHelper) - .storeDouble(R.string.key_statuslights_iage_warning, sp, resourceHelper) - .storeDouble(R.string.key_statuslights_iage_critical, sp, resourceHelper) - .storeDouble(R.string.key_statuslights_sage_warning, sp, resourceHelper) - .storeDouble(R.string.key_statuslights_sage_critical, sp, resourceHelper) - .storeDouble(R.string.key_statuslights_sbat_warning, sp, resourceHelper) - .storeDouble(R.string.key_statuslights_sbat_critical, sp, resourceHelper) - .storeDouble(R.string.key_statuslights_bage_warning, sp, resourceHelper) - .storeDouble(R.string.key_statuslights_bage_critical, sp, resourceHelper) - .storeDouble(R.string.key_statuslights_res_warning, sp, resourceHelper) - .storeDouble(R.string.key_statuslights_res_critical, sp, resourceHelper) - .storeDouble(R.string.key_statuslights_bat_warning, sp, resourceHelper) - .storeDouble(R.string.key_statuslights_bat_critical, sp, resourceHelper) + .storeString(R.string.key_quickwizard, sp, resourceHelper) + .storeInt(R.string.key_eatingsoon_duration, sp, resourceHelper) + .storeDouble(R.string.key_eatingsoon_target, sp, resourceHelper) + .storeInt(R.string.key_activity_duration, sp, resourceHelper) + .storeDouble(R.string.key_activity_target, sp, resourceHelper) + .storeInt(R.string.key_hypo_duration, sp, resourceHelper) + .storeDouble(R.string.key_hypo_target, sp, resourceHelper) + .storeDouble(R.string.key_low_mark, sp, resourceHelper) + .storeDouble(R.string.key_high_mark, sp, resourceHelper) + .storeDouble(R.string.key_statuslights_cage_warning, sp, resourceHelper) + .storeDouble(R.string.key_statuslights_cage_critical, sp, resourceHelper) + .storeDouble(R.string.key_statuslights_iage_warning, sp, resourceHelper) + .storeDouble(R.string.key_statuslights_iage_critical, sp, resourceHelper) + .storeDouble(R.string.key_statuslights_sage_warning, sp, resourceHelper) + .storeDouble(R.string.key_statuslights_sage_critical, sp, resourceHelper) + .storeDouble(R.string.key_statuslights_sbat_warning, sp, resourceHelper) + .storeDouble(R.string.key_statuslights_sbat_critical, sp, resourceHelper) + .storeDouble(R.string.key_statuslights_bage_warning, sp, resourceHelper) + .storeDouble(R.string.key_statuslights_bage_critical, sp, resourceHelper) + .storeDouble(R.string.key_statuslights_res_warning, sp, resourceHelper) + .storeDouble(R.string.key_statuslights_res_critical, sp, resourceHelper) + .storeDouble(R.string.key_statuslights_bat_warning, sp, resourceHelper) + .storeDouble(R.string.key_statuslights_bat_critical, sp, resourceHelper) } - @Volatile var runningRefresh = false + @Volatile + var runningRefresh = false override fun refreshLoop(from: String) { if (runningRefresh) return runningRefresh = true @@ -252,11 +238,11 @@ class OverviewPlugin @Inject constructor( overviewBus.send(EventUpdateOverview(from, OverviewData.Property.TEMPORARY_TARGET)) overviewBus.send(EventUpdateOverview(from, OverviewData.Property.SENSITIVITY)) loadAsData(from) - preparePredictions(from) - prepareBasalData(from) - prepareTemporaryTargetData(from) - prepareTreatmentsData(from) - prepareIobAutosensData(from) + overviewData.preparePredictions(from) + overviewData.prepareBasalData(from) + overviewData.prepareTemporaryTargetData(from) + overviewData.prepareTreatmentsData(from) + overviewData.prepareIobAutosensData(from) overviewBus.send(EventUpdateOverview(from, OverviewData.Property.GRAPH)) aapsLogger.debug(LTag.UI, "refreshLoop finished") runningRefresh = false @@ -271,9 +257,9 @@ class OverviewPlugin @Inject constructor( loadTemporaryTarget(from) loadIobCobResults(from) loadAsData(from) - prepareBasalData(from) - prepareTemporaryTargetData(from) - prepareTreatmentsData(from) + overviewData.prepareBasalData(from) + overviewData.prepareTemporaryTargetData(from) + overviewData.prepareTreatmentsData(from) // prepareIobAutosensData(from) // preparePredictions(from) overviewBus.send(EventUpdateOverview(from, OverviewData.Property.GRAPH)) @@ -299,8 +285,8 @@ class OverviewPlugin @Inject constructor( 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 + if (tempTarget is ValueWrapper.Existing) overviewData.temporaryTarget = tempTarget.value + else overviewData.temporaryTarget = null overviewBus.send(EventUpdateOverview(from, OverviewData.Property.TEMPORARY_TARGET)) } @@ -326,514 +312,4 @@ class OverviewPlugin @Inject constructor( overviewBus.send(EventUpdateOverview(from, OverviewData.Property.IOB_COB)) } - @Synchronized - @Suppress("SameParameterValue", "UNUSED_PARAMETER") - private fun prepareBgData(from: String) { -// val start = dateUtil.now() - var maxBgValue = Double.MIN_VALUE - overviewData.bgReadingsArray = repository.compatGetBgReadingsDataFromTime(overviewData.fromTime, overviewData.toTime, false).blockingGet() - val bgListArray: MutableList = ArrayList() - for (bg in overviewData.bgReadingsArray) { - if (bg.timestamp < overviewData.fromTime || bg.timestamp > overviewData.toTime) continue - if (bg.value > maxBgValue) maxBgValue = bg.value - bgListArray.add(GlucoseValueDataPoint(bg, defaultValueHelper, profileFunction, resourceHelper)) - } - overviewData.bgReadingGraphSeries = PointsWithLabelGraphSeries(Array(bgListArray.size) { i -> bgListArray[i] }) - overviewData.maxBgValue = Profile.fromMgdlToUnits(maxBgValue, profileFunction.getUnits()) - if (defaultValueHelper.determineHighLine() > maxBgValue) overviewData.maxBgValue = defaultValueHelper.determineHighLine() - overviewData.maxBgValue = addUpperChartMargin(overviewData.maxBgValue) -// profiler.log(LTag.UI, "prepareBgData() $from", start) - } - - @Suppress("UNUSED_PARAMETER") - @Synchronized - private fun preparePredictions(from: String) { -// val start = dateUtil.now() - val apsResult = if (config.APS) loopPlugin.lastRun?.constraintsProcessed else nsDeviceStatus.getAPSResult(injector) - val predictionsAvailable = if (config.APS) loopPlugin.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 = overviewData.rangeToDisplay - predictionHours - overviewData.toTime = calendar.timeInMillis + 100000 // little bit more to avoid wrong rounding - GraphView specific - overviewData.fromTime = overviewData.toTime - T.hours(hoursToFetch.toLong()).msecs() - overviewData.endTime = overviewData.toTime + T.hours(predictionHours.toLong()).msecs() - } else { - overviewData.toTime = calendar.timeInMillis + 100000 // little bit more to avoid wrong rounding - GraphView specific - overviewData.fromTime = overviewData.toTime - T.hours(overviewData.rangeToDisplay.toLong()).msecs() - overviewData.endTime = overviewData.toTime - } - - val bgListArray: MutableList = ArrayList() - val predictions: MutableList? = apsResult?.predictions - ?.map { bg -> GlucoseValueDataPoint(bg, defaultValueHelper, profileFunction, resourceHelper) } - ?.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) - } - overviewData.predictionsGraphSeries = PointsWithLabelGraphSeries(Array(bgListArray.size) { i -> bgListArray[i] }) -// profiler.log(LTag.UI, "preparePredictions() $from", start) - } - - @Synchronized - @Suppress("SameParameterValue", "UNUSED_PARAMETER") - private 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 = ArrayList() - for (inMemoryGlucoseValue in bucketedData) { - if (inMemoryGlucoseValue.timestamp < overviewData.fromTime || inMemoryGlucoseValue.timestamp > overviewData.toTime) continue - bucketedListArray.add(InMemoryGlucoseValueDataPoint(inMemoryGlucoseValue, profileFunction, resourceHelper)) - } - overviewData.bucketedGraphSeries = PointsWithLabelGraphSeries(Array(bucketedListArray.size) { i -> bucketedListArray[i] }) -// profiler.log(LTag.UI, "prepareBucketedData() $from", start) - } - - @Suppress("UNUSED_PARAMETER") - @Synchronized - private fun prepareBasalData(from: String) { -// val start = dateUtil.now() - 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 = overviewData.fromTime - while (time < overviewData.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, overviewData.basalScale)) - tempBasalArray.add(ScaledDataPoint(time, tempBasalValue.also { basal = it }, overviewData.basalScale)) - } - if (lastBaseBasal != 0.0) { - baseBasalArray.add(ScaledDataPoint(time, lastBaseBasal, overviewData.basalScale)) - baseBasalArray.add(ScaledDataPoint(time, 0.0, overviewData.basalScale)) - lastBaseBasal = 0.0 - } - } else { - if (baseBasalValue != lastBaseBasal) { - baseBasalArray.add(ScaledDataPoint(time, lastBaseBasal, overviewData.basalScale)) - baseBasalArray.add(ScaledDataPoint(time, baseBasalValue.also { basal = it }, overviewData.basalScale)) - lastBaseBasal = baseBasalValue - } - if (lastTempBasal != 0.0) { - tempBasalArray.add(ScaledDataPoint(time, lastTempBasal, overviewData.basalScale)) - tempBasalArray.add(ScaledDataPoint(time, 0.0, overviewData.basalScale)) - } - } - if (baseBasalValue != lastLineBasal) { - basalLineArray.add(ScaledDataPoint(time, lastLineBasal, overviewData.basalScale)) - basalLineArray.add(ScaledDataPoint(time, baseBasalValue, overviewData.basalScale)) - } - if (absoluteLineValue != lastAbsoluteLineBasal) { - absoluteBasalLineArray.add(ScaledDataPoint(time, lastAbsoluteLineBasal, overviewData.basalScale)) - absoluteBasalLineArray.add(ScaledDataPoint(time, basal, overviewData.basalScale)) - } - lastAbsoluteLineBasal = absoluteLineValue - lastLineBasal = baseBasalValue - lastTempBasal = tempBasalValue - overviewData.maxBasalValueFound = max(overviewData.maxBasalValueFound, max(tempBasalValue, baseBasalValue)) - time += 60 * 1000L - } - - // final points - basalLineArray.add(ScaledDataPoint(overviewData.toTime, lastLineBasal, overviewData.basalScale)) - baseBasalArray.add(ScaledDataPoint(overviewData.toTime, lastBaseBasal, overviewData.basalScale)) - tempBasalArray.add(ScaledDataPoint(overviewData.toTime, lastTempBasal, overviewData.basalScale)) - absoluteBasalLineArray.add(ScaledDataPoint(overviewData.toTime, lastAbsoluteLineBasal, overviewData.basalScale)) - - // create series - overviewData.baseBasalGraphSeries = LineGraphSeries(Array(baseBasalArray.size) { i -> baseBasalArray[i] }).also { - it.isDrawBackground = true - it.backgroundColor = resourceHelper.gc(R.color.basebasal) - it.thickness = 0 - } - overviewData.tempBasalGraphSeries = LineGraphSeries(Array(tempBasalArray.size) { i -> tempBasalArray[i] }).also { - it.isDrawBackground = true - it.backgroundColor = resourceHelper.gc(R.color.tempbasal) - it.thickness = 0 - } - overviewData.basalLineGraphSeries = LineGraphSeries(Array(basalLineArray.size) { i -> basalLineArray[i] }).also { - it.setCustomPaint(Paint().also { paint -> - paint.style = Paint.Style.STROKE - paint.strokeWidth = resourceHelper.getDisplayMetrics().scaledDensity * 2 - paint.pathEffect = DashPathEffect(floatArrayOf(2f, 4f), 0f) - paint.color = resourceHelper.gc(R.color.basal) - }) - } - overviewData.absoluteBasalGraphSeries = LineGraphSeries(Array(absoluteBasalLineArray.size) { i -> absoluteBasalLineArray[i] }).also { - it.setCustomPaint(Paint().also { absolutePaint -> - absolutePaint.style = Paint.Style.STROKE - absolutePaint.strokeWidth = resourceHelper.getDisplayMetrics().scaledDensity * 2 - absolutePaint.color = resourceHelper.gc(R.color.basal) - }) - } -// profiler.log(LTag.UI, "prepareBasalData() $from", start) - } - - @Suppress("UNUSED_PARAMETER") - @Synchronized - private fun prepareTemporaryTargetData(from: String) { -// val start = dateUtil.now() - val profile = overviewData.profile ?: return - val units = profileFunction.getUnits() - var toTime = overviewData.toTime - val targetsSeriesArray: MutableList = ArrayList() - var lastTarget = -1.0 - loopPlugin.lastRun?.constraintsProcessed?.let { toTime = max(it.latestPredictionsTime, toTime) } - var time = overviewData.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 - overviewData.temporaryTargetSeries = LineGraphSeries(Array(targetsSeriesArray.size) { i -> targetsSeriesArray[i] }).also { - it.isDrawBackground = false - it.color = resourceHelper.gc(R.color.tempTargetBackground) - it.thickness = 2 - } -// profiler.log(LTag.UI, "prepareTemporaryTargetData() $from", start) - } - - @Suppress("UNUSED_PARAMETER") - @Synchronized - private fun prepareTreatmentsData(from: String) { -// val start = dateUtil.now() - overviewData.maxTreatmentsValue = 0.0 - val filteredTreatments: MutableList = ArrayList() - repository.getBolusesIncludingInvalidFromTimeToTime(overviewData.fromTime, overviewData.endTime, true).blockingGet() - .map { BolusDataPoint(it, resourceHelper, activePlugin, defaultValueHelper) } - .filter { it.data.type != Bolus.Type.SMB || it.data.isValid } - .forEach { - it.y = getNearestBg(it.x.toLong()) - filteredTreatments.add(it) - } - repository.getCarbsIncludingInvalidFromTimeToTimeExpanded(overviewData.fromTime, overviewData.endTime, true).blockingGet() - .map { CarbsDataPoint(it, resourceHelper) } - .forEach { - it.y = getNearestBg(it.x.toLong()) - filteredTreatments.add(it) - } - - // ProfileSwitch - repository.getEffectiveProfileSwitchDataFromTimeToTime(overviewData.fromTime, overviewData.endTime, true).blockingGet() - .map { EffectiveProfileSwitchDataPoint(it) } - .forEach(filteredTreatments::add) - - // Extended bolus - if (!activePlugin.activePump.isFakingTempsByExtendedBoluses) { - repository.getExtendedBolusDataFromTimeToTime(overviewData.fromTime, overviewData.endTime, true).blockingGet() - .map { ExtendedBolusDataPoint(it) } - .filter { it.duration != 0L } - .forEach { - it.y = getNearestBg(it.x.toLong()) - filteredTreatments.add(it) - } - } - - // Careportal - repository.compatGetTherapyEventDataFromToTime(overviewData.fromTime - T.hours(6).msecs(), overviewData.endTime).blockingGet() - .map { TherapyEventDataPoint(it, resourceHelper, profileFunction, translator) } - .filterTimeframe(overviewData.fromTime, overviewData.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 { overviewData.maxTreatmentsValue = maxOf(overviewData.maxTreatmentsValue, it) } - - overviewData.treatmentsSeries = PointsWithLabelGraphSeries(filteredTreatments.toTypedArray()) -// profiler.log(LTag.UI, "prepareTreatmentsData() $from", start) - } - - @Suppress("UNUSED_PARAMETER") - @Synchronized - private fun prepareIobAutosensData(from: String) { -// val start = dateUtil.now() - val iobArray: MutableList = ArrayList() - val absIobArray: MutableList = ArrayList() - overviewData.maxIobValueFound = Double.MIN_VALUE - var lastIob = 0.0 - var absLastIob = 0.0 - var time = overviewData.fromTime - - val minFailOverActiveList: MutableList = ArrayList() - val cobArray: MutableList = ArrayList() - overviewData.maxCobValueFound = Double.MIN_VALUE - var lastCob = 0 - - val actArrayHist: MutableList = ArrayList() - val actArrayPrediction: MutableList = ArrayList() - val now = dateUtil.now().toDouble() - overviewData.maxIAValue = 0.0 - - val bgiArrayHist: MutableList = ArrayList() - val bgiArrayPrediction: MutableList = ArrayList() - overviewData.maxBGIValue = Double.MIN_VALUE - - val devArray: MutableList = ArrayList() - overviewData.maxDevValueFound = Double.MIN_VALUE - - val ratioArray: MutableList = ArrayList() - overviewData.maxRatioValueFound = 5.0 //even if sens data equals 0 for all the period, minimum scale is between 95% and 105% - overviewData.minRatioValueFound = -5.0 - - val dsMaxArray: MutableList = ArrayList() - val dsMinArray: MutableList = ArrayList() - overviewData.maxFromMaxValueFound = Double.MIN_VALUE - overviewData.maxFromMinValueFound = Double.MIN_VALUE - - val adsData = iobCobCalculator.ads.clone() - - while (time <= overviewData.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, overviewData.iobScale)) - iobArray.add(ScaledDataPoint(time, iob.iob, overviewData.iobScale)) - overviewData.maxIobValueFound = maxOf(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, overviewData.iobScale)) - absIobArray.add(ScaledDataPoint(time, absIob.iob, overviewData.iobScale)) - overviewData.maxIobValueFound = maxOf(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(), overviewData.cobScale)) - cobArray.add(ScaledDataPoint(time, cob.toDouble(), overviewData.cobScale)) - overviewData.maxCobValueFound = max(overviewData.maxCobValueFound, cob.toDouble()) - lastCob = cob - } - if (autosensData.failoverToMinAbsorbtionRate) { - autosensData.setScale(overviewData.cobScale) - autosensData.setChartTime(time) - minFailOverActiveList.add(autosensData) - } - } - - // ACTIVITY - if (time <= now) actArrayHist.add(ScaledDataPoint(time, iob.activity, overviewData.actScale)) - else actArrayPrediction.add(ScaledDataPoint(time, iob.activity, overviewData.actScale)) - overviewData.maxIAValue = max(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, overviewData.bgiScale)) - else bgiArrayPrediction.add(ScaledDataPoint(time, bgi, overviewData.bgiScale)) - overviewData.maxBGIValue = max(overviewData.maxBGIValue, max(abs(bgi), deviation)) - - // DEVIATIONS - if (autosensData != null) { - var color = resourceHelper.gc(R.color.deviationblack) // "=" - if (autosensData.type == "" || autosensData.type == "non-meal") { - if (autosensData.pastSensitivity == "C") color = resourceHelper.gc(R.color.deviationgrey) - if (autosensData.pastSensitivity == "+") color = resourceHelper.gc(R.color.deviationgreen) - if (autosensData.pastSensitivity == "-") color = resourceHelper.gc(R.color.deviationred) - } else if (autosensData.type == "uam") { - color = resourceHelper.gc(R.color.uam) - } else if (autosensData.type == "csf") { - color = resourceHelper.gc(R.color.deviationgrey) - } - devArray.add(DeviationDataPoint(time.toDouble(), autosensData.deviation, color, overviewData.devScale)) - overviewData.maxDevValueFound = maxOf(overviewData.maxDevValueFound, abs(autosensData.deviation), abs(bgi)) - } - - // RATIO - if (autosensData != null) { - ratioArray.add(ScaledDataPoint(time, 100.0 * (autosensData.autosensResult.ratio - 1), overviewData.ratioScale)) - overviewData.maxRatioValueFound = max(overviewData.maxRatioValueFound, 100.0 * (autosensData.autosensResult.ratio - 1)) - overviewData.minRatioValueFound = min(overviewData.minRatioValueFound, 100.0 * (autosensData.autosensResult.ratio - 1)) - } - - // DEV SLOPE - if (autosensData != null) { - dsMaxArray.add(ScaledDataPoint(time, autosensData.slopeFromMaxDeviation, overviewData.dsMaxScale)) - dsMinArray.add(ScaledDataPoint(time, autosensData.slopeFromMinDeviation, overviewData.dsMinScale)) - overviewData.maxFromMaxValueFound = max(overviewData.maxFromMaxValueFound, abs(autosensData.slopeFromMaxDeviation)) - overviewData.maxFromMinValueFound = max(overviewData.maxFromMinValueFound, abs(autosensData.slopeFromMinDeviation)) - } - - time += 5 * 60 * 1000L - } - // IOB - overviewData.iobSeries = FixedLineGraphSeries(Array(iobArray.size) { i -> iobArray[i] }).also { - it.isDrawBackground = true - it.backgroundColor = -0x7f000001 and resourceHelper.gc(R.color.iob) //50% - it.color = resourceHelper.gc(R.color.iob) - it.thickness = 3 - } - overviewData.absIobSeries = FixedLineGraphSeries(Array(absIobArray.size) { i -> absIobArray[i] }).also { - it.isDrawBackground = true - it.backgroundColor = -0x7f000001 and resourceHelper.gc(R.color.iob) //50% - it.color = resourceHelper.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 = iobCobCalculator.calculateIobArrayForSMB(lastAutosensResult, SMBDefaults.exercise_mode, SMBDefaults.half_basal_exercise_target, isTempTarget) - for (i in iobPredictionArray) { - iobPrediction.add(i.setColor(resourceHelper.gc(R.color.iobPredAS))) - overviewData.maxIobValueFound = max(overviewData.maxIobValueFound, abs(i.iob)) - } - overviewData.iobPredictions1Series = PointsWithLabelGraphSeries(Array(iobPrediction.size) { i -> iobPrediction[i] }) - val iobPrediction2: MutableList = ArrayList() - val iobPredictionArray2 = iobCobCalculator.calculateIobArrayForSMB(AutosensResult(), SMBDefaults.exercise_mode, SMBDefaults.half_basal_exercise_target, isTempTarget) - for (i in iobPredictionArray2) { - iobPrediction2.add(i.setColor(resourceHelper.gc(R.color.iobPred))) - overviewData.maxIobValueFound = max(overviewData.maxIobValueFound, abs(i.iob)) - } - overviewData.iobPredictions2Series = PointsWithLabelGraphSeries(Array(iobPrediction2.size) { i -> iobPrediction2[i] }) - aapsLogger.debug(LTag.AUTOSENS, "IOB prediction for AS=" + DecimalFormatter.to2Decimal(lastAutosensResult.ratio) + ": " + iobCobCalculator.iobArrayToString(iobPredictionArray)) - aapsLogger.debug(LTag.AUTOSENS, "IOB prediction for AS=" + DecimalFormatter.to2Decimal(1.0) + ": " + iobCobCalculator.iobArrayToString(iobPredictionArray2)) - } else { - overviewData.iobPredictions1Series = PointsWithLabelGraphSeries() - overviewData.iobPredictions2Series = PointsWithLabelGraphSeries() - } - - // COB - overviewData.cobSeries = FixedLineGraphSeries(Array(cobArray.size) { i -> cobArray[i] }).also { - it.isDrawBackground = true - it.backgroundColor = -0x7f000001 and resourceHelper.gc(R.color.cob) //50% - it.color = resourceHelper.gc(R.color.cob) - it.thickness = 3 - } - overviewData.cobMinFailOverSeries = PointsWithLabelGraphSeries(Array(minFailOverActiveList.size) { i -> minFailOverActiveList[i] }) - - // ACTIVITY - overviewData.activitySeries = FixedLineGraphSeries(Array(actArrayHist.size) { i -> actArrayHist[i] }).also { - it.isDrawBackground = false - it.color = resourceHelper.gc(R.color.activity) - it.thickness = 3 - } - 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 = resourceHelper.gc(R.color.activity) - }) - } - - // BGI - overviewData.minusBgiSeries = FixedLineGraphSeries(Array(bgiArrayHist.size) { i -> bgiArrayHist[i] }).also { - it.isDrawBackground = false - it.color = resourceHelper.gc(R.color.bgi) - it.thickness = 3 - } - 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 = resourceHelper.gc(R.color.bgi) - }) - } - - // DEVIATIONS - overviewData.deviationsSeries = BarGraphSeries(Array(devArray.size) { i -> devArray[i] }).also { - it.setValueDependentColor { data: DeviationDataPoint -> data.color } - } - - // RATIO - overviewData.ratioSeries = LineGraphSeries(Array(ratioArray.size) { i -> ratioArray[i] }).also { - it.color = resourceHelper.gc(R.color.ratio) - it.thickness = 3 - } - - // DEV SLOPE - overviewData.dsMaxSeries = LineGraphSeries(Array(dsMaxArray.size) { i -> dsMaxArray[i] }).also { - it.color = resourceHelper.gc(R.color.devslopepos) - it.thickness = 3 - } - overviewData.dsMinSeries = LineGraphSeries(Array(dsMinArray.size) { i -> dsMinArray[i] }).also { - it.color = resourceHelper.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 { - 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 } } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/graphData/GraphData.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/graphData/GraphData.kt index c2055e61e8..ba3e33667f 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/graphData/GraphData.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/graphData/GraphData.kt @@ -26,16 +26,16 @@ import kotlin.math.max class GraphData( injector: HasAndroidInjector, - private val graph: GraphView + private val graph: GraphView, + private val overviewData: OverviewData ) { @Inject lateinit var aapsLogger: AAPSLogger @Inject lateinit var profileFunction: ProfileFunction @Inject lateinit var resourceHelper: ResourceHelper @Inject lateinit var defaultValueHelper: DefaultValueHelper - @Inject lateinit var overviewData: OverviewData - var maxY = Double.MIN_VALUE + private var maxY = Double.MIN_VALUE private var minY = Double.MAX_VALUE private val units: GlucoseUnit private val series: MutableList> = ArrayList() @@ -201,7 +201,7 @@ class GraphData( graph.gridLabelRenderer.numHorizontalLabels = 7 // only 7 because of the space } - internal fun addSeries(s: Series<*>) = series.add(s) + private fun addSeries(s: Series<*>) = series.add(s) fun performUpdate() { // clear old data diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/IobCobOref1Thread.kt b/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/IobCobOref1Thread.kt index d577666d27..51ef6da52f 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/IobCobOref1Thread.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/IobCobOref1Thread.kt @@ -99,7 +99,7 @@ class IobCobOref1Thread internal constructor( // start from oldest to be able sub cob for (i in bucketedData.size - 4 downTo 0) { val progress = i.toString() + if (buildHelper.isDev()) " ($from)" else "" - rxBus.send(EventIobCalculationProgress(progress)) + rxBus.send(EventIobCalculationProgress(progress, cause)) if (iobCobCalculatorPlugin.stopCalculationTrigger) { iobCobCalculatorPlugin.stopCalculationTrigger = false aapsLogger.debug(LTag.AUTOSENS, "Aborting calculation thread (trigger): $from") @@ -325,7 +325,7 @@ class IobCobOref1Thread internal constructor( }.start() } finally { mWakeLock?.release() - rxBus.send(EventIobCalculationProgress("")) + rxBus.send(EventIobCalculationProgress("", cause)) aapsLogger.debug(LTag.AUTOSENS, "AUTOSENSDATA thread ended: $from") profiler.log(LTag.AUTOSENS, "IobCobOref1Thread", start) } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/IobCobThread.kt b/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/IobCobThread.kt index e6fa48cca2..cd3c12c438 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/IobCobThread.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/IobCobThread.kt @@ -98,7 +98,7 @@ class IobCobThread @Inject internal constructor( // start from oldest to be able sub cob for (i in bucketedData.size - 4 downTo 0) { val progress = i.toString() + if (buildHelper.isDev()) " ($from)" else "" - rxBus.send(EventIobCalculationProgress(progress)) + rxBus.send(EventIobCalculationProgress(progress, cause)) if (iobCobCalculatorPlugin.stopCalculationTrigger) { iobCobCalculatorPlugin.stopCalculationTrigger = false aapsLogger.debug(LTag.AUTOSENS, "Aborting calculation thread (trigger): $from") @@ -272,7 +272,7 @@ class IobCobThread @Inject internal constructor( }.start() } finally { mWakeLock?.release() - rxBus.send(EventIobCalculationProgress("")) + rxBus.send(EventIobCalculationProgress("", cause)) aapsLogger.debug(LTag.AUTOSENS, "AUTOSENSDATA thread ended: $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 f2e8059b10..a5326e4ad3 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 @@ -2,4 +2,4 @@ package info.nightscout.androidaps.plugins.iob.iobCobCalculator.events import info.nightscout.androidaps.events.Event -class EventIobCalculationProgress(var progress: String) : Event() \ No newline at end of file +class EventIobCalculationProgress(val progress: String, val cause: Event?) : Event() \ 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 98ce50f0c4..65bd506f7e 100644 --- a/app/src/main/res/layout/activity_historybrowse.xml +++ b/app/src/main/res/layout/activity_historybrowse.xml @@ -4,7 +4,7 @@ xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" - tools:context="info.nightscout.androidaps.historyBrowser.HistoryBrowseActivity"> + tools:context="info.nightscout.androidaps.activities.HistoryBrowseActivity"> diff --git a/app/src/test/java/info/nightscout/androidaps/interfaces/ConstraintsCheckerTest.kt b/app/src/test/java/info/nightscout/androidaps/interfaces/ConstraintsCheckerTest.kt index 8569bdc726..c560e0a38b 100644 --- a/app/src/test/java/info/nightscout/androidaps/interfaces/ConstraintsCheckerTest.kt +++ b/app/src/test/java/info/nightscout/androidaps/interfaces/ConstraintsCheckerTest.kt @@ -28,8 +28,6 @@ import info.nightscout.androidaps.plugins.pump.insight.LocalInsightPlugin import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpPlugin import info.nightscout.androidaps.plugins.sensitivity.SensitivityOref1Plugin import info.nightscout.androidaps.plugins.source.GlimpPlugin -import info.nightscout.androidaps.plugins.treatments.TreatmentService -import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin import info.nightscout.androidaps.utils.HardLimits import info.nightscout.androidaps.utils.Profiler import info.nightscout.androidaps.utils.buildHelper.BuildHelper @@ -51,7 +49,7 @@ import java.util.* @RunWith(PowerMockRunner::class) @PrepareForTest( ConstraintChecker::class, SP::class, Context::class, - OpenAPSAMAPlugin::class, OpenAPSSMBPlugin::class, TreatmentsPlugin::class, TreatmentService::class, + OpenAPSAMAPlugin::class, OpenAPSSMBPlugin::class, VirtualPumpPlugin::class, DetailedBolusInfoStorage::class, TemporaryBasalStorage::class, GlimpPlugin::class, Profiler::class, UserEntryLogger::class, LoggerUtils::class, AppRepository::class, InsightDatabaseDao::class) class ConstraintsCheckerTest : TestBaseWithProfile() { diff --git a/app/src/test/java/info/nightscout/androidaps/plugins/aps/loop/LoopPluginTest.kt b/app/src/test/java/info/nightscout/androidaps/plugins/aps/loop/LoopPluginTest.kt index f6ec5e4687..046472a25e 100644 --- a/app/src/test/java/info/nightscout/androidaps/plugins/aps/loop/LoopPluginTest.kt +++ b/app/src/test/java/info/nightscout/androidaps/plugins/aps/loop/LoopPluginTest.kt @@ -14,7 +14,6 @@ import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker import info.nightscout.androidaps.plugins.configBuilder.RunningConfiguration import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpPlugin -import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin import info.nightscout.androidaps.receivers.ReceiverStatusStore import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.FabricPrivacy @@ -41,7 +40,6 @@ class LoopPluginTest : TestBase() { @Mock lateinit var context: Context @Mock lateinit var commandQueue: CommandQueueProvider @Mock lateinit var activePlugin: ActivePlugin - @Mock lateinit var treatmentsPlugin: TreatmentsPlugin @Mock lateinit var virtualPumpPlugin: VirtualPumpPlugin @Mock lateinit var iobCobCalculator: IobCobCalculator @Mock lateinit var fabricPrivacy: FabricPrivacy diff --git a/app/src/test/java/info/nightscout/androidaps/queue/CommandQueueTest.kt b/app/src/test/java/info/nightscout/androidaps/queue/CommandQueueTest.kt index cd03c5cffa..ba57bfa9d1 100644 --- a/app/src/test/java/info/nightscout/androidaps/queue/CommandQueueTest.kt +++ b/app/src/test/java/info/nightscout/androidaps/queue/CommandQueueTest.kt @@ -20,7 +20,6 @@ import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker import info.nightscout.androidaps.plugins.general.maintenance.LoggerUtils import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpPlugin -import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin import info.nightscout.androidaps.queue.commands.* import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.FabricPrivacy @@ -45,7 +44,7 @@ import java.util.* @RunWith(PowerMockRunner::class) @PrepareForTest( ConstraintChecker::class, VirtualPumpPlugin::class, ToastUtils::class, Context::class, - TreatmentsPlugin::class, FabricPrivacy::class, LoggerUtils::class, PowerManager::class, + FabricPrivacy::class, LoggerUtils::class, PowerManager::class, AppRepository::class) class CommandQueueTest : TestBaseWithProfile() { diff --git a/app/src/test/java/info/nightscout/androidaps/queue/QueueThreadTest.kt b/app/src/test/java/info/nightscout/androidaps/queue/QueueThreadTest.kt index ff19abebf4..5dd203a40d 100644 --- a/app/src/test/java/info/nightscout/androidaps/queue/QueueThreadTest.kt +++ b/app/src/test/java/info/nightscout/androidaps/queue/QueueThreadTest.kt @@ -14,7 +14,6 @@ import info.nightscout.androidaps.interfaces.PumpSync import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker import info.nightscout.androidaps.plugins.general.maintenance.LoggerUtils import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpPlugin -import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin import info.nightscout.androidaps.queue.commands.Command import info.nightscout.androidaps.queue.commands.CommandTempBasalAbsolute import info.nightscout.androidaps.utils.FabricPrivacy @@ -34,7 +33,7 @@ import org.powermock.modules.junit4.PowerMockRunner @RunWith(PowerMockRunner::class) @PrepareForTest( ConstraintChecker::class, VirtualPumpPlugin::class, ToastUtils::class, Context::class, - TreatmentsPlugin::class, FabricPrivacy::class, LoggerUtils::class, PowerManager::class) + FabricPrivacy::class, LoggerUtils::class, PowerManager::class) class QueueThreadTest : TestBaseWithProfile() { @Mock lateinit var constraintChecker: ConstraintChecker diff --git a/app/src/test/java/info/nightscout/androidaps/utils/wizard/BolusWizardTest.kt b/app/src/test/java/info/nightscout/androidaps/utils/wizard/BolusWizardTest.kt index fa1e175567..38fd598f5e 100644 --- a/app/src/test/java/info/nightscout/androidaps/utils/wizard/BolusWizardTest.kt +++ b/app/src/test/java/info/nightscout/androidaps/utils/wizard/BolusWizardTest.kt @@ -13,7 +13,6 @@ import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensDataStore import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatusProvider import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpPlugin -import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.resources.ResourceHelper import org.junit.Assert @@ -40,7 +39,6 @@ class BolusWizardTest : TestBase() { @Mock lateinit var commandQueue: CommandQueueProvider @Mock lateinit var loopPlugin: LoopPlugin @Mock lateinit var iobCobCalculator: IobCobCalculator - @Mock lateinit var treatmentsPlugin: TreatmentsPlugin @Mock lateinit var virtualPumpPlugin: VirtualPumpPlugin @Mock lateinit var dateUtil: DateUtil @Mock lateinit var autosensDataStore: AutosensDataStore @@ -71,7 +69,6 @@ class BolusWizardTest : TestBase() { `when`(profile.getIc()).thenReturn(insulinToCarbRatio) `when`(profileFunction.getUnits()).thenReturn(GlucoseUnit.MGDL) - `when`(activePlugin.activeTreatments).thenReturn(treatmentsPlugin) `when`(iobCobCalculator.calculateIobFromBolus()).thenReturn(IobTotal(System.currentTimeMillis())) `when`(iobCobCalculator.calculateIobFromTempBasalsIncludingConvertedExtended()).thenReturn(IobTotal(System.currentTimeMillis())) `when`(activePlugin.activePump).thenReturn(virtualPumpPlugin)