Merge branch 'dev' into FixSensScale

This commit is contained in:
Philoul 2021-05-25 22:56:00 +02:00
commit 3a24af1a4c
68 changed files with 1257 additions and 1354 deletions

View file

@ -68,7 +68,8 @@
</intent-filter> </intent-filter>
</activity> </activity>
<activity android:name=".plugins.general.maintenance.activities.PrefImportListActivity" /> <activity android:name=".plugins.general.maintenance.activities.PrefImportListActivity" />
<activity android:name=".historyBrowser.HistoryBrowseActivity" /> <activity android:name=".activities.HistoryBrowseActivity" />
<activity android:name=".activities.TreatmentsActivity" />
<activity android:name=".activities.SurveyActivity" /> <activity android:name=".activities.SurveyActivity" />
<activity android:name=".activities.ProfileHelperActivity" <activity android:name=".activities.ProfileHelperActivity"
android:theme="@style/ProfileHelperAppTheme" /> android:theme="@style/ProfileHelperAppTheme" />

View file

@ -27,18 +27,14 @@ import com.google.firebase.crashlytics.FirebaseCrashlytics
import com.joanzapata.iconify.Iconify import com.joanzapata.iconify.Iconify
import com.joanzapata.iconify.fonts.FontAwesomeModule import com.joanzapata.iconify.fonts.FontAwesomeModule
import dev.doubledot.doki.ui.DokiActivity import dev.doubledot.doki.ui.DokiActivity
import info.nightscout.androidaps.activities.NoSplashAppCompatActivity import info.nightscout.androidaps.activities.*
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.database.entities.UserEntry.Action import info.nightscout.androidaps.database.entities.UserEntry.Action
import info.nightscout.androidaps.database.entities.UserEntry.Sources import info.nightscout.androidaps.database.entities.UserEntry.Sources
import info.nightscout.androidaps.databinding.ActivityMainBinding import info.nightscout.androidaps.databinding.ActivityMainBinding
import info.nightscout.androidaps.events.EventAppExit import info.nightscout.androidaps.events.EventAppExit
import info.nightscout.androidaps.events.EventPreferenceChange import info.nightscout.androidaps.events.EventPreferenceChange
import info.nightscout.androidaps.events.EventRebuildTabs 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.ActivePlugin
import info.nightscout.androidaps.interfaces.Config import info.nightscout.androidaps.interfaces.Config
import info.nightscout.androidaps.interfaces.IconsProvider import info.nightscout.androidaps.interfaces.IconsProvider
@ -291,6 +287,11 @@ class MainActivity : NoSplashAppCompatActivity() {
return true return true
} }
R.id.nav_treatments -> {
startActivity(Intent(this, TreatmentsActivity::class.java))
return true
}
R.id.nav_setupwizard -> { R.id.nav_setupwizard -> {
protectionCheck.queryProtection(this, ProtectionCheck.Protection.PREFERENCES, { protectionCheck.queryProtection(this, ProtectionCheck.Protection.PREFERENCES, {
startActivity(Intent(this, SetupWizardActivity::class.java)) startActivity(Intent(this, SetupWizardActivity::class.java))

View file

@ -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<GraphView>()
private val secondaryGraphsLabel = ArrayList<TextView>()
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<GraphData> = 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()
}
}
}

View file

@ -1,53 +1,28 @@
package info.nightscout.androidaps.plugins.treatments package info.nightscout.androidaps.activities
import android.os.Bundle import android.os.Bundle
import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentTransaction import androidx.fragment.app.FragmentTransaction
import dagger.android.support.DaggerFragment
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.activities.fragments.*
import info.nightscout.androidaps.databinding.TreatmentsFragmentBinding 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.extensions.toVisibility
import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.interfaces.ActivePlugin
import info.nightscout.androidaps.utils.rx.AapsSchedulers import info.nightscout.androidaps.utils.buildHelper.BuildHelper
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.rxkotlin.plusAssign
import javax.inject.Inject 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 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 override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// This property is only valid between onCreateView and binding = TreatmentsFragmentBinding.inflate(layoutInflater)
// onDestroyView. setContentView(binding.root)
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)
binding.tempBasals.visibility = buildHelper.isEngineeringMode().toVisibility() binding.tempBasals.visibility = buildHelper.isEngineeringMode().toVisibility()
binding.extendedBoluses.visibility = (buildHelper.isEngineeringMode() && !activePlugin.activePump.isFakingTempsByExtendedBoluses).toVisibility() binding.extendedBoluses.visibility = (buildHelper.isEngineeringMode() && !activePlugin.activePump.isFakingTempsByExtendedBoluses).toVisibility()
@ -84,33 +59,10 @@ class TreatmentsFragment : DaggerFragment() {
setBackgroundColorOnSelected(binding.treatments) 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) { private fun setFragment(selectedFragment: Fragment) {
childFragmentManager.beginTransaction() supportFragmentManager.beginTransaction()
.replace(R.id.fragment_container, selectedFragment) // f2_container is your FrameLayout container .replace(R.id.fragment_container, selectedFragment)
.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN) .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE)
.addToBackStack(null)
.commit() .commit()
} }
@ -125,8 +77,4 @@ class TreatmentsFragment : DaggerFragment() {
selected.setBackgroundColor(resourceHelper.gc(R.color.tabBgColorSelected)) 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()
}
}

View file

@ -1,4 +1,4 @@
package info.nightscout.androidaps.plugins.treatments.fragments package info.nightscout.androidaps.activities.fragments
import android.graphics.Paint import android.graphics.Paint
import android.os.Bundle import android.os.Bundle

View file

@ -1,4 +1,4 @@
package info.nightscout.androidaps.plugins.treatments.fragments package info.nightscout.androidaps.activities.fragments
import android.graphics.Paint import android.graphics.Paint
import android.os.Bundle 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.bus.RxBusWrapper
import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientRestart import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientRestart
import info.nightscout.androidaps.plugins.treatments.events.EventTreatmentUpdateGui 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.DateUtil
import info.nightscout.androidaps.utils.FabricPrivacy import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.T import info.nightscout.androidaps.utils.T

View file

@ -1,4 +1,4 @@
package info.nightscout.androidaps.plugins.treatments.fragments package info.nightscout.androidaps.activities.fragments
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.content.DialogInterface 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.LTag
import info.nightscout.androidaps.logging.UserEntryLogger import info.nightscout.androidaps.logging.UserEntryLogger
import info.nightscout.androidaps.plugins.bus.RxBusWrapper 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.DateUtil
import info.nightscout.androidaps.utils.FabricPrivacy import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.T import info.nightscout.androidaps.utils.T

View file

@ -1,4 +1,4 @@
package info.nightscout.androidaps.plugins.treatments.fragments package info.nightscout.androidaps.activities.fragments
import android.graphics.Paint import android.graphics.Paint
import android.os.Bundle 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.LocalProfilePlugin
import info.nightscout.androidaps.plugins.profile.local.events.EventLocalProfileChanged import info.nightscout.androidaps.plugins.profile.local.events.EventLocalProfileChanged
import info.nightscout.androidaps.plugins.treatments.events.EventTreatmentUpdateGui 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.DateUtil
import info.nightscout.androidaps.utils.FabricPrivacy import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.T import info.nightscout.androidaps.utils.T

View file

@ -1,4 +1,4 @@
package info.nightscout.androidaps.plugins.treatments.fragments package info.nightscout.androidaps.activities.fragments
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.content.DialogInterface 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.bus.RxBusWrapper
import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientRestart import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientRestart
import info.nightscout.androidaps.plugins.treatments.events.EventTreatmentUpdateGui 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.DateUtil
import info.nightscout.androidaps.utils.FabricPrivacy import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.T import info.nightscout.androidaps.utils.T

View file

@ -1,4 +1,4 @@
package info.nightscout.androidaps.plugins.treatments.fragments package info.nightscout.androidaps.activities.fragments
import android.content.DialogInterface import android.content.DialogInterface
import android.graphics.Paint 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.LTag
import info.nightscout.androidaps.logging.UserEntryLogger import info.nightscout.androidaps.logging.UserEntryLogger
import info.nightscout.androidaps.plugins.bus.RxBusWrapper 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.DateUtil
import info.nightscout.androidaps.utils.FabricPrivacy import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.T import info.nightscout.androidaps.utils.T

View file

@ -1,4 +1,4 @@
package info.nightscout.androidaps.plugins.treatments.fragments package info.nightscout.androidaps.activities.fragments
import android.os.Bundle import android.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater

View file

@ -4,7 +4,7 @@ import dagger.Module
import dagger.android.ContributesAndroidInjector import dagger.android.ContributesAndroidInjector
import info.nightscout.androidaps.MainActivity import info.nightscout.androidaps.MainActivity
import info.nightscout.androidaps.activities.* 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.maintenance.activities.LogSettingActivity
import info.nightscout.androidaps.plugins.general.openhumans.OpenHumansLoginActivity import info.nightscout.androidaps.plugins.general.openhumans.OpenHumansLoginActivity
import info.nightscout.androidaps.plugins.general.overview.activities.QuickWizardListActivity import info.nightscout.androidaps.plugins.general.overview.activities.QuickWizardListActivity
@ -15,6 +15,7 @@ import info.nightscout.androidaps.setupwizard.SetupWizardActivity
@Suppress("unused") @Suppress("unused")
abstract class ActivitiesModule { abstract class ActivitiesModule {
@ContributesAndroidInjector abstract fun contributesTreatmentsActivity(): TreatmentsActivity
@ContributesAndroidInjector abstract fun contributesHistoryBrowseActivity(): HistoryBrowseActivity @ContributesAndroidInjector abstract fun contributesHistoryBrowseActivity(): HistoryBrowseActivity
@ContributesAndroidInjector abstract fun contributesLogSettingActivity(): LogSettingActivity @ContributesAndroidInjector abstract fun contributesLogSettingActivity(): LogSettingActivity
@ContributesAndroidInjector abstract fun contributeMainActivity(): MainActivity @ContributesAndroidInjector abstract fun contributeMainActivity(): MainActivity

View file

@ -31,8 +31,7 @@ import info.nightscout.androidaps.plugins.insulin.InsulinFragment
import info.nightscout.androidaps.plugins.profile.local.LocalProfileFragment import info.nightscout.androidaps.plugins.profile.local.LocalProfileFragment
import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpFragment import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpFragment
import info.nightscout.androidaps.plugins.source.BGSourceFragment import info.nightscout.androidaps.plugins.source.BGSourceFragment
import info.nightscout.androidaps.plugins.treatments.TreatmentsFragment import info.nightscout.androidaps.activities.fragments.*
import info.nightscout.androidaps.plugins.treatments.fragments.*
import info.nightscout.androidaps.utils.protection.PasswordCheck import info.nightscout.androidaps.utils.protection.PasswordCheck
@Module @Module
@ -61,7 +60,6 @@ abstract class FragmentsModule {
@ContributesAndroidInjector abstract fun contributesWearFragment(): WearFragment @ContributesAndroidInjector abstract fun contributesWearFragment(): WearFragment
@ContributesAndroidInjector abstract fun contributesTidepoolFragment(): TidepoolFragment @ContributesAndroidInjector abstract fun contributesTidepoolFragment(): TidepoolFragment
@ContributesAndroidInjector abstract fun contributesTreatmentsFragment(): TreatmentsFragment
@ContributesAndroidInjector abstract fun contributesTreatmentsBolusFragment(): TreatmentsBolusCarbsFragment @ContributesAndroidInjector abstract fun contributesTreatmentsBolusFragment(): TreatmentsBolusCarbsFragment
@ContributesAndroidInjector abstract fun contributesTreatmentsTemporaryBasalsFragment(): TreatmentsTemporaryBasalsFragment @ContributesAndroidInjector abstract fun contributesTreatmentsTemporaryBasalsFragment(): TreatmentsTemporaryBasalsFragment
@ContributesAndroidInjector abstract fun contributesTreatmentsTempTargetFragment(): TreatmentsTempTargetFragment @ContributesAndroidInjector abstract fun contributesTreatmentsTempTargetFragment(): TreatmentsTempTargetFragment

View file

@ -27,7 +27,6 @@ import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.logging.LTag
import info.nightscout.androidaps.logging.UserEntryLogger import info.nightscout.androidaps.logging.UserEntryLogger
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker 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.Callback
import info.nightscout.androidaps.queue.CommandQueue import info.nightscout.androidaps.queue.CommandQueue
import info.nightscout.androidaps.utils.* import info.nightscout.androidaps.utils.*
@ -47,7 +46,6 @@ class CarbsDialog : DialogFragmentWithDate() {
@Inject lateinit var resourceHelper: ResourceHelper @Inject lateinit var resourceHelper: ResourceHelper
@Inject lateinit var constraintChecker: ConstraintChecker @Inject lateinit var constraintChecker: ConstraintChecker
@Inject lateinit var defaultValueHelper: DefaultValueHelper @Inject lateinit var defaultValueHelper: DefaultValueHelper
@Inject lateinit var treatmentsPlugin: TreatmentsPlugin
@Inject lateinit var profileFunction: ProfileFunction @Inject lateinit var profileFunction: ProfileFunction
@Inject lateinit var iobCobCalculator: IobCobCalculator @Inject lateinit var iobCobCalculator: IobCobCalculator
@Inject lateinit var uel: UserEntryLogger @Inject lateinit var uel: UserEntryLogger

View file

@ -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<GraphView>()
private val secondaryGraphsLabel = ArrayList<TextView>()
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<GraphData> = 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()
}
}
}
}
}

View file

@ -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
}
}

View file

@ -104,7 +104,8 @@ class ProfileFunctionImplementation @Inject constructor(
timeshift = T.hours(timeShiftInHours.toLong()).msecs(), timeshift = T.hours(timeShiftInHours.toLong()).msecs(),
percentage = percentage, percentage = percentage,
duration = T.mins(durationInMinutes.toLong()).msecs(), 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)) disposable += repository.runTransactionForResult(InsertOrUpdateProfileSwitch(ps))
.subscribe({ result -> .subscribe({ result ->
result.inserted.forEach { aapsLogger.debug(LTag.DATABASE, "Inserted ProfileSwitch $it") } result.inserted.forEach { aapsLogger.debug(LTag.DATABASE, "Inserted ProfileSwitch $it") }

View file

@ -28,7 +28,7 @@ import info.nightscout.androidaps.events.EventTherapyEventChange
import info.nightscout.androidaps.extensions.toStringMedium import info.nightscout.androidaps.extensions.toStringMedium
import info.nightscout.androidaps.extensions.toStringShort import info.nightscout.androidaps.extensions.toStringShort
import info.nightscout.androidaps.extensions.toVisibility 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.ActivePlugin
import info.nightscout.androidaps.interfaces.CommandQueueProvider import info.nightscout.androidaps.interfaces.CommandQueueProvider
import info.nightscout.androidaps.interfaces.Config import info.nightscout.androidaps.interfaces.Config

View file

@ -561,9 +561,9 @@ class DataSyncSelectorImplementation @Inject constructor(
val lastSync = sp.getLong(R.string.key_ns_profile_store_last_synced_timestamp, 0) 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) val lastChange = sp.getLong(R.string.key_local_profile_last_change, 0)
if (lastChange == 0L) return if (lastChange == 0L) return
localProfilePlugin.createProfileStore() if (lastChange > lastSync) {
val profileJson = localProfilePlugin.profile?.data ?: return val profileJson = localProfilePlugin.profile?.data ?: return
if (lastChange > lastSync)
nsClientPlugin.nsClientService?.dbAdd("profile", profileJson, DataSyncSelector.PairProfileStore(profileJson, dateUtil.now()), "") nsClientPlugin.nsClientService?.dbAdd("profile", profileJson, DataSyncSelector.PairProfileStore(profileJson, dateUtil.now()), "")
}
} }
} }

View file

@ -34,7 +34,7 @@ class NSClientMbgWorker(
var ret = Result.success() var ret = Result.success()
val acceptNSData = sp.getBoolean(R.string.key_ns_receive_therapy_events, false) || config.NSCLIENT 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)) val mbgArray = dataWorker.pickupJSONArray(inputData.getLong(DataWorker.STORE_KEY, -1))
?: return Result.failure(workDataOf("Error" to "missing input data")) ?: return Result.failure(workDataOf("Error" to "missing input data"))

View file

@ -1,46 +1,64 @@
package info.nightscout.androidaps.plugins.general.overview 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.BarGraphSeries
import com.jjoe64.graphview.series.DataPoint import com.jjoe64.graphview.series.DataPoint
import com.jjoe64.graphview.series.LineGraphSeries import com.jjoe64.graphview.series.LineGraphSeries
import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.data.IobTotal 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.ExtendedBolus
import info.nightscout.androidaps.database.entities.GlucoseValue import info.nightscout.androidaps.database.entities.GlucoseValue
import info.nightscout.androidaps.database.entities.TemporaryBasal import info.nightscout.androidaps.database.entities.TemporaryBasal
import info.nightscout.androidaps.database.entities.TemporaryTarget import info.nightscout.androidaps.database.entities.TemporaryTarget
import info.nightscout.androidaps.extensions.convertedToPercent import info.nightscout.androidaps.extensions.convertedToPercent
import info.nightscout.androidaps.extensions.target
import info.nightscout.androidaps.extensions.toStringFull import info.nightscout.androidaps.extensions.toStringFull
import info.nightscout.androidaps.extensions.toStringShort import info.nightscout.androidaps.extensions.toStringShort
import info.nightscout.androidaps.extensions.valueToUnits import info.nightscout.androidaps.extensions.valueToUnits
import info.nightscout.androidaps.interfaces.ActivePlugin import info.nightscout.androidaps.interfaces.*
import info.nightscout.androidaps.interfaces.Profile import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.interfaces.ProfileFunction import info.nightscout.androidaps.logging.LTag
import info.nightscout.androidaps.plugins.general.overview.graphExtensions.DataPointWithLabelInterface import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin
import info.nightscout.androidaps.plugins.general.overview.graphExtensions.FixedLineGraphSeries import info.nightscout.androidaps.plugins.aps.openAPSSMB.SMBDefaults
import info.nightscout.androidaps.plugins.general.overview.graphExtensions.PointsWithLabelGraphSeries import info.nightscout.androidaps.plugins.general.nsclient.data.NSDeviceStatus
import info.nightscout.androidaps.plugins.general.overview.graphExtensions.Scale import info.nightscout.androidaps.plugins.general.overview.graphExtensions.*
import info.nightscout.androidaps.plugins.general.overview.graphExtensions.ScaledDataPoint import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensResult
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.CobInfo import info.nightscout.androidaps.plugins.iob.iobCobCalculator.CobInfo
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.data.AutosensData import info.nightscout.androidaps.plugins.iob.iobCobCalculator.data.AutosensData
import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.*
import info.nightscout.androidaps.utils.DefaultValueHelper
import info.nightscout.androidaps.utils.T
import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.sharedPreferences.SP import info.nightscout.androidaps.utils.sharedPreferences.SP
import java.util.* import java.util.*
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
import kotlin.collections.ArrayList import kotlin.collections.ArrayList
import kotlin.math.abs
import kotlin.math.ceil
import kotlin.math.max
import kotlin.math.min
@Singleton @Singleton
class OverviewData @Inject constructor( class OverviewData @Inject constructor(
private val injector: HasAndroidInjector,
private val aapsLogger: AAPSLogger,
private val resourceHelper: ResourceHelper, private val resourceHelper: ResourceHelper,
private val dateUtil: DateUtil, private val dateUtil: DateUtil,
private val sp: SP, private val sp: SP,
private val activePlugin: ActivePlugin, private val activePlugin: ActivePlugin,
private val defaultValueHelper: DefaultValueHelper, 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 { enum class Property {
@ -84,7 +102,7 @@ class OverviewData @Inject constructor(
var profileName: String? = null var profileName: String? = null
var profileNameWithRemainingTime: String? = null var profileNameWithRemainingTime: String? = null
val profileBackgroudColor: Int val profileBackgroundColor: Int
get() = get() =
profile?.let { profile -> profile?.let { profile ->
if (profile.percentage != 100 || profile.timeshift != 0) resourceHelper.gc(R.color.ribbonWarning) if (profile.percentage != 100 || profile.timeshift != 0) resourceHelper.gc(R.color.ribbonWarning)
@ -211,7 +229,7 @@ class OverviewData @Inject constructor(
* TEMP TARGET * TEMP TARGET
*/ */
var temporarytarget: TemporaryTarget? = null var temporaryTarget: TemporaryTarget? = null
/* /*
* SENSITIVITY * SENSITIVITY
@ -278,4 +296,515 @@ class OverviewData @Inject constructor(
var dsMaxSeries: LineGraphSeries<ScaledDataPoint> = LineGraphSeries() var dsMaxSeries: LineGraphSeries<ScaledDataPoint> = LineGraphSeries()
var dsMinSeries: LineGraphSeries<ScaledDataPoint> = LineGraphSeries() var dsMinSeries: LineGraphSeries<ScaledDataPoint> = 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<DataPointWithLabelInterface> = 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<DataPointWithLabelInterface> = java.util.ArrayList()
val predictions: MutableList<GlucoseValueDataPoint>? = 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<DataPointWithLabelInterface> = 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<ScaledDataPoint> = java.util.ArrayList()
val tempBasalArray: MutableList<ScaledDataPoint> = java.util.ArrayList()
val basalLineArray: MutableList<ScaledDataPoint> = java.util.ArrayList()
val absoluteBasalLineArray: MutableList<ScaledDataPoint> = 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<DataPoint> = 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<DataPointWithLabelInterface> = 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<ScaledDataPoint> = java.util.ArrayList()
val absIobArray: MutableList<ScaledDataPoint> = java.util.ArrayList()
maxIobValueFound = Double.MIN_VALUE
var lastIob = 0.0
var absLastIob = 0.0
var time = fromTime
val minFailOverActiveList: MutableList<DataPointWithLabelInterface> = java.util.ArrayList()
val cobArray: MutableList<ScaledDataPoint> = java.util.ArrayList()
maxCobValueFound = Double.MIN_VALUE
var lastCob = 0
val actArrayHist: MutableList<ScaledDataPoint> = java.util.ArrayList()
val actArrayPrediction: MutableList<ScaledDataPoint> = java.util.ArrayList()
val now = dateUtil.now().toDouble()
maxIAValue = 0.0
val bgiArrayHist: MutableList<ScaledDataPoint> = java.util.ArrayList()
val bgiArrayPrediction: MutableList<ScaledDataPoint> = java.util.ArrayList()
maxBGIValue = Double.MIN_VALUE
val devArray: MutableList<OverviewPlugin.DeviationDataPoint> = java.util.ArrayList()
maxDevValueFound = Double.MIN_VALUE
val ratioArray: MutableList<ScaledDataPoint> = 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<ScaledDataPoint> = java.util.ArrayList()
val dsMinArray: MutableList<ScaledDataPoint> = 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<DataPointWithLabelInterface> = 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<DataPointWithLabelInterface> = 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 <E : DataPointWithLabelInterface> List<E>.filterTimeframe(fromTime: Long, endTime: Long): List<E> =
filter { it.x + it.duration >= fromTime && it.x <= endTime }
} }

View file

@ -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.pump.common.defs.PumpType
import info.nightscout.androidaps.plugins.source.DexcomPlugin import info.nightscout.androidaps.plugins.source.DexcomPlugin
import info.nightscout.androidaps.plugins.source.XdripPlugin import info.nightscout.androidaps.plugins.source.XdripPlugin
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin
import info.nightscout.androidaps.queue.CommandQueue import info.nightscout.androidaps.queue.CommandQueue
import info.nightscout.androidaps.skins.SkinProvider import info.nightscout.androidaps.skins.SkinProvider
import info.nightscout.androidaps.utils.* import info.nightscout.androidaps.utils.*
@ -92,7 +91,6 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
@Inject lateinit var nsDeviceStatus: NSDeviceStatus @Inject lateinit var nsDeviceStatus: NSDeviceStatus
@Inject lateinit var loopPlugin: LoopPlugin @Inject lateinit var loopPlugin: LoopPlugin
@Inject lateinit var activePlugin: ActivePlugin @Inject lateinit var activePlugin: ActivePlugin
@Inject lateinit var treatmentsPlugin: TreatmentsPlugin
@Inject lateinit var iobCobCalculator: IobCobCalculator @Inject lateinit var iobCobCalculator: IobCobCalculator
@Inject lateinit var dexcomPlugin: DexcomPlugin @Inject lateinit var dexcomPlugin: DexcomPlugin
@Inject lateinit var dexcomMediator: DexcomPlugin.DexcomMediator @Inject lateinit var dexcomMediator: DexcomPlugin.DexcomMediator
@ -108,7 +106,6 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
@Inject lateinit var trendCalculator: TrendCalculator @Inject lateinit var trendCalculator: TrendCalculator
@Inject lateinit var config: Config @Inject lateinit var config: Config
@Inject lateinit var dateUtil: DateUtil @Inject lateinit var dateUtil: DateUtil
@Inject lateinit var databaseHelper: DatabaseHelperInterface
@Inject lateinit var uel: UserEntryLogger @Inject lateinit var uel: UserEntryLogger
@Inject lateinit var repository: AppRepository @Inject lateinit var repository: AppRepository
@Inject lateinit var glucoseStatusProvider: GlucoseStatusProvider @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.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) binding.infoLayout.longAvgDelta.text = Profile.toSignedUnitsString(glucoseStatus.longAvgDelta, glucoseStatus.longAvgDelta * Constants.MGDL_TO_MMOLL, units)
} else { } 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.delta.text = "Δ " + resourceHelper.gs(R.string.notavailable)
binding.infoLayout.avgDelta.text = "" binding.infoLayout.avgDelta.text = ""
binding.infoLayout.longAvgDelta.text = "" binding.infoLayout.longAvgDelta.text = ""
@ -640,7 +637,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
OverviewData.Property.PROFILE -> { OverviewData.Property.PROFILE -> {
binding.loopPumpStatusLayout.activeProfile.text = overviewData.profileNameWithRemainingTime binding.loopPumpStatusLayout.activeProfile.text = overviewData.profileNameWithRemainingTime
?: "" ?: ""
binding.loopPumpStatusLayout.activeProfile.setBackgroundColor(overviewData.profileBackgroudColor) binding.loopPumpStatusLayout.activeProfile.setBackgroundColor(overviewData.profileBackgroundColor)
binding.loopPumpStatusLayout.activeProfile.setTextColor(overviewData.profileTextColor) binding.loopPumpStatusLayout.activeProfile.setTextColor(overviewData.profileTextColor)
} }
@ -705,7 +702,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
OverviewData.Property.TEMPORARY_TARGET -> { OverviewData.Property.TEMPORARY_TARGET -> {
// temp target // temp target
val tempTarget = overviewData.temporarytarget val tempTarget = overviewData.temporaryTarget
if (tempTarget != null) { if (tempTarget != null) {
binding.loopPumpStatusLayout.tempTarget.setTextColor(resourceHelper.gc(R.color.ribbonTextWarning)) binding.loopPumpStatusLayout.tempTarget.setTextColor(resourceHelper.gc(R.color.ribbonTextWarning))
binding.loopPumpStatusLayout.tempTarget.setBackgroundColor(resourceHelper.gc(R.color.ribbonWarning)) binding.loopPumpStatusLayout.tempTarget.setBackgroundColor(resourceHelper.gc(R.color.ribbonWarning))
@ -730,7 +727,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
} }
OverviewData.Property.GRAPH -> { OverviewData.Property.GRAPH -> {
val graphData = GraphData(injector, binding.graphsLayout.bgGraph) val graphData = GraphData(injector, binding.graphsLayout.bgGraph, overviewData)
val menuChartSettings = overviewMenus.setting val menuChartSettings = overviewMenus.setting
graphData.addInRangeArea(overviewData.fromTime, overviewData.endTime, defaultValueHelper.determineLowLine(), defaultValueHelper.determineHighLine()) graphData.addInRangeArea(overviewData.fromTime, overviewData.endTime, defaultValueHelper.determineLowLine(), defaultValueHelper.determineHighLine())
graphData.addBgReadings(menuChartSettings[0][OverviewMenus.CharType.PRE.ordinal]) graphData.addBgReadings(menuChartSettings[0][OverviewMenus.CharType.PRE.ordinal])
@ -755,7 +752,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
val now = System.currentTimeMillis() val now = System.currentTimeMillis()
for (g in 0 until min(secondaryGraphs.size, menuChartSettings.size + 1)) { 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 useABSForScale = false
var useIobForScale = false var useIobForScale = false
var useCobForScale = false var useCobForScale = false

View file

@ -1,85 +1,68 @@
package info.nightscout.androidaps.plugins.general.overview package info.nightscout.androidaps.plugins.general.overview
import android.graphics.DashPathEffect
import android.graphics.Paint
import androidx.preference.PreferenceFragmentCompat import androidx.preference.PreferenceFragmentCompat
import androidx.preference.SwitchPreference 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 dagger.android.HasAndroidInjector
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.data.IobTotal
import info.nightscout.androidaps.database.AppRepository import info.nightscout.androidaps.database.AppRepository
import info.nightscout.androidaps.database.ValueWrapper import info.nightscout.androidaps.database.ValueWrapper
import info.nightscout.androidaps.database.entities.Bolus
import info.nightscout.androidaps.events.* import info.nightscout.androidaps.events.*
import info.nightscout.androidaps.extensions.* import info.nightscout.androidaps.extensions.*
import info.nightscout.androidaps.interfaces.* import info.nightscout.androidaps.interfaces.*
import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.logging.LTag
import info.nightscout.androidaps.plugins.aps.events.EventLoopInvoked 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.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.EventDismissNotification
import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification 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.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.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.EventBucketedDataCreated
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventIobCalculationProgress 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.resources.ResourceHelper
import info.nightscout.androidaps.utils.rx.AapsSchedulers import info.nightscout.androidaps.utils.rx.AapsSchedulers
import info.nightscout.androidaps.utils.sharedPreferences.SP import info.nightscout.androidaps.utils.sharedPreferences.SP
import io.reactivex.disposables.CompositeDisposable import io.reactivex.disposables.CompositeDisposable
import io.reactivex.rxkotlin.plusAssign import io.reactivex.rxkotlin.plusAssign
import org.json.JSONObject import org.json.JSONObject
import java.util.*
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
import kotlin.math.abs
import kotlin.math.ceil
import kotlin.math.max
import kotlin.math.min
@Singleton @Singleton
class OverviewPlugin @Inject constructor( class OverviewPlugin @Inject constructor(
injector: HasAndroidInjector, injector: HasAndroidInjector,
private val notificationStore: NotificationStore, private val notificationStore: NotificationStore,
private val fabricPrivacy: FabricPrivacy, private val fabricPrivacy: FabricPrivacy,
private val rxBus: RxBusWrapper, private val rxBus: RxBusWrapper,
private val sp: SP, private val sp: SP,
aapsLogger: AAPSLogger, aapsLogger: AAPSLogger,
private val aapsSchedulers: AapsSchedulers, private val aapsSchedulers: AapsSchedulers,
resourceHelper: ResourceHelper, resourceHelper: ResourceHelper,
private val config: Config, private val config: Config,
private val dateUtil: DateUtil, private val dateUtil: DateUtil,
private val translator: Translator, private val translator: Translator,
// private val profiler: Profiler, // private val profiler: Profiler,
private val profileFunction: ProfileFunction, private val profileFunction: ProfileFunction,
private val iobCobCalculator: IobCobCalculator, private val iobCobCalculator: IobCobCalculator,
private val repository: AppRepository, private val repository: AppRepository,
private val defaultValueHelper: DefaultValueHelper, private val overviewData: OverviewData,
private val loopPlugin: LoopPlugin, private val overviewMenus: OverviewMenus
private val activePlugin: ActivePlugin,
private val nsDeviceStatus: NSDeviceStatus,
private val overviewData: OverviewData,
private val overviewMenus: OverviewMenus
) : PluginBase(PluginDescription() ) : PluginBase(PluginDescription()
.mainType(PluginType.GENERAL) .mainType(PluginType.GENERAL)
.fragmentClass(OverviewFragment::class.qualifiedName) .fragmentClass(OverviewFragment::class.qualifiedName)
.alwaysVisible(true) .alwaysVisible(true)
.alwaysEnabled(true) .alwaysEnabled(true)
.pluginIcon(R.drawable.ic_home) .pluginIcon(R.drawable.ic_home)
.pluginName(R.string.overview) .pluginName(R.string.overview)
.shortName(R.string.overview_shortname) .shortName(R.string.overview_shortname)
.preferencesId(R.xml.pref_overview) .preferencesId(R.xml.pref_overview)
.description(R.string.description_overview), .description(R.string.description_overview),
aapsLogger, resourceHelper, injector aapsLogger, resourceHelper, injector
), Overview { ), Overview {
private var disposable: CompositeDisposable = CompositeDisposable() private var disposable: CompositeDisposable = CompositeDisposable()
@ -95,74 +78,76 @@ class OverviewPlugin @Inject constructor(
notificationStore.createNotificationChannel() notificationStore.createNotificationChannel()
disposable += rxBus disposable += rxBus
.toObservable(EventNewNotification::class.java) .toObservable(EventNewNotification::class.java)
.observeOn(aapsSchedulers.io) .observeOn(aapsSchedulers.io)
.subscribe({ n -> .subscribe({ n ->
if (notificationStore.add(n.notification)) if (notificationStore.add(n.notification))
rxBus.send(EventRefreshOverview("EventNewNotification")) rxBus.send(EventRefreshOverview("EventNewNotification"))
}, fabricPrivacy::logException) }, fabricPrivacy::logException)
disposable += rxBus disposable += rxBus
.toObservable(EventDismissNotification::class.java) .toObservable(EventDismissNotification::class.java)
.observeOn(aapsSchedulers.io) .observeOn(aapsSchedulers.io)
.subscribe({ n -> .subscribe({ n ->
if (notificationStore.remove(n.id)) if (notificationStore.remove(n.id))
rxBus.send(EventRefreshOverview("EventDismissNotification")) rxBus.send(EventRefreshOverview("EventDismissNotification"))
}, fabricPrivacy::logException) }, fabricPrivacy::logException)
disposable += rxBus disposable += rxBus
.toObservable(EventIobCalculationProgress::class.java) .toObservable(EventIobCalculationProgress::class.java)
.observeOn(aapsSchedulers.main) .observeOn(aapsSchedulers.main)
.subscribe({ overviewData.calcProgress = it.progress; overviewBus.send(EventUpdateOverview("EventIobCalculationProgress", OverviewData.Property.CALC_PROGRESS)) }, fabricPrivacy::logException) .subscribe({ overviewData.calcProgress = it.progress; overviewBus.send(EventUpdateOverview("EventIobCalculationProgress", OverviewData.Property.CALC_PROGRESS)) }, fabricPrivacy::logException)
disposable += rxBus disposable += rxBus
.toObservable(EventTempBasalChange::class.java) .toObservable(EventTempBasalChange::class.java)
.observeOn(aapsSchedulers.io) .observeOn(aapsSchedulers.io)
.subscribe({ loadTemporaryBasal("EventTempBasalChange") }, fabricPrivacy::logException) .subscribe({ loadTemporaryBasal("EventTempBasalChange") }, fabricPrivacy::logException)
disposable += rxBus disposable += rxBus
.toObservable(EventExtendedBolusChange::class.java) .toObservable(EventExtendedBolusChange::class.java)
.observeOn(aapsSchedulers.io) .observeOn(aapsSchedulers.io)
.subscribe({ loadExtendedBolus("EventExtendedBolusChange") }, fabricPrivacy::logException) .subscribe({ loadExtendedBolus("EventExtendedBolusChange") }, fabricPrivacy::logException)
disposable += rxBus disposable += rxBus
.toObservable(EventNewBG::class.java) .toObservable(EventNewBG::class.java)
.observeOn(aapsSchedulers.io) .observeOn(aapsSchedulers.io)
.subscribe({ loadBg("EventNewBG") }, fabricPrivacy::logException) .subscribe({ loadBg("EventNewBG") }, fabricPrivacy::logException)
disposable += rxBus disposable += rxBus
.toObservable(EventTempTargetChange::class.java) .toObservable(EventTempTargetChange::class.java)
.observeOn(aapsSchedulers.io) .observeOn(aapsSchedulers.io)
.subscribe({ loadTemporaryTarget("EventTempTargetChange") }, fabricPrivacy::logException) .subscribe({ loadTemporaryTarget("EventTempTargetChange") }, fabricPrivacy::logException)
disposable += rxBus disposable += rxBus
.toObservable(EventTreatmentChange::class.java) .toObservable(EventTreatmentChange::class.java)
.observeOn(aapsSchedulers.io) .observeOn(aapsSchedulers.io)
.subscribe({ .subscribe({
loadIobCobResults("EventTreatmentChange") loadIobCobResults("EventTreatmentChange")
prepareTreatmentsData("EventTreatmentChange") overviewData.prepareTreatmentsData("EventTreatmentChange")
overviewBus.send(EventUpdateOverview("EventTreatmentChange", OverviewData.Property.GRAPH)) overviewBus.send(EventUpdateOverview("EventTreatmentChange", OverviewData.Property.GRAPH))
}, fabricPrivacy::logException) }, fabricPrivacy::logException)
disposable += rxBus disposable += rxBus
.toObservable(EventTherapyEventChange::class.java) .toObservable(EventTherapyEventChange::class.java)
.observeOn(aapsSchedulers.io) .observeOn(aapsSchedulers.io)
.subscribe({ .subscribe({
prepareTreatmentsData("EventTherapyEventChange") overviewData.prepareTreatmentsData("EventTherapyEventChange")
overviewBus.send(EventUpdateOverview("EventTherapyEventChange", OverviewData.Property.GRAPH)) overviewBus.send(EventUpdateOverview("EventTherapyEventChange", OverviewData.Property.GRAPH))
}, fabricPrivacy::logException) }, fabricPrivacy::logException)
disposable += rxBus disposable += rxBus
.toObservable(EventBucketedDataCreated::class.java) .toObservable(EventBucketedDataCreated::class.java)
.observeOn(aapsSchedulers.io) .observeOn(aapsSchedulers.io)
.subscribe({ .subscribe({
prepareBucketedData("EventBucketedDataCreated") overviewData.prepareBucketedData("EventBucketedDataCreated")
prepareBgData("EventBucketedDataCreated") overviewData.prepareBgData("EventBucketedDataCreated")
overviewBus.send(EventUpdateOverview("EventBucketedDataCreated", OverviewData.Property.GRAPH)) overviewBus.send(EventUpdateOverview("EventBucketedDataCreated", OverviewData.Property.GRAPH))
}, fabricPrivacy::logException) }, fabricPrivacy::logException)
disposable += rxBus disposable += rxBus
.toObservable(EventLoopInvoked::class.java) .toObservable(EventLoopInvoked::class.java)
.observeOn(aapsSchedulers.io) .observeOn(aapsSchedulers.io)
.subscribe({ preparePredictions("EventLoopInvoked") }, fabricPrivacy::logException) .subscribe({ overviewData.preparePredictions("EventLoopInvoked") }, fabricPrivacy::logException)
disposable.add(rxBus disposable.add(rxBus
.toObservable(EventProfileSwitchChanged::class.java) .toObservable(EventProfileSwitchChanged::class.java)
.observeOn(aapsSchedulers.io) .observeOn(aapsSchedulers.io)
.subscribe({ loadProfile("EventProfileSwitchChanged") }, fabricPrivacy::logException)) .subscribe({ loadProfile("EventProfileSwitchChanged") }, fabricPrivacy::logException))
disposable.add(rxBus disposable.add(rxBus
.toObservable(EventAutosensCalculationFinished::class.java) .toObservable(EventAutosensCalculationFinished::class.java)
.observeOn(aapsSchedulers.io) .observeOn(aapsSchedulers.io)
.subscribe({ refreshLoop("EventAutosensCalculationFinished") }, fabricPrivacy::logException)) .subscribe({
if (it.cause !is EventCustomCalculationFinished) refreshLoop("EventAutosensCalculationFinished")
}, fabricPrivacy::logException))
Thread { loadAll("onResume") }.start() Thread { loadAll("onResume") }.start()
} }
@ -187,59 +172,60 @@ class OverviewPlugin @Inject constructor(
} }
override fun configuration(): JSONObject = override fun configuration(): JSONObject =
JSONObject() JSONObject()
.putString(R.string.key_quickwizard, sp, resourceHelper) .putString(R.string.key_quickwizard, sp, resourceHelper)
.putInt(R.string.key_eatingsoon_duration, sp, resourceHelper) .putInt(R.string.key_eatingsoon_duration, sp, resourceHelper)
.putDouble(R.string.key_eatingsoon_target, sp, resourceHelper) .putDouble(R.string.key_eatingsoon_target, sp, resourceHelper)
.putInt(R.string.key_activity_duration, sp, resourceHelper) .putInt(R.string.key_activity_duration, sp, resourceHelper)
.putDouble(R.string.key_activity_target, sp, resourceHelper) .putDouble(R.string.key_activity_target, sp, resourceHelper)
.putInt(R.string.key_hypo_duration, sp, resourceHelper) .putInt(R.string.key_hypo_duration, sp, resourceHelper)
.putDouble(R.string.key_hypo_target, sp, resourceHelper) .putDouble(R.string.key_hypo_target, sp, resourceHelper)
.putDouble(R.string.key_low_mark, sp, resourceHelper) .putDouble(R.string.key_low_mark, sp, resourceHelper)
.putDouble(R.string.key_high_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_warning, sp, resourceHelper)
.putDouble(R.string.key_statuslights_cage_critical, 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_warning, sp, resourceHelper)
.putDouble(R.string.key_statuslights_iage_critical, 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_warning, sp, resourceHelper)
.putDouble(R.string.key_statuslights_sage_critical, 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_warning, sp, resourceHelper)
.putDouble(R.string.key_statuslights_sbat_critical, 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_warning, sp, resourceHelper)
.putDouble(R.string.key_statuslights_bage_critical, 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_warning, sp, resourceHelper)
.putDouble(R.string.key_statuslights_res_critical, 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_warning, sp, resourceHelper)
.putDouble(R.string.key_statuslights_bat_critical, sp, resourceHelper) .putDouble(R.string.key_statuslights_bat_critical, sp, resourceHelper)
override fun applyConfiguration(configuration: JSONObject) { override fun applyConfiguration(configuration: JSONObject) {
configuration configuration
.storeString(R.string.key_quickwizard, sp, resourceHelper) .storeString(R.string.key_quickwizard, sp, resourceHelper)
.storeInt(R.string.key_eatingsoon_duration, sp, resourceHelper) .storeInt(R.string.key_eatingsoon_duration, sp, resourceHelper)
.storeDouble(R.string.key_eatingsoon_target, sp, resourceHelper) .storeDouble(R.string.key_eatingsoon_target, sp, resourceHelper)
.storeInt(R.string.key_activity_duration, sp, resourceHelper) .storeInt(R.string.key_activity_duration, sp, resourceHelper)
.storeDouble(R.string.key_activity_target, sp, resourceHelper) .storeDouble(R.string.key_activity_target, sp, resourceHelper)
.storeInt(R.string.key_hypo_duration, sp, resourceHelper) .storeInt(R.string.key_hypo_duration, sp, resourceHelper)
.storeDouble(R.string.key_hypo_target, sp, resourceHelper) .storeDouble(R.string.key_hypo_target, sp, resourceHelper)
.storeDouble(R.string.key_low_mark, sp, resourceHelper) .storeDouble(R.string.key_low_mark, sp, resourceHelper)
.storeDouble(R.string.key_high_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_warning, sp, resourceHelper)
.storeDouble(R.string.key_statuslights_cage_critical, 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_warning, sp, resourceHelper)
.storeDouble(R.string.key_statuslights_iage_critical, 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_warning, sp, resourceHelper)
.storeDouble(R.string.key_statuslights_sage_critical, 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_warning, sp, resourceHelper)
.storeDouble(R.string.key_statuslights_sbat_critical, 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_warning, sp, resourceHelper)
.storeDouble(R.string.key_statuslights_bage_critical, 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_warning, sp, resourceHelper)
.storeDouble(R.string.key_statuslights_res_critical, 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_warning, sp, resourceHelper)
.storeDouble(R.string.key_statuslights_bat_critical, sp, resourceHelper) .storeDouble(R.string.key_statuslights_bat_critical, sp, resourceHelper)
} }
@Volatile var runningRefresh = false @Volatile
var runningRefresh = false
override fun refreshLoop(from: String) { override fun refreshLoop(from: String) {
if (runningRefresh) return if (runningRefresh) return
runningRefresh = true runningRefresh = true
@ -252,11 +238,11 @@ class OverviewPlugin @Inject constructor(
overviewBus.send(EventUpdateOverview(from, OverviewData.Property.TEMPORARY_TARGET)) overviewBus.send(EventUpdateOverview(from, OverviewData.Property.TEMPORARY_TARGET))
overviewBus.send(EventUpdateOverview(from, OverviewData.Property.SENSITIVITY)) overviewBus.send(EventUpdateOverview(from, OverviewData.Property.SENSITIVITY))
loadAsData(from) loadAsData(from)
preparePredictions(from) overviewData.preparePredictions(from)
prepareBasalData(from) overviewData.prepareBasalData(from)
prepareTemporaryTargetData(from) overviewData.prepareTemporaryTargetData(from)
prepareTreatmentsData(from) overviewData.prepareTreatmentsData(from)
prepareIobAutosensData(from) overviewData.prepareIobAutosensData(from)
overviewBus.send(EventUpdateOverview(from, OverviewData.Property.GRAPH)) overviewBus.send(EventUpdateOverview(from, OverviewData.Property.GRAPH))
aapsLogger.debug(LTag.UI, "refreshLoop finished") aapsLogger.debug(LTag.UI, "refreshLoop finished")
runningRefresh = false runningRefresh = false
@ -271,9 +257,9 @@ class OverviewPlugin @Inject constructor(
loadTemporaryTarget(from) loadTemporaryTarget(from)
loadIobCobResults(from) loadIobCobResults(from)
loadAsData(from) loadAsData(from)
prepareBasalData(from) overviewData.prepareBasalData(from)
prepareTemporaryTargetData(from) overviewData.prepareTemporaryTargetData(from)
prepareTreatmentsData(from) overviewData.prepareTreatmentsData(from)
// prepareIobAutosensData(from) // prepareIobAutosensData(from)
// preparePredictions(from) // preparePredictions(from)
overviewBus.send(EventUpdateOverview(from, OverviewData.Property.GRAPH)) overviewBus.send(EventUpdateOverview(from, OverviewData.Property.GRAPH))
@ -299,8 +285,8 @@ class OverviewPlugin @Inject constructor(
private fun loadTemporaryTarget(from: String) { private fun loadTemporaryTarget(from: String) {
val tempTarget = repository.getTemporaryTargetActiveAt(dateUtil.now()).blockingGet() val tempTarget = repository.getTemporaryTargetActiveAt(dateUtil.now()).blockingGet()
if (tempTarget is ValueWrapper.Existing) overviewData.temporarytarget = tempTarget.value if (tempTarget is ValueWrapper.Existing) overviewData.temporaryTarget = tempTarget.value
else overviewData.temporarytarget = null else overviewData.temporaryTarget = null
overviewBus.send(EventUpdateOverview(from, OverviewData.Property.TEMPORARY_TARGET)) overviewBus.send(EventUpdateOverview(from, OverviewData.Property.TEMPORARY_TARGET))
} }
@ -326,514 +312,4 @@ class OverviewPlugin @Inject constructor(
overviewBus.send(EventUpdateOverview(from, OverviewData.Property.IOB_COB)) 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<DataPointWithLabelInterface> = 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<DataPointWithLabelInterface> = ArrayList()
val predictions: MutableList<GlucoseValueDataPoint>? = 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<DataPointWithLabelInterface> = 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<ScaledDataPoint> = ArrayList()
val tempBasalArray: MutableList<ScaledDataPoint> = ArrayList()
val basalLineArray: MutableList<ScaledDataPoint> = ArrayList()
val absoluteBasalLineArray: MutableList<ScaledDataPoint> = 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<DataPoint> = 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<DataPointWithLabelInterface> = 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<ScaledDataPoint> = ArrayList()
val absIobArray: MutableList<ScaledDataPoint> = ArrayList()
overviewData.maxIobValueFound = Double.MIN_VALUE
var lastIob = 0.0
var absLastIob = 0.0
var time = overviewData.fromTime
val minFailOverActiveList: MutableList<DataPointWithLabelInterface> = ArrayList()
val cobArray: MutableList<ScaledDataPoint> = ArrayList()
overviewData.maxCobValueFound = Double.MIN_VALUE
var lastCob = 0
val actArrayHist: MutableList<ScaledDataPoint> = ArrayList()
val actArrayPrediction: MutableList<ScaledDataPoint> = ArrayList()
val now = dateUtil.now().toDouble()
overviewData.maxIAValue = 0.0
val bgiArrayHist: MutableList<ScaledDataPoint> = ArrayList()
val bgiArrayPrediction: MutableList<ScaledDataPoint> = ArrayList()
overviewData.maxBGIValue = Double.MIN_VALUE
val devArray: MutableList<DeviationDataPoint> = ArrayList()
overviewData.maxDevValueFound = Double.MIN_VALUE
val ratioArray: MutableList<ScaledDataPoint> = 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<ScaledDataPoint> = ArrayList()
val dsMinArray: MutableList<ScaledDataPoint> = 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<DataPointWithLabelInterface> = 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<DataPointWithLabelInterface> = 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 <E : DataPointWithLabelInterface> List<E>.filterTimeframe(fromTime: Long, endTime: Long): List<E> =
filter { it.x + it.duration >= fromTime && it.x <= endTime }
} }

View file

@ -27,16 +27,16 @@ import kotlin.math.max
class GraphData( class GraphData(
injector: HasAndroidInjector, injector: HasAndroidInjector,
private val graph: GraphView private val graph: GraphView,
private val overviewData: OverviewData
) { ) {
@Inject lateinit var aapsLogger: AAPSLogger @Inject lateinit var aapsLogger: AAPSLogger
@Inject lateinit var profileFunction: ProfileFunction @Inject lateinit var profileFunction: ProfileFunction
@Inject lateinit var resourceHelper: ResourceHelper @Inject lateinit var resourceHelper: ResourceHelper
@Inject lateinit var defaultValueHelper: DefaultValueHelper @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 var minY = Double.MAX_VALUE
private val units: GlucoseUnit private val units: GlucoseUnit
private val series: MutableList<Series<*>> = ArrayList() private val series: MutableList<Series<*>> = ArrayList()
@ -214,7 +214,7 @@ class GraphData(
graph.gridLabelRenderer.numHorizontalLabels = 7 // only 7 because of the space 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() { fun performUpdate() {
// clear old data // clear old data

View file

@ -99,7 +99,7 @@ class IobCobOref1Thread internal constructor(
// start from oldest to be able sub cob // start from oldest to be able sub cob
for (i in bucketedData.size - 4 downTo 0) { for (i in bucketedData.size - 4 downTo 0) {
val progress = i.toString() + if (buildHelper.isDev()) " ($from)" else "" val progress = i.toString() + if (buildHelper.isDev()) " ($from)" else ""
rxBus.send(EventIobCalculationProgress(progress)) rxBus.send(EventIobCalculationProgress(progress, cause))
if (iobCobCalculatorPlugin.stopCalculationTrigger) { if (iobCobCalculatorPlugin.stopCalculationTrigger) {
iobCobCalculatorPlugin.stopCalculationTrigger = false iobCobCalculatorPlugin.stopCalculationTrigger = false
aapsLogger.debug(LTag.AUTOSENS, "Aborting calculation thread (trigger): $from") aapsLogger.debug(LTag.AUTOSENS, "Aborting calculation thread (trigger): $from")
@ -325,7 +325,7 @@ class IobCobOref1Thread internal constructor(
}.start() }.start()
} finally { } finally {
mWakeLock?.release() mWakeLock?.release()
rxBus.send(EventIobCalculationProgress("")) rxBus.send(EventIobCalculationProgress("", cause))
aapsLogger.debug(LTag.AUTOSENS, "AUTOSENSDATA thread ended: $from") aapsLogger.debug(LTag.AUTOSENS, "AUTOSENSDATA thread ended: $from")
profiler.log(LTag.AUTOSENS, "IobCobOref1Thread", start) profiler.log(LTag.AUTOSENS, "IobCobOref1Thread", start)
} }

View file

@ -98,7 +98,7 @@ class IobCobThread @Inject internal constructor(
// start from oldest to be able sub cob // start from oldest to be able sub cob
for (i in bucketedData.size - 4 downTo 0) { for (i in bucketedData.size - 4 downTo 0) {
val progress = i.toString() + if (buildHelper.isDev()) " ($from)" else "" val progress = i.toString() + if (buildHelper.isDev()) " ($from)" else ""
rxBus.send(EventIobCalculationProgress(progress)) rxBus.send(EventIobCalculationProgress(progress, cause))
if (iobCobCalculatorPlugin.stopCalculationTrigger) { if (iobCobCalculatorPlugin.stopCalculationTrigger) {
iobCobCalculatorPlugin.stopCalculationTrigger = false iobCobCalculatorPlugin.stopCalculationTrigger = false
aapsLogger.debug(LTag.AUTOSENS, "Aborting calculation thread (trigger): $from") aapsLogger.debug(LTag.AUTOSENS, "Aborting calculation thread (trigger): $from")
@ -272,7 +272,7 @@ class IobCobThread @Inject internal constructor(
}.start() }.start()
} finally { } finally {
mWakeLock?.release() mWakeLock?.release()
rxBus.send(EventIobCalculationProgress("")) rxBus.send(EventIobCalculationProgress("", cause))
aapsLogger.debug(LTag.AUTOSENS, "AUTOSENSDATA thread ended: $from") aapsLogger.debug(LTag.AUTOSENS, "AUTOSENSDATA thread ended: $from")
profiler.log(LTag.AUTOSENS, "IobCobThread", start) profiler.log(LTag.AUTOSENS, "IobCobThread", start)
} }

View file

@ -2,4 +2,4 @@ package info.nightscout.androidaps.plugins.iob.iobCobCalculator.events
import info.nightscout.androidaps.events.Event import info.nightscout.androidaps.events.Event
class EventIobCalculationProgress(var progress: String) : Event() class EventIobCalculationProgress(val progress: String, val cause: Event?) : Event()

View file

@ -70,7 +70,7 @@ class LocalProfileFragment : DaggerFragment() {
} }
private fun sumLabel(): String { private fun sumLabel(): String {
val profile = localProfilePlugin.createProfileStore().getDefaultProfile() val profile = localProfilePlugin.profile?.getDefaultProfile()
val sum = profile?.let { ProfileSealed.Pure(profile).baseBasalSum() } ?: 0.0 val sum = profile?.let { ProfileSealed.Pure(profile).baseBasalSum() } ?: 0.0
return "" + DecimalFormatter.to2Decimal(sum) + resourceHelper.gs(R.string.insulin_unit_shortname) return "" + DecimalFormatter.to2Decimal(sum) + resourceHelper.gs(R.string.insulin_unit_shortname)
} }

View file

@ -139,6 +139,7 @@ class LocalProfilePlugin @Inject constructor(
} }
sp.putInt(Constants.LOCAL_PROFILE + "_profiles", numOfProfiles) sp.putInt(Constants.LOCAL_PROFILE + "_profiles", numOfProfiles)
sp.putLong(R.string.key_local_profile_last_change, dateUtil.now())
createAndStoreConvertedProfile() createAndStoreConvertedProfile()
isEdited = false isEdited = false
aapsLogger.debug(LTag.PROFILE, "Storing settings: " + rawProfile?.data.toString()) aapsLogger.debug(LTag.PROFILE, "Storing settings: " + rawProfile?.data.toString())
@ -148,12 +149,9 @@ class LocalProfilePlugin @Inject constructor(
val name = it.name ?: "." val name = it.name ?: "."
if (name.contains(".")) namesOK = false if (name.contains(".")) namesOK = false
} }
if (namesOK) if (!namesOK) activity?.let {
sp.putLong(R.string.key_local_profile_last_change, dateUtil.now()) OKDialog.show(it, "", resourceHelper.gs(R.string.profilenamecontainsdot))
else }
activity?.let {
OKDialog.show(it, "", resourceHelper.gs(R.string.profilenamecontainsdot))
}
} }
@Synchronized @Synchronized
@ -372,7 +370,8 @@ class LocalProfilePlugin @Inject constructor(
} }
} }
if (numOfProfiles > 0) json.put("defaultProfile", currentProfile()?.name) 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) json.put("store", store)
} catch (e: JSONException) { } catch (e: JSONException) {
aapsLogger.error("Unhandled exception", e) aapsLogger.error("Unhandled exception", e)
@ -412,11 +411,19 @@ class LocalProfilePlugin @Inject constructor(
val profileJson = dataWorker.pickupJSONObject(inputData.getLong(DataWorker.STORE_KEY, -1)) val profileJson = dataWorker.pickupJSONObject(inputData.getLong(DataWorker.STORE_KEY, -1))
?: return Result.failure(workDataOf("Error" to "missing input data")) ?: return Result.failure(workDataOf("Error" to "missing input data"))
if (sp.getBoolean(R.string.key_ns_receive_profile_store, false) || config.NSCLIENT) { if (sp.getBoolean(R.string.key_ns_receive_profile_store, false) || config.NSCLIENT) {
localProfilePlugin.loadFromStore(ProfileStore(injector, profileJson, dateUtil)) val store = ProfileStore(injector, profileJson, dateUtil)
aapsLogger.debug(LTag.PROFILE, "Received profileStore: $profileJson") val startDate = store.getStartDate()
return Result.success(workDataOf("Data" to profileJson.toString().substring(0..min(5000, profileJson.length())))) 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"))
} }
} }

View file

@ -94,7 +94,7 @@ class DexcomPlugin @Inject constructor(
override fun doWork(): Result { override fun doWork(): Result {
var ret = Result.success() 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)) val bundle = dataWorker.pickupBundle(inputData.getLong(DataWorker.STORE_KEY, -1))
?: return Result.failure(workDataOf("Error" to "missing input data")) ?: return Result.failure(workDataOf("Error" to "missing input data"))
try { try {

View file

@ -69,7 +69,7 @@ class EversensePlugin @Inject constructor(
override fun doWork(): Result { override fun doWork(): Result {
var ret = Result.success() 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)) val bundle = dataWorker.pickupBundle(inputData.getLong(DataWorker.STORE_KEY, -1))
?: return Result.failure(workDataOf("Error" to "missing input data")) ?: return Result.failure(workDataOf("Error" to "missing input data"))
if (bundle.containsKey("currentCalibrationPhase")) aapsLogger.debug(LTag.BGSOURCE, "currentCalibrationPhase: " + bundle.getString("currentCalibrationPhase")) if (bundle.containsKey("currentCalibrationPhase")) aapsLogger.debug(LTag.BGSOURCE, "currentCalibrationPhase: " + bundle.getString("currentCalibrationPhase"))

View file

@ -56,7 +56,7 @@ class GlimpPlugin @Inject constructor(
override fun doWork(): Result { override fun doWork(): Result {
var ret = Result.success() 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}") aapsLogger.debug(LTag.BGSOURCE, "Received Glimp Data: $inputData}")
val glucoseValues = mutableListOf<CgmSourceTransaction.TransactionGlucoseValue>() val glucoseValues = mutableListOf<CgmSourceTransaction.TransactionGlucoseValue>()
glucoseValues += CgmSourceTransaction.TransactionGlucoseValue( glucoseValues += CgmSourceTransaction.TransactionGlucoseValue(

View file

@ -115,7 +115,7 @@ class NSClientSourcePlugin @Inject constructor(
override fun doWork(): Result { override fun doWork(): Result {
var ret = Result.success() 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)) val sgvs = dataWorker.pickupJSONArray(inputData.getLong(DataWorker.STORE_KEY, -1))
?: return Result.failure(workDataOf("Error" to "missing input data")) ?: return Result.failure(workDataOf("Error" to "missing input data"))

View file

@ -60,7 +60,7 @@ class PoctechPlugin @Inject constructor(
override fun doWork(): Result { override fun doWork(): Result {
var ret = Result.success() 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") aapsLogger.debug(LTag.BGSOURCE, "Received Poctech Data $inputData")
try { try {
val glucoseValues = mutableListOf<CgmSourceTransaction.TransactionGlucoseValue>() val glucoseValues = mutableListOf<CgmSourceTransaction.TransactionGlucoseValue>()

View file

@ -59,7 +59,7 @@ class TomatoPlugin @Inject constructor(
override fun doWork(): Result { override fun doWork(): Result {
var ret = Result.success() 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<CgmSourceTransaction.TransactionGlucoseValue>() val glucoseValues = mutableListOf<CgmSourceTransaction.TransactionGlucoseValue>()
glucoseValues += CgmSourceTransaction.TransactionGlucoseValue( glucoseValues += CgmSourceTransaction.TransactionGlucoseValue(
timestamp = inputData.getLong("com.fanqies.tomatofn.Extras.Time", 0), timestamp = inputData.getLong("com.fanqies.tomatofn.Extras.Time", 0),

View file

@ -73,7 +73,7 @@ class XdripPlugin @Inject constructor(
override fun doWork(): Result { override fun doWork(): Result {
var ret = Result.success() 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)) val bundle = dataWorker.pickupBundle(inputData.getLong(DataWorker.STORE_KEY, -1))
?: return Result.failure(workDataOf("Error" to "missing input data")) ?: return Result.failure(workDataOf("Error" to "missing input data"))

View file

@ -67,7 +67,6 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface
) { ) {
super(new PluginDescription() super(new PluginDescription()
.mainType(PluginType.TREATMENT) .mainType(PluginType.TREATMENT)
.fragmentClass(TreatmentsFragment.class.getName())
.pluginIcon(R.drawable.ic_treatments) .pluginIcon(R.drawable.ic_treatments)
.pluginName(R.string.treatments) .pluginName(R.string.treatments)
.shortName(R.string.treatments_shortname) .shortName(R.string.treatments_shortname)

View file

@ -566,11 +566,12 @@ open class CommandQueue @Inject constructor(
return HtmlHelper.fromHtml(s) return HtmlHelper.fromHtml(s)
} }
override fun isThisProfileSet(profile: Profile): Boolean { override fun isThisProfileSet(requestedProfile: Profile): Boolean {
val result = activePlugin.activePump.isThisProfileSet(profile) val runningProfile = profileFunction.getProfile() ?: return false
val result = activePlugin.activePump.isThisProfileSet(requestedProfile) && requestedProfile.isEqual(runningProfile)
if (!result) { if (!result) {
aapsLogger.debug(LTag.PUMPQUEUE, "Current profile: ${profileFunction.getProfile()}") aapsLogger.debug(LTag.PUMPQUEUE, "Current profile: ${profileFunction.getProfile()}")
aapsLogger.debug(LTag.PUMPQUEUE, "New profile: $profile") aapsLogger.debug(LTag.PUMPQUEUE, "New profile: $requestedProfile")
} }
return result return result
} }

View file

@ -119,18 +119,18 @@ class KeepAliveReceiver : DaggerBroadcastReceiver() {
private fun checkPump() { private fun checkPump() {
val pump = activePlugin.activePump val pump = activePlugin.activePump
val ps = profileFunction.getRequestedProfile() ?: return val ps = profileFunction.getRequestedProfile() ?: return
val profile = ProfileSealed.PS(ps) val requestedProfile = ProfileSealed.PS(ps)
val runningProfile = profileFunction.getProfile()
val lastConnection = pump.lastDataTime() val lastConnection = pump.lastDataTime()
val isStatusOutdated = lastConnection + STATUS_UPDATE_FREQUENCY < System.currentTimeMillis() 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)) aapsLogger.debug(LTag.CORE, "Last connection: " + dateUtil.dateAndTimeString(lastConnection))
// sometimes keep alive broadcast stops // sometimes keep alive broadcast stops
// as as workaround test if readStatus was requested before an alarm is generated // as as workaround test if readStatus was requested before an alarm is generated
if (lastReadStatus != 0L && lastReadStatus > System.currentTimeMillis() - T.mins(5).msecs()) { if (lastReadStatus != 0L && lastReadStatus > System.currentTimeMillis() - T.mins(5).msecs()) {
localAlertUtils.checkPumpUnreachableAlarm(lastConnection, isStatusOutdated, loopPlugin.isDisconnected) localAlertUtils.checkPumpUnreachableAlarm(lastConnection, isStatusOutdated, loopPlugin.isDisconnected)
} }
if (!pump.isThisProfileSet(profile) && !commandQueue.isRunning(Command.CommandType.BASAL_PROFILE) if (runningProfile == null || ((!pump.isThisProfileSet(requestedProfile) || !requestedProfile.isEqual(runningProfile)) && !commandQueue.isRunning(Command.CommandType.BASAL_PROFILE))) {
|| profileFunction.getProfile() == null) {
rxBus.send(EventProfileSwitchChanged()) rxBus.send(EventProfileSwitchChanged())
} else if (isStatusOutdated && !pump.isBusy()) { } else if (isStatusOutdated && !pump.isBusy()) {
lastReadStatus = System.currentTimeMillis() lastReadStatus = System.currentTimeMillis()

View file

@ -4,7 +4,7 @@
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
tools:context="info.nightscout.androidaps.historyBrowser.HistoryBrowseActivity"> tools:context="info.nightscout.androidaps.activities.HistoryBrowseActivity">
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
@ -72,7 +72,7 @@
android:layout_weight="1"> android:layout_weight="1">
<com.jjoe64.graphview.GraphView <com.jjoe64.graphview.GraphView
android:id="@+id/bggraph" android:id="@+id/bg_graph"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="match_parent" /> android:layout_height="match_parent" />

View file

@ -239,7 +239,7 @@
android:layout_marginBottom="10dp" android:layout_marginBottom="10dp"
android:orientation="vertical" /> android:orientation="vertical" />
<info.nightscout.androidaps.plugins.treatments.fragments.ProfileGraph <info.nightscout.androidaps.utils.ui.ProfileGraph
android:id="@+id/basal_graph" android:id="@+id/basal_graph"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="100dip" android:layout_height="100dip"

View file

@ -4,7 +4,7 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:orientation="vertical" android:orientation="vertical"
tools:context=".plugins.treatments.fragments.TreatmentsBolusCarbsFragment"> tools:context="info.nightscout.androidaps.activities.fragments.TreatmentsBolusCarbsFragment">
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"

View file

@ -4,7 +4,7 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:orientation="vertical" android:orientation="vertical"
tools:context="info.nightscout.androidaps.plugins.treatments.fragments.TreatmentsCareportalFragment"> tools:context="info.nightscout.androidaps.activities.fragments.TreatmentsCareportalFragment">
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"

View file

@ -4,7 +4,7 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:orientation="vertical" android:orientation="vertical"
tools:context=".plugins.treatments.fragments.TreatmentsExtendedBolusesFragment"> tools:context="info.nightscout.androidaps.activities.fragments.TreatmentsExtendedBolusesFragment">
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"

View file

@ -4,7 +4,7 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:orientation="vertical" android:orientation="vertical"
tools:context=".plugins.treatments.TreatmentsFragment"> tools:context="info.nightscout.androidaps.activities.TreatmentsActivity">
<com.google.android.flexbox.FlexboxLayout <com.google.android.flexbox.FlexboxLayout

View file

@ -4,7 +4,7 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:orientation="vertical" android:orientation="vertical"
tools:context="info.nightscout.androidaps.plugins.treatments.fragments.TreatmentsProfileSwitchFragment"> tools:context="info.nightscout.androidaps.activities.fragments.TreatmentsProfileSwitchFragment">
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"

View file

@ -4,7 +4,7 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:orientation="vertical" android:orientation="vertical"
tools:context="info.nightscout.androidaps.plugins.treatments.fragments.TreatmentsTemporaryBasalsFragment"> tools:context="info.nightscout.androidaps.activities.fragments.TreatmentsTemporaryBasalsFragment">
<LinearLayout <LinearLayout

View file

@ -4,7 +4,7 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:orientation="vertical" android:orientation="vertical"
tools:context="info.nightscout.androidaps.plugins.treatments.fragments.TreatmentsTempTargetFragment"> tools:context="info.nightscout.androidaps.activities.fragments.TreatmentsTempTargetFragment">
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"

View file

@ -4,7 +4,7 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:orientation="vertical" android:orientation="vertical"
tools:context=".plugins.treatments.fragments.TreatmentsUserEntryFragment"> tools:context="info.nightscout.androidaps.activities.fragments.TreatmentsUserEntryFragment">
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"

View file

@ -10,6 +10,10 @@
android:id="@+id/nav_plugin_preferences" android:id="@+id/nav_plugin_preferences"
app:showAsAction="never" app:showAsAction="never"
android:title="@string/nav_plugin_preferences" /> android:title="@string/nav_plugin_preferences" />
<item
android:id="@+id/nav_treatments"
app:showAsAction="never"
android:title="@string/treatments" />
<item <item
android:id="@+id/nav_historybrowser" android:id="@+id/nav_historybrowser"
app:showAsAction="never" app:showAsAction="never"

View file

@ -28,8 +28,6 @@ import info.nightscout.androidaps.plugins.pump.insight.LocalInsightPlugin
import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpPlugin import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpPlugin
import info.nightscout.androidaps.plugins.sensitivity.SensitivityOref1Plugin import info.nightscout.androidaps.plugins.sensitivity.SensitivityOref1Plugin
import info.nightscout.androidaps.plugins.source.GlimpPlugin import info.nightscout.androidaps.plugins.source.GlimpPlugin
import info.nightscout.androidaps.plugins.treatments.TreatmentService
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin
import info.nightscout.androidaps.utils.HardLimits import info.nightscout.androidaps.utils.HardLimits
import info.nightscout.androidaps.utils.Profiler import info.nightscout.androidaps.utils.Profiler
import info.nightscout.androidaps.utils.buildHelper.BuildHelper import info.nightscout.androidaps.utils.buildHelper.BuildHelper
@ -51,7 +49,7 @@ import java.util.*
@RunWith(PowerMockRunner::class) @RunWith(PowerMockRunner::class)
@PrepareForTest( @PrepareForTest(
ConstraintChecker::class, SP::class, Context::class, ConstraintChecker::class, SP::class, Context::class,
OpenAPSAMAPlugin::class, OpenAPSSMBPlugin::class, TreatmentsPlugin::class, TreatmentService::class, OpenAPSAMAPlugin::class, OpenAPSSMBPlugin::class,
VirtualPumpPlugin::class, DetailedBolusInfoStorage::class, TemporaryBasalStorage::class, GlimpPlugin::class, Profiler::class, VirtualPumpPlugin::class, DetailedBolusInfoStorage::class, TemporaryBasalStorage::class, GlimpPlugin::class, Profiler::class,
UserEntryLogger::class, LoggerUtils::class, AppRepository::class, InsightDatabaseDao::class) UserEntryLogger::class, LoggerUtils::class, AppRepository::class, InsightDatabaseDao::class)
class ConstraintsCheckerTest : TestBaseWithProfile() { class ConstraintsCheckerTest : TestBaseWithProfile() {

View file

@ -14,7 +14,6 @@ import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
import info.nightscout.androidaps.plugins.configBuilder.RunningConfiguration import info.nightscout.androidaps.plugins.configBuilder.RunningConfiguration
import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpPlugin import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpPlugin
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin
import info.nightscout.androidaps.receivers.ReceiverStatusStore import info.nightscout.androidaps.receivers.ReceiverStatusStore
import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.FabricPrivacy import info.nightscout.androidaps.utils.FabricPrivacy
@ -41,7 +40,6 @@ class LoopPluginTest : TestBase() {
@Mock lateinit var context: Context @Mock lateinit var context: Context
@Mock lateinit var commandQueue: CommandQueueProvider @Mock lateinit var commandQueue: CommandQueueProvider
@Mock lateinit var activePlugin: ActivePlugin @Mock lateinit var activePlugin: ActivePlugin
@Mock lateinit var treatmentsPlugin: TreatmentsPlugin
@Mock lateinit var virtualPumpPlugin: VirtualPumpPlugin @Mock lateinit var virtualPumpPlugin: VirtualPumpPlugin
@Mock lateinit var iobCobCalculator: IobCobCalculator @Mock lateinit var iobCobCalculator: IobCobCalculator
@Mock lateinit var fabricPrivacy: FabricPrivacy @Mock lateinit var fabricPrivacy: FabricPrivacy

View file

@ -20,7 +20,6 @@ import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
import info.nightscout.androidaps.plugins.general.maintenance.LoggerUtils import info.nightscout.androidaps.plugins.general.maintenance.LoggerUtils
import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpPlugin import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpPlugin
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin
import info.nightscout.androidaps.queue.commands.* import info.nightscout.androidaps.queue.commands.*
import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.FabricPrivacy import info.nightscout.androidaps.utils.FabricPrivacy
@ -45,7 +44,7 @@ import java.util.*
@RunWith(PowerMockRunner::class) @RunWith(PowerMockRunner::class)
@PrepareForTest( @PrepareForTest(
ConstraintChecker::class, VirtualPumpPlugin::class, ToastUtils::class, Context::class, ConstraintChecker::class, VirtualPumpPlugin::class, ToastUtils::class, Context::class,
TreatmentsPlugin::class, FabricPrivacy::class, LoggerUtils::class, PowerManager::class, FabricPrivacy::class, LoggerUtils::class, PowerManager::class,
AppRepository::class) AppRepository::class)
class CommandQueueTest : TestBaseWithProfile() { class CommandQueueTest : TestBaseWithProfile() {

View file

@ -14,7 +14,6 @@ import info.nightscout.androidaps.interfaces.PumpSync
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
import info.nightscout.androidaps.plugins.general.maintenance.LoggerUtils import info.nightscout.androidaps.plugins.general.maintenance.LoggerUtils
import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpPlugin import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpPlugin
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin
import info.nightscout.androidaps.queue.commands.Command import info.nightscout.androidaps.queue.commands.Command
import info.nightscout.androidaps.queue.commands.CommandTempBasalAbsolute import info.nightscout.androidaps.queue.commands.CommandTempBasalAbsolute
import info.nightscout.androidaps.utils.FabricPrivacy import info.nightscout.androidaps.utils.FabricPrivacy
@ -34,7 +33,7 @@ import org.powermock.modules.junit4.PowerMockRunner
@RunWith(PowerMockRunner::class) @RunWith(PowerMockRunner::class)
@PrepareForTest( @PrepareForTest(
ConstraintChecker::class, VirtualPumpPlugin::class, ToastUtils::class, Context::class, ConstraintChecker::class, VirtualPumpPlugin::class, ToastUtils::class, Context::class,
TreatmentsPlugin::class, FabricPrivacy::class, LoggerUtils::class, PowerManager::class) FabricPrivacy::class, LoggerUtils::class, PowerManager::class)
class QueueThreadTest : TestBaseWithProfile() { class QueueThreadTest : TestBaseWithProfile() {
@Mock lateinit var constraintChecker: ConstraintChecker @Mock lateinit var constraintChecker: ConstraintChecker

View file

@ -13,7 +13,6 @@ import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensDataStore import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensDataStore
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatusProvider import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatusProvider
import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpPlugin import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpPlugin
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin
import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.resources.ResourceHelper
import org.junit.Assert import org.junit.Assert
@ -40,7 +39,6 @@ class BolusWizardTest : TestBase() {
@Mock lateinit var commandQueue: CommandQueueProvider @Mock lateinit var commandQueue: CommandQueueProvider
@Mock lateinit var loopPlugin: LoopPlugin @Mock lateinit var loopPlugin: LoopPlugin
@Mock lateinit var iobCobCalculator: IobCobCalculator @Mock lateinit var iobCobCalculator: IobCobCalculator
@Mock lateinit var treatmentsPlugin: TreatmentsPlugin
@Mock lateinit var virtualPumpPlugin: VirtualPumpPlugin @Mock lateinit var virtualPumpPlugin: VirtualPumpPlugin
@Mock lateinit var dateUtil: DateUtil @Mock lateinit var dateUtil: DateUtil
@Mock lateinit var autosensDataStore: AutosensDataStore @Mock lateinit var autosensDataStore: AutosensDataStore
@ -71,7 +69,6 @@ class BolusWizardTest : TestBase() {
`when`(profile.getIc()).thenReturn(insulinToCarbRatio) `when`(profile.getIc()).thenReturn(insulinToCarbRatio)
`when`(profileFunction.getUnits()).thenReturn(GlucoseUnit.MGDL) `when`(profileFunction.getUnits()).thenReturn(GlucoseUnit.MGDL)
`when`(activePlugin.activeTreatments).thenReturn(treatmentsPlugin)
`when`(iobCobCalculator.calculateIobFromBolus()).thenReturn(IobTotal(System.currentTimeMillis())) `when`(iobCobCalculator.calculateIobFromBolus()).thenReturn(IobTotal(System.currentTimeMillis()))
`when`(iobCobCalculator.calculateIobFromTempBasalsIncludingConvertedExtended()).thenReturn(IobTotal(System.currentTimeMillis())) `when`(iobCobCalculator.calculateIobFromTempBasalsIncludingConvertedExtended()).thenReturn(IobTotal(System.currentTimeMillis()))
`when`(activePlugin.activePump).thenReturn(virtualPumpPlugin) `when`(activePlugin.activePump).thenReturn(virtualPumpPlugin)

View file

@ -15,7 +15,6 @@ import info.nightscout.androidaps.interfaces.Profile.Companion.secondsFromMidnig
import info.nightscout.androidaps.interfaces.Profile.Companion.toMgdl import info.nightscout.androidaps.interfaces.Profile.Companion.toMgdl
import info.nightscout.androidaps.interfaces.Profile.ProfileValue import info.nightscout.androidaps.interfaces.Profile.ProfileValue
import info.nightscout.androidaps.interfaces.Pump import info.nightscout.androidaps.interfaces.Pump
import info.nightscout.androidaps.interfaces.PumpDescription
import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification
import info.nightscout.androidaps.plugins.general.overview.notifications.Notification import info.nightscout.androidaps.plugins.general.overview.notifications.Notification
@ -153,6 +152,7 @@ sealed class ProfileSealed(
if (getIcTimeFromMidnight(seconds) != profile.getIcTimeFromMidnight(seconds)) return false if (getIcTimeFromMidnight(seconds) != profile.getIcTimeFromMidnight(seconds)) return false
if (getTargetLowMgdlTimeFromMidnight(seconds) != profile.getTargetLowMgdlTimeFromMidnight(seconds)) return false if (getTargetLowMgdlTimeFromMidnight(seconds) != profile.getTargetLowMgdlTimeFromMidnight(seconds)) return false
if (getTargetHighMgdlTimeFromMidnight(seconds) != profile.getTargetHighMgdlTimeFromMidnight(seconds)) return false if (getTargetHighMgdlTimeFromMidnight(seconds) != profile.getTargetHighMgdlTimeFromMidnight(seconds)) return false
if (dia != profile.dia) return false
} }
return true return true
} }

View file

@ -38,5 +38,5 @@ interface CommandQueueProvider {
fun isCustomCommandRunning(customCommandType: Class<out CustomCommand>): Boolean fun isCustomCommandRunning(customCommandType: Class<out CustomCommand>): Boolean
fun isCustomCommandInQueue(customCommandType: Class<out CustomCommand>): Boolean fun isCustomCommandInQueue(customCommandType: Class<out CustomCommand>): Boolean
fun spannedStatus(): Spanned fun spannedStatus(): Spanned
fun isThisProfileSet(profile: Profile): Boolean fun isThisProfileSet(requestedProfile: Profile): Boolean
} }

View file

@ -31,6 +31,15 @@ class ProfileStore(val injector: HasAndroidInjector, val data: JSONObject, val d
return null 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 getDefaultProfile(): PureProfile? = getDefaultProfileName()?.let { getSpecificProfile(it) }
fun getDefaultProfileJson(): JSONObject? = getDefaultProfileName()?.let { getSpecificProfileJson(it) } fun getDefaultProfileJson(): JSONObject? = getDefaultProfileName()?.let { getSpecificProfileJson(it) }

View file

@ -29,7 +29,7 @@ class DetailedBolusInfoStorage @Inject constructor(
val d = store[i] val d = store[i]
//aapsLogger.debug(LTag.PUMP, "Existing bolus info: " + 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) { 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) store.removeAt(i)
return d return d
} }
@ -38,22 +38,22 @@ class DetailedBolusInfoStorage @Inject constructor(
for (i in store.indices) { for (i in store.indices) {
val d = store[i] 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) { 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) store.removeAt(i)
return d return d
} }
} }
// If not found, use last record if amount is the same // If not found, use last record if amount is the same
if (store.size > 0) { // if (store.size > 0) {
val d = store[store.size - 1] // val d = store[store.size - 1]
if (abs(d.insulin - bolus) < 0.01) { // if (abs(d.insulin - bolus) < 0.01) {
aapsLogger.debug(LTag.PUMP, "Using LAST & removing bolus info: $d") // aapsLogger.debug(LTag.PUMP, "Using LAST & removing bolus info for time $bolusTime: $d")
store.removeAt(store.size - 1) // store.removeAt(store.size - 1)
return d // return d
} // }
} // }
//Not found //Not found
//aapsLogger.debug(LTag.PUMP, "Bolus info not found") aapsLogger.debug(LTag.PUMP, "Bolus info not found for time $bolusTime")
return null return null
} }
} }

View file

@ -1,7 +1,6 @@
package info.nightscout.androidaps.plugins.treatments.fragments package info.nightscout.androidaps.utils.ui
import android.content.Context import android.content.Context
import android.graphics.Color
import android.util.AttributeSet import android.util.AttributeSet
import com.jjoe64.graphview.GraphView import com.jjoe64.graphview.GraphView
import com.jjoe64.graphview.series.DataPoint 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.core.R
import info.nightscout.androidaps.interfaces.Profile import info.nightscout.androidaps.interfaces.Profile
import info.nightscout.androidaps.utils.Round import info.nightscout.androidaps.utils.Round
import java.util.* import java.util.ArrayList
import kotlin.math.max import kotlin.math.max
class ProfileGraph : GraphView { class ProfileGraph : GraphView {

View file

@ -371,7 +371,7 @@
</LinearLayout> </LinearLayout>
<info.nightscout.androidaps.plugins.treatments.fragments.ProfileGraph <info.nightscout.androidaps.utils.ui.ProfileGraph
android:id="@+id/basal_graph" android:id="@+id/basal_graph"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="100dip" android:layout_height="100dip"

View file

@ -79,10 +79,10 @@ class DetailedBolusInfoStorageTest : TestBase() {
assertNull(d) assertNull(d)
assertEquals(3, detailedBolusInfoStorage.store.size) assertEquals(3, detailedBolusInfoStorage.store.size)
// Use last, if bolus size is the same // Use last, if bolus size is the same
setUp() // setUp()
d = detailedBolusInfoStorage.findDetailedBolusInfo(1070000, 5.0) // d = detailedBolusInfoStorage.findDetailedBolusInfo(1070000, 5.0)
assertEquals(5.0, d!!.insulin, 0.01) // assertEquals(5.0, d!!.insulin, 0.01)
assertEquals(2, detailedBolusInfoStorage.store.size) // assertEquals(2, detailedBolusInfoStorage.store.size)
} }
} }

View file

@ -62,9 +62,6 @@ class BLEComm @Inject internal constructor(
private const val PACKET_START_BYTE = 0xA5.toByte() private const val PACKET_START_BYTE = 0xA5.toByte()
private const val PACKET_END_BYTE = 0x5A.toByte() private const val PACKET_END_BYTE = 0x5A.toByte()
private const val BLE5_PACKET_START_BYTE = 0x73.toByte()
private const val BLE5_PACKET_END_BYTE = 0xBF.toByte()
} }
private var scheduledDisconnection: ScheduledFuture<*>? = null private var scheduledDisconnection: ScheduledFuture<*>? = null
@ -326,13 +323,16 @@ class BLEComm @Inject internal constructor(
} }
private val readBuffer = ByteArray(1024) private val readBuffer = ByteArray(1024)
private var bufferLength = 0 @Volatile private var bufferLength = 0
private fun addToReadBuffer(buffer: ByteArray) { private fun addToReadBuffer(buffer: ByteArray) {
//log.debug("addToReadBuffer " + DanaRS_Packet.toHexString(buffer)); //log.debug("addToReadBuffer " + DanaRS_Packet.toHexString(buffer));
if (buffer.isEmpty()) { if (buffer.isEmpty()) {
return return
} }
if (bufferLength == 1024) {
aapsLogger.debug(LTag.PUMPBTCOMM, "1024 XXXXXXXXXXXXXX")
}
synchronized(readBuffer) { synchronized(readBuffer) {
// Append incoming data to input buffer // Append incoming data to input buffer
System.arraycopy(buffer, 0, readBuffer, bufferLength, buffer.size) System.arraycopy(buffer, 0, readBuffer, bufferLength, buffer.size)
@ -342,21 +342,23 @@ class BLEComm @Inject internal constructor(
@kotlin.ExperimentalStdlibApi @kotlin.ExperimentalStdlibApi
private fun readDataParsing(receivedData: ByteArray) { private fun readDataParsing(receivedData: ByteArray) {
//aapsLogger.debug(LTag.PUMPBTCOMM, "readDataParsing") //aapsLogger.debug(LTag.PUMPBTCOMM, "<<<<< readDataParsing " + DanaRS_Packet.toHexString(receivedData))
var startSignatureFound = false var startSignatureFound = false
var packetIsValid = false var packetIsValid = false
var isProcessing: Boolean var isProcessing: Boolean
isProcessing = true isProcessing = true
var inputBuffer: ByteArray? = null var inputBuffer: ByteArray?
// decrypt 2nd level after successful connection // decrypt 2nd level after successful connection
val incomingBuffer = if (encryption == EncryptionType.ENCRYPTION_RSv3 && isConnected) val incomingBuffer =
bleEncryption.decryptSecondLevelPacket(receivedData).also { if (isConnected && (encryption == EncryptionType.ENCRYPTION_RSv3 || encryption == EncryptionType.ENCRYPTION_BLE5))
encryptedDataRead = true bleEncryption.decryptSecondLevelPacket(receivedData).also {
sp.putLong(R.string.key_rs_last_clear_key_request, 0L) encryptedDataRead = true
} sp.putLong(R.string.key_rs_last_clear_key_request, 0L)
else receivedData }
else receivedData
addToReadBuffer(incomingBuffer) addToReadBuffer(incomingBuffer)
//aapsLogger.debug(LTag.PUMPBTCOMM, "incomingBuffer " + DanaRS_Packet.toHexString(incomingBuffer))
while (isProcessing) { while (isProcessing) {
var length = 0 var length = 0
@ -386,58 +388,29 @@ class BLEComm @Inject internal constructor(
// Verify packed end [5A 5A] // Verify packed end [5A 5A]
if (readBuffer[length + 5] == PACKET_END_BYTE && readBuffer[length + 6] == PACKET_END_BYTE) { if (readBuffer[length + 5] == PACKET_END_BYTE && readBuffer[length + 6] == PACKET_END_BYTE) {
packetIsValid = true 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) { 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 // decrypt the packet
bleEncryption.getDecryptedPacket(inputBuffer)?.let { decryptedBuffer -> bleEncryption.getDecryptedPacket(inputBuffer)?.let { decryptedBuffer ->
if (decryptedBuffer[0] == BleEncryption.DANAR_PACKET__TYPE_ENCRYPTION_RESPONSE.toByte()) { if (decryptedBuffer[0] == BleEncryption.DANAR_PACKET__TYPE_ENCRYPTION_RESPONSE.toByte()) {

View file

@ -16,7 +16,7 @@ internal interface GlucoseValueDao : TraceableDao<GlucoseValue> {
@Query("DELETE FROM $TABLE_GLUCOSE_VALUES") @Query("DELETE FROM $TABLE_GLUCOSE_VALUES")
override fun deleteAllEntries() 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<GlucoseValue> fun getLast(): Maybe<GlucoseValue>
@Query("SELECT id FROM $TABLE_GLUCOSE_VALUES ORDER BY id DESC limit 1") @Query("SELECT id FROM $TABLE_GLUCOSE_VALUES ORDER BY id DESC limit 1")