diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 18750bfda8..77b68adf4a 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -68,7 +68,8 @@ - + + diff --git a/app/src/main/java/info/nightscout/androidaps/MainActivity.kt b/app/src/main/java/info/nightscout/androidaps/MainActivity.kt index 4fa4fbe4b9..42559a543b 100644 --- a/app/src/main/java/info/nightscout/androidaps/MainActivity.kt +++ b/app/src/main/java/info/nightscout/androidaps/MainActivity.kt @@ -27,18 +27,14 @@ import com.google.firebase.crashlytics.FirebaseCrashlytics import com.joanzapata.iconify.Iconify import com.joanzapata.iconify.fonts.FontAwesomeModule import dev.doubledot.doki.ui.DokiActivity -import info.nightscout.androidaps.activities.NoSplashAppCompatActivity -import info.nightscout.androidaps.activities.PreferencesActivity -import info.nightscout.androidaps.activities.ProfileHelperActivity -import info.nightscout.androidaps.activities.SingleFragmentActivity -import info.nightscout.androidaps.activities.StatsActivity +import info.nightscout.androidaps.activities.* import info.nightscout.androidaps.database.entities.UserEntry.Action import info.nightscout.androidaps.database.entities.UserEntry.Sources import info.nightscout.androidaps.databinding.ActivityMainBinding import info.nightscout.androidaps.events.EventAppExit import info.nightscout.androidaps.events.EventPreferenceChange import info.nightscout.androidaps.events.EventRebuildTabs -import info.nightscout.androidaps.historyBrowser.HistoryBrowseActivity +import info.nightscout.androidaps.activities.HistoryBrowseActivity import info.nightscout.androidaps.interfaces.ActivePlugin import info.nightscout.androidaps.interfaces.Config import info.nightscout.androidaps.interfaces.IconsProvider @@ -291,6 +287,11 @@ class MainActivity : NoSplashAppCompatActivity() { return true } + R.id.nav_treatments -> { + startActivity(Intent(this, TreatmentsActivity::class.java)) + return true + } + R.id.nav_setupwizard -> { protectionCheck.queryProtection(this, ProtectionCheck.Protection.PREFERENCES, { startActivity(Intent(this, SetupWizardActivity::class.java)) diff --git a/app/src/main/java/info/nightscout/androidaps/activities/HistoryBrowseActivity.kt b/app/src/main/java/info/nightscout/androidaps/activities/HistoryBrowseActivity.kt new file mode 100644 index 0000000000..6b0be2cc68 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/activities/HistoryBrowseActivity.kt @@ -0,0 +1,391 @@ +package info.nightscout.androidaps.activities + +import android.annotation.SuppressLint +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 com.jjoe64.graphview.GraphView +import dagger.android.HasAndroidInjector +import info.nightscout.androidaps.R +import info.nightscout.androidaps.database.AppRepository +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.Config +import info.nightscout.androidaps.interfaces.ProfileFunction +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.bus.RxBusWrapper +import info.nightscout.androidaps.plugins.general.nsclient.data.NSDeviceStatus +import info.nightscout.androidaps.plugins.general.overview.OverviewData +import info.nightscout.androidaps.plugins.general.overview.OverviewMenus +import info.nightscout.androidaps.plugins.general.overview.graphData.GraphData +import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin +import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventBucketedDataCreated +import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventIobCalculationProgress +import info.nightscout.androidaps.plugins.sensitivity.SensitivityAAPSPlugin +import info.nightscout.androidaps.plugins.sensitivity.SensitivityOref1Plugin +import info.nightscout.androidaps.plugins.sensitivity.SensitivityWeightedAveragePlugin +import info.nightscout.androidaps.utils.* +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 io.reactivex.rxkotlin.plusAssign +import java.util.* +import javax.inject.Inject +import kotlin.math.min + +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 activePlugin: ActivePlugin + @Inject lateinit var buildHelper: BuildHelper + @Inject lateinit var sensitivityOref1Plugin: SensitivityOref1Plugin + @Inject lateinit var sensitivityAAPSPlugin: SensitivityAAPSPlugin + @Inject lateinit var sensitivityWeightedAveragePlugin: SensitivityWeightedAveragePlugin + @Inject lateinit var repository: AppRepository + @Inject lateinit var fabricPrivacy: FabricPrivacy + @Inject lateinit var overviewMenus: OverviewMenus + @Inject lateinit var dateUtil: DateUtil + @Inject lateinit var config: Config + @Inject lateinit var loopPlugin: LoopPlugin + @Inject lateinit var nsDeviceStatus: NSDeviceStatus + @Inject lateinit var translator: Translator + + 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 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/plugins/treatments/TreatmentsFragment.kt b/app/src/main/java/info/nightscout/androidaps/activities/TreatmentsActivity.kt similarity index 53% rename from app/src/main/java/info/nightscout/androidaps/plugins/treatments/TreatmentsFragment.kt rename to app/src/main/java/info/nightscout/androidaps/activities/TreatmentsActivity.kt index 9de459f622..4cd4ab559a 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/treatments/TreatmentsFragment.kt +++ b/app/src/main/java/info/nightscout/androidaps/activities/TreatmentsActivity.kt @@ -1,53 +1,28 @@ -package info.nightscout.androidaps.plugins.treatments +package info.nightscout.androidaps.activities import android.os.Bundle -import android.view.LayoutInflater import android.view.View -import android.view.ViewGroup import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentTransaction -import dagger.android.support.DaggerFragment import info.nightscout.androidaps.R +import info.nightscout.androidaps.activities.fragments.* import info.nightscout.androidaps.databinding.TreatmentsFragmentBinding -import info.nightscout.androidaps.events.EventExtendedBolusChange -import info.nightscout.androidaps.interfaces.ActivePlugin -import info.nightscout.androidaps.interfaces.IobCobCalculator -import info.nightscout.androidaps.plugins.bus.RxBusWrapper -import info.nightscout.androidaps.plugins.treatments.fragments.* -import info.nightscout.androidaps.utils.DateUtil -import info.nightscout.androidaps.utils.FabricPrivacy -import info.nightscout.androidaps.utils.buildHelper.BuildHelper import info.nightscout.androidaps.extensions.toVisibility -import info.nightscout.androidaps.utils.resources.ResourceHelper -import info.nightscout.androidaps.utils.rx.AapsSchedulers -import io.reactivex.disposables.CompositeDisposable -import io.reactivex.rxkotlin.plusAssign +import info.nightscout.androidaps.interfaces.ActivePlugin +import info.nightscout.androidaps.utils.buildHelper.BuildHelper import javax.inject.Inject -class TreatmentsFragment : DaggerFragment() { +class TreatmentsActivity : NoSplashAppCompatActivity() { - @Inject lateinit var rxBus: RxBusWrapper - @Inject lateinit var resourceHelper: ResourceHelper - @Inject lateinit var fabricPrivacy: FabricPrivacy - @Inject lateinit var activePlugin: ActivePlugin - @Inject lateinit var iobCobCalculator: IobCobCalculator - @Inject lateinit var aapsSchedulers: AapsSchedulers @Inject lateinit var buildHelper: BuildHelper - @Inject lateinit var dateUtil: DateUtil + @Inject lateinit var activePlugin: ActivePlugin - private val disposable = CompositeDisposable() + private lateinit var binding: TreatmentsFragmentBinding - private var _binding: TreatmentsFragmentBinding? = null - - // This property is only valid between onCreateView and - // onDestroyView. - private val binding get() = _binding!! - - override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View = - TreatmentsFragmentBinding.inflate(inflater, container, false).also { _binding = it }.root - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + binding = TreatmentsFragmentBinding.inflate(layoutInflater) + setContentView(binding.root) binding.tempBasals.visibility = buildHelper.isEngineeringMode().toVisibility() binding.extendedBoluses.visibility = (buildHelper.isEngineeringMode() && !activePlugin.activePump.isFakingTempsByExtendedBoluses).toVisibility() @@ -84,33 +59,10 @@ class TreatmentsFragment : DaggerFragment() { setBackgroundColorOnSelected(binding.treatments) } - @Synchronized - override fun onResume() { - super.onResume() - disposable += rxBus - .toObservable(EventExtendedBolusChange::class.java) - .observeOn(aapsSchedulers.main) - .subscribe({ updateGui() }, fabricPrivacy::logException) - updateGui() - } - - @Synchronized - override fun onPause() { - super.onPause() - disposable.clear() - } - - @Synchronized - override fun onDestroyView() { - super.onDestroyView() - _binding = null - } - private fun setFragment(selectedFragment: Fragment) { - childFragmentManager.beginTransaction() - .replace(R.id.fragment_container, selectedFragment) // f2_container is your FrameLayout container - .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN) - .addToBackStack(null) + supportFragmentManager.beginTransaction() + .replace(R.id.fragment_container, selectedFragment) + .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE) .commit() } @@ -125,8 +77,4 @@ class TreatmentsFragment : DaggerFragment() { selected.setBackgroundColor(resourceHelper.gc(R.color.tabBgColorSelected)) } - private fun updateGui() { - if (_binding == null) return - binding.extendedBoluses.visibility = (activePlugin.activePump.pumpDescription.isExtendedBolusCapable || iobCobCalculator.getExtendedBolus(dateUtil.now()) != null).toVisibility() - } -} \ No newline at end of file +} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/treatments/fragments/TreatmentsBolusCarbsFragment.kt b/app/src/main/java/info/nightscout/androidaps/activities/fragments/TreatmentsBolusCarbsFragment.kt similarity index 99% rename from app/src/main/java/info/nightscout/androidaps/plugins/treatments/fragments/TreatmentsBolusCarbsFragment.kt rename to app/src/main/java/info/nightscout/androidaps/activities/fragments/TreatmentsBolusCarbsFragment.kt index 2ba8978ea8..4b5dc48e2a 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/treatments/fragments/TreatmentsBolusCarbsFragment.kt +++ b/app/src/main/java/info/nightscout/androidaps/activities/fragments/TreatmentsBolusCarbsFragment.kt @@ -1,4 +1,4 @@ -package info.nightscout.androidaps.plugins.treatments.fragments +package info.nightscout.androidaps.activities.fragments import android.graphics.Paint import android.os.Bundle diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/treatments/fragments/TreatmentsCareportalFragment.kt b/app/src/main/java/info/nightscout/androidaps/activities/fragments/TreatmentsCareportalFragment.kt similarity index 98% rename from app/src/main/java/info/nightscout/androidaps/plugins/treatments/fragments/TreatmentsCareportalFragment.kt rename to app/src/main/java/info/nightscout/androidaps/activities/fragments/TreatmentsCareportalFragment.kt index ce75d4dc3c..f3eb9e551f 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/treatments/fragments/TreatmentsCareportalFragment.kt +++ b/app/src/main/java/info/nightscout/androidaps/activities/fragments/TreatmentsCareportalFragment.kt @@ -1,4 +1,4 @@ -package info.nightscout.androidaps.plugins.treatments.fragments +package info.nightscout.androidaps.activities.fragments import android.graphics.Paint import android.os.Bundle @@ -25,7 +25,7 @@ import info.nightscout.androidaps.logging.UserEntryLogger import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientRestart import info.nightscout.androidaps.plugins.treatments.events.EventTreatmentUpdateGui -import info.nightscout.androidaps.plugins.treatments.fragments.TreatmentsCareportalFragment.RecyclerViewAdapter.TherapyEventsViewHolder +import info.nightscout.androidaps.activities.fragments.TreatmentsCareportalFragment.RecyclerViewAdapter.TherapyEventsViewHolder import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.FabricPrivacy import info.nightscout.androidaps.utils.T diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/treatments/fragments/TreatmentsExtendedBolusesFragment.kt b/app/src/main/java/info/nightscout/androidaps/activities/fragments/TreatmentsExtendedBolusesFragment.kt similarity index 97% rename from app/src/main/java/info/nightscout/androidaps/plugins/treatments/fragments/TreatmentsExtendedBolusesFragment.kt rename to app/src/main/java/info/nightscout/androidaps/activities/fragments/TreatmentsExtendedBolusesFragment.kt index 36b0a8a69a..d5dfec5f6c 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/treatments/fragments/TreatmentsExtendedBolusesFragment.kt +++ b/app/src/main/java/info/nightscout/androidaps/activities/fragments/TreatmentsExtendedBolusesFragment.kt @@ -1,4 +1,4 @@ -package info.nightscout.androidaps.plugins.treatments.fragments +package info.nightscout.androidaps.activities.fragments import android.annotation.SuppressLint import android.content.DialogInterface @@ -30,7 +30,7 @@ import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.logging.UserEntryLogger import info.nightscout.androidaps.plugins.bus.RxBusWrapper -import info.nightscout.androidaps.plugins.treatments.fragments.TreatmentsExtendedBolusesFragment.RecyclerViewAdapter.ExtendedBolusesViewHolder +import info.nightscout.androidaps.activities.fragments.TreatmentsExtendedBolusesFragment.RecyclerViewAdapter.ExtendedBolusesViewHolder import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.FabricPrivacy import info.nightscout.androidaps.utils.T diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/treatments/fragments/TreatmentsProfileSwitchFragment.kt b/app/src/main/java/info/nightscout/androidaps/activities/fragments/TreatmentsProfileSwitchFragment.kt similarity index 98% rename from app/src/main/java/info/nightscout/androidaps/plugins/treatments/fragments/TreatmentsProfileSwitchFragment.kt rename to app/src/main/java/info/nightscout/androidaps/activities/fragments/TreatmentsProfileSwitchFragment.kt index 796c811f0f..151b37234f 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/treatments/fragments/TreatmentsProfileSwitchFragment.kt +++ b/app/src/main/java/info/nightscout/androidaps/activities/fragments/TreatmentsProfileSwitchFragment.kt @@ -1,4 +1,4 @@ -package info.nightscout.androidaps.plugins.treatments.fragments +package info.nightscout.androidaps.activities.fragments import android.graphics.Paint import android.os.Bundle @@ -30,7 +30,7 @@ import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventNewHi import info.nightscout.androidaps.plugins.profile.local.LocalProfilePlugin import info.nightscout.androidaps.plugins.profile.local.events.EventLocalProfileChanged import info.nightscout.androidaps.plugins.treatments.events.EventTreatmentUpdateGui -import info.nightscout.androidaps.plugins.treatments.fragments.TreatmentsProfileSwitchFragment.RecyclerProfileViewAdapter.ProfileSwitchViewHolder +import info.nightscout.androidaps.activities.fragments.TreatmentsProfileSwitchFragment.RecyclerProfileViewAdapter.ProfileSwitchViewHolder import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.FabricPrivacy import info.nightscout.androidaps.utils.T diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/treatments/fragments/TreatmentsTempTargetFragment.kt b/app/src/main/java/info/nightscout/androidaps/activities/fragments/TreatmentsTempTargetFragment.kt similarity index 98% rename from app/src/main/java/info/nightscout/androidaps/plugins/treatments/fragments/TreatmentsTempTargetFragment.kt rename to app/src/main/java/info/nightscout/androidaps/activities/fragments/TreatmentsTempTargetFragment.kt index d603263fc1..16e8a5ae32 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/treatments/fragments/TreatmentsTempTargetFragment.kt +++ b/app/src/main/java/info/nightscout/androidaps/activities/fragments/TreatmentsTempTargetFragment.kt @@ -1,4 +1,4 @@ -package info.nightscout.androidaps.plugins.treatments.fragments +package info.nightscout.androidaps.activities.fragments import android.annotation.SuppressLint import android.content.DialogInterface @@ -29,7 +29,7 @@ import info.nightscout.androidaps.logging.UserEntryLogger import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientRestart import info.nightscout.androidaps.plugins.treatments.events.EventTreatmentUpdateGui -import info.nightscout.androidaps.plugins.treatments.fragments.TreatmentsTempTargetFragment.RecyclerViewAdapter.TempTargetsViewHolder +import info.nightscout.androidaps.activities.fragments.TreatmentsTempTargetFragment.RecyclerViewAdapter.TempTargetsViewHolder import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.FabricPrivacy import info.nightscout.androidaps.utils.T diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/treatments/fragments/TreatmentsTemporaryBasalsFragment.kt b/app/src/main/java/info/nightscout/androidaps/activities/fragments/TreatmentsTemporaryBasalsFragment.kt similarity index 98% rename from app/src/main/java/info/nightscout/androidaps/plugins/treatments/fragments/TreatmentsTemporaryBasalsFragment.kt rename to app/src/main/java/info/nightscout/androidaps/activities/fragments/TreatmentsTemporaryBasalsFragment.kt index c9bda0e311..590fef204f 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/treatments/fragments/TreatmentsTemporaryBasalsFragment.kt +++ b/app/src/main/java/info/nightscout/androidaps/activities/fragments/TreatmentsTemporaryBasalsFragment.kt @@ -1,4 +1,4 @@ -package info.nightscout.androidaps.plugins.treatments.fragments +package info.nightscout.androidaps.activities.fragments import android.content.DialogInterface import android.graphics.Paint @@ -36,7 +36,7 @@ import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.logging.UserEntryLogger import info.nightscout.androidaps.plugins.bus.RxBusWrapper -import info.nightscout.androidaps.plugins.treatments.fragments.TreatmentsTemporaryBasalsFragment.RecyclerViewAdapter.TempBasalsViewHolder +import info.nightscout.androidaps.activities.fragments.TreatmentsTemporaryBasalsFragment.RecyclerViewAdapter.TempBasalsViewHolder import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.FabricPrivacy import info.nightscout.androidaps.utils.T diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/treatments/fragments/TreatmentsUserEntryFragment.kt b/app/src/main/java/info/nightscout/androidaps/activities/fragments/TreatmentsUserEntryFragment.kt similarity index 99% rename from app/src/main/java/info/nightscout/androidaps/plugins/treatments/fragments/TreatmentsUserEntryFragment.kt rename to app/src/main/java/info/nightscout/androidaps/activities/fragments/TreatmentsUserEntryFragment.kt index 9bbc46d63b..b0936580ae 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/treatments/fragments/TreatmentsUserEntryFragment.kt +++ b/app/src/main/java/info/nightscout/androidaps/activities/fragments/TreatmentsUserEntryFragment.kt @@ -1,4 +1,4 @@ -package info.nightscout.androidaps.plugins.treatments.fragments +package info.nightscout.androidaps.activities.fragments import android.os.Bundle import android.view.LayoutInflater 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 95e0888b79..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 @@ -15,6 +15,7 @@ import info.nightscout.androidaps.setupwizard.SetupWizardActivity @Suppress("unused") abstract class ActivitiesModule { + @ContributesAndroidInjector abstract fun contributesTreatmentsActivity(): TreatmentsActivity @ContributesAndroidInjector abstract fun contributesHistoryBrowseActivity(): HistoryBrowseActivity @ContributesAndroidInjector abstract fun contributesLogSettingActivity(): LogSettingActivity @ContributesAndroidInjector abstract fun contributeMainActivity(): MainActivity diff --git a/app/src/main/java/info/nightscout/androidaps/dependencyInjection/FragmentsModule.kt b/app/src/main/java/info/nightscout/androidaps/dependencyInjection/FragmentsModule.kt index 60eb3ace15..84e4ef80fb 100644 --- a/app/src/main/java/info/nightscout/androidaps/dependencyInjection/FragmentsModule.kt +++ b/app/src/main/java/info/nightscout/androidaps/dependencyInjection/FragmentsModule.kt @@ -31,8 +31,7 @@ import info.nightscout.androidaps.plugins.insulin.InsulinFragment import info.nightscout.androidaps.plugins.profile.local.LocalProfileFragment import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpFragment import info.nightscout.androidaps.plugins.source.BGSourceFragment -import info.nightscout.androidaps.plugins.treatments.TreatmentsFragment -import info.nightscout.androidaps.plugins.treatments.fragments.* +import info.nightscout.androidaps.activities.fragments.* import info.nightscout.androidaps.utils.protection.PasswordCheck @Module @@ -61,7 +60,6 @@ abstract class FragmentsModule { @ContributesAndroidInjector abstract fun contributesWearFragment(): WearFragment @ContributesAndroidInjector abstract fun contributesTidepoolFragment(): TidepoolFragment - @ContributesAndroidInjector abstract fun contributesTreatmentsFragment(): TreatmentsFragment @ContributesAndroidInjector abstract fun contributesTreatmentsBolusFragment(): TreatmentsBolusCarbsFragment @ContributesAndroidInjector abstract fun contributesTreatmentsTemporaryBasalsFragment(): TreatmentsTemporaryBasalsFragment @ContributesAndroidInjector abstract fun contributesTreatmentsTempTargetFragment(): TreatmentsTempTargetFragment 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/configBuilder/ProfileFunctionImplementation.kt b/app/src/main/java/info/nightscout/androidaps/plugins/configBuilder/ProfileFunctionImplementation.kt index c5049d171d..26a478240a 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/configBuilder/ProfileFunctionImplementation.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/configBuilder/ProfileFunctionImplementation.kt @@ -104,7 +104,8 @@ class ProfileFunctionImplementation @Inject constructor( timeshift = T.hours(timeShiftInHours.toLong()).msecs(), percentage = percentage, duration = T.mins(durationInMinutes.toLong()).msecs(), - insulinConfiguration = activePlugin.activeInsulin.insulinConfiguration) + insulinConfiguration = activePlugin.activeInsulin.insulinConfiguration.also { it.insulinEndTime = (pureProfile.dia * 3600 * 1000).toLong() } + ) disposable += repository.runTransactionForResult(InsertOrUpdateProfileSwitch(ps)) .subscribe({ result -> result.inserted.forEach { aapsLogger.debug(LTag.DATABASE, "Inserted ProfileSwitch $it") } 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/nsclient/DataSyncSelectorImplementation.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/DataSyncSelectorImplementation.kt index 5f1e910af8..5f1844315f 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/DataSyncSelectorImplementation.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/DataSyncSelectorImplementation.kt @@ -561,9 +561,9 @@ class DataSyncSelectorImplementation @Inject constructor( val lastSync = sp.getLong(R.string.key_ns_profile_store_last_synced_timestamp, 0) val lastChange = sp.getLong(R.string.key_local_profile_last_change, 0) if (lastChange == 0L) return - localProfilePlugin.createProfileStore() - val profileJson = localProfilePlugin.profile?.data ?: return - if (lastChange > lastSync) + if (lastChange > lastSync) { + val profileJson = localProfilePlugin.profile?.data ?: return nsClientPlugin.nsClientService?.dbAdd("profile", profileJson, DataSyncSelector.PairProfileStore(profileJson, dateUtil.now()), "") + } } } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NSClientMbgWorker.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NSClientMbgWorker.kt index 8c73fd908f..b7f1d1540c 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NSClientMbgWorker.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NSClientMbgWorker.kt @@ -34,7 +34,7 @@ class NSClientMbgWorker( var ret = Result.success() val acceptNSData = sp.getBoolean(R.string.key_ns_receive_therapy_events, false) || config.NSCLIENT - if (!acceptNSData) return ret + if (!acceptNSData) return Result.success(workDataOf("Result" to "Sync not enabled")) val mbgArray = dataWorker.pickupJSONArray(inputData.getLong(DataWorker.STORE_KEY, -1)) ?: return Result.failure(workDataOf("Error" to "missing input data")) 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 1346374246..4beb99759a 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 9217164710..9f02c3297a 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 @@ -623,7 +620,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList binding.infoLayout.avgDelta.text = Profile.toSignedUnitsString(glucoseStatus.shortAvgDelta, glucoseStatus.shortAvgDelta * Constants.MGDL_TO_MMOLL, units) binding.infoLayout.longAvgDelta.text = Profile.toSignedUnitsString(glucoseStatus.longAvgDelta, glucoseStatus.longAvgDelta * Constants.MGDL_TO_MMOLL, units) } else { - binding.infoLayout.deltaLarge.text = "Δ " + resourceHelper.gs(R.string.notavailable) + binding.infoLayout.deltaLarge.text = "" binding.infoLayout.delta.text = "Δ " + resourceHelper.gs(R.string.notavailable) binding.infoLayout.avgDelta.text = "" binding.infoLayout.longAvgDelta.text = "" @@ -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 cbc021b421..0ffe4a9cb3 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 @@ -27,16 +27,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() @@ -214,7 +214,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/java/info/nightscout/androidaps/plugins/profile/local/LocalProfileFragment.kt b/app/src/main/java/info/nightscout/androidaps/plugins/profile/local/LocalProfileFragment.kt index 31f01df6c1..cef0babae1 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/profile/local/LocalProfileFragment.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/profile/local/LocalProfileFragment.kt @@ -70,7 +70,7 @@ class LocalProfileFragment : DaggerFragment() { } private fun sumLabel(): String { - val profile = localProfilePlugin.createProfileStore().getDefaultProfile() + val profile = localProfilePlugin.profile?.getDefaultProfile() val sum = profile?.let { ProfileSealed.Pure(profile).baseBasalSum() } ?: 0.0 return " ∑" + DecimalFormatter.to2Decimal(sum) + resourceHelper.gs(R.string.insulin_unit_shortname) } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/profile/local/LocalProfilePlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/profile/local/LocalProfilePlugin.kt index 42afbb4c5c..2feeab89d8 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/profile/local/LocalProfilePlugin.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/profile/local/LocalProfilePlugin.kt @@ -139,6 +139,7 @@ class LocalProfilePlugin @Inject constructor( } sp.putInt(Constants.LOCAL_PROFILE + "_profiles", numOfProfiles) + sp.putLong(R.string.key_local_profile_last_change, dateUtil.now()) createAndStoreConvertedProfile() isEdited = false aapsLogger.debug(LTag.PROFILE, "Storing settings: " + rawProfile?.data.toString()) @@ -148,12 +149,9 @@ class LocalProfilePlugin @Inject constructor( val name = it.name ?: "." if (name.contains(".")) namesOK = false } - if (namesOK) - sp.putLong(R.string.key_local_profile_last_change, dateUtil.now()) - else - activity?.let { - OKDialog.show(it, "", resourceHelper.gs(R.string.profilenamecontainsdot)) - } + if (!namesOK) activity?.let { + OKDialog.show(it, "", resourceHelper.gs(R.string.profilenamecontainsdot)) + } } @Synchronized @@ -372,7 +370,8 @@ class LocalProfilePlugin @Inject constructor( } } if (numOfProfiles > 0) json.put("defaultProfile", currentProfile()?.name) - json.put("startDate", dateUtil.toISOAsUTC(dateUtil.now())) + val startDate = sp.getLong(R.string.key_local_profile_last_change, dateUtil.now()) + json.put("startDate", dateUtil.toISOAsUTC(startDate)) json.put("store", store) } catch (e: JSONException) { aapsLogger.error("Unhandled exception", e) @@ -412,11 +411,19 @@ class LocalProfilePlugin @Inject constructor( val profileJson = dataWorker.pickupJSONObject(inputData.getLong(DataWorker.STORE_KEY, -1)) ?: return Result.failure(workDataOf("Error" to "missing input data")) if (sp.getBoolean(R.string.key_ns_receive_profile_store, false) || config.NSCLIENT) { - localProfilePlugin.loadFromStore(ProfileStore(injector, profileJson, dateUtil)) - aapsLogger.debug(LTag.PROFILE, "Received profileStore: $profileJson") - return Result.success(workDataOf("Data" to profileJson.toString().substring(0..min(5000, profileJson.length())))) + val store = ProfileStore(injector, profileJson, dateUtil) + val startDate = store.getStartDate() + val lastLocalChange = sp.getLong(R.string.key_local_profile_last_change, 0) + aapsLogger.debug(LTag.PROFILE, "Received profileStore: StartDate: $startDate Local last modification: $lastLocalChange") + @Suppress("LiftReturnOrAssignment") + if (startDate > lastLocalChange || startDate % 1000 == 0L) {// whole second means edited in NS + localProfilePlugin.loadFromStore(store) + aapsLogger.debug(LTag.PROFILE, "Received profileStore: $profileJson") + return Result.success(workDataOf("Data" to profileJson.toString().substring(0..min(5000, profileJson.length())))) + } else + return Result.success(workDataOf("Result" to "Unchanged. Ignoring")) } - return Result.success() + return Result.success(workDataOf("Result" to "Sync not enabled")) } } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/source/DexcomPlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/source/DexcomPlugin.kt index 6b6cb588e8..d744d81340 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/source/DexcomPlugin.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/source/DexcomPlugin.kt @@ -94,7 +94,7 @@ class DexcomPlugin @Inject constructor( override fun doWork(): Result { var ret = Result.success() - if (!dexcomPlugin.isEnabled(PluginType.BGSOURCE)) return Result.success() + if (!dexcomPlugin.isEnabled(PluginType.BGSOURCE)) return Result.success(workDataOf("Result" to "Plugin not enabled")) val bundle = dataWorker.pickupBundle(inputData.getLong(DataWorker.STORE_KEY, -1)) ?: return Result.failure(workDataOf("Error" to "missing input data")) try { diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/source/EversensePlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/source/EversensePlugin.kt index 434e5eb873..a6c51cf5de 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/source/EversensePlugin.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/source/EversensePlugin.kt @@ -69,7 +69,7 @@ class EversensePlugin @Inject constructor( override fun doWork(): Result { var ret = Result.success() - if (!eversensePlugin.isEnabled(PluginType.BGSOURCE)) return Result.success() + if (!eversensePlugin.isEnabled(PluginType.BGSOURCE)) return Result.success(workDataOf("Result" to "Plugin not enabled")) val bundle = dataWorker.pickupBundle(inputData.getLong(DataWorker.STORE_KEY, -1)) ?: return Result.failure(workDataOf("Error" to "missing input data")) if (bundle.containsKey("currentCalibrationPhase")) aapsLogger.debug(LTag.BGSOURCE, "currentCalibrationPhase: " + bundle.getString("currentCalibrationPhase")) diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/source/GlimpPlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/source/GlimpPlugin.kt index 36724eb4b5..d2b167a43d 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/source/GlimpPlugin.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/source/GlimpPlugin.kt @@ -56,7 +56,7 @@ class GlimpPlugin @Inject constructor( override fun doWork(): Result { var ret = Result.success() - if (!glimpPlugin.isEnabled(PluginType.BGSOURCE)) return Result.success() + if (!glimpPlugin.isEnabled(PluginType.BGSOURCE)) return Result.success(workDataOf("Result" to "Plugin not enabled")) aapsLogger.debug(LTag.BGSOURCE, "Received Glimp Data: $inputData}") val glucoseValues = mutableListOf() glucoseValues += CgmSourceTransaction.TransactionGlucoseValue( diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/source/NSClientSourcePlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/source/NSClientSourcePlugin.kt index 52874bb335..a0aa888901 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/source/NSClientSourcePlugin.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/source/NSClientSourcePlugin.kt @@ -115,7 +115,7 @@ class NSClientSourcePlugin @Inject constructor( override fun doWork(): Result { var ret = Result.success() - if (!nsClientSourcePlugin.isEnabled() && !sp.getBoolean(R.string.key_ns_receive_cgm, true) && !dexcomPlugin.isEnabled()) return Result.success() + if (!nsClientSourcePlugin.isEnabled() && !sp.getBoolean(R.string.key_ns_receive_cgm, true) && !dexcomPlugin.isEnabled()) return Result.success(workDataOf("Result" to "Sync not enabled")) val sgvs = dataWorker.pickupJSONArray(inputData.getLong(DataWorker.STORE_KEY, -1)) ?: return Result.failure(workDataOf("Error" to "missing input data")) diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/source/PoctechPlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/source/PoctechPlugin.kt index 17aefac5b5..fa7e0a278a 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/source/PoctechPlugin.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/source/PoctechPlugin.kt @@ -60,7 +60,7 @@ class PoctechPlugin @Inject constructor( override fun doWork(): Result { var ret = Result.success() - if (!poctechPlugin.isEnabled(PluginType.BGSOURCE)) return Result.success() + if (!poctechPlugin.isEnabled(PluginType.BGSOURCE)) return Result.success(workDataOf("Result" to "Plugin not enabled")) aapsLogger.debug(LTag.BGSOURCE, "Received Poctech Data $inputData") try { val glucoseValues = mutableListOf() diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/source/TomatoPlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/source/TomatoPlugin.kt index cf6fce3da5..52773e1d76 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/source/TomatoPlugin.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/source/TomatoPlugin.kt @@ -59,7 +59,7 @@ class TomatoPlugin @Inject constructor( override fun doWork(): Result { var ret = Result.success() - if (!tomatoPlugin.isEnabled(PluginType.BGSOURCE)) return Result.success() + if (!tomatoPlugin.isEnabled(PluginType.BGSOURCE)) return Result.success(workDataOf("Result" to "Plugin not enabled")) val glucoseValues = mutableListOf() glucoseValues += CgmSourceTransaction.TransactionGlucoseValue( timestamp = inputData.getLong("com.fanqies.tomatofn.Extras.Time", 0), diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/source/XdripPlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/source/XdripPlugin.kt index 622d69c284..bbb8b2c7e1 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/source/XdripPlugin.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/source/XdripPlugin.kt @@ -73,7 +73,7 @@ class XdripPlugin @Inject constructor( override fun doWork(): Result { var ret = Result.success() - if (!xdripPlugin.isEnabled(PluginType.BGSOURCE)) return Result.success() + if (!xdripPlugin.isEnabled(PluginType.BGSOURCE)) return Result.success(workDataOf("Result" to "Plugin not enabled")) val bundle = dataWorker.pickupBundle(inputData.getLong(DataWorker.STORE_KEY, -1)) ?: return Result.failure(workDataOf("Error" to "missing input data")) diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/treatments/TreatmentsPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/treatments/TreatmentsPlugin.java index d994c0475f..04345c3c6d 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/treatments/TreatmentsPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/treatments/TreatmentsPlugin.java @@ -67,7 +67,6 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface ) { super(new PluginDescription() .mainType(PluginType.TREATMENT) - .fragmentClass(TreatmentsFragment.class.getName()) .pluginIcon(R.drawable.ic_treatments) .pluginName(R.string.treatments) .shortName(R.string.treatments_shortname) diff --git a/app/src/main/java/info/nightscout/androidaps/queue/CommandQueue.kt b/app/src/main/java/info/nightscout/androidaps/queue/CommandQueue.kt index 448e917ae9..d759844d87 100644 --- a/app/src/main/java/info/nightscout/androidaps/queue/CommandQueue.kt +++ b/app/src/main/java/info/nightscout/androidaps/queue/CommandQueue.kt @@ -566,11 +566,12 @@ open class CommandQueue @Inject constructor( return HtmlHelper.fromHtml(s) } - override fun isThisProfileSet(profile: Profile): Boolean { - val result = activePlugin.activePump.isThisProfileSet(profile) + override fun isThisProfileSet(requestedProfile: Profile): Boolean { + val runningProfile = profileFunction.getProfile() ?: return false + val result = activePlugin.activePump.isThisProfileSet(requestedProfile) && requestedProfile.isEqual(runningProfile) if (!result) { aapsLogger.debug(LTag.PUMPQUEUE, "Current profile: ${profileFunction.getProfile()}") - aapsLogger.debug(LTag.PUMPQUEUE, "New profile: $profile") + aapsLogger.debug(LTag.PUMPQUEUE, "New profile: $requestedProfile") } return result } diff --git a/app/src/main/java/info/nightscout/androidaps/receivers/KeepAliveReceiver.kt b/app/src/main/java/info/nightscout/androidaps/receivers/KeepAliveReceiver.kt index 1b78360966..48f073e804 100644 --- a/app/src/main/java/info/nightscout/androidaps/receivers/KeepAliveReceiver.kt +++ b/app/src/main/java/info/nightscout/androidaps/receivers/KeepAliveReceiver.kt @@ -119,18 +119,18 @@ class KeepAliveReceiver : DaggerBroadcastReceiver() { private fun checkPump() { val pump = activePlugin.activePump val ps = profileFunction.getRequestedProfile() ?: return - val profile = ProfileSealed.PS(ps) + val requestedProfile = ProfileSealed.PS(ps) + val runningProfile = profileFunction.getProfile() val lastConnection = pump.lastDataTime() val isStatusOutdated = lastConnection + STATUS_UPDATE_FREQUENCY < System.currentTimeMillis() - val isBasalOutdated = abs(profile.getBasal() - pump.baseBasalRate) > pump.pumpDescription.basalStep + val isBasalOutdated = abs(requestedProfile.getBasal() - pump.baseBasalRate) > pump.pumpDescription.basalStep aapsLogger.debug(LTag.CORE, "Last connection: " + dateUtil.dateAndTimeString(lastConnection)) // sometimes keep alive broadcast stops // as as workaround test if readStatus was requested before an alarm is generated if (lastReadStatus != 0L && lastReadStatus > System.currentTimeMillis() - T.mins(5).msecs()) { localAlertUtils.checkPumpUnreachableAlarm(lastConnection, isStatusOutdated, loopPlugin.isDisconnected) } - if (!pump.isThisProfileSet(profile) && !commandQueue.isRunning(Command.CommandType.BASAL_PROFILE) - || profileFunction.getProfile() == null) { + if (runningProfile == null || ((!pump.isThisProfileSet(requestedProfile) || !requestedProfile.isEqual(runningProfile)) && !commandQueue.isRunning(Command.CommandType.BASAL_PROFILE))) { rxBus.send(EventProfileSwitchChanged()) } else if (isStatusOutdated && !pump.isBusy()) { lastReadStatus = System.currentTimeMillis() 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/main/res/layout/localprofile_fragment.xml b/app/src/main/res/layout/localprofile_fragment.xml index 920d10f4ee..e66a0c9c62 100644 --- a/app/src/main/res/layout/localprofile_fragment.xml +++ b/app/src/main/res/layout/localprofile_fragment.xml @@ -239,7 +239,7 @@ android:layout_marginBottom="10dp" android:orientation="vertical" /> - + tools:context="info.nightscout.androidaps.activities.fragments.TreatmentsBolusCarbsFragment"> + tools:context="info.nightscout.androidaps.activities.fragments.TreatmentsCareportalFragment"> + tools:context="info.nightscout.androidaps.activities.fragments.TreatmentsExtendedBolusesFragment"> + tools:context="info.nightscout.androidaps.activities.TreatmentsActivity"> + tools:context="info.nightscout.androidaps.activities.fragments.TreatmentsProfileSwitchFragment"> + tools:context="info.nightscout.androidaps.activities.fragments.TreatmentsTemporaryBasalsFragment"> + tools:context="info.nightscout.androidaps.activities.fragments.TreatmentsTempTargetFragment"> + tools:context="info.nightscout.androidaps.activities.fragments.TreatmentsUserEntryFragment"> + ): Boolean fun isCustomCommandInQueue(customCommandType: Class): Boolean fun spannedStatus(): Spanned - fun isThisProfileSet(profile: Profile): Boolean + fun isThisProfileSet(requestedProfile: Profile): Boolean } \ No newline at end of file diff --git a/core/src/main/java/info/nightscout/androidaps/interfaces/ProfileStore.kt b/core/src/main/java/info/nightscout/androidaps/interfaces/ProfileStore.kt index 91a00c4dc4..5884128606 100644 --- a/core/src/main/java/info/nightscout/androidaps/interfaces/ProfileStore.kt +++ b/core/src/main/java/info/nightscout/androidaps/interfaces/ProfileStore.kt @@ -31,6 +31,15 @@ class ProfileStore(val injector: HasAndroidInjector, val data: JSONObject, val d return null } + fun getStartDate(): Long { + val iso = JsonHelper.safeGetString(data, "startDate") ?: return 0 + return try { + dateUtil.fromISODateString(iso) + } catch (e: Exception) { + 0 + } + } + fun getDefaultProfile(): PureProfile? = getDefaultProfileName()?.let { getSpecificProfile(it) } fun getDefaultProfileJson(): JSONObject? = getDefaultProfileName()?.let { getSpecificProfileJson(it) } diff --git a/core/src/main/java/info/nightscout/androidaps/plugins/pump/common/bolusInfo/DetailedBolusInfoStorage.kt b/core/src/main/java/info/nightscout/androidaps/plugins/pump/common/bolusInfo/DetailedBolusInfoStorage.kt index 062d41191f..57a732cbc3 100644 --- a/core/src/main/java/info/nightscout/androidaps/plugins/pump/common/bolusInfo/DetailedBolusInfoStorage.kt +++ b/core/src/main/java/info/nightscout/androidaps/plugins/pump/common/bolusInfo/DetailedBolusInfoStorage.kt @@ -29,7 +29,7 @@ class DetailedBolusInfoStorage @Inject constructor( val d = store[i] //aapsLogger.debug(LTag.PUMP, "Existing bolus info: " + store[i]) if (bolusTime > d.timestamp - T.mins(1).msecs() && bolusTime < d.timestamp + T.mins(1).msecs() && abs(store[i].insulin - bolus) < 0.01) { - aapsLogger.debug(LTag.PUMP, "Using & removing bolus info: ${store[i]}") + aapsLogger.debug(LTag.PUMP, "Using & removing bolus info for time $bolusTime: ${store[i]}") store.removeAt(i) return d } @@ -38,22 +38,22 @@ class DetailedBolusInfoStorage @Inject constructor( for (i in store.indices) { val d = store[i] if (bolusTime > d.timestamp - T.mins(1).msecs() && bolusTime < d.timestamp + T.mins(1).msecs() && bolus <= store[i].insulin + 0.01) { - aapsLogger.debug(LTag.PUMP, "Using TIME-ONLY & removing bolus info: ${store[i]}") + aapsLogger.debug(LTag.PUMP, "Using TIME-ONLY & removing bolus info for time $bolusTime: ${store[i]}") store.removeAt(i) return d } } // If not found, use last record if amount is the same - if (store.size > 0) { - val d = store[store.size - 1] - if (abs(d.insulin - bolus) < 0.01) { - aapsLogger.debug(LTag.PUMP, "Using LAST & removing bolus info: $d") - store.removeAt(store.size - 1) - return d - } - } + // if (store.size > 0) { + // val d = store[store.size - 1] + // if (abs(d.insulin - bolus) < 0.01) { + // aapsLogger.debug(LTag.PUMP, "Using LAST & removing bolus info for time $bolusTime: $d") + // store.removeAt(store.size - 1) + // return d + // } + // } //Not found - //aapsLogger.debug(LTag.PUMP, "Bolus info not found") + aapsLogger.debug(LTag.PUMP, "Bolus info not found for time $bolusTime") return null } } \ No newline at end of file diff --git a/core/src/main/java/info/nightscout/androidaps/plugins/treatments/fragments/ProfileGraph.kt b/core/src/main/java/info/nightscout/androidaps/utils/ui/ProfileGraph.kt similarity index 96% rename from core/src/main/java/info/nightscout/androidaps/plugins/treatments/fragments/ProfileGraph.kt rename to core/src/main/java/info/nightscout/androidaps/utils/ui/ProfileGraph.kt index 0623cbaf40..61e4f64a74 100644 --- a/core/src/main/java/info/nightscout/androidaps/plugins/treatments/fragments/ProfileGraph.kt +++ b/core/src/main/java/info/nightscout/androidaps/utils/ui/ProfileGraph.kt @@ -1,7 +1,6 @@ -package info.nightscout.androidaps.plugins.treatments.fragments +package info.nightscout.androidaps.utils.ui import android.content.Context -import android.graphics.Color import android.util.AttributeSet import com.jjoe64.graphview.GraphView import com.jjoe64.graphview.series.DataPoint @@ -9,7 +8,7 @@ import com.jjoe64.graphview.series.LineGraphSeries import info.nightscout.androidaps.core.R import info.nightscout.androidaps.interfaces.Profile import info.nightscout.androidaps.utils.Round -import java.util.* +import java.util.ArrayList import kotlin.math.max class ProfileGraph : GraphView { diff --git a/core/src/main/res/layout/dialog_profileviewer.xml b/core/src/main/res/layout/dialog_profileviewer.xml index 822213e76c..7f02c1457e 100644 --- a/core/src/main/res/layout/dialog_profileviewer.xml +++ b/core/src/main/res/layout/dialog_profileviewer.xml @@ -371,7 +371,7 @@ - ? = null @@ -326,13 +323,16 @@ class BLEComm @Inject internal constructor( } private val readBuffer = ByteArray(1024) - private var bufferLength = 0 + @Volatile private var bufferLength = 0 private fun addToReadBuffer(buffer: ByteArray) { //log.debug("addToReadBuffer " + DanaRS_Packet.toHexString(buffer)); if (buffer.isEmpty()) { return } + if (bufferLength == 1024) { + aapsLogger.debug(LTag.PUMPBTCOMM, "1024 XXXXXXXXXXXXXX") + } synchronized(readBuffer) { // Append incoming data to input buffer System.arraycopy(buffer, 0, readBuffer, bufferLength, buffer.size) @@ -342,21 +342,23 @@ class BLEComm @Inject internal constructor( @kotlin.ExperimentalStdlibApi private fun readDataParsing(receivedData: ByteArray) { - //aapsLogger.debug(LTag.PUMPBTCOMM, "readDataParsing") + //aapsLogger.debug(LTag.PUMPBTCOMM, "<<<<< readDataParsing " + DanaRS_Packet.toHexString(receivedData)) var startSignatureFound = false var packetIsValid = false var isProcessing: Boolean isProcessing = true - var inputBuffer: ByteArray? = null + var inputBuffer: ByteArray? // decrypt 2nd level after successful connection - val incomingBuffer = if (encryption == EncryptionType.ENCRYPTION_RSv3 && isConnected) - bleEncryption.decryptSecondLevelPacket(receivedData).also { - encryptedDataRead = true - sp.putLong(R.string.key_rs_last_clear_key_request, 0L) - } - else receivedData + val incomingBuffer = + if (isConnected && (encryption == EncryptionType.ENCRYPTION_RSv3 || encryption == EncryptionType.ENCRYPTION_BLE5)) + bleEncryption.decryptSecondLevelPacket(receivedData).also { + encryptedDataRead = true + sp.putLong(R.string.key_rs_last_clear_key_request, 0L) + } + else receivedData addToReadBuffer(incomingBuffer) + //aapsLogger.debug(LTag.PUMPBTCOMM, "incomingBuffer " + DanaRS_Packet.toHexString(incomingBuffer)) while (isProcessing) { var length = 0 @@ -386,58 +388,29 @@ class BLEComm @Inject internal constructor( // Verify packed end [5A 5A] if (readBuffer[length + 5] == PACKET_END_BYTE && readBuffer[length + 6] == PACKET_END_BYTE) { packetIsValid = true + } else if (readBuffer[length + 5] == readBuffer[length + 6]) { + // BLE5 + packetIsValid = true + readBuffer[length + 5] = PACKET_END_BYTE + readBuffer[length + 6] = PACKET_END_BYTE } } - // packet can be BLE5 encrypted too - if (!packetIsValid && encryption == EncryptionType.ENCRYPTION_BLE5) { - var startIndex: Int = -1 - // Find encrypted packet start [73 73] - if (bufferLength >= 6) { - for (idxStartByte in 0 until bufferLength - 2) { - if (readBuffer[idxStartByte] == BLE5_PACKET_START_BYTE && readBuffer[idxStartByte + 1] == BLE5_PACKET_START_BYTE) { - if (idxStartByte > 0) { - // if buffer doesn't start with signature remove the leading trash - aapsLogger.debug(LTag.PUMPBTCOMM, "Shifting the input buffer by $idxStartByte bytes") - System.arraycopy(readBuffer, idxStartByte, readBuffer, 0, bufferLength - idxStartByte) - bufferLength -= idxStartByte - } - startIndex = idxStartByte - break - } - } - } - // 73 73 ENCRYPTED CONTENT BF BF - if (startIndex != -1) { - for (idxEndByte in 5..bufferLength - 2) { - if (readBuffer[idxEndByte] == BLE5_PACKET_END_BYTE && readBuffer[idxEndByte + 1] == BLE5_PACKET_END_BYTE) { - length = idxEndByte - startIndex + 2 - 7 - packetIsValid = true - encryptedDataRead = true - break - } - } - } - } - if (packetIsValid) { - inputBuffer = ByteArray(length + 7) - // copy packet to input buffer - System.arraycopy(readBuffer, 0, inputBuffer, 0, length + 7) - // Cut off the message from readBuffer - try { - System.arraycopy(readBuffer, length + 7, readBuffer, 0, bufferLength - (length + 7)) - } catch (e: Exception) { - aapsLogger.error("length: " + length + "bufferLength: " + bufferLength) - throw e - } - bufferLength -= length + 7 - // now we have encrypted packet in inputBuffer - } - } - if (packetIsValid && encryptedDataRead && encryption == EncryptionType.ENCRYPTION_BLE5) { - inputBuffer = bleEncryption.decryptSecondLevelPacket(inputBuffer) } if (packetIsValid) { - // aapsLogger.debug(LTag.PUMPBTCOMM, "<<<<< PROCESSING: " + DanaRS_Packet.toHexString(inputBuffer)) + inputBuffer = ByteArray(length + 7) + // copy packet to input buffer + System.arraycopy(readBuffer, 0, inputBuffer, 0, length + 7) + // Cut off the message from readBuffer + try { + System.arraycopy(readBuffer, length + 7, readBuffer, 0, bufferLength - (length + 7)) + } catch (e: Exception) { + aapsLogger.error("length: " + length + "bufferLength: " + bufferLength) + throw e + } + bufferLength -= length + 7 + // now we have encrypted packet in inputBuffer + + //aapsLogger.debug(LTag.PUMPBTCOMM, "<<<<< PROCESSING: " + DanaRS_Packet.toHexString(inputBuffer)) // decrypt the packet bleEncryption.getDecryptedPacket(inputBuffer)?.let { decryptedBuffer -> if (decryptedBuffer[0] == BleEncryption.DANAR_PACKET__TYPE_ENCRYPTION_RESPONSE.toByte()) { diff --git a/danars/src/main/jniLibs/arm64-v8a/libBleEncryption.so b/danars/src/main/jniLibs/arm64-v8a/libBleEncryption.so index ce5fff9e71..7c0c49b7e8 100644 Binary files a/danars/src/main/jniLibs/arm64-v8a/libBleEncryption.so and b/danars/src/main/jniLibs/arm64-v8a/libBleEncryption.so differ diff --git a/danars/src/main/jniLibs/armeabi-v7a/libBleEncryption.so b/danars/src/main/jniLibs/armeabi-v7a/libBleEncryption.so index eab5691db8..4778aca663 100644 Binary files a/danars/src/main/jniLibs/armeabi-v7a/libBleEncryption.so and b/danars/src/main/jniLibs/armeabi-v7a/libBleEncryption.so differ diff --git a/danars/src/main/jniLibs/x86/libBleEncryption.so b/danars/src/main/jniLibs/x86/libBleEncryption.so index 9885d73606..e5ef3a17a4 100644 Binary files a/danars/src/main/jniLibs/x86/libBleEncryption.so and b/danars/src/main/jniLibs/x86/libBleEncryption.so differ diff --git a/danars/src/main/jniLibs/x86_64/libBleEncryption.so b/danars/src/main/jniLibs/x86_64/libBleEncryption.so index 00e47ca4d3..e4c02d8842 100644 Binary files a/danars/src/main/jniLibs/x86_64/libBleEncryption.so and b/danars/src/main/jniLibs/x86_64/libBleEncryption.so differ diff --git a/database/src/main/java/info/nightscout/androidaps/database/daos/GlucoseValueDao.kt b/database/src/main/java/info/nightscout/androidaps/database/daos/GlucoseValueDao.kt index 27cde3dbe4..bda5c63b2f 100644 --- a/database/src/main/java/info/nightscout/androidaps/database/daos/GlucoseValueDao.kt +++ b/database/src/main/java/info/nightscout/androidaps/database/daos/GlucoseValueDao.kt @@ -16,7 +16,7 @@ internal interface GlucoseValueDao : TraceableDao { @Query("DELETE FROM $TABLE_GLUCOSE_VALUES") override fun deleteAllEntries() - @Query("SELECT * FROM $TABLE_GLUCOSE_VALUES ORDER BY id DESC limit 1") + @Query("SELECT * FROM $TABLE_GLUCOSE_VALUES WHERE isValid = 1 AND referenceId IS NULL ORDER BY id DESC limit 1") fun getLast(): Maybe @Query("SELECT id FROM $TABLE_GLUCOSE_VALUES ORDER BY id DESC limit 1")