Merge pull request #31 from 0pen-dash/avereha/merge-dev
avereha/merge dev
This commit is contained in:
commit
311d12ffe6
620 changed files with 25090 additions and 22456 deletions
73
.circleci/config.yml
Normal file
73
.circleci/config.yml
Normal file
|
@ -0,0 +1,73 @@
|
|||
# Use the latest 2.1 version of CircleCI pipeline process engine.
|
||||
# See: https://circleci.com/docs/2.0/configuration-reference
|
||||
version: 2.1
|
||||
|
||||
# Orbs are reusable packages of CircleCI configuration that you may share across projects, enabling you to create encapsulated, parameterized commands, jobs, and executors that can be used across multiple projects.
|
||||
orbs:
|
||||
android: circleci/android@1.0.3
|
||||
codecov: codecov/codecov@1.2.0
|
||||
|
||||
jobs:
|
||||
# Below is the definition of your job to build and test your app, you can rename and customize it as you want.
|
||||
build-and-test:
|
||||
# These next lines define the Android machine image executor: https://circleci.com/docs/2.0/executor-types/
|
||||
executor:
|
||||
name: android/android-machine
|
||||
|
||||
steps:
|
||||
# Checkout the code as the first step.
|
||||
- checkout
|
||||
|
||||
# The next step will run the unit tests
|
||||
- android/run-tests:
|
||||
test-command: ./gradlew -Pcoverage -PfirebaseDisable testFullDebugUnitTest jacocoTestFullDebugUnitTestReport
|
||||
|
||||
# Then start the emulator and run the Instrumentation tests!
|
||||
# - android/start-emulator-and-run-tests:
|
||||
# test-command: ./gradlew connectedDebugAndroidTest
|
||||
# system-image: system-images;android-25;google_apis;x86
|
||||
|
||||
# And finally run the release build
|
||||
# - run:
|
||||
# name: Assemble release build
|
||||
# command: |
|
||||
# ./gradlew assembleRelease
|
||||
- codecov/upload:
|
||||
file: './app/build/jacoco/jacoco.xml'
|
||||
- codecov/upload:
|
||||
file: './automation/build/jacoco/jacoco.xml'
|
||||
- codecov/upload:
|
||||
file: './combo/build/jacoco/jacoco.xml'
|
||||
- codecov/upload:
|
||||
file: './core/build/jacoco/jacoco.xml'
|
||||
- codecov/upload:
|
||||
file: './dana/build/jacoco/jacoco.xml'
|
||||
- codecov/upload:
|
||||
file: './danar/build/jacoco/jacoco.xml'
|
||||
- codecov/upload:
|
||||
file: './danars/build/jacoco/jacoco.xml'
|
||||
- codecov/upload:
|
||||
file: './database/build/jacoco/jacoco.xml'
|
||||
- codecov/upload:
|
||||
file: './insight/build/jacoco/jacoco.xml'
|
||||
- codecov/upload:
|
||||
file: './medtronic/build/jacoco/jacoco.xml'
|
||||
- codecov/upload:
|
||||
file: './omnipod-common/build/jacoco/jacoco.xml'
|
||||
- codecov/upload:
|
||||
file: './omnipod-dash/build/jacoco/jacoco.xml'
|
||||
- codecov/upload:
|
||||
file: './omnipod-eros/build/jacoco/jacoco.xml'
|
||||
- codecov/upload:
|
||||
file: './rileylink/build/jacoco/jacoco.xml'
|
||||
- codecov/upload:
|
||||
file: './wear/build/jacoco/jacoco.xml'
|
||||
|
||||
workflows:
|
||||
# Below is the definition of your workflow.
|
||||
# Inside the workflow, you provide the jobs you want to run, e.g this workflow runs the build-and-test job above.
|
||||
# CircleCI will run this workflow on every commit.
|
||||
# For more details on extending your workflow, see the configuration docs: https://circleci.com/docs/2.0/configuration-reference/#workflows
|
||||
sample:
|
||||
jobs:
|
||||
- build-and-test
|
|
@ -111,7 +111,7 @@ android {
|
|||
defaultConfig {
|
||||
multiDexEnabled true
|
||||
versionCode 1500
|
||||
version "2.8.2.1-dev-e3"
|
||||
version "2.8.2.1-dev-e5"
|
||||
buildConfigField "String", "VERSION", '"' + version + '"'
|
||||
buildConfigField "String", "BUILDVERSION", '"' + generateGitBuild() + '-' + generateDate() + '"'
|
||||
buildConfigField "String", "REMOTE", '"' + generateGitRemote() + '"'
|
||||
|
@ -186,6 +186,7 @@ dependencies {
|
|||
implementation project(':danars')
|
||||
implementation project(':danar')
|
||||
implementation project(':insight')
|
||||
implementation project(':pump-common')
|
||||
implementation project(':rileylink')
|
||||
implementation project(':medtronic')
|
||||
implementation project(':omnipod-common')
|
||||
|
@ -197,8 +198,6 @@ dependencies {
|
|||
/* Dagger2 - We are going to use dagger.android which includes
|
||||
* support for Activity and fragment injection so we need to include
|
||||
* the following dependencies */
|
||||
|
||||
|
||||
annotationProcessor "com.google.dagger:dagger-compiler:$dagger_version"
|
||||
annotationProcessor "com.google.dagger:dagger-android-processor:$dagger_version"
|
||||
kapt "com.google.dagger:dagger-android-processor:$dagger_version"
|
||||
|
|
Binary file not shown.
|
@ -68,7 +68,8 @@
|
|||
</intent-filter>
|
||||
</activity>
|
||||
<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.ProfileHelperActivity"
|
||||
android:theme="@style/ProfileHelperAppTheme" />
|
||||
|
|
|
@ -27,18 +27,14 @@ import com.google.firebase.crashlytics.FirebaseCrashlytics
|
|||
import com.joanzapata.iconify.Iconify
|
||||
import com.joanzapata.iconify.fonts.FontAwesomeModule
|
||||
import dev.doubledot.doki.ui.DokiActivity
|
||||
import info.nightscout.androidaps.activities.NoSplashAppCompatActivity
|
||||
import info.nightscout.androidaps.activities.PreferencesActivity
|
||||
import info.nightscout.androidaps.activities.ProfileHelperActivity
|
||||
import info.nightscout.androidaps.activities.SingleFragmentActivity
|
||||
import info.nightscout.androidaps.activities.StatsActivity
|
||||
import info.nightscout.androidaps.activities.*
|
||||
import info.nightscout.androidaps.database.entities.UserEntry.Action
|
||||
import info.nightscout.androidaps.database.entities.UserEntry.Sources
|
||||
import info.nightscout.androidaps.databinding.ActivityMainBinding
|
||||
import info.nightscout.androidaps.events.EventAppExit
|
||||
import info.nightscout.androidaps.events.EventPreferenceChange
|
||||
import info.nightscout.androidaps.events.EventRebuildTabs
|
||||
import info.nightscout.androidaps.historyBrowser.HistoryBrowseActivity
|
||||
import info.nightscout.androidaps.activities.HistoryBrowseActivity
|
||||
import info.nightscout.androidaps.interfaces.ActivePlugin
|
||||
import info.nightscout.androidaps.interfaces.Config
|
||||
import info.nightscout.androidaps.interfaces.IconsProvider
|
||||
|
@ -99,6 +95,7 @@ class MainActivity : NoSplashAppCompatActivity() {
|
|||
|
||||
private lateinit var binding: ActivityMainBinding
|
||||
|
||||
@kotlin.ExperimentalStdlibApi
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
Iconify.with(FontAwesomeModule())
|
||||
|
@ -290,6 +287,11 @@ class MainActivity : NoSplashAppCompatActivity() {
|
|||
return true
|
||||
}
|
||||
|
||||
R.id.nav_treatments -> {
|
||||
startActivity(Intent(this, TreatmentsActivity::class.java))
|
||||
return true
|
||||
}
|
||||
|
||||
R.id.nav_setupwizard -> {
|
||||
protectionCheck.queryProtection(this, ProtectionCheck.Protection.PREFERENCES, {
|
||||
startActivity(Intent(this, SetupWizardActivity::class.java))
|
||||
|
@ -359,11 +361,12 @@ class MainActivity : NoSplashAppCompatActivity() {
|
|||
// Correct place for calling setUserStats() would be probably MainApp
|
||||
// but we need to have it called at least once a day. Thus this location
|
||||
|
||||
@kotlin.ExperimentalStdlibApi
|
||||
private fun setUserStats() {
|
||||
if (!fabricPrivacy.fabricEnabled()) return
|
||||
val closedLoopEnabled = if (constraintChecker.isClosedLoopAllowed().value()) "CLOSED_LOOP_ENABLED" else "CLOSED_LOOP_DISABLED"
|
||||
// Size is limited to 36 chars
|
||||
val remote = BuildConfig.REMOTE.toLowerCase(Locale.getDefault())
|
||||
val remote = BuildConfig.REMOTE.lowercase(Locale.getDefault())
|
||||
.replace("https://", "")
|
||||
.replace("http://", "")
|
||||
.replace(".git", "")
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -7,8 +7,10 @@ import javax.inject.Inject
|
|||
class RequestDexcomPermissionActivity : DialogAppCompatActivity() {
|
||||
@Inject lateinit var dexcomPlugin: DexcomPlugin
|
||||
|
||||
private val requestCode = "AndroidAPS <3".map { it.toInt() }.sum()
|
||||
@kotlin.ExperimentalStdlibApi
|
||||
private val requestCode = "AndroidAPS <3".map { it.code }.sum()
|
||||
|
||||
@kotlin.ExperimentalStdlibApi
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
requestPermissions(arrayOf(DexcomPlugin.PERMISSION), requestCode)
|
||||
|
|
|
@ -1,53 +1,28 @@
|
|||
package info.nightscout.androidaps.plugins.treatments
|
||||
package info.nightscout.androidaps.activities
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.FragmentTransaction
|
||||
import dagger.android.support.DaggerFragment
|
||||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.activities.fragments.*
|
||||
import info.nightscout.androidaps.databinding.TreatmentsFragmentBinding
|
||||
import info.nightscout.androidaps.events.EventExtendedBolusChange
|
||||
import info.nightscout.androidaps.interfaces.ActivePlugin
|
||||
import info.nightscout.androidaps.interfaces.IobCobCalculator
|
||||
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
||||
import info.nightscout.androidaps.plugins.treatments.fragments.*
|
||||
import info.nightscout.androidaps.utils.DateUtil
|
||||
import info.nightscout.androidaps.utils.FabricPrivacy
|
||||
import info.nightscout.androidaps.utils.buildHelper.BuildHelper
|
||||
import info.nightscout.androidaps.extensions.toVisibility
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
||||
import io.reactivex.disposables.CompositeDisposable
|
||||
import io.reactivex.rxkotlin.plusAssign
|
||||
import info.nightscout.androidaps.interfaces.ActivePlugin
|
||||
import info.nightscout.androidaps.utils.buildHelper.BuildHelper
|
||||
import javax.inject.Inject
|
||||
|
||||
class TreatmentsFragment : DaggerFragment() {
|
||||
class TreatmentsActivity : NoSplashAppCompatActivity() {
|
||||
|
||||
@Inject lateinit var rxBus: RxBusWrapper
|
||||
@Inject lateinit var resourceHelper: ResourceHelper
|
||||
@Inject lateinit var fabricPrivacy: FabricPrivacy
|
||||
@Inject lateinit var activePlugin: ActivePlugin
|
||||
@Inject lateinit var iobCobCalculator: IobCobCalculator
|
||||
@Inject lateinit var aapsSchedulers: AapsSchedulers
|
||||
@Inject lateinit var buildHelper: BuildHelper
|
||||
@Inject lateinit var dateUtil: DateUtil
|
||||
@Inject lateinit var activePlugin: ActivePlugin
|
||||
|
||||
private val disposable = CompositeDisposable()
|
||||
private lateinit var binding: TreatmentsFragmentBinding
|
||||
|
||||
private var _binding: TreatmentsFragmentBinding? = null
|
||||
|
||||
// This property is only valid between onCreateView and
|
||||
// onDestroyView.
|
||||
private val binding get() = _binding!!
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View =
|
||||
TreatmentsFragmentBinding.inflate(inflater, container, false).also { _binding = it }.root
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
binding = TreatmentsFragmentBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
|
||||
binding.tempBasals.visibility = buildHelper.isEngineeringMode().toVisibility()
|
||||
binding.extendedBoluses.visibility = (buildHelper.isEngineeringMode() && !activePlugin.activePump.isFakingTempsByExtendedBoluses).toVisibility()
|
||||
|
@ -84,33 +59,10 @@ class TreatmentsFragment : DaggerFragment() {
|
|||
setBackgroundColorOnSelected(binding.treatments)
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
disposable += rxBus
|
||||
.toObservable(EventExtendedBolusChange::class.java)
|
||||
.observeOn(aapsSchedulers.main)
|
||||
.subscribe({ updateGui() }, fabricPrivacy::logException)
|
||||
updateGui()
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
override fun onPause() {
|
||||
super.onPause()
|
||||
disposable.clear()
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
override fun onDestroyView() {
|
||||
super.onDestroyView()
|
||||
_binding = null
|
||||
}
|
||||
|
||||
private fun setFragment(selectedFragment: Fragment) {
|
||||
childFragmentManager.beginTransaction()
|
||||
.replace(R.id.fragment_container, selectedFragment) // f2_container is your FrameLayout container
|
||||
.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
|
||||
.addToBackStack(null)
|
||||
supportFragmentManager.beginTransaction()
|
||||
.replace(R.id.fragment_container, selectedFragment)
|
||||
.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE)
|
||||
.commit()
|
||||
}
|
||||
|
||||
|
@ -125,8 +77,4 @@ class TreatmentsFragment : DaggerFragment() {
|
|||
selected.setBackgroundColor(resourceHelper.gc(R.color.tabBgColorSelected))
|
||||
}
|
||||
|
||||
private fun updateGui() {
|
||||
if (_binding == null) return
|
||||
binding.extendedBoluses.visibility = (activePlugin.activePump.pumpDescription.isExtendedBolusCapable || iobCobCalculator.getExtendedBolus(dateUtil.now()) != null).toVisibility()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package info.nightscout.androidaps.plugins.treatments.fragments
|
||||
package info.nightscout.androidaps.activities.fragments
|
||||
|
||||
import android.graphics.Paint
|
||||
import android.os.Bundle
|
||||
|
@ -156,7 +156,7 @@ class TreatmentsBolusCarbsFragment : DaggerFragment() {
|
|||
})
|
||||
}
|
||||
}
|
||||
val nsUploadOnly = sp.getBoolean(R.string.key_ns_upload_only, true) || !buildHelper.isEngineeringMode()
|
||||
val nsUploadOnly = !sp.getBoolean(R.string.key_ns_receive_insulin, false) || !sp.getBoolean(R.string.key_ns_receive_carbs, false) || !buildHelper.isEngineeringMode()
|
||||
if (nsUploadOnly) binding.refreshFromNightscout.visibility = View.GONE
|
||||
binding.showInvalidated.setOnCheckedChangeListener { _, _ ->
|
||||
rxBus.send(EventTreatmentUpdateGui())
|
|
@ -1,4 +1,4 @@
|
|||
package info.nightscout.androidaps.plugins.treatments.fragments
|
||||
package info.nightscout.androidaps.activities.fragments
|
||||
|
||||
import android.graphics.Paint
|
||||
import android.os.Bundle
|
||||
|
@ -25,7 +25,7 @@ import info.nightscout.androidaps.logging.UserEntryLogger
|
|||
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
||||
import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientRestart
|
||||
import info.nightscout.androidaps.plugins.treatments.events.EventTreatmentUpdateGui
|
||||
import info.nightscout.androidaps.plugins.treatments.fragments.TreatmentsCareportalFragment.RecyclerViewAdapter.TherapyEventsViewHolder
|
||||
import info.nightscout.androidaps.activities.fragments.TreatmentsCareportalFragment.RecyclerViewAdapter.TherapyEventsViewHolder
|
||||
import info.nightscout.androidaps.utils.DateUtil
|
||||
import info.nightscout.androidaps.utils.FabricPrivacy
|
||||
import info.nightscout.androidaps.utils.T
|
||||
|
@ -102,7 +102,7 @@ class TreatmentsCareportalFragment : DaggerFragment() {
|
|||
}
|
||||
}
|
||||
|
||||
val nsUploadOnly = sp.getBoolean(R.string.key_ns_upload_only, true) || !buildHelper.isEngineeringMode()
|
||||
val nsUploadOnly = !sp.getBoolean(R.string.key_ns_receive_therapy_events, false) || !buildHelper.isEngineeringMode()
|
||||
if (nsUploadOnly) binding.refreshFromNightscout.visibility = View.GONE
|
||||
binding.showInvalidated.setOnCheckedChangeListener { _, _ ->
|
||||
rxBus.send(EventTreatmentUpdateGui())
|
|
@ -1,4 +1,4 @@
|
|||
package info.nightscout.androidaps.plugins.treatments.fragments
|
||||
package info.nightscout.androidaps.activities.fragments
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.DialogInterface
|
||||
|
@ -15,6 +15,7 @@ import info.nightscout.androidaps.database.AppRepository
|
|||
import info.nightscout.androidaps.database.entities.ExtendedBolus
|
||||
import info.nightscout.androidaps.database.entities.UserEntry.Action
|
||||
import info.nightscout.androidaps.database.entities.UserEntry.Sources
|
||||
import info.nightscout.androidaps.database.entities.ValueWithUnit
|
||||
import info.nightscout.androidaps.database.interfaces.end
|
||||
import info.nightscout.androidaps.database.transactions.InvalidateExtendedBolusTransaction
|
||||
import info.nightscout.androidaps.databinding.TreatmentsExtendedbolusFragmentBinding
|
||||
|
@ -29,7 +30,7 @@ import info.nightscout.androidaps.logging.AAPSLogger
|
|||
import info.nightscout.androidaps.logging.LTag
|
||||
import info.nightscout.androidaps.logging.UserEntryLogger
|
||||
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
||||
import info.nightscout.androidaps.plugins.treatments.fragments.TreatmentsExtendedBolusesFragment.RecyclerViewAdapter.ExtendedBolusesViewHolder
|
||||
import info.nightscout.androidaps.activities.fragments.TreatmentsExtendedBolusesFragment.RecyclerViewAdapter.ExtendedBolusesViewHolder
|
||||
import info.nightscout.androidaps.utils.DateUtil
|
||||
import info.nightscout.androidaps.utils.FabricPrivacy
|
||||
import info.nightscout.androidaps.utils.T
|
||||
|
@ -157,7 +158,11 @@ class TreatmentsExtendedBolusesFragment : DaggerFragment() {
|
|||
${resourceHelper.gs(R.string.extended_bolus)}
|
||||
${resourceHelper.gs(R.string.date)}: ${dateUtil.dateAndTimeString(extendedBolus.timestamp)}
|
||||
""".trimIndent(), { _: DialogInterface, _: Int ->
|
||||
uel.log(Action.EXTENDED_BOLUS_REMOVED, Sources.Treatments)
|
||||
uel.log(Action.EXTENDED_BOLUS_REMOVED, Sources.Treatments,
|
||||
ValueWithUnit.Timestamp(extendedBolus.timestamp),
|
||||
ValueWithUnit.Insulin(extendedBolus.amount),
|
||||
ValueWithUnit.UnitPerHour(extendedBolus.rate),
|
||||
ValueWithUnit.Minute(TimeUnit.MILLISECONDS.toMinutes(extendedBolus.duration).toInt()))
|
||||
disposable += repository.runTransactionForResult(InvalidateExtendedBolusTransaction(extendedBolus.id))
|
||||
.subscribe(
|
||||
{ aapsLogger.debug(LTag.DATABASE, "Removed extended bolus $extendedBolus") },
|
|
@ -1,4 +1,4 @@
|
|||
package info.nightscout.androidaps.plugins.treatments.fragments
|
||||
package info.nightscout.androidaps.activities.fragments
|
||||
|
||||
import android.graphics.Paint
|
||||
import android.os.Bundle
|
||||
|
@ -21,18 +21,16 @@ import info.nightscout.androidaps.dialogs.ProfileViewerDialog
|
|||
import info.nightscout.androidaps.events.EventProfileSwitchChanged
|
||||
import info.nightscout.androidaps.extensions.getCustomizedName
|
||||
import info.nightscout.androidaps.extensions.toVisibility
|
||||
import info.nightscout.androidaps.interfaces.UploadQueueInterface
|
||||
import info.nightscout.androidaps.logging.AAPSLogger
|
||||
import info.nightscout.androidaps.logging.LTag
|
||||
import info.nightscout.androidaps.logging.UserEntryLogger
|
||||
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
||||
import info.nightscout.androidaps.plugins.general.nsclient.NSUpload
|
||||
import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientRestart
|
||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventNewHistoryData
|
||||
import info.nightscout.androidaps.plugins.profile.local.LocalProfilePlugin
|
||||
import info.nightscout.androidaps.plugins.profile.local.events.EventLocalProfileChanged
|
||||
import info.nightscout.androidaps.plugins.treatments.events.EventTreatmentUpdateGui
|
||||
import info.nightscout.androidaps.plugins.treatments.fragments.TreatmentsProfileSwitchFragment.RecyclerProfileViewAdapter.ProfileSwitchViewHolder
|
||||
import info.nightscout.androidaps.activities.fragments.TreatmentsProfileSwitchFragment.RecyclerProfileViewAdapter.ProfileSwitchViewHolder
|
||||
import info.nightscout.androidaps.utils.DateUtil
|
||||
import info.nightscout.androidaps.utils.FabricPrivacy
|
||||
import info.nightscout.androidaps.utils.T
|
||||
|
@ -55,8 +53,6 @@ class TreatmentsProfileSwitchFragment : DaggerFragment() {
|
|||
@Inject lateinit var localProfilePlugin: LocalProfilePlugin
|
||||
@Inject lateinit var resourceHelper: ResourceHelper
|
||||
@Inject lateinit var fabricPrivacy: FabricPrivacy
|
||||
@Inject lateinit var nsUpload: NSUpload
|
||||
@Inject lateinit var uploadQueue: UploadQueueInterface
|
||||
@Inject lateinit var dateUtil: DateUtil
|
||||
@Inject lateinit var buildHelper: BuildHelper
|
||||
@Inject lateinit var aapsSchedulers: AapsSchedulers
|
||||
|
@ -103,7 +99,7 @@ class TreatmentsProfileSwitchFragment : DaggerFragment() {
|
|||
}
|
||||
}
|
||||
}
|
||||
if (sp.getBoolean(R.string.key_ns_upload_only, true) || !buildHelper.isEngineeringMode()) binding.refreshFromNightscout.visibility = View.GONE
|
||||
if (!sp.getBoolean(R.string.key_ns_receive_profile_switch, false) || !buildHelper.isEngineeringMode()) binding.refreshFromNightscout.visibility = View.GONE
|
||||
binding.showInvalidated.setOnCheckedChangeListener { _, _ ->
|
||||
rxBus.send(EventTreatmentUpdateGui())
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package info.nightscout.androidaps.plugins.treatments.fragments
|
||||
package info.nightscout.androidaps.activities.fragments
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.DialogInterface
|
||||
|
@ -23,14 +23,13 @@ import info.nightscout.androidaps.databinding.TreatmentsTemptargetFragmentBindin
|
|||
import info.nightscout.androidaps.databinding.TreatmentsTemptargetItemBinding
|
||||
import info.nightscout.androidaps.events.EventTempTargetChange
|
||||
import info.nightscout.androidaps.interfaces.ProfileFunction
|
||||
import info.nightscout.androidaps.interfaces.UploadQueueInterface
|
||||
import info.nightscout.androidaps.logging.AAPSLogger
|
||||
import info.nightscout.androidaps.logging.LTag
|
||||
import info.nightscout.androidaps.logging.UserEntryLogger
|
||||
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
||||
import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientRestart
|
||||
import info.nightscout.androidaps.plugins.treatments.events.EventTreatmentUpdateGui
|
||||
import info.nightscout.androidaps.plugins.treatments.fragments.TreatmentsTempTargetFragment.RecyclerViewAdapter.TempTargetsViewHolder
|
||||
import info.nightscout.androidaps.activities.fragments.TreatmentsTempTargetFragment.RecyclerViewAdapter.TempTargetsViewHolder
|
||||
import info.nightscout.androidaps.utils.DateUtil
|
||||
import info.nightscout.androidaps.utils.FabricPrivacy
|
||||
import info.nightscout.androidaps.utils.T
|
||||
|
@ -58,7 +57,6 @@ class TreatmentsTempTargetFragment : DaggerFragment() {
|
|||
@Inject lateinit var aapsLogger: AAPSLogger
|
||||
@Inject lateinit var profileFunction: ProfileFunction
|
||||
@Inject lateinit var resourceHelper: ResourceHelper
|
||||
@Inject lateinit var uploadQueue: UploadQueueInterface
|
||||
@Inject lateinit var fabricPrivacy: FabricPrivacy
|
||||
@Inject lateinit var translator: Translator
|
||||
@Inject lateinit var dateUtil: DateUtil
|
||||
|
@ -99,7 +97,7 @@ class TreatmentsTempTargetFragment : DaggerFragment() {
|
|||
})
|
||||
}
|
||||
}
|
||||
val nsUploadOnly = sp.getBoolean(R.string.key_ns_upload_only, true) || !buildHelper.isEngineeringMode()
|
||||
val nsUploadOnly = !sp.getBoolean(R.string.key_ns_receive_temp_target, false) || !buildHelper.isEngineeringMode()
|
||||
if (nsUploadOnly) binding.refreshFromNightscout.visibility = View.INVISIBLE
|
||||
binding.showInvalidated.setOnCheckedChangeListener { _, _ ->
|
||||
rxBus.send(EventTreatmentUpdateGui())
|
||||
|
@ -151,7 +149,7 @@ class TreatmentsTempTargetFragment : DaggerFragment() {
|
|||
_binding = null
|
||||
}
|
||||
|
||||
private inner class RecyclerViewAdapter internal constructor(private var tempTargetList: List<TemporaryTarget>) : RecyclerView.Adapter<TempTargetsViewHolder>() {
|
||||
private inner class RecyclerViewAdapter(private var tempTargetList: List<TemporaryTarget>) : RecyclerView.Adapter<TempTargetsViewHolder>() {
|
||||
|
||||
private val dbRecord = repository.getTemporaryTargetActiveAt(dateUtil.now()).blockingGet()
|
||||
private val currentlyActiveTarget = if (dbRecord is ValueWrapper.Existing) dbRecord.value else null
|
|
@ -1,4 +1,4 @@
|
|||
package info.nightscout.androidaps.plugins.treatments.fragments
|
||||
package info.nightscout.androidaps.activities.fragments
|
||||
|
||||
import android.content.DialogInterface
|
||||
import android.graphics.Paint
|
||||
|
@ -12,12 +12,15 @@ import dagger.android.support.DaggerFragment
|
|||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.data.IobTotal
|
||||
import info.nightscout.androidaps.database.AppRepository
|
||||
import info.nightscout.androidaps.database.ValueWrapper
|
||||
import info.nightscout.androidaps.database.entities.ExtendedBolus
|
||||
import info.nightscout.androidaps.database.entities.TemporaryBasal
|
||||
import info.nightscout.androidaps.database.entities.UserEntry.*
|
||||
import info.nightscout.androidaps.database.entities.UserEntry.Action
|
||||
import info.nightscout.androidaps.database.entities.UserEntry.Sources
|
||||
import info.nightscout.androidaps.database.entities.ValueWithUnit
|
||||
import info.nightscout.androidaps.database.interfaces.end
|
||||
import info.nightscout.androidaps.database.transactions.InvalidateExtendedBolusTransaction
|
||||
import info.nightscout.androidaps.database.transactions.InvalidateTemporaryBasalTransaction
|
||||
import info.nightscout.androidaps.databinding.TreatmentsTempbasalsFragmentBinding
|
||||
import info.nightscout.androidaps.databinding.TreatmentsTempbasalsItemBinding
|
||||
|
@ -33,7 +36,7 @@ import info.nightscout.androidaps.logging.AAPSLogger
|
|||
import info.nightscout.androidaps.logging.LTag
|
||||
import info.nightscout.androidaps.logging.UserEntryLogger
|
||||
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
||||
import info.nightscout.androidaps.plugins.treatments.fragments.TreatmentsTemporaryBasalsFragment.RecyclerViewAdapter.TempBasalsViewHolder
|
||||
import info.nightscout.androidaps.activities.fragments.TreatmentsTemporaryBasalsFragment.RecyclerViewAdapter.TempBasalsViewHolder
|
||||
import info.nightscout.androidaps.utils.DateUtil
|
||||
import info.nightscout.androidaps.utils.FabricPrivacy
|
||||
import info.nightscout.androidaps.utils.T
|
||||
|
@ -42,6 +45,7 @@ import info.nightscout.androidaps.utils.resources.ResourceHelper
|
|||
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
||||
import io.reactivex.disposables.CompositeDisposable
|
||||
import io.reactivex.rxkotlin.plusAssign
|
||||
import java.util.concurrent.TimeUnit
|
||||
import javax.inject.Inject
|
||||
import kotlin.math.abs
|
||||
|
||||
|
@ -194,21 +198,41 @@ class TreatmentsTemporaryBasalsFragment : DaggerFragment() {
|
|||
init {
|
||||
binding.remove.setOnClickListener { v: View ->
|
||||
val tempBasal = v.tag as TemporaryBasal
|
||||
var extendedBolus: ExtendedBolus? = null
|
||||
val isFakeExtended = tempBasal.type == TemporaryBasal.Type.FAKE_EXTENDED
|
||||
if (isFakeExtended) {
|
||||
val eb = repository.getExtendedBolusActiveAt(tempBasal.timestamp).blockingGet()
|
||||
extendedBolus = if (eb is ValueWrapper.Existing) eb.value else null
|
||||
}
|
||||
val profile = profileFunction.getProfile(dateUtil.now())
|
||||
?: return@setOnClickListener
|
||||
context?.let {
|
||||
OKDialog.showConfirmation(it, resourceHelper.gs(R.string.removerecord),
|
||||
"""
|
||||
${resourceHelper.gs(R.string.tempbasal_label)}: ${tempBasal.toStringFull(profile, dateUtil)}
|
||||
${if (isFakeExtended) resourceHelper.gs(R.string.extended_bolus) else resourceHelper.gs(R.string.tempbasal_label)}: ${tempBasal.toStringFull(profile, dateUtil)}
|
||||
${resourceHelper.gs(R.string.date)}: ${dateUtil.dateAndTimeString(tempBasal.timestamp)}
|
||||
""".trimIndent(),
|
||||
{ _: DialogInterface?, _: Int ->
|
||||
uel.log(Action.TEMP_BASAL_REMOVED, Sources.Treatments,
|
||||
ValueWithUnit.Timestamp(tempBasal.timestamp))
|
||||
disposable += repository.runTransactionForResult(InvalidateTemporaryBasalTransaction(tempBasal.id))
|
||||
.subscribe(
|
||||
{ aapsLogger.debug(LTag.DATABASE, "Removed temporary basal $tempBasal") },
|
||||
{ aapsLogger.error(LTag.DATABASE, "Error while invalidating temporary basal", it) })
|
||||
if (isFakeExtended && extendedBolus != null) {
|
||||
uel.log(Action.EXTENDED_BOLUS_REMOVED, Sources.Treatments,
|
||||
ValueWithUnit.Timestamp(extendedBolus.timestamp),
|
||||
ValueWithUnit.Insulin(extendedBolus.amount),
|
||||
ValueWithUnit.UnitPerHour(extendedBolus.rate),
|
||||
ValueWithUnit.Minute(TimeUnit.MILLISECONDS.toMinutes(extendedBolus.duration).toInt()))
|
||||
disposable += repository.runTransactionForResult(InvalidateExtendedBolusTransaction(extendedBolus.id))
|
||||
.subscribe(
|
||||
{ aapsLogger.debug(LTag.DATABASE, "Removed extended bolus $extendedBolus") },
|
||||
{ aapsLogger.error(LTag.DATABASE, "Error while invalidating extended bolus", it) })
|
||||
} else if (!isFakeExtended) {
|
||||
uel.log(Action.TEMP_BASAL_REMOVED, Sources.Treatments,
|
||||
ValueWithUnit.Timestamp(tempBasal.timestamp),
|
||||
if (tempBasal.isAbsolute) ValueWithUnit.UnitPerHour(tempBasal.rate) else ValueWithUnit.Percent(tempBasal.rate.toInt()),
|
||||
ValueWithUnit.Minute(T.msecs(tempBasal.duration).mins().toInt()))
|
||||
disposable += repository.runTransactionForResult(InvalidateTemporaryBasalTransaction(tempBasal.id))
|
||||
.subscribe(
|
||||
{ aapsLogger.debug(LTag.DATABASE, "Removed temporary basal $tempBasal") },
|
||||
{ aapsLogger.error(LTag.DATABASE, "Error while invalidating temporary basal", it) })
|
||||
}
|
||||
}, null)
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package info.nightscout.androidaps.plugins.treatments.fragments
|
||||
package info.nightscout.androidaps.activities.fragments
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
|
@ -1,7 +1,5 @@
|
|||
package info.nightscout.androidaps.data.defaultProfile
|
||||
|
||||
import dagger.android.HasAndroidInjector
|
||||
import info.nightscout.androidaps.data.ProfileImplOld
|
||||
import info.nightscout.androidaps.data.PureProfile
|
||||
import info.nightscout.androidaps.extensions.pureProfileFromJson
|
||||
import info.nightscout.androidaps.interfaces.GlucoseUnit
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package info.nightscout.androidaps.data.defaultProfile
|
||||
|
||||
import dagger.android.HasAndroidInjector
|
||||
import info.nightscout.androidaps.data.ProfileImplOld
|
||||
import info.nightscout.androidaps.data.PureProfile
|
||||
import info.nightscout.androidaps.extensions.pureProfileFromJson
|
||||
import info.nightscout.androidaps.interfaces.GlucoseUnit
|
||||
|
|
|
@ -75,12 +75,16 @@ class CompatDBHelper @Inject constructor(
|
|||
rxBus.send(EventFoodDatabaseChanged())
|
||||
}
|
||||
it.filterIsInstance<ProfileSwitch>().firstOrNull()?.let {
|
||||
aapsLogger.debug(LTag.DATABASE, "Firing EventProfileNeedsUpdate")
|
||||
aapsLogger.debug(LTag.DATABASE, "Firing EventProfileSwitchChanged")
|
||||
rxBus.send(EventProfileSwitchChanged())
|
||||
}
|
||||
it.filterIsInstance<EffectiveProfileSwitch>().firstOrNull()?.let {
|
||||
aapsLogger.debug(LTag.DATABASE, "Firing EventProfileNeedsUpdate")
|
||||
aapsLogger.debug(LTag.DATABASE, "Firing EventProfileSwitchChanged")
|
||||
rxBus.send(EventProfileSwitchChanged())
|
||||
}
|
||||
it.filterIsInstance<OfflineEvent>().firstOrNull()?.let {
|
||||
aapsLogger.debug(LTag.DATABASE, "Firing EventOfflineChange")
|
||||
rxBus.send(EventOfflineChange())
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,8 +4,6 @@ import android.content.Context;
|
|||
import android.database.DatabaseUtils;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.j256.ormlite.android.apptools.OrmLiteSqliteOpenHelper;
|
||||
import com.j256.ormlite.dao.CloseableIterator;
|
||||
import com.j256.ormlite.dao.Dao;
|
||||
|
@ -20,19 +18,14 @@ import java.sql.SQLException;
|
|||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import info.nightscout.androidaps.events.EventRefreshOverview;
|
||||
import info.nightscout.androidaps.interfaces.ActivePlugin;
|
||||
import info.nightscout.androidaps.interfaces.DatabaseHelperInterface;
|
||||
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.nsclient.NSUpload;
|
||||
import info.nightscout.androidaps.plugins.general.openhumans.OpenHumansUploader;
|
||||
import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpPlugin;
|
||||
import info.nightscout.androidaps.utils.DateUtil;
|
||||
|
@ -51,12 +44,9 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
|
|||
@Inject VirtualPumpPlugin virtualPumpPlugin;
|
||||
@Inject OpenHumansUploader openHumansUploader;
|
||||
@Inject ActivePlugin activePlugin;
|
||||
@Inject NSUpload nsUpload;
|
||||
@Inject DateUtil dateUtil;
|
||||
|
||||
public static final String DATABASE_NAME = "AndroidAPSDb";
|
||||
public static final String DATABASE_DANARHISTORY = "DanaRHistory";
|
||||
public static final String DATABASE_DBREQUESTS = "DBRequests";
|
||||
|
||||
private static final int DATABASE_VERSION = 13;
|
||||
|
||||
|
@ -76,19 +66,8 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
|
|||
public void onCreate(SQLiteDatabase database, ConnectionSource connectionSource) {
|
||||
try {
|
||||
aapsLogger.info(LTag.DATABASE, "onCreate");
|
||||
TableUtils.createTableIfNotExists(connectionSource, DanaRHistoryRecord.class);
|
||||
TableUtils.createTableIfNotExists(connectionSource, DbRequest.class);
|
||||
TableUtils.createTableIfNotExists(connectionSource, TemporaryBasal.class);
|
||||
TableUtils.createTableIfNotExists(connectionSource, ExtendedBolus.class);
|
||||
TableUtils.createTableIfNotExists(connectionSource, InsightHistoryOffset.class);
|
||||
TableUtils.createTableIfNotExists(connectionSource, InsightBolusID.class);
|
||||
TableUtils.createTableIfNotExists(connectionSource, InsightPumpID.class);
|
||||
TableUtils.createTableIfNotExists(connectionSource, OmnipodHistoryRecord.class);
|
||||
TableUtils.createTableIfNotExists(connectionSource, OHQueueItem.class);
|
||||
database.execSQL("INSERT INTO sqlite_sequence (name, seq) SELECT \"" + DatabaseHelperInterface.Companion.DATABASE_INSIGHT_BOLUS_IDS + "\", " + System.currentTimeMillis() + " " +
|
||||
"WHERE NOT EXISTS (SELECT 1 FROM sqlite_sequence WHERE name = \"" + DatabaseHelperInterface.Companion.DATABASE_INSIGHT_BOLUS_IDS + "\")");
|
||||
database.execSQL("INSERT INTO sqlite_sequence (name, seq) SELECT \"" + DatabaseHelperInterface.Companion.DATABASE_INSIGHT_PUMP_IDS + "\", " + System.currentTimeMillis() + " " +
|
||||
"WHERE NOT EXISTS (SELECT 1 FROM sqlite_sequence WHERE name = \"" + DatabaseHelperInterface.Companion.DATABASE_INSIGHT_PUMP_IDS + "\")");
|
||||
} catch (SQLException e) {
|
||||
aapsLogger.error("Can't create database", e);
|
||||
throw new RuntimeException(e);
|
||||
|
@ -103,22 +82,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
|
|||
|
||||
if (oldVersion < 7) {
|
||||
aapsLogger.info(LTag.DATABASE, "onUpgrade");
|
||||
TableUtils.dropTable(connectionSource, DanaRHistoryRecord.class, true);
|
||||
TableUtils.dropTable(connectionSource, DbRequest.class, true);
|
||||
TableUtils.dropTable(connectionSource, TemporaryBasal.class, true);
|
||||
TableUtils.dropTable(connectionSource, ExtendedBolus.class, true);
|
||||
onCreate(database, connectionSource);
|
||||
} else if (oldVersion < 10) {
|
||||
TableUtils.createTableIfNotExists(connectionSource, InsightHistoryOffset.class);
|
||||
TableUtils.createTableIfNotExists(connectionSource, InsightBolusID.class);
|
||||
TableUtils.createTableIfNotExists(connectionSource, InsightPumpID.class);
|
||||
database.execSQL("INSERT INTO sqlite_sequence (name, seq) SELECT \"" + DatabaseHelperInterface.Companion.DATABASE_INSIGHT_BOLUS_IDS + "\", " + System.currentTimeMillis() + " " +
|
||||
"WHERE NOT EXISTS (SELECT 1 FROM sqlite_sequence WHERE name = \"" + DatabaseHelperInterface.Companion.DATABASE_INSIGHT_BOLUS_IDS + "\")");
|
||||
database.execSQL("INSERT INTO sqlite_sequence (name, seq) SELECT \"" + DatabaseHelperInterface.Companion.DATABASE_INSIGHT_PUMP_IDS + "\", " + System.currentTimeMillis() + " " +
|
||||
"WHERE NOT EXISTS (SELECT 1 FROM sqlite_sequence WHERE name = \"" + DatabaseHelperInterface.Companion.DATABASE_INSIGHT_PUMP_IDS + "\")");
|
||||
} else if (oldVersion < 11) {
|
||||
database.execSQL("UPDATE sqlite_sequence SET seq = " + System.currentTimeMillis() + " WHERE name = \"" + DatabaseHelperInterface.Companion.DATABASE_INSIGHT_BOLUS_IDS + "\"");
|
||||
database.execSQL("UPDATE sqlite_sequence SET seq = " + System.currentTimeMillis() + " WHERE name = \"" + DatabaseHelperInterface.Companion.DATABASE_INSIGHT_PUMP_IDS + "\"");
|
||||
}
|
||||
TableUtils.createTableIfNotExists(connectionSource, OHQueueItem.class);
|
||||
} catch (SQLException e) {
|
||||
|
@ -149,15 +113,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
|
|||
|
||||
public void resetDatabases() {
|
||||
try {
|
||||
TableUtils.dropTable(connectionSource, DanaRHistoryRecord.class, true);
|
||||
TableUtils.dropTable(connectionSource, DbRequest.class, true);
|
||||
TableUtils.dropTable(connectionSource, TemporaryBasal.class, true);
|
||||
TableUtils.dropTable(connectionSource, ExtendedBolus.class, true);
|
||||
TableUtils.dropTable(connectionSource, OmnipodHistoryRecord.class, true);
|
||||
TableUtils.createTableIfNotExists(connectionSource, DanaRHistoryRecord.class);
|
||||
TableUtils.createTableIfNotExists(connectionSource, DbRequest.class);
|
||||
TableUtils.createTableIfNotExists(connectionSource, TemporaryBasal.class);
|
||||
TableUtils.createTableIfNotExists(connectionSource, ExtendedBolus.class);
|
||||
TableUtils.createTableIfNotExists(connectionSource, OmnipodHistoryRecord.class);
|
||||
updateEarliestDataChange(0);
|
||||
} catch (SQLException e) {
|
||||
|
@ -177,34 +133,6 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
|
|||
|
||||
// ------------------ getDao -------------------------------------------
|
||||
|
||||
private Dao<DanaRHistoryRecord, String> getDaoDanaRHistory() throws SQLException {
|
||||
return getDao(DanaRHistoryRecord.class);
|
||||
}
|
||||
|
||||
private Dao<DbRequest, String> getDaoDbRequest() throws SQLException {
|
||||
return getDao(DbRequest.class);
|
||||
}
|
||||
|
||||
private Dao<TemporaryBasal, Long> getDaoTemporaryBasal() throws SQLException {
|
||||
return getDao(TemporaryBasal.class);
|
||||
}
|
||||
|
||||
private Dao<ExtendedBolus, Long> getDaoExtendedBolus() throws SQLException {
|
||||
return getDao(ExtendedBolus.class);
|
||||
}
|
||||
|
||||
private Dao<InsightPumpID, Long> getDaoInsightPumpID() throws SQLException {
|
||||
return getDao(InsightPumpID.class);
|
||||
}
|
||||
|
||||
private Dao<InsightBolusID, Long> getDaoInsightBolusID() throws SQLException {
|
||||
return getDao(InsightBolusID.class);
|
||||
}
|
||||
|
||||
private Dao<InsightHistoryOffset, String> getDaoInsightHistoryOffset() throws SQLException {
|
||||
return getDao(InsightHistoryOffset.class);
|
||||
}
|
||||
|
||||
private Dao<OmnipodHistoryRecord, Long> getDaoPodHistory() throws SQLException {
|
||||
return getDao(OmnipodHistoryRecord.class);
|
||||
}
|
||||
|
@ -213,76 +141,6 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
|
|||
return getDao(OHQueueItem.class);
|
||||
}
|
||||
|
||||
public long roundDateToSec(long date) {
|
||||
long rounded = date - date % 1000;
|
||||
if (rounded != date)
|
||||
aapsLogger.debug(LTag.DATABASE, "Rounding " + date + " to " + rounded);
|
||||
return rounded;
|
||||
}
|
||||
|
||||
// ------------- DbRequests handling -------------------
|
||||
|
||||
public void create(DbRequest dbr) throws SQLException {
|
||||
getDaoDbRequest().create(dbr);
|
||||
}
|
||||
|
||||
public int delete(DbRequest dbr) {
|
||||
try {
|
||||
return getDaoDbRequest().delete(dbr);
|
||||
} catch (SQLException e) {
|
||||
aapsLogger.error("Unhandled exception", e);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public int deleteDbRequest(String nsClientId) {
|
||||
try {
|
||||
return getDaoDbRequest().deleteById(nsClientId);
|
||||
} catch (SQLException e) {
|
||||
aapsLogger.error("Unhandled exception", e);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void deleteDbRequestbyMongoId(String action, String id) {
|
||||
try {
|
||||
QueryBuilder<DbRequest, String> queryBuilder = getDaoDbRequest().queryBuilder();
|
||||
// By nsID
|
||||
Where where = queryBuilder.where();
|
||||
where.eq("_id", id).and().eq("action", action);
|
||||
queryBuilder.limit(10L);
|
||||
PreparedQuery<DbRequest> preparedQuery = queryBuilder.prepare();
|
||||
List<DbRequest> dbList = getDaoDbRequest().query(preparedQuery);
|
||||
for (DbRequest r : dbList) delete(r);
|
||||
// By nsClientID
|
||||
where = queryBuilder.where();
|
||||
where.eq("nsClientID", id).and().eq("action", action);
|
||||
queryBuilder.limit(10L);
|
||||
preparedQuery = queryBuilder.prepare();
|
||||
dbList = getDaoDbRequest().query(preparedQuery);
|
||||
for (DbRequest r : dbList) delete(r);
|
||||
} catch (SQLException e) {
|
||||
aapsLogger.error("Unhandled exception", e);
|
||||
}
|
||||
}
|
||||
|
||||
public void deleteAllDbRequests() {
|
||||
try {
|
||||
TableUtils.clearTable(connectionSource, DbRequest.class);
|
||||
} catch (SQLException e) {
|
||||
aapsLogger.error("Unhandled exception", e);
|
||||
}
|
||||
}
|
||||
|
||||
public CloseableIterator getDbRequestIterator() {
|
||||
try {
|
||||
return getDaoDbRequest().closeableIterator();
|
||||
} catch (SQLException e) {
|
||||
aapsLogger.error("Unhandled exception", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static void updateEarliestDataChange(long newDate) {
|
||||
if (earliestDataChange == null) {
|
||||
earliestDataChange = newDate;
|
||||
|
@ -293,495 +151,6 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
|
|||
}
|
||||
}
|
||||
|
||||
// ----------------- DanaRHistory handling --------------------
|
||||
|
||||
public void createOrUpdate(DanaRHistoryRecord record) {
|
||||
try {
|
||||
getDaoDanaRHistory().createOrUpdate(record);
|
||||
} catch (SQLException e) {
|
||||
aapsLogger.error("Unhandled exception", e);
|
||||
}
|
||||
}
|
||||
|
||||
public List<DanaRHistoryRecord> getDanaRHistoryRecordsByType(byte type) {
|
||||
List<DanaRHistoryRecord> historyList;
|
||||
try {
|
||||
QueryBuilder<DanaRHistoryRecord, String> queryBuilder = getDaoDanaRHistory().queryBuilder();
|
||||
queryBuilder.orderBy("recordDate", false);
|
||||
Where where = queryBuilder.where();
|
||||
where.eq("recordCode", type);
|
||||
queryBuilder.limit(200L);
|
||||
PreparedQuery<DanaRHistoryRecord> preparedQuery = queryBuilder.prepare();
|
||||
historyList = getDaoDanaRHistory().query(preparedQuery);
|
||||
} catch (SQLException e) {
|
||||
aapsLogger.error("Unhandled exception", e);
|
||||
historyList = new ArrayList<>();
|
||||
}
|
||||
return historyList;
|
||||
}
|
||||
|
||||
// ------------ TemporaryBasal handling ---------------
|
||||
|
||||
//return true if new record was created
|
||||
public boolean createOrUpdate(TemporaryBasal tempBasal) {
|
||||
try {
|
||||
TemporaryBasal old;
|
||||
tempBasal.date = roundDateToSec(tempBasal.date);
|
||||
|
||||
if (tempBasal.source == Source.PUMP) {
|
||||
// check for changed from pump change in NS
|
||||
QueryBuilder<TemporaryBasal, Long> queryBuilder = getDaoTemporaryBasal().queryBuilder();
|
||||
Where where = queryBuilder.where();
|
||||
where.eq("pumpId", tempBasal.pumpId);
|
||||
PreparedQuery<TemporaryBasal> preparedQuery = queryBuilder.prepare();
|
||||
List<TemporaryBasal> trList = getDaoTemporaryBasal().query(preparedQuery);
|
||||
if (trList.size() > 0) {
|
||||
// do nothing, pump history record cannot be changed
|
||||
aapsLogger.debug(LTag.DATABASE, "TEMPBASAL: Already exists from: " + Source.getString(tempBasal.source) + " " + tempBasal.toString());
|
||||
return false;
|
||||
}
|
||||
|
||||
// search by date (in case its standard record that has become pump record)
|
||||
QueryBuilder<TemporaryBasal, Long> queryBuilder2 = getDaoTemporaryBasal().queryBuilder();
|
||||
Where where2 = queryBuilder2.where();
|
||||
where2.eq("date", tempBasal.date);
|
||||
PreparedQuery<TemporaryBasal> preparedQuery2 = queryBuilder2.prepare();
|
||||
List<TemporaryBasal> trList2 = getDaoTemporaryBasal().query(preparedQuery2);
|
||||
|
||||
if (trList2.size() > 0) {
|
||||
old = trList2.get(0);
|
||||
|
||||
old.copyFromPump(tempBasal);
|
||||
old.source = Source.PUMP;
|
||||
|
||||
aapsLogger.debug(LTag.DATABASE, "TEMPBASAL: Updated record with Pump Data : " + Source.getString(tempBasal.source) + " " + tempBasal.toString());
|
||||
|
||||
getDaoTemporaryBasal().update(old);
|
||||
openHumansUploader.enqueueTemporaryBasal(old);
|
||||
|
||||
updateEarliestDataChange(tempBasal.date);
|
||||
// scheduleTemporaryBasalChange();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
getDaoTemporaryBasal().create(tempBasal);
|
||||
openHumansUploader.enqueueTemporaryBasal(tempBasal);
|
||||
aapsLogger.debug(LTag.DATABASE, "TEMPBASAL: New record from: " + Source.getString(tempBasal.source) + " " + tempBasal.toString());
|
||||
updateEarliestDataChange(tempBasal.date);
|
||||
// scheduleTemporaryBasalChange();
|
||||
return true;
|
||||
}
|
||||
if (tempBasal.source == Source.NIGHTSCOUT) {
|
||||
old = getDaoTemporaryBasal().queryForId(tempBasal.date);
|
||||
if (old != null) {
|
||||
if (!old.isAbsolute && tempBasal.isAbsolute) { // converted to absolute by "ns_sync_use_absolute"
|
||||
// so far ignore, do not convert back because it may not be accurate
|
||||
return false;
|
||||
}
|
||||
if (!old.isEqual(tempBasal)) {
|
||||
long oldDate = old.date;
|
||||
getDaoTemporaryBasal().delete(old); // need to delete/create because date may change too
|
||||
old.copyFrom(tempBasal);
|
||||
getDaoTemporaryBasal().create(old);
|
||||
openHumansUploader.enqueueTemporaryBasal(old);
|
||||
aapsLogger.debug(LTag.DATABASE, "TEMPBASAL: Updating record by date from: " + Source.getString(tempBasal.source) + " " + old.toString());
|
||||
updateEarliestDataChange(oldDate);
|
||||
updateEarliestDataChange(old.date);
|
||||
// scheduleTemporaryBasalChange();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
// find by NS _id
|
||||
if (tempBasal._id != null) {
|
||||
QueryBuilder<TemporaryBasal, Long> queryBuilder = getDaoTemporaryBasal().queryBuilder();
|
||||
Where where = queryBuilder.where();
|
||||
where.eq("_id", tempBasal._id);
|
||||
PreparedQuery<TemporaryBasal> preparedQuery = queryBuilder.prepare();
|
||||
List<TemporaryBasal> trList = getDaoTemporaryBasal().query(preparedQuery);
|
||||
if (trList.size() > 0) {
|
||||
old = trList.get(0);
|
||||
if (!old.isEqual(tempBasal)) {
|
||||
long oldDate = old.date;
|
||||
getDaoTemporaryBasal().delete(old); // need to delete/create because date may change too
|
||||
old.copyFrom(tempBasal);
|
||||
getDaoTemporaryBasal().create(old);
|
||||
openHumansUploader.enqueueTemporaryBasal(old);
|
||||
aapsLogger.debug(LTag.DATABASE, "TEMPBASAL: Updating record by _id from: " + Source.getString(tempBasal.source) + " " + old.toString());
|
||||
updateEarliestDataChange(oldDate);
|
||||
updateEarliestDataChange(old.date);
|
||||
// scheduleTemporaryBasalChange();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
getDaoTemporaryBasal().create(tempBasal);
|
||||
openHumansUploader.enqueueTemporaryBasal(tempBasal);
|
||||
aapsLogger.debug(LTag.DATABASE, "TEMPBASAL: New record from: " + Source.getString(tempBasal.source) + " " + tempBasal.toString());
|
||||
updateEarliestDataChange(tempBasal.date);
|
||||
// scheduleTemporaryBasalChange();
|
||||
return true;
|
||||
}
|
||||
if (tempBasal.source == Source.USER) {
|
||||
getDaoTemporaryBasal().create(tempBasal);
|
||||
openHumansUploader.enqueueTemporaryBasal(tempBasal);
|
||||
aapsLogger.debug(LTag.DATABASE, "TEMPBASAL: New record from: " + Source.getString(tempBasal.source) + " " + tempBasal.toString());
|
||||
updateEarliestDataChange(tempBasal.date);
|
||||
// scheduleTemporaryBasalChange();
|
||||
return true;
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
aapsLogger.error("Unhandled exception", e);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void delete(TemporaryBasal tempBasal) {
|
||||
try {
|
||||
getDaoTemporaryBasal().delete(tempBasal);
|
||||
openHumansUploader.enqueueTemporaryBasal(tempBasal, true);
|
||||
updateEarliestDataChange(tempBasal.date);
|
||||
} catch (SQLException e) {
|
||||
aapsLogger.error("Unhandled exception", e);
|
||||
}
|
||||
// scheduleTemporaryBasalChange();
|
||||
}
|
||||
|
||||
public List<TemporaryBasal> getTemporaryBasalsDataFromTime(long mills, boolean ascending) {
|
||||
try {
|
||||
List<TemporaryBasal> tempbasals;
|
||||
QueryBuilder<TemporaryBasal, Long> queryBuilder = getDaoTemporaryBasal().queryBuilder();
|
||||
queryBuilder.orderBy("date", ascending);
|
||||
Where where = queryBuilder.where();
|
||||
where.ge("date", mills);
|
||||
PreparedQuery<TemporaryBasal> preparedQuery = queryBuilder.prepare();
|
||||
tempbasals = getDaoTemporaryBasal().query(preparedQuery);
|
||||
return tempbasals;
|
||||
} catch (SQLException e) {
|
||||
aapsLogger.error("Unhandled exception", e);
|
||||
}
|
||||
return new ArrayList<TemporaryBasal>();
|
||||
}
|
||||
|
||||
/*
|
||||
{
|
||||
"_id": "59232e1ddd032d04218dab00",
|
||||
"eventType": "Temp Basal",
|
||||
"duration": 60,
|
||||
"percent": -50,
|
||||
"created_at": "2017-05-22T18:29:57Z",
|
||||
"enteredBy": "AndroidAPS",
|
||||
"notes": "Basal Temp Start 50% 60.0 min",
|
||||
"NSCLIENT_ID": 1495477797863,
|
||||
"mills": 1495477797000,
|
||||
"mgdl": 194.5,
|
||||
"endmills": 1495481397000
|
||||
}
|
||||
*/
|
||||
|
||||
public TemporaryBasal findTempBasalByPumpId(Long pumpId) {
|
||||
try {
|
||||
QueryBuilder<TemporaryBasal, Long> queryBuilder = null;
|
||||
queryBuilder = getDaoTemporaryBasal().queryBuilder();
|
||||
queryBuilder.orderBy("date", false);
|
||||
Where where = queryBuilder.where();
|
||||
where.eq("pumpId", pumpId);
|
||||
PreparedQuery<TemporaryBasal> preparedQuery = queryBuilder.prepare();
|
||||
List<TemporaryBasal> list = getDaoTemporaryBasal().query(preparedQuery);
|
||||
|
||||
if (list.size() > 0)
|
||||
return list.get(0);
|
||||
else
|
||||
return null;
|
||||
|
||||
} catch (SQLException e) {
|
||||
aapsLogger.error("Unhandled exception", e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
// ------------ ExtendedBolus handling ---------------
|
||||
|
||||
public ExtendedBolus getExtendedBolusByPumpId(long pumpId) {
|
||||
try {
|
||||
return getDaoExtendedBolus().queryBuilder()
|
||||
.where().eq("pumpId", pumpId)
|
||||
.queryForFirst();
|
||||
} catch (SQLException e) {
|
||||
aapsLogger.error("Unhandled exception", e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void delete(ExtendedBolus extendedBolus) {
|
||||
try {
|
||||
getDaoExtendedBolus().delete(extendedBolus);
|
||||
openHumansUploader.enqueueExtendedBolus(extendedBolus, true);
|
||||
updateEarliestDataChange(extendedBolus.date);
|
||||
} catch (SQLException e) {
|
||||
aapsLogger.error("Unhandled exception", e);
|
||||
}
|
||||
// scheduleExtendedBolusChange();
|
||||
}
|
||||
|
||||
/*
|
||||
{
|
||||
"_id": "5924898d577eb0880e355337",
|
||||
"eventType": "Combo Bolus",
|
||||
"duration": 120,
|
||||
"splitNow": 0,
|
||||
"splitExt": 100,
|
||||
"enteredinsulin": 1,
|
||||
"relative": 1,
|
||||
"created_at": "2017-05-23T19:12:14Z",
|
||||
"enteredBy": "AndroidAPS",
|
||||
"NSCLIENT_ID": 1495566734628,
|
||||
"mills": 1495566734000,
|
||||
"mgdl": 106
|
||||
}
|
||||
*/
|
||||
|
||||
// ---------------- ProfileSwitch handling ---------------
|
||||
|
||||
/*
|
||||
public boolean createOrUpdate(ProfileSwitch profileSwitch) {
|
||||
try {
|
||||
ProfileSwitch old;
|
||||
profileSwitch.date = roundDateToSec(profileSwitch.date);
|
||||
|
||||
if (profileSwitch.source == Source.NIGHTSCOUT) {
|
||||
old = getDaoProfileSwitch().queryForId(profileSwitch.date);
|
||||
if (old != null) {
|
||||
if (!old.isEqual(profileSwitch)) {
|
||||
profileSwitch.source = old.source;
|
||||
profileSwitch.profileName = old.profileName; // preserver profileName to prevent multiple CPP extension
|
||||
getDaoProfileSwitch().delete(old); // need to delete/create because date may change too
|
||||
getDaoProfileSwitch().create(profileSwitch);
|
||||
aapsLogger.debug(LTag.DATABASE, "PROFILESWITCH: Updating record by date from: " + Source.getString(profileSwitch.source) + " " + old.toString());
|
||||
openHumansUploader.enqueueProfileSwitch(profileSwitch);
|
||||
scheduleProfileSwitchChange();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
// find by NS _id
|
||||
if (profileSwitch._id != null) {
|
||||
QueryBuilder<ProfileSwitch, Long> queryBuilder = getDaoProfileSwitch().queryBuilder();
|
||||
Where where = queryBuilder.where();
|
||||
where.eq("_id", profileSwitch._id);
|
||||
PreparedQuery<ProfileSwitch> preparedQuery = queryBuilder.prepare();
|
||||
List<ProfileSwitch> trList = getDaoProfileSwitch().query(preparedQuery);
|
||||
if (trList.size() > 0) {
|
||||
old = trList.get(0);
|
||||
if (!old.isEqual(profileSwitch)) {
|
||||
getDaoProfileSwitch().delete(old); // need to delete/create because date may change too
|
||||
old.copyFrom(profileSwitch);
|
||||
getDaoProfileSwitch().create(old);
|
||||
aapsLogger.debug(LTag.DATABASE, "PROFILESWITCH: Updating record by _id from: " + Source.getString(profileSwitch.source) + " " + old.toString());
|
||||
openHumansUploader.enqueueProfileSwitch(old);
|
||||
scheduleProfileSwitchChange();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
// look for already added percentage from NS
|
||||
profileSwitch.profileName = PercentageSplitter.INSTANCE.pureName(profileSwitch.profileName);
|
||||
getDaoProfileSwitch().create(profileSwitch);
|
||||
aapsLogger.debug(LTag.DATABASE, "PROFILESWITCH: New record from: " + Source.getString(profileSwitch.source) + " " + profileSwitch.toString());
|
||||
openHumansUploader.enqueueProfileSwitch(profileSwitch);
|
||||
scheduleProfileSwitchChange();
|
||||
return true;
|
||||
}
|
||||
if (profileSwitch.source == Source.USER) {
|
||||
getDaoProfileSwitch().create(profileSwitch);
|
||||
aapsLogger.debug(LTag.DATABASE, "PROFILESWITCH: New record from: " + Source.getString(profileSwitch.source) + " " + profileSwitch.toString());
|
||||
openHumansUploader.enqueueProfileSwitch(profileSwitch);
|
||||
scheduleProfileSwitchChange();
|
||||
return true;
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
aapsLogger.error("Unhandled exception", e);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void delete(ProfileSwitch profileSwitch) {
|
||||
try {
|
||||
getDaoProfileSwitch().delete(profileSwitch);
|
||||
openHumansUploader.enqueueProfileSwitch(profileSwitch, true);
|
||||
scheduleProfileSwitchChange();
|
||||
} catch (SQLException e) {
|
||||
aapsLogger.error("Unhandled exception", e);
|
||||
}
|
||||
}
|
||||
|
||||
private void scheduleProfileSwitchChange() {
|
||||
class PostRunnable implements Runnable {
|
||||
public void run() {
|
||||
aapsLogger.debug(LTag.DATABASE, "Firing EventProfileNeedsUpdate");
|
||||
rxBus.send(new EventReloadProfileSwitchData());
|
||||
rxBus.send(new EventProfileNeedsUpdate());
|
||||
scheduledProfileSwitchEventPost = null;
|
||||
}
|
||||
}
|
||||
// prepare task for execution in 1 sec
|
||||
// cancel waiting task to prevent sending multiple posts
|
||||
if (scheduledProfileSwitchEventPost != null)
|
||||
scheduledProfileSwitchEventPost.cancel(false);
|
||||
Runnable task = new PostRunnable();
|
||||
final int sec = 1;
|
||||
scheduledProfileSwitchEventPost = profileSwitchEventWorker.schedule(task, sec, TimeUnit.SECONDS);
|
||||
|
||||
}
|
||||
*/
|
||||
/*
|
||||
{
|
||||
"_id":"592fa43ed97496a80da913d2",
|
||||
"created_at":"2017-06-01T05:20:06Z",
|
||||
"eventType":"Profile Switch",
|
||||
"profile":"2016 +30%",
|
||||
"units":"mmol",
|
||||
"enteredBy":"sony",
|
||||
"NSCLIENT_ID":1496294454309,
|
||||
}
|
||||
*/
|
||||
/*
|
||||
|
||||
public void createProfileSwitchFromJsonIfNotExists(JSONObject trJson) {
|
||||
try {
|
||||
ProfileSwitch profileSwitch = new ProfileSwitch(StaticInjector.Companion.getInstance());
|
||||
profileSwitch.date = trJson.getLong("mills");
|
||||
if (trJson.has("duration"))
|
||||
profileSwitch.durationInMinutes = trJson.getInt("duration");
|
||||
profileSwitch._id = trJson.getString("_id");
|
||||
profileSwitch.profileName = trJson.getString("profile");
|
||||
profileSwitch.isCPP = trJson.has("CircadianPercentageProfile");
|
||||
profileSwitch.source = Source.NIGHTSCOUT;
|
||||
if (trJson.has("timeshift"))
|
||||
profileSwitch.timeshift = trJson.getInt("timeshift");
|
||||
if (trJson.has("percentage"))
|
||||
profileSwitch.percentage = trJson.getInt("percentage");
|
||||
if (trJson.has("profileJson"))
|
||||
profileSwitch.profileJson = trJson.getString("profileJson");
|
||||
else {
|
||||
ProfileSource profileSource = activePlugin.getActiveProfileSource();
|
||||
ProfileStore store = profileSource.getProfile();
|
||||
if (store != null) {
|
||||
PureProfile profile = store.getSpecificProfile(profileSwitch.profileName);
|
||||
if (profile != null) {
|
||||
profileSwitch.profileJson = profile.getJsonObject().toString();
|
||||
aapsLogger.debug(LTag.DATABASE, "Profile switch prefilled with JSON from local store");
|
||||
// Update data in NS
|
||||
nsUpload.updateProfileSwitch(profileSwitch, dateUtil);
|
||||
} else {
|
||||
aapsLogger.debug(LTag.DATABASE, "JSON for profile switch doesn't exist. Ignoring: " + trJson.toString());
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
aapsLogger.debug(LTag.DATABASE, "Store for profile switch doesn't exist. Ignoring: " + trJson.toString());
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (trJson.has("profilePlugin"))
|
||||
profileSwitch.profilePlugin = trJson.getString("profilePlugin");
|
||||
createOrUpdate(profileSwitch);
|
||||
} catch (JSONException e) {
|
||||
aapsLogger.error("Unhandled exception: " + trJson.toString(), e);
|
||||
}
|
||||
}
|
||||
|
||||
public void deleteProfileSwitchById(String _id) {
|
||||
ProfileSwitch stored = findProfileSwitchById(_id);
|
||||
if (stored != null) {
|
||||
aapsLogger.debug(LTag.DATABASE, "PROFILESWITCH: Removing ProfileSwitch record from database: " + stored.toString());
|
||||
delete(stored);
|
||||
scheduleProfileSwitchChange();
|
||||
}
|
||||
}
|
||||
|
||||
public ProfileSwitch findProfileSwitchById(String _id) {
|
||||
try {
|
||||
QueryBuilder<ProfileSwitch, Long> queryBuilder = getDaoProfileSwitch().queryBuilder();
|
||||
Where where = queryBuilder.where();
|
||||
where.eq("_id", _id);
|
||||
PreparedQuery<ProfileSwitch> preparedQuery = queryBuilder.prepare();
|
||||
List<ProfileSwitch> list = getDaoProfileSwitch().query(preparedQuery);
|
||||
|
||||
if (list.size() == 1) {
|
||||
return list.get(0);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
aapsLogger.error("Unhandled exception", e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
*/
|
||||
// ---------------- Insight history handling ---------------
|
||||
|
||||
public void createOrUpdate(InsightHistoryOffset offset) {
|
||||
try {
|
||||
getDaoInsightHistoryOffset().createOrUpdate(offset);
|
||||
} catch (SQLException e) {
|
||||
aapsLogger.error("Unhandled exception", e);
|
||||
}
|
||||
}
|
||||
|
||||
public InsightHistoryOffset getInsightHistoryOffset(String pumpSerial) {
|
||||
try {
|
||||
return getDaoInsightHistoryOffset().queryForId(pumpSerial);
|
||||
} catch (SQLException e) {
|
||||
aapsLogger.error("Unhandled exception", e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void createOrUpdate(InsightBolusID bolusID) {
|
||||
try {
|
||||
getDaoInsightBolusID().createOrUpdate(bolusID);
|
||||
} catch (SQLException e) {
|
||||
aapsLogger.error("Unhandled exception", e);
|
||||
}
|
||||
}
|
||||
|
||||
public InsightBolusID getInsightBolusID(String pumpSerial, int bolusID, long timestamp) {
|
||||
try {
|
||||
return getDaoInsightBolusID().queryBuilder()
|
||||
.where().eq("pumpSerial", pumpSerial)
|
||||
.and().eq("bolusID", bolusID)
|
||||
.and().between("timestamp", timestamp - 259200000, timestamp + 259200000)
|
||||
.queryForFirst();
|
||||
} catch (SQLException e) {
|
||||
aapsLogger.error("Unhandled exception", e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void createOrUpdate(InsightPumpID pumpID) {
|
||||
try {
|
||||
getDaoInsightPumpID().createOrUpdate(pumpID);
|
||||
} catch (SQLException e) {
|
||||
aapsLogger.error("Unhandled exception", e);
|
||||
}
|
||||
}
|
||||
|
||||
public InsightPumpID getPumpStoppedEvent(String pumpSerial, long before) {
|
||||
try {
|
||||
return getDaoInsightPumpID().queryBuilder()
|
||||
.orderBy("timestamp", false)
|
||||
.where().eq("pumpSerial", pumpSerial)
|
||||
.and().in("eventType", "PumpStopped", "PumpPaused")
|
||||
.and().lt("timestamp", before)
|
||||
.queryForFirst();
|
||||
} catch (SQLException e) {
|
||||
aapsLogger.error("Unhandled exception", e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// ---------------- Food handling ---------------
|
||||
|
||||
// ---------------- PodHistory handling ---------------
|
||||
|
@ -924,14 +293,4 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
|
|||
}
|
||||
return 0L;
|
||||
}
|
||||
|
||||
public long getCountOfAllRows() {
|
||||
try {
|
||||
return getDaoExtendedBolus().countOf()
|
||||
+ getDaoTemporaryBasal().countOf();
|
||||
} catch (SQLException e) {
|
||||
aapsLogger.error("Unhandled exception", e);
|
||||
}
|
||||
return 0L;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,8 +5,6 @@ import androidx.annotation.Nullable;
|
|||
|
||||
import com.j256.ormlite.dao.CloseableIterator;
|
||||
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
|
||||
|
@ -23,61 +21,24 @@ public class DatabaseHelperProvider implements DatabaseHelperInterface {
|
|||
@Inject DatabaseHelperProvider() {
|
||||
}
|
||||
|
||||
@Override public void createOrUpdate(@NonNull DanaRHistoryRecord record) {
|
||||
MainApp.Companion.getDbHelper().createOrUpdate(record);
|
||||
}
|
||||
|
||||
@Override public void createOrUpdate(@NonNull OmnipodHistoryRecord record) {
|
||||
MainApp.Companion.getDbHelper().createOrUpdate(record);
|
||||
}
|
||||
|
||||
@NonNull @Override public List<DanaRHistoryRecord> getDanaRHistoryRecordsByType(byte type) {
|
||||
return MainApp.Companion.getDbHelper().getDanaRHistoryRecordsByType(type);
|
||||
}
|
||||
|
||||
@Override public long size(@NonNull String table) {
|
||||
return MainApp.Companion.getDbHelper().size(table);
|
||||
}
|
||||
|
||||
@Override public void create(@NonNull DbRequest record) {
|
||||
try {
|
||||
MainApp.Companion.getDbHelper().create(record);
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override public void deleteAllDbRequests() {
|
||||
MainApp.Companion.getDbHelper().deleteAllDbRequests();
|
||||
}
|
||||
|
||||
@Override public int deleteDbRequest(@NonNull String id) {
|
||||
return MainApp.Companion.getDbHelper().deleteDbRequest(id);
|
||||
}
|
||||
|
||||
@Override public void deleteDbRequestbyMongoId(@NonNull String action, @NonNull String _id) {
|
||||
MainApp.Companion.getDbHelper().deleteDbRequestbyMongoId(action, _id);
|
||||
}
|
||||
|
||||
@NonNull @Override public CloseableIterator<DbRequest> getDbRequestIterator() {
|
||||
return MainApp.Companion.getDbHelper().getDbRequestIterator();
|
||||
}
|
||||
|
||||
@Override public long roundDateToSec(long date) {
|
||||
return MainApp.Companion.getDbHelper().roundDateToSec(date);
|
||||
}
|
||||
|
||||
@Override public boolean createOrUpdate(@NonNull TemporaryBasal tempBasal) {
|
||||
return MainApp.Companion.getDbHelper().createOrUpdate(tempBasal);
|
||||
// return MainApp.Companion.getDbHelper().createOrUpdate(tempBasal);
|
||||
return false;
|
||||
}
|
||||
|
||||
@Nullable @Override public TemporaryBasal findTempBasalByPumpId(long id) {
|
||||
return MainApp.Companion.getDbHelper().findTempBasalByPumpId(id);
|
||||
// return MainApp.Companion.getDbHelper().findTempBasalByPumpId(id);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
@NonNull @Override public List<TemporaryBasal> getTemporaryBasalsDataFromTime(long mills, boolean ascending) {
|
||||
return MainApp.Companion.getDbHelper().getTemporaryBasalsDataFromTime(mills, ascending);
|
||||
// return MainApp.Companion.getDbHelper().getTemporaryBasalsDataFromTime(mills, ascending);
|
||||
return null;
|
||||
}
|
||||
|
||||
@NonNull @Override public List<OmnipodHistoryRecord> getAllOmnipodHistoryRecordsFromTimestamp(long timestamp, boolean ascending) {
|
||||
|
@ -88,36 +49,13 @@ public class DatabaseHelperProvider implements DatabaseHelperInterface {
|
|||
return MainApp.Companion.getDbHelper().findOmnipodHistoryRecordByPumpId(pumpId);
|
||||
}
|
||||
|
||||
@Override public void createOrUpdate(@NonNull InsightBolusID record) {
|
||||
MainApp.Companion.getDbHelper().createOrUpdate(record);
|
||||
}
|
||||
|
||||
@Override public void createOrUpdate(@NonNull InsightPumpID record) {
|
||||
MainApp.Companion.getDbHelper().createOrUpdate(record);
|
||||
}
|
||||
|
||||
@Override public void createOrUpdate(@NonNull InsightHistoryOffset record) {
|
||||
MainApp.Companion.getDbHelper().createOrUpdate(record);
|
||||
}
|
||||
|
||||
@Override public void delete(@NonNull ExtendedBolus extendedBolus) {
|
||||
MainApp.Companion.getDbHelper().delete(extendedBolus);
|
||||
// MainApp.Companion.getDbHelper().delete(extendedBolus);
|
||||
}
|
||||
|
||||
@Nullable @Override public ExtendedBolus getExtendedBolusByPumpId(long pumpId) {
|
||||
return MainApp.Companion.getDbHelper().getExtendedBolusByPumpId(pumpId);
|
||||
}
|
||||
|
||||
@Nullable @Override public InsightBolusID getInsightBolusID(@NonNull String pumpSerial, int bolusID, long timestamp) {
|
||||
return MainApp.Companion.getDbHelper().getInsightBolusID(pumpSerial, bolusID, timestamp);
|
||||
}
|
||||
|
||||
@Nullable @Override public InsightHistoryOffset getInsightHistoryOffset(@NonNull String pumpSerial) {
|
||||
return MainApp.Companion.getDbHelper().getInsightHistoryOffset(pumpSerial);
|
||||
}
|
||||
|
||||
@Nullable @Override public InsightPumpID getPumpStoppedEvent(@NonNull String pumpSerial, long before) {
|
||||
return MainApp.Companion.getDbHelper().getPumpStoppedEvent(pumpSerial, before);
|
||||
// return MainApp.Companion.getDbHelper().getExtendedBolusByPumpId(pumpId);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override public void resetDatabases() {
|
||||
|
@ -140,10 +78,6 @@ public class DatabaseHelperProvider implements DatabaseHelperInterface {
|
|||
MainApp.Companion.getDbHelper().clearOpenHumansQueue();
|
||||
}
|
||||
|
||||
@Override public long getCountOfAllRows() {
|
||||
return MainApp.Companion.getDbHelper().getCountOfAllRows();
|
||||
}
|
||||
|
||||
@Override public void removeAllOHQueueItemsWithIdSmallerThan(long id) {
|
||||
MainApp.Companion.getDbHelper().removeAllOHQueueItemsWithIdSmallerThan(id);
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ import dagger.Module
|
|||
import dagger.android.ContributesAndroidInjector
|
||||
import info.nightscout.androidaps.MainActivity
|
||||
import info.nightscout.androidaps.activities.*
|
||||
import info.nightscout.androidaps.historyBrowser.HistoryBrowseActivity
|
||||
import info.nightscout.androidaps.activities.HistoryBrowseActivity
|
||||
import info.nightscout.androidaps.plugins.general.maintenance.activities.LogSettingActivity
|
||||
import info.nightscout.androidaps.plugins.general.openhumans.OpenHumansLoginActivity
|
||||
import info.nightscout.androidaps.plugins.general.overview.activities.QuickWizardListActivity
|
||||
|
@ -15,6 +15,7 @@ import info.nightscout.androidaps.setupwizard.SetupWizardActivity
|
|||
@Suppress("unused")
|
||||
abstract class ActivitiesModule {
|
||||
|
||||
@ContributesAndroidInjector abstract fun contributesTreatmentsActivity(): TreatmentsActivity
|
||||
@ContributesAndroidInjector abstract fun contributesHistoryBrowseActivity(): HistoryBrowseActivity
|
||||
@ContributesAndroidInjector abstract fun contributesLogSettingActivity(): LogSettingActivity
|
||||
@ContributesAndroidInjector abstract fun contributeMainActivity(): MainActivity
|
||||
|
|
|
@ -7,12 +7,15 @@ import dagger.android.AndroidInjector
|
|||
import info.nightscout.androidaps.MainApp
|
||||
import info.nightscout.androidaps.automation.di.AutomationModule
|
||||
import info.nightscout.androidaps.combo.di.ComboModule
|
||||
import info.nightscout.androidaps.di.CoreModule
|
||||
import info.nightscout.androidaps.dana.di.DanaHistoryModule
|
||||
import info.nightscout.androidaps.dana.di.DanaModule
|
||||
import info.nightscout.androidaps.danar.di.DanaRModule
|
||||
import info.nightscout.androidaps.danars.di.DanaRSModule
|
||||
import info.nightscout.androidaps.danars.di.InsightModule
|
||||
import info.nightscout.androidaps.database.DatabaseModule
|
||||
import info.nightscout.androidaps.di.CoreModule
|
||||
import info.nightscout.androidaps.insight.di.InsightDatabaseModule
|
||||
import info.nightscout.androidaps.insight.di.InsightModule
|
||||
import info.nightscout.androidaps.plugins.pump.common.di.PumpCommonModule
|
||||
import info.nightscout.androidaps.plugins.pump.common.di.RileyLinkModule
|
||||
import info.nightscout.androidaps.plugins.pump.medtronic.di.MedtronicModule
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.dagger.OmnipodDashModule
|
||||
|
@ -35,6 +38,7 @@ import javax.inject.Singleton
|
|||
CommandQueueModule::class,
|
||||
ObjectivesModule::class,
|
||||
WizardModule::class,
|
||||
PumpCommonModule::class,
|
||||
RileyLinkModule::class,
|
||||
MedtronicModule::class,
|
||||
OmnipodDashModule::class,
|
||||
|
@ -47,10 +51,12 @@ import javax.inject.Singleton
|
|||
UIModule::class,
|
||||
CoreModule::class,
|
||||
DanaModule::class,
|
||||
DanaHistoryModule::class,
|
||||
DanaRModule::class,
|
||||
DanaRSModule::class,
|
||||
ComboModule::class,
|
||||
InsightModule::class,
|
||||
InsightDatabaseModule::class,
|
||||
WorkersModule::class,
|
||||
OHUploaderModule::class
|
||||
]
|
||||
|
|
|
@ -6,32 +6,34 @@ import dagger.Lazy
|
|||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.android.HasAndroidInjector
|
||||
import info.nightscout.androidaps.interfaces.Config
|
||||
import info.nightscout.androidaps.MainApp
|
||||
import info.nightscout.androidaps.database.AppRepository
|
||||
import info.nightscout.androidaps.db.DatabaseHelperProvider
|
||||
import info.nightscout.androidaps.interfaces.*
|
||||
import info.nightscout.androidaps.logging.AAPSLogger
|
||||
import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin
|
||||
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
||||
import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin
|
||||
import info.nightscout.androidaps.plugins.configBuilder.PluginStore
|
||||
import info.nightscout.androidaps.plugins.configBuilder.ProfileFunctionImplementation
|
||||
import info.nightscout.androidaps.plugins.general.maintenance.ImportExportPrefsImpl
|
||||
import info.nightscout.androidaps.plugins.general.nsclient.DataSyncSelectorImplementation
|
||||
import info.nightscout.androidaps.plugins.general.nsclient.UploadQueue
|
||||
import info.nightscout.androidaps.plugins.general.smsCommunicator.SmsCommunicatorPlugin
|
||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin
|
||||
import info.nightscout.androidaps.plugins.pump.PumpSyncImplementation
|
||||
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin
|
||||
import info.nightscout.androidaps.queue.CommandQueue
|
||||
import info.nightscout.androidaps.utils.DateUtil
|
||||
import info.nightscout.androidaps.utils.androidNotification.NotificationHolderImpl
|
||||
import info.nightscout.androidaps.utils.buildHelper.ConfigImpl
|
||||
import info.nightscout.androidaps.utils.resources.IconsProviderImplementation
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
||||
import info.nightscout.androidaps.utils.rx.DefaultAapsSchedulers
|
||||
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
||||
import info.nightscout.androidaps.utils.storage.FileStorage
|
||||
import info.nightscout.androidaps.utils.storage.Storage
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Suppress("unused")
|
||||
@Module(includes = [
|
||||
AppModule.AppBindings::class
|
||||
|
@ -64,32 +66,32 @@ open class AppModule {
|
|||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun providesUploadQueue(
|
||||
aapsLogger: AAPSLogger,
|
||||
databaseHelper: DatabaseHelperInterface,
|
||||
context: Context,
|
||||
sp: SP,
|
||||
rxBus: RxBusWrapper
|
||||
): UploadQueueAdminInterface = UploadQueue(aapsLogger, databaseHelper, context, sp, rxBus)
|
||||
fun provideProfileFunction(aapsLogger: AAPSLogger, sp: SP, resourceHelper: ResourceHelper, activePlugin: ActivePlugin, repository: AppRepository, dateUtil: DateUtil): ProfileFunction {
|
||||
return ProfileFunctionImplementation(aapsLogger, sp, resourceHelper, activePlugin, repository, dateUtil)
|
||||
}
|
||||
|
||||
@Module
|
||||
interface AppBindings {
|
||||
|
||||
@Binds fun bindContext(mainApp: MainApp): Context
|
||||
@Binds fun bindInjector(mainApp: MainApp): HasAndroidInjector
|
||||
@Binds fun bindActivePluginProvider(pluginStore: PluginStore): ActivePlugin
|
||||
@Binds fun bindCommandQueueProvider(commandQueue: CommandQueue): CommandQueueProvider
|
||||
@Binds fun bindConfigInterface(config: ConfigImpl): Config
|
||||
@Binds fun bindConfigBuilderInterface(configBuilderPlugin: ConfigBuilderPlugin): ConfigBuilder
|
||||
|
||||
@Binds
|
||||
fun bindConfigBuilderInterface(configBuilderPlugin: ConfigBuilderPlugin): ConfigBuilder
|
||||
@Binds fun bindTreatmentsInterface(treatmentsPlugin: TreatmentsPlugin): TreatmentsInterface
|
||||
|
||||
@Binds fun bindDatabaseHelperInterface(databaseHelperProvider: DatabaseHelperProvider): DatabaseHelperInterface
|
||||
@Binds fun bindNotificationHolderInterface(notificationHolder: NotificationHolderImpl): NotificationHolder
|
||||
@Binds fun bindImportExportPrefsInterface(importExportPrefs: ImportExportPrefsImpl): ImportExportPrefs
|
||||
@Binds fun bindIconsProviderInterface(iconsProvider: IconsProviderImplementation): IconsProvider
|
||||
@Binds fun bindLoopInterface(loopPlugin: LoopPlugin): LoopInterface
|
||||
@Binds fun bindLoopInterface(loopPlugin: LoopPlugin): Loop
|
||||
@Binds fun bindIobCobCalculatorInterface(iobCobCalculatorPlugin: IobCobCalculatorPlugin): IobCobCalculator
|
||||
@Binds fun bindSmsCommunicatorInterface(smsCommunicatorPlugin: SmsCommunicatorPlugin): SmsCommunicator
|
||||
@Binds fun bindUploadQueueAdminInterfaceToUploadQueue(uploadQueueAdminInterface: UploadQueueAdminInterface) : UploadQueueInterface
|
||||
@Binds fun bindDataSyncSelector(dataSyncSelectorImplementation: DataSyncSelectorImplementation): DataSyncSelector
|
||||
|
||||
@Binds fun bindPumpSync(pumpSyncImplementation: PumpSyncImplementation): PumpSync
|
||||
|
||||
}
|
||||
|
|
|
@ -29,11 +29,9 @@ import info.nightscout.androidaps.plugins.general.tidepool.TidepoolFragment
|
|||
import info.nightscout.androidaps.plugins.general.wear.WearFragment
|
||||
import info.nightscout.androidaps.plugins.insulin.InsulinFragment
|
||||
import info.nightscout.androidaps.plugins.profile.local.LocalProfileFragment
|
||||
import info.nightscout.androidaps.plugins.profile.ns.NSProfileFragment
|
||||
import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpFragment
|
||||
import info.nightscout.androidaps.plugins.source.BGSourceFragment
|
||||
import info.nightscout.androidaps.plugins.treatments.TreatmentsFragment
|
||||
import info.nightscout.androidaps.plugins.treatments.fragments.*
|
||||
import info.nightscout.androidaps.activities.fragments.*
|
||||
import info.nightscout.androidaps.utils.protection.PasswordCheck
|
||||
|
||||
@Module
|
||||
|
@ -46,8 +44,7 @@ abstract class FragmentsModule {
|
|||
@ContributesAndroidInjector abstract fun contributesAutomationFragment(): AutomationFragment
|
||||
@ContributesAndroidInjector abstract fun contributesBGSourceFragment(): BGSourceFragment
|
||||
|
||||
@ContributesAndroidInjector
|
||||
abstract fun contributesConfigBuilderFragment(): ConfigBuilderFragment
|
||||
@ContributesAndroidInjector abstract fun contributesConfigBuilderFragment(): ConfigBuilderFragment
|
||||
|
||||
@ContributesAndroidInjector abstract fun contributesFoodFragment(): FoodFragment
|
||||
@ContributesAndroidInjector abstract fun contributesInsulinFragment(): InsulinFragment
|
||||
|
@ -58,14 +55,11 @@ abstract class FragmentsModule {
|
|||
@ContributesAndroidInjector abstract fun contributesOverviewFragment(): OverviewFragment
|
||||
@ContributesAndroidInjector abstract fun contributesLoopFragment(): LoopFragment
|
||||
@ContributesAndroidInjector abstract fun contributesMaintenanceFragment(): MaintenanceFragment
|
||||
@ContributesAndroidInjector abstract fun contributesNSProfileFragment(): NSProfileFragment
|
||||
@ContributesAndroidInjector abstract fun contributesNSClientFragment(): NSClientFragment
|
||||
@ContributesAndroidInjector
|
||||
abstract fun contributesSmsCommunicatorFragment(): SmsCommunicatorFragment
|
||||
@ContributesAndroidInjector abstract fun contributesSmsCommunicatorFragment(): SmsCommunicatorFragment
|
||||
@ContributesAndroidInjector abstract fun contributesWearFragment(): WearFragment
|
||||
|
||||
@ContributesAndroidInjector abstract fun contributesTidepoolFragment(): TidepoolFragment
|
||||
@ContributesAndroidInjector abstract fun contributesTreatmentsFragment(): TreatmentsFragment
|
||||
@ContributesAndroidInjector abstract fun contributesTreatmentsBolusFragment(): TreatmentsBolusCarbsFragment
|
||||
@ContributesAndroidInjector abstract fun contributesTreatmentsTemporaryBasalsFragment(): TreatmentsTemporaryBasalsFragment
|
||||
@ContributesAndroidInjector abstract fun contributesTreatmentsTempTargetFragment(): TreatmentsTempTargetFragment
|
||||
|
@ -85,8 +79,7 @@ abstract class FragmentsModule {
|
|||
@ContributesAndroidInjector abstract fun contributesEditEventDialog(): EditEventDialog
|
||||
@ContributesAndroidInjector abstract fun contributesEditTriggerDialog(): EditTriggerDialog
|
||||
|
||||
@ContributesAndroidInjector
|
||||
abstract fun contributesEditQuickWizardDialog(): EditQuickWizardDialog
|
||||
@ContributesAndroidInjector abstract fun contributesEditQuickWizardDialog(): EditQuickWizardDialog
|
||||
|
||||
@ContributesAndroidInjector abstract fun contributesExtendedBolusDialog(): ExtendedBolusDialog
|
||||
@ContributesAndroidInjector abstract fun contributesFillDialog(): FillDialog
|
||||
|
@ -102,8 +95,7 @@ abstract class FragmentsModule {
|
|||
@ContributesAndroidInjector abstract fun contributesWizardDialog(): WizardDialog
|
||||
@ContributesAndroidInjector abstract fun contributesWizardInfoDialog(): WizardInfoDialog
|
||||
|
||||
@ContributesAndroidInjector
|
||||
abstract fun contributesExchangeAuthTokenDialot(): OpenHumansLoginActivity.ExchangeAuthTokenDialog
|
||||
@ContributesAndroidInjector abstract fun contributesExchangeAuthTokenDialog(): OpenHumansLoginActivity.ExchangeAuthTokenDialog
|
||||
|
||||
@ContributesAndroidInjector abstract fun contributesPasswordCheck(): PasswordCheck
|
||||
}
|
|
@ -37,7 +37,6 @@ import info.nightscout.androidaps.plugins.insulin.InsulinOrefRapidActingPlugin
|
|||
import info.nightscout.androidaps.plugins.insulin.InsulinOrefUltraRapidActingPlugin
|
||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin
|
||||
import info.nightscout.androidaps.plugins.profile.local.LocalProfilePlugin
|
||||
import info.nightscout.androidaps.plugins.profile.ns.NSProfilePlugin
|
||||
import info.nightscout.androidaps.plugins.pump.combo.ComboPlugin
|
||||
import info.nightscout.androidaps.plugins.pump.insight.LocalInsightPlugin
|
||||
import info.nightscout.androidaps.plugins.pump.mdi.MDIPlugin
|
||||
|
@ -151,11 +150,11 @@ abstract class PluginsModule {
|
|||
@IntKey(140)
|
||||
abstract fun bindComboPlugin(plugin: ComboPlugin): PluginBase
|
||||
|
||||
@Binds
|
||||
@PumpDriver
|
||||
@IntoMap
|
||||
@IntKey(150)
|
||||
abstract fun bindMedtronicPumpPlugin(plugin: MedtronicPumpPlugin): PluginBase
|
||||
// @Binds
|
||||
// @PumpDriver
|
||||
// @IntoMap
|
||||
// @IntKey(150)
|
||||
// abstract fun bindMedtronicPumpPlugin(plugin: MedtronicPumpPlugin): PluginBase
|
||||
|
||||
@Binds
|
||||
@PumpDriver
|
||||
|
@ -202,12 +201,6 @@ abstract class PluginsModule {
|
|||
@Binds
|
||||
@AllConfigs
|
||||
@IntoMap
|
||||
@IntKey(230)
|
||||
abstract fun bindNSProfilePlugin(plugin: NSProfilePlugin): PluginBase
|
||||
|
||||
@Binds
|
||||
@NotNSClient
|
||||
@IntoMap
|
||||
@IntKey(240)
|
||||
abstract fun bindLocalProfilePlugin(plugin: LocalProfilePlugin): PluginBase
|
||||
|
||||
|
@ -355,11 +348,11 @@ abstract class PluginsModule {
|
|||
@IntKey(470)
|
||||
abstract fun bindRandomBgPlugin(plugin: RandomBgPlugin): PluginBase
|
||||
|
||||
@Binds
|
||||
@NotNSClient
|
||||
@IntoMap
|
||||
@IntKey(480)
|
||||
abstract fun bindOpenHumansPlugin(plugin: OpenHumansUploader): PluginBase
|
||||
// @Binds
|
||||
// @NotNSClient
|
||||
// @IntoMap
|
||||
// @IntKey(480)
|
||||
// abstract fun bindOpenHumansPlugin(plugin: OpenHumansUploader): PluginBase
|
||||
|
||||
@Binds
|
||||
@AllConfigs
|
||||
|
@ -379,4 +372,4 @@ abstract class PluginsModule {
|
|||
@Qualifier
|
||||
annotation class APS
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ import info.nightscout.androidaps.plugins.general.nsclient.NSClientMbgWorker
|
|||
import info.nightscout.androidaps.plugins.general.nsclient.NSClientRemoveWorker
|
||||
import info.nightscout.androidaps.plugins.general.nsclient.NSClientUpdateRemoveAckWorker
|
||||
import info.nightscout.androidaps.plugins.general.smsCommunicator.SmsCommunicatorPlugin
|
||||
import info.nightscout.androidaps.plugins.profile.ns.NSProfilePlugin
|
||||
import info.nightscout.androidaps.plugins.profile.local.LocalProfilePlugin
|
||||
import info.nightscout.androidaps.plugins.source.*
|
||||
|
||||
@Module
|
||||
|
@ -24,7 +24,7 @@ abstract class WorkersModule {
|
|||
@ContributesAndroidInjector abstract fun contributesTomatoWorker(): TomatoPlugin.TomatoWorker
|
||||
@ContributesAndroidInjector abstract fun contributesEversenseWorker(): EversensePlugin.EversenseWorker
|
||||
@ContributesAndroidInjector abstract fun contributesNSClientSourceWorker(): NSClientSourcePlugin.NSClientSourceWorker
|
||||
@ContributesAndroidInjector abstract fun contributesNSProfileWorker(): NSProfilePlugin.NSProfileWorker
|
||||
@ContributesAndroidInjector abstract fun contributesNSProfileWorker(): LocalProfilePlugin.NSProfileWorker
|
||||
@ContributesAndroidInjector abstract fun contributesSmsCommunicatorWorker(): SmsCommunicatorPlugin.SmsCommunicatorWorker
|
||||
@ContributesAndroidInjector abstract fun contributesNSClientWorker(): NSClientAddUpdateWorker
|
||||
@ContributesAndroidInjector abstract fun contributesNSClientAddAckWorker(): NSClientAddAckWorker
|
||||
|
|
|
@ -17,7 +17,7 @@ import info.nightscout.androidaps.database.entities.TemporaryTarget
|
|||
import info.nightscout.androidaps.database.entities.UserEntry.Action
|
||||
import info.nightscout.androidaps.database.entities.UserEntry.Sources
|
||||
import info.nightscout.androidaps.database.entities.ValueWithUnit
|
||||
import info.nightscout.androidaps.database.transactions.InsertTemporaryTargetAndCancelCurrentTransaction
|
||||
import info.nightscout.androidaps.database.transactions.InsertAndCancelCurrentTemporaryTargetTransaction
|
||||
import info.nightscout.androidaps.databinding.DialogCarbsBinding
|
||||
import info.nightscout.androidaps.extensions.formatColor
|
||||
import info.nightscout.androidaps.interfaces.Constraint
|
||||
|
@ -27,7 +27,6 @@ import info.nightscout.androidaps.interfaces.ProfileFunction
|
|||
import info.nightscout.androidaps.logging.LTag
|
||||
import info.nightscout.androidaps.logging.UserEntryLogger
|
||||
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
|
||||
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin
|
||||
import info.nightscout.androidaps.queue.Callback
|
||||
import info.nightscout.androidaps.queue.CommandQueue
|
||||
import info.nightscout.androidaps.utils.*
|
||||
|
@ -47,7 +46,6 @@ class CarbsDialog : DialogFragmentWithDate() {
|
|||
@Inject lateinit var resourceHelper: ResourceHelper
|
||||
@Inject lateinit var constraintChecker: ConstraintChecker
|
||||
@Inject lateinit var defaultValueHelper: DefaultValueHelper
|
||||
@Inject lateinit var treatmentsPlugin: TreatmentsPlugin
|
||||
@Inject lateinit var profileFunction: ProfileFunction
|
||||
@Inject lateinit var iobCobCalculator: IobCobCalculator
|
||||
@Inject lateinit var uel: UserEntryLogger
|
||||
|
@ -228,7 +226,7 @@ class CarbsDialog : DialogFragmentWithDate() {
|
|||
ValueWithUnit.TherapyEventTTReason(TemporaryTarget.Reason.ACTIVITY),
|
||||
ValueWithUnit.fromGlucoseUnit(activityTT, units.asText),
|
||||
ValueWithUnit.Minute(activityTTDuration))
|
||||
disposable += repository.runTransactionForResult(InsertTemporaryTargetAndCancelCurrentTransaction(
|
||||
disposable += repository.runTransactionForResult(InsertAndCancelCurrentTemporaryTargetTransaction(
|
||||
timestamp = System.currentTimeMillis(),
|
||||
duration = TimeUnit.MINUTES.toMillis(activityTTDuration.toLong()),
|
||||
reason = TemporaryTarget.Reason.ACTIVITY,
|
||||
|
@ -247,7 +245,7 @@ class CarbsDialog : DialogFragmentWithDate() {
|
|||
ValueWithUnit.TherapyEventTTReason(TemporaryTarget.Reason.EATING_SOON),
|
||||
ValueWithUnit.fromGlucoseUnit(eatingSoonTT, units.asText),
|
||||
ValueWithUnit.Minute(eatingSoonTTDuration))
|
||||
disposable += repository.runTransactionForResult(InsertTemporaryTargetAndCancelCurrentTransaction(
|
||||
disposable += repository.runTransactionForResult(InsertAndCancelCurrentTemporaryTargetTransaction(
|
||||
timestamp = System.currentTimeMillis(),
|
||||
duration = TimeUnit.MINUTES.toMillis(eatingSoonTTDuration.toLong()),
|
||||
reason = TemporaryTarget.Reason.EATING_SOON,
|
||||
|
@ -266,7 +264,7 @@ class CarbsDialog : DialogFragmentWithDate() {
|
|||
ValueWithUnit.TherapyEventTTReason(TemporaryTarget.Reason.HYPOGLYCEMIA),
|
||||
ValueWithUnit.fromGlucoseUnit(hypoTT, units.asText),
|
||||
ValueWithUnit.Minute(hypoTTDuration))
|
||||
disposable += repository.runTransactionForResult(InsertTemporaryTargetAndCancelCurrentTransaction(
|
||||
disposable += repository.runTransactionForResult(InsertAndCancelCurrentTemporaryTargetTransaction(
|
||||
timestamp = System.currentTimeMillis(),
|
||||
duration = TimeUnit.MINUTES.toMillis(hypoTTDuration.toLong()),
|
||||
reason = TemporaryTarget.Reason.HYPOGLYCEMIA,
|
||||
|
|
|
@ -16,7 +16,7 @@ import info.nightscout.androidaps.database.entities.ValueWithUnit
|
|||
import info.nightscout.androidaps.database.entities.TemporaryTarget
|
||||
import info.nightscout.androidaps.database.entities.UserEntry.Action
|
||||
import info.nightscout.androidaps.database.entities.UserEntry.Sources
|
||||
import info.nightscout.androidaps.database.transactions.InsertTemporaryTargetAndCancelCurrentTransaction
|
||||
import info.nightscout.androidaps.database.transactions.InsertAndCancelCurrentTemporaryTargetTransaction
|
||||
import info.nightscout.androidaps.databinding.DialogInsulinBinding
|
||||
import info.nightscout.androidaps.logging.LTag
|
||||
import info.nightscout.androidaps.logging.UserEntryLogger
|
||||
|
@ -186,7 +186,7 @@ class InsulinDialog : DialogFragmentWithDate() {
|
|||
ValueWithUnit.TherapyEventTTReason(TemporaryTarget.Reason.EATING_SOON),
|
||||
ValueWithUnit.fromGlucoseUnit(eatingSoonTT, units.asText),
|
||||
ValueWithUnit.Minute(eatingSoonTTDuration))
|
||||
disposable += repository.runTransactionForResult(InsertTemporaryTargetAndCancelCurrentTransaction(
|
||||
disposable += repository.runTransactionForResult(InsertAndCancelCurrentTemporaryTargetTransaction(
|
||||
timestamp = System.currentTimeMillis(),
|
||||
duration = TimeUnit.MINUTES.toMillis(eatingSoonTTDuration.toLong()),
|
||||
reason = TemporaryTarget.Reason.EATING_SOON,
|
||||
|
|
|
@ -12,9 +12,13 @@ import androidx.fragment.app.FragmentManager
|
|||
import dagger.android.support.DaggerDialogFragment
|
||||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.activities.ErrorHelperActivity
|
||||
import info.nightscout.androidaps.database.AppRepository
|
||||
import info.nightscout.androidaps.database.entities.OfflineEvent
|
||||
import info.nightscout.androidaps.database.entities.ValueWithUnit
|
||||
import info.nightscout.androidaps.database.entities.UserEntry.Action
|
||||
import info.nightscout.androidaps.database.entities.UserEntry.Sources
|
||||
import info.nightscout.androidaps.database.transactions.CancelCurrentOfflineEventIfAnyTransaction
|
||||
import info.nightscout.androidaps.database.transactions.InsertAndCancelCurrentOfflineEventTransaction
|
||||
import info.nightscout.androidaps.databinding.DialogLoopBinding
|
||||
import info.nightscout.androidaps.events.EventPreferenceChange
|
||||
import info.nightscout.androidaps.events.EventRefreshOverview
|
||||
|
@ -29,8 +33,13 @@ import info.nightscout.androidaps.utils.FabricPrivacy
|
|||
import info.nightscout.androidaps.utils.ToastUtils
|
||||
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
|
||||
import info.nightscout.androidaps.extensions.toVisibility
|
||||
import info.nightscout.androidaps.logging.LTag
|
||||
import info.nightscout.androidaps.utils.DateUtil
|
||||
import info.nightscout.androidaps.utils.T
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
||||
import io.reactivex.disposables.CompositeDisposable
|
||||
import io.reactivex.rxkotlin.plusAssign
|
||||
import javax.inject.Inject
|
||||
|
||||
class LoopDialog : DaggerDialogFragment() {
|
||||
|
@ -48,6 +57,8 @@ class LoopDialog : DaggerDialogFragment() {
|
|||
@Inject lateinit var commandQueue: CommandQueueProvider
|
||||
@Inject lateinit var configBuilder: ConfigBuilder
|
||||
@Inject lateinit var uel: UserEntryLogger
|
||||
@Inject lateinit var dateUtil: DateUtil
|
||||
@Inject lateinit var repository: AppRepository
|
||||
|
||||
private var showOkCancel: Boolean = true
|
||||
private var _binding: DialogLoopBinding? = null
|
||||
|
@ -58,6 +69,8 @@ class LoopDialog : DaggerDialogFragment() {
|
|||
// onDestroyView.
|
||||
private val binding get() = _binding!!
|
||||
|
||||
val disposable = CompositeDisposable()
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
dialog?.window?.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
|
||||
|
@ -118,6 +131,7 @@ class LoopDialog : DaggerDialogFragment() {
|
|||
super.onDestroyView()
|
||||
_binding = null
|
||||
loopHandler.removeCallbacksAndMessages(null)
|
||||
disposable.clear()
|
||||
}
|
||||
|
||||
var task: Runnable? = null
|
||||
|
@ -196,6 +210,7 @@ class LoopDialog : DaggerDialogFragment() {
|
|||
binding.overviewDisconnectButtons.visibility = View.GONE
|
||||
binding.overviewReconnect.visibility = View.VISIBLE
|
||||
}
|
||||
binding.overviewLoop.visibility = (!loopPlugin.isSuspended && !loopPlugin.isDisconnected).toVisibility()
|
||||
}
|
||||
val profile = profileFunction.getProfile()
|
||||
val profileStore = activePlugin.activeProfileSource.profile
|
||||
|
@ -211,22 +226,22 @@ class LoopDialog : DaggerDialogFragment() {
|
|||
private fun onClickOkCancelEnabled(v: View): Boolean {
|
||||
var description = ""
|
||||
when (v.id) {
|
||||
R.id.overview_closeloop -> description = resourceHelper.gs(R.string.closedloop)
|
||||
R.id.overview_lgsloop -> description = resourceHelper.gs(R.string.lowglucosesuspend)
|
||||
R.id.overview_openloop -> description = resourceHelper.gs(R.string.openloop)
|
||||
R.id.overview_disable -> description = resourceHelper.gs(R.string.disableloop)
|
||||
R.id.overview_enable -> description = resourceHelper.gs(R.string.enableloop)
|
||||
R.id.overview_resume -> description = resourceHelper.gs(R.string.resume)
|
||||
R.id.overview_reconnect -> description = resourceHelper.gs(R.string.reconnect)
|
||||
R.id.overview_suspend_1h -> description = resourceHelper.gs(R.string.suspendloopfor1h)
|
||||
R.id.overview_suspend_2h -> description = resourceHelper.gs(R.string.suspendloopfor2h)
|
||||
R.id.overview_suspend_3h -> description = resourceHelper.gs(R.string.suspendloopfor3h)
|
||||
R.id.overview_suspend_10h -> description = resourceHelper.gs(R.string.suspendloopfor10h)
|
||||
R.id.overview_closeloop -> description = resourceHelper.gs(R.string.closedloop)
|
||||
R.id.overview_lgsloop -> description = resourceHelper.gs(R.string.lowglucosesuspend)
|
||||
R.id.overview_openloop -> description = resourceHelper.gs(R.string.openloop)
|
||||
R.id.overview_disable -> description = resourceHelper.gs(R.string.disableloop)
|
||||
R.id.overview_enable -> description = resourceHelper.gs(R.string.enableloop)
|
||||
R.id.overview_resume -> description = resourceHelper.gs(R.string.resume)
|
||||
R.id.overview_reconnect -> description = resourceHelper.gs(R.string.reconnect)
|
||||
R.id.overview_suspend_1h -> description = resourceHelper.gs(R.string.suspendloopfor1h)
|
||||
R.id.overview_suspend_2h -> description = resourceHelper.gs(R.string.suspendloopfor2h)
|
||||
R.id.overview_suspend_3h -> description = resourceHelper.gs(R.string.suspendloopfor3h)
|
||||
R.id.overview_suspend_10h -> description = resourceHelper.gs(R.string.suspendloopfor10h)
|
||||
R.id.overview_disconnect_15m -> description = resourceHelper.gs(R.string.disconnectpumpfor15m)
|
||||
R.id.overview_disconnect_30m -> description = resourceHelper.gs(R.string.disconnectpumpfor30m)
|
||||
R.id.overview_disconnect_1h -> description = resourceHelper.gs(R.string.disconnectpumpfor1h)
|
||||
R.id.overview_disconnect_2h -> description = resourceHelper.gs(R.string.disconnectpumpfor2h)
|
||||
R.id.overview_disconnect_3h -> description = resourceHelper.gs(R.string.disconnectpumpfor3h)
|
||||
R.id.overview_disconnect_1h -> description = resourceHelper.gs(R.string.disconnectpumpfor1h)
|
||||
R.id.overview_disconnect_2h -> description = resourceHelper.gs(R.string.disconnectpumpfor2h)
|
||||
R.id.overview_disconnect_3h -> description = resourceHelper.gs(R.string.disconnectpumpfor3h)
|
||||
}
|
||||
activity?.let { activity ->
|
||||
OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.confirm), description, Runnable {
|
||||
|
@ -237,30 +252,29 @@ class LoopDialog : DaggerDialogFragment() {
|
|||
}
|
||||
|
||||
fun onClick(v: View): Boolean {
|
||||
val profile = profileFunction.getProfile() ?: return true
|
||||
when (v.id) {
|
||||
R.id.overview_closeloop -> {
|
||||
R.id.overview_closeloop -> {
|
||||
uel.log(Action.CLOSED_LOOP_MODE, Sources.LoopDialog)
|
||||
sp.putString(R.string.key_aps_mode, "closed")
|
||||
rxBus.send(EventPreferenceChange(resourceHelper.gs(R.string.closedloop)))
|
||||
return true
|
||||
}
|
||||
|
||||
R.id.overview_lgsloop -> {
|
||||
R.id.overview_lgsloop -> {
|
||||
uel.log(Action.LGS_LOOP_MODE, Sources.LoopDialog)
|
||||
sp.putString(R.string.key_aps_mode, "lgs")
|
||||
rxBus.send(EventPreferenceChange(resourceHelper.gs(R.string.lowglucosesuspend)))
|
||||
return true
|
||||
}
|
||||
|
||||
R.id.overview_openloop -> {
|
||||
R.id.overview_openloop -> {
|
||||
uel.log(Action.OPEN_LOOP_MODE, Sources.LoopDialog)
|
||||
sp.putString(R.string.key_aps_mode, "open")
|
||||
rxBus.send(EventPreferenceChange(resourceHelper.gs(R.string.lowglucosesuspend)))
|
||||
return true
|
||||
}
|
||||
|
||||
R.id.overview_disable -> {
|
||||
R.id.overview_disable -> {
|
||||
uel.log(Action.LOOP_DISABLED, Sources.LoopDialog)
|
||||
loopPlugin.setPluginEnabled(PluginType.LOOP, false)
|
||||
loopPlugin.setFragmentVisible(PluginType.LOOP, false)
|
||||
|
@ -273,23 +287,39 @@ class LoopDialog : DaggerDialogFragment() {
|
|||
}
|
||||
}
|
||||
})
|
||||
loopPlugin.createOfflineEvent(24 * 60) // upload 24h, we don't know real duration
|
||||
disposable += repository.runTransactionForResult(InsertAndCancelCurrentOfflineEventTransaction(dateUtil.now(), T.days(365).msecs(), OfflineEvent.Reason.DISABLE_LOOP))
|
||||
.subscribe({ result ->
|
||||
result.updated.forEach { aapsLogger.debug(LTag.DATABASE, "Updated OfflineEvent $it") }
|
||||
result.inserted.forEach { aapsLogger.debug(LTag.DATABASE, "Inserted OfflineEvent $it") }
|
||||
}, {
|
||||
aapsLogger.error(LTag.DATABASE, "Error while saving OfflineEvent", it)
|
||||
})
|
||||
return true
|
||||
}
|
||||
|
||||
R.id.overview_enable -> {
|
||||
R.id.overview_enable -> {
|
||||
uel.log(Action.LOOP_ENABLED, Sources.LoopDialog)
|
||||
loopPlugin.setPluginEnabled(PluginType.LOOP, true)
|
||||
loopPlugin.setFragmentVisible(PluginType.LOOP, true)
|
||||
configBuilder.storeSettings("EnablingLoop")
|
||||
rxBus.send(EventRefreshOverview("suspendmenu"))
|
||||
loopPlugin.createOfflineEvent(0)
|
||||
disposable += repository.runTransactionForResult(CancelCurrentOfflineEventIfAnyTransaction(dateUtil.now()))
|
||||
.subscribe({ result ->
|
||||
result.updated.forEach { aapsLogger.debug(LTag.DATABASE, "Updated OfflineEvent $it") }
|
||||
}, {
|
||||
aapsLogger.error(LTag.DATABASE, "Error while saving OfflineEvent", it)
|
||||
})
|
||||
return true
|
||||
}
|
||||
|
||||
R.id.overview_resume, R.id.overview_reconnect -> {
|
||||
uel.log(if (v.id==R.id.overview_resume) Action.RESUME else Action.RECONNECT, Sources.LoopDialog)
|
||||
loopPlugin.suspendTo(0L)
|
||||
uel.log(if (v.id == R.id.overview_resume) Action.RESUME else Action.RECONNECT, Sources.LoopDialog)
|
||||
disposable += repository.runTransactionForResult(CancelCurrentOfflineEventIfAnyTransaction(dateUtil.now()))
|
||||
.subscribe({ result ->
|
||||
result.updated.forEach { aapsLogger.debug(LTag.DATABASE, "Updated OfflineEvent $it") }
|
||||
}, {
|
||||
aapsLogger.error(LTag.DATABASE, "Error while saving OfflineEvent", it)
|
||||
})
|
||||
rxBus.send(EventRefreshOverview("suspendmenu"))
|
||||
commandQueue.cancelTempBasal(true, object : Callback() {
|
||||
override fun run() {
|
||||
|
@ -299,70 +329,123 @@ class LoopDialog : DaggerDialogFragment() {
|
|||
}
|
||||
})
|
||||
sp.putBoolean(R.string.key_objectiveusereconnect, true)
|
||||
loopPlugin.createOfflineEvent(0)
|
||||
return true
|
||||
}
|
||||
|
||||
R.id.overview_suspend_1h -> {
|
||||
R.id.overview_suspend_1h -> {
|
||||
uel.log(Action.SUSPEND, Sources.LoopDialog, ValueWithUnit.Hour(1))
|
||||
loopPlugin.suspendLoop(60)
|
||||
disposable += repository.runTransactionForResult(InsertAndCancelCurrentOfflineEventTransaction(dateUtil.now(), T.hours(1).msecs(), OfflineEvent.Reason.SUSPEND))
|
||||
.subscribe({ result ->
|
||||
result.updated.forEach { aapsLogger.debug(LTag.DATABASE, "Updated OfflineEvent $it") }
|
||||
result.inserted.forEach { aapsLogger.debug(LTag.DATABASE, "Inserted OfflineEvent $it") }
|
||||
}, {
|
||||
aapsLogger.error(LTag.DATABASE, "Error while saving OfflineEvent", it)
|
||||
})
|
||||
rxBus.send(EventRefreshOverview("suspendmenu"))
|
||||
return true
|
||||
}
|
||||
|
||||
R.id.overview_suspend_2h -> {
|
||||
R.id.overview_suspend_2h -> {
|
||||
uel.log(Action.SUSPEND, Sources.LoopDialog, ValueWithUnit.Hour(2))
|
||||
loopPlugin.suspendLoop(120)
|
||||
disposable += repository.runTransactionForResult(InsertAndCancelCurrentOfflineEventTransaction(dateUtil.now(), T.hours(2).msecs(), OfflineEvent.Reason.SUSPEND))
|
||||
.subscribe({ result ->
|
||||
result.updated.forEach { aapsLogger.debug(LTag.DATABASE, "Updated OfflineEvent $it") }
|
||||
result.inserted.forEach { aapsLogger.debug(LTag.DATABASE, "Inserted OfflineEvent $it") }
|
||||
}, {
|
||||
aapsLogger.error(LTag.DATABASE, "Error while saving OfflineEvent", it)
|
||||
})
|
||||
rxBus.send(EventRefreshOverview("suspendmenu"))
|
||||
return true
|
||||
}
|
||||
|
||||
R.id.overview_suspend_3h -> {
|
||||
R.id.overview_suspend_3h -> {
|
||||
uel.log(Action.SUSPEND, Sources.LoopDialog, ValueWithUnit.Hour(3))
|
||||
loopPlugin.suspendLoop(180)
|
||||
disposable += repository.runTransactionForResult(InsertAndCancelCurrentOfflineEventTransaction(dateUtil.now(), T.hours(3).msecs(), OfflineEvent.Reason.SUSPEND))
|
||||
.subscribe({ result ->
|
||||
result.updated.forEach { aapsLogger.debug(LTag.DATABASE, "Updated OfflineEvent $it") }
|
||||
result.inserted.forEach { aapsLogger.debug(LTag.DATABASE, "Inserted OfflineEvent $it") }
|
||||
}, {
|
||||
aapsLogger.error(LTag.DATABASE, "Error while saving OfflineEvent", it)
|
||||
})
|
||||
rxBus.send(EventRefreshOverview("suspendmenu"))
|
||||
return true
|
||||
}
|
||||
|
||||
R.id.overview_suspend_10h -> {
|
||||
R.id.overview_suspend_10h -> {
|
||||
uel.log(Action.SUSPEND, Sources.LoopDialog, ValueWithUnit.Hour(10))
|
||||
loopPlugin.suspendLoop(600)
|
||||
disposable += repository.runTransactionForResult(InsertAndCancelCurrentOfflineEventTransaction(dateUtil.now(), T.hours(10).msecs(), OfflineEvent.Reason.SUSPEND))
|
||||
.subscribe({ result ->
|
||||
result.updated.forEach { aapsLogger.debug(LTag.DATABASE, "Updated OfflineEvent $it") }
|
||||
result.inserted.forEach { aapsLogger.debug(LTag.DATABASE, "Inserted OfflineEvent $it") }
|
||||
}, {
|
||||
aapsLogger.error(LTag.DATABASE, "Error while saving OfflineEvent", it)
|
||||
})
|
||||
rxBus.send(EventRefreshOverview("suspendmenu"))
|
||||
return true
|
||||
}
|
||||
|
||||
R.id.overview_disconnect_15m -> {
|
||||
R.id.overview_disconnect_15m -> {
|
||||
uel.log(Action.DISCONNECT, Sources.LoopDialog, ValueWithUnit.Minute(15))
|
||||
loopPlugin.disconnectPump(15, profile)
|
||||
disposable += repository.runTransactionForResult(InsertAndCancelCurrentOfflineEventTransaction(dateUtil.now(), T.mins(15).msecs(), OfflineEvent.Reason.DISCONNECT_PUMP))
|
||||
.subscribe({ result ->
|
||||
result.updated.forEach { aapsLogger.debug(LTag.DATABASE, "Updated OfflineEvent $it") }
|
||||
result.inserted.forEach { aapsLogger.debug(LTag.DATABASE, "Inserted OfflineEvent $it") }
|
||||
}, {
|
||||
aapsLogger.error(LTag.DATABASE, "Error while saving OfflineEvent", it)
|
||||
})
|
||||
rxBus.send(EventRefreshOverview("suspendmenu"))
|
||||
return true
|
||||
}
|
||||
|
||||
R.id.overview_disconnect_30m -> {
|
||||
R.id.overview_disconnect_30m -> {
|
||||
uel.log(Action.DISCONNECT, Sources.LoopDialog, ValueWithUnit.Minute(30))
|
||||
loopPlugin.disconnectPump(30, profile)
|
||||
disposable += repository.runTransactionForResult(InsertAndCancelCurrentOfflineEventTransaction(dateUtil.now(), T.mins(30).msecs(), OfflineEvent.Reason.DISCONNECT_PUMP))
|
||||
.subscribe({ result ->
|
||||
result.updated.forEach { aapsLogger.debug(LTag.DATABASE, "Updated OfflineEvent $it") }
|
||||
result.inserted.forEach { aapsLogger.debug(LTag.DATABASE, "Inserted OfflineEvent $it") }
|
||||
}, {
|
||||
aapsLogger.error(LTag.DATABASE, "Error while saving OfflineEvent", it)
|
||||
})
|
||||
rxBus.send(EventRefreshOverview("suspendmenu"))
|
||||
return true
|
||||
}
|
||||
|
||||
R.id.overview_disconnect_1h -> {
|
||||
R.id.overview_disconnect_1h -> {
|
||||
uel.log(Action.DISCONNECT, Sources.LoopDialog, ValueWithUnit.Hour(1))
|
||||
loopPlugin.disconnectPump(60, profile)
|
||||
disposable += repository.runTransactionForResult(InsertAndCancelCurrentOfflineEventTransaction(dateUtil.now(), T.mins(60).msecs(), OfflineEvent.Reason.DISCONNECT_PUMP))
|
||||
.subscribe({ result ->
|
||||
result.updated.forEach { aapsLogger.debug(LTag.DATABASE, "Updated OfflineEvent $it") }
|
||||
result.inserted.forEach { aapsLogger.debug(LTag.DATABASE, "Inserted OfflineEvent $it") }
|
||||
}, {
|
||||
aapsLogger.error(LTag.DATABASE, "Error while saving OfflineEvent", it)
|
||||
})
|
||||
sp.putBoolean(R.string.key_objectiveusedisconnect, true)
|
||||
rxBus.send(EventRefreshOverview("suspendmenu"))
|
||||
return true
|
||||
}
|
||||
|
||||
R.id.overview_disconnect_2h -> {
|
||||
R.id.overview_disconnect_2h -> {
|
||||
uel.log(Action.DISCONNECT, Sources.LoopDialog, ValueWithUnit.Hour(2))
|
||||
loopPlugin.disconnectPump(120, profile)
|
||||
disposable += repository.runTransactionForResult(InsertAndCancelCurrentOfflineEventTransaction(dateUtil.now(), T.mins(120).msecs(), OfflineEvent.Reason.DISCONNECT_PUMP))
|
||||
.subscribe({ result ->
|
||||
result.updated.forEach { aapsLogger.debug(LTag.DATABASE, "Updated OfflineEvent $it") }
|
||||
result.inserted.forEach { aapsLogger.debug(LTag.DATABASE, "Inserted OfflineEvent $it") }
|
||||
}, {
|
||||
aapsLogger.error(LTag.DATABASE, "Error while saving OfflineEvent", it)
|
||||
})
|
||||
rxBus.send(EventRefreshOverview("suspendmenu"))
|
||||
return true
|
||||
}
|
||||
|
||||
R.id.overview_disconnect_3h -> {
|
||||
R.id.overview_disconnect_3h -> {
|
||||
uel.log(Action.DISCONNECT, Sources.LoopDialog, ValueWithUnit.Hour(3))
|
||||
loopPlugin.disconnectPump(180, profile)
|
||||
disposable += repository.runTransactionForResult(InsertAndCancelCurrentOfflineEventTransaction(dateUtil.now(), T.mins(180).msecs(), OfflineEvent.Reason.DISCONNECT_PUMP))
|
||||
.subscribe({ result ->
|
||||
result.updated.forEach { aapsLogger.debug(LTag.DATABASE, "Updated OfflineEvent $it") }
|
||||
result.inserted.forEach { aapsLogger.debug(LTag.DATABASE, "Inserted OfflineEvent $it") }
|
||||
}, {
|
||||
aapsLogger.error(LTag.DATABASE, "Error while saving OfflineEvent", it)
|
||||
})
|
||||
rxBus.send(EventRefreshOverview("suspendmenu"))
|
||||
return true
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ import info.nightscout.androidaps.database.entities.TemporaryTarget
|
|||
import info.nightscout.androidaps.database.entities.UserEntry.Action
|
||||
import info.nightscout.androidaps.database.entities.UserEntry.Sources
|
||||
import info.nightscout.androidaps.database.transactions.CancelCurrentTemporaryTargetIfAnyTransaction
|
||||
import info.nightscout.androidaps.database.transactions.InsertTemporaryTargetAndCancelCurrentTransaction
|
||||
import info.nightscout.androidaps.database.transactions.InsertAndCancelCurrentTemporaryTargetTransaction
|
||||
import info.nightscout.androidaps.databinding.DialogTemptargetBinding
|
||||
import info.nightscout.androidaps.interfaces.GlucoseUnit
|
||||
import info.nightscout.androidaps.interfaces.ProfileFunction
|
||||
|
@ -196,7 +196,7 @@ class TempTargetDialog : DialogFragmentWithDate() {
|
|||
aapsLogger.error(LTag.DATABASE, "Error while saving temporary target", it)
|
||||
})
|
||||
} else {
|
||||
disposable += repository.runTransactionForResult(InsertTemporaryTargetAndCancelCurrentTransaction(
|
||||
disposable += repository.runTransactionForResult(InsertAndCancelCurrentTemporaryTargetTransaction(
|
||||
timestamp = eventTime,
|
||||
duration = TimeUnit.MINUTES.toMillis(duration.toLong()),
|
||||
reason = when (reason) {
|
||||
|
|
|
@ -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, iobCobCalculatorPluginHistory)
|
||||
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], iobCobCalculatorPluginHistory)
|
||||
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()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
package info.nightscout.androidaps.plugins.aps.events
|
||||
|
||||
import info.nightscout.androidaps.events.Event
|
||||
|
||||
class EventLoopInvoked : Event()
|
|
@ -16,18 +16,19 @@ import info.nightscout.androidaps.data.DetailedBolusInfo
|
|||
import info.nightscout.androidaps.interfaces.Profile
|
||||
import info.nightscout.androidaps.data.PumpEnactResult
|
||||
import info.nightscout.androidaps.database.AppRepository
|
||||
import info.nightscout.androidaps.database.entities.TherapyEvent
|
||||
import info.nightscout.androidaps.database.ValueWrapper
|
||||
import info.nightscout.androidaps.database.entities.OfflineEvent
|
||||
import info.nightscout.androidaps.database.entities.UserEntry.Action
|
||||
import info.nightscout.androidaps.database.entities.UserEntry.Sources
|
||||
import info.nightscout.androidaps.database.entities.ValueWithUnit
|
||||
import info.nightscout.androidaps.database.transactions.InsertIfNewByTimestampTherapyEventTransaction
|
||||
import info.nightscout.androidaps.database.transactions.InsertAndCancelCurrentOfflineEventTransaction
|
||||
import info.nightscout.androidaps.database.transactions.InsertTherapyEventAnnouncementTransaction
|
||||
import info.nightscout.androidaps.events.EventAcceptOpenLoopChange
|
||||
import info.nightscout.androidaps.events.EventAutosensCalculationFinished
|
||||
import info.nightscout.androidaps.events.EventNewBG
|
||||
import info.nightscout.androidaps.events.EventTempTargetChange
|
||||
import info.nightscout.androidaps.interfaces.*
|
||||
import info.nightscout.androidaps.interfaces.LoopInterface.LastRun
|
||||
import info.nightscout.androidaps.interfaces.Loop.LastRun
|
||||
import info.nightscout.androidaps.logging.AAPSLogger
|
||||
import info.nightscout.androidaps.logging.LTag
|
||||
import info.nightscout.androidaps.logging.UserEntryLogger
|
||||
|
@ -54,6 +55,7 @@ import info.nightscout.androidaps.extensions.buildDeviceStatus
|
|||
import info.nightscout.androidaps.extensions.convertedToAbsolute
|
||||
import info.nightscout.androidaps.extensions.convertedToPercent
|
||||
import info.nightscout.androidaps.extensions.plannedRemainingMinutes
|
||||
import info.nightscout.androidaps.plugins.aps.events.EventLoopInvoked
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
||||
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
||||
|
@ -95,7 +97,7 @@ open class LoopPlugin @Inject constructor(
|
|||
.enableByDefault(config.APS)
|
||||
.description(R.string.description_loop),
|
||||
aapsLogger, resourceHelper, injector
|
||||
), LoopInterface {
|
||||
), Loop {
|
||||
|
||||
private val disposable = CompositeDisposable()
|
||||
private var lastBgTriggeredRun: Long = 0
|
||||
|
@ -157,48 +159,19 @@ open class LoopPlugin @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
override fun suspendTo(endTime: Long) {
|
||||
sp.putLong("loopSuspendedTill", endTime)
|
||||
sp.putBoolean("isSuperBolus", false)
|
||||
sp.putBoolean("isDisconnected", false)
|
||||
override fun minutesToEndOfSuspend(): Int {
|
||||
val offlineEventWrapped = repository.getOfflineEventActiveAt(dateUtil.now()).blockingGet()
|
||||
return if (offlineEventWrapped is ValueWrapper.Existing) T.msecs(offlineEventWrapped.value.timestamp + offlineEventWrapped.value.duration - dateUtil.now()).mins().toInt()
|
||||
else 0
|
||||
}
|
||||
|
||||
fun superBolusTo(endTime: Long) {
|
||||
sp.putLong("loopSuspendedTill", endTime)
|
||||
sp.putBoolean("isSuperBolus", true)
|
||||
sp.putBoolean("isDisconnected", false)
|
||||
}
|
||||
|
||||
private fun disconnectTo(endTime: Long) {
|
||||
sp.putLong("loopSuspendedTill", endTime)
|
||||
sp.putBoolean("isSuperBolus", false)
|
||||
sp.putBoolean("isDisconnected", true)
|
||||
}
|
||||
|
||||
fun minutesToEndOfSuspend(): Int {
|
||||
val loopSuspendedTill = sp.getLong("loopSuspendedTill", 0L)
|
||||
if (loopSuspendedTill == 0L) return 0
|
||||
val now = System.currentTimeMillis()
|
||||
val millisDiff = loopSuspendedTill - now
|
||||
if (loopSuspendedTill <= now) { // time exceeded
|
||||
suspendTo(0L)
|
||||
return 0
|
||||
}
|
||||
return (millisDiff / 60.0 / 1000.0).toInt()
|
||||
}
|
||||
|
||||
// time exceeded
|
||||
override val isSuspended: Boolean
|
||||
get() {
|
||||
val loopSuspendedTill = sp.getLong("loopSuspendedTill", 0L)
|
||||
if (loopSuspendedTill == 0L) return false
|
||||
val now = System.currentTimeMillis()
|
||||
if (loopSuspendedTill <= now) { // time exceeded
|
||||
suspendTo(0L)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
get() = repository.getOfflineEventActiveAt(dateUtil.now()).blockingGet() is ValueWrapper.Existing
|
||||
|
||||
override var enabled: Boolean
|
||||
get() = isEnabled()
|
||||
set(value) { setPluginEnabled(PluginType.LOOP, value)}
|
||||
|
||||
val isLGS: Boolean
|
||||
get() {
|
||||
val closedLoopEnabled = constraintChecker.isClosedLoopAllowed()
|
||||
|
@ -210,30 +183,16 @@ open class LoopPlugin @Inject constructor(
|
|||
return isLGS
|
||||
}
|
||||
|
||||
// time exceeded
|
||||
val isSuperBolus: Boolean
|
||||
get() {
|
||||
val loopSuspendedTill = sp.getLong("loopSuspendedTill", 0L)
|
||||
if (loopSuspendedTill == 0L) return false
|
||||
val now = System.currentTimeMillis()
|
||||
if (loopSuspendedTill <= now) { // time exceeded
|
||||
suspendTo(0L)
|
||||
return false
|
||||
}
|
||||
return sp.getBoolean("isSuperBolus", false)
|
||||
val offlineEventWrapped = repository.getOfflineEventActiveAt(dateUtil.now()).blockingGet()
|
||||
return offlineEventWrapped is ValueWrapper.Existing && offlineEventWrapped.value.reason == OfflineEvent.Reason.SUPER_BOLUS
|
||||
}
|
||||
|
||||
// time exceeded
|
||||
val isDisconnected: Boolean
|
||||
get() {
|
||||
val loopSuspendedTill = sp.getLong("loopSuspendedTill", 0L)
|
||||
if (loopSuspendedTill == 0L) return false
|
||||
val now = System.currentTimeMillis()
|
||||
if (loopSuspendedTill <= now) { // time exceeded
|
||||
suspendTo(0L)
|
||||
return false
|
||||
}
|
||||
return sp.getBoolean("isDisconnected", false)
|
||||
val offlineEventWrapped = repository.getOfflineEventActiveAt(dateUtil.now()).blockingGet()
|
||||
return offlineEventWrapped is ValueWrapper.Existing && offlineEventWrapped.value.reason == OfflineEvent.Reason.DISCONNECT_PUMP
|
||||
}
|
||||
|
||||
@Suppress("SameParameterValue")
|
||||
|
@ -286,7 +245,7 @@ open class LoopPlugin @Inject constructor(
|
|||
if (apsResult == null) {
|
||||
rxBus.send(EventLoopSetLastRunGui(resourceHelper.gs(R.string.noapsselected)))
|
||||
return
|
||||
}
|
||||
} else rxBus.send(EventLoopInvoked())
|
||||
|
||||
// Prepare for pumps using % basals
|
||||
if (pump.pumpDescription.tempBasalStyle == PumpDescription.PERCENT && allowPercentage()) {
|
||||
|
@ -403,7 +362,7 @@ open class LoopPlugin @Inject constructor(
|
|||
val waiting = PumpEnactResult(injector)
|
||||
waiting.queued = true
|
||||
if (resultAfterConstraints.tempBasalRequested) lastRun.tbrSetByPump = waiting
|
||||
if (resultAfterConstraints.bolusRequested) lastRun.smbSetByPump = waiting
|
||||
if (resultAfterConstraints.bolusRequested()) lastRun.smbSetByPump = waiting
|
||||
rxBus.send(EventLoopUpdateGui())
|
||||
fabricPrivacy.logCustom("APSRequest")
|
||||
applyTBRRequest(resultAfterConstraints, profile, object : Callback() {
|
||||
|
@ -600,7 +559,7 @@ open class LoopPlugin @Inject constructor(
|
|||
}
|
||||
|
||||
private fun applySMBRequest(request: APSResult, callback: Callback?) {
|
||||
if (!request.bolusRequested) {
|
||||
if (!request.bolusRequested()) {
|
||||
return
|
||||
}
|
||||
val pump = activePlugin.activePump
|
||||
|
@ -641,11 +600,17 @@ open class LoopPlugin @Inject constructor(
|
|||
return virtualPumpPlugin.isEnabled(PluginType.PUMP)
|
||||
}
|
||||
|
||||
fun disconnectPump(durationInMinutes: Int, profile: Profile?) {
|
||||
override fun goToZeroTemp(durationInMinutes: Int, profile: Profile, reason: OfflineEvent.Reason) {
|
||||
val pump = activePlugin.activePump
|
||||
disconnectTo(System.currentTimeMillis() + durationInMinutes * 60 * 1000L)
|
||||
disposable += repository.runTransactionForResult(InsertAndCancelCurrentOfflineEventTransaction(dateUtil.now(), T.mins(durationInMinutes.toLong()).msecs(), reason))
|
||||
.subscribe({ result ->
|
||||
result.updated.forEach { aapsLogger.debug(LTag.DATABASE, "Updated OfflineEvent $it") }
|
||||
result.inserted.forEach { aapsLogger.debug(LTag.DATABASE, "Inserted OfflineEvent $it") }
|
||||
}, {
|
||||
aapsLogger.error(LTag.DATABASE, "Error while saving OfflineEvent", it)
|
||||
})
|
||||
if (pump.pumpDescription.tempBasalStyle == PumpDescription.ABSOLUTE) {
|
||||
commandQueue.tempBasalAbsolute(0.0, durationInMinutes, true, profile!!, PumpSync.TemporaryBasalType.EMULATED_PUMP_SUSPEND, object : Callback() {
|
||||
commandQueue.tempBasalAbsolute(0.0, durationInMinutes, true, profile, PumpSync.TemporaryBasalType.EMULATED_PUMP_SUSPEND, object : Callback() {
|
||||
override fun run() {
|
||||
if (!result.success) {
|
||||
ErrorHelperActivity.runAlarm(context, result.comment, resourceHelper.gs(R.string.tempbasaldeliveryerror), info.nightscout.androidaps.dana.R.raw.boluserror)
|
||||
|
@ -653,7 +618,7 @@ open class LoopPlugin @Inject constructor(
|
|||
}
|
||||
})
|
||||
} else {
|
||||
commandQueue.tempBasalPercent(0, durationInMinutes, true, profile!!, PumpSync.TemporaryBasalType.EMULATED_PUMP_SUSPEND, object : Callback() {
|
||||
commandQueue.tempBasalPercent(0, durationInMinutes, true, profile, PumpSync.TemporaryBasalType.EMULATED_PUMP_SUSPEND, object : Callback() {
|
||||
override fun run() {
|
||||
if (!result.success) {
|
||||
ErrorHelperActivity.runAlarm(context, result.comment, resourceHelper.gs(R.string.tempbasaldeliveryerror), info.nightscout.androidaps.dana.R.raw.boluserror)
|
||||
|
@ -670,11 +635,16 @@ open class LoopPlugin @Inject constructor(
|
|||
}
|
||||
})
|
||||
}
|
||||
createOfflineEvent(durationInMinutes)
|
||||
}
|
||||
|
||||
override fun suspendLoop(durationInMinutes: Int) {
|
||||
suspendTo(System.currentTimeMillis() + durationInMinutes * 60 * 1000)
|
||||
disposable += repository.runTransactionForResult(InsertAndCancelCurrentOfflineEventTransaction(dateUtil.now(), T.mins(durationInMinutes.toLong()).msecs(), OfflineEvent.Reason.SUSPEND))
|
||||
.subscribe({ result ->
|
||||
result.updated.forEach { aapsLogger.debug(LTag.DATABASE, "Updated OfflineEvent $it") }
|
||||
result.inserted.forEach { aapsLogger.debug(LTag.DATABASE, "Inserted OfflineEvent $it") }
|
||||
}, {
|
||||
aapsLogger.error(LTag.DATABASE, "Error while saving OfflineEvent", it)
|
||||
})
|
||||
commandQueue.cancelTempBasal(true, object : Callback() {
|
||||
override fun run() {
|
||||
if (!result.success) {
|
||||
|
@ -682,20 +652,6 @@ open class LoopPlugin @Inject constructor(
|
|||
}
|
||||
}
|
||||
})
|
||||
createOfflineEvent(durationInMinutes)
|
||||
}
|
||||
|
||||
override fun createOfflineEvent(durationInMinutes: Int) {
|
||||
disposable += repository.runTransactionForResult(InsertIfNewByTimestampTherapyEventTransaction(
|
||||
timestamp = dateUtil.now(),
|
||||
type = TherapyEvent.Type.APS_OFFLINE,
|
||||
duration = T.mins(durationInMinutes.toLong()).msecs(),
|
||||
enteredBy = "openaps://" + "AndroidAPS",
|
||||
glucoseUnit = TherapyEvent.GlucoseUnit.MGDL
|
||||
)).subscribe(
|
||||
{ result -> result.inserted.forEach { aapsLogger.debug(LTag.DATABASE, "Inserted therapy event $it") } },
|
||||
{ aapsLogger.error(LTag.DATABASE, "Error while saving therapy event", it) }
|
||||
)
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
|
|
@ -40,7 +40,6 @@ class DetermineBasalResultAMA private constructor(injector: HasAndroidInjector)
|
|||
tempBasalRequested = false
|
||||
}
|
||||
}
|
||||
bolusRequested = false
|
||||
}
|
||||
|
||||
override fun newAndClone(injector: HasAndroidInjector): DetermineBasalResultAMA {
|
||||
|
|
|
@ -58,6 +58,7 @@ class OpenAPSAMAFragment : DaggerFragment() {
|
|||
}
|
||||
|
||||
@Synchronized
|
||||
@kotlin.ExperimentalStdlibApi
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
|
||||
|
@ -90,6 +91,7 @@ class OpenAPSAMAFragment : DaggerFragment() {
|
|||
}
|
||||
|
||||
@Synchronized
|
||||
@kotlin.ExperimentalStdlibApi
|
||||
private fun updateGUI() {
|
||||
if (_binding == null) return
|
||||
openAPSAMAPlugin.lastAPSResult?.let { lastAPSResult ->
|
||||
|
|
|
@ -35,7 +35,6 @@ class DetermineBasalResultSMB private constructor(injector: HasAndroidInjector)
|
|||
duration = -1
|
||||
}
|
||||
if (result.has("units")) {
|
||||
bolusRequested = true
|
||||
smb = result.getDouble("units")
|
||||
} else {
|
||||
smb = 0.0
|
||||
|
|
|
@ -59,6 +59,7 @@ class OpenAPSSMBFragment : DaggerFragment() {
|
|||
}
|
||||
|
||||
@Synchronized
|
||||
@kotlin.ExperimentalStdlibApi
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
disposable += rxBus
|
||||
|
@ -90,6 +91,7 @@ class OpenAPSSMBFragment : DaggerFragment() {
|
|||
}
|
||||
|
||||
@Synchronized
|
||||
@kotlin.ExperimentalStdlibApi
|
||||
fun updateGUI() {
|
||||
if (_binding == null) return
|
||||
openAPSSMBPlugin.lastAPSResult?.let { lastAPSResult ->
|
||||
|
|
|
@ -184,4 +184,4 @@ class PluginStore @Inject constructor(
|
|||
|
||||
override fun getPluginsList(): ArrayList<PluginBase> = ArrayList(plugins)
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package info.nightscout.androidaps.plugins.configBuilder
|
||||
|
||||
import androidx.collection.LongSparseArray
|
||||
import info.nightscout.androidaps.Constants
|
||||
import info.nightscout.androidaps.core.R
|
||||
import info.nightscout.androidaps.data.ProfileSealed
|
||||
|
@ -35,6 +36,8 @@ class ProfileFunctionImplementation @Inject constructor(
|
|||
private val dateUtil: DateUtil
|
||||
) : ProfileFunction {
|
||||
|
||||
val cache = LongSparseArray<Profile>()
|
||||
|
||||
private val disposable = CompositeDisposable()
|
||||
|
||||
override fun getProfileName(): String =
|
||||
|
@ -65,10 +68,20 @@ class ProfileFunctionImplementation @Inject constructor(
|
|||
getProfile(dateUtil.now())
|
||||
|
||||
override fun getProfile(time: Long): Profile? {
|
||||
// aapsLogger.debug("XXXXXXXXXXXXXXX getProfile called for $time")
|
||||
val rounded = time - time % 1000
|
||||
val cached = cache[rounded]
|
||||
if (cached != null) {
|
||||
// aapsLogger.debug("XXXXXXXXXXXXXXX HIT getProfile for $time $rounded")
|
||||
return cached
|
||||
}
|
||||
// aapsLogger.debug("XXXXXXXXXXXXXXX getProfile called for $time")
|
||||
val ps = repository.getEffectiveProfileSwitchActiveAt(time).blockingGet()
|
||||
return if (ps is ValueWrapper.Existing) ProfileSealed.EPS(ps.value)
|
||||
else null
|
||||
if (ps is ValueWrapper.Existing) {
|
||||
val sealed = ProfileSealed.EPS(ps.value)
|
||||
cache.put(rounded, sealed)
|
||||
return sealed
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
override fun getRequestedProfile(): ProfileSwitch? = repository.getActiveProfileSwitch(dateUtil.now())
|
||||
|
@ -91,7 +104,8 @@ class ProfileFunctionImplementation @Inject constructor(
|
|||
timeshift = T.hours(timeShiftInHours.toLong()).msecs(),
|
||||
percentage = percentage,
|
||||
duration = T.mins(durationInMinutes.toLong()).msecs(),
|
||||
insulinConfiguration = activePlugin.activeInsulin.insulinConfiguration)
|
||||
insulinConfiguration = activePlugin.activeInsulin.insulinConfiguration.also { it.insulinEndTime = (pureProfile.dia * 3600 * 1000).toLong() }
|
||||
)
|
||||
disposable += repository.runTransactionForResult(InsertOrUpdateProfileSwitch(ps))
|
||||
.subscribe({ result ->
|
||||
result.inserted.forEach { aapsLogger.debug(LTag.DATABASE, "Inserted ProfileSwitch $it") }
|
|
@ -120,9 +120,10 @@ class ObjectivesPlugin @Inject constructor(
|
|||
sp.putBoolean(R.string.key_objectiveusescale, false)
|
||||
}
|
||||
|
||||
@kotlin.ExperimentalStdlibApi
|
||||
fun completeObjectives(activity: FragmentActivity, request: String) {
|
||||
val requestCode = sp.getString(R.string.key_objectives_request_code, "")
|
||||
var url = sp.getString(R.string.key_nsclientinternal_url, "").toLowerCase(Locale.getDefault())
|
||||
var url = sp.getString(R.string.key_nsclientinternal_url, "").lowercase(Locale.getDefault())
|
||||
if (!url.endsWith("/")) url = "$url/"
|
||||
@Suppress("DEPRECATION") val hashNS = Hashing.sha1().hashString(url + BuildConfig.APPLICATION_ID + "/" + requestCode, Charsets.UTF_8).toString()
|
||||
if (request.equals(hashNS.substring(0, 10), ignoreCase = true)) {
|
||||
|
|
|
@ -5,7 +5,6 @@ import dagger.android.HasAndroidInjector
|
|||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.plugins.constraints.objectives.ObjectivesPlugin
|
||||
import info.nightscout.androidaps.plugins.general.nsclient.NSClientPlugin
|
||||
import info.nightscout.androidaps.plugins.general.nsclient.services.NSClientService
|
||||
import info.nightscout.androidaps.utils.T
|
||||
import javax.inject.Inject
|
||||
|
||||
|
@ -28,8 +27,9 @@ class Objective3 @Inject constructor(injector: HasAndroidInjector) : Objective(i
|
|||
}
|
||||
|
||||
override fun specialActionEnabled(): Boolean =
|
||||
NSClientService.isConnected && NSClientService.hasWriteAuth
|
||||
nsClientPlugin.nsClientService?.isConnected == true && nsClientPlugin.nsClientService?.hasWriteAuth == true
|
||||
|
||||
@kotlin.ExperimentalStdlibApi
|
||||
override fun specialAction(activity: FragmentActivity, input: String) {
|
||||
objectivesPlugin.completeObjectives(activity, input)
|
||||
}
|
||||
|
|
|
@ -152,12 +152,13 @@ class SignatureVerifierPlugin @Inject constructor(
|
|||
return sb.toString()
|
||||
}
|
||||
|
||||
@kotlin.ExperimentalStdlibApi
|
||||
fun singleCharUnMap(shortHash: String): String {
|
||||
val array = ByteArray(shortHash.length)
|
||||
val sb = StringBuilder()
|
||||
for (i in array.indices) {
|
||||
if (i != 0) sb.append(":")
|
||||
sb.append(String.format("%02X", 0xFF and map[map.indexOf(shortHash[i])].toInt()))
|
||||
sb.append(String.format("%02X", 0xFF and map[map.indexOf(shortHash[i])].code))
|
||||
}
|
||||
return sb.toString()
|
||||
}
|
||||
|
|
|
@ -11,7 +11,6 @@ import android.widget.LinearLayout
|
|||
import android.widget.TextView
|
||||
import androidx.core.content.ContextCompat
|
||||
import dagger.android.support.DaggerFragment
|
||||
import info.nightscout.androidaps.interfaces.Config
|
||||
import info.nightscout.androidaps.Constants
|
||||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.activities.ErrorHelperActivity
|
||||
|
@ -21,13 +20,18 @@ import info.nightscout.androidaps.database.ValueWrapper
|
|||
import info.nightscout.androidaps.database.entities.UserEntry.Action
|
||||
import info.nightscout.androidaps.database.entities.UserEntry.Sources
|
||||
import info.nightscout.androidaps.dialogs.*
|
||||
import info.nightscout.androidaps.events.*
|
||||
import info.nightscout.androidaps.events.EventCustomActionsChanged
|
||||
import info.nightscout.androidaps.events.EventExtendedBolusChange
|
||||
import info.nightscout.androidaps.events.EventInitializationChanged
|
||||
import info.nightscout.androidaps.events.EventTempBasalChange
|
||||
import info.nightscout.androidaps.events.EventTherapyEventChange
|
||||
import info.nightscout.androidaps.extensions.toStringMedium
|
||||
import info.nightscout.androidaps.extensions.toStringShort
|
||||
import info.nightscout.androidaps.extensions.toVisibility
|
||||
import info.nightscout.androidaps.historyBrowser.HistoryBrowseActivity
|
||||
import info.nightscout.androidaps.activities.HistoryBrowseActivity
|
||||
import info.nightscout.androidaps.interfaces.ActivePlugin
|
||||
import info.nightscout.androidaps.interfaces.CommandQueueProvider
|
||||
import info.nightscout.androidaps.interfaces.Config
|
||||
import info.nightscout.androidaps.interfaces.IobCobCalculator
|
||||
import info.nightscout.androidaps.interfaces.ProfileFunction
|
||||
import info.nightscout.androidaps.logging.AAPSLogger
|
||||
|
@ -229,10 +233,6 @@ class ActionsFragment : DaggerFragment() {
|
|||
.toObservable(EventInitializationChanged::class.java)
|
||||
.observeOn(aapsSchedulers.main)
|
||||
.subscribe({ updateGui() }, fabricPrivacy::logException)
|
||||
disposable += rxBus
|
||||
.toObservable(EventRefreshOverview::class.java)
|
||||
.observeOn(aapsSchedulers.main)
|
||||
.subscribe({ updateGui() }, fabricPrivacy::logException)
|
||||
disposable += rxBus
|
||||
.toObservable(EventExtendedBolusChange::class.java)
|
||||
.observeOn(aapsSchedulers.main)
|
||||
|
|
|
@ -67,6 +67,7 @@ class FoodFragment : DaggerFragment() {
|
|||
return binding.root
|
||||
}
|
||||
|
||||
@kotlin.ExperimentalStdlibApi
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
|
@ -128,6 +129,7 @@ class FoodFragment : DaggerFragment() {
|
|||
}
|
||||
|
||||
@Synchronized
|
||||
@kotlin.ExperimentalStdlibApi
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
disposable.add(rxBus
|
||||
|
@ -139,6 +141,7 @@ class FoodFragment : DaggerFragment() {
|
|||
swapAdapter()
|
||||
}
|
||||
|
||||
@kotlin.ExperimentalStdlibApi
|
||||
private fun swapAdapter() {
|
||||
disposable += repository
|
||||
.getFoodData()
|
||||
|
@ -199,6 +202,7 @@ class FoodFragment : DaggerFragment() {
|
|||
}
|
||||
}
|
||||
|
||||
@kotlin.ExperimentalStdlibApi
|
||||
private fun filterData() {
|
||||
val textFilter = binding.filter.text.toString()
|
||||
val categoryFilter = binding.category.selectedItem?.toString()
|
||||
|
@ -210,7 +214,7 @@ class FoodFragment : DaggerFragment() {
|
|||
if (f.category == null || f.subCategory == null) continue
|
||||
if (subcategoryFilter != resourceHelper.gs(R.string.none) && f.subCategory != subcategoryFilter) continue
|
||||
if (categoryFilter != resourceHelper.gs(R.string.none) && f.category != categoryFilter) continue
|
||||
if (textFilter != "" && !f.name.toLowerCase(Locale.getDefault()).contains(textFilter.toLowerCase(Locale.getDefault()))) continue
|
||||
if (textFilter != "" && !f.name.lowercase(Locale.getDefault()).contains(textFilter.lowercase(Locale.getDefault()))) continue
|
||||
newFiltered.add(f)
|
||||
}
|
||||
filtered = newFiltered
|
||||
|
|
|
@ -7,13 +7,14 @@ import android.view.View
|
|||
import android.view.ViewGroup
|
||||
import dagger.android.support.DaggerFragment
|
||||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.dana.database.DanaHistoryDatabase
|
||||
import info.nightscout.androidaps.database.AppRepository
|
||||
import info.nightscout.androidaps.database.entities.UserEntry.Action
|
||||
import info.nightscout.androidaps.database.entities.UserEntry.Sources
|
||||
import info.nightscout.androidaps.databinding.MaintenanceFragmentBinding
|
||||
import info.nightscout.androidaps.events.EventNewBG
|
||||
import info.nightscout.androidaps.insight.database.InsightDatabase
|
||||
import info.nightscout.androidaps.interfaces.DataSyncSelector
|
||||
import info.nightscout.androidaps.interfaces.DatabaseHelperInterface
|
||||
import info.nightscout.androidaps.interfaces.ImportExportPrefs
|
||||
import info.nightscout.androidaps.interfaces.PumpSync
|
||||
import info.nightscout.androidaps.logging.AAPSLogger
|
||||
|
@ -38,7 +39,8 @@ class MaintenanceFragment : DaggerFragment() {
|
|||
@Inject lateinit var importExportPrefs: ImportExportPrefs
|
||||
@Inject lateinit var aapsSchedulers: AapsSchedulers
|
||||
@Inject lateinit var repository: AppRepository
|
||||
@Inject lateinit var databaseHelper: DatabaseHelperInterface
|
||||
@Inject lateinit var danaHistoryDatabase: DanaHistoryDatabase
|
||||
@Inject lateinit var insightDatabase: InsightDatabase
|
||||
@Inject lateinit var uel: UserEntryLogger
|
||||
@Inject lateinit var dataSyncSelector: DataSyncSelector
|
||||
@Inject lateinit var pumpSync: PumpSync
|
||||
|
@ -68,8 +70,9 @@ class MaintenanceFragment : DaggerFragment() {
|
|||
OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.maintenance), resourceHelper.gs(R.string.reset_db_confirm), Runnable {
|
||||
compositeDisposable.add(
|
||||
fromAction {
|
||||
databaseHelper.resetDatabases()
|
||||
repository.clearDatabases()
|
||||
danaHistoryDatabase.clearAllTables()
|
||||
insightDatabase.clearAllTables()
|
||||
dataSyncSelector.resetToNextFullSync()
|
||||
pumpSync.connectNewPump()
|
||||
}
|
||||
|
|
|
@ -2,14 +2,15 @@ package info.nightscout.androidaps.plugins.general.nsclient
|
|||
|
||||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.database.AppRepository
|
||||
import info.nightscout.androidaps.database.entities.DeviceStatus
|
||||
import info.nightscout.androidaps.database.ValueWrapper
|
||||
import info.nightscout.androidaps.database.entities.*
|
||||
import info.nightscout.androidaps.extensions.toJson
|
||||
import info.nightscout.androidaps.interfaces.ActivePlugin
|
||||
import info.nightscout.androidaps.interfaces.DataSyncSelector
|
||||
import info.nightscout.androidaps.interfaces.ProfileFunction
|
||||
import info.nightscout.androidaps.logging.AAPSLogger
|
||||
import info.nightscout.androidaps.logging.LTag
|
||||
import info.nightscout.androidaps.extensions.toJson
|
||||
import info.nightscout.androidaps.plugins.profile.local.LocalProfilePlugin
|
||||
import info.nightscout.androidaps.utils.DateUtil
|
||||
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
||||
import javax.inject.Inject
|
||||
|
@ -21,9 +22,28 @@ class DataSyncSelectorImplementation @Inject constructor(
|
|||
private val profileFunction: ProfileFunction,
|
||||
private val nsClientPlugin: NSClientPlugin,
|
||||
private val activePlugin: ActivePlugin,
|
||||
private val appRepository: AppRepository
|
||||
private val appRepository: AppRepository,
|
||||
private val localProfilePlugin: LocalProfilePlugin
|
||||
) : DataSyncSelector {
|
||||
|
||||
override fun doUpload() {
|
||||
if (sp.getBoolean(R.string.key_ns_upload, true)) {
|
||||
processChangedBolusesCompat()
|
||||
processChangedCarbsCompat()
|
||||
processChangedBolusCalculatorResultsCompat()
|
||||
processChangedTemporaryBasalsCompat()
|
||||
processChangedExtendedBolusesCompat()
|
||||
processChangedProfileSwitchesCompat()
|
||||
processChangedGlucoseValuesCompat()
|
||||
processChangedTempTargetsCompat()
|
||||
processChangedFoodsCompat()
|
||||
processChangedTherapyEventsCompat()
|
||||
processChangedDeviceStatusesCompat()
|
||||
processChangedOfflineEventsCompat()
|
||||
processChangedProfileStore()
|
||||
}
|
||||
}
|
||||
|
||||
override fun resetToNextFullSync() {
|
||||
sp.remove(R.string.key_ns_temporary_target_last_synced_id)
|
||||
sp.remove(R.string.key_ns_glucose_value_last_synced_id)
|
||||
|
@ -36,6 +56,8 @@ class DataSyncSelectorImplementation @Inject constructor(
|
|||
sp.remove(R.string.key_ns_extended_bolus_last_synced_id)
|
||||
sp.remove(R.string.key_ns_therapy_event_last_synced_id)
|
||||
sp.remove(R.string.key_ns_profile_switch_last_synced_id)
|
||||
sp.remove(R.string.key_ns_offline_event_last_synced_id)
|
||||
sp.remove(R.string.key_ns_profile_store_last_synced_timestamp)
|
||||
}
|
||||
|
||||
override fun confirmLastBolusIdIfGreater(lastSynced: Long) {
|
||||
|
@ -56,22 +78,28 @@ class DataSyncSelectorImplementation @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
private var lastBolusId = -1L
|
||||
private var lastBolusTime = -1L
|
||||
override fun processChangedBolusesCompat(): Boolean {
|
||||
val startId = sp.getLong(R.string.key_ns_bolus_last_synced_id, 0)
|
||||
val lastDbIdWrapped = appRepository.getLastBolusIdWrapped().blockingGet()
|
||||
val lastDbId = if (lastDbIdWrapped is ValueWrapper.Existing) lastDbIdWrapped.value else 0L
|
||||
var startId = sp.getLong(R.string.key_ns_bolus_last_synced_id, 0)
|
||||
if (startId > lastDbId) {
|
||||
sp.putLong(R.string.key_ns_bolus_last_synced_id, 0)
|
||||
startId = 0
|
||||
}
|
||||
if (startId == lastBolusId && dateUtil.now() - lastBolusTime < 5000) return false
|
||||
lastBolusId = startId
|
||||
lastBolusTime = dateUtil.now()
|
||||
appRepository.getNextSyncElementBolus(startId).blockingGet()?.let { bolus ->
|
||||
aapsLogger.info(LTag.DATABASE, "Loading Bolus data Start: $startId ID: ${bolus.first.id} HistoryID: ${bolus.second} ")
|
||||
when {
|
||||
// removed and not uploaded yet = ignore
|
||||
!bolus.first.isValid && bolus.first.interfaceIDs.nightscoutId == null -> Any()
|
||||
// removed and already uploaded = send for removal
|
||||
!bolus.first.isValid && bolus.first.interfaceIDs.nightscoutId != null ->
|
||||
nsClientPlugin.nsClientService?.dbRemove("treatments", bolus.first.interfaceIDs.nightscoutId, DataSyncSelector.PairBolus(bolus.first, bolus.second))
|
||||
// existing without nsId = create new
|
||||
bolus.first.isValid && bolus.first.interfaceIDs.nightscoutId == null ->
|
||||
nsClientPlugin.nsClientService?.dbAdd("treatments", bolus.first.toJson(dateUtil), DataSyncSelector.PairBolus(bolus.first, bolus.second))
|
||||
// existing with nsId = update
|
||||
bolus.first.isValid && bolus.first.interfaceIDs.nightscoutId != null ->
|
||||
nsClientPlugin.nsClientService?.dbUpdate("treatments", bolus.first.interfaceIDs.nightscoutId, bolus.first.toJson(dateUtil), DataSyncSelector.PairBolus(bolus.first, bolus.second))
|
||||
// without nsId = create new
|
||||
bolus.first.interfaceIDs.nightscoutId == null ->
|
||||
nsClientPlugin.nsClientService?.dbAdd("treatments", bolus.first.toJson(true, dateUtil), DataSyncSelector.PairBolus(bolus.first, bolus.second), "$startId/$lastDbId")
|
||||
// with nsId = update
|
||||
bolus.first.interfaceIDs.nightscoutId != null ->
|
||||
nsClientPlugin.nsClientService?.dbUpdate("treatments", bolus.first.interfaceIDs.nightscoutId, bolus.first.toJson(false, dateUtil), DataSyncSelector.PairBolus(bolus.first, bolus.second), "$startId/$lastDbId")
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
@ -93,22 +121,28 @@ class DataSyncSelectorImplementation @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
private var lastCarbsId = -1L
|
||||
private var lastCarbsTime = -1L
|
||||
override fun processChangedCarbsCompat(): Boolean {
|
||||
val startId = sp.getLong(R.string.key_ns_carbs_last_synced_id, 0)
|
||||
val lastDbIdWrapped = appRepository.getLastCarbsIdWrapped().blockingGet()
|
||||
val lastDbId = if (lastDbIdWrapped is ValueWrapper.Existing) lastDbIdWrapped.value else 0L
|
||||
var startId = sp.getLong(R.string.key_ns_carbs_last_synced_id, 0)
|
||||
if (startId > lastDbId) {
|
||||
sp.putLong(R.string.key_ns_carbs_last_synced_id, 0)
|
||||
startId = 0
|
||||
}
|
||||
if (startId == lastCarbsId && dateUtil.now() - lastCarbsTime < 5000) return false
|
||||
lastCarbsId = startId
|
||||
lastCarbsTime = dateUtil.now()
|
||||
appRepository.getNextSyncElementCarbs(startId).blockingGet()?.let { carb ->
|
||||
aapsLogger.info(LTag.DATABASE, "Loading Carbs data Start: $startId ID: ${carb.first.id} HistoryID: ${carb.second} ")
|
||||
when {
|
||||
// removed and not uploaded yet = ignore
|
||||
!carb.first.isValid && carb.first.interfaceIDs.nightscoutId == null -> Any()
|
||||
// removed and already uploaded = send for removal
|
||||
!carb.first.isValid && carb.first.interfaceIDs.nightscoutId != null ->
|
||||
nsClientPlugin.nsClientService?.dbRemove("treatments", carb.first.interfaceIDs.nightscoutId, DataSyncSelector.PairCarbs(carb.first, carb.second))
|
||||
// existing without nsId = create new
|
||||
carb.first.isValid && carb.first.interfaceIDs.nightscoutId == null ->
|
||||
nsClientPlugin.nsClientService?.dbAdd("treatments", carb.first.toJson(dateUtil), DataSyncSelector.PairCarbs(carb.first, carb.second))
|
||||
// existing with nsId = update
|
||||
carb.first.isValid && carb.first.interfaceIDs.nightscoutId != null ->
|
||||
nsClientPlugin.nsClientService?.dbUpdate("treatments", carb.first.interfaceIDs.nightscoutId, carb.first.toJson(dateUtil), DataSyncSelector.PairCarbs(carb.first, carb.second))
|
||||
// without nsId = create new
|
||||
carb.first.interfaceIDs.nightscoutId == null ->
|
||||
nsClientPlugin.nsClientService?.dbAdd("treatments", carb.first.toJson(true, dateUtil), DataSyncSelector.PairCarbs(carb.first, carb.second), "$startId/$lastDbId")
|
||||
// with nsId = update
|
||||
carb.first.interfaceIDs.nightscoutId != null ->
|
||||
nsClientPlugin.nsClientService?.dbUpdate("treatments", carb.first.interfaceIDs.nightscoutId, carb.first.toJson(false, dateUtil), DataSyncSelector.PairCarbs(carb.first, carb.second), "$startId/$lastDbId")
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
@ -130,22 +164,28 @@ class DataSyncSelectorImplementation @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
private var lastBcrId = -1L
|
||||
private var lastBcrTime = -1L
|
||||
override fun processChangedBolusCalculatorResultsCompat(): Boolean {
|
||||
val startId = sp.getLong(R.string.key_ns_bolus_calculator_result_last_synced_id, 0)
|
||||
val lastDbIdWrapped = appRepository.getLastBolusCalculatorResultIdWrapped().blockingGet()
|
||||
val lastDbId = if (lastDbIdWrapped is ValueWrapper.Existing) lastDbIdWrapped.value else 0L
|
||||
var startId = sp.getLong(R.string.key_ns_bolus_calculator_result_last_synced_id, 0)
|
||||
if (startId > lastDbId) {
|
||||
sp.putLong(R.string.key_ns_bolus_calculator_result_last_synced_id, 0)
|
||||
startId = 0
|
||||
}
|
||||
if (startId == lastBcrId && dateUtil.now() - lastBcrTime < 5000) return false
|
||||
lastBcrId = startId
|
||||
lastBcrTime = dateUtil.now()
|
||||
appRepository.getNextSyncElementBolusCalculatorResult(startId).blockingGet()?.let { bolusCalculatorResult ->
|
||||
aapsLogger.info(LTag.DATABASE, "Loading BolusCalculatorResult data Start: $startId ID: ${bolusCalculatorResult.first.id} HistoryID: ${bolusCalculatorResult.second} ")
|
||||
when {
|
||||
// removed and not uploaded yet = ignore
|
||||
!bolusCalculatorResult.first.isValid && bolusCalculatorResult.first.interfaceIDs.nightscoutId == null -> Any()
|
||||
// removed and already uploaded = send for removal
|
||||
!bolusCalculatorResult.first.isValid && bolusCalculatorResult.first.interfaceIDs.nightscoutId != null ->
|
||||
nsClientPlugin.nsClientService?.dbRemove("treatments", bolusCalculatorResult.first.interfaceIDs.nightscoutId, DataSyncSelector.PairBolusCalculatorResult(bolusCalculatorResult.first, bolusCalculatorResult.second))
|
||||
// existing without nsId = create new
|
||||
bolusCalculatorResult.first.isValid && bolusCalculatorResult.first.interfaceIDs.nightscoutId == null ->
|
||||
nsClientPlugin.nsClientService?.dbAdd("treatments", bolusCalculatorResult.first.toJson(dateUtil), DataSyncSelector.PairBolusCalculatorResult(bolusCalculatorResult.first, bolusCalculatorResult.second))
|
||||
// existing with nsId = update
|
||||
bolusCalculatorResult.first.isValid && bolusCalculatorResult.first.interfaceIDs.nightscoutId != null ->
|
||||
nsClientPlugin.nsClientService?.dbUpdate("treatments", bolusCalculatorResult.first.interfaceIDs.nightscoutId, bolusCalculatorResult.first.toJson(dateUtil), DataSyncSelector.PairBolusCalculatorResult(bolusCalculatorResult.first, bolusCalculatorResult.second))
|
||||
// without nsId = create new
|
||||
bolusCalculatorResult.first.interfaceIDs.nightscoutId == null ->
|
||||
nsClientPlugin.nsClientService?.dbAdd("treatments", bolusCalculatorResult.first.toJson(true, dateUtil), DataSyncSelector.PairBolusCalculatorResult(bolusCalculatorResult.first, bolusCalculatorResult.second), "$startId/$lastDbId")
|
||||
// with nsId = update
|
||||
bolusCalculatorResult.first.interfaceIDs.nightscoutId != null ->
|
||||
nsClientPlugin.nsClientService?.dbUpdate("treatments", bolusCalculatorResult.first.interfaceIDs.nightscoutId, bolusCalculatorResult.first.toJson(false, dateUtil), DataSyncSelector.PairBolusCalculatorResult(bolusCalculatorResult.first, bolusCalculatorResult.second), "$startId/$lastDbId")
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
@ -167,22 +207,28 @@ class DataSyncSelectorImplementation @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
private var lastTtId = -1L
|
||||
private var lastTtTime = -1L
|
||||
override fun processChangedTempTargetsCompat(): Boolean {
|
||||
val startId = sp.getLong(R.string.key_ns_temporary_target_last_synced_id, 0)
|
||||
val lastDbIdWrapped = appRepository.getLastTempTargetIdWrapped().blockingGet()
|
||||
val lastDbId = if (lastDbIdWrapped is ValueWrapper.Existing) lastDbIdWrapped.value else 0L
|
||||
var startId = sp.getLong(R.string.key_ns_temporary_target_last_synced_id, 0)
|
||||
if (startId > lastDbId) {
|
||||
sp.putLong(R.string.key_ns_temporary_target_last_synced_id, 0)
|
||||
startId = 0
|
||||
}
|
||||
if (startId == lastTtId && dateUtil.now() - lastTtTime < 5000) return false
|
||||
lastTtId = startId
|
||||
lastTtTime = dateUtil.now()
|
||||
appRepository.getNextSyncElementTemporaryTarget(startId).blockingGet()?.let { tt ->
|
||||
aapsLogger.info(LTag.DATABASE, "Loading TemporaryTarget data Start: $startId ID: ${tt.first.id} HistoryID: ${tt.second} ")
|
||||
when {
|
||||
// removed and not uploaded yet = ignore
|
||||
!tt.first.isValid && tt.first.interfaceIDs.nightscoutId == null -> Any()
|
||||
// removed and already uploaded = send for removal
|
||||
!tt.first.isValid && tt.first.interfaceIDs.nightscoutId != null ->
|
||||
nsClientPlugin.nsClientService?.dbRemove("treatments", tt.first.interfaceIDs.nightscoutId, DataSyncSelector.PairTemporaryTarget(tt.first, tt.second))
|
||||
// existing without nsId = create new
|
||||
tt.first.isValid && tt.first.interfaceIDs.nightscoutId == null ->
|
||||
nsClientPlugin.nsClientService?.dbAdd("treatments", tt.first.toJson(profileFunction.getUnits(), dateUtil), DataSyncSelector.PairTemporaryTarget(tt.first, tt.second))
|
||||
// without nsId = create new
|
||||
tt.first.interfaceIDs.nightscoutId == null ->
|
||||
nsClientPlugin.nsClientService?.dbAdd("treatments", tt.first.toJson(true, profileFunction.getUnits(), dateUtil), DataSyncSelector.PairTemporaryTarget(tt.first, tt.second), "$startId/$lastDbId")
|
||||
// existing with nsId = update
|
||||
tt.first.isValid && tt.first.interfaceIDs.nightscoutId != null ->
|
||||
nsClientPlugin.nsClientService?.dbUpdate("treatments", tt.first.interfaceIDs.nightscoutId, tt.first.toJson(profileFunction.getUnits(), dateUtil), DataSyncSelector.PairTemporaryTarget(tt.first, tt.second))
|
||||
tt.first.interfaceIDs.nightscoutId != null ->
|
||||
nsClientPlugin.nsClientService?.dbUpdate("treatments", tt.first.interfaceIDs.nightscoutId, tt.first.toJson(false, profileFunction.getUnits(), dateUtil), DataSyncSelector.PairTemporaryTarget(tt.first, tt.second), "$startId/$lastDbId")
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
@ -204,22 +250,28 @@ class DataSyncSelectorImplementation @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
private var lastFoodId = -1L
|
||||
private var lastFoodTime = -1L
|
||||
override fun processChangedFoodsCompat(): Boolean {
|
||||
val startId = sp.getLong(R.string.key_ns_food_last_synced_id, 0)
|
||||
appRepository.getNextSyncElementFood(startId).blockingGet()?.let { tt ->
|
||||
aapsLogger.info(LTag.DATABASE, "Loading Food data Start: $startId ID: ${tt.first.id} HistoryID: ${tt.second} ")
|
||||
val lastDbIdWrapped = appRepository.getLastFoodIdWrapped().blockingGet()
|
||||
val lastDbId = if (lastDbIdWrapped is ValueWrapper.Existing) lastDbIdWrapped.value else 0L
|
||||
var startId = sp.getLong(R.string.key_ns_food_last_synced_id, 0)
|
||||
if (startId > lastDbId) {
|
||||
sp.putLong(R.string.key_ns_food_last_synced_id, 0)
|
||||
startId = 0
|
||||
}
|
||||
if (startId == lastFoodId && dateUtil.now() - lastFoodTime < 5000) return false
|
||||
lastFoodId = startId
|
||||
lastFoodTime = dateUtil.now()
|
||||
appRepository.getNextSyncElementFood(startId).blockingGet()?.let { food ->
|
||||
aapsLogger.info(LTag.DATABASE, "Loading Food data Start: $startId ID: ${food.first.id} HistoryID: ${food.second} ")
|
||||
when {
|
||||
// removed and not uploaded yet = ignore
|
||||
!tt.first.isValid && tt.first.interfaceIDs.nightscoutId == null -> Any()
|
||||
// removed and already uploaded = send for removal
|
||||
!tt.first.isValid && tt.first.interfaceIDs.nightscoutId != null ->
|
||||
nsClientPlugin.nsClientService?.dbRemove("food", tt.first.interfaceIDs.nightscoutId, DataSyncSelector.PairFood(tt.first, tt.second))
|
||||
// existing without nsId = create new
|
||||
tt.first.isValid && tt.first.interfaceIDs.nightscoutId == null ->
|
||||
nsClientPlugin.nsClientService?.dbAdd("food", tt.first.toJson(), DataSyncSelector.PairFood(tt.first, tt.second))
|
||||
// existing with nsId = update
|
||||
tt.first.isValid && tt.first.interfaceIDs.nightscoutId != null ->
|
||||
nsClientPlugin.nsClientService?.dbUpdate("food", tt.first.interfaceIDs.nightscoutId, tt.first.toJson(), DataSyncSelector.PairFood(tt.first, tt.second))
|
||||
// without nsId = create new
|
||||
food.first.interfaceIDs.nightscoutId == null ->
|
||||
nsClientPlugin.nsClientService?.dbAdd("food", food.first.toJson(true), DataSyncSelector.PairFood(food.first, food.second), "$startId/$lastDbId")
|
||||
// with nsId = update
|
||||
food.first.interfaceIDs.nightscoutId != null ->
|
||||
nsClientPlugin.nsClientService?.dbUpdate("food", food.first.interfaceIDs.nightscoutId, food.first.toJson(false), DataSyncSelector.PairFood(food.first, food.second), "$startId/$lastDbId")
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
@ -241,25 +293,35 @@ class DataSyncSelectorImplementation @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
private var lastGvId = -1L
|
||||
private var lastGvTime = -1L
|
||||
override fun processChangedGlucoseValuesCompat(): Boolean {
|
||||
val startId = sp.getLong(R.string.key_ns_glucose_value_last_synced_id, 0)
|
||||
val lastDbIdWrapped = appRepository.getLastGlucoseValueIdWrapped().blockingGet()
|
||||
val lastDbId = if (lastDbIdWrapped is ValueWrapper.Existing) lastDbIdWrapped.value else 0L
|
||||
var startId = sp.getLong(R.string.key_ns_glucose_value_last_synced_id, 0)
|
||||
if (startId > lastDbId) {
|
||||
sp.putLong(R.string.key_ns_glucose_value_last_synced_id, 0)
|
||||
startId = 0
|
||||
}
|
||||
if (startId == lastGvId && dateUtil.now() - lastGvTime < 5000) return false
|
||||
lastGvId = startId
|
||||
lastGvTime = dateUtil.now()
|
||||
appRepository.getNextSyncElementGlucoseValue(startId).blockingGet()?.let { gv ->
|
||||
aapsLogger.info(LTag.DATABASE, "Loading GlucoseValue data Start: $startId ID: ${gv.first.id} HistoryID: ${gv.second} ")
|
||||
if (activePlugin.activeBgSource.shouldUploadToNs(gv.first)) {
|
||||
when {
|
||||
// removed and not uploaded yet = ignore
|
||||
!gv.first.isValid && gv.first.interfaceIDs.nightscoutId == null -> Any()
|
||||
// removed and already uploaded = send for removal
|
||||
!gv.first.isValid && gv.first.interfaceIDs.nightscoutId != null ->
|
||||
nsClientPlugin.nsClientService?.dbRemove("entries", gv.first.interfaceIDs.nightscoutId, DataSyncSelector.PairGlucoseValue(gv.first, gv.second))
|
||||
// existing without nsId = create new
|
||||
gv.first.isValid && gv.first.interfaceIDs.nightscoutId == null ->
|
||||
nsClientPlugin.nsClientService?.dbAdd("entries", gv.first.toJson(dateUtil), DataSyncSelector.PairGlucoseValue(gv.first, gv.second))
|
||||
// existing with nsId = update
|
||||
gv.first.isValid && gv.first.interfaceIDs.nightscoutId != null ->
|
||||
nsClientPlugin.nsClientService?.dbUpdate("entries", gv.first.interfaceIDs.nightscoutId, gv.first.toJson(dateUtil), DataSyncSelector.PairGlucoseValue(gv.first, gv.second))
|
||||
// without nsId = create new
|
||||
gv.first.interfaceIDs.nightscoutId == null ->
|
||||
nsClientPlugin.nsClientService?.dbAdd("entries", gv.first.toJson(true, dateUtil), DataSyncSelector.PairGlucoseValue(gv.first, gv.second), "$startId/$lastDbId")
|
||||
// with nsId = update
|
||||
gv.first.interfaceIDs.nightscoutId != null ->
|
||||
nsClientPlugin.nsClientService?.dbUpdate("entries", gv.first.interfaceIDs.nightscoutId, gv.first.toJson(false, dateUtil), DataSyncSelector.PairGlucoseValue(gv.first, gv.second), "$startId/$lastDbId")
|
||||
}
|
||||
return true
|
||||
} else {
|
||||
confirmLastGlucoseValueIdIfGreater(gv.second)
|
||||
lastGvId = -1
|
||||
processChangedGlucoseValuesCompat()
|
||||
}
|
||||
}
|
||||
return false
|
||||
|
@ -280,22 +342,28 @@ class DataSyncSelectorImplementation @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
private var lastTeId = -1L
|
||||
private var lastTeTime = -1L
|
||||
override fun processChangedTherapyEventsCompat(): Boolean {
|
||||
val startId = sp.getLong(R.string.key_ns_therapy_event_last_synced_id, 0)
|
||||
appRepository.getNextSyncElementTherapyEvent(startId).blockingGet()?.let { tt ->
|
||||
aapsLogger.info(LTag.DATABASE, "Loading TherapyEvents data Start: $startId ID: ${tt.first.id} HistoryID: ${tt.second} ")
|
||||
val lastDbIdWrapped = appRepository.getLastTherapyEventIdWrapped().blockingGet()
|
||||
val lastDbId = if (lastDbIdWrapped is ValueWrapper.Existing) lastDbIdWrapped.value else 0L
|
||||
var startId = sp.getLong(R.string.key_ns_therapy_event_last_synced_id, 0)
|
||||
if (startId > lastDbId) {
|
||||
sp.putLong(R.string.key_ns_therapy_event_last_synced_id, 0)
|
||||
startId = 0
|
||||
}
|
||||
if (startId == lastTeId && dateUtil.now() - lastTeTime < 5000) return false
|
||||
lastTeId = startId
|
||||
lastTeTime = dateUtil.now()
|
||||
appRepository.getNextSyncElementTherapyEvent(startId).blockingGet()?.let { te ->
|
||||
aapsLogger.info(LTag.DATABASE, "Loading TherapyEvents data Start: $startId ID: ${te.first.id} HistoryID: ${te.second} ")
|
||||
when {
|
||||
// removed and not uploaded yet = ignore
|
||||
!tt.first.isValid && tt.first.interfaceIDs.nightscoutId == null -> Any()
|
||||
// removed and already uploaded = send for removal
|
||||
!tt.first.isValid && tt.first.interfaceIDs.nightscoutId != null ->
|
||||
nsClientPlugin.nsClientService?.dbRemove("treatments", tt.first.interfaceIDs.nightscoutId, DataSyncSelector.PairTherapyEvent(tt.first, tt.second))
|
||||
// existing without nsId = create new
|
||||
tt.first.isValid && tt.first.interfaceIDs.nightscoutId == null ->
|
||||
nsClientPlugin.nsClientService?.dbAdd("treatments", tt.first.toJson(), DataSyncSelector.PairTherapyEvent(tt.first, tt.second))
|
||||
// existing with nsId = update
|
||||
tt.first.isValid && tt.first.interfaceIDs.nightscoutId != null ->
|
||||
nsClientPlugin.nsClientService?.dbUpdate("treatments", tt.first.interfaceIDs.nightscoutId, tt.first.toJson(), DataSyncSelector.PairTherapyEvent(tt.first, tt.second))
|
||||
// without nsId = create new
|
||||
te.first.interfaceIDs.nightscoutId == null ->
|
||||
nsClientPlugin.nsClientService?.dbAdd("treatments", te.first.toJson(true), DataSyncSelector.PairTherapyEvent(te.first, te.second), "$startId/$lastDbId")
|
||||
// nsId = update
|
||||
te.first.interfaceIDs.nightscoutId != null ->
|
||||
nsClientPlugin.nsClientService?.dbUpdate("treatments", te.first.interfaceIDs.nightscoutId, te.first.toJson(false), DataSyncSelector.PairTherapyEvent(te.first, te.second), "$startId/$lastDbId")
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
@ -316,14 +384,25 @@ class DataSyncSelectorImplementation @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
private var lastDsId = -1L
|
||||
private var lastDsTime = -1L
|
||||
override fun processChangedDeviceStatusesCompat(): Boolean {
|
||||
val startId = sp.getLong(R.string.key_ns_device_status_last_synced_id, 0)
|
||||
val lastDbIdWrapped = appRepository.getLastDeviceStatusIdWrapped().blockingGet()
|
||||
val lastDbId = if (lastDbIdWrapped is ValueWrapper.Existing) lastDbIdWrapped.value else 0L
|
||||
var startId = sp.getLong(R.string.key_ns_device_status_last_synced_id, 0)
|
||||
if (startId > lastDbId) {
|
||||
sp.putLong(R.string.key_ns_device_status_last_synced_id, 0)
|
||||
startId = 0
|
||||
}
|
||||
if (startId == lastDsId && dateUtil.now() - lastDsTime < 5000) return false
|
||||
lastDsId = startId
|
||||
lastDsTime = dateUtil.now()
|
||||
appRepository.getNextSyncElementDeviceStatus(startId).blockingGet()?.let { deviceStatus ->
|
||||
aapsLogger.info(LTag.DATABASE, "Loading DeviceStatus data Start: $startId ID: ${deviceStatus.id}")
|
||||
when {
|
||||
// without nsId = create new
|
||||
deviceStatus.interfaceIDs.nightscoutId == null ->
|
||||
nsClientPlugin.nsClientService?.dbAdd("devicestatus", deviceStatus.toJson(dateUtil), deviceStatus)
|
||||
nsClientPlugin.nsClientService?.dbAdd("devicestatus", deviceStatus.toJson(dateUtil), deviceStatus, "$startId/$lastDbId")
|
||||
// with nsId = ignore
|
||||
deviceStatus.interfaceIDs.nightscoutId != null -> Any()
|
||||
}
|
||||
|
@ -347,25 +426,37 @@ class DataSyncSelectorImplementation @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
private var lastTbrId = -1L
|
||||
private var lastTbrTime = -1L
|
||||
override fun processChangedTemporaryBasalsCompat(): Boolean {
|
||||
val startId = sp.getLong(R.string.key_ns_temporary_basal_last_synced_id, 0)
|
||||
val useAbsolute = sp.getBoolean(R.string.key_ns_sync_use_absolute, false)
|
||||
val lastDbIdWrapped = appRepository.getLastTemporaryBasalIdWrapped().blockingGet()
|
||||
val lastDbId = if (lastDbIdWrapped is ValueWrapper.Existing) lastDbIdWrapped.value else 0L
|
||||
var startId = sp.getLong(R.string.key_ns_temporary_basal_last_synced_id, 0)
|
||||
if (startId > lastDbId) {
|
||||
sp.putLong(R.string.key_ns_temporary_basal_last_synced_id, 0)
|
||||
startId = 0
|
||||
}
|
||||
if (startId == lastTbrId && dateUtil.now() - lastTbrTime < 5000) return false
|
||||
lastTbrId = startId
|
||||
lastTbrTime = dateUtil.now()
|
||||
appRepository.getNextSyncElementTemporaryBasal(startId).blockingGet()?.let { tb ->
|
||||
aapsLogger.info(LTag.DATABASE, "Loading TemporaryBasal data Start: $startId ID: ${tb.first.id} HistoryID: ${tb.second} ")
|
||||
profileFunction.getProfile(tb.first.timestamp)?.let { profile ->
|
||||
val profile = profileFunction.getProfile(tb.first.timestamp)
|
||||
if (profile != null) {
|
||||
when {
|
||||
// removed and not uploaded yet = ignore
|
||||
!tb.first.isValid && tb.first.interfaceIDs.nightscoutId == null -> Any()
|
||||
// removed and already uploaded = send for removal
|
||||
!tb.first.isValid && tb.first.interfaceIDs.nightscoutId != null ->
|
||||
nsClientPlugin.nsClientService?.dbRemove("treatments", tb.first.interfaceIDs.nightscoutId, DataSyncSelector.PairTemporaryBasal(tb.first, tb.second))
|
||||
// existing without nsId = create new
|
||||
tb.first.isValid && tb.first.interfaceIDs.nightscoutId == null ->
|
||||
nsClientPlugin.nsClientService?.dbAdd("treatments", tb.first.toJson(profile, dateUtil), DataSyncSelector.PairTemporaryBasal(tb.first, tb.second))
|
||||
// existing with nsId = update
|
||||
tb.first.isValid && tb.first.interfaceIDs.nightscoutId != null ->
|
||||
nsClientPlugin.nsClientService?.dbUpdate("treatments", tb.first.interfaceIDs.nightscoutId, tb.first.toJson(profile, dateUtil), DataSyncSelector.PairTemporaryBasal(tb.first, tb.second))
|
||||
// without nsId = create new
|
||||
tb.first.interfaceIDs.nightscoutId == null ->
|
||||
nsClientPlugin.nsClientService?.dbAdd("treatments", tb.first.toJson(true, profile, dateUtil, useAbsolute), DataSyncSelector.PairTemporaryBasal(tb.first, tb.second), "$startId/$lastDbId")
|
||||
// with nsId = update
|
||||
tb.first.interfaceIDs.nightscoutId != null ->
|
||||
nsClientPlugin.nsClientService?.dbUpdate("treatments", tb.first.interfaceIDs.nightscoutId, tb.first.toJson(false, profile, dateUtil, useAbsolute), DataSyncSelector.PairTemporaryBasal(tb.first, tb.second), "$startId/$lastDbId")
|
||||
}
|
||||
return true
|
||||
} else {
|
||||
confirmLastTemporaryBasalIdIfGreater(tb.second)
|
||||
lastTbrId = -1
|
||||
processChangedTemporaryBasalsCompat()
|
||||
}
|
||||
}
|
||||
return false
|
||||
|
@ -386,25 +477,37 @@ class DataSyncSelectorImplementation @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
private var lastEbId = -1L
|
||||
private var lastEbTime = -1L
|
||||
override fun processChangedExtendedBolusesCompat(): Boolean {
|
||||
val startId = sp.getLong(R.string.key_ns_extended_bolus_last_synced_id, 0)
|
||||
val useAbsolute = sp.getBoolean(R.string.key_ns_sync_use_absolute, false)
|
||||
val lastDbIdWrapped = appRepository.getLastExtendedBolusIdWrapped().blockingGet()
|
||||
val lastDbId = if (lastDbIdWrapped is ValueWrapper.Existing) lastDbIdWrapped.value else 0L
|
||||
var startId = sp.getLong(R.string.key_ns_extended_bolus_last_synced_id, 0)
|
||||
if (startId > lastDbId) {
|
||||
sp.putLong(R.string.key_ns_extended_bolus_last_synced_id, 0)
|
||||
startId = 0
|
||||
}
|
||||
if (startId == lastEbId && dateUtil.now() - lastEbTime < 5000) return false
|
||||
lastEbId = startId
|
||||
lastEbTime = dateUtil.now()
|
||||
appRepository.getNextSyncElementExtendedBolus(startId).blockingGet()?.let { eb ->
|
||||
aapsLogger.info(LTag.DATABASE, "Loading ExtendedBolus data Start: $startId ID: ${eb.first.id} HistoryID: ${eb.second} ")
|
||||
profileFunction.getProfile(eb.first.timestamp)?.let { profile ->
|
||||
val profile = profileFunction.getProfile(eb.first.timestamp)
|
||||
if (profile != null) {
|
||||
when {
|
||||
// removed and not uploaded yet = ignore
|
||||
!eb.first.isValid && eb.first.interfaceIDs.nightscoutId == null -> Any()
|
||||
// removed and already uploaded = send for removal
|
||||
!eb.first.isValid && eb.first.interfaceIDs.nightscoutId != null ->
|
||||
nsClientPlugin.nsClientService?.dbRemove("treatments", eb.first.interfaceIDs.nightscoutId, DataSyncSelector.PairExtendedBolus(eb.first, eb.second))
|
||||
// existing without nsId = create new
|
||||
eb.first.isValid && eb.first.interfaceIDs.nightscoutId == null ->
|
||||
nsClientPlugin.nsClientService?.dbAdd("treatments", eb.first.toJson(profile, dateUtil), DataSyncSelector.PairExtendedBolus(eb.first, eb.second))
|
||||
// existing with nsId = update
|
||||
eb.first.isValid && eb.first.interfaceIDs.nightscoutId != null ->
|
||||
nsClientPlugin.nsClientService?.dbUpdate("treatments", eb.first.interfaceIDs.nightscoutId, eb.first.toJson(profile, dateUtil), DataSyncSelector.PairExtendedBolus(eb.first, eb.second))
|
||||
// without nsId = create new
|
||||
eb.first.interfaceIDs.nightscoutId == null ->
|
||||
nsClientPlugin.nsClientService?.dbAdd("treatments", eb.first.toJson(true, profile, dateUtil, useAbsolute), DataSyncSelector.PairExtendedBolus(eb.first, eb.second), "$startId/$lastDbId")
|
||||
// with nsId = update
|
||||
eb.first.interfaceIDs.nightscoutId != null ->
|
||||
nsClientPlugin.nsClientService?.dbUpdate("treatments", eb.first.interfaceIDs.nightscoutId, eb.first.toJson(false, profile, dateUtil, useAbsolute), DataSyncSelector.PairExtendedBolus(eb.first, eb.second), "$startId/$lastDbId")
|
||||
}
|
||||
return true
|
||||
} else {
|
||||
confirmLastExtendedBolusIdIfGreater(eb.second)
|
||||
lastEbId = -1
|
||||
processChangedExtendedBolusesCompat()
|
||||
}
|
||||
}
|
||||
return false
|
||||
|
@ -424,25 +527,88 @@ class DataSyncSelectorImplementation @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
private var lastPsId = -1L
|
||||
private var lastPsTime = -1L
|
||||
override fun processChangedProfileSwitchesCompat(): Boolean {
|
||||
val startId = sp.getLong(R.string.key_ns_profile_switch_last_synced_id, 0)
|
||||
appRepository.getNextSyncElementProfileSwitch(startId).blockingGet()?.let { eb ->
|
||||
aapsLogger.info(LTag.DATABASE, "Loading ProfileSwitch data Start: $startId ID: ${eb.first.id} HistoryID: ${eb.second} ")
|
||||
val lastDbIdWrapped = appRepository.getLastProfileSwitchIdWrapped().blockingGet()
|
||||
val lastDbId = if (lastDbIdWrapped is ValueWrapper.Existing) lastDbIdWrapped.value else 0L
|
||||
var startId = sp.getLong(R.string.key_ns_profile_switch_last_synced_id, 0)
|
||||
if (startId > lastDbId) {
|
||||
sp.putLong(R.string.key_ns_profile_switch_last_synced_id, 0)
|
||||
startId = 0
|
||||
}
|
||||
if (startId == lastPsId && dateUtil.now() - lastPsTime < 5000) return false
|
||||
lastPsId = startId
|
||||
lastPsTime = dateUtil.now()
|
||||
appRepository.getNextSyncElementProfileSwitch(startId).blockingGet()?.let { ps ->
|
||||
aapsLogger.info(LTag.DATABASE, "Loading ProfileSwitch data Start: $startId ID: ${ps.first.id} HistoryID: ${ps.second} ")
|
||||
when {
|
||||
// removed and not uploaded yet = ignore
|
||||
!eb.first.isValid && eb.first.interfaceIDs.nightscoutId == null -> Any()
|
||||
// removed and already uploaded = send for removal
|
||||
!eb.first.isValid && eb.first.interfaceIDs.nightscoutId != null ->
|
||||
nsClientPlugin.nsClientService?.dbRemove("treatments", eb.first.interfaceIDs.nightscoutId, DataSyncSelector.PairProfileSwitch(eb.first, eb.second))
|
||||
// existing without nsId = create new
|
||||
eb.first.isValid && eb.first.interfaceIDs.nightscoutId == null ->
|
||||
nsClientPlugin.nsClientService?.dbAdd("treatments", eb.first.toJson(dateUtil), DataSyncSelector.PairProfileSwitch(eb.first, eb.second))
|
||||
// existing with nsId = update
|
||||
eb.first.isValid && eb.first.interfaceIDs.nightscoutId != null ->
|
||||
nsClientPlugin.nsClientService?.dbUpdate("treatments", eb.first.interfaceIDs.nightscoutId, eb.first.toJson(dateUtil), DataSyncSelector.PairProfileSwitch(eb.first, eb.second))
|
||||
// without nsId = create new
|
||||
ps.first.interfaceIDs.nightscoutId == null ->
|
||||
nsClientPlugin.nsClientService?.dbAdd("treatments", ps.first.toJson(true, dateUtil), DataSyncSelector.PairProfileSwitch(ps.first, ps.second), "$startId/$lastDbId")
|
||||
// with nsId = update
|
||||
ps.first.interfaceIDs.nightscoutId != null ->
|
||||
nsClientPlugin.nsClientService?.dbUpdate("treatments", ps.first.interfaceIDs.nightscoutId, ps.first.toJson(false, dateUtil), DataSyncSelector.PairProfileSwitch(ps.first, ps.second), "$startId/$lastDbId")
|
||||
}
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
override fun confirmLastOfflineEventIdIfGreater(lastSynced: Long) {
|
||||
if (lastSynced > sp.getLong(R.string.key_ns_offline_event_last_synced_id, 0)) {
|
||||
aapsLogger.debug(LTag.NSCLIENT, "Setting OfflineEvent data sync from $lastSynced")
|
||||
sp.putLong(R.string.key_ns_offline_event_last_synced_id, lastSynced)
|
||||
}
|
||||
}
|
||||
|
||||
// Prepared for v3 (returns all modified after)
|
||||
override fun changedOfflineEvents(): List<OfflineEvent> {
|
||||
val startId = sp.getLong(R.string.key_ns_offline_event_last_synced_id, 0)
|
||||
return appRepository.getModifiedOfflineEventsDataFromId(startId).blockingGet().also {
|
||||
aapsLogger.debug(LTag.NSCLIENT, "Loading OfflineEvent data for sync from $startId. Records ${it.size}")
|
||||
}
|
||||
}
|
||||
|
||||
private var lastOeId = -1L
|
||||
private var lastOeTime = -1L
|
||||
override fun processChangedOfflineEventsCompat(): Boolean {
|
||||
val lastDbIdWrapped = appRepository.getLastOfflineEventIdWrapped().blockingGet()
|
||||
val lastDbId = if (lastDbIdWrapped is ValueWrapper.Existing) lastDbIdWrapped.value else 0L
|
||||
var startId = sp.getLong(R.string.key_ns_offline_event_last_synced_id, 0)
|
||||
if (startId > lastDbId) {
|
||||
sp.putLong(R.string.key_ns_offline_event_last_synced_id, 0)
|
||||
startId = 0
|
||||
}
|
||||
if (startId == lastOeId && dateUtil.now() - lastOeTime < 5000) return false
|
||||
lastOeId = startId
|
||||
lastOeTime = dateUtil.now()
|
||||
appRepository.getNextSyncElementOfflineEvent(startId).blockingGet()?.let { oe ->
|
||||
aapsLogger.info(LTag.DATABASE, "Loading OfflineEvent data Start: $startId ID: ${oe.first.id} HistoryID: ${oe.second} ")
|
||||
when {
|
||||
// without nsId = create new
|
||||
oe.first.interfaceIDs.nightscoutId == null ->
|
||||
nsClientPlugin.nsClientService?.dbAdd("treatments", oe.first.toJson(true, dateUtil), DataSyncSelector.PairOfflineEvent(oe.first, oe.second), "$startId/$lastDbId")
|
||||
// existing with nsId = update
|
||||
oe.first.interfaceIDs.nightscoutId != null ->
|
||||
nsClientPlugin.nsClientService?.dbUpdate("treatments", oe.first.interfaceIDs.nightscoutId, oe.first.toJson(false, dateUtil), DataSyncSelector.PairOfflineEvent(oe.first, oe.second), "$startId/$lastDbId")
|
||||
}
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
override fun confirmLastProfileStore(lastSynced: Long) {
|
||||
sp.putLong(R.string.key_ns_profile_store_last_synced_timestamp, lastSynced)
|
||||
}
|
||||
|
||||
override fun processChangedProfileStore() {
|
||||
val lastSync = sp.getLong(R.string.key_ns_profile_store_last_synced_timestamp, 0)
|
||||
val lastChange = sp.getLong(R.string.key_local_profile_last_change, 0)
|
||||
if (lastChange == 0L) return
|
||||
if (lastChange > lastSync) {
|
||||
val profileJson = localProfilePlugin.profile?.data ?: return
|
||||
nsClientPlugin.nsClientService?.dbAdd("profile", profileJson, DataSyncSelector.PairProfileStore(profileJson, dateUtil.now()), "")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -147,7 +147,7 @@ class NSClientAddAckWorker(
|
|||
dataSyncSelector.confirmLastCarbsIdIfGreater(pair.updateRecordId)
|
||||
}
|
||||
.blockingGet()
|
||||
rxBus.send(EventNSClientNewLog("DBADD", "Acked Carbs" + pair.value.interfaceIDs.nightscoutId))
|
||||
rxBus.send(EventNSClientNewLog("DBADD", "Acked Carbs " + pair.value.interfaceIDs.nightscoutId))
|
||||
// Send new if waiting
|
||||
dataSyncSelector.processChangedCarbsCompat()
|
||||
}
|
||||
|
@ -166,7 +166,7 @@ class NSClientAddAckWorker(
|
|||
dataSyncSelector.confirmLastBolusCalculatorResultsIdIfGreater(pair.updateRecordId)
|
||||
}
|
||||
.blockingGet()
|
||||
rxBus.send(EventNSClientNewLog("DBADD", "Acked BolusCalculatorResult" + pair.value.interfaceIDs.nightscoutId))
|
||||
rxBus.send(EventNSClientNewLog("DBADD", "Acked BolusCalculatorResult " + pair.value.interfaceIDs.nightscoutId))
|
||||
// Send new if waiting
|
||||
dataSyncSelector.processChangedBolusCalculatorResultsCompat()
|
||||
}
|
||||
|
@ -185,7 +185,7 @@ class NSClientAddAckWorker(
|
|||
dataSyncSelector.confirmLastTemporaryBasalIdIfGreater(pair.updateRecordId)
|
||||
}
|
||||
.blockingGet()
|
||||
rxBus.send(EventNSClientNewLog("DBADD", "Acked TemporaryBasal" + pair.value.interfaceIDs.nightscoutId))
|
||||
rxBus.send(EventNSClientNewLog("DBADD", "Acked TemporaryBasal " + pair.value.interfaceIDs.nightscoutId))
|
||||
// Send new if waiting
|
||||
dataSyncSelector.processChangedTemporaryBasalsCompat()
|
||||
}
|
||||
|
@ -204,9 +204,9 @@ class NSClientAddAckWorker(
|
|||
dataSyncSelector.confirmLastExtendedBolusIdIfGreater(pair.updateRecordId)
|
||||
}
|
||||
.blockingGet()
|
||||
rxBus.send(EventNSClientNewLog("DBADD", "Acked ExtendedBolus" + pair.value.interfaceIDs.nightscoutId))
|
||||
rxBus.send(EventNSClientNewLog("DBADD", "Acked ExtendedBolus " + pair.value.interfaceIDs.nightscoutId))
|
||||
// Send new if waiting
|
||||
dataSyncSelector.processChangedTemporaryBasalsCompat()
|
||||
dataSyncSelector.processChangedExtendedBolusesCompat()
|
||||
}
|
||||
|
||||
is PairProfileSwitch -> {
|
||||
|
@ -223,9 +223,9 @@ class NSClientAddAckWorker(
|
|||
dataSyncSelector.confirmLastProfileSwitchIdIfGreater(pair.updateRecordId)
|
||||
}
|
||||
.blockingGet()
|
||||
rxBus.send(EventNSClientNewLog("DBADD", "Acked ProfileSwitch" + pair.value.interfaceIDs.nightscoutId))
|
||||
rxBus.send(EventNSClientNewLog("DBADD", "Acked ProfileSwitch " + pair.value.interfaceIDs.nightscoutId))
|
||||
// Send new if waiting
|
||||
dataSyncSelector.processChangedTemporaryBasalsCompat()
|
||||
dataSyncSelector.processChangedProfileSwitchesCompat()
|
||||
}
|
||||
|
||||
is DeviceStatus -> {
|
||||
|
@ -242,10 +242,35 @@ class NSClientAddAckWorker(
|
|||
dataSyncSelector.confirmLastDeviceStatusIdIfGreater(deviceStatus.id)
|
||||
}
|
||||
.blockingGet()
|
||||
rxBus.send(EventNSClientNewLog("DBADD", "Acked DeviceStatus" + deviceStatus.interfaceIDs.nightscoutId))
|
||||
rxBus.send(EventNSClientNewLog("DBADD", "Acked DeviceStatus " + deviceStatus.interfaceIDs.nightscoutId))
|
||||
// Send new if waiting
|
||||
dataSyncSelector.processChangedDeviceStatusesCompat()
|
||||
}
|
||||
|
||||
is PairProfileStore -> {
|
||||
dataSyncSelector.confirmLastProfileStore(ack.originalObject.timestampSync)
|
||||
rxBus.send(EventNSClientNewLog("DBADD", "Acked ProfileStore " + ack.id))
|
||||
}
|
||||
|
||||
is PairOfflineEvent -> {
|
||||
val pair = ack.originalObject
|
||||
pair.value.interfaceIDs.nightscoutId = ack.id
|
||||
repository.runTransactionForResult(UpdateNsIdOfflineEventTransaction(pair.value))
|
||||
.doOnError { error ->
|
||||
aapsLogger.error(LTag.DATABASE, "Updated ns id of OfflineEvent failed", error)
|
||||
ret = Result.failure((workDataOf("Error" to error.toString())))
|
||||
}
|
||||
.doOnSuccess {
|
||||
ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
|
||||
aapsLogger.debug(LTag.DATABASE, "Updated ns id of OfflineEvent " + pair.value)
|
||||
dataSyncSelector.confirmLastOfflineEventIdIfGreater(pair.updateRecordId)
|
||||
}
|
||||
.blockingGet()
|
||||
rxBus.send(EventNSClientNewLog("DBADD", "Acked OfflineEvent " + pair.value.interfaceIDs.nightscoutId))
|
||||
// Send new if waiting
|
||||
dataSyncSelector.processChangedOfflineEventsCompat()
|
||||
}
|
||||
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ import info.nightscout.androidaps.database.entities.UserEntry.Sources
|
|||
import info.nightscout.androidaps.database.entities.ValueWithUnit
|
||||
import info.nightscout.androidaps.database.transactions.*
|
||||
import info.nightscout.androidaps.extensions.*
|
||||
import info.nightscout.androidaps.interfaces.ActivePlugin
|
||||
import info.nightscout.androidaps.interfaces.Config
|
||||
import info.nightscout.androidaps.logging.AAPSLogger
|
||||
import info.nightscout.androidaps.logging.LTag
|
||||
|
@ -43,13 +44,11 @@ class NSClientAddUpdateWorker(
|
|||
@Inject lateinit var dateUtil: DateUtil
|
||||
@Inject lateinit var config: Config
|
||||
@Inject lateinit var repository: AppRepository
|
||||
@Inject lateinit var activePlugin: ActivePlugin
|
||||
@Inject lateinit var rxBus: RxBusWrapper
|
||||
@Inject lateinit var uel: UserEntryLogger
|
||||
|
||||
override fun doWork(): Result {
|
||||
val acceptNSData = !sp.getBoolean(R.string.key_ns_upload_only, true) && buildHelper.isEngineeringMode() || config.NSCLIENT
|
||||
if (!acceptNSData) return Result.success()
|
||||
|
||||
val treatments = dataWorker.pickupJSONArray(inputData.getLong(DataWorker.STORE_KEY, -1))
|
||||
?: return Result.failure(workDataOf("Error" to "missing input data"))
|
||||
|
||||
|
@ -73,62 +72,66 @@ class NSClientAddUpdateWorker(
|
|||
if (mills > latestDateInReceivedData) latestDateInReceivedData = mills
|
||||
|
||||
if (insulin > 0) {
|
||||
bolusFromJson(json)?.let { bolus ->
|
||||
repository.runTransactionForResult(SyncNsBolusTransaction(bolus, invalidateByNsOnly = false))
|
||||
.doOnError {
|
||||
aapsLogger.error(LTag.DATABASE, "Error while saving bolus", it)
|
||||
ret = Result.failure(workDataOf("Error" to it.toString()))
|
||||
}
|
||||
.blockingGet()
|
||||
.also { result ->
|
||||
result.inserted.forEach {
|
||||
uel.log(Action.BOLUS, Sources.NSClient,
|
||||
ValueWithUnit.Timestamp(it.timestamp),
|
||||
ValueWithUnit.Insulin(it.amount)
|
||||
)
|
||||
aapsLogger.debug(LTag.DATABASE, "Inserted bolus $it")
|
||||
if (sp.getBoolean(R.string.key_ns_receive_insulin, false) && buildHelper.isEngineeringMode() || config.NSCLIENT) {
|
||||
bolusFromJson(json)?.let { bolus ->
|
||||
repository.runTransactionForResult(SyncNsBolusTransaction(bolus, invalidateByNsOnly = false))
|
||||
.doOnError {
|
||||
aapsLogger.error(LTag.DATABASE, "Error while saving bolus", it)
|
||||
ret = Result.failure(workDataOf("Error" to it.toString()))
|
||||
}
|
||||
result.invalidated.forEach {
|
||||
uel.log(Action.BOLUS_REMOVED, Sources.NSClient,
|
||||
ValueWithUnit.Timestamp(it.timestamp),
|
||||
ValueWithUnit.Insulin(it.amount)
|
||||
)
|
||||
aapsLogger.debug(LTag.DATABASE, "Invalidated bolus $it")
|
||||
.blockingGet()
|
||||
.also { result ->
|
||||
result.inserted.forEach {
|
||||
uel.log(Action.BOLUS, Sources.NSClient,
|
||||
ValueWithUnit.Timestamp(it.timestamp),
|
||||
ValueWithUnit.Insulin(it.amount)
|
||||
)
|
||||
aapsLogger.debug(LTag.DATABASE, "Inserted bolus $it")
|
||||
}
|
||||
result.invalidated.forEach {
|
||||
uel.log(Action.BOLUS_REMOVED, Sources.NSClient,
|
||||
ValueWithUnit.Timestamp(it.timestamp),
|
||||
ValueWithUnit.Insulin(it.amount)
|
||||
)
|
||||
aapsLogger.debug(LTag.DATABASE, "Invalidated bolus $it")
|
||||
}
|
||||
result.updatedNsId.forEach {
|
||||
aapsLogger.debug(LTag.DATABASE, "Updated nsId bolus $it")
|
||||
}
|
||||
}
|
||||
result.updatedNsId.forEach {
|
||||
aapsLogger.debug(LTag.DATABASE, "Updated nsId bolus $it")
|
||||
}
|
||||
}
|
||||
} ?: aapsLogger.error("Error parsing bolus json $json")
|
||||
} ?: aapsLogger.error("Error parsing bolus json $json")
|
||||
}
|
||||
}
|
||||
if (carbs > 0) {
|
||||
carbsFromJson(json)?.let { carb ->
|
||||
repository.runTransactionForResult(SyncNsCarbsTransaction(carb, invalidateByNsOnly = false))
|
||||
.doOnError {
|
||||
aapsLogger.error(LTag.DATABASE, "Error while saving carbs", it)
|
||||
ret = Result.failure(workDataOf("Error" to it.toString()))
|
||||
}
|
||||
.blockingGet()
|
||||
.also { result ->
|
||||
result.inserted.forEach {
|
||||
uel.log(Action.CARBS, Sources.NSClient,
|
||||
ValueWithUnit.Timestamp(it.timestamp),
|
||||
ValueWithUnit.Gram(it.amount.toInt())
|
||||
)
|
||||
aapsLogger.debug(LTag.DATABASE, "Inserted carbs $it")
|
||||
if (sp.getBoolean(R.string.key_ns_receive_carbs, false) && buildHelper.isEngineeringMode() || config.NSCLIENT) {
|
||||
carbsFromJson(json)?.let { carb ->
|
||||
repository.runTransactionForResult(SyncNsCarbsTransaction(carb, invalidateByNsOnly = false))
|
||||
.doOnError {
|
||||
aapsLogger.error(LTag.DATABASE, "Error while saving carbs", it)
|
||||
ret = Result.failure(workDataOf("Error" to it.toString()))
|
||||
}
|
||||
result.invalidated.forEach {
|
||||
uel.log(Action.CARBS_REMOVED, Sources.NSClient,
|
||||
ValueWithUnit.Timestamp(it.timestamp),
|
||||
ValueWithUnit.Gram(it.amount.toInt())
|
||||
)
|
||||
aapsLogger.debug(LTag.DATABASE, "Invalidated carbs $it")
|
||||
.blockingGet()
|
||||
.also { result ->
|
||||
result.inserted.forEach {
|
||||
uel.log(Action.CARBS, Sources.NSClient,
|
||||
ValueWithUnit.Timestamp(it.timestamp),
|
||||
ValueWithUnit.Gram(it.amount.toInt())
|
||||
)
|
||||
aapsLogger.debug(LTag.DATABASE, "Inserted carbs $it")
|
||||
}
|
||||
result.invalidated.forEach {
|
||||
uel.log(Action.CARBS_REMOVED, Sources.NSClient,
|
||||
ValueWithUnit.Timestamp(it.timestamp),
|
||||
ValueWithUnit.Gram(it.amount.toInt())
|
||||
)
|
||||
aapsLogger.debug(LTag.DATABASE, "Invalidated carbs $it")
|
||||
}
|
||||
result.updatedNsId.forEach {
|
||||
aapsLogger.debug(LTag.DATABASE, "Updated nsId carbs $it")
|
||||
}
|
||||
}
|
||||
result.updatedNsId.forEach {
|
||||
aapsLogger.debug(LTag.DATABASE, "Updated nsId carbs $it")
|
||||
}
|
||||
}
|
||||
} ?: aapsLogger.error("Error parsing bolus json $json")
|
||||
} ?: aapsLogger.error("Error parsing bolus json $json")
|
||||
}
|
||||
}
|
||||
// Convert back emulated TBR -> EB
|
||||
if (eventType == TherapyEvent.Type.TEMPORARY_BASAL.text && json.has("extendedEmulated")) {
|
||||
|
@ -140,46 +143,48 @@ class NSClientAddUpdateWorker(
|
|||
when {
|
||||
insulin > 0 || carbs > 0 -> Any()
|
||||
eventType == TherapyEvent.Type.TEMPORARY_TARGET.text ->
|
||||
temporaryTargetFromJson(json)?.let { temporaryTarget ->
|
||||
repository.runTransactionForResult(SyncNsTemporaryTargetTransaction(temporaryTarget, invalidateByNsOnly = false))
|
||||
.doOnError {
|
||||
aapsLogger.error(LTag.DATABASE, "Error while saving temporary target", it)
|
||||
ret = Result.failure(workDataOf("Error" to it.toString()))
|
||||
}
|
||||
.blockingGet()
|
||||
.also { result ->
|
||||
result.inserted.forEach { tt ->
|
||||
uel.log(Action.TT, Sources.NSClient,
|
||||
ValueWithUnit.TherapyEventTTReason(tt.reason),
|
||||
ValueWithUnit.fromGlucoseUnit(tt.lowTarget, Constants.MGDL),
|
||||
ValueWithUnit.fromGlucoseUnit(tt.highTarget, Constants.MGDL).takeIf { tt.lowTarget != tt.highTarget },
|
||||
ValueWithUnit.Minute(TimeUnit.MILLISECONDS.toMinutes(tt.duration).toInt())
|
||||
)
|
||||
aapsLogger.debug(LTag.DATABASE, "Inserted TemporaryTarget $tt")
|
||||
if (sp.getBoolean(R.string.key_ns_receive_temp_target, false) && buildHelper.isEngineeringMode() || config.NSCLIENT) {
|
||||
temporaryTargetFromJson(json)?.let { temporaryTarget ->
|
||||
repository.runTransactionForResult(SyncNsTemporaryTargetTransaction(temporaryTarget, invalidateByNsOnly = false))
|
||||
.doOnError {
|
||||
aapsLogger.error(LTag.DATABASE, "Error while saving temporary target", it)
|
||||
ret = Result.failure(workDataOf("Error" to it.toString()))
|
||||
}
|
||||
result.invalidated.forEach { tt ->
|
||||
uel.log(Action.TT_REMOVED, Sources.NSClient,
|
||||
ValueWithUnit.TherapyEventTTReason(tt.reason),
|
||||
ValueWithUnit.Mgdl(tt.lowTarget),
|
||||
ValueWithUnit.Mgdl(tt.highTarget).takeIf { tt.lowTarget != tt.highTarget },
|
||||
ValueWithUnit.Minute(TimeUnit.MILLISECONDS.toMinutes(tt.duration).toInt())
|
||||
)
|
||||
aapsLogger.debug(LTag.DATABASE, "Invalidated TemporaryTarget $tt")
|
||||
.blockingGet()
|
||||
.also { result ->
|
||||
result.inserted.forEach { tt ->
|
||||
uel.log(Action.TT, Sources.NSClient,
|
||||
ValueWithUnit.TherapyEventTTReason(tt.reason),
|
||||
ValueWithUnit.fromGlucoseUnit(tt.lowTarget, Constants.MGDL),
|
||||
ValueWithUnit.fromGlucoseUnit(tt.highTarget, Constants.MGDL).takeIf { tt.lowTarget != tt.highTarget },
|
||||
ValueWithUnit.Minute(TimeUnit.MILLISECONDS.toMinutes(tt.duration).toInt())
|
||||
)
|
||||
aapsLogger.debug(LTag.DATABASE, "Inserted TemporaryTarget $tt")
|
||||
}
|
||||
result.invalidated.forEach { tt ->
|
||||
uel.log(Action.TT_REMOVED, Sources.NSClient,
|
||||
ValueWithUnit.TherapyEventTTReason(tt.reason),
|
||||
ValueWithUnit.Mgdl(tt.lowTarget),
|
||||
ValueWithUnit.Mgdl(tt.highTarget).takeIf { tt.lowTarget != tt.highTarget },
|
||||
ValueWithUnit.Minute(TimeUnit.MILLISECONDS.toMinutes(tt.duration).toInt())
|
||||
)
|
||||
aapsLogger.debug(LTag.DATABASE, "Invalidated TemporaryTarget $tt")
|
||||
}
|
||||
result.ended.forEach { tt ->
|
||||
uel.log(Action.CANCEL_TT, Sources.NSClient,
|
||||
ValueWithUnit.TherapyEventTTReason(tt.reason),
|
||||
ValueWithUnit.Mgdl(tt.lowTarget),
|
||||
ValueWithUnit.Mgdl(tt.highTarget).takeIf { tt.lowTarget != tt.highTarget },
|
||||
ValueWithUnit.Minute(TimeUnit.MILLISECONDS.toMinutes(tt.duration).toInt())
|
||||
)
|
||||
aapsLogger.debug(LTag.DATABASE, "Updated TemporaryTarget $tt")
|
||||
}
|
||||
result.updatedNsId.forEach {
|
||||
aapsLogger.debug(LTag.DATABASE, "Updated nsId TemporaryTarget $it")
|
||||
}
|
||||
}
|
||||
result.ended.forEach { tt ->
|
||||
uel.log(Action.CANCEL_TT, Sources.NSClient,
|
||||
ValueWithUnit.TherapyEventTTReason(tt.reason),
|
||||
ValueWithUnit.Mgdl(tt.lowTarget),
|
||||
ValueWithUnit.Mgdl(tt.highTarget).takeIf { tt.lowTarget != tt.highTarget },
|
||||
ValueWithUnit.Minute(TimeUnit.MILLISECONDS.toMinutes(tt.duration).toInt())
|
||||
)
|
||||
aapsLogger.debug(LTag.DATABASE, "Updated TemporaryTarget $tt")
|
||||
}
|
||||
result.updatedNsId.forEach {
|
||||
aapsLogger.debug(LTag.DATABASE, "Updated nsId TemporaryTarget $it")
|
||||
}
|
||||
}
|
||||
} ?: aapsLogger.error("Error parsing TT json $json")
|
||||
} ?: aapsLogger.error("Error parsing TT json $json")
|
||||
}
|
||||
eventType == TherapyEvent.Type.CANNULA_CHANGE.text ||
|
||||
eventType == TherapyEvent.Type.INSULIN_CHANGE.text ||
|
||||
eventType == TherapyEvent.Type.SENSOR_CHANGE.text ||
|
||||
|
@ -188,160 +193,205 @@ class NSClientAddUpdateWorker(
|
|||
eventType == TherapyEvent.Type.ANNOUNCEMENT.text ||
|
||||
eventType == TherapyEvent.Type.QUESTION.text ||
|
||||
eventType == TherapyEvent.Type.EXERCISE.text ||
|
||||
eventType == TherapyEvent.Type.APS_OFFLINE.text ||
|
||||
eventType == TherapyEvent.Type.PUMP_BATTERY_CHANGE.text ->
|
||||
therapyEventFromJson(json)?.let { therapyEvent ->
|
||||
repository.runTransactionForResult(SyncNsTherapyEventTransaction(therapyEvent, invalidateByNsOnly = false))
|
||||
.doOnError {
|
||||
aapsLogger.error(LTag.DATABASE, "Error while saving therapy event", it)
|
||||
ret = Result.failure(workDataOf("Error" to it.toString()))
|
||||
}
|
||||
.blockingGet()
|
||||
.also { result ->
|
||||
val action = when (eventType) {
|
||||
TherapyEvent.Type.CANNULA_CHANGE.text -> Action.SITE_CHANGE
|
||||
TherapyEvent.Type.INSULIN_CHANGE.text -> Action.RESERVOIR_CHANGE
|
||||
else -> Action.CAREPORTAL
|
||||
if (sp.getBoolean(R.string.key_ns_receive_therapy_events, false) || config.NSCLIENT) {
|
||||
therapyEventFromJson(json)?.let { therapyEvent ->
|
||||
repository.runTransactionForResult(SyncNsTherapyEventTransaction(therapyEvent, invalidateByNsOnly = false))
|
||||
.doOnError {
|
||||
aapsLogger.error(LTag.DATABASE, "Error while saving therapy event", it)
|
||||
ret = Result.failure(workDataOf("Error" to it.toString()))
|
||||
}
|
||||
result.inserted.forEach {
|
||||
uel.log(action, Sources.NSClient,
|
||||
it.note ?: "",
|
||||
ValueWithUnit.Timestamp(it.timestamp),
|
||||
ValueWithUnit.TherapyEventType(it.type)
|
||||
)
|
||||
aapsLogger.debug(LTag.DATABASE, "Inserted TherapyEvent $it")
|
||||
.blockingGet()
|
||||
.also { result ->
|
||||
val action = when (eventType) {
|
||||
TherapyEvent.Type.CANNULA_CHANGE.text -> Action.SITE_CHANGE
|
||||
TherapyEvent.Type.INSULIN_CHANGE.text -> Action.RESERVOIR_CHANGE
|
||||
else -> Action.CAREPORTAL
|
||||
}
|
||||
result.inserted.forEach {
|
||||
uel.log(action, Sources.NSClient,
|
||||
it.note ?: "",
|
||||
ValueWithUnit.Timestamp(it.timestamp),
|
||||
ValueWithUnit.TherapyEventType(it.type)
|
||||
)
|
||||
aapsLogger.debug(LTag.DATABASE, "Inserted TherapyEvent $it")
|
||||
}
|
||||
result.invalidated.forEach {
|
||||
uel.log(Action.CAREPORTAL_REMOVED, Sources.NSClient,
|
||||
it.note ?: "",
|
||||
ValueWithUnit.Timestamp(it.timestamp),
|
||||
ValueWithUnit.TherapyEventType(it.type)
|
||||
)
|
||||
aapsLogger.debug(LTag.DATABASE, "Invalidated TherapyEvent $it")
|
||||
}
|
||||
result.updatedNsId.forEach {
|
||||
aapsLogger.debug(LTag.DATABASE, "Updated nsId TherapyEvent $it")
|
||||
}
|
||||
}
|
||||
result.invalidated.forEach {
|
||||
uel.log(Action.CAREPORTAL_REMOVED, Sources.NSClient,
|
||||
it.note ?: "",
|
||||
ValueWithUnit.Timestamp(it.timestamp),
|
||||
ValueWithUnit.TherapyEventType(it.type)
|
||||
)
|
||||
aapsLogger.debug(LTag.DATABASE, "Invalidated TherapyEvent $it")
|
||||
}
|
||||
result.updatedNsId.forEach {
|
||||
aapsLogger.debug(LTag.DATABASE, "Updated nsId TherapyEvent $it")
|
||||
}
|
||||
}
|
||||
} ?: aapsLogger.error("Error parsing TherapyEvent json $json")
|
||||
} ?: aapsLogger.error("Error parsing TherapyEvent json $json")
|
||||
}
|
||||
eventType == TherapyEvent.Type.COMBO_BOLUS.text ->
|
||||
extendedBolusFromJson(json)?.let { extendedBolus ->
|
||||
repository.runTransactionForResult(SyncNsExtendedBolusTransaction(extendedBolus, invalidateByNsOnly = false))
|
||||
.doOnError {
|
||||
aapsLogger.error(LTag.DATABASE, "Error while saving extended bolus", it)
|
||||
ret = Result.failure(workDataOf("Error" to it.toString()))
|
||||
}
|
||||
.blockingGet()
|
||||
.also { result ->
|
||||
result.inserted.forEach {
|
||||
uel.log(Action.EXTENDED_BOLUS, Sources.NSClient,
|
||||
ValueWithUnit.Timestamp(it.timestamp),
|
||||
ValueWithUnit.Insulin(it.amount),
|
||||
ValueWithUnit.UnitPerHour(it.rate),
|
||||
ValueWithUnit.Minute(TimeUnit.MILLISECONDS.toMinutes(it.duration).toInt())
|
||||
)
|
||||
aapsLogger.debug(LTag.DATABASE, "Inserted ExtendedBolus $it")
|
||||
if (config.NSCLIENT) {
|
||||
extendedBolusFromJson(json)?.let { extendedBolus ->
|
||||
repository.runTransactionForResult(SyncNsExtendedBolusTransaction(extendedBolus, invalidateByNsOnly = false))
|
||||
.doOnError {
|
||||
aapsLogger.error(LTag.DATABASE, "Error while saving extended bolus", it)
|
||||
ret = Result.failure(workDataOf("Error" to it.toString()))
|
||||
}
|
||||
result.invalidated.forEach {
|
||||
uel.log(Action.EXTENDED_BOLUS_REMOVED, Sources.NSClient,
|
||||
ValueWithUnit.Timestamp(it.timestamp),
|
||||
ValueWithUnit.Insulin(it.amount),
|
||||
ValueWithUnit.UnitPerHour(it.rate),
|
||||
ValueWithUnit.Minute(TimeUnit.MILLISECONDS.toMinutes(it.duration).toInt())
|
||||
)
|
||||
aapsLogger.debug(LTag.DATABASE, "Invalidated ExtendedBolus $it")
|
||||
.blockingGet()
|
||||
.also { result ->
|
||||
result.inserted.forEach {
|
||||
uel.log(Action.EXTENDED_BOLUS, Sources.NSClient,
|
||||
ValueWithUnit.Timestamp(it.timestamp),
|
||||
ValueWithUnit.Insulin(it.amount),
|
||||
ValueWithUnit.UnitPerHour(it.rate),
|
||||
ValueWithUnit.Minute(TimeUnit.MILLISECONDS.toMinutes(it.duration).toInt())
|
||||
)
|
||||
aapsLogger.debug(LTag.DATABASE, "Inserted ExtendedBolus $it")
|
||||
}
|
||||
result.invalidated.forEach {
|
||||
uel.log(Action.EXTENDED_BOLUS_REMOVED, Sources.NSClient,
|
||||
ValueWithUnit.Timestamp(it.timestamp),
|
||||
ValueWithUnit.Insulin(it.amount),
|
||||
ValueWithUnit.UnitPerHour(it.rate),
|
||||
ValueWithUnit.Minute(TimeUnit.MILLISECONDS.toMinutes(it.duration).toInt())
|
||||
)
|
||||
aapsLogger.debug(LTag.DATABASE, "Invalidated ExtendedBolus $it")
|
||||
}
|
||||
result.ended.forEach {
|
||||
uel.log(Action.CANCEL_EXTENDED_BOLUS, Sources.NSClient,
|
||||
ValueWithUnit.Timestamp(it.timestamp),
|
||||
ValueWithUnit.Insulin(it.amount),
|
||||
ValueWithUnit.UnitPerHour(it.rate),
|
||||
ValueWithUnit.Minute(TimeUnit.MILLISECONDS.toMinutes(it.duration).toInt())
|
||||
)
|
||||
aapsLogger.debug(LTag.DATABASE, "Updated ExtendedBolus $it")
|
||||
}
|
||||
result.updatedNsId.forEach {
|
||||
aapsLogger.debug(LTag.DATABASE, "Updated nsId ExtendedBolus $it")
|
||||
}
|
||||
}
|
||||
result.ended.forEach {
|
||||
uel.log(Action.CANCEL_EXTENDED_BOLUS, Sources.NSClient,
|
||||
ValueWithUnit.Timestamp(it.timestamp),
|
||||
ValueWithUnit.Insulin(it.amount),
|
||||
ValueWithUnit.UnitPerHour(it.rate),
|
||||
ValueWithUnit.Minute(TimeUnit.MILLISECONDS.toMinutes(it.duration).toInt())
|
||||
)
|
||||
aapsLogger.debug(LTag.DATABASE, "Updated ExtendedBolus $it")
|
||||
}
|
||||
result.updatedNsId.forEach {
|
||||
aapsLogger.debug(LTag.DATABASE, "Updated nsId ExtendedBolus $it")
|
||||
}
|
||||
}
|
||||
} ?: aapsLogger.error("Error parsing ExtendedBolus json $json")
|
||||
} ?: aapsLogger.error("Error parsing ExtendedBolus json $json")
|
||||
}
|
||||
eventType == TherapyEvent.Type.TEMPORARY_BASAL.text ->
|
||||
temporaryBasalFromJson(json)?.let { temporaryBasal ->
|
||||
repository.runTransactionForResult(SyncNsTemporaryBasalTransaction(temporaryBasal, invalidateByNsOnly = false))
|
||||
.doOnError {
|
||||
aapsLogger.error(LTag.DATABASE, "Error while saving temporary basal", it)
|
||||
ret = Result.failure(workDataOf("Error" to it.toString()))
|
||||
}
|
||||
.blockingGet()
|
||||
.also { result ->
|
||||
result.inserted.forEach {
|
||||
uel.log(Action.TEMP_BASAL, Sources.NSClient,
|
||||
ValueWithUnit.Timestamp(it.timestamp),
|
||||
ValueWithUnit.UnitPerHour(it.rate),
|
||||
ValueWithUnit.Minute(TimeUnit.MILLISECONDS.toMinutes(it.duration).toInt())
|
||||
)
|
||||
aapsLogger.debug(LTag.DATABASE, "Inserted TemporaryBasal $it")
|
||||
if (config.NSCLIENT) {
|
||||
temporaryBasalFromJson(json)?.let { temporaryBasal ->
|
||||
repository.runTransactionForResult(SyncNsTemporaryBasalTransaction(temporaryBasal, invalidateByNsOnly = false))
|
||||
.doOnError {
|
||||
aapsLogger.error(LTag.DATABASE, "Error while saving temporary basal", it)
|
||||
ret = Result.failure(workDataOf("Error" to it.toString()))
|
||||
}
|
||||
result.invalidated.forEach {
|
||||
uel.log(Action.TEMP_BASAL_REMOVED, Sources.NSClient,
|
||||
ValueWithUnit.Timestamp(it.timestamp),
|
||||
ValueWithUnit.UnitPerHour(it.rate),
|
||||
ValueWithUnit.Minute(TimeUnit.MILLISECONDS.toMinutes(it.duration).toInt())
|
||||
)
|
||||
aapsLogger.debug(LTag.DATABASE, "Invalidated TemporaryBasal $it")
|
||||
.blockingGet()
|
||||
.also { result ->
|
||||
result.inserted.forEach {
|
||||
uel.log(Action.TEMP_BASAL, Sources.NSClient,
|
||||
ValueWithUnit.Timestamp(it.timestamp),
|
||||
if (it.isAbsolute) ValueWithUnit.UnitPerHour(it.rate) else ValueWithUnit.Percent(it.rate.toInt()),
|
||||
ValueWithUnit.Minute(TimeUnit.MILLISECONDS.toMinutes(it.duration).toInt())
|
||||
)
|
||||
aapsLogger.debug(LTag.DATABASE, "Inserted TemporaryBasal $it")
|
||||
}
|
||||
result.invalidated.forEach {
|
||||
uel.log(Action.TEMP_BASAL_REMOVED, Sources.NSClient,
|
||||
ValueWithUnit.Timestamp(it.timestamp),
|
||||
if (it.isAbsolute) ValueWithUnit.UnitPerHour(it.rate) else ValueWithUnit.Percent(it.rate.toInt()),
|
||||
ValueWithUnit.Minute(TimeUnit.MILLISECONDS.toMinutes(it.duration).toInt())
|
||||
)
|
||||
aapsLogger.debug(LTag.DATABASE, "Invalidated TemporaryBasal $it")
|
||||
}
|
||||
result.ended.forEach {
|
||||
uel.log(Action.CANCEL_TEMP_BASAL, Sources.NSClient,
|
||||
ValueWithUnit.Timestamp(it.timestamp),
|
||||
if (it.isAbsolute) ValueWithUnit.UnitPerHour(it.rate) else ValueWithUnit.Percent(it.rate.toInt()),
|
||||
ValueWithUnit.Minute(TimeUnit.MILLISECONDS.toMinutes(it.duration).toInt())
|
||||
)
|
||||
aapsLogger.debug(LTag.DATABASE, "Ended TemporaryBasal $it")
|
||||
}
|
||||
result.updatedNsId.forEach {
|
||||
aapsLogger.debug(LTag.DATABASE, "Updated nsId TemporaryBasal $it")
|
||||
}
|
||||
}
|
||||
result.ended.forEach {
|
||||
uel.log(Action.CANCEL_TEMP_BASAL, Sources.NSClient,
|
||||
ValueWithUnit.Timestamp(it.timestamp),
|
||||
ValueWithUnit.UnitPerHour(it.rate),
|
||||
ValueWithUnit.Minute(TimeUnit.MILLISECONDS.toMinutes(it.duration).toInt())
|
||||
)
|
||||
aapsLogger.debug(LTag.DATABASE, "Ended TemporaryBasal $it")
|
||||
}
|
||||
result.updatedNsId.forEach {
|
||||
aapsLogger.debug(LTag.DATABASE, "Updated nsId TemporaryBasal $it")
|
||||
}
|
||||
}
|
||||
} ?: aapsLogger.error("Error parsing TemporaryBasal json $json")
|
||||
} ?: aapsLogger.error("Error parsing TemporaryBasal json $json")
|
||||
}
|
||||
eventType == TherapyEvent.Type.PROFILE_SWITCH.text ->
|
||||
profileSwitchFromJson(json, dateUtil)?.let { profileSwitch ->
|
||||
repository.runTransactionForResult(SyncNsProfileSwitchTransaction(profileSwitch, invalidateByNsOnly = false))
|
||||
.doOnError {
|
||||
aapsLogger.error(LTag.DATABASE, "Error while saving ProfileSwitch", it)
|
||||
ret = Result.failure(workDataOf("Error" to it.toString()))
|
||||
}
|
||||
.blockingGet()
|
||||
.also { result ->
|
||||
result.inserted.forEach {
|
||||
uel.log(Action.PROFILE_SWITCH, Sources.NSClient,
|
||||
ValueWithUnit.Timestamp(it.timestamp))
|
||||
aapsLogger.debug(LTag.DATABASE, "Inserted ProfileSwitch $it")
|
||||
if (sp.getBoolean(R.string.key_ns_receive_profile_switch, false) && buildHelper.isEngineeringMode() || config.NSCLIENT) {
|
||||
profileSwitchFromJson(json, dateUtil, activePlugin)?.let { profileSwitch ->
|
||||
repository.runTransactionForResult(SyncNsProfileSwitchTransaction(profileSwitch, invalidateByNsOnly = false))
|
||||
.doOnError {
|
||||
aapsLogger.error(LTag.DATABASE, "Error while saving ProfileSwitch", it)
|
||||
ret = Result.failure(workDataOf("Error" to it.toString()))
|
||||
}
|
||||
result.invalidated.forEach {
|
||||
uel.log(Action.PROFILE_SWITCH_REMOVED, Sources.NSClient,
|
||||
ValueWithUnit.Timestamp(it.timestamp))
|
||||
aapsLogger.debug(LTag.DATABASE, "Invalidated ProfileSwitch $it")
|
||||
.blockingGet()
|
||||
.also { result ->
|
||||
result.inserted.forEach {
|
||||
uel.log(Action.PROFILE_SWITCH, Sources.NSClient,
|
||||
ValueWithUnit.Timestamp(it.timestamp))
|
||||
aapsLogger.debug(LTag.DATABASE, "Inserted ProfileSwitch $it")
|
||||
}
|
||||
result.invalidated.forEach {
|
||||
uel.log(Action.PROFILE_SWITCH_REMOVED, Sources.NSClient,
|
||||
ValueWithUnit.Timestamp(it.timestamp))
|
||||
aapsLogger.debug(LTag.DATABASE, "Invalidated ProfileSwitch $it")
|
||||
}
|
||||
result.updatedNsId.forEach {
|
||||
aapsLogger.debug(LTag.DATABASE, "Updated nsId ProfileSwitch $it")
|
||||
}
|
||||
}
|
||||
result.updatedNsId.forEach {
|
||||
aapsLogger.debug(LTag.DATABASE, "Updated nsId ProfileSwitch $it")
|
||||
} ?: aapsLogger.error("Error parsing ProfileSwitch json $json")
|
||||
}
|
||||
eventType == TherapyEvent.Type.APS_OFFLINE.text ->
|
||||
if (sp.getBoolean(R.string.key_ns_receive_offline_event, false) && buildHelper.isEngineeringMode() || config.NSCLIENT) {
|
||||
offlineEventFromJson(json)?.let { offlineEvent ->
|
||||
repository.runTransactionForResult(SyncNsOfflineEventTransaction(offlineEvent, invalidateByNsOnly = false))
|
||||
.doOnError {
|
||||
aapsLogger.error(LTag.DATABASE, "Error while saving OfflineEvent", it)
|
||||
ret = Result.failure(workDataOf("Error" to it.toString()))
|
||||
}
|
||||
}
|
||||
} ?: aapsLogger.error("Error parsing TemporaryBasal json $json")
|
||||
.blockingGet()
|
||||
.also { result ->
|
||||
result.inserted.forEach { oe ->
|
||||
uel.log(Action.LOOP_CHANGE, Sources.NSClient,
|
||||
ValueWithUnit.OfflineEventReason(oe.reason),
|
||||
ValueWithUnit.Minute(TimeUnit.MILLISECONDS.toMinutes(oe.duration).toInt())
|
||||
)
|
||||
aapsLogger.debug(LTag.DATABASE, "Inserted OfflineEvent $oe")
|
||||
}
|
||||
result.invalidated.forEach { oe ->
|
||||
uel.log(Action.LOOP_REMOVED, Sources.NSClient,
|
||||
ValueWithUnit.OfflineEventReason(oe.reason),
|
||||
ValueWithUnit.Minute(TimeUnit.MILLISECONDS.toMinutes(oe.duration).toInt())
|
||||
)
|
||||
aapsLogger.debug(LTag.DATABASE, "Invalidated OfflineEvent $oe")
|
||||
}
|
||||
result.ended.forEach { oe ->
|
||||
uel.log(Action.LOOP_CHANGE, Sources.NSClient,
|
||||
ValueWithUnit.OfflineEventReason(oe.reason),
|
||||
ValueWithUnit.Minute(TimeUnit.MILLISECONDS.toMinutes(oe.duration).toInt())
|
||||
)
|
||||
aapsLogger.debug(LTag.DATABASE, "Updated OfflineEvent $oe")
|
||||
}
|
||||
result.updatedNsId.forEach {
|
||||
aapsLogger.debug(LTag.DATABASE, "Updated nsId OfflineEvent $it")
|
||||
}
|
||||
}
|
||||
} ?: aapsLogger.error("Error parsing OfflineEvent json $json")
|
||||
}
|
||||
}
|
||||
if (eventType == TherapyEvent.Type.ANNOUNCEMENT.text) {
|
||||
val date = safeGetLong(json, "mills")
|
||||
val now = System.currentTimeMillis()
|
||||
val enteredBy = JsonHelper.safeGetString(json, "enteredBy", "")
|
||||
val notes = JsonHelper.safeGetString(json, "notes", "")
|
||||
if (date > now - 15 * 60 * 1000L && notes.isNotEmpty()
|
||||
&& enteredBy != sp.getString("careportal_enteredby", "AndroidAPS")) {
|
||||
val defaultVal = config.NSCLIENT
|
||||
if (sp.getBoolean(R.string.key_ns_announcements, defaultVal)) {
|
||||
val announcement = Notification(Notification.NS_ANNOUNCEMENT, notes, Notification.ANNOUNCEMENT, 60)
|
||||
rxBus.send(EventNewNotification(announcement))
|
||||
if (sp.getBoolean(R.string.key_ns_receive_therapy_events, false) || config.NSCLIENT)
|
||||
if (eventType == TherapyEvent.Type.ANNOUNCEMENT.text) {
|
||||
val date = safeGetLong(json, "mills")
|
||||
val now = System.currentTimeMillis()
|
||||
val enteredBy = JsonHelper.safeGetString(json, "enteredBy", "")
|
||||
val notes = JsonHelper.safeGetString(json, "notes", "")
|
||||
if (date > now - 15 * 60 * 1000L && notes.isNotEmpty()
|
||||
&& enteredBy != sp.getString("careportal_enteredby", "AndroidAPS")) {
|
||||
val defaultVal = config.NSCLIENT
|
||||
if (sp.getBoolean(R.string.key_ns_announcements, defaultVal)) {
|
||||
val announcement = Notification(Notification.NS_ANNOUNCEMENT, notes, Notification.ANNOUNCEMENT, 60)
|
||||
rxBus.send(EventNewNotification(announcement))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
nsClientPlugin.updateLatestDateReceivedIfNewer(latestDateInReceivedData)
|
||||
return ret
|
||||
|
|
|
@ -12,14 +12,11 @@ import info.nightscout.androidaps.database.entities.UserEntry.Action
|
|||
import info.nightscout.androidaps.database.entities.UserEntry.Sources
|
||||
import info.nightscout.androidaps.databinding.NsClientFragmentBinding
|
||||
import info.nightscout.androidaps.interfaces.DataSyncSelector
|
||||
import info.nightscout.androidaps.interfaces.UploadQueueAdminInterface
|
||||
import info.nightscout.androidaps.logging.UserEntryLogger
|
||||
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
||||
import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientNewLog
|
||||
import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientRestart
|
||||
import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientUpdateGUI
|
||||
import info.nightscout.androidaps.utils.FabricPrivacy
|
||||
import info.nightscout.androidaps.utils.HtmlHelper.fromHtml
|
||||
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
||||
|
@ -33,7 +30,6 @@ class NSClientFragment : DaggerFragment() {
|
|||
@Inject lateinit var sp: SP
|
||||
@Inject lateinit var resourceHelper: ResourceHelper
|
||||
@Inject lateinit var rxBus: RxBusWrapper
|
||||
@Inject lateinit var uploadQueue: UploadQueueAdminInterface
|
||||
@Inject lateinit var fabricPrivacy: FabricPrivacy
|
||||
@Inject lateinit var aapsSchedulers: AapsSchedulers
|
||||
@Inject lateinit var dataSyncSelector: DataSyncSelector
|
||||
|
@ -72,18 +68,6 @@ class NSClientFragment : DaggerFragment() {
|
|||
binding.restart.paintFlags = binding.restart.paintFlags or Paint.UNDERLINE_TEXT_FLAG
|
||||
binding.deliverNow.setOnClickListener { nsClientPlugin.resend("GUI") }
|
||||
binding.deliverNow.paintFlags = binding.deliverNow.paintFlags or Paint.UNDERLINE_TEXT_FLAG
|
||||
binding.clearQueue.setOnClickListener {
|
||||
context?.let { context ->
|
||||
OKDialog.showConfirmation(context, resourceHelper.gs(R.string.nsclientinternal), resourceHelper.gs(R.string.clearqueueconfirm), Runnable {
|
||||
uel.log(Action.NS_QUEUE_CLEARED, Sources.NSClient)
|
||||
uploadQueue.clearQueue()
|
||||
updateGui()
|
||||
})
|
||||
}
|
||||
}
|
||||
binding.clearQueue.paintFlags = binding.clearQueue.paintFlags or Paint.UNDERLINE_TEXT_FLAG
|
||||
binding.showQueue.setOnClickListener { rxBus.send(EventNSClientNewLog("QUEUE", uploadQueue.textList())) }
|
||||
binding.showQueue.paintFlags = binding.showQueue.paintFlags or Paint.UNDERLINE_TEXT_FLAG
|
||||
binding.fullSync.setOnClickListener {
|
||||
context?.let { context ->
|
||||
OKDialog.showConfirmation(context, resourceHelper.gs(R.string.nsclientinternal), resourceHelper.gs(R.string.full_sync), Runnable {
|
||||
|
@ -116,7 +100,6 @@ class NSClientFragment : DaggerFragment() {
|
|||
binding.log.text = nsClientPlugin.textLog
|
||||
if (nsClientPlugin.autoscroll) binding.logScrollview.fullScroll(ScrollView.FOCUS_DOWN)
|
||||
binding.url.text = nsClientPlugin.url()
|
||||
binding.queue.text = fromHtml(resourceHelper.gs(R.string.queue) + " <b>" + uploadQueue.size() + "</b>")
|
||||
binding.status.text = nsClientPlugin.status
|
||||
}
|
||||
}
|
|
@ -8,13 +8,13 @@ import dagger.android.HasAndroidInjector
|
|||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.database.AppRepository
|
||||
import info.nightscout.androidaps.database.transactions.SyncNsTherapyEventTransaction
|
||||
import info.nightscout.androidaps.extensions.therapyEventFromNsMbg
|
||||
import info.nightscout.androidaps.interfaces.Config
|
||||
import info.nightscout.androidaps.logging.AAPSLogger
|
||||
import info.nightscout.androidaps.logging.LTag
|
||||
import info.nightscout.androidaps.plugins.general.nsclient.data.NSMbg
|
||||
import info.nightscout.androidaps.receivers.DataWorker
|
||||
import info.nightscout.androidaps.utils.buildHelper.BuildHelper
|
||||
import info.nightscout.androidaps.extensions.therapyEventFromNsMbg
|
||||
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
||||
import javax.inject.Inject
|
||||
|
||||
|
@ -33,8 +33,8 @@ class NSClientMbgWorker(
|
|||
override fun doWork(): Result {
|
||||
var ret = Result.success()
|
||||
|
||||
val acceptNSData = !sp.getBoolean(R.string.key_ns_upload_only, true) && buildHelper.isEngineeringMode() || config.NSCLIENT
|
||||
if (!acceptNSData) return ret
|
||||
val acceptNSData = sp.getBoolean(R.string.key_ns_receive_therapy_events, false) || config.NSCLIENT
|
||||
if (!acceptNSData) return Result.success(workDataOf("Result" to "Sync not enabled"))
|
||||
|
||||
val mbgArray = dataWorker.pickupJSONArray(inputData.getLong(DataWorker.STORE_KEY, -1))
|
||||
?: return Result.failure(workDataOf("Error" to "missing input data"))
|
||||
|
|
|
@ -1,320 +0,0 @@
|
|||
package info.nightscout.androidaps.plugins.general.nsclient;
|
||||
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.ServiceConnection;
|
||||
import android.os.Handler;
|
||||
import android.os.HandlerThread;
|
||||
import android.os.IBinder;
|
||||
import android.text.Spanned;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.preference.PreferenceFragmentCompat;
|
||||
import androidx.preference.SwitchPreference;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import dagger.android.HasAndroidInjector;
|
||||
import info.nightscout.androidaps.interfaces.Config;
|
||||
import info.nightscout.androidaps.Constants;
|
||||
import info.nightscout.androidaps.R;
|
||||
import info.nightscout.androidaps.events.EventAppExit;
|
||||
import info.nightscout.androidaps.events.EventChargingState;
|
||||
import info.nightscout.androidaps.events.EventNetworkChange;
|
||||
import info.nightscout.androidaps.events.EventPreferenceChange;
|
||||
import info.nightscout.androidaps.interfaces.PluginBase;
|
||||
import info.nightscout.androidaps.interfaces.PluginDescription;
|
||||
import info.nightscout.androidaps.interfaces.PluginType;
|
||||
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.nsclient.data.AlarmAck;
|
||||
import info.nightscout.androidaps.plugins.general.nsclient.data.NSAlarm;
|
||||
import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientNewLog;
|
||||
import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientResend;
|
||||
import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientStatus;
|
||||
import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientUpdateGUI;
|
||||
import info.nightscout.androidaps.plugins.general.nsclient.services.NSClientService;
|
||||
import info.nightscout.androidaps.utils.FabricPrivacy;
|
||||
import info.nightscout.androidaps.utils.HtmlHelper;
|
||||
import info.nightscout.androidaps.utils.ToastUtils;
|
||||
import info.nightscout.androidaps.utils.buildHelper.BuildHelper;
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper;
|
||||
import info.nightscout.androidaps.utils.rx.AapsSchedulers;
|
||||
import info.nightscout.androidaps.utils.sharedPreferences.SP;
|
||||
import io.reactivex.disposables.CompositeDisposable;
|
||||
|
||||
@Singleton
|
||||
public class NSClientPlugin extends PluginBase {
|
||||
private final CompositeDisposable disposable = new CompositeDisposable();
|
||||
|
||||
private final AAPSLogger aapsLogger;
|
||||
private final RxBusWrapper rxBus;
|
||||
private final ResourceHelper resourceHelper;
|
||||
private final Context context;
|
||||
private final AapsSchedulers aapsSchedulers;
|
||||
private final FabricPrivacy fabricPrivacy;
|
||||
private final SP sp;
|
||||
private final NsClientReceiverDelegate nsClientReceiverDelegate;
|
||||
private final Config config;
|
||||
private final BuildHelper buildHelper;
|
||||
|
||||
public Handler handler;
|
||||
|
||||
private final List<EventNSClientNewLog> listLog = new ArrayList<>();
|
||||
Spanned textLog = HtmlHelper.INSTANCE.fromHtml("");
|
||||
|
||||
public boolean paused;
|
||||
boolean autoscroll;
|
||||
|
||||
public String status = "";
|
||||
|
||||
public @Nullable NSClientService nsClientService = null;
|
||||
|
||||
|
||||
@Inject
|
||||
public NSClientPlugin(
|
||||
HasAndroidInjector injector,
|
||||
AAPSLogger aapsLogger,
|
||||
AapsSchedulers aapsSchedulers,
|
||||
RxBusWrapper rxBus,
|
||||
ResourceHelper resourceHelper,
|
||||
Context context,
|
||||
FabricPrivacy fabricPrivacy,
|
||||
SP sp,
|
||||
NsClientReceiverDelegate nsClientReceiverDelegate,
|
||||
Config config,
|
||||
BuildHelper buildHelper
|
||||
) {
|
||||
super(new PluginDescription()
|
||||
.mainType(PluginType.GENERAL)
|
||||
.fragmentClass(NSClientFragment.class.getName())
|
||||
.pluginIcon(R.drawable.ic_nightscout_syncs)
|
||||
.pluginName(R.string.nsclientinternal)
|
||||
.shortName(R.string.nsclientinternal_shortname)
|
||||
.preferencesId(R.xml.pref_nsclientinternal)
|
||||
.description(R.string.description_ns_client),
|
||||
aapsLogger, resourceHelper, injector
|
||||
);
|
||||
|
||||
this.aapsLogger = aapsLogger;
|
||||
this.aapsSchedulers = aapsSchedulers;
|
||||
this.rxBus = rxBus;
|
||||
this.resourceHelper = resourceHelper;
|
||||
this.context = context;
|
||||
this.fabricPrivacy = fabricPrivacy;
|
||||
this.sp = sp;
|
||||
this.nsClientReceiverDelegate = nsClientReceiverDelegate;
|
||||
this.config = config;
|
||||
this.buildHelper = buildHelper;
|
||||
|
||||
if (config.getNSCLIENT()) {
|
||||
getPluginDescription().alwaysEnabled(true).visibleByDefault(true);
|
||||
}
|
||||
if (handler == null) {
|
||||
HandlerThread handlerThread = new HandlerThread(NSClientPlugin.class.getSimpleName() + "Handler");
|
||||
handlerThread.start();
|
||||
handler = new Handler(handlerThread.getLooper());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public boolean isAllowed() {
|
||||
return nsClientReceiverDelegate.allowed;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void onStart() {
|
||||
paused = sp.getBoolean(R.string.key_nsclientinternal_paused, false);
|
||||
autoscroll = sp.getBoolean(R.string.key_nsclientinternal_autoscroll, true);
|
||||
|
||||
Intent intent = new Intent(context, NSClientService.class);
|
||||
context.bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
|
||||
super.onStart();
|
||||
|
||||
nsClientReceiverDelegate.grabReceiversState();
|
||||
disposable.add(rxBus
|
||||
.toObservable(EventNSClientStatus.class)
|
||||
.observeOn(aapsSchedulers.getIo())
|
||||
.subscribe(event -> {
|
||||
status = event.getStatus(resourceHelper);
|
||||
rxBus.send(new EventNSClientUpdateGUI());
|
||||
}, fabricPrivacy::logException)
|
||||
);
|
||||
disposable.add(rxBus
|
||||
.toObservable(EventNetworkChange.class)
|
||||
.observeOn(aapsSchedulers.getIo())
|
||||
.subscribe(nsClientReceiverDelegate::onStatusEvent, fabricPrivacy::logException)
|
||||
);
|
||||
disposable.add(rxBus
|
||||
.toObservable(EventPreferenceChange.class)
|
||||
.observeOn(aapsSchedulers.getIo())
|
||||
.subscribe(nsClientReceiverDelegate::onStatusEvent, fabricPrivacy::logException)
|
||||
);
|
||||
disposable.add(rxBus
|
||||
.toObservable(EventAppExit.class)
|
||||
.observeOn(aapsSchedulers.getIo())
|
||||
.subscribe(event -> {
|
||||
if (nsClientService != null) {
|
||||
context.unbindService(mConnection);
|
||||
}
|
||||
}, fabricPrivacy::logException)
|
||||
);
|
||||
disposable.add(rxBus
|
||||
.toObservable(EventNSClientNewLog.class)
|
||||
.observeOn(aapsSchedulers.getIo())
|
||||
.subscribe(event -> {
|
||||
addToLog(event);
|
||||
aapsLogger.debug(LTag.NSCLIENT, event.getAction() + " " + event.getLogText());
|
||||
}, fabricPrivacy::logException)
|
||||
);
|
||||
disposable.add(rxBus
|
||||
.toObservable(EventChargingState.class)
|
||||
.observeOn(aapsSchedulers.getIo())
|
||||
.subscribe(nsClientReceiverDelegate::onStatusEvent, fabricPrivacy::logException)
|
||||
);
|
||||
disposable.add(rxBus
|
||||
.toObservable(EventNSClientResend.class)
|
||||
.observeOn(aapsSchedulers.getIo())
|
||||
.subscribe(event -> resend(event.getReason()), fabricPrivacy::logException)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStop() {
|
||||
context.getApplicationContext().unbindService(mConnection);
|
||||
disposable.clear();
|
||||
super.onStop();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preprocessPreferences(@NonNull PreferenceFragmentCompat preferenceFragment) {
|
||||
super.preprocessPreferences(preferenceFragment);
|
||||
|
||||
if (config.getNSCLIENT()) {
|
||||
SwitchPreference key_ns_uploadlocalprofile = preferenceFragment.findPreference(resourceHelper.gs(R.string.key_ns_uploadlocalprofile));
|
||||
if (key_ns_uploadlocalprofile != null) key_ns_uploadlocalprofile.setVisible(false);
|
||||
SwitchPreference key_ns_autobackfill = preferenceFragment.findPreference(resourceHelper.gs(R.string.key_ns_autobackfill));
|
||||
if (key_ns_autobackfill != null) key_ns_autobackfill.setVisible(false);
|
||||
SwitchPreference key_ns_create_announcements_from_errors = preferenceFragment.findPreference(resourceHelper.gs(R.string.key_ns_create_announcements_from_errors));
|
||||
if (key_ns_create_announcements_from_errors != null)
|
||||
key_ns_create_announcements_from_errors.setVisible(false);
|
||||
SwitchPreference key_ns_create_announcements_from_carbs_req = preferenceFragment.findPreference(resourceHelper.gs(R.string.key_ns_create_announcements_from_carbs_req));
|
||||
if (key_ns_create_announcements_from_carbs_req != null)
|
||||
key_ns_create_announcements_from_carbs_req.setVisible(false);
|
||||
SwitchPreference key_ns_upload_only = preferenceFragment.findPreference(resourceHelper.gs(R.string.key_ns_upload_only));
|
||||
if (key_ns_upload_only != null) {
|
||||
key_ns_upload_only.setVisible(false);
|
||||
key_ns_upload_only.setEnabled(false);
|
||||
}
|
||||
SwitchPreference key_ns_sync_use_absolute = preferenceFragment.findPreference(resourceHelper.gs(R.string.key_ns_sync_use_absolute));
|
||||
if (key_ns_sync_use_absolute != null) key_ns_sync_use_absolute.setVisible(false);
|
||||
} else {
|
||||
// APS or pumpControl mode
|
||||
SwitchPreference key_ns_upload_only = preferenceFragment.findPreference(resourceHelper.gs(R.string.key_ns_upload_only));
|
||||
if (key_ns_upload_only != null)
|
||||
key_ns_upload_only.setVisible(buildHelper.isEngineeringMode());
|
||||
}
|
||||
}
|
||||
|
||||
private final ServiceConnection mConnection = new ServiceConnection() {
|
||||
|
||||
public void onServiceDisconnected(ComponentName name) {
|
||||
aapsLogger.debug(LTag.NSCLIENT, "Service is disconnected");
|
||||
nsClientService = null;
|
||||
}
|
||||
|
||||
public void onServiceConnected(ComponentName name, IBinder service) {
|
||||
aapsLogger.debug(LTag.NSCLIENT, "Service is connected");
|
||||
NSClientService.LocalBinder mLocalBinder = (NSClientService.LocalBinder) service;
|
||||
if (mLocalBinder != null) // is null when running in roboelectric
|
||||
nsClientService = mLocalBinder.getServiceInstance();
|
||||
}
|
||||
};
|
||||
|
||||
synchronized void clearLog() {
|
||||
handler.post(() -> {
|
||||
synchronized (listLog) {
|
||||
listLog.clear();
|
||||
}
|
||||
rxBus.send(new EventNSClientUpdateGUI());
|
||||
});
|
||||
}
|
||||
|
||||
private synchronized void addToLog(final EventNSClientNewLog ev) {
|
||||
handler.post(() -> {
|
||||
synchronized (listLog) {
|
||||
listLog.add(ev);
|
||||
// remove the first line if log is too large
|
||||
if (listLog.size() >= Constants.MAX_LOG_LINES) {
|
||||
listLog.remove(0);
|
||||
}
|
||||
}
|
||||
rxBus.send(new EventNSClientUpdateGUI());
|
||||
});
|
||||
}
|
||||
|
||||
synchronized void updateLog() {
|
||||
try {
|
||||
StringBuilder newTextLog = new StringBuilder();
|
||||
synchronized (listLog) {
|
||||
for (EventNSClientNewLog log : listLog) {
|
||||
newTextLog.append(log.toPreparedHtml());
|
||||
}
|
||||
}
|
||||
textLog = HtmlHelper.INSTANCE.fromHtml(newTextLog.toString());
|
||||
} catch (OutOfMemoryError e) {
|
||||
ToastUtils.showToastInUiThread(context, rxBus, "Out of memory!\nStop using this phone !!!", R.raw.error);
|
||||
}
|
||||
}
|
||||
|
||||
void resend(String reason) {
|
||||
if (nsClientService != null)
|
||||
nsClientService.resend(reason);
|
||||
}
|
||||
|
||||
public void pause(boolean newState) {
|
||||
sp.putBoolean(R.string.key_nsclientinternal_paused, newState);
|
||||
paused = newState;
|
||||
rxBus.send(new EventPreferenceChange(resourceHelper, R.string.key_nsclientinternal_paused));
|
||||
}
|
||||
|
||||
public String url() {
|
||||
return NSClientService.nsURL;
|
||||
}
|
||||
|
||||
public boolean hasWritePermission() {
|
||||
return NSClientService.hasWriteAuth;
|
||||
}
|
||||
|
||||
public void handleClearAlarm(NSAlarm originalAlarm, long silenceTimeInMsec) {
|
||||
|
||||
if (!isEnabled(PluginType.GENERAL)) {
|
||||
return;
|
||||
}
|
||||
if (sp.getBoolean(R.string.key_ns_noupload, false)) {
|
||||
aapsLogger.debug(LTag.NSCLIENT, "Upload disabled. Message dropped");
|
||||
return;
|
||||
}
|
||||
|
||||
AlarmAck ack = new AlarmAck();
|
||||
ack.level = originalAlarm.level();
|
||||
ack.group = originalAlarm.group();
|
||||
ack.silenceTime = silenceTimeInMsec;
|
||||
|
||||
if (nsClientService != null)
|
||||
nsClientService.sendAlarmAck(ack);
|
||||
}
|
||||
|
||||
public void updateLatestDateReceivedIfNewer(long latestReceived) {
|
||||
if (nsClientService != null && latestReceived > nsClientService.latestDateInReceivedData)
|
||||
nsClientService.latestDateInReceivedData = latestReceived;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,243 @@
|
|||
package info.nightscout.androidaps.plugins.general.nsclient
|
||||
|
||||
import android.content.ComponentName
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.ServiceConnection
|
||||
import android.os.Handler
|
||||
import android.os.HandlerThread
|
||||
import android.os.IBinder
|
||||
import androidx.preference.PreferenceFragmentCompat
|
||||
import androidx.preference.PreferenceScreen
|
||||
import androidx.preference.SwitchPreference
|
||||
import dagger.android.HasAndroidInjector
|
||||
import info.nightscout.androidaps.Constants
|
||||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.events.EventAppExit
|
||||
import info.nightscout.androidaps.events.EventChargingState
|
||||
import info.nightscout.androidaps.events.EventNetworkChange
|
||||
import info.nightscout.androidaps.events.EventPreferenceChange
|
||||
import info.nightscout.androidaps.interfaces.Config
|
||||
import info.nightscout.androidaps.interfaces.PluginBase
|
||||
import info.nightscout.androidaps.interfaces.PluginDescription
|
||||
import info.nightscout.androidaps.interfaces.PluginType
|
||||
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.nsclient.data.AlarmAck
|
||||
import info.nightscout.androidaps.plugins.general.nsclient.data.NSAlarm
|
||||
import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientNewLog
|
||||
import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientResend
|
||||
import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientStatus
|
||||
import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientUpdateGUI
|
||||
import info.nightscout.androidaps.plugins.general.nsclient.services.NSClientService
|
||||
import info.nightscout.androidaps.utils.FabricPrivacy
|
||||
import info.nightscout.androidaps.utils.HtmlHelper.fromHtml
|
||||
import info.nightscout.androidaps.utils.ToastUtils
|
||||
import info.nightscout.androidaps.utils.buildHelper.BuildHelper
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
||||
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
||||
import io.reactivex.disposables.CompositeDisposable
|
||||
import java.util.*
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
class NSClientPlugin @Inject constructor(
|
||||
injector: HasAndroidInjector,
|
||||
aapsLogger: AAPSLogger,
|
||||
private val aapsSchedulers: AapsSchedulers,
|
||||
private val rxBus: RxBusWrapper,
|
||||
resourceHelper: ResourceHelper,
|
||||
private val context: Context,
|
||||
private val fabricPrivacy: FabricPrivacy,
|
||||
private val sp: SP,
|
||||
private val nsClientReceiverDelegate: NsClientReceiverDelegate,
|
||||
private val config: Config,
|
||||
private val buildHelper: BuildHelper
|
||||
) : PluginBase(PluginDescription()
|
||||
.mainType(PluginType.GENERAL)
|
||||
.fragmentClass(NSClientFragment::class.java.name)
|
||||
.pluginIcon(R.drawable.ic_nightscout_syncs)
|
||||
.pluginName(R.string.nsclientinternal)
|
||||
.shortName(R.string.nsclientinternal_shortname)
|
||||
.preferencesId(R.xml.pref_nsclientinternal)
|
||||
.description(R.string.description_ns_client),
|
||||
aapsLogger, resourceHelper, injector
|
||||
) {
|
||||
|
||||
private val disposable = CompositeDisposable()
|
||||
var handler: Handler? = null
|
||||
private val listLog: MutableList<EventNSClientNewLog> = ArrayList()
|
||||
var textLog = fromHtml("")
|
||||
var paused = false
|
||||
var autoscroll = false
|
||||
var status = ""
|
||||
var nsClientService: NSClientService? = null
|
||||
val isAllowed: Boolean
|
||||
get() = nsClientReceiverDelegate.allowed
|
||||
|
||||
init {
|
||||
if (config.NSCLIENT) {
|
||||
pluginDescription.alwaysEnabled(true).visibleByDefault(true)
|
||||
}
|
||||
if (handler == null) {
|
||||
val handlerThread = HandlerThread(NSClientPlugin::class.java.simpleName + "Handler")
|
||||
handlerThread.start()
|
||||
handler = Handler(handlerThread.looper)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
paused = sp.getBoolean(R.string.key_nsclientinternal_paused, false)
|
||||
autoscroll = sp.getBoolean(R.string.key_nsclientinternal_autoscroll, true)
|
||||
val intent = Intent(context, NSClientService::class.java)
|
||||
context.bindService(intent, mConnection, Context.BIND_AUTO_CREATE)
|
||||
super.onStart()
|
||||
nsClientReceiverDelegate.grabReceiversState()
|
||||
disposable.add(rxBus
|
||||
.toObservable(EventNSClientStatus::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.subscribe({ event: EventNSClientStatus ->
|
||||
status = event.getStatus(resourceHelper)
|
||||
rxBus.send(EventNSClientUpdateGUI())
|
||||
}, fabricPrivacy::logException)
|
||||
)
|
||||
disposable.add(rxBus
|
||||
.toObservable(EventNetworkChange::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.subscribe({ ev -> nsClientReceiverDelegate.onStatusEvent(ev) }, fabricPrivacy::logException)
|
||||
)
|
||||
disposable.add(rxBus
|
||||
.toObservable(EventPreferenceChange::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.subscribe({ ev -> nsClientReceiverDelegate.onStatusEvent(ev) }, fabricPrivacy::logException)
|
||||
)
|
||||
disposable.add(rxBus
|
||||
.toObservable(EventAppExit::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.subscribe({ if (nsClientService != null) context.unbindService(mConnection) }, fabricPrivacy::logException)
|
||||
)
|
||||
disposable.add(rxBus
|
||||
.toObservable(EventNSClientNewLog::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.subscribe({ event: EventNSClientNewLog ->
|
||||
addToLog(event)
|
||||
aapsLogger.debug(LTag.NSCLIENT, event.action + " " + event.logText)
|
||||
}, fabricPrivacy::logException)
|
||||
)
|
||||
disposable.add(rxBus
|
||||
.toObservable(EventChargingState::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.subscribe({ ev -> nsClientReceiverDelegate.onStatusEvent(ev) }, fabricPrivacy::logException)
|
||||
)
|
||||
disposable.add(rxBus
|
||||
.toObservable(EventNSClientResend::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.subscribe({ event -> resend(event.reason) }, fabricPrivacy::logException)
|
||||
)
|
||||
}
|
||||
|
||||
override fun onStop() {
|
||||
context.applicationContext.unbindService(mConnection)
|
||||
disposable.clear()
|
||||
super.onStop()
|
||||
}
|
||||
|
||||
override fun preprocessPreferences(preferenceFragment: PreferenceFragmentCompat) {
|
||||
super.preprocessPreferences(preferenceFragment)
|
||||
if (config.NSCLIENT) {
|
||||
preferenceFragment.findPreference<PreferenceScreen>(resourceHelper.gs(R.string.ns_sync_options))?.isVisible = false
|
||||
|
||||
preferenceFragment.findPreference<SwitchPreference>(resourceHelper.gs(R.string.key_ns_create_announcements_from_errors))?.isVisible = false
|
||||
preferenceFragment.findPreference<SwitchPreference>(resourceHelper.gs(R.string.key_ns_create_announcements_from_carbs_req))?.isVisible = false
|
||||
preferenceFragment.findPreference<SwitchPreference>(resourceHelper.gs(R.string.key_ns_sync_use_absolute))?.isVisible = false
|
||||
} else {
|
||||
// APS or pumpControl mode
|
||||
preferenceFragment.findPreference<SwitchPreference>(resourceHelper.gs(R.string.key_ns_receive_profile_switch))?.isVisible = buildHelper.isEngineeringMode()
|
||||
preferenceFragment.findPreference<SwitchPreference>(resourceHelper.gs(R.string.key_ns_receive_insulin))?.isVisible = buildHelper.isEngineeringMode()
|
||||
preferenceFragment.findPreference<SwitchPreference>(resourceHelper.gs(R.string.key_ns_receive_carbs))?.isVisible = buildHelper.isEngineeringMode()
|
||||
preferenceFragment.findPreference<SwitchPreference>(resourceHelper.gs(R.string.key_ns_receive_temp_target))?.isVisible = buildHelper.isEngineeringMode()
|
||||
}
|
||||
}
|
||||
|
||||
private val mConnection: ServiceConnection = object : ServiceConnection {
|
||||
override fun onServiceDisconnected(name: ComponentName) {
|
||||
aapsLogger.debug(LTag.NSCLIENT, "Service is disconnected")
|
||||
nsClientService = null
|
||||
}
|
||||
|
||||
override fun onServiceConnected(name: ComponentName, service: IBinder) {
|
||||
aapsLogger.debug(LTag.NSCLIENT, "Service is connected")
|
||||
val mLocalBinder = service as NSClientService.LocalBinder
|
||||
@Suppress("UNNECESSARY_SAFE_CALL")
|
||||
nsClientService = mLocalBinder?.serviceInstance // is null when running in roboelectric
|
||||
}
|
||||
}
|
||||
|
||||
@Synchronized fun clearLog() {
|
||||
handler?.post {
|
||||
synchronized(listLog) { listLog.clear() }
|
||||
rxBus.send(EventNSClientUpdateGUI())
|
||||
}
|
||||
}
|
||||
|
||||
@Synchronized private fun addToLog(ev: EventNSClientNewLog) {
|
||||
handler?.post {
|
||||
synchronized(listLog) {
|
||||
listLog.add(ev)
|
||||
// remove the first line if log is too large
|
||||
if (listLog.size >= Constants.MAX_LOG_LINES) {
|
||||
listLog.removeAt(0)
|
||||
}
|
||||
}
|
||||
rxBus.send(EventNSClientUpdateGUI())
|
||||
}
|
||||
}
|
||||
|
||||
@Synchronized fun updateLog() {
|
||||
try {
|
||||
val newTextLog = StringBuilder()
|
||||
synchronized(listLog) {
|
||||
for (log in listLog) {
|
||||
newTextLog.append(log.toPreparedHtml())
|
||||
}
|
||||
}
|
||||
textLog = fromHtml(newTextLog.toString())
|
||||
} catch (e: OutOfMemoryError) {
|
||||
ToastUtils.showToastInUiThread(context, rxBus, "Out of memory!\nStop using this phone !!!", R.raw.error)
|
||||
}
|
||||
}
|
||||
|
||||
fun resend(reason: String) {
|
||||
nsClientService?.resend(reason)
|
||||
}
|
||||
|
||||
fun pause(newState: Boolean) {
|
||||
sp.putBoolean(R.string.key_nsclientinternal_paused, newState)
|
||||
paused = newState
|
||||
rxBus.send(EventPreferenceChange(resourceHelper, R.string.key_nsclientinternal_paused))
|
||||
}
|
||||
|
||||
fun url(): String = nsClientService?.nsURL ?: ""
|
||||
fun hasWritePermission(): Boolean = nsClientService?.hasWriteAuth ?: false
|
||||
|
||||
fun handleClearAlarm(originalAlarm: NSAlarm, silenceTimeInMilliseconds: Long) {
|
||||
if (!isEnabled(PluginType.GENERAL)) return
|
||||
if (!sp.getBoolean(R.string.key_ns_upload, false)) {
|
||||
aapsLogger.debug(LTag.NSCLIENT, "Upload disabled. Message dropped")
|
||||
return
|
||||
}
|
||||
nsClientService?.sendAlarmAck(
|
||||
AlarmAck().also { ack ->
|
||||
ack.level = originalAlarm.level()
|
||||
ack.group = originalAlarm.group()
|
||||
ack.silenceTime = silenceTimeInMilliseconds
|
||||
})
|
||||
}
|
||||
|
||||
fun updateLatestDateReceivedIfNewer(latestReceived: Long) {
|
||||
nsClientService?.let { if (latestReceived > it.latestDateInReceivedData) it.latestDateInReceivedData = latestReceived }
|
||||
}
|
||||
}
|
|
@ -42,8 +42,9 @@ class NSClientRemoveWorker(
|
|||
@Inject lateinit var uel: UserEntryLogger
|
||||
|
||||
override fun doWork(): Result {
|
||||
val acceptNSData = !sp.getBoolean(R.string.key_ns_upload_only, true) && buildHelper.isEngineeringMode() || config.NSCLIENT
|
||||
if (!acceptNSData) return Result.success()
|
||||
// Do not accept removed data over WS. Only invalidated trough NSClient
|
||||
@Suppress("ConstantConditionIf")
|
||||
if (true) return Result.success()
|
||||
|
||||
var ret = Result.success()
|
||||
|
||||
|
|
|
@ -39,7 +39,7 @@ class NSClientUpdateRemoveAckWorker(
|
|||
is PairTemporaryTarget -> {
|
||||
val pair = ack.originalObject
|
||||
dataSyncSelector.confirmLastTempTargetsIdIfGreater(pair.updateRecordId)
|
||||
rxBus.send(EventNSClientNewLog("DBUPDATE/DBREMOVE", "Acked TemporaryTarget" + ack._id))
|
||||
rxBus.send(EventNSClientNewLog("DBUPDATE", "Acked TemporaryTarget" + ack._id))
|
||||
// Send new if waiting
|
||||
dataSyncSelector.processChangedTempTargetsCompat()
|
||||
ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
|
||||
|
@ -48,7 +48,7 @@ class NSClientUpdateRemoveAckWorker(
|
|||
is PairGlucoseValue -> {
|
||||
val pair = ack.originalObject
|
||||
dataSyncSelector.confirmLastGlucoseValueIdIfGreater(pair.updateRecordId)
|
||||
rxBus.send(EventNSClientNewLog("DBUPDATE/DBREMOVE", "Acked GlucoseValue " + ack._id))
|
||||
rxBus.send(EventNSClientNewLog("DBUPDATE", "Acked GlucoseValue " + ack._id))
|
||||
// Send new if waiting
|
||||
dataSyncSelector.processChangedGlucoseValuesCompat()
|
||||
ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
|
||||
|
@ -57,7 +57,7 @@ class NSClientUpdateRemoveAckWorker(
|
|||
is PairFood -> {
|
||||
val pair = ack.originalObject
|
||||
dataSyncSelector.confirmLastFoodIdIfGreater(pair.updateRecordId)
|
||||
rxBus.send(EventNSClientNewLog("DBUPDATE/DBREMOVE", "Acked Food " + ack._id))
|
||||
rxBus.send(EventNSClientNewLog("DBUPDATE", "Acked Food " + ack._id))
|
||||
// Send new if waiting
|
||||
dataSyncSelector.processChangedFoodsCompat()
|
||||
ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
|
||||
|
@ -66,7 +66,7 @@ class NSClientUpdateRemoveAckWorker(
|
|||
is PairTherapyEvent -> {
|
||||
val pair = ack.originalObject
|
||||
dataSyncSelector.confirmLastTherapyEventIdIfGreater(pair.updateRecordId)
|
||||
rxBus.send(EventNSClientNewLog("DBUPDATE/DBREMOVE", "Acked TherapyEvent " + ack._id))
|
||||
rxBus.send(EventNSClientNewLog("DBUPDATE", "Acked TherapyEvent " + ack._id))
|
||||
// Send new if waiting
|
||||
dataSyncSelector.processChangedTherapyEventsCompat()
|
||||
ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
|
||||
|
@ -75,7 +75,7 @@ class NSClientUpdateRemoveAckWorker(
|
|||
is PairBolus -> {
|
||||
val pair = ack.originalObject
|
||||
dataSyncSelector.confirmLastBolusIdIfGreater(pair.updateRecordId)
|
||||
rxBus.send(EventNSClientNewLog("DBUPDATE/DBREMOVE", "Acked Bolus " + ack._id))
|
||||
rxBus.send(EventNSClientNewLog("DBUPDATE", "Acked Bolus " + ack._id))
|
||||
// Send new if waiting
|
||||
dataSyncSelector.processChangedBolusesCompat()
|
||||
ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
|
||||
|
@ -84,7 +84,7 @@ class NSClientUpdateRemoveAckWorker(
|
|||
is PairCarbs -> {
|
||||
val pair = ack.originalObject
|
||||
dataSyncSelector.confirmLastCarbsIdIfGreater(pair.updateRecordId)
|
||||
rxBus.send(EventNSClientNewLog("DBUPDATE/DBREMOVE", "Acked Carbs " + ack._id))
|
||||
rxBus.send(EventNSClientNewLog("DBUPDATE", "Acked Carbs " + ack._id))
|
||||
// Send new if waiting
|
||||
dataSyncSelector.processChangedCarbsCompat()
|
||||
ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
|
||||
|
@ -93,7 +93,7 @@ class NSClientUpdateRemoveAckWorker(
|
|||
is PairBolusCalculatorResult -> {
|
||||
val pair = ack.originalObject
|
||||
dataSyncSelector.confirmLastBolusCalculatorResultsIdIfGreater(pair.updateRecordId)
|
||||
rxBus.send(EventNSClientNewLog("DBUPDATE/DBREMOVE", "Acked BolusCalculatorResult " + ack._id))
|
||||
rxBus.send(EventNSClientNewLog("DBUPDATE", "Acked BolusCalculatorResult " + ack._id))
|
||||
// Send new if waiting
|
||||
dataSyncSelector.processChangedBolusCalculatorResultsCompat()
|
||||
ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
|
||||
|
@ -102,7 +102,7 @@ class NSClientUpdateRemoveAckWorker(
|
|||
is PairTemporaryBasal -> {
|
||||
val pair = ack.originalObject
|
||||
dataSyncSelector.confirmLastTemporaryBasalIdIfGreater(pair.updateRecordId)
|
||||
rxBus.send(EventNSClientNewLog("DBUPDATE/DBREMOVE", "Acked TemporaryBasal " + ack._id))
|
||||
rxBus.send(EventNSClientNewLog("DBUPDATE", "Acked TemporaryBasal " + ack._id))
|
||||
// Send new if waiting
|
||||
dataSyncSelector.processChangedTemporaryBasalsCompat()
|
||||
ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
|
||||
|
@ -111,7 +111,7 @@ class NSClientUpdateRemoveAckWorker(
|
|||
is PairExtendedBolus -> {
|
||||
val pair = ack.originalObject
|
||||
dataSyncSelector.confirmLastExtendedBolusIdIfGreater(pair.updateRecordId)
|
||||
rxBus.send(EventNSClientNewLog("DBUPDATE/DBREMOVE", "Acked ExtendedBolus " + ack._id))
|
||||
rxBus.send(EventNSClientNewLog("DBUPDATE", "Acked ExtendedBolus " + ack._id))
|
||||
// Send new if waiting
|
||||
dataSyncSelector.processChangedExtendedBolusesCompat()
|
||||
ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
|
||||
|
@ -120,11 +120,20 @@ class NSClientUpdateRemoveAckWorker(
|
|||
is PairProfileSwitch -> {
|
||||
val pair = ack.originalObject
|
||||
dataSyncSelector.confirmLastProfileSwitchIdIfGreater(pair.updateRecordId)
|
||||
rxBus.send(EventNSClientNewLog("DBUPDATE/DBREMOVE", "Acked ProfileSwitch " + ack._id))
|
||||
rxBus.send(EventNSClientNewLog("DBUPDATE", "Acked ProfileSwitch " + ack._id))
|
||||
// Send new if waiting
|
||||
dataSyncSelector.processChangedProfileSwitchesCompat()
|
||||
ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
|
||||
}
|
||||
|
||||
is PairOfflineEvent -> {
|
||||
val pair = ack.originalObject
|
||||
dataSyncSelector.confirmLastOfflineEventIdIfGreater(pair.updateRecordId)
|
||||
rxBus.send(EventNSClientNewLog("DBUPDATE", "Acked OfflineEvent" + ack._id))
|
||||
// Send new if waiting
|
||||
dataSyncSelector.processChangedOfflineEventsCompat()
|
||||
ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
|
|
@ -1,117 +0,0 @@
|
|||
package info.nightscout.androidaps.plugins.general.nsclient;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import info.nightscout.androidaps.R;
|
||||
import info.nightscout.androidaps.events.EventChargingState;
|
||||
import info.nightscout.androidaps.events.EventNetworkChange;
|
||||
import info.nightscout.androidaps.events.EventPreferenceChange;
|
||||
import info.nightscout.androidaps.plugins.bus.RxBusWrapper;
|
||||
import info.nightscout.androidaps.receivers.ReceiverStatusStore;
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper;
|
||||
import info.nightscout.androidaps.utils.sharedPreferences.SP;
|
||||
|
||||
@Singleton
|
||||
class NsClientReceiverDelegate {
|
||||
|
||||
private boolean allowedChargingState = true;
|
||||
private boolean allowedNetworkState = true;
|
||||
boolean allowed = true;
|
||||
|
||||
private RxBusWrapper rxBus;
|
||||
private ResourceHelper resourceHelper;
|
||||
private SP sp;
|
||||
private ReceiverStatusStore receiverStatusStore;
|
||||
|
||||
@Inject
|
||||
public NsClientReceiverDelegate(
|
||||
RxBusWrapper rxBus,
|
||||
ResourceHelper resourceHelper,
|
||||
SP sp,
|
||||
ReceiverStatusStore receiverStatusStore
|
||||
) {
|
||||
this.rxBus = rxBus;
|
||||
this.resourceHelper = resourceHelper;
|
||||
this.sp = sp;
|
||||
this.receiverStatusStore = receiverStatusStore;
|
||||
}
|
||||
|
||||
void grabReceiversState() {
|
||||
|
||||
receiverStatusStore.updateNetworkStatus();
|
||||
}
|
||||
|
||||
void onStatusEvent(EventPreferenceChange ev) {
|
||||
if (ev.isChanged(resourceHelper, R.string.key_ns_wifionly) ||
|
||||
ev.isChanged(resourceHelper, R.string.key_ns_wifi_ssids) ||
|
||||
ev.isChanged(resourceHelper, R.string.key_ns_allowroaming)
|
||||
) {
|
||||
receiverStatusStore.updateNetworkStatus();
|
||||
onStatusEvent(receiverStatusStore.getLastNetworkEvent());
|
||||
} else if (ev.isChanged(resourceHelper, R.string.key_ns_chargingonly)) {
|
||||
receiverStatusStore.broadcastChargingState();
|
||||
}
|
||||
}
|
||||
|
||||
void onStatusEvent(final EventChargingState ev) {
|
||||
boolean newChargingState = calculateStatus(ev);
|
||||
|
||||
if (newChargingState != allowedChargingState) {
|
||||
allowedChargingState = newChargingState;
|
||||
processStateChange();
|
||||
}
|
||||
}
|
||||
|
||||
void onStatusEvent(final EventNetworkChange ev) {
|
||||
boolean newNetworkState = calculateStatus(ev);
|
||||
|
||||
if (newNetworkState != allowedNetworkState) {
|
||||
allowedNetworkState = newNetworkState;
|
||||
processStateChange();
|
||||
}
|
||||
}
|
||||
|
||||
private void processStateChange() {
|
||||
boolean newAllowedState = allowedChargingState && allowedNetworkState;
|
||||
if (newAllowedState != allowed) {
|
||||
allowed = newAllowedState;
|
||||
rxBus.send(new EventPreferenceChange(resourceHelper.gs(R.string.key_nsclientinternal_paused)));
|
||||
}
|
||||
}
|
||||
|
||||
boolean calculateStatus(final EventChargingState ev) {
|
||||
boolean chargingOnly = sp.getBoolean(R.string.key_ns_chargingonly, false);
|
||||
boolean newAllowedState = true;
|
||||
|
||||
if (!ev.isCharging() && chargingOnly) {
|
||||
newAllowedState = false;
|
||||
}
|
||||
|
||||
return newAllowedState;
|
||||
}
|
||||
|
||||
boolean calculateStatus(final EventNetworkChange ev) {
|
||||
boolean wifiOnly = sp.getBoolean(R.string.key_ns_wifionly, false);
|
||||
String allowedSSIDstring = sp.getString(R.string.key_ns_wifi_ssids, "");
|
||||
String[] allowedSSIDs = allowedSSIDstring.split(";");
|
||||
if (allowedSSIDstring.isEmpty()) allowedSSIDs = new String[0];
|
||||
boolean allowRoaming = sp.getBoolean(R.string.key_ns_allowroaming, true);
|
||||
|
||||
boolean newAllowedState = true;
|
||||
|
||||
if (ev.getWifiConnected()) {
|
||||
if (allowedSSIDs.length != 0 && !Arrays.asList(allowedSSIDs).contains(ev.getSsid())) {
|
||||
newAllowedState = false;
|
||||
}
|
||||
} else {
|
||||
if ((!allowRoaming && ev.getRoaming()) || wifiOnly) {
|
||||
newAllowedState = false;
|
||||
}
|
||||
}
|
||||
|
||||
return newAllowedState;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,91 @@
|
|||
package info.nightscout.androidaps.plugins.general.nsclient
|
||||
|
||||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.events.EventChargingState
|
||||
import info.nightscout.androidaps.events.EventNetworkChange
|
||||
import info.nightscout.androidaps.events.EventPreferenceChange
|
||||
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
||||
import info.nightscout.androidaps.receivers.ReceiverStatusStore
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
class NsClientReceiverDelegate @Inject constructor(
|
||||
private val rxBus: RxBusWrapper,
|
||||
private val resourceHelper: ResourceHelper,
|
||||
private val sp: SP,
|
||||
private val receiverStatusStore: ReceiverStatusStore
|
||||
) {
|
||||
|
||||
private var allowedChargingState = true
|
||||
private var allowedNetworkState = true
|
||||
var allowed = true
|
||||
|
||||
fun grabReceiversState() {
|
||||
receiverStatusStore.updateNetworkStatus()
|
||||
}
|
||||
|
||||
fun onStatusEvent(ev: EventPreferenceChange) {
|
||||
if (ev.isChanged(resourceHelper, R.string.key_ns_wifionly) ||
|
||||
ev.isChanged(resourceHelper, R.string.key_ns_wifi_ssids) ||
|
||||
ev.isChanged(resourceHelper, R.string.key_ns_allowroaming)) {
|
||||
receiverStatusStore.updateNetworkStatus()
|
||||
onStatusEvent(receiverStatusStore.lastNetworkEvent)
|
||||
} else if (ev.isChanged(resourceHelper, R.string.key_ns_chargingonly)) {
|
||||
receiverStatusStore.broadcastChargingState()
|
||||
}
|
||||
}
|
||||
|
||||
fun onStatusEvent(ev: EventChargingState) {
|
||||
val newChargingState = calculateStatus(ev)
|
||||
if (newChargingState != allowedChargingState) {
|
||||
allowedChargingState = newChargingState
|
||||
processStateChange()
|
||||
}
|
||||
}
|
||||
|
||||
fun onStatusEvent(ev: EventNetworkChange?) {
|
||||
val newNetworkState = calculateStatus(ev)
|
||||
if (newNetworkState != allowedNetworkState) {
|
||||
allowedNetworkState = newNetworkState
|
||||
processStateChange()
|
||||
}
|
||||
}
|
||||
|
||||
private fun processStateChange() {
|
||||
val newAllowedState = allowedChargingState && allowedNetworkState
|
||||
if (newAllowedState != allowed) {
|
||||
allowed = newAllowedState
|
||||
rxBus.send(EventPreferenceChange(resourceHelper.gs(R.string.key_nsclientinternal_paused)))
|
||||
}
|
||||
}
|
||||
|
||||
fun calculateStatus(ev: EventChargingState): Boolean {
|
||||
val chargingOnly = sp.getBoolean(R.string.key_ns_chargingonly, false)
|
||||
var newAllowedState = true
|
||||
if (!ev.isCharging && chargingOnly) {
|
||||
newAllowedState = false
|
||||
}
|
||||
return newAllowedState
|
||||
}
|
||||
|
||||
fun calculateStatus(ev: EventNetworkChange?): Boolean {
|
||||
val wifiOnly = sp.getBoolean(R.string.key_ns_wifionly, false)
|
||||
val allowedSsidString = sp.getString(R.string.key_ns_wifi_ssids, "")
|
||||
val allowedSSIDs: List<String> = if (allowedSsidString.isEmpty()) List(0) { "" } else allowedSsidString.split(";")
|
||||
val allowRoaming = sp.getBoolean(R.string.key_ns_allowroaming, true)
|
||||
var newAllowedState = true
|
||||
if (ev?.wifiConnected == true) {
|
||||
if (allowedSSIDs.isNotEmpty() && !allowedSSIDs.contains(ev.ssid)) {
|
||||
newAllowedState = false
|
||||
}
|
||||
} else {
|
||||
if (!allowRoaming && ev?.roaming == true || wifiOnly) {
|
||||
newAllowedState = false
|
||||
}
|
||||
}
|
||||
return newAllowedState
|
||||
}
|
||||
}
|
|
@ -1,124 +0,0 @@
|
|||
package info.nightscout.androidaps.plugins.general.nsclient;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.SystemClock;
|
||||
|
||||
import com.j256.ormlite.dao.CloseableIterator;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
import info.nightscout.androidaps.R;
|
||||
import info.nightscout.androidaps.db.DatabaseHelper;
|
||||
import info.nightscout.androidaps.db.DbRequest;
|
||||
import info.nightscout.androidaps.interfaces.DatabaseHelperInterface;
|
||||
import info.nightscout.androidaps.interfaces.UploadQueueAdminInterface;
|
||||
import info.nightscout.androidaps.interfaces.UploadQueueInterface;
|
||||
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.nsclient.events.EventNSClientResend;
|
||||
import info.nightscout.androidaps.plugins.general.nsclient.services.NSClientService;
|
||||
import info.nightscout.androidaps.utils.sharedPreferences.SP;
|
||||
|
||||
/**
|
||||
* Created by mike on 21.02.2016.
|
||||
*/
|
||||
public class UploadQueue implements UploadQueueAdminInterface {
|
||||
private final AAPSLogger aapsLogger;
|
||||
private final DatabaseHelperInterface databaseHelper;
|
||||
private final Context context;
|
||||
private final SP sp;
|
||||
private final RxBusWrapper rxBus;
|
||||
|
||||
public UploadQueue(
|
||||
AAPSLogger aapsLogger,
|
||||
DatabaseHelperInterface databaseHelper,
|
||||
Context context,
|
||||
SP sp,
|
||||
RxBusWrapper rxBus
|
||||
) {
|
||||
this.aapsLogger = aapsLogger;
|
||||
this.databaseHelper = databaseHelper;
|
||||
this.context = context;
|
||||
this.sp = sp;
|
||||
this.rxBus = rxBus;
|
||||
}
|
||||
|
||||
public String status() {
|
||||
return "QUEUE: " + databaseHelper.size(DatabaseHelper.DATABASE_DBREQUESTS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long size() {
|
||||
return databaseHelper.size(DatabaseHelper.DATABASE_DBREQUESTS);
|
||||
}
|
||||
|
||||
private void startService() {
|
||||
if (NSClientService.handler == null) {
|
||||
context.startService(new Intent(context, NSClientService.class));
|
||||
SystemClock.sleep(2000);
|
||||
}
|
||||
}
|
||||
|
||||
public void add(final DbRequest dbr) {
|
||||
if (sp.getBoolean(R.string.key_ns_noupload, false)) return;
|
||||
aapsLogger.debug(LTag.NSCLIENT, "Adding to queue: " + dbr.log());
|
||||
try {
|
||||
databaseHelper.create(dbr);
|
||||
} catch (Exception e) {
|
||||
aapsLogger.error("Unhandled exception", e);
|
||||
}
|
||||
rxBus.send(new EventNSClientResend("newdata"));
|
||||
}
|
||||
|
||||
@Override public void clearQueue() {
|
||||
startService();
|
||||
if (NSClientService.handler != null) {
|
||||
NSClientService.handler.post(() -> {
|
||||
aapsLogger.debug(LTag.NSCLIENT, "ClearQueue");
|
||||
databaseHelper.deleteAllDbRequests();
|
||||
aapsLogger.debug(LTag.NSCLIENT, status());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeByMongoId(final String action, final String _id) {
|
||||
if (_id == null || _id.equals(""))
|
||||
return;
|
||||
startService();
|
||||
if (NSClientService.handler != null) {
|
||||
NSClientService.handler.post(() -> {
|
||||
databaseHelper.deleteDbRequestbyMongoId(action, _id);
|
||||
aapsLogger.debug(LTag.NSCLIENT, "Removing " + _id + " from UploadQueue. " + status());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override public String textList() {
|
||||
String result = "";
|
||||
CloseableIterator<DbRequest> iterator;
|
||||
try {
|
||||
iterator = databaseHelper.getDbRequestIterator();
|
||||
try {
|
||||
while (iterator.hasNext()) {
|
||||
DbRequest dbr = iterator.next();
|
||||
result += "<br>";
|
||||
result += dbr.action.toUpperCase() + " ";
|
||||
result += dbr.collection + ": ";
|
||||
result += dbr.data;
|
||||
}
|
||||
} finally {
|
||||
iterator.close();
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
aapsLogger.error("Unhandled exception", e);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,913 +0,0 @@
|
|||
package info.nightscout.androidaps.plugins.general.nsclient.services;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Binder;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.HandlerThread;
|
||||
import android.os.IBinder;
|
||||
import android.os.PowerManager;
|
||||
import android.os.SystemClock;
|
||||
|
||||
import androidx.work.OneTimeWorkRequest;
|
||||
|
||||
import com.google.common.base.Charsets;
|
||||
import com.google.common.hash.Hashing;
|
||||
import com.j256.ormlite.dao.CloseableIterator;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.net.URISyntaxException;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import dagger.android.DaggerService;
|
||||
import dagger.android.HasAndroidInjector;
|
||||
import info.nightscout.androidaps.interfaces.Config;
|
||||
import info.nightscout.androidaps.R;
|
||||
import info.nightscout.androidaps.database.AppRepository;
|
||||
import info.nightscout.androidaps.db.DbRequest;
|
||||
import info.nightscout.androidaps.events.EventAppExit;
|
||||
import info.nightscout.androidaps.events.EventConfigBuilderChange;
|
||||
import info.nightscout.androidaps.events.EventPreferenceChange;
|
||||
import info.nightscout.androidaps.interfaces.DataSyncSelector;
|
||||
import info.nightscout.androidaps.interfaces.DatabaseHelperInterface;
|
||||
import info.nightscout.androidaps.interfaces.PluginType;
|
||||
import info.nightscout.androidaps.interfaces.UploadQueueInterface;
|
||||
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.food.FoodPlugin;
|
||||
import info.nightscout.androidaps.plugins.general.nsclient.NSClientAddAckWorker;
|
||||
import info.nightscout.androidaps.plugins.general.nsclient.NSClientAddUpdateWorker;
|
||||
import info.nightscout.androidaps.plugins.general.nsclient.NSClientMbgWorker;
|
||||
import info.nightscout.androidaps.plugins.general.nsclient.NSClientPlugin;
|
||||
import info.nightscout.androidaps.plugins.general.nsclient.NSClientRemoveWorker;
|
||||
import info.nightscout.androidaps.plugins.general.nsclient.NSClientUpdateRemoveAckWorker;
|
||||
import info.nightscout.androidaps.plugins.general.nsclient.acks.NSAddAck;
|
||||
import info.nightscout.androidaps.plugins.general.nsclient.acks.NSAuthAck;
|
||||
import info.nightscout.androidaps.plugins.general.nsclient.acks.NSUpdateAck;
|
||||
import info.nightscout.androidaps.plugins.general.nsclient.data.AlarmAck;
|
||||
import info.nightscout.androidaps.plugins.general.nsclient.data.NSAlarm;
|
||||
import info.nightscout.androidaps.plugins.general.nsclient.data.NSDeviceStatus;
|
||||
import info.nightscout.androidaps.plugins.general.nsclient.data.NSSettingsStatus;
|
||||
import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientNewLog;
|
||||
import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientRestart;
|
||||
import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientStatus;
|
||||
import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientUpdateGUI;
|
||||
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.notifications.Notification;
|
||||
import info.nightscout.androidaps.plugins.general.overview.notifications.NotificationWithAction;
|
||||
import info.nightscout.androidaps.plugins.profile.ns.NSProfilePlugin;
|
||||
import info.nightscout.androidaps.plugins.source.NSClientSourcePlugin;
|
||||
import info.nightscout.androidaps.receivers.DataWorker;
|
||||
import info.nightscout.androidaps.services.Intents;
|
||||
import info.nightscout.androidaps.utils.DateUtil;
|
||||
import info.nightscout.androidaps.utils.FabricPrivacy;
|
||||
import info.nightscout.androidaps.utils.JsonHelper;
|
||||
import info.nightscout.androidaps.utils.T;
|
||||
import info.nightscout.androidaps.utils.buildHelper.BuildHelper;
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper;
|
||||
import info.nightscout.androidaps.utils.rx.AapsSchedulers;
|
||||
import info.nightscout.androidaps.utils.sharedPreferences.SP;
|
||||
import io.reactivex.disposables.CompositeDisposable;
|
||||
import io.socket.client.IO;
|
||||
import io.socket.client.Socket;
|
||||
import io.socket.emitter.Emitter;
|
||||
|
||||
public class NSClientService extends DaggerService {
|
||||
@Inject HasAndroidInjector injector;
|
||||
@Inject AAPSLogger aapsLogger;
|
||||
@Inject AapsSchedulers aapsSchedulers;
|
||||
@Inject NSSettingsStatus nsSettingsStatus;
|
||||
@Inject NSDeviceStatus nsDeviceStatus;
|
||||
@Inject DatabaseHelperInterface databaseHelper;
|
||||
@Inject RxBusWrapper rxBus;
|
||||
@Inject ResourceHelper resourceHelper;
|
||||
@Inject SP sp;
|
||||
@Inject FabricPrivacy fabricPrivacy;
|
||||
@Inject NSClientPlugin nsClientPlugin;
|
||||
@Inject BuildHelper buildHelper;
|
||||
@Inject Config config;
|
||||
@Inject DateUtil dateUtil;
|
||||
@Inject UploadQueueInterface uploadQueue;
|
||||
@Inject DataWorker dataWorker;
|
||||
@Inject DataSyncSelector dataSyncSelector;
|
||||
@Inject AppRepository repository;
|
||||
|
||||
private final CompositeDisposable disposable = new CompositeDisposable();
|
||||
|
||||
static public PowerManager.WakeLock mWakeLock;
|
||||
private final IBinder mBinder = new NSClientService.LocalBinder();
|
||||
|
||||
static public Handler handler;
|
||||
|
||||
public static Socket mSocket;
|
||||
public static boolean isConnected = false;
|
||||
public static boolean hasWriteAuth = false;
|
||||
private static Integer dataCounter = 0;
|
||||
private static Integer connectCounter = 0;
|
||||
|
||||
|
||||
private boolean nsEnabled = false;
|
||||
static public String nsURL = "";
|
||||
private String nsAPISecret = "";
|
||||
private String nsDevice = "";
|
||||
private final Integer nsHours = 48;
|
||||
|
||||
public long lastResendTime = 0;
|
||||
public long lastAckTime = 0;
|
||||
|
||||
public long latestDateInReceivedData = 0;
|
||||
|
||||
private String nsAPIhashCode = "";
|
||||
|
||||
private final ArrayList<Long> reconnections = new ArrayList<>();
|
||||
private final int WATCHDOG_INTERVAL_MINUTES = 2;
|
||||
private final int WATCHDOG_RECONNECT_IN = 15;
|
||||
private final int WATCHDOG_MAX_CONNECTIONS = 5;
|
||||
|
||||
public NSClientService() {
|
||||
super();
|
||||
if (handler == null) {
|
||||
HandlerThread handlerThread = new HandlerThread(NSClientService.class.getSimpleName() + "Handler");
|
||||
handlerThread.start();
|
||||
handler = new Handler(handlerThread.getLooper());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
PowerManager powerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
|
||||
mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "AndroidAPS:NSClientService");
|
||||
mWakeLock.acquire();
|
||||
|
||||
initialize();
|
||||
|
||||
disposable.add(rxBus
|
||||
.toObservable(EventConfigBuilderChange.class)
|
||||
.observeOn(aapsSchedulers.getIo())
|
||||
.subscribe(event -> {
|
||||
if (nsEnabled != nsClientPlugin.isEnabled(PluginType.GENERAL)) {
|
||||
latestDateInReceivedData = 0;
|
||||
destroy();
|
||||
initialize();
|
||||
}
|
||||
}, fabricPrivacy::logException)
|
||||
);
|
||||
disposable.add(rxBus
|
||||
.toObservable(EventPreferenceChange.class)
|
||||
.observeOn(aapsSchedulers.getIo())
|
||||
.subscribe(event -> {
|
||||
if (event.isChanged(resourceHelper, R.string.key_nsclientinternal_url) ||
|
||||
event.isChanged(resourceHelper, R.string.key_nsclientinternal_api_secret) ||
|
||||
event.isChanged(resourceHelper, R.string.key_nsclientinternal_paused)
|
||||
) {
|
||||
latestDateInReceivedData = 0;
|
||||
destroy();
|
||||
initialize();
|
||||
}
|
||||
}, fabricPrivacy::logException)
|
||||
);
|
||||
disposable.add(rxBus
|
||||
.toObservable(EventAppExit.class)
|
||||
.observeOn(aapsSchedulers.getIo())
|
||||
.subscribe(event -> {
|
||||
aapsLogger.debug(LTag.NSCLIENT, "EventAppExit received");
|
||||
destroy();
|
||||
stopSelf();
|
||||
}, fabricPrivacy::logException)
|
||||
);
|
||||
disposable.add(rxBus
|
||||
.toObservable(EventNSClientRestart.class)
|
||||
.observeOn(aapsSchedulers.getIo())
|
||||
.subscribe(event -> {
|
||||
latestDateInReceivedData = 0;
|
||||
restart();
|
||||
}, fabricPrivacy::logException)
|
||||
);
|
||||
disposable.add(rxBus
|
||||
.toObservable(NSAuthAck.class)
|
||||
.observeOn(aapsSchedulers.getIo())
|
||||
.subscribe(this::processAuthAck, fabricPrivacy::logException)
|
||||
);
|
||||
disposable.add(rxBus
|
||||
.toObservable(NSUpdateAck.class)
|
||||
.observeOn(aapsSchedulers.getIo())
|
||||
.subscribe(this::processUpdateAck, fabricPrivacy::logException)
|
||||
);
|
||||
disposable.add(rxBus
|
||||
.toObservable(NSAddAck.class)
|
||||
.observeOn(aapsSchedulers.getIo())
|
||||
.subscribe(this::processAddAck, fabricPrivacy::logException)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
disposable.clear();
|
||||
if (mWakeLock.isHeld()) mWakeLock.release();
|
||||
}
|
||||
|
||||
public void processAddAck(NSAddAck ack) {
|
||||
lastAckTime = dateUtil.now();
|
||||
dataWorker.enqueue(
|
||||
new OneTimeWorkRequest.Builder(NSClientAddAckWorker.class)
|
||||
.setInputData(dataWorker.storeInputData(ack, null))
|
||||
.build());
|
||||
}
|
||||
|
||||
public void processUpdateAck(NSUpdateAck ack) {
|
||||
lastAckTime = dateUtil.now();
|
||||
dataWorker.enqueue(
|
||||
new OneTimeWorkRequest.Builder(NSClientUpdateRemoveAckWorker.class)
|
||||
.setInputData(dataWorker.storeInputData(ack, null))
|
||||
.build());
|
||||
}
|
||||
|
||||
public void processAuthAck(NSAuthAck ack) {
|
||||
String connectionStatus = "Authenticated (";
|
||||
if (ack.read) connectionStatus += "R";
|
||||
if (ack.write) connectionStatus += "W";
|
||||
if (ack.write_treatment) connectionStatus += "T";
|
||||
connectionStatus += ')';
|
||||
isConnected = true;
|
||||
hasWriteAuth = ack.write && ack.write_treatment;
|
||||
rxBus.send(new EventNSClientStatus(connectionStatus));
|
||||
rxBus.send(new EventNSClientNewLog("AUTH", connectionStatus));
|
||||
if (!ack.write) {
|
||||
rxBus.send(new EventNSClientNewLog("ERROR", "Write permission not granted !!!!"));
|
||||
}
|
||||
if (!ack.write_treatment) {
|
||||
rxBus.send(new EventNSClientNewLog("ERROR", "Write treatment permission not granted !!!!"));
|
||||
}
|
||||
if (!hasWriteAuth) {
|
||||
Notification noperm = new Notification(Notification.NSCLIENT_NO_WRITE_PERMISSION, resourceHelper.gs(R.string.nowritepermission), Notification.URGENT);
|
||||
rxBus.send(new EventNewNotification(noperm));
|
||||
} else {
|
||||
rxBus.send(new EventDismissNotification(Notification.NSCLIENT_NO_WRITE_PERMISSION));
|
||||
}
|
||||
}
|
||||
|
||||
public class LocalBinder extends Binder {
|
||||
public NSClientService getServiceInstance() {
|
||||
return NSClientService.this;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) {
|
||||
return mBinder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||
|
||||
return START_STICKY;
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public void initialize() {
|
||||
dataCounter = 0;
|
||||
|
||||
readPreferences();
|
||||
|
||||
if (!nsAPISecret.equals(""))
|
||||
nsAPIhashCode = Hashing.sha1().hashString(nsAPISecret, Charsets.UTF_8).toString();
|
||||
|
||||
rxBus.send(new EventNSClientStatus("Initializing"));
|
||||
if (!nsClientPlugin.isAllowed()) {
|
||||
rxBus.send(new EventNSClientNewLog("NSCLIENT", "not allowed"));
|
||||
rxBus.send(new EventNSClientStatus("Not allowed"));
|
||||
} else if (nsClientPlugin.paused) {
|
||||
rxBus.send(new EventNSClientNewLog("NSCLIENT", "paused"));
|
||||
rxBus.send(new EventNSClientStatus("Paused"));
|
||||
} else if (!nsEnabled) {
|
||||
rxBus.send(new EventNSClientNewLog("NSCLIENT", "disabled"));
|
||||
rxBus.send(new EventNSClientStatus("Disabled"));
|
||||
} else if (!nsURL.equals("") && (buildHelper.isEngineeringMode() || nsURL.toLowerCase().startsWith("https://"))) {
|
||||
try {
|
||||
rxBus.send(new EventNSClientStatus("Connecting ..."));
|
||||
IO.Options opt = new IO.Options();
|
||||
opt.forceNew = true;
|
||||
opt.reconnection = true;
|
||||
mSocket = IO.socket(nsURL, opt);
|
||||
mSocket.on(Socket.EVENT_CONNECT, onConnect);
|
||||
mSocket.on(Socket.EVENT_DISCONNECT, onDisconnect);
|
||||
mSocket.on(Socket.EVENT_ERROR, onError);
|
||||
mSocket.on(Socket.EVENT_CONNECT_ERROR, onError);
|
||||
mSocket.on(Socket.EVENT_CONNECT_TIMEOUT, onError);
|
||||
mSocket.on(Socket.EVENT_PING, onPing);
|
||||
rxBus.send(new EventNSClientNewLog("NSCLIENT", "do connect"));
|
||||
mSocket.connect();
|
||||
mSocket.on("dataUpdate", onDataUpdate);
|
||||
mSocket.on("announcement", onAnnouncement);
|
||||
mSocket.on("alarm", onAlarm);
|
||||
mSocket.on("urgent_alarm", onUrgentAlarm);
|
||||
mSocket.on("clear_alarm", onClearAlarm);
|
||||
} catch (URISyntaxException | RuntimeException e) {
|
||||
rxBus.send(new EventNSClientNewLog("NSCLIENT", "Wrong URL syntax"));
|
||||
rxBus.send(new EventNSClientStatus("Wrong URL syntax"));
|
||||
}
|
||||
} else if (nsURL.toLowerCase().startsWith("http://")) {
|
||||
rxBus.send(new EventNSClientNewLog("NSCLIENT", "NS URL not encrypted"));
|
||||
rxBus.send(new EventNSClientStatus("Not encrypted"));
|
||||
} else {
|
||||
rxBus.send(new EventNSClientNewLog("NSCLIENT", "No NS URL specified"));
|
||||
rxBus.send(new EventNSClientStatus("Not configured"));
|
||||
}
|
||||
}
|
||||
|
||||
private final Emitter.Listener onConnect = new Emitter.Listener() {
|
||||
@Override
|
||||
public void call(Object... args) {
|
||||
connectCounter++;
|
||||
String socketId = mSocket != null ? mSocket.id() : "NULL";
|
||||
rxBus.send(new EventNSClientNewLog("NSCLIENT", "connect #" + connectCounter + " event. ID: " + socketId));
|
||||
if (mSocket != null)
|
||||
sendAuthMessage(new NSAuthAck(rxBus));
|
||||
watchdog();
|
||||
}
|
||||
};
|
||||
|
||||
void watchdog() {
|
||||
synchronized (reconnections) {
|
||||
long now = dateUtil.now();
|
||||
reconnections.add(now);
|
||||
for (int i = 0; i < reconnections.size(); i++) {
|
||||
Long r = reconnections.get(i);
|
||||
if (r < now - T.mins(WATCHDOG_INTERVAL_MINUTES).msecs()) {
|
||||
reconnections.remove(r);
|
||||
}
|
||||
}
|
||||
rxBus.send(new EventNSClientNewLog("WATCHDOG", "connections in last " + WATCHDOG_INTERVAL_MINUTES + " mins: " + reconnections.size() + "/" + WATCHDOG_MAX_CONNECTIONS));
|
||||
if (reconnections.size() >= WATCHDOG_MAX_CONNECTIONS) {
|
||||
Notification n = new Notification(Notification.NS_MALFUNCTION, resourceHelper.gs(R.string.nsmalfunction), Notification.URGENT);
|
||||
rxBus.send(new EventNewNotification(n));
|
||||
rxBus.send(new EventNSClientNewLog("WATCHDOG", "pausing for " + WATCHDOG_RECONNECT_IN + " mins"));
|
||||
nsClientPlugin.pause(true);
|
||||
rxBus.send(new EventNSClientUpdateGUI());
|
||||
new Thread(() -> {
|
||||
SystemClock.sleep(T.mins(WATCHDOG_RECONNECT_IN).msecs());
|
||||
rxBus.send(new EventNSClientNewLog("WATCHDOG", "reenabling NSClient"));
|
||||
nsClientPlugin.pause(false);
|
||||
}).start();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private final Emitter.Listener onDisconnect = new Emitter.Listener() {
|
||||
@Override
|
||||
public void call(Object... args) {
|
||||
aapsLogger.debug(LTag.NSCLIENT, "disconnect reason: {}", args);
|
||||
rxBus.send(new EventNSClientNewLog("NSCLIENT", "disconnect event"));
|
||||
}
|
||||
};
|
||||
|
||||
public synchronized void destroy() {
|
||||
if (mSocket != null) {
|
||||
mSocket.off(Socket.EVENT_CONNECT);
|
||||
mSocket.off(Socket.EVENT_DISCONNECT);
|
||||
mSocket.off(Socket.EVENT_PING);
|
||||
mSocket.off("dataUpdate");
|
||||
mSocket.off("announcement");
|
||||
mSocket.off("alarm");
|
||||
mSocket.off("urgent_alarm");
|
||||
mSocket.off("clear_alarm");
|
||||
|
||||
rxBus.send(new EventNSClientNewLog("NSCLIENT", "destroy"));
|
||||
isConnected = false;
|
||||
hasWriteAuth = false;
|
||||
mSocket.disconnect();
|
||||
mSocket = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void sendAuthMessage(NSAuthAck ack) {
|
||||
JSONObject authMessage = new JSONObject();
|
||||
try {
|
||||
authMessage.put("client", "Android_" + nsDevice);
|
||||
authMessage.put("history", nsHours);
|
||||
authMessage.put("status", true); // receive status
|
||||
authMessage.put("from", latestDateInReceivedData); // send data newer than
|
||||
authMessage.put("secret", nsAPIhashCode);
|
||||
} catch (JSONException e) {
|
||||
aapsLogger.error("Unhandled exception", e);
|
||||
return;
|
||||
}
|
||||
rxBus.send(new EventNSClientNewLog("AUTH", "requesting auth"));
|
||||
if (mSocket != null)
|
||||
mSocket.emit("authorize", authMessage, ack);
|
||||
}
|
||||
|
||||
public void readPreferences() {
|
||||
nsEnabled = nsClientPlugin.isEnabled(PluginType.GENERAL);
|
||||
nsURL = sp.getString(R.string.key_nsclientinternal_url, "");
|
||||
nsAPISecret = sp.getString(R.string.key_nsclientinternal_api_secret, "");
|
||||
nsDevice = sp.getString("careportal_enteredby", "");
|
||||
}
|
||||
|
||||
private final Emitter.Listener onError = new Emitter.Listener() {
|
||||
@Override
|
||||
public void call(final Object... args) {
|
||||
String msg = "Unknown Error";
|
||||
if (args.length > 0 && args[0] != null) {
|
||||
msg = args[0].toString();
|
||||
}
|
||||
rxBus.send(new EventNSClientNewLog("ERROR", msg));
|
||||
}
|
||||
};
|
||||
|
||||
private final Emitter.Listener onPing = new Emitter.Listener() {
|
||||
@Override
|
||||
public void call(final Object... args) {
|
||||
rxBus.send(new EventNSClientNewLog("PING", "received"));
|
||||
// send data if there is something waiting
|
||||
resend("Ping received");
|
||||
}
|
||||
};
|
||||
|
||||
private final Emitter.Listener onAnnouncement = new Emitter.Listener() {
|
||||
/*
|
||||
{
|
||||
"level":0,
|
||||
"title":"Announcement",
|
||||
"message":"test",
|
||||
"plugin":{"name":"treatmentnotify","label":"Treatment Notifications","pluginType":"notification","enabled":true},
|
||||
"group":"Announcement",
|
||||
"isAnnouncement":true,
|
||||
"key":"9ac46ad9a1dcda79dd87dae418fce0e7955c68da"
|
||||
}
|
||||
*/
|
||||
@Override
|
||||
public void call(final Object... args) {
|
||||
JSONObject data;
|
||||
try {
|
||||
data = (JSONObject) args[0];
|
||||
handleAnnouncement(data);
|
||||
} catch (Exception e) {
|
||||
aapsLogger.error("Unhandled exception", e);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private final Emitter.Listener onAlarm = new Emitter.Listener() {
|
||||
/*
|
||||
{
|
||||
"level":1,
|
||||
"title":"Warning HIGH",
|
||||
"message":"BG Now: 5 -0.2 → mmol\/L\nRaw BG: 4.8 mmol\/L Čistý\nBG 15m: 4.8 mmol\/L\nIOB: -0.02U\nCOB: 0g",
|
||||
"eventName":"high",
|
||||
"plugin":{"name":"simplealarms","label":"Simple Alarms","pluginType":"notification","enabled":true},
|
||||
"pushoverSound":"climb",
|
||||
"debug":{"lastSGV":5,"thresholds":{"bgHigh":180,"bgTargetTop":75,"bgTargetBottom":72,"bgLow":70}},
|
||||
"group":"default",
|
||||
"key":"simplealarms_1"
|
||||
}
|
||||
*/
|
||||
@Override
|
||||
public void call(final Object... args) {
|
||||
JSONObject data;
|
||||
try {
|
||||
data = (JSONObject) args[0];
|
||||
handleAlarm(data);
|
||||
} catch (Exception e) {
|
||||
aapsLogger.error("Unhandled exception", e);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private final Emitter.Listener onUrgentAlarm = args -> {
|
||||
JSONObject data;
|
||||
try {
|
||||
data = (JSONObject) args[0];
|
||||
handleUrgentAlarm(data);
|
||||
} catch (Exception e) {
|
||||
aapsLogger.error("Unhandled exception", e);
|
||||
}
|
||||
};
|
||||
|
||||
private final Emitter.Listener onClearAlarm = new Emitter.Listener() {
|
||||
/*
|
||||
{
|
||||
"clear":true,
|
||||
"title":"All Clear",
|
||||
"message":"default - Urgent was ack'd",
|
||||
"group":"default"
|
||||
}
|
||||
*/
|
||||
@Override
|
||||
public void call(final Object... args) {
|
||||
JSONObject data;
|
||||
try {
|
||||
data = (JSONObject) args[0];
|
||||
rxBus.send(new EventNSClientNewLog("CLEARALARM", "received"));
|
||||
rxBus.send(new EventDismissNotification(Notification.NS_ALARM));
|
||||
rxBus.send(new EventDismissNotification(Notification.NS_URGENT_ALARM));
|
||||
aapsLogger.debug(LTag.NSCLIENT, data.toString());
|
||||
} catch (Exception e) {
|
||||
aapsLogger.error("Unhandled exception", e);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private final Emitter.Listener onDataUpdate = new Emitter.Listener() {
|
||||
@Override
|
||||
public void call(final Object... args) {
|
||||
NSClientService.handler.post(() -> {
|
||||
PowerManager powerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
|
||||
PowerManager.WakeLock wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
|
||||
"AndroidAPS:NSClientService_onDataUpdate");
|
||||
wakeLock.acquire();
|
||||
try {
|
||||
|
||||
JSONObject data = (JSONObject) args[0];
|
||||
boolean broadcastProfile = false;
|
||||
try {
|
||||
// delta means only increment/changes are comming
|
||||
boolean isDelta = data.has("delta");
|
||||
boolean isFull = !isDelta;
|
||||
rxBus.send(new EventNSClientNewLog("DATA", "Data packet #" + dataCounter++ + (isDelta ? " delta" : " full")));
|
||||
|
||||
if (data.has("status")) {
|
||||
JSONObject status = data.getJSONObject("status");
|
||||
nsSettingsStatus.handleNewData(status);
|
||||
} else if (!isDelta) {
|
||||
rxBus.send(new EventNSClientNewLog("ERROR", "Unsupported Nightscout version !!!!"));
|
||||
}
|
||||
|
||||
if (data.has("profiles")) {
|
||||
JSONArray profiles = data.getJSONArray("profiles");
|
||||
if (profiles.length() > 0) {
|
||||
// take the newest
|
||||
JSONObject profileStoreJson = (JSONObject) profiles.get(profiles.length() - 1);
|
||||
rxBus.send(new EventNSClientNewLog("PROFILE", "profile received"));
|
||||
dataWorker.enqueue(
|
||||
new OneTimeWorkRequest.Builder(NSProfilePlugin.NSProfileWorker.class)
|
||||
.setInputData(dataWorker.storeInputData(profileStoreJson, null))
|
||||
.build());
|
||||
|
||||
if (sp.getBoolean(R.string.key_nsclient_localbroadcasts, false)) {
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putString("profile", profileStoreJson.toString());
|
||||
bundle.putBoolean("delta", isDelta);
|
||||
Intent intent = new Intent(Intents.ACTION_NEW_PROFILE);
|
||||
intent.putExtras(bundle);
|
||||
intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
|
||||
sendBroadcast(intent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (data.has("treatments")) {
|
||||
JSONArray treatments = data.getJSONArray("treatments");
|
||||
JSONArray removedTreatments = new JSONArray();
|
||||
JSONArray addedOrUpdatedTreatments = new JSONArray();
|
||||
if (treatments.length() > 0)
|
||||
rxBus.send(new EventNSClientNewLog("DATA", "received " + treatments.length() + " treatments"));
|
||||
for (Integer index = 0; index < treatments.length(); index++) {
|
||||
JSONObject jsonTreatment = treatments.getJSONObject(index);
|
||||
String action = JsonHelper.safeGetStringAllowNull(jsonTreatment, "action", null);
|
||||
long mills = JsonHelper.safeGetLong(jsonTreatment, "mills");
|
||||
|
||||
if (action == null) addedOrUpdatedTreatments.put(jsonTreatment);
|
||||
else if (action.equals("update"))
|
||||
addedOrUpdatedTreatments.put(jsonTreatment);
|
||||
else if (action.equals("remove") && mills > dateUtil.now() - T.days(1).msecs()) // handle 1 day old deletions only
|
||||
removedTreatments.put(jsonTreatment);
|
||||
}
|
||||
if (removedTreatments.length() > 0) {
|
||||
dataWorker.enqueue(
|
||||
new OneTimeWorkRequest.Builder(NSClientRemoveWorker.class)
|
||||
.setInputData(dataWorker.storeInputData(removedTreatments, null))
|
||||
.build());
|
||||
|
||||
if (sp.getBoolean(R.string.key_nsclient_localbroadcasts, false)) {
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putString("treatments", removedTreatments.toString());
|
||||
bundle.putBoolean("delta", isDelta);
|
||||
Intent intent = new Intent(Intents.ACTION_REMOVED_TREATMENT);
|
||||
intent.putExtras(bundle);
|
||||
intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
|
||||
sendBroadcast(intent);
|
||||
}
|
||||
}
|
||||
if (addedOrUpdatedTreatments.length() > 0) {
|
||||
dataWorker.enqueue(
|
||||
new OneTimeWorkRequest.Builder(NSClientAddUpdateWorker.class)
|
||||
.setInputData(dataWorker.storeInputData(addedOrUpdatedTreatments, null))
|
||||
.build());
|
||||
|
||||
if (sp.getBoolean(R.string.key_nsclient_localbroadcasts, false)) {
|
||||
List<JSONArray> splitted = splitArray(addedOrUpdatedTreatments);
|
||||
for (JSONArray part : splitted) {
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putString("treatments", part.toString());
|
||||
bundle.putBoolean("delta", isDelta);
|
||||
Intent intent = new Intent(Intents.ACTION_CHANGED_TREATMENT);
|
||||
intent.putExtras(bundle);
|
||||
intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
|
||||
sendBroadcast(intent);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (data.has("devicestatus")) {
|
||||
JSONArray devicestatuses = data.getJSONArray("devicestatus");
|
||||
if (devicestatuses.length() > 0) {
|
||||
rxBus.send(new EventNSClientNewLog("DATA", "received " + devicestatuses.length() + " device statuses"));
|
||||
nsDeviceStatus.handleNewData(devicestatuses);
|
||||
}
|
||||
}
|
||||
if (data.has("food")) {
|
||||
JSONArray foods = data.getJSONArray("food");
|
||||
if (foods.length() > 0)
|
||||
rxBus.send(new EventNSClientNewLog("DATA", "received " + foods.length() + " foods"));
|
||||
dataWorker.enqueue(
|
||||
new OneTimeWorkRequest.Builder(FoodPlugin.FoodWorker.class)
|
||||
.setInputData(dataWorker.storeInputData(foods, null))
|
||||
.build());
|
||||
}
|
||||
//noinspection SpellCheckingInspection
|
||||
if (data.has("mbgs")) {
|
||||
JSONArray mbgArray = data.getJSONArray("mbgs");
|
||||
if (mbgArray.length() > 0)
|
||||
rxBus.send(new EventNSClientNewLog("DATA", "received " + mbgArray.length() + " mbgs"));
|
||||
dataWorker.enqueue(
|
||||
new OneTimeWorkRequest.Builder(NSClientMbgWorker.class)
|
||||
.setInputData(dataWorker.storeInputData(mbgArray, null))
|
||||
.build());
|
||||
}
|
||||
if (data.has("cals")) {
|
||||
JSONArray cals = data.getJSONArray("cals");
|
||||
if (cals.length() > 0)
|
||||
rxBus.send(new EventNSClientNewLog("DATA", "received " + cals.length() + " cals"));
|
||||
// Calibrations ignored
|
||||
}
|
||||
if (data.has("sgvs")) {
|
||||
JSONArray sgvs = data.getJSONArray("sgvs");
|
||||
if (sgvs.length() > 0)
|
||||
rxBus.send(new EventNSClientNewLog("DATA", "received " + sgvs.length() + " sgvs"));
|
||||
|
||||
dataWorker.enqueue(new OneTimeWorkRequest.Builder(NSClientSourcePlugin.NSClientSourceWorker.class)
|
||||
.setInputData(dataWorker.storeInputData(sgvs, null))
|
||||
.build());
|
||||
|
||||
List<JSONArray> splitted = splitArray(sgvs);
|
||||
if (sp.getBoolean(R.string.key_nsclient_localbroadcasts, false)) {
|
||||
for (JSONArray part : splitted) {
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putString("sgvs", part.toString());
|
||||
bundle.putBoolean("delta", isDelta);
|
||||
Intent intent = new Intent(Intents.ACTION_NEW_SGV);
|
||||
intent.putExtras(bundle);
|
||||
intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
|
||||
sendBroadcast(intent);
|
||||
}
|
||||
}
|
||||
}
|
||||
rxBus.send(new EventNSClientNewLog("LAST", dateUtil.dateAndTimeString(latestDateInReceivedData)));
|
||||
} catch (JSONException e) {
|
||||
aapsLogger.error("Unhandled exception", e);
|
||||
}
|
||||
//rxBus.send(new EventNSClientNewLog("NSCLIENT", "onDataUpdate end");
|
||||
} finally {
|
||||
if (wakeLock.isHeld()) wakeLock.release();
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
public void dbUpdate(DbRequest dbr, NSUpdateAck ack) {
|
||||
try {
|
||||
if (!isConnected || !hasWriteAuth) return;
|
||||
JSONObject message = new JSONObject();
|
||||
message.put("collection", dbr.collection);
|
||||
message.put("_id", dbr._id);
|
||||
message.put("data", new JSONObject(dbr.data));
|
||||
mSocket.emit("dbUpdate", message, ack);
|
||||
rxBus.send(new EventNSClientNewLog("DBUPDATE " + dbr.collection, "Sent " + dbr._id));
|
||||
} catch (JSONException e) {
|
||||
aapsLogger.error("Unhandled exception", e);
|
||||
}
|
||||
}
|
||||
|
||||
public void dbUpdate(String collection, String _id, JSONObject data, Object originalObject) {
|
||||
try {
|
||||
if (!isConnected || !hasWriteAuth) return;
|
||||
JSONObject message = new JSONObject();
|
||||
message.put("collection", collection);
|
||||
message.put("_id", _id);
|
||||
message.put("data", data);
|
||||
mSocket.emit("dbUpdate", message, new NSUpdateAck("dbUpdate", _id, aapsLogger, rxBus, originalObject));
|
||||
rxBus.send(new EventNSClientNewLog("DBUPDATE " + collection, "Sent " + originalObject.getClass().getSimpleName() + " " + _id));
|
||||
} catch (JSONException e) {
|
||||
aapsLogger.error("Unhandled exception", e);
|
||||
}
|
||||
}
|
||||
|
||||
public void dbRemove(DbRequest dbr, NSUpdateAck ack) {
|
||||
try {
|
||||
if (!isConnected || !hasWriteAuth) return;
|
||||
JSONObject message = new JSONObject();
|
||||
message.put("collection", dbr.collection);
|
||||
message.put("_id", dbr._id);
|
||||
mSocket.emit("dbRemove", message, ack);
|
||||
rxBus.send(new EventNSClientNewLog("DBREMOVE " + dbr.collection, "Sent " + dbr._id));
|
||||
} catch (JSONException e) {
|
||||
aapsLogger.error("Unhandled exception", e);
|
||||
}
|
||||
}
|
||||
|
||||
public void dbRemove(String collection, String _id, Object originalObject) {
|
||||
try {
|
||||
if (!isConnected || !hasWriteAuth) return;
|
||||
JSONObject message = new JSONObject();
|
||||
message.put("collection", collection);
|
||||
message.put("_id", _id);
|
||||
mSocket.emit("dbRemove", message, new NSUpdateAck("dbRemove", _id, aapsLogger, rxBus, originalObject));
|
||||
rxBus.send(new EventNSClientNewLog("DBREMOVE " + collection, "Sent " + originalObject.getClass().getSimpleName() + " " + _id));
|
||||
} catch (JSONException e) {
|
||||
aapsLogger.error("Unhandled exception", e);
|
||||
}
|
||||
}
|
||||
|
||||
public void dbAdd(DbRequest dbr, NSAddAck ack) {
|
||||
try {
|
||||
if (!isConnected || !hasWriteAuth) return;
|
||||
JSONObject message = new JSONObject();
|
||||
message.put("collection", dbr.collection);
|
||||
message.put("data", new JSONObject(dbr.data));
|
||||
mSocket.emit("dbAdd", message, ack);
|
||||
rxBus.send(new EventNSClientNewLog("DBADD " + dbr.collection, "Sent " + dbr.nsClientID));
|
||||
} catch (JSONException e) {
|
||||
aapsLogger.error("Unhandled exception", e);
|
||||
}
|
||||
}
|
||||
|
||||
public void dbAdd(String collection, JSONObject data, Object originalObject) {
|
||||
try {
|
||||
if (!isConnected || !hasWriteAuth) return;
|
||||
JSONObject message = new JSONObject();
|
||||
message.put("collection", collection);
|
||||
message.put("data", data);
|
||||
mSocket.emit("dbAdd", message, new NSAddAck(aapsLogger, rxBus, originalObject));
|
||||
rxBus.send(new EventNSClientNewLog("DBADD " + collection, "Sent " + originalObject.getClass().getSimpleName() + " " + data));
|
||||
} catch (JSONException e) {
|
||||
aapsLogger.error("Unhandled exception", e);
|
||||
}
|
||||
}
|
||||
|
||||
public void sendAlarmAck(AlarmAck alarmAck) {
|
||||
if (!isConnected || !hasWriteAuth) return;
|
||||
mSocket.emit("ack", alarmAck.level, alarmAck.group, alarmAck.silenceTime);
|
||||
rxBus.send(new EventNSClientNewLog("ALARMACK ", alarmAck.level + " " + alarmAck.group + " " + alarmAck.silenceTime));
|
||||
}
|
||||
|
||||
public void resend(final String reason) {
|
||||
if (!isConnected || !hasWriteAuth) return;
|
||||
|
||||
handler.post(() -> {
|
||||
if (mSocket == null || !mSocket.connected()) return;
|
||||
|
||||
rxBus.send(new EventNSClientNewLog("QUEUE", "Resend started: " + reason));
|
||||
|
||||
if (lastAckTime > System.currentTimeMillis() - 10 * 1000L) {
|
||||
aapsLogger.debug(LTag.NSCLIENT, "Skipping resend by lastAckTime: " + ((System.currentTimeMillis() - lastAckTime) / 1000L) + " sec");
|
||||
return;
|
||||
}
|
||||
|
||||
dataSyncSelector.processChangedBolusesCompat();
|
||||
dataSyncSelector.processChangedCarbsCompat();
|
||||
dataSyncSelector.processChangedBolusCalculatorResultsCompat();
|
||||
dataSyncSelector.processChangedTemporaryBasalsCompat();
|
||||
dataSyncSelector.processChangedExtendedBolusesCompat();
|
||||
dataSyncSelector.processChangedProfileSwitchesCompat();
|
||||
dataSyncSelector.processChangedGlucoseValuesCompat();
|
||||
dataSyncSelector.processChangedTempTargetsCompat();
|
||||
dataSyncSelector.processChangedFoodsCompat();
|
||||
dataSyncSelector.processChangedTherapyEventsCompat();
|
||||
dataSyncSelector.processChangedDeviceStatusesCompat();
|
||||
|
||||
if (uploadQueue.size() == 0)
|
||||
return;
|
||||
|
||||
if (lastResendTime > System.currentTimeMillis() - 10 * 1000L) {
|
||||
aapsLogger.debug(LTag.NSCLIENT, "Skipping resend by lastResendTime: " + ((System.currentTimeMillis() - lastResendTime) / 1000L) + " sec");
|
||||
return;
|
||||
}
|
||||
lastResendTime = System.currentTimeMillis();
|
||||
|
||||
CloseableIterator<DbRequest> iterator;
|
||||
int maxcount = 30;
|
||||
try {
|
||||
iterator = databaseHelper.getDbRequestIterator();
|
||||
try {
|
||||
while (iterator.hasNext() && maxcount > 0) {
|
||||
DbRequest dbr = iterator.next();
|
||||
if (dbr.action.equals("dbAdd")) {
|
||||
NSAddAck addAck = new NSAddAck(aapsLogger, rxBus, null);
|
||||
dbAdd(dbr, addAck);
|
||||
} else if (dbr.action.equals("dbRemove")) {
|
||||
NSUpdateAck removeAck = new NSUpdateAck("dbRemove", dbr._id, aapsLogger, rxBus, null);
|
||||
dbRemove(dbr, removeAck);
|
||||
} else if (dbr.action.equals("dbUpdate")) {
|
||||
NSUpdateAck updateAck = new NSUpdateAck("dbUpdate", dbr._id, aapsLogger, rxBus, null);
|
||||
dbUpdate(dbr, updateAck);
|
||||
}
|
||||
maxcount--;
|
||||
}
|
||||
} finally {
|
||||
iterator.close();
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
aapsLogger.error("Unhandled exception", e);
|
||||
}
|
||||
|
||||
rxBus.send(new EventNSClientNewLog("QUEUE", "Resend ended: " + reason));
|
||||
});
|
||||
}
|
||||
|
||||
public void restart() {
|
||||
destroy();
|
||||
initialize();
|
||||
}
|
||||
|
||||
private void handleAnnouncement(JSONObject announcement) {
|
||||
boolean defaultVal = config.getNSCLIENT();
|
||||
if (sp.getBoolean(R.string.key_ns_announcements, defaultVal)) {
|
||||
NSAlarm nsAlarm = new NSAlarm(announcement);
|
||||
Notification notification = new NotificationWithAction(injector, nsAlarm);
|
||||
rxBus.send(new EventNewNotification(notification));
|
||||
rxBus.send(new EventNSClientNewLog("ANNOUNCEMENT", JsonHelper.safeGetString(announcement, "message", "received")));
|
||||
aapsLogger.debug(LTag.NSCLIENT, announcement.toString());
|
||||
}
|
||||
}
|
||||
|
||||
private void handleAlarm(JSONObject alarm) {
|
||||
boolean defaultVal = config.getNSCLIENT();
|
||||
if (sp.getBoolean(R.string.key_ns_alarms, defaultVal)) {
|
||||
long snoozedTo = sp.getLong(R.string.key_snoozedTo, 0L);
|
||||
if (snoozedTo == 0L || System.currentTimeMillis() > snoozedTo) {
|
||||
NSAlarm nsAlarm = new NSAlarm(alarm);
|
||||
Notification notification = new NotificationWithAction(injector, nsAlarm);
|
||||
rxBus.send(new EventNewNotification(notification));
|
||||
}
|
||||
rxBus.send(new EventNSClientNewLog("ALARM", JsonHelper.safeGetString(alarm, "message", "received")));
|
||||
aapsLogger.debug(LTag.NSCLIENT, alarm.toString());
|
||||
}
|
||||
}
|
||||
|
||||
private void handleUrgentAlarm(JSONObject alarm) {
|
||||
boolean defaultVal = config.getNSCLIENT();
|
||||
if (sp.getBoolean(R.string.key_ns_alarms, defaultVal)) {
|
||||
long snoozedTo = sp.getLong(R.string.key_snoozedTo, 0L);
|
||||
if (snoozedTo == 0L || System.currentTimeMillis() > snoozedTo) {
|
||||
NSAlarm nsAlarm = new NSAlarm(alarm);
|
||||
Notification notification = new NotificationWithAction(injector, nsAlarm);
|
||||
rxBus.send(new EventNewNotification(notification));
|
||||
}
|
||||
rxBus.send(new EventNSClientNewLog("URGENTALARM", JsonHelper.safeGetString(alarm, "message", "received")));
|
||||
aapsLogger.debug(LTag.NSCLIENT, alarm.toString());
|
||||
}
|
||||
}
|
||||
|
||||
public List<JSONArray> splitArray(JSONArray array) {
|
||||
List<JSONArray> ret = new ArrayList<>();
|
||||
try {
|
||||
int size = array.length();
|
||||
int count = 0;
|
||||
JSONArray newarr = null;
|
||||
for (int i = 0; i < size; i++) {
|
||||
if (count == 0) {
|
||||
if (newarr != null) {
|
||||
ret.add(newarr);
|
||||
}
|
||||
newarr = new JSONArray();
|
||||
count = 20;
|
||||
}
|
||||
newarr.put(array.get(i));
|
||||
--count;
|
||||
}
|
||||
if (newarr != null && newarr.length() > 0) {
|
||||
ret.add(newarr);
|
||||
}
|
||||
} catch (JSONException e) {
|
||||
aapsLogger.error("Unhandled exception", e);
|
||||
ret = new ArrayList<>();
|
||||
ret.add(array);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,731 @@
|
|||
package info.nightscout.androidaps.plugins.general.nsclient.services
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.*
|
||||
import androidx.work.OneTimeWorkRequest
|
||||
import com.google.common.base.Charsets
|
||||
import com.google.common.hash.Hashing
|
||||
import dagger.android.DaggerService
|
||||
import dagger.android.HasAndroidInjector
|
||||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.database.AppRepository
|
||||
import info.nightscout.androidaps.events.EventAppExit
|
||||
import info.nightscout.androidaps.events.EventConfigBuilderChange
|
||||
import info.nightscout.androidaps.events.EventPreferenceChange
|
||||
import info.nightscout.androidaps.interfaces.Config
|
||||
import info.nightscout.androidaps.interfaces.DataSyncSelector
|
||||
import info.nightscout.androidaps.interfaces.DatabaseHelperInterface
|
||||
import info.nightscout.androidaps.interfaces.PluginType
|
||||
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.food.FoodPlugin.FoodWorker
|
||||
import info.nightscout.androidaps.plugins.general.nsclient.*
|
||||
import info.nightscout.androidaps.plugins.general.nsclient.acks.NSAddAck
|
||||
import info.nightscout.androidaps.plugins.general.nsclient.acks.NSAuthAck
|
||||
import info.nightscout.androidaps.plugins.general.nsclient.acks.NSUpdateAck
|
||||
import info.nightscout.androidaps.plugins.general.nsclient.data.AlarmAck
|
||||
import info.nightscout.androidaps.plugins.general.nsclient.data.NSAlarm
|
||||
import info.nightscout.androidaps.plugins.general.nsclient.data.NSDeviceStatus
|
||||
import info.nightscout.androidaps.plugins.general.nsclient.data.NSSettingsStatus
|
||||
import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientNewLog
|
||||
import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientRestart
|
||||
import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientStatus
|
||||
import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientUpdateGUI
|
||||
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.notifications.Notification
|
||||
import info.nightscout.androidaps.plugins.general.overview.notifications.NotificationWithAction
|
||||
import info.nightscout.androidaps.plugins.profile.local.LocalProfilePlugin
|
||||
import info.nightscout.androidaps.plugins.source.NSClientSourcePlugin.NSClientSourceWorker
|
||||
import info.nightscout.androidaps.receivers.DataWorker
|
||||
import info.nightscout.androidaps.services.Intents
|
||||
import info.nightscout.androidaps.utils.DateUtil
|
||||
import info.nightscout.androidaps.utils.FabricPrivacy
|
||||
import info.nightscout.androidaps.utils.JsonHelper.safeGetLong
|
||||
import info.nightscout.androidaps.utils.JsonHelper.safeGetString
|
||||
import info.nightscout.androidaps.utils.JsonHelper.safeGetStringAllowNull
|
||||
import info.nightscout.androidaps.utils.T.Companion.days
|
||||
import info.nightscout.androidaps.utils.T.Companion.mins
|
||||
import info.nightscout.androidaps.utils.buildHelper.BuildHelper
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
||||
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
||||
import io.reactivex.disposables.CompositeDisposable
|
||||
import io.socket.client.IO
|
||||
import io.socket.client.Socket
|
||||
import io.socket.emitter.Emitter
|
||||
import org.json.JSONArray
|
||||
import org.json.JSONException
|
||||
import org.json.JSONObject
|
||||
import java.net.URISyntaxException
|
||||
import java.util.*
|
||||
import javax.inject.Inject
|
||||
|
||||
class NSClientService : DaggerService() {
|
||||
|
||||
@Inject lateinit var injector: HasAndroidInjector
|
||||
@Inject lateinit var aapsLogger: AAPSLogger
|
||||
@Inject lateinit var aapsSchedulers: AapsSchedulers
|
||||
@Inject lateinit var nsSettingsStatus: NSSettingsStatus
|
||||
@Inject lateinit var nsDeviceStatus: NSDeviceStatus
|
||||
@Inject lateinit var databaseHelper: DatabaseHelperInterface
|
||||
@Inject lateinit var rxBus: RxBusWrapper
|
||||
@Inject lateinit var resourceHelper: ResourceHelper
|
||||
@Inject lateinit var sp: SP
|
||||
@Inject lateinit var fabricPrivacy: FabricPrivacy
|
||||
@Inject lateinit var nsClientPlugin: NSClientPlugin
|
||||
@Inject lateinit var buildHelper: BuildHelper
|
||||
@Inject lateinit var config: Config
|
||||
@Inject lateinit var dateUtil: DateUtil
|
||||
@Inject lateinit var dataWorker: DataWorker
|
||||
@Inject lateinit var dataSyncSelector: DataSyncSelector
|
||||
@Inject lateinit var repository: AppRepository
|
||||
|
||||
companion object {
|
||||
|
||||
private const val WATCHDOG_INTERVAL_MINUTES = 2
|
||||
private const val WATCHDOG_RECONNECT_IN = 15
|
||||
private const val WATCHDOG_MAX_CONNECTIONS = 5
|
||||
}
|
||||
|
||||
private val disposable = CompositeDisposable()
|
||||
|
||||
private var wakeLock: PowerManager.WakeLock? = null
|
||||
private val binder: IBinder = LocalBinder()
|
||||
private var handler: Handler? = null
|
||||
private var socket: Socket? = null
|
||||
private var dataCounter = 0
|
||||
private var connectCounter = 0
|
||||
private var nsEnabled = false
|
||||
private var nsAPISecret = ""
|
||||
private var nsDevice = ""
|
||||
private val nsHours = 48
|
||||
private var lastAckTime: Long = 0
|
||||
private var nsApiHashCode = ""
|
||||
private val reconnections = ArrayList<Long>()
|
||||
|
||||
var isConnected = false
|
||||
var hasWriteAuth = false
|
||||
var nsURL = ""
|
||||
var latestDateInReceivedData: Long = 0
|
||||
|
||||
@SuppressLint("WakelockTimeout")
|
||||
@kotlin.ExperimentalStdlibApi
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
wakeLock = (getSystemService(Context.POWER_SERVICE) as PowerManager).newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "AndroidAPS:NSClientService")
|
||||
wakeLock?.acquire()
|
||||
initialize()
|
||||
disposable.add(rxBus
|
||||
.toObservable(EventConfigBuilderChange::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.subscribe({
|
||||
if (nsEnabled != nsClientPlugin.isEnabled(PluginType.GENERAL)) {
|
||||
latestDateInReceivedData = 0
|
||||
destroy()
|
||||
initialize()
|
||||
}
|
||||
}, fabricPrivacy::logException)
|
||||
)
|
||||
disposable.add(rxBus
|
||||
.toObservable(EventPreferenceChange::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.subscribe({ event: EventPreferenceChange ->
|
||||
if (event.isChanged(resourceHelper, R.string.key_nsclientinternal_url) ||
|
||||
event.isChanged(resourceHelper, R.string.key_nsclientinternal_api_secret) ||
|
||||
event.isChanged(resourceHelper, R.string.key_nsclientinternal_paused)) {
|
||||
latestDateInReceivedData = 0
|
||||
destroy()
|
||||
initialize()
|
||||
}
|
||||
}, fabricPrivacy::logException)
|
||||
)
|
||||
disposable.add(rxBus
|
||||
.toObservable(EventAppExit::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.subscribe({
|
||||
aapsLogger.debug(LTag.NSCLIENT, "EventAppExit received")
|
||||
destroy()
|
||||
stopSelf()
|
||||
}, fabricPrivacy::logException)
|
||||
)
|
||||
disposable.add(rxBus
|
||||
.toObservable(EventNSClientRestart::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.subscribe({
|
||||
latestDateInReceivedData = 0
|
||||
restart()
|
||||
}, fabricPrivacy::logException)
|
||||
)
|
||||
disposable.add(rxBus
|
||||
.toObservable(NSAuthAck::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.subscribe({ ack -> processAuthAck(ack) }, fabricPrivacy::logException)
|
||||
)
|
||||
disposable.add(rxBus
|
||||
.toObservable(NSUpdateAck::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.subscribe({ ack -> processUpdateAck(ack) }, fabricPrivacy::logException)
|
||||
)
|
||||
disposable.add(rxBus
|
||||
.toObservable(NSAddAck::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.subscribe({ ack -> processAddAck(ack) }, fabricPrivacy::logException)
|
||||
)
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
disposable.clear()
|
||||
if (wakeLock?.isHeld == true) wakeLock?.release()
|
||||
}
|
||||
|
||||
private fun processAddAck(ack: NSAddAck) {
|
||||
lastAckTime = dateUtil.now()
|
||||
dataWorker.enqueue(
|
||||
OneTimeWorkRequest.Builder(NSClientAddAckWorker::class.java)
|
||||
.setInputData(dataWorker.storeInputData(ack, null))
|
||||
.build())
|
||||
}
|
||||
|
||||
private fun processUpdateAck(ack: NSUpdateAck) {
|
||||
lastAckTime = dateUtil.now()
|
||||
dataWorker.enqueue(
|
||||
OneTimeWorkRequest.Builder(NSClientUpdateRemoveAckWorker::class.java)
|
||||
.setInputData(dataWorker.storeInputData(ack, null))
|
||||
.build())
|
||||
}
|
||||
|
||||
fun processAuthAck(ack: NSAuthAck) {
|
||||
var connectionStatus = "Authenticated ("
|
||||
if (ack.read) connectionStatus += "R"
|
||||
if (ack.write) connectionStatus += "W"
|
||||
if (ack.write_treatment) connectionStatus += "T"
|
||||
connectionStatus += ')'
|
||||
isConnected = true
|
||||
hasWriteAuth = ack.write && ack.write_treatment
|
||||
rxBus.send(EventNSClientStatus(connectionStatus))
|
||||
rxBus.send(EventNSClientNewLog("AUTH", connectionStatus))
|
||||
if (!ack.write) {
|
||||
rxBus.send(EventNSClientNewLog("ERROR", "Write permission not granted "))
|
||||
}
|
||||
if (!ack.write_treatment) {
|
||||
rxBus.send(EventNSClientNewLog("ERROR", "Write treatment permission not granted "))
|
||||
}
|
||||
if (!hasWriteAuth) {
|
||||
val noWritePerm = Notification(Notification.NSCLIENT_NO_WRITE_PERMISSION, resourceHelper.gs(R.string.nowritepermission), Notification.URGENT)
|
||||
rxBus.send(EventNewNotification(noWritePerm))
|
||||
} else {
|
||||
rxBus.send(EventDismissNotification(Notification.NSCLIENT_NO_WRITE_PERMISSION))
|
||||
}
|
||||
}
|
||||
|
||||
inner class LocalBinder : Binder() {
|
||||
|
||||
val serviceInstance: NSClientService
|
||||
get() = this@NSClientService
|
||||
}
|
||||
|
||||
override fun onBind(intent: Intent): IBinder {
|
||||
return binder
|
||||
}
|
||||
|
||||
override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
|
||||
return START_STICKY
|
||||
}
|
||||
|
||||
@kotlin.ExperimentalStdlibApi
|
||||
fun initialize() {
|
||||
dataCounter = 0
|
||||
readPreferences()
|
||||
@Suppress("UnstableApiUsage", "DEPRECATION")
|
||||
if (nsAPISecret != "") nsApiHashCode = Hashing.sha1().hashString(nsAPISecret, Charsets.UTF_8).toString()
|
||||
rxBus.send(EventNSClientStatus("Initializing"))
|
||||
if (!nsClientPlugin.isAllowed) {
|
||||
rxBus.send(EventNSClientNewLog("NSCLIENT", "not allowed"))
|
||||
rxBus.send(EventNSClientStatus("Not allowed"))
|
||||
} else if (nsClientPlugin.paused) {
|
||||
rxBus.send(EventNSClientNewLog("NSCLIENT", "paused"))
|
||||
rxBus.send(EventNSClientStatus("Paused"))
|
||||
} else if (!nsEnabled) {
|
||||
rxBus.send(EventNSClientNewLog("NSCLIENT", "disabled"))
|
||||
rxBus.send(EventNSClientStatus("Disabled"))
|
||||
} else if (nsURL != "" && (buildHelper.isEngineeringMode() || nsURL.lowercase(Locale.getDefault()).startsWith("https://"))) {
|
||||
try {
|
||||
rxBus.send(EventNSClientStatus("Connecting ..."))
|
||||
val opt = IO.Options()
|
||||
opt.forceNew = true
|
||||
opt.reconnection = true
|
||||
socket = IO.socket(nsURL, opt).also { socket ->
|
||||
socket.on(Socket.EVENT_CONNECT, onConnect)
|
||||
socket.on(Socket.EVENT_DISCONNECT, onDisconnect)
|
||||
socket.on(Socket.EVENT_ERROR, onError)
|
||||
socket.on(Socket.EVENT_CONNECT_ERROR, onError)
|
||||
socket.on(Socket.EVENT_CONNECT_TIMEOUT, onError)
|
||||
socket.on(Socket.EVENT_PING, onPing)
|
||||
rxBus.send(EventNSClientNewLog("NSCLIENT", "do connect"))
|
||||
socket.connect()
|
||||
socket.on("dataUpdate", onDataUpdate)
|
||||
socket.on("announcement", onAnnouncement)
|
||||
socket.on("alarm", onAlarm)
|
||||
socket.on("urgent_alarm", onUrgentAlarm)
|
||||
socket.on("clear_alarm", onClearAlarm)
|
||||
}
|
||||
} catch (e: URISyntaxException) {
|
||||
rxBus.send(EventNSClientNewLog("NSCLIENT", "Wrong URL syntax"))
|
||||
rxBus.send(EventNSClientStatus("Wrong URL syntax"))
|
||||
} catch (e: RuntimeException) {
|
||||
rxBus.send(EventNSClientNewLog("NSCLIENT", "Wrong URL syntax"))
|
||||
rxBus.send(EventNSClientStatus("Wrong URL syntax"))
|
||||
}
|
||||
} else if (nsURL.lowercase(Locale.getDefault()).startsWith("http://")) {
|
||||
rxBus.send(EventNSClientNewLog("NSCLIENT", "NS URL not encrypted"))
|
||||
rxBus.send(EventNSClientStatus("Not encrypted"))
|
||||
} else {
|
||||
rxBus.send(EventNSClientNewLog("NSCLIENT", "No NS URL specified"))
|
||||
rxBus.send(EventNSClientStatus("Not configured"))
|
||||
}
|
||||
}
|
||||
|
||||
private val onConnect = Emitter.Listener {
|
||||
connectCounter++
|
||||
val socketId = socket?.id() ?: "NULL"
|
||||
rxBus.send(EventNSClientNewLog("NSCLIENT", "connect #$connectCounter event. ID: $socketId"))
|
||||
if (socket != null) sendAuthMessage(NSAuthAck(rxBus))
|
||||
watchdog()
|
||||
}
|
||||
|
||||
private fun watchdog() {
|
||||
synchronized(reconnections) {
|
||||
val now = dateUtil.now()
|
||||
reconnections.add(now)
|
||||
for (r in reconnections.reversed()) {
|
||||
if (r < now - mins(WATCHDOG_INTERVAL_MINUTES.toLong()).msecs()) {
|
||||
reconnections.remove(r)
|
||||
}
|
||||
}
|
||||
rxBus.send(EventNSClientNewLog("WATCHDOG", "connections in last " + WATCHDOG_INTERVAL_MINUTES + " minutes: " + reconnections.size + "/" + WATCHDOG_MAX_CONNECTIONS))
|
||||
if (reconnections.size >= WATCHDOG_MAX_CONNECTIONS) {
|
||||
val n = Notification(Notification.NS_MALFUNCTION, resourceHelper.gs(R.string.nsmalfunction), Notification.URGENT)
|
||||
rxBus.send(EventNewNotification(n))
|
||||
rxBus.send(EventNSClientNewLog("WATCHDOG", "pausing for $WATCHDOG_RECONNECT_IN minutes"))
|
||||
nsClientPlugin.pause(true)
|
||||
rxBus.send(EventNSClientUpdateGUI())
|
||||
Thread {
|
||||
SystemClock.sleep(mins(WATCHDOG_RECONNECT_IN.toLong()).msecs())
|
||||
rxBus.send(EventNSClientNewLog("WATCHDOG", "re-enabling NSClient"))
|
||||
nsClientPlugin.pause(false)
|
||||
}.start()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val onDisconnect = Emitter.Listener { args ->
|
||||
aapsLogger.debug(LTag.NSCLIENT, "disconnect reason: {}", *args)
|
||||
rxBus.send(EventNSClientNewLog("NSCLIENT", "disconnect event"))
|
||||
}
|
||||
|
||||
@Synchronized fun destroy() {
|
||||
socket?.off(Socket.EVENT_CONNECT)
|
||||
socket?.off(Socket.EVENT_DISCONNECT)
|
||||
socket?.off(Socket.EVENT_PING)
|
||||
socket?.off("dataUpdate")
|
||||
socket?.off("announcement")
|
||||
socket?.off("alarm")
|
||||
socket?.off("urgent_alarm")
|
||||
socket?.off("clear_alarm")
|
||||
rxBus.send(EventNSClientNewLog("NSCLIENT", "destroy"))
|
||||
isConnected = false
|
||||
hasWriteAuth = false
|
||||
socket?.disconnect()
|
||||
socket = null
|
||||
}
|
||||
|
||||
private fun sendAuthMessage(ack: NSAuthAck?) {
|
||||
val authMessage = JSONObject()
|
||||
try {
|
||||
authMessage.put("client", "Android_$nsDevice")
|
||||
authMessage.put("history", nsHours)
|
||||
authMessage.put("status", true) // receive status
|
||||
authMessage.put("from", latestDateInReceivedData) // send data newer than
|
||||
authMessage.put("secret", nsApiHashCode)
|
||||
} catch (e: JSONException) {
|
||||
aapsLogger.error("Unhandled exception", e)
|
||||
return
|
||||
}
|
||||
rxBus.send(EventNSClientNewLog("AUTH", "requesting auth"))
|
||||
socket?.emit("authorize", authMessage, ack)
|
||||
}
|
||||
|
||||
fun readPreferences() {
|
||||
nsEnabled = nsClientPlugin.isEnabled(PluginType.GENERAL)
|
||||
nsURL = sp.getString(R.string.key_nsclientinternal_url, "")
|
||||
nsAPISecret = sp.getString(R.string.key_nsclientinternal_api_secret, "")
|
||||
nsDevice = sp.getString("careportal_enteredby", "")
|
||||
}
|
||||
|
||||
private val onError = Emitter.Listener { args ->
|
||||
var msg = "Unknown Error"
|
||||
if (args.isNotEmpty() && args[0] != null) {
|
||||
msg = args[0].toString()
|
||||
}
|
||||
rxBus.send(EventNSClientNewLog("ERROR", msg))
|
||||
}
|
||||
private val onPing = Emitter.Listener {
|
||||
rxBus.send(EventNSClientNewLog("PING", "received"))
|
||||
// send data if there is something waiting
|
||||
resend("Ping received")
|
||||
}
|
||||
private val onAnnouncement = Emitter.Listener { args ->
|
||||
|
||||
/*
|
||||
{
|
||||
"level":0,
|
||||
"title":"Announcement",
|
||||
"message":"test",
|
||||
"plugin":{"name":"treatmentnotify","label":"Treatment Notifications","pluginType":"notification","enabled":true},
|
||||
"group":"Announcement",
|
||||
"isAnnouncement":true,
|
||||
"key":"9ac46ad9a1dcda79dd87dae418fce0e7955c68da"
|
||||
}
|
||||
*/
|
||||
val data: JSONObject
|
||||
try {
|
||||
data = args[0] as JSONObject
|
||||
handleAnnouncement(data)
|
||||
} catch (e: Exception) {
|
||||
aapsLogger.error("Unhandled exception", e)
|
||||
}
|
||||
}
|
||||
private val onAlarm = Emitter.Listener { args ->
|
||||
|
||||
/*
|
||||
{
|
||||
"level":1,
|
||||
"title":"Warning HIGH",
|
||||
"message":"BG Now: 5 -0.2 → mmol\/L\nRaw BG: 4.8 mmol\/L Čistý\nBG 15m: 4.8 mmol\/L\nIOB: -0.02U\nCOB: 0g",
|
||||
"eventName":"high",
|
||||
"plugin":{"name":"simplealarms","label":"Simple Alarms","pluginType":"notification","enabled":true},
|
||||
"pushoverSound":"climb",
|
||||
"debug":{"lastSGV":5,"thresholds":{"bgHigh":180,"bgTargetTop":75,"bgTargetBottom":72,"bgLow":70}},
|
||||
"group":"default",
|
||||
"key":"simplealarms_1"
|
||||
}
|
||||
*/
|
||||
val data: JSONObject
|
||||
try {
|
||||
data = args[0] as JSONObject
|
||||
handleAlarm(data)
|
||||
} catch (e: Exception) {
|
||||
aapsLogger.error("Unhandled exception", e)
|
||||
}
|
||||
}
|
||||
private val onUrgentAlarm = Emitter.Listener { args: Array<Any> ->
|
||||
val data: JSONObject
|
||||
try {
|
||||
data = args[0] as JSONObject
|
||||
handleUrgentAlarm(data)
|
||||
} catch (e: Exception) {
|
||||
aapsLogger.error("Unhandled exception", e)
|
||||
}
|
||||
}
|
||||
private val onClearAlarm = Emitter.Listener { args ->
|
||||
|
||||
/*
|
||||
{
|
||||
"clear":true,
|
||||
"title":"All Clear",
|
||||
"message":"default - Urgent was ack'd",
|
||||
"group":"default"
|
||||
}
|
||||
*/
|
||||
val data: JSONObject
|
||||
try {
|
||||
data = args[0] as JSONObject
|
||||
rxBus.send(EventNSClientNewLog("CLEARALARM", "received"))
|
||||
rxBus.send(EventDismissNotification(Notification.NS_ALARM))
|
||||
rxBus.send(EventDismissNotification(Notification.NS_URGENT_ALARM))
|
||||
aapsLogger.debug(LTag.NSCLIENT, data.toString())
|
||||
} catch (e: Exception) {
|
||||
aapsLogger.error("Unhandled exception", e)
|
||||
}
|
||||
}
|
||||
private val onDataUpdate = Emitter.Listener { args ->
|
||||
handler?.post {
|
||||
// val powerManager = getSystemService(POWER_SERVICE) as PowerManager
|
||||
// val wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
|
||||
// "AndroidAPS:NSClientService_onDataUpdate")
|
||||
// wakeLock.acquire(3000)
|
||||
try {
|
||||
val data = args[0] as JSONObject
|
||||
try {
|
||||
// delta means only increment/changes are coming
|
||||
val isDelta = data.has("delta")
|
||||
rxBus.send(EventNSClientNewLog("DATA", "Data packet #" + dataCounter++ + if (isDelta) " delta" else " full"))
|
||||
if (data.has("status")) {
|
||||
val status = data.getJSONObject("status")
|
||||
nsSettingsStatus.handleNewData(status)
|
||||
} else if (!isDelta) {
|
||||
rxBus.send(EventNSClientNewLog("ERROR", "Unsupported Nightscout version "))
|
||||
}
|
||||
if (data.has("profiles")) {
|
||||
val profiles = data.getJSONArray("profiles")
|
||||
if (profiles.length() > 0) {
|
||||
// take the newest
|
||||
val profileStoreJson = profiles[profiles.length() - 1] as JSONObject
|
||||
rxBus.send(EventNSClientNewLog("PROFILE", "profile received"))
|
||||
dataWorker.enqueue(
|
||||
OneTimeWorkRequest.Builder(LocalProfilePlugin.NSProfileWorker::class.java)
|
||||
.setInputData(dataWorker.storeInputData(profileStoreJson, null))
|
||||
.build())
|
||||
if (sp.getBoolean(R.string.key_nsclient_localbroadcasts, false)) {
|
||||
val bundle = Bundle()
|
||||
bundle.putString("profile", profileStoreJson.toString())
|
||||
bundle.putBoolean("delta", isDelta)
|
||||
val intent = Intent(Intents.ACTION_NEW_PROFILE)
|
||||
intent.putExtras(bundle)
|
||||
intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES)
|
||||
sendBroadcast(intent)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (data.has("treatments")) {
|
||||
val treatments = data.getJSONArray("treatments")
|
||||
val removedTreatments = JSONArray()
|
||||
val addedOrUpdatedTreatments = JSONArray()
|
||||
if (treatments.length() > 0) rxBus.send(EventNSClientNewLog("DATA", "received " + treatments.length() + " treatments"))
|
||||
for (index in 0 until treatments.length()) {
|
||||
val jsonTreatment = treatments.getJSONObject(index)
|
||||
val action = safeGetStringAllowNull(jsonTreatment, "action", null)
|
||||
val mills = safeGetLong(jsonTreatment, "mills")
|
||||
if (action == null) addedOrUpdatedTreatments.put(jsonTreatment) else if (action == "update") addedOrUpdatedTreatments.put(jsonTreatment) else if (action == "remove" && mills > dateUtil.now() - days(1).msecs()) // handle 1 day old deletions only
|
||||
removedTreatments.put(jsonTreatment)
|
||||
}
|
||||
if (removedTreatments.length() > 0) {
|
||||
dataWorker.enqueue(
|
||||
OneTimeWorkRequest.Builder(NSClientRemoveWorker::class.java)
|
||||
.setInputData(dataWorker.storeInputData(removedTreatments, null))
|
||||
.build())
|
||||
if (sp.getBoolean(R.string.key_nsclient_localbroadcasts, false)) {
|
||||
val bundle = Bundle()
|
||||
bundle.putString("treatments", removedTreatments.toString())
|
||||
bundle.putBoolean("delta", isDelta)
|
||||
val intent = Intent(Intents.ACTION_REMOVED_TREATMENT)
|
||||
intent.putExtras(bundle)
|
||||
intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES)
|
||||
sendBroadcast(intent)
|
||||
}
|
||||
}
|
||||
if (addedOrUpdatedTreatments.length() > 0) {
|
||||
dataWorker.enqueue(
|
||||
OneTimeWorkRequest.Builder(NSClientAddUpdateWorker::class.java)
|
||||
.setInputData(dataWorker.storeInputData(addedOrUpdatedTreatments, null))
|
||||
.build())
|
||||
if (sp.getBoolean(R.string.key_nsclient_localbroadcasts, false)) {
|
||||
val splitted = splitArray(addedOrUpdatedTreatments)
|
||||
for (part in splitted) {
|
||||
val bundle = Bundle()
|
||||
bundle.putString("treatments", part.toString())
|
||||
bundle.putBoolean("delta", isDelta)
|
||||
val intent = Intent(Intents.ACTION_CHANGED_TREATMENT)
|
||||
intent.putExtras(bundle)
|
||||
intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES)
|
||||
sendBroadcast(intent)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (data.has("devicestatus")) {
|
||||
val devicestatuses = data.getJSONArray("devicestatus")
|
||||
if (devicestatuses.length() > 0) {
|
||||
rxBus.send(EventNSClientNewLog("DATA", "received " + devicestatuses.length() + " device statuses"))
|
||||
nsDeviceStatus.handleNewData(devicestatuses)
|
||||
}
|
||||
}
|
||||
if (data.has("food")) {
|
||||
val foods = data.getJSONArray("food")
|
||||
if (foods.length() > 0) rxBus.send(EventNSClientNewLog("DATA", "received " + foods.length() + " foods"))
|
||||
dataWorker.enqueue(
|
||||
OneTimeWorkRequest.Builder(FoodWorker::class.java)
|
||||
.setInputData(dataWorker.storeInputData(foods, null))
|
||||
.build())
|
||||
}
|
||||
if (data.has("mbgs")) {
|
||||
val mbgArray = data.getJSONArray("mbgs")
|
||||
if (mbgArray.length() > 0) rxBus.send(EventNSClientNewLog("DATA", "received " + mbgArray.length() + " mbgs"))
|
||||
dataWorker.enqueue(
|
||||
OneTimeWorkRequest.Builder(NSClientMbgWorker::class.java)
|
||||
.setInputData(dataWorker.storeInputData(mbgArray, null))
|
||||
.build())
|
||||
}
|
||||
if (data.has("cals")) {
|
||||
val cals = data.getJSONArray("cals")
|
||||
if (cals.length() > 0) rxBus.send(EventNSClientNewLog("DATA", "received " + cals.length() + " cals"))
|
||||
// Calibrations ignored
|
||||
}
|
||||
if (data.has("sgvs")) {
|
||||
val sgvs = data.getJSONArray("sgvs")
|
||||
if (sgvs.length() > 0) rxBus.send(EventNSClientNewLog("DATA", "received " + sgvs.length() + " sgvs"))
|
||||
dataWorker.enqueue(OneTimeWorkRequest.Builder(NSClientSourceWorker::class.java)
|
||||
.setInputData(dataWorker.storeInputData(sgvs, null))
|
||||
.build())
|
||||
val splitted = splitArray(sgvs)
|
||||
if (sp.getBoolean(R.string.key_nsclient_localbroadcasts, false)) {
|
||||
for (part in splitted) {
|
||||
val bundle = Bundle()
|
||||
bundle.putString("sgvs", part.toString())
|
||||
bundle.putBoolean("delta", isDelta)
|
||||
val intent = Intent(Intents.ACTION_NEW_SGV)
|
||||
intent.putExtras(bundle)
|
||||
intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES)
|
||||
sendBroadcast(intent)
|
||||
}
|
||||
}
|
||||
}
|
||||
rxBus.send(EventNSClientNewLog("LAST", dateUtil.dateAndTimeString(latestDateInReceivedData)))
|
||||
} catch (e: JSONException) {
|
||||
aapsLogger.error("Unhandled exception", e)
|
||||
}
|
||||
//rxBus.send(new EventNSClientNewLog("NSCLIENT", "onDataUpdate end");
|
||||
} finally {
|
||||
// if (wakeLock.isHeld) wakeLock.release()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun dbUpdate(collection: String, _id: String?, data: JSONObject?, originalObject: Any, progress: String) {
|
||||
try {
|
||||
if (_id == null) return
|
||||
if (!isConnected || !hasWriteAuth) return
|
||||
val message = JSONObject()
|
||||
message.put("collection", collection)
|
||||
message.put("_id", _id)
|
||||
message.put("data", data)
|
||||
socket?.emit("dbUpdate", message, NSUpdateAck("dbUpdate", _id, aapsLogger, rxBus, originalObject))
|
||||
rxBus.send(EventNSClientNewLog("DBUPDATE $collection", "Sent " + originalObject.javaClass.simpleName + " " + _id + " " + progress))
|
||||
} catch (e: JSONException) {
|
||||
aapsLogger.error("Unhandled exception", e)
|
||||
}
|
||||
}
|
||||
|
||||
fun dbAdd(collection: String, data: JSONObject, originalObject: Any, progress: String) {
|
||||
try {
|
||||
if (!isConnected || !hasWriteAuth) return
|
||||
val message = JSONObject()
|
||||
message.put("collection", collection)
|
||||
message.put("data", data)
|
||||
socket?.emit("dbAdd", message, NSAddAck(aapsLogger, rxBus, originalObject))
|
||||
rxBus.send(EventNSClientNewLog("DBADD $collection", "Sent " + originalObject.javaClass.simpleName + " " + data + " " + progress))
|
||||
} catch (e: JSONException) {
|
||||
aapsLogger.error("Unhandled exception", e)
|
||||
}
|
||||
}
|
||||
|
||||
fun sendAlarmAck(alarmAck: AlarmAck) {
|
||||
if (!isConnected || !hasWriteAuth) return
|
||||
socket?.emit("ack", alarmAck.level, alarmAck.group, alarmAck.silenceTime)
|
||||
rxBus.send(EventNSClientNewLog("ALARMACK ", alarmAck.level.toString() + " " + alarmAck.group + " " + alarmAck.silenceTime))
|
||||
}
|
||||
|
||||
fun resend(reason: String) {
|
||||
if (!isConnected || !hasWriteAuth) return
|
||||
handler?.post {
|
||||
if (socket?.connected() != true) return@post
|
||||
if (lastAckTime > System.currentTimeMillis() - 10 * 1000L) {
|
||||
aapsLogger.debug(LTag.NSCLIENT, "Skipping resend by lastAckTime: " + (System.currentTimeMillis() - lastAckTime) / 1000L + " sec")
|
||||
return@post
|
||||
}
|
||||
// val powerManager = getSystemService(POWER_SERVICE) as PowerManager
|
||||
// val wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
|
||||
// "AndroidAPS:NSClientService_onDataUpdate")
|
||||
// wakeLock.acquire(mins(10).msecs())
|
||||
try {
|
||||
rxBus.send(EventNSClientNewLog("QUEUE", "Resend started: $reason"))
|
||||
dataSyncSelector.doUpload()
|
||||
rxBus.send(EventNSClientNewLog("QUEUE", "Resend ended: $reason"))
|
||||
} finally {
|
||||
// if (wakeLock.isHeld) wakeLock.release()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@kotlin.ExperimentalStdlibApi
|
||||
fun restart() {
|
||||
destroy()
|
||||
initialize()
|
||||
}
|
||||
|
||||
private fun handleAnnouncement(announcement: JSONObject) {
|
||||
val defaultVal = config.NSCLIENT
|
||||
if (sp.getBoolean(R.string.key_ns_announcements, defaultVal)) {
|
||||
val nsAlarm = NSAlarm(announcement)
|
||||
val notification: Notification = NotificationWithAction(injector, nsAlarm)
|
||||
rxBus.send(EventNewNotification(notification))
|
||||
rxBus.send(EventNSClientNewLog("ANNOUNCEMENT", safeGetString(announcement, "message", "received")))
|
||||
aapsLogger.debug(LTag.NSCLIENT, announcement.toString())
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleAlarm(alarm: JSONObject) {
|
||||
val defaultVal = config.NSCLIENT
|
||||
if (sp.getBoolean(R.string.key_ns_alarms, defaultVal)) {
|
||||
val snoozedTo = sp.getLong(R.string.key_snoozedTo, 0L)
|
||||
if (snoozedTo == 0L || System.currentTimeMillis() > snoozedTo) {
|
||||
val nsAlarm = NSAlarm(alarm)
|
||||
val notification: Notification = NotificationWithAction(injector, nsAlarm)
|
||||
rxBus.send(EventNewNotification(notification))
|
||||
}
|
||||
rxBus.send(EventNSClientNewLog("ALARM", safeGetString(alarm, "message", "received")))
|
||||
aapsLogger.debug(LTag.NSCLIENT, alarm.toString())
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleUrgentAlarm(alarm: JSONObject) {
|
||||
val defaultVal = config.NSCLIENT
|
||||
if (sp.getBoolean(R.string.key_ns_alarms, defaultVal)) {
|
||||
val snoozedTo = sp.getLong(R.string.key_snoozedTo, 0L)
|
||||
if (snoozedTo == 0L || System.currentTimeMillis() > snoozedTo) {
|
||||
val nsAlarm = NSAlarm(alarm)
|
||||
val notification: Notification = NotificationWithAction(injector, nsAlarm)
|
||||
rxBus.send(EventNewNotification(notification))
|
||||
}
|
||||
rxBus.send(EventNSClientNewLog("URGENTALARM", safeGetString(alarm, "message", "received")))
|
||||
aapsLogger.debug(LTag.NSCLIENT, alarm.toString())
|
||||
}
|
||||
}
|
||||
|
||||
private fun splitArray(array: JSONArray): List<JSONArray> {
|
||||
var ret: MutableList<JSONArray> = ArrayList()
|
||||
try {
|
||||
val size = array.length()
|
||||
var count = 0
|
||||
var newarr: JSONArray? = null
|
||||
for (i in 0 until size) {
|
||||
if (count == 0) {
|
||||
if (newarr != null) ret.add(newarr)
|
||||
newarr = JSONArray()
|
||||
count = 20
|
||||
}
|
||||
newarr?.put(array[i])
|
||||
--count
|
||||
}
|
||||
if (newarr != null && newarr.length() > 0) ret.add(newarr)
|
||||
} catch (e: JSONException) {
|
||||
aapsLogger.error("Unhandled exception", e)
|
||||
ret = ArrayList()
|
||||
ret.add(array)
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
init {
|
||||
if (handler == null) {
|
||||
val handlerThread = HandlerThread(NSClientService::class.java.simpleName + "Handler")
|
||||
handlerThread.start()
|
||||
handler = Handler(handlerThread.looper)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,8 +2,10 @@ package info.nightscout.androidaps.plugins.general.openhumans
|
|||
|
||||
import java.util.*
|
||||
|
||||
fun String.isAllowedKey() = if (startsWith("ConfigBuilder_")) true else allowedKeys.contains(this.toUpperCase(Locale.ROOT))
|
||||
@kotlin.ExperimentalStdlibApi
|
||||
fun String.isAllowedKey() = if (startsWith("ConfigBuilder_")) true else allowedKeys.contains(this.uppercase(Locale.ROOT))
|
||||
|
||||
@kotlin.ExperimentalStdlibApi
|
||||
private val allowedKeys = """
|
||||
absorption
|
||||
absorption_maxtime
|
||||
|
@ -206,4 +208,4 @@ private val allowedKeys = """
|
|||
xdripstatus
|
||||
xdripstatus_detailediob
|
||||
xdripstatus_showbgi
|
||||
""".trimIndent().split("\n").filterNot { it.isBlank() }.map { it.toUpperCase() }
|
||||
""".trimIndent().split("\n").filterNot { it.isBlank() }.map { it.uppercase(Locale.getDefault()) }
|
|
@ -28,6 +28,7 @@ class OHUploadWorker(context: Context, workerParameters: WorkerParameters)
|
|||
@Inject
|
||||
lateinit var resourceHelper: ResourceHelper
|
||||
|
||||
@kotlin.ExperimentalStdlibApi
|
||||
override fun createWork(): Single<Result> = Single.defer {
|
||||
|
||||
// Here we inject every time we create work
|
||||
|
|
|
@ -178,24 +178,24 @@ class OpenHumansUploader @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
@JvmOverloads
|
||||
fun enqueueTreatment(treatment: Treatment?, deleted: Boolean = false) = treatment?.let {
|
||||
insertQueueItem("Treatments") {
|
||||
put("date", treatment.date)
|
||||
put("isValid", treatment.isValid)
|
||||
put("source", treatment.source)
|
||||
put("nsId", treatment._id)
|
||||
put("boluscalc", treatment.boluscalc)
|
||||
put("carbs", treatment.carbs)
|
||||
put("dia", treatment.dia)
|
||||
put("insulin", treatment.insulin)
|
||||
put("insulinInterfaceID", treatment.insulinInterfaceID)
|
||||
put("isSMB", treatment.isSMB)
|
||||
put("mealBolus", treatment.mealBolus)
|
||||
put("bolusCalcJson", treatment.getBoluscalc())
|
||||
put("isDeletion", deleted)
|
||||
}
|
||||
}
|
||||
// @JvmOverloads
|
||||
// fun enqueueTreatment(treatment: Treatment?, deleted: Boolean = false) = treatment?.let {
|
||||
// insertQueueItem("Treatments") {
|
||||
// put("date", treatment.date)
|
||||
// put("isValid", treatment.isValid)
|
||||
// put("source", treatment.source)
|
||||
// put("nsId", treatment._id)
|
||||
// put("boluscalc", treatment.boluscalc)
|
||||
// put("carbs", treatment.carbs)
|
||||
// put("dia", treatment.dia)
|
||||
// put("insulin", treatment.insulin)
|
||||
// put("insulinInterfaceID", treatment.insulinInterfaceID)
|
||||
// put("isSMB", treatment.isSMB)
|
||||
// put("mealBolus", treatment.mealBolus)
|
||||
// put("bolusCalcJson", treatment.getBoluscalc())
|
||||
// put("isDeletion", deleted)
|
||||
// }
|
||||
// }
|
||||
|
||||
@JvmOverloads
|
||||
fun enqueueTherapyEvent(therapyEvent: TherapyEvent, deleted: Boolean = false) = insertQueueItem("TherapyEvents") {
|
||||
|
@ -210,17 +210,17 @@ class OpenHumansUploader @Inject constructor(
|
|||
put("isDeletion", deleted)
|
||||
}
|
||||
|
||||
@JvmOverloads
|
||||
fun enqueueExtendedBolus(extendedBolus: ExtendedBolus, deleted: Boolean = false) = insertQueueItem("ExtendedBoluses") {
|
||||
put("date", extendedBolus.date)
|
||||
put("isValid", extendedBolus.isValid)
|
||||
put("source", extendedBolus.source)
|
||||
put("nsId", extendedBolus._id)
|
||||
put("pumpId", extendedBolus.pumpId)
|
||||
put("insulin", extendedBolus.insulin)
|
||||
put("durationInMinutes", extendedBolus.durationInMinutes)
|
||||
put("isDeletion", deleted)
|
||||
}
|
||||
// @JvmOverloads
|
||||
// fun enqueueExtendedBolus(extendedBolus: ExtendedBolus, deleted: Boolean = false) = insertQueueItem("ExtendedBoluses") {
|
||||
// put("date", extendedBolus.date)
|
||||
// put("isValid", extendedBolus.isValid)
|
||||
// put("source", extendedBolus.source)
|
||||
// put("nsId", extendedBolus._id)
|
||||
// put("pumpId", extendedBolus.pumpId)
|
||||
// put("insulin", extendedBolus.insulin)
|
||||
// put("durationInMinutes", extendedBolus.durationInMinutes)
|
||||
// put("isDeletion", deleted)
|
||||
// }
|
||||
|
||||
// @JvmOverloads
|
||||
// fun enqueueProfileSwitch(profileSwitch: ProfileSwitch, deleted: Boolean = false) = insertQueueItem("ProfileSwitches") {
|
||||
|
@ -244,22 +244,22 @@ class OpenHumansUploader @Inject constructor(
|
|||
// put("double", tdd.total)
|
||||
// }
|
||||
|
||||
@JvmOverloads
|
||||
fun enqueueTemporaryBasal(temporaryBasal: TemporaryBasal?, deleted: Boolean = false) = temporaryBasal?.let {
|
||||
insertQueueItem("TemporaryBasals") {
|
||||
put("date", temporaryBasal.date)
|
||||
put("isValid", temporaryBasal.isValid)
|
||||
put("source", temporaryBasal.source)
|
||||
put("nsId", temporaryBasal._id)
|
||||
put("pumpId", temporaryBasal.pumpId)
|
||||
put("durationInMinutes", temporaryBasal.durationInMinutes)
|
||||
put("durationInMinutes", temporaryBasal.durationInMinutes)
|
||||
put("isAbsolute", temporaryBasal.isAbsolute)
|
||||
put("percentRate", temporaryBasal.percentRate)
|
||||
put("absoluteRate", temporaryBasal.absoluteRate)
|
||||
put("isDeletion", deleted)
|
||||
}
|
||||
}
|
||||
// @JvmOverloads
|
||||
// fun enqueueTemporaryBasal(temporaryBasal: TemporaryBasal?, deleted: Boolean = false) = temporaryBasal?.let {
|
||||
// insertQueueItem("TemporaryBasals") {
|
||||
// put("date", temporaryBasal.date)
|
||||
// put("isValid", temporaryBasal.isValid)
|
||||
// put("source", temporaryBasal.source)
|
||||
// put("nsId", temporaryBasal._id)
|
||||
// put("pumpId", temporaryBasal.pumpId)
|
||||
// put("durationInMinutes", temporaryBasal.durationInMinutes)
|
||||
// put("durationInMinutes", temporaryBasal.durationInMinutes)
|
||||
// put("isAbsolute", temporaryBasal.isAbsolute)
|
||||
// put("percentRate", temporaryBasal.percentRate)
|
||||
// put("absoluteRate", temporaryBasal.absoluteRate)
|
||||
// put("isDeletion", deleted)
|
||||
// }
|
||||
// }
|
||||
|
||||
@JvmOverloads
|
||||
fun enqueueTempTarget(tempTarget: TemporaryTarget?, deleted: Boolean = false) = tempTarget?.let {
|
||||
|
@ -439,6 +439,7 @@ class OpenHumansUploader @Inject constructor(
|
|||
notificationManager.notify(FAILURE_NOTIFICATION_ID, notification)
|
||||
}
|
||||
|
||||
@kotlin.ExperimentalStdlibApi
|
||||
fun uploadDataSegmentally(): Completable =
|
||||
uploadData(UPLOAD_SEGMENT_SIZE)
|
||||
.repeatUntil { databaseHelper.getOHQueueSize() == 0L }
|
||||
|
@ -452,6 +453,7 @@ class OpenHumansUploader @Inject constructor(
|
|||
aapsLogger.error(LTag.OHUPLOADER, "Segmental upload exceptional", it)
|
||||
}
|
||||
|
||||
@kotlin.ExperimentalStdlibApi
|
||||
@Suppress("SameParameterValue")
|
||||
private fun uploadData(maxEntries: Long): Completable = gatherData(maxEntries)
|
||||
.flatMap { data -> refreshAccessTokensIfNeeded().map { accessToken -> accessToken to data } }
|
||||
|
@ -494,6 +496,7 @@ class OpenHumansUploader @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
@kotlin.ExperimentalStdlibApi
|
||||
private fun gatherData(maxEntries: Long) = Single.defer {
|
||||
val items = databaseHelper.getAllOHQueueItems(maxEntries)
|
||||
val baos = ByteArrayOutputStream()
|
||||
|
|
|
@ -0,0 +1,811 @@
|
|||
package info.nightscout.androidaps.plugins.general.overview
|
||||
|
||||
import android.graphics.DashPathEffect
|
||||
import android.graphics.Paint
|
||||
import com.jjoe64.graphview.series.BarGraphSeries
|
||||
import com.jjoe64.graphview.series.DataPoint
|
||||
import com.jjoe64.graphview.series.LineGraphSeries
|
||||
import dagger.android.HasAndroidInjector
|
||||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.data.IobTotal
|
||||
import info.nightscout.androidaps.database.AppRepository
|
||||
import info.nightscout.androidaps.database.ValueWrapper
|
||||
import info.nightscout.androidaps.database.entities.*
|
||||
import info.nightscout.androidaps.extensions.*
|
||||
import info.nightscout.androidaps.interfaces.*
|
||||
import info.nightscout.androidaps.logging.AAPSLogger
|
||||
import info.nightscout.androidaps.logging.LTag
|
||||
import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin
|
||||
import info.nightscout.androidaps.plugins.aps.openAPSSMB.SMBDefaults
|
||||
import info.nightscout.androidaps.plugins.general.nsclient.data.NSDeviceStatus
|
||||
import info.nightscout.androidaps.plugins.general.overview.graphExtensions.*
|
||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensResult
|
||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.CobInfo
|
||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.data.AutosensData
|
||||
import info.nightscout.androidaps.utils.*
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
||||
import java.util.*
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
import kotlin.collections.ArrayList
|
||||
import kotlin.math.abs
|
||||
import kotlin.math.ceil
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
|
||||
@Singleton
|
||||
class OverviewData @Inject constructor(
|
||||
private val injector: HasAndroidInjector,
|
||||
private val aapsLogger: AAPSLogger,
|
||||
private val resourceHelper: ResourceHelper,
|
||||
private val dateUtil: DateUtil,
|
||||
private val sp: SP,
|
||||
private val activePlugin: ActivePlugin,
|
||||
private val defaultValueHelper: DefaultValueHelper,
|
||||
private val profileFunction: ProfileFunction,
|
||||
private val 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 {
|
||||
TIME,
|
||||
CALC_PROGRESS,
|
||||
PROFILE,
|
||||
TEMPORARY_BASAL,
|
||||
EXTENDED_BOLUS,
|
||||
TEMPORARY_TARGET,
|
||||
BG,
|
||||
IOB_COB,
|
||||
SENSITIVITY,
|
||||
GRAPH
|
||||
}
|
||||
|
||||
var rangeToDisplay = 6 // for graph
|
||||
var toTime: Long = 0
|
||||
var fromTime: Long = 0
|
||||
var endTime: Long = 0
|
||||
|
||||
fun initRange() {
|
||||
rangeToDisplay = sp.getInt(R.string.key_rangetodisplay, 6)
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
toTime = calendar.timeInMillis + 100000 // little bit more to avoid wrong rounding - GraphView specific
|
||||
fromTime = toTime - T.hours(rangeToDisplay.toLong()).msecs()
|
||||
endTime = toTime
|
||||
}
|
||||
|
||||
/*
|
||||
* PROFILE
|
||||
*/
|
||||
var profile: Profile? = null
|
||||
var profileName: String? = null
|
||||
var profileNameWithRemainingTime: String? = null
|
||||
|
||||
val profileBackgroundColor: Int
|
||||
get() =
|
||||
profile?.let { profile ->
|
||||
if (profile.percentage != 100 || profile.timeshift != 0) resourceHelper.gc(R.color.ribbonWarning)
|
||||
else resourceHelper.gc(R.color.ribbonDefault)
|
||||
} ?: resourceHelper.gc(R.color.ribbonTextDefault)
|
||||
|
||||
val profileTextColor: Int
|
||||
get() =
|
||||
profile?.let { profile ->
|
||||
if (profile.percentage != 100 || profile.timeshift != 0) resourceHelper.gc(R.color.ribbonTextWarning)
|
||||
else resourceHelper.gc(R.color.ribbonTextDefault)
|
||||
} ?: resourceHelper.gc(R.color.ribbonTextDefault)
|
||||
|
||||
/*
|
||||
* CALC PROGRESS
|
||||
*/
|
||||
|
||||
var calcProgress: String = ""
|
||||
|
||||
/*
|
||||
* BG
|
||||
*/
|
||||
|
||||
var lastBg: GlucoseValue? = null
|
||||
|
||||
val lastBgColor: Int
|
||||
get() = lastBg?.let { lastBg ->
|
||||
when {
|
||||
lastBg.valueToUnits(profileFunction.getUnits()) < defaultValueHelper.determineLowLine() -> resourceHelper.gc(R.color.low)
|
||||
lastBg.valueToUnits(profileFunction.getUnits()) > defaultValueHelper.determineHighLine() -> resourceHelper.gc(R.color.high)
|
||||
else -> resourceHelper.gc(R.color.inrange)
|
||||
}
|
||||
} ?: resourceHelper.gc(R.color.inrange)
|
||||
|
||||
val isActualBg: Boolean
|
||||
get() =
|
||||
lastBg?.let { lastBg ->
|
||||
lastBg.timestamp > dateUtil.now() - T.mins(9).msecs()
|
||||
} ?: false
|
||||
|
||||
/*
|
||||
* TEMPORARY BASAL
|
||||
*/
|
||||
|
||||
var temporaryBasal: TemporaryBasal? = null
|
||||
|
||||
val temporaryBasalText: String
|
||||
get() =
|
||||
profile?.let { profile ->
|
||||
if (temporaryBasal?.isInProgress == false) temporaryBasal = null
|
||||
temporaryBasal?.let { "T:" + it.toStringShort() }
|
||||
?: resourceHelper.gs(R.string.pump_basebasalrate, profile.getBasal())
|
||||
} ?: resourceHelper.gs(R.string.notavailable)
|
||||
|
||||
val temporaryBasalDialogText: String
|
||||
get() = profile?.let { profile ->
|
||||
temporaryBasal?.let { temporaryBasal ->
|
||||
"${resourceHelper.gs(R.string.basebasalrate_label)}: ${resourceHelper.gs(R.string.pump_basebasalrate, profile.getBasal())}" +
|
||||
"\n" + resourceHelper.gs(R.string.tempbasal_label) + ": " + temporaryBasal.toStringFull(profile, dateUtil)
|
||||
}
|
||||
?: "${resourceHelper.gs(R.string.basebasalrate_label)}: ${resourceHelper.gs(R.string.pump_basebasalrate, profile.getBasal())}"
|
||||
} ?: resourceHelper.gs(R.string.notavailable)
|
||||
|
||||
val temporaryBasalIcon: Int
|
||||
get() =
|
||||
profile?.let { profile ->
|
||||
temporaryBasal?.let { temporaryBasal ->
|
||||
val percentRate = temporaryBasal.convertedToPercent(dateUtil.now(), profile)
|
||||
when {
|
||||
percentRate > 100 -> R.drawable.ic_cp_basal_tbr_high
|
||||
percentRate < 100 -> R.drawable.ic_cp_basal_tbr_low
|
||||
else -> R.drawable.ic_cp_basal_no_tbr
|
||||
}
|
||||
}
|
||||
} ?: R.drawable.ic_cp_basal_no_tbr
|
||||
|
||||
val temporaryBasalColor: Int
|
||||
get() = temporaryBasal?.let { resourceHelper.gc(R.color.basal) }
|
||||
?: resourceHelper.gc(R.color.defaulttextcolor)
|
||||
|
||||
/*
|
||||
* EXTENDED BOLUS
|
||||
*/
|
||||
|
||||
var extendedBolus: ExtendedBolus? = null
|
||||
|
||||
val extendedBolusText: String
|
||||
get() =
|
||||
extendedBolus?.let { extendedBolus ->
|
||||
if (!extendedBolus.isInProgress(dateUtil)) {
|
||||
this@OverviewData.extendedBolus = null
|
||||
""
|
||||
} else if (activePlugin.activePump.isFakingTempsByExtendedBoluses) resourceHelper.gs(R.string.pump_basebasalrate, extendedBolus.rate)
|
||||
else ""
|
||||
} ?: ""
|
||||
|
||||
val extendedBolusDialogText: String
|
||||
get() = extendedBolus?.toStringFull(dateUtil) ?: ""
|
||||
|
||||
/*
|
||||
* IOB, COB
|
||||
*/
|
||||
|
||||
var bolusIob: IobTotal? = null
|
||||
var basalIob: IobTotal? = null
|
||||
var cobInfo: CobInfo? = null
|
||||
var lastCarbsTime: Long = 0L
|
||||
|
||||
val iobText: String
|
||||
get() =
|
||||
bolusIob?.let { bolusIob ->
|
||||
basalIob?.let { basalIob ->
|
||||
resourceHelper.gs(R.string.formatinsulinunits, bolusIob.iob + basalIob.basaliob)
|
||||
} ?: resourceHelper.gs(R.string.value_unavailable_short)
|
||||
} ?: resourceHelper.gs(R.string.value_unavailable_short)
|
||||
|
||||
val iobDialogText: String
|
||||
get() =
|
||||
bolusIob?.let { bolusIob ->
|
||||
basalIob?.let { basalIob ->
|
||||
resourceHelper.gs(R.string.formatinsulinunits, bolusIob.iob + basalIob.basaliob) + "\n" +
|
||||
resourceHelper.gs(R.string.bolus) + ": " + resourceHelper.gs(R.string.formatinsulinunits, bolusIob.iob) + "\n" +
|
||||
resourceHelper.gs(R.string.basal) + ": " + resourceHelper.gs(R.string.formatinsulinunits, basalIob.basaliob)
|
||||
} ?: resourceHelper.gs(R.string.value_unavailable_short)
|
||||
} ?: resourceHelper.gs(R.string.value_unavailable_short)
|
||||
|
||||
/*
|
||||
* TEMP TARGET
|
||||
*/
|
||||
|
||||
var temporaryTarget: TemporaryTarget? = null
|
||||
|
||||
/*
|
||||
* SENSITIVITY
|
||||
*/
|
||||
|
||||
var lastAutosensData: AutosensData? = null
|
||||
/*
|
||||
* Graphs
|
||||
*/
|
||||
|
||||
var bgReadingsArray: List<GlucoseValue> = ArrayList()
|
||||
var maxBgValue = Double.MIN_VALUE
|
||||
var bucketedGraphSeries: PointsWithLabelGraphSeries<DataPointWithLabelInterface> = PointsWithLabelGraphSeries()
|
||||
var bgReadingGraphSeries: PointsWithLabelGraphSeries<DataPointWithLabelInterface> = PointsWithLabelGraphSeries()
|
||||
var predictionsGraphSeries: PointsWithLabelGraphSeries<DataPointWithLabelInterface> = PointsWithLabelGraphSeries()
|
||||
|
||||
var maxBasalValueFound = 0.0
|
||||
val basalScale = Scale()
|
||||
var baseBasalGraphSeries: LineGraphSeries<ScaledDataPoint> = LineGraphSeries()
|
||||
var tempBasalGraphSeries: LineGraphSeries<ScaledDataPoint> = LineGraphSeries()
|
||||
var basalLineGraphSeries: LineGraphSeries<ScaledDataPoint> = LineGraphSeries()
|
||||
var absoluteBasalGraphSeries: LineGraphSeries<ScaledDataPoint> = LineGraphSeries()
|
||||
|
||||
var temporaryTargetSeries: LineGraphSeries<DataPoint> = LineGraphSeries()
|
||||
|
||||
var maxIAValue = 0.0
|
||||
val actScale = Scale()
|
||||
var activitySeries: FixedLineGraphSeries<ScaledDataPoint> = FixedLineGraphSeries()
|
||||
var activityPredictionSeries: FixedLineGraphSeries<ScaledDataPoint> = FixedLineGraphSeries()
|
||||
|
||||
var maxTreatmentsValue = 0.0
|
||||
var treatmentsSeries: PointsWithLabelGraphSeries<DataPointWithLabelInterface> = PointsWithLabelGraphSeries()
|
||||
|
||||
var maxIobValueFound = Double.MIN_VALUE
|
||||
val iobScale = Scale()
|
||||
var iobSeries: FixedLineGraphSeries<ScaledDataPoint> = FixedLineGraphSeries()
|
||||
var absIobSeries: FixedLineGraphSeries<ScaledDataPoint> = FixedLineGraphSeries()
|
||||
var iobPredictions1Series: PointsWithLabelGraphSeries<DataPointWithLabelInterface> = PointsWithLabelGraphSeries()
|
||||
var iobPredictions2Series: PointsWithLabelGraphSeries<DataPointWithLabelInterface> = PointsWithLabelGraphSeries()
|
||||
|
||||
var maxBGIValue = Double.MIN_VALUE
|
||||
val bgiScale = Scale()
|
||||
var minusBgiSeries: FixedLineGraphSeries<ScaledDataPoint> = FixedLineGraphSeries()
|
||||
var minusBgiHistSeries: FixedLineGraphSeries<ScaledDataPoint> = FixedLineGraphSeries()
|
||||
|
||||
var maxCobValueFound = Double.MIN_VALUE
|
||||
val cobScale = Scale()
|
||||
var cobSeries: FixedLineGraphSeries<ScaledDataPoint> = FixedLineGraphSeries()
|
||||
var cobMinFailOverSeries: PointsWithLabelGraphSeries<DataPointWithLabelInterface> = PointsWithLabelGraphSeries()
|
||||
|
||||
var maxDevValueFound = Double.MIN_VALUE
|
||||
val devScale = Scale()
|
||||
var deviationsSeries: BarGraphSeries<OverviewPlugin.DeviationDataPoint> = BarGraphSeries()
|
||||
|
||||
var maxRatioValueFound = 5.0 //even if sens data equals 0 for all the period, minimum scale is between 95% and 105%
|
||||
var minRatioValueFound = -maxRatioValueFound
|
||||
val ratioScale = Scale()
|
||||
var ratioSeries: LineGraphSeries<ScaledDataPoint> = LineGraphSeries()
|
||||
|
||||
var maxFromMaxValueFound = Double.MIN_VALUE
|
||||
var maxFromMinValueFound = Double.MIN_VALUE
|
||||
val dsMaxScale = Scale()
|
||||
val dsMinScale = Scale()
|
||||
var dsMaxSeries: 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)
|
||||
|
||||
// OfflineEvent
|
||||
repository.getOfflineEventDataFromTimeToTime(fromTime, endTime, true).blockingGet()
|
||||
.map { TherapyEventDataPoint(TherapyEvent(timestamp = it.timestamp, duration = it.duration, type = TherapyEvent.Type.APS_OFFLINE, glucoseUnit = TherapyEvent.GlucoseUnit.MMOL), resourceHelper, profileFunction, translator) }
|
||||
.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 }
|
||||
|
||||
}
|
|
@ -10,6 +10,7 @@ import android.graphics.Paint
|
|||
import android.graphics.drawable.AnimationDrawable
|
||||
import android.os.Bundle
|
||||
import android.os.Handler
|
||||
import android.os.HandlerThread
|
||||
import android.util.DisplayMetrics
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
|
@ -19,25 +20,27 @@ import android.widget.LinearLayout
|
|||
import android.widget.RelativeLayout
|
||||
import android.widget.TextView
|
||||
import androidx.core.text.toSpanned
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.jjoe64.graphview.GraphView
|
||||
import dagger.android.HasAndroidInjector
|
||||
import dagger.android.support.DaggerFragment
|
||||
import info.nightscout.androidaps.interfaces.Config
|
||||
import info.nightscout.androidaps.Constants
|
||||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.interfaces.Profile
|
||||
import info.nightscout.androidaps.database.AppRepository
|
||||
import info.nightscout.androidaps.database.ValueWrapper
|
||||
import info.nightscout.androidaps.database.entities.TemporaryTarget
|
||||
import info.nightscout.androidaps.database.entities.UserEntry.Action
|
||||
import info.nightscout.androidaps.database.entities.UserEntry.Sources
|
||||
import info.nightscout.androidaps.database.interfaces.end
|
||||
import info.nightscout.androidaps.databinding.OverviewFragmentBinding
|
||||
import info.nightscout.androidaps.dialogs.*
|
||||
import info.nightscout.androidaps.events.*
|
||||
import info.nightscout.androidaps.extensions.*
|
||||
import info.nightscout.androidaps.events.EventAcceptOpenLoopChange
|
||||
import info.nightscout.androidaps.events.EventInitializationChanged
|
||||
import info.nightscout.androidaps.events.EventPreferenceChange
|
||||
import info.nightscout.androidaps.events.EventPumpStatusChanged
|
||||
import info.nightscout.androidaps.events.EventRefreshOverview
|
||||
import info.nightscout.androidaps.extensions.directionToIcon
|
||||
import info.nightscout.androidaps.extensions.isInProgress
|
||||
import info.nightscout.androidaps.extensions.toVisibility
|
||||
import info.nightscout.androidaps.extensions.valueToUnitsString
|
||||
import info.nightscout.androidaps.interfaces.*
|
||||
import info.nightscout.androidaps.logging.AAPSLogger
|
||||
import info.nightscout.androidaps.logging.UserEntryLogger
|
||||
|
@ -47,22 +50,19 @@ import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
|||
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
|
||||
import info.nightscout.androidaps.plugins.general.nsclient.data.NSDeviceStatus
|
||||
import info.nightscout.androidaps.plugins.general.overview.activities.QuickWizardListActivity
|
||||
import info.nightscout.androidaps.plugins.general.overview.events.EventUpdateOverview
|
||||
import info.nightscout.androidaps.plugins.general.overview.graphData.GraphData
|
||||
import info.nightscout.androidaps.plugins.general.overview.graphExtensions.GlucoseValueDataPoint
|
||||
import info.nightscout.androidaps.plugins.general.overview.notifications.NotificationStore
|
||||
import info.nightscout.androidaps.plugins.general.wear.events.EventWearInitiateAction
|
||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatusProvider
|
||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventIobCalculationProgress
|
||||
import info.nightscout.androidaps.plugins.pump.common.defs.PumpType
|
||||
import info.nightscout.androidaps.plugins.source.DexcomPlugin
|
||||
import info.nightscout.androidaps.plugins.source.XdripPlugin
|
||||
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin
|
||||
import info.nightscout.androidaps.queue.CommandQueue
|
||||
import info.nightscout.androidaps.skins.SkinProvider
|
||||
import info.nightscout.androidaps.utils.*
|
||||
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
|
||||
import info.nightscout.androidaps.utils.buildHelper.BuildHelper
|
||||
import info.nightscout.androidaps.utils.extensions.*
|
||||
import info.nightscout.androidaps.utils.protection.ProtectionCheck
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
||||
|
@ -70,15 +70,11 @@ import info.nightscout.androidaps.utils.sharedPreferences.SP
|
|||
import info.nightscout.androidaps.utils.ui.UIRunnable
|
||||
import info.nightscout.androidaps.utils.wizard.QuickWizard
|
||||
import io.reactivex.disposables.CompositeDisposable
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import io.reactivex.rxkotlin.plusAssign
|
||||
import java.util.*
|
||||
import javax.inject.Inject
|
||||
import kotlin.collections.ArrayList
|
||||
import kotlin.math.abs
|
||||
import kotlin.math.ceil
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
|
||||
class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickListener {
|
||||
|
@ -96,7 +92,6 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
|
|||
@Inject lateinit var nsDeviceStatus: NSDeviceStatus
|
||||
@Inject lateinit var loopPlugin: LoopPlugin
|
||||
@Inject lateinit var activePlugin: ActivePlugin
|
||||
@Inject lateinit var treatmentsPlugin: TreatmentsPlugin
|
||||
@Inject lateinit var iobCobCalculator: IobCobCalculator
|
||||
@Inject lateinit var dexcomPlugin: DexcomPlugin
|
||||
@Inject lateinit var dexcomMediator: DexcomPlugin.DexcomMediator
|
||||
|
@ -112,10 +107,11 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
|
|||
@Inject lateinit var trendCalculator: TrendCalculator
|
||||
@Inject lateinit var config: Config
|
||||
@Inject lateinit var dateUtil: DateUtil
|
||||
@Inject lateinit var databaseHelper: DatabaseHelperInterface
|
||||
@Inject lateinit var uel: UserEntryLogger
|
||||
@Inject lateinit var repository: AppRepository
|
||||
@Inject lateinit var glucoseStatusProvider: GlucoseStatusProvider
|
||||
@Inject lateinit var overviewData: OverviewData
|
||||
@Inject lateinit var overviewPlugin: OverviewPlugin
|
||||
|
||||
private val disposable = CompositeDisposable()
|
||||
|
||||
|
@ -123,17 +119,14 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
|
|||
private var smallHeight = false
|
||||
private lateinit var dm: DisplayMetrics
|
||||
private var axisWidth: Int = 0
|
||||
private var rangeToDisplay = 6 // for graph
|
||||
private var loopHandler = Handler()
|
||||
private var refreshLoop: Runnable? = null
|
||||
private lateinit var handler: Handler
|
||||
|
||||
private val secondaryGraphs = ArrayList<GraphView>()
|
||||
private val secondaryGraphsLabel = ArrayList<TextView>()
|
||||
|
||||
private var carbAnimation: AnimationDrawable? = null
|
||||
|
||||
private val graphLock = Object()
|
||||
|
||||
private var _binding: OverviewFragmentBinding? = null
|
||||
|
||||
// This property is only valid between onCreateView and
|
||||
|
@ -150,6 +143,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
|
|||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
handler = Handler(HandlerThread(this::class.simpleName + "Handler").also { it.start() }.looper)
|
||||
|
||||
// pre-process landscape mode
|
||||
val screenWidth = dm.widthPixels
|
||||
|
@ -175,13 +169,14 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
|
|||
carbAnimation?.setEnterFadeDuration(1200)
|
||||
carbAnimation?.setExitFadeDuration(1200)
|
||||
|
||||
rangeToDisplay = sp.getInt(R.string.key_rangetodisplay, 6)
|
||||
|
||||
binding.graphsLayout.bgGraph.setOnLongClickListener {
|
||||
rangeToDisplay += 6
|
||||
rangeToDisplay = if (rangeToDisplay > 24) 6 else rangeToDisplay
|
||||
sp.putInt(R.string.key_rangetodisplay, rangeToDisplay)
|
||||
updateGUI("rangeChange")
|
||||
overviewData.rangeToDisplay += 6
|
||||
overviewData.rangeToDisplay = if (overviewData.rangeToDisplay > 24) 6 else overviewData.rangeToDisplay
|
||||
sp.putInt(R.string.key_rangetodisplay, overviewData.rangeToDisplay)
|
||||
overviewData.initRange()
|
||||
updateGUI("rangeChange", OverviewData.Property.GRAPH)
|
||||
rxBus.send(EventPreferenceChange(resourceHelper, R.string.key_rangetodisplay))
|
||||
sp.putBoolean(R.string.key_objectiveusescale, true)
|
||||
false
|
||||
}
|
||||
|
@ -210,55 +205,32 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
|
|||
override fun onPause() {
|
||||
super.onPause()
|
||||
disposable.clear()
|
||||
loopHandler.removeCallbacksAndMessages(null)
|
||||
handler.removeCallbacksAndMessages(null)
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
disposable += activePlugin.activeOverview.overviewBus
|
||||
.toObservable(EventUpdateOverview::class.java)
|
||||
.observeOn(aapsSchedulers.main)
|
||||
.subscribe({ updateGUI(it.from, it.what) }, fabricPrivacy::logException)
|
||||
|
||||
disposable.add(rxBus
|
||||
.toObservable(EventRefreshOverview::class.java)
|
||||
.observeOn(aapsSchedulers.main)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.subscribe({
|
||||
if (it.now) updateGUI(it.from)
|
||||
if (it.now) overviewPlugin.refreshLoop(it.from)
|
||||
else scheduleUpdateGUI(it.from)
|
||||
}, fabricPrivacy::logException))
|
||||
disposable.add(rxBus
|
||||
.toObservable(EventExtendedBolusChange::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.subscribe({ scheduleUpdateGUI("EventExtendedBolusChange") }, fabricPrivacy::logException))
|
||||
disposable.add(rxBus
|
||||
.toObservable(EventTempBasalChange::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.subscribe({ scheduleUpdateGUI("EventTempBasalChange") }, fabricPrivacy::logException))
|
||||
disposable.add(rxBus
|
||||
.toObservable(EventTreatmentChange::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.subscribe({ scheduleUpdateGUI("EventTreatmentChange") }, fabricPrivacy::logException))
|
||||
disposable.add(rxBus
|
||||
.toObservable(EventTempTargetChange::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.subscribe({ scheduleUpdateGUI("EventTempTargetChange") }, fabricPrivacy::logException))
|
||||
disposable.add(rxBus
|
||||
.toObservable(EventAcceptOpenLoopChange::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.subscribe({ scheduleUpdateGUI("EventAcceptOpenLoopChange") }, fabricPrivacy::logException))
|
||||
disposable.add(rxBus
|
||||
.toObservable(EventTherapyEventChange::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.subscribe({ scheduleUpdateGUI("EventCareportalEventChange") }, fabricPrivacy::logException))
|
||||
disposable.add(rxBus
|
||||
.toObservable(EventInitializationChanged::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.subscribe({ scheduleUpdateGUI("EventInitializationChanged") }, fabricPrivacy::logException))
|
||||
disposable.add(rxBus
|
||||
.toObservable(EventAutosensCalculationFinished::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.subscribe({ scheduleUpdateGUI("EventAutosensCalculationFinished") }, fabricPrivacy::logException))
|
||||
disposable.add(rxBus
|
||||
.toObservable(EventProfileSwitchChanged::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.subscribe({ scheduleUpdateGUI("EventProfileNeedsUpdate") }, fabricPrivacy::logException))
|
||||
.observeOn(aapsSchedulers.main)
|
||||
.subscribe({ updateGUI("EventInitializationChanged", OverviewData.Property.TIME) }, fabricPrivacy::logException))
|
||||
disposable.add(rxBus
|
||||
.toObservable(EventPreferenceChange::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
|
@ -271,18 +243,14 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
|
|||
.toObservable(EventPumpStatusChanged::class.java)
|
||||
.observeOn(aapsSchedulers.main)
|
||||
.subscribe({ updatePumpStatus(it) }, fabricPrivacy::logException))
|
||||
disposable.add(rxBus
|
||||
.toObservable(EventIobCalculationProgress::class.java)
|
||||
.observeOn(aapsSchedulers.main)
|
||||
.subscribe({ binding.graphsLayout.iobCalculationProgress.text = it.progress }, fabricPrivacy::logException))
|
||||
|
||||
refreshLoop = Runnable {
|
||||
scheduleUpdateGUI("refreshLoop")
|
||||
loopHandler.postDelayed(refreshLoop, 60 * 1000L)
|
||||
overviewPlugin.refreshLoop("refreshLoop")
|
||||
handler.postDelayed(refreshLoop, 60 * 1000L)
|
||||
}
|
||||
loopHandler.postDelayed(refreshLoop, 60 * 1000L)
|
||||
handler.postDelayed(refreshLoop, 60 * 1000L)
|
||||
|
||||
updateGUI("onResume")
|
||||
for (p in OverviewData.Property.values()) updateGUI("onResume", p)
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
|
@ -297,14 +265,14 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
|
|||
if (childFragmentManager.isStateSaved) return
|
||||
activity?.let { activity ->
|
||||
when (v.id) {
|
||||
R.id.treatment_button -> protectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, UIRunnable { if (isAdded) TreatmentDialog().show(childFragmentManager, "Overview") })
|
||||
R.id.wizard_button -> protectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, UIRunnable { if (isAdded) WizardDialog().show(childFragmentManager, "Overview") })
|
||||
R.id.insulin_button -> protectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, UIRunnable { if (isAdded) InsulinDialog().show(childFragmentManager, "Overview") })
|
||||
R.id.treatment_button -> protectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, UIRunnable { if (isAdded) TreatmentDialog().show(childFragmentManager, "Overview") })
|
||||
R.id.wizard_button -> protectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, UIRunnable { if (isAdded) WizardDialog().show(childFragmentManager, "Overview") })
|
||||
R.id.insulin_button -> protectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, UIRunnable { if (isAdded) InsulinDialog().show(childFragmentManager, "Overview") })
|
||||
R.id.quick_wizard_button -> protectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, UIRunnable { if (isAdded) onClickQuickWizard() })
|
||||
R.id.carbs_button -> protectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, UIRunnable { if (isAdded) CarbsDialog().show(childFragmentManager, "Overview") })
|
||||
R.id.temp_target -> protectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, UIRunnable { if (isAdded) TempTargetDialog().show(childFragmentManager, "Overview") })
|
||||
R.id.carbs_button -> protectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, UIRunnable { if (isAdded) CarbsDialog().show(childFragmentManager, "Overview") })
|
||||
R.id.temp_target -> protectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, UIRunnable { if (isAdded) TempTargetDialog().show(childFragmentManager, "Overview") })
|
||||
|
||||
R.id.active_profile -> {
|
||||
R.id.active_profile -> {
|
||||
ProfileViewerDialog().also { pvd ->
|
||||
pvd.arguments = Bundle().also {
|
||||
it.putLong("time", dateUtil.now())
|
||||
|
@ -313,7 +281,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
|
|||
}.show(childFragmentManager, "ProfileViewDialog")
|
||||
}
|
||||
|
||||
R.id.cgm_button -> {
|
||||
R.id.cgm_button -> {
|
||||
if (xdripPlugin.isEnabled(PluginType.BGSOURCE))
|
||||
openCgmApp("com.eveningoutpost.dexdrip")
|
||||
else if (dexcomPlugin.isEnabled(PluginType.BGSOURCE)) {
|
||||
|
@ -324,7 +292,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
|
|||
}
|
||||
}
|
||||
|
||||
R.id.calibration_button -> {
|
||||
R.id.calibration_button -> {
|
||||
if (xdripPlugin.isEnabled(PluginType.BGSOURCE)) {
|
||||
CalibrationDialog().show(childFragmentManager, "CalibrationDialog")
|
||||
} else if (dexcomPlugin.isEnabled(PluginType.BGSOURCE)) {
|
||||
|
@ -339,27 +307,29 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
|
|||
}
|
||||
}
|
||||
|
||||
R.id.accept_temp_button -> {
|
||||
R.id.accept_temp_button -> {
|
||||
profileFunction.getProfile() ?: return
|
||||
if (loopPlugin.isEnabled(PluginType.LOOP)) {
|
||||
val lastRun = loopPlugin.lastRun
|
||||
loopPlugin.invoke("Accept temp button", false)
|
||||
if (lastRun?.lastAPSRun != null && lastRun.constraintsProcessed?.isChangeRequested == true) {
|
||||
protectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, UIRunnable {
|
||||
OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.tempbasal_label), lastRun.constraintsProcessed?.toSpanned()
|
||||
?: "".toSpanned(), {
|
||||
uel.log(Action.ACCEPTS_TEMP_BASAL, Sources.Overview)
|
||||
binding.buttonsLayout.acceptTempButton.visibility = View.GONE
|
||||
(context?.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager).cancel(Constants.notificationID)
|
||||
rxBus.send(EventWearInitiateAction("cancelChangeRequest"))
|
||||
loopPlugin.acceptChangeRequest()
|
||||
handler.post {
|
||||
val lastRun = loopPlugin.lastRun
|
||||
loopPlugin.invoke("Accept temp button", false)
|
||||
if (lastRun?.lastAPSRun != null && lastRun.constraintsProcessed?.isChangeRequested == true) {
|
||||
protectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, UIRunnable {
|
||||
OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.tempbasal_label), lastRun.constraintsProcessed?.toSpanned()
|
||||
?: "".toSpanned(), {
|
||||
uel.log(Action.ACCEPTS_TEMP_BASAL, Sources.Overview)
|
||||
binding.buttonsLayout.acceptTempButton.visibility = View.GONE
|
||||
(context?.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager).cancel(Constants.notificationID)
|
||||
rxBus.send(EventWearInitiateAction("cancelChangeRequest"))
|
||||
Thread { loopPlugin.acceptChangeRequest() }.run()
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
R.id.aps_mode -> {
|
||||
R.id.aps_mode -> {
|
||||
protectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, UIRunnable {
|
||||
if (isAdded) LoopDialog().also { dialog ->
|
||||
dialog.arguments = Bundle().also { it.putInt("showOkCancel", 1) }
|
||||
|
@ -391,7 +361,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
|
|||
return true
|
||||
}
|
||||
|
||||
R.id.aps_mode -> {
|
||||
R.id.aps_mode -> {
|
||||
activity?.let { activity ->
|
||||
protectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, UIRunnable {
|
||||
LoopDialog().also { dialog ->
|
||||
|
@ -401,8 +371,8 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
|
|||
}
|
||||
}
|
||||
|
||||
R.id.temp_target -> v.performClick()
|
||||
R.id.active_profile -> activity?.let { activity -> protectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, UIRunnable { ProfileSwitchDialog().show(childFragmentManager, "Overview") }) }
|
||||
R.id.temp_target -> v.performClick()
|
||||
R.id.active_profile -> activity?.let { activity -> protectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, UIRunnable { ProfileSwitchDialog().show(childFragmentManager, "Overview") }) }
|
||||
|
||||
}
|
||||
return false
|
||||
|
@ -490,133 +460,11 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
|
|||
|
||||
}
|
||||
|
||||
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.graphsLayout.iobGraph.removeAllViews()
|
||||
for (i in 1 until numOfGraphs) {
|
||||
val relativeLayout = RelativeLayout(context)
|
||||
relativeLayout.layoutParams = RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
|
||||
|
||||
val graph = GraphView(context)
|
||||
graph.layoutParams = LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, resourceHelper.dpToPx(skinProvider.activeSkin().secondaryGraphHeight)).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(context)
|
||||
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.graphsLayout.iobGraph.addView(relativeLayout)
|
||||
secondaryGraphs.add(graph)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var task: Runnable? = null
|
||||
|
||||
private fun scheduleUpdateGUI(from: String) {
|
||||
class UpdateRunnable : Runnable {
|
||||
|
||||
override fun run() {
|
||||
updateGUI(from)
|
||||
task = null
|
||||
}
|
||||
}
|
||||
view?.removeCallbacks(task)
|
||||
task = UpdateRunnable()
|
||||
view?.postDelayed(task, 500)
|
||||
}
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
fun updateGUI(from: String) {
|
||||
if (_binding == null) return
|
||||
aapsLogger.debug("UpdateGUI from $from")
|
||||
|
||||
binding.infoLayout.time.text = dateUtil.timeString(dateUtil.now())
|
||||
|
||||
if (!profileFunction.isProfileValid("Overview")) {
|
||||
binding.loopPumpStatusLayout.pumpStatus.setText(R.string.noprofileset)
|
||||
binding.loopPumpStatusLayout.pumpStatusLayout.visibility = View.VISIBLE
|
||||
binding.loopPumpStatusLayout.loopLayout.visibility = View.GONE
|
||||
return
|
||||
}
|
||||
binding.notifications.let { notificationStore.updateNotifications(it) }
|
||||
binding.loopPumpStatusLayout.pumpStatusLayout.visibility = View.GONE
|
||||
binding.loopPumpStatusLayout.loopLayout.visibility = View.VISIBLE
|
||||
|
||||
val profile = profileFunction.getProfile() ?: return
|
||||
val actualBG = iobCobCalculator.ads.actualBg()
|
||||
val lastBG = iobCobCalculator.ads.lastBg()
|
||||
private fun processAps() {
|
||||
val pump = activePlugin.activePump
|
||||
val units = profileFunction.getUnits()
|
||||
val lowLine = defaultValueHelper.determineLowLine()
|
||||
val highLine = defaultValueHelper.determineHighLine()
|
||||
val lastRun = loopPlugin.lastRun
|
||||
val predictionsAvailable = if (config.APS) lastRun?.request?.hasPredictions == true else config.NSCLIENT
|
||||
|
||||
try {
|
||||
updateGraph(lastRun, predictionsAvailable, lowLine, highLine, pump, profile)
|
||||
} catch (e: IllegalStateException) {
|
||||
return // view no longer exists
|
||||
}
|
||||
|
||||
//Start with updating the BG as it is unaffected by loop.
|
||||
// **** BG value ****
|
||||
if (lastBG != null) {
|
||||
val color = when {
|
||||
lastBG.valueToUnits(units) < lowLine -> resourceHelper.gc(R.color.low)
|
||||
lastBG.valueToUnits(units) > highLine -> resourceHelper.gc(R.color.high)
|
||||
else -> resourceHelper.gc(R.color.inrange)
|
||||
}
|
||||
|
||||
binding.infoLayout.bg.text = lastBG.valueToUnitsString(units)
|
||||
binding.infoLayout.bg.setTextColor(color)
|
||||
binding.infoLayout.arrow.setImageResource(trendCalculator.getTrendArrow(lastBG).directionToIcon())
|
||||
binding.infoLayout.arrow.setColorFilter(color)
|
||||
|
||||
val glucoseStatus = glucoseStatusProvider.glucoseStatusData
|
||||
if (glucoseStatus != null) {
|
||||
binding.infoLayout.deltaLarge.text = Profile.toSignedUnitsString(glucoseStatus.delta, glucoseStatus.delta * Constants.MGDL_TO_MMOLL, units)
|
||||
binding.infoLayout.deltaLarge.setTextColor(color)
|
||||
binding.infoLayout.delta.text = Profile.toSignedUnitsString(glucoseStatus.delta, glucoseStatus.delta * 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)
|
||||
} else {
|
||||
binding.infoLayout.delta.text = "Δ " + resourceHelper.gs(R.string.notavailable)
|
||||
binding.infoLayout.avgDelta.text = ""
|
||||
binding.infoLayout.longAvgDelta.text = ""
|
||||
}
|
||||
|
||||
// strike through if BG is old
|
||||
binding.infoLayout.bg.let { overview_bg ->
|
||||
var flag = overview_bg.paintFlags
|
||||
flag = if (actualBG == null) {
|
||||
flag or Paint.STRIKE_THRU_TEXT_FLAG
|
||||
} else flag and Paint.STRIKE_THRU_TEXT_FLAG.inv()
|
||||
overview_bg.paintFlags = flag
|
||||
}
|
||||
binding.infoLayout.timeAgo.text = dateUtil.minAgo(resourceHelper, lastBG.timestamp)
|
||||
binding.infoLayout.timeAgoShort.text = "(" + dateUtil.minAgoShort(lastBG.timestamp) + ")"
|
||||
|
||||
}
|
||||
val closedLoopEnabled = constraintChecker.isClosedLoopAllowed()
|
||||
|
||||
// aps mode
|
||||
val closedLoopEnabled = constraintChecker.isClosedLoopAllowed()
|
||||
if (config.APS && pump.pumpDescription.isTempBasalCapable) {
|
||||
binding.infoLayout.apsMode.visibility = View.VISIBLE
|
||||
binding.infoLayout.timeLayout.visibility = View.GONE
|
||||
|
@ -677,119 +525,6 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
|
|||
binding.infoLayout.timeLayout.visibility = View.VISIBLE
|
||||
}
|
||||
|
||||
// temp target
|
||||
val tempTarget: ValueWrapper<TemporaryTarget> = repository.getTemporaryTargetActiveAt(dateUtil.now()).blockingGet()
|
||||
if (tempTarget is ValueWrapper.Existing) {
|
||||
binding.loopPumpStatusLayout.tempTarget.setTextColor(resourceHelper.gc(R.color.ribbonTextWarning))
|
||||
binding.loopPumpStatusLayout.tempTarget.setBackgroundColor(resourceHelper.gc(R.color.ribbonWarning))
|
||||
binding.loopPumpStatusLayout.tempTarget.text = Profile.toTargetRangeString(tempTarget.value.lowTarget, tempTarget.value.highTarget, GlucoseUnit.MGDL, units) + " " + dateUtil.untilString(tempTarget.value.end, resourceHelper)
|
||||
} else {
|
||||
// If the target is not the same as set in the profile then oref has overridden it
|
||||
val targetUsed = lastRun?.constraintsProcessed?.targetBG ?: 0.0
|
||||
|
||||
if (targetUsed != 0.0 && abs(profile.getTargetMgdl() - targetUsed) > 0.01) {
|
||||
aapsLogger.debug("Adjusted target. Profile: ${profile.getTargetMgdl()} APS: $targetUsed")
|
||||
binding.loopPumpStatusLayout.tempTarget.text = Profile.toTargetRangeString(targetUsed, targetUsed, GlucoseUnit.MGDL, units)
|
||||
binding.loopPumpStatusLayout.tempTarget.setTextColor(resourceHelper.gc(R.color.ribbonTextWarning))
|
||||
binding.loopPumpStatusLayout.tempTarget.setBackgroundColor(resourceHelper.gc(R.color.tempTargetBackground))
|
||||
} else {
|
||||
binding.loopPumpStatusLayout.tempTarget.setTextColor(resourceHelper.gc(R.color.ribbonTextDefault))
|
||||
binding.loopPumpStatusLayout.tempTarget.setBackgroundColor(resourceHelper.gc(R.color.ribbonDefault))
|
||||
binding.loopPumpStatusLayout.tempTarget.text = Profile.toTargetRangeString(profile.getTargetLowMgdl(), profile.getTargetHighMgdl(), GlucoseUnit.MGDL, units)
|
||||
}
|
||||
}
|
||||
|
||||
// Basal, TBR
|
||||
val activeTemp = iobCobCalculator.getTempBasalIncludingConvertedExtended(System.currentTimeMillis())
|
||||
binding.infoLayout.baseBasal.text = activeTemp?.let { "T:" + activeTemp.toStringShort() }
|
||||
?: resourceHelper.gs(R.string.pump_basebasalrate, profile.getBasal())
|
||||
binding.infoLayout.basalLayout.setOnClickListener {
|
||||
var fullText = "${resourceHelper.gs(R.string.basebasalrate_label)}: ${resourceHelper.gs(R.string.pump_basebasalrate, profile.getBasal())}"
|
||||
if (activeTemp != null)
|
||||
fullText += "\n" + resourceHelper.gs(R.string.tempbasal_label) + ": " + activeTemp.toStringFull(profile, dateUtil)
|
||||
activity?.let {
|
||||
OKDialog.show(it, resourceHelper.gs(R.string.basal), fullText)
|
||||
}
|
||||
}
|
||||
binding.infoLayout.baseBasal.setTextColor(activeTemp?.let { resourceHelper.gc(R.color.basal) }
|
||||
?: resourceHelper.gc(R.color.defaulttextcolor))
|
||||
|
||||
binding.infoLayout.baseBasalIcon.setImageResource(R.drawable.ic_cp_basal_no_tbr)
|
||||
val percentRate = activeTemp?.convertedToPercent(System.currentTimeMillis(), profile)
|
||||
?: 100
|
||||
if (percentRate > 100) binding.infoLayout.baseBasalIcon.setImageResource(R.drawable.ic_cp_basal_tbr_high)
|
||||
if (percentRate < 100) binding.infoLayout.baseBasalIcon.setImageResource(R.drawable.ic_cp_basal_tbr_low)
|
||||
|
||||
// Extended bolus
|
||||
val extendedBolus = repository.getExtendedBolusActiveAt(dateUtil.now()).blockingGet()
|
||||
binding.infoLayout.extendedBolus.text =
|
||||
if (extendedBolus is ValueWrapper.Existing && !pump.isFakingTempsByExtendedBoluses)
|
||||
resourceHelper.gs(R.string.pump_basebasalrate, extendedBolus.value.rate)
|
||||
else ""
|
||||
binding.infoLayout.extendedBolus.setOnClickListener {
|
||||
if (extendedBolus is ValueWrapper.Existing) activity?.let {
|
||||
OKDialog.show(it, resourceHelper.gs(R.string.extended_bolus), extendedBolus.value.toStringFull(dateUtil))
|
||||
}
|
||||
}
|
||||
binding.infoLayout.extendedLayout.visibility = (extendedBolus is ValueWrapper.Existing && !pump.isFakingTempsByExtendedBoluses).toVisibility()
|
||||
|
||||
// Active profile
|
||||
binding.loopPumpStatusLayout.activeProfile.text = profileFunction.getProfileNameWithRemainingTime()
|
||||
if (profile.percentage != 100 || profile.timeshift != 0) {
|
||||
binding.loopPumpStatusLayout.activeProfile.setBackgroundColor(resourceHelper.gc(R.color.ribbonWarning))
|
||||
binding.loopPumpStatusLayout.activeProfile.setTextColor(resourceHelper.gc(R.color.ribbonTextWarning))
|
||||
} else {
|
||||
binding.loopPumpStatusLayout.activeProfile.setBackgroundColor(resourceHelper.gc(R.color.ribbonDefault))
|
||||
binding.loopPumpStatusLayout.activeProfile.setTextColor(resourceHelper.gc(R.color.ribbonTextDefault))
|
||||
}
|
||||
|
||||
processButtonsVisibility()
|
||||
|
||||
// iob
|
||||
val bolusIob = iobCobCalculator.calculateIobFromBolus().round()
|
||||
val basalIob = iobCobCalculator.calculateIobFromTempBasalsIncludingConvertedExtended().round()
|
||||
binding.infoLayout.iob.text = resourceHelper.gs(R.string.formatinsulinunits, bolusIob.iob + basalIob.basaliob)
|
||||
|
||||
binding.infoLayout.iobLayout.setOnClickListener {
|
||||
activity?.let {
|
||||
OKDialog.show(it, resourceHelper.gs(R.string.iob),
|
||||
resourceHelper.gs(R.string.formatinsulinunits, bolusIob.iob + basalIob.basaliob) + "\n" +
|
||||
resourceHelper.gs(R.string.bolus) + ": " + resourceHelper.gs(R.string.formatinsulinunits, bolusIob.iob) + "\n" +
|
||||
resourceHelper.gs(R.string.basal) + ": " + resourceHelper.gs(R.string.formatinsulinunits, basalIob.basaliob)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Status lights
|
||||
binding.statusLightsLayout.statusLights.visibility = (sp.getBoolean(R.string.key_show_statuslights, true) || config.NSCLIENT).toVisibility()
|
||||
statusLightHandler.updateStatusLights(binding.statusLightsLayout.cannulaAge, binding.statusLightsLayout.insulinAge, binding.statusLightsLayout.reservoirLevel, binding.statusLightsLayout.sensorAge, null, binding.statusLightsLayout.pbAge, binding.statusLightsLayout.batteryLevel)
|
||||
|
||||
// cob
|
||||
var cobText: String = resourceHelper.gs(R.string.value_unavailable_short)
|
||||
val cobInfo = iobCobCalculator.getCobInfo(false, "Overview COB")
|
||||
if (cobInfo.displayCob != null) {
|
||||
cobText = resourceHelper.gs(R.string.format_carbs, cobInfo.displayCob!!.toInt())
|
||||
if (cobInfo.futureCarbs > 0) cobText += "(" + DecimalFormatter.to0Decimal(cobInfo.futureCarbs) + ")"
|
||||
}
|
||||
|
||||
if (config.APS && lastRun?.constraintsProcessed != null) {
|
||||
if (lastRun.constraintsProcessed!!.carbsReq > 0) {
|
||||
//only display carbsreq when carbs have not been entered recently
|
||||
val lastCarb = repository.getLastCarbsRecordWrapped().blockingGet()
|
||||
val lastCarbsTime = if (lastCarb is ValueWrapper.Existing) lastCarb.value.timestamp else 0L
|
||||
if (lastCarbsTime < lastRun.lastAPSRun) {
|
||||
cobText = cobText + " | " + lastRun.constraintsProcessed!!.carbsReq + " " + resourceHelper.gs(R.string.required)
|
||||
}
|
||||
binding.infoLayout.cob.text = cobText
|
||||
if (carbAnimation?.isRunning == false)
|
||||
carbAnimation?.start()
|
||||
} else {
|
||||
binding.infoLayout.cob.text = cobText
|
||||
carbAnimation?.stop()
|
||||
carbAnimation?.selectDrawable(0)
|
||||
}
|
||||
} else binding.infoLayout.cob.text = cobText
|
||||
|
||||
// pump status from ns
|
||||
binding.pump.text = nsDeviceStatus.pumpStatus
|
||||
binding.pump.setOnClickListener { activity?.let { OKDialog.show(it, resourceHelper.gs(R.string.pump), nsDeviceStatus.extendedPumpStatus) } }
|
||||
|
@ -801,131 +536,256 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
|
|||
// Uploader status from ns
|
||||
binding.uploader.text = nsDeviceStatus.uploaderStatusSpanned
|
||||
binding.uploader.setOnClickListener { activity?.let { OKDialog.show(it, resourceHelper.gs(R.string.uploader), nsDeviceStatus.extendedUploaderStatus) } }
|
||||
|
||||
// Sensitivity
|
||||
if (sp.getBoolean(R.string.key_openapsama_useautosens, false) && constraintChecker.isAutosensModeEnabled().value()) {
|
||||
binding.infoLayout.sensitivityIcon.setImageResource(R.drawable.ic_swap_vert_black_48dp_green)
|
||||
} else {
|
||||
binding.infoLayout.sensitivityIcon.setImageResource(R.drawable.ic_x_swap_vert)
|
||||
}
|
||||
|
||||
binding.infoLayout.sensitivity.text =
|
||||
iobCobCalculator.ads.getLastAutosensData("Overview", aapsLogger, dateUtil)?.let { autosensData ->
|
||||
String.format(Locale.ENGLISH, "%.0f%%", autosensData.autosensResult.ratio * 100)
|
||||
} ?: ""
|
||||
}
|
||||
|
||||
private fun updateGraph(lastRun: LoopInterface.LastRun?, predictionsAvailable: Boolean, lowLine: Double, highLine: Double, pump: Pump, profile: Profile) {
|
||||
viewLifecycleOwner.lifecycleScope.launch(Dispatchers.Main) {
|
||||
if (_binding == null) return@launch
|
||||
val menuChartSettings = overviewMenus.setting
|
||||
prepareGraphsIfNeeded(menuChartSettings.size)
|
||||
val graphData = GraphData(injector, binding.graphsLayout.bgGraph, iobCobCalculator)
|
||||
val secondaryGraphsData: ArrayList<GraphData> = ArrayList()
|
||||
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.graphsLayout.iobGraph.removeAllViews()
|
||||
for (i in 1 until numOfGraphs) {
|
||||
val relativeLayout = RelativeLayout(context)
|
||||
relativeLayout.layoutParams = RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
|
||||
|
||||
// do preparation in different thread
|
||||
withContext(Dispatchers.Default) {
|
||||
// align to hours
|
||||
val calendar = Calendar.getInstance()
|
||||
calendar.timeInMillis = System.currentTimeMillis()
|
||||
calendar[Calendar.MILLISECOND] = 0
|
||||
calendar[Calendar.SECOND] = 0
|
||||
calendar[Calendar.MINUTE] = 0
|
||||
calendar.add(Calendar.HOUR, 1)
|
||||
val hoursToFetch: Int
|
||||
val toTime: Long
|
||||
val fromTime: Long
|
||||
val endTime: Long
|
||||
val apsResult = if (config.APS) lastRun?.constraintsProcessed else nsDeviceStatus.getAPSResult(injector)
|
||||
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)
|
||||
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()
|
||||
val graph = GraphView(context)
|
||||
graph.layoutParams = LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, resourceHelper.dpToPx(skinProvider.activeSkin().secondaryGraphHeight)).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(context)
|
||||
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.graphsLayout.iobGraph.addView(relativeLayout)
|
||||
secondaryGraphs.add(graph)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var task: Runnable? = null
|
||||
|
||||
private fun scheduleUpdateGUI(from: String) {
|
||||
class UpdateRunnable : Runnable {
|
||||
|
||||
override fun run() {
|
||||
overviewPlugin.refreshLoop(from)
|
||||
task = null
|
||||
}
|
||||
}
|
||||
handler.removeCallbacks(task)
|
||||
task = UpdateRunnable()
|
||||
handler.postDelayed(task, 500)
|
||||
}
|
||||
|
||||
@Suppress("UNUSED_PARAMETER")
|
||||
@SuppressLint("SetTextI18n")
|
||||
fun updateGUI(from: String, what: OverviewData.Property) {
|
||||
// if (what != OverviewData.Property.CALC_PROGRESS)
|
||||
// aapsLogger.debug(LTag.UI, "UpdateGui $from $what")
|
||||
if (overviewData.profile == null) {
|
||||
binding.loopPumpStatusLayout.pumpStatus.setText(R.string.noprofileset)
|
||||
binding.loopPumpStatusLayout.pumpStatusLayout.visibility = View.VISIBLE
|
||||
binding.loopPumpStatusLayout.loopLayout.visibility = View.GONE
|
||||
return
|
||||
}
|
||||
binding.notifications.let { notificationStore.updateNotifications(it) }
|
||||
binding.loopPumpStatusLayout.pumpStatusLayout.visibility = View.GONE
|
||||
binding.loopPumpStatusLayout.loopLayout.visibility = View.VISIBLE
|
||||
|
||||
val units = profileFunction.getUnits()
|
||||
val pump = activePlugin.activePump
|
||||
when (what) {
|
||||
OverviewData.Property.BG -> {
|
||||
binding.infoLayout.bg.text = overviewData.lastBg?.valueToUnitsString(units)
|
||||
?: resourceHelper.gs(R.string.notavailable)
|
||||
binding.infoLayout.bg.setTextColor(overviewData.lastBgColor)
|
||||
binding.infoLayout.arrow.setImageResource(trendCalculator.getTrendArrow(overviewData.lastBg).directionToIcon())
|
||||
binding.infoLayout.arrow.setColorFilter(overviewData.lastBgColor)
|
||||
|
||||
val glucoseStatus = glucoseStatusProvider.glucoseStatusData
|
||||
if (glucoseStatus != null) {
|
||||
binding.infoLayout.deltaLarge.text = Profile.toSignedUnitsString(glucoseStatus.delta, glucoseStatus.delta * Constants.MGDL_TO_MMOLL, units)
|
||||
binding.infoLayout.deltaLarge.setTextColor(overviewData.lastBgColor)
|
||||
binding.infoLayout.delta.text = Profile.toSignedUnitsString(glucoseStatus.delta, glucoseStatus.delta * 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)
|
||||
} else {
|
||||
hoursToFetch = rangeToDisplay
|
||||
toTime = calendar.timeInMillis + 100000 // little bit more to avoid wrong rounding - GraphView specific
|
||||
fromTime = toTime - T.hours(hoursToFetch.toLong()).msecs()
|
||||
endTime = toTime
|
||||
binding.infoLayout.deltaLarge.text = ""
|
||||
binding.infoLayout.delta.text = "Δ " + resourceHelper.gs(R.string.notavailable)
|
||||
binding.infoLayout.avgDelta.text = ""
|
||||
binding.infoLayout.longAvgDelta.text = ""
|
||||
}
|
||||
val now = System.currentTimeMillis()
|
||||
|
||||
// ------------------ 1st graph
|
||||
// strike through if BG is old
|
||||
binding.infoLayout.bg.paintFlags =
|
||||
if (!overviewData.isActualBg) binding.infoLayout.bg.paintFlags or Paint.STRIKE_THRU_TEXT_FLAG
|
||||
else binding.infoLayout.bg.paintFlags and Paint.STRIKE_THRU_TEXT_FLAG.inv()
|
||||
binding.infoLayout.timeAgo.text = dateUtil.minAgo(resourceHelper, overviewData.lastBg?.timestamp)
|
||||
binding.infoLayout.timeAgoShort.text = "(" + dateUtil.minAgoShort(overviewData.lastBg?.timestamp) + ")"
|
||||
}
|
||||
|
||||
// **** In range Area ****
|
||||
graphData.addInRangeArea(fromTime, endTime, lowLine, highLine)
|
||||
OverviewData.Property.PROFILE -> {
|
||||
binding.loopPumpStatusLayout.activeProfile.text = overviewData.profileNameWithRemainingTime
|
||||
?: ""
|
||||
binding.loopPumpStatusLayout.activeProfile.setBackgroundColor(overviewData.profileBackgroundColor)
|
||||
binding.loopPumpStatusLayout.activeProfile.setTextColor(overviewData.profileTextColor)
|
||||
}
|
||||
|
||||
// **** BG ****
|
||||
if (predictionsAvailable && menuChartSettings[0][OverviewMenus.CharType.PRE.ordinal])
|
||||
graphData.addBgReadings(fromTime, toTime, highLine, apsResult?.predictions?.map { bg-> GlucoseValueDataPoint(bg, defaultValueHelper, profileFunction, resourceHelper) }?.toMutableList())
|
||||
else graphData.addBgReadings(fromTime, toTime, highLine, null)
|
||||
if (buildHelper.isDev()) graphData.addBucketedData(fromTime, toTime)
|
||||
OverviewData.Property.TEMPORARY_BASAL -> {
|
||||
binding.infoLayout.baseBasal.text = overviewData.temporaryBasalText
|
||||
binding.infoLayout.baseBasal.setTextColor(overviewData.temporaryBasalColor)
|
||||
binding.infoLayout.baseBasalIcon.setImageResource(overviewData.temporaryBasalIcon)
|
||||
binding.infoLayout.basalLayout.setOnClickListener {
|
||||
activity?.let { OKDialog.show(it, resourceHelper.gs(R.string.basal), overviewData.temporaryBasalDialogText) }
|
||||
}
|
||||
}
|
||||
|
||||
// Treatments
|
||||
graphData.addTreatments(fromTime, endTime)
|
||||
OverviewData.Property.EXTENDED_BOLUS -> {
|
||||
binding.infoLayout.extendedBolus.text = overviewData.extendedBolusText
|
||||
binding.infoLayout.extendedBolus.setOnClickListener {
|
||||
activity?.let { OKDialog.show(it, resourceHelper.gs(R.string.extended_bolus), overviewData.extendedBolusDialogText) }
|
||||
}
|
||||
binding.infoLayout.extendedLayout.visibility = (overviewData.extendedBolus != null && !pump.isFakingTempsByExtendedBoluses).toVisibility()
|
||||
|
||||
// set manual x bounds to have nice steps
|
||||
graphData.setNumVerticalLabels()
|
||||
graphData.formatAxis(fromTime, endTime)
|
||||
}
|
||||
|
||||
OverviewData.Property.TIME -> {
|
||||
binding.infoLayout.time.text = dateUtil.timeString(dateUtil.now())
|
||||
// Status lights
|
||||
binding.statusLightsLayout.statusLights.visibility = (sp.getBoolean(R.string.key_show_statuslights, true) || config.NSCLIENT).toVisibility()
|
||||
statusLightHandler.updateStatusLights(binding.statusLightsLayout.cannulaAge, binding.statusLightsLayout.insulinAge, binding.statusLightsLayout.reservoirLevel, binding.statusLightsLayout.sensorAge, null, binding.statusLightsLayout.pbAge, binding.statusLightsLayout.batteryLevel)
|
||||
processButtonsVisibility()
|
||||
processAps()
|
||||
}
|
||||
|
||||
if (menuChartSettings[0][OverviewMenus.CharType.ACT.ordinal])
|
||||
graphData.addActivity(fromTime, endTime, false, 0.8)
|
||||
OverviewData.Property.IOB_COB -> {
|
||||
binding.infoLayout.iob.text = overviewData.iobText
|
||||
binding.infoLayout.iobLayout.setOnClickListener {
|
||||
activity?.let { OKDialog.show(it, resourceHelper.gs(R.string.iob), overviewData.iobDialogText) }
|
||||
}
|
||||
// cob
|
||||
var cobText: String = resourceHelper.gs(R.string.value_unavailable_short)
|
||||
overviewData.cobInfo?.let { cobInfo ->
|
||||
if (cobInfo.displayCob != null) {
|
||||
cobText = resourceHelper.gs(R.string.format_carbs, cobInfo.displayCob!!.toInt())
|
||||
if (cobInfo.futureCarbs > 0) cobText += "(" + DecimalFormatter.to0Decimal(cobInfo.futureCarbs) + ")"
|
||||
}
|
||||
}
|
||||
binding.infoLayout.cob.text = cobText
|
||||
|
||||
// add basal data
|
||||
if (pump.pumpDescription.isTempBasalCapable && menuChartSettings[0][OverviewMenus.CharType.BAS.ordinal])
|
||||
graphData.addBasals(fromTime, now, lowLine / graphData.maxY / 1.2)
|
||||
|
||||
// add target line
|
||||
graphData.addTargetLine(fromTime, toTime, profile, loopPlugin.lastRun)
|
||||
|
||||
// **** NOW line ****
|
||||
graphData.addNowLine(now)
|
||||
|
||||
// ------------------ 2nd graph
|
||||
synchronized(graphLock) {
|
||||
for (g in 0 until min(secondaryGraphs.size, menuChartSettings.size + 1)) {
|
||||
val secondGraphData = GraphData(injector, secondaryGraphs[g], iobCobCalculator)
|
||||
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 constraintsProcessed = loopPlugin.lastRun?.constraintsProcessed
|
||||
val lastRun = loopPlugin.lastRun
|
||||
if (config.APS && constraintsProcessed != null && lastRun != null) {
|
||||
if (constraintsProcessed.carbsReq > 0) {
|
||||
//only display carbsreq when carbs have not been entered recently
|
||||
if (overviewData.lastCarbsTime < lastRun.lastAPSRun) {
|
||||
cobText = cobText + " | " + constraintsProcessed.carbsReq + " " + resourceHelper.gs(R.string.required)
|
||||
}
|
||||
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, now, useABSForScale, 1.0)
|
||||
if (menuChartSettings[g + 1][OverviewMenus.CharType.IOB.ordinal]) secondGraphData.addIob(fromTime, now, useIobForScale, 1.0, menuChartSettings[g + 1][OverviewMenus.CharType.PRE.ordinal], alignIobScale)
|
||||
if (menuChartSettings[g + 1][OverviewMenus.CharType.COB.ordinal]) secondGraphData.addCob(fromTime, now, useCobForScale, if (useCobForScale) 1.0 else 0.5)
|
||||
if (menuChartSettings[g + 1][OverviewMenus.CharType.DEV.ordinal]) secondGraphData.addDeviations(fromTime, now, useDevForScale, 1.0, alignDevBgiScale)
|
||||
if (menuChartSettings[g + 1][OverviewMenus.CharType.BGI.ordinal]) secondGraphData.addMinusBGI(fromTime, endTime, useBGIForScale, if (alignDevBgiScale) 1.0 else 0.8, alignDevBgiScale)
|
||||
if (menuChartSettings[g + 1][OverviewMenus.CharType.SEN.ordinal]) secondGraphData.addRatio(fromTime, now, useRatioForScale, if (useRatioForScale) 1.0 else 0.8)
|
||||
if (menuChartSettings[g + 1][OverviewMenus.CharType.DEVSLOPE.ordinal] && buildHelper.isDev()) secondGraphData.addDeviationSlope(fromTime, now, useDSForScale, 1.0)
|
||||
|
||||
// set manual x bounds to have nice steps
|
||||
secondGraphData.formatAxis(fromTime, endTime)
|
||||
secondGraphData.addNowLine(now)
|
||||
secondaryGraphsData.add(secondGraphData)
|
||||
if (carbAnimation?.isRunning == false)
|
||||
carbAnimation?.start()
|
||||
} else {
|
||||
carbAnimation?.stop()
|
||||
carbAnimation?.selectDrawable(0)
|
||||
}
|
||||
}
|
||||
}
|
||||
// finally enforce drawing of graphs in UI thread
|
||||
graphData.performUpdate()
|
||||
synchronized(graphLock) {
|
||||
|
||||
OverviewData.Property.TEMPORARY_TARGET -> {
|
||||
// temp target
|
||||
if (overviewData.temporaryTarget?.isInProgress(dateUtil) == false) overviewData.temporaryTarget = null
|
||||
val tempTarget = overviewData.temporaryTarget
|
||||
if (tempTarget != null) {
|
||||
binding.loopPumpStatusLayout.tempTarget.setTextColor(resourceHelper.gc(R.color.ribbonTextWarning))
|
||||
binding.loopPumpStatusLayout.tempTarget.setBackgroundColor(resourceHelper.gc(R.color.ribbonWarning))
|
||||
binding.loopPumpStatusLayout.tempTarget.text = Profile.toTargetRangeString(tempTarget.lowTarget, tempTarget.highTarget, GlucoseUnit.MGDL, units) + " " + dateUtil.untilString(tempTarget.end, resourceHelper)
|
||||
} else {
|
||||
// If the target is not the same as set in the profile then oref has overridden it
|
||||
overviewData.profile?.let { profile ->
|
||||
val targetUsed = loopPlugin.lastRun?.constraintsProcessed?.targetBG ?: 0.0
|
||||
|
||||
if (targetUsed != 0.0 && abs(profile.getTargetMgdl() - targetUsed) > 0.01) {
|
||||
aapsLogger.debug("Adjusted target. Profile: ${profile.getTargetMgdl()} APS: $targetUsed")
|
||||
binding.loopPumpStatusLayout.tempTarget.text = Profile.toTargetRangeString(targetUsed, targetUsed, GlucoseUnit.MGDL, units)
|
||||
binding.loopPumpStatusLayout.tempTarget.setTextColor(resourceHelper.gc(R.color.ribbonTextWarning))
|
||||
binding.loopPumpStatusLayout.tempTarget.setBackgroundColor(resourceHelper.gc(R.color.tempTargetBackground))
|
||||
} else {
|
||||
binding.loopPumpStatusLayout.tempTarget.setTextColor(resourceHelper.gc(R.color.ribbonTextDefault))
|
||||
binding.loopPumpStatusLayout.tempTarget.setBackgroundColor(resourceHelper.gc(R.color.ribbonDefault))
|
||||
binding.loopPumpStatusLayout.tempTarget.text = Profile.toTargetRangeString(profile.getTargetLowMgdl(), profile.getTargetHighMgdl(), GlucoseUnit.MGDL, units)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
OverviewData.Property.GRAPH -> {
|
||||
val graphData = GraphData(injector, binding.graphsLayout.bgGraph, overviewData)
|
||||
val menuChartSettings = overviewMenus.setting
|
||||
graphData.addInRangeArea(overviewData.fromTime, overviewData.endTime, defaultValueHelper.determineLowLine(), defaultValueHelper.determineHighLine())
|
||||
graphData.addBgReadings(menuChartSettings[0][OverviewMenus.CharType.PRE.ordinal])
|
||||
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, if(useDSForScale) 1.0 else 0.8, useRatioForScale)
|
||||
|
||||
// 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 = (
|
||||
|
@ -940,6 +800,23 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
|
|||
secondaryGraphsData[g].performUpdate()
|
||||
}
|
||||
}
|
||||
|
||||
OverviewData.Property.CALC_PROGRESS -> {
|
||||
binding.graphsLayout.iobCalculationProgress.text = overviewData.calcProgress
|
||||
}
|
||||
|
||||
OverviewData.Property.SENSITIVITY -> {
|
||||
if (sp.getBoolean(R.string.key_openapsama_useautosens, false) && constraintChecker.isAutosensModeEnabled().value()) {
|
||||
binding.infoLayout.sensitivityIcon.setImageResource(R.drawable.ic_swap_vert_black_48dp_green)
|
||||
} else {
|
||||
binding.infoLayout.sensitivityIcon.setImageResource(R.drawable.ic_x_swap_vert)
|
||||
}
|
||||
|
||||
binding.infoLayout.sensitivity.text =
|
||||
overviewData.lastAutosensData?.let { autosensData ->
|
||||
String.format(Locale.ENGLISH, "%.0f%%", autosensData.autosensResult.ratio * 100)
|
||||
} ?: ""
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,18 +34,19 @@ class OverviewMenus @Inject constructor(
|
|||
|
||||
enum class CharType(@StringRes val nameId: Int, @ColorRes val colorId: Int, val primary: Boolean, val secondary: Boolean, @StringRes val shortnameId: Int) {
|
||||
PRE(R.string.overview_show_predictions, R.color.prediction, primary = true, secondary = false, shortnameId = R.string.prediction_shortname),
|
||||
BAS(R.string.overview_show_basals, R.color.basal, primary = true, secondary = false,shortnameId = R.string.basal_shortname),
|
||||
ABS(R.string.overview_show_absinsulin, R.color.iob, primary = false, secondary = true,shortnameId = R.string.abs_insulin_shortname),
|
||||
IOB(R.string.overview_show_iob, R.color.iob, primary = false, secondary = true,shortnameId = R.string.iob),
|
||||
COB(R.string.overview_show_cob, R.color.cob, primary = false, secondary = true,shortnameId = R.string.cob),
|
||||
DEV(R.string.overview_show_deviations, R.color.bgi, primary = false, secondary = true,shortnameId = R.string.deviation_shortname),
|
||||
BGI(R.string.overview_show_bgi, R.color.bgi, primary = false, secondary = true,shortnameId = R.string.bgi_shortname),
|
||||
SEN(R.string.overview_show_sensitivity, R.color.ratio, primary = false, secondary = true,shortnameId = R.string.sensitivity_shortname),
|
||||
ACT(R.string.overview_show_activity, R.color.activity, primary = true, secondary = false,shortnameId = R.string.activity_shortname),
|
||||
DEVSLOPE(R.string.overview_show_deviationslope, R.color.devslopepos, primary = false, secondary = true,shortnameId = R.string.devslope_shortname)
|
||||
BAS(R.string.overview_show_basals, R.color.basal, primary = true, secondary = false, shortnameId = R.string.basal_shortname),
|
||||
ABS(R.string.overview_show_absinsulin, R.color.iob, primary = false, secondary = true, shortnameId = R.string.abs_insulin_shortname),
|
||||
IOB(R.string.overview_show_iob, R.color.iob, primary = false, secondary = true, shortnameId = R.string.iob),
|
||||
COB(R.string.overview_show_cob, R.color.cob, primary = false, secondary = true, shortnameId = R.string.cob),
|
||||
DEV(R.string.overview_show_deviations, R.color.bgi, primary = false, secondary = true, shortnameId = R.string.deviation_shortname),
|
||||
BGI(R.string.overview_show_bgi, R.color.bgi, primary = false, secondary = true, shortnameId = R.string.bgi_shortname),
|
||||
SEN(R.string.overview_show_sensitivity, R.color.ratio, primary = false, secondary = true, shortnameId = R.string.sensitivity_shortname),
|
||||
ACT(R.string.overview_show_activity, R.color.activity, primary = true, secondary = false, shortnameId = R.string.activity_shortname),
|
||||
DEVSLOPE(R.string.overview_show_deviationslope, R.color.devslopepos, primary = false, secondary = true, shortnameId = R.string.devslope_shortname)
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
const val MAX_GRAPHS = 5 // including main
|
||||
}
|
||||
|
||||
|
@ -58,12 +59,10 @@ class OverviewMenus @Inject constructor(
|
|||
return r.toString()
|
||||
}
|
||||
|
||||
|
||||
|
||||
private var _setting: MutableList<Array<Boolean>> = ArrayList()
|
||||
|
||||
val setting: List<Array<Boolean>>
|
||||
get() = _setting.toMutableList() // implicitly does a list copy
|
||||
get() = _setting.toMutableList() // implicitly does a list copy
|
||||
|
||||
private fun storeGraphConfig() {
|
||||
val sts = Gson().toJson(_setting)
|
||||
|
@ -71,7 +70,7 @@ class OverviewMenus @Inject constructor(
|
|||
aapsLogger.debug(sts)
|
||||
}
|
||||
|
||||
private fun loadGraphConfig() {
|
||||
fun loadGraphConfig() {
|
||||
val sts = sp.getString(R.string.key_graphconfig, "")
|
||||
if (sts.isNotEmpty()) {
|
||||
_setting = Gson().fromJson(sts, Array<Array<Boolean>>::class.java).toMutableList()
|
||||
|
@ -88,7 +87,6 @@ class OverviewMenus @Inject constructor(
|
|||
}
|
||||
|
||||
fun setupChartMenu(chartButton: ImageButton) {
|
||||
loadGraphConfig()
|
||||
val settingsCopy = setting
|
||||
val numOfGraphs = settingsCopy.size // 1 main + x secondary
|
||||
|
||||
|
@ -100,6 +98,8 @@ class OverviewMenus @Inject constructor(
|
|||
}
|
||||
val popup = PopupMenu(v.context, v)
|
||||
|
||||
val used = arrayListOf<Int>()
|
||||
|
||||
for (g in 0 until numOfGraphs) {
|
||||
if (g != 0 && g < numOfGraphs) {
|
||||
val dividerItem = popup.menu.add(Menu.NONE, g, Menu.NONE, "------- ${resourceHelper.gs(R.string.graph_menu_divider_header)} $g -------")
|
||||
|
@ -112,6 +112,10 @@ class OverviewMenus @Inject constructor(
|
|||
var insert = true
|
||||
if (m == CharType.PRE) insert = predictionsAvailable
|
||||
if (m == CharType.DEVSLOPE) insert = buildHelper.isDev()
|
||||
if (used.contains(m.ordinal)) insert = false
|
||||
for (g2 in g + 1 until numOfGraphs) {
|
||||
if (settingsCopy[g2][m.ordinal]) insert = false
|
||||
}
|
||||
if (insert) {
|
||||
val item = popup.menu.add(Menu.NONE, m.ordinal + 100 * (g + 1), Menu.NONE, resourceHelper.gs(m.nameId))
|
||||
val title = item.title
|
||||
|
@ -120,6 +124,7 @@ class OverviewMenus @Inject constructor(
|
|||
item.title = s
|
||||
item.isCheckable = true
|
||||
item.isChecked = settingsCopy[g][m.ordinal]
|
||||
if (settingsCopy[g][m.ordinal]) used.add(m.ordinal)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -131,16 +136,20 @@ class OverviewMenus @Inject constructor(
|
|||
|
||||
popup.setOnMenuItemClickListener {
|
||||
// id < 100 graph header - divider 1, 2, 3 .....
|
||||
if (it.itemId == numOfGraphs) {
|
||||
// add new empty
|
||||
_setting.add(Array(CharType.values().size) { false })
|
||||
} else if (it.itemId < 100) {
|
||||
// remove graph
|
||||
_setting.removeAt(it.itemId)
|
||||
} else {
|
||||
val graphNumber = it.itemId / 100 - 1
|
||||
val item = it.itemId % 100
|
||||
_setting[graphNumber][item] = !it.isChecked
|
||||
when {
|
||||
it.itemId == numOfGraphs -> {
|
||||
// add new empty
|
||||
_setting.add(Array(CharType.values().size) { false })
|
||||
}
|
||||
it.itemId < 100 -> {
|
||||
// remove graph
|
||||
_setting.removeAt(it.itemId)
|
||||
}
|
||||
else -> {
|
||||
val graphNumber = it.itemId / 100 - 1
|
||||
val item = it.itemId % 100
|
||||
_setting[graphNumber][item] = !it.isChecked
|
||||
}
|
||||
}
|
||||
storeGraphConfig()
|
||||
setupChartMenu(chartButton)
|
||||
|
@ -153,4 +162,11 @@ class OverviewMenus @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
fun isEnabledIn(type: CharType): Int {
|
||||
val settingsCopy = setting
|
||||
val numOfGraphs = settingsCopy.size // 1 main + x secondary
|
||||
for (g in 0 until numOfGraphs) if (settingsCopy[g][type.ordinal]) return g
|
||||
return -1
|
||||
}
|
||||
|
||||
}
|
|
@ -3,20 +3,27 @@ package info.nightscout.androidaps.plugins.general.overview
|
|||
import androidx.preference.PreferenceFragmentCompat
|
||||
import androidx.preference.SwitchPreference
|
||||
import dagger.android.HasAndroidInjector
|
||||
import info.nightscout.androidaps.interfaces.Config
|
||||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.events.EventRefreshOverview
|
||||
import info.nightscout.androidaps.database.AppRepository
|
||||
import info.nightscout.androidaps.database.ValueWrapper
|
||||
import info.nightscout.androidaps.events.*
|
||||
import info.nightscout.androidaps.extensions.*
|
||||
import info.nightscout.androidaps.interfaces.Overview
|
||||
import info.nightscout.androidaps.interfaces.PluginBase
|
||||
import info.nightscout.androidaps.interfaces.PluginDescription
|
||||
import info.nightscout.androidaps.interfaces.PluginType
|
||||
import info.nightscout.androidaps.interfaces.*
|
||||
import info.nightscout.androidaps.logging.AAPSLogger
|
||||
import info.nightscout.androidaps.logging.LTag
|
||||
import info.nightscout.androidaps.plugins.aps.events.EventLoopInvoked
|
||||
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
||||
import info.nightscout.androidaps.plugins.general.overview.events.EventDismissNotification
|
||||
import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification
|
||||
import info.nightscout.androidaps.plugins.general.overview.events.EventUpdateOverview
|
||||
import info.nightscout.androidaps.plugins.general.overview.graphExtensions.Scale
|
||||
import info.nightscout.androidaps.plugins.general.overview.graphExtensions.ScaledDataPoint
|
||||
import info.nightscout.androidaps.plugins.general.overview.notifications.NotificationStore
|
||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventBucketedDataCreated
|
||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventIobCalculationProgress
|
||||
import info.nightscout.androidaps.utils.DateUtil
|
||||
import info.nightscout.androidaps.utils.FabricPrivacy
|
||||
import info.nightscout.androidaps.utils.Translator
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
||||
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
||||
|
@ -28,47 +35,121 @@ import javax.inject.Singleton
|
|||
|
||||
@Singleton
|
||||
class OverviewPlugin @Inject constructor(
|
||||
injector: HasAndroidInjector,
|
||||
private val notificationStore: NotificationStore,
|
||||
private val fabricPrivacy: FabricPrivacy,
|
||||
private val rxBus: RxBusWrapper,
|
||||
private val sp: SP,
|
||||
aapsLogger: AAPSLogger,
|
||||
private val aapsSchedulers: AapsSchedulers,
|
||||
resourceHelper: ResourceHelper,
|
||||
private val config: Config
|
||||
injector: HasAndroidInjector,
|
||||
private val notificationStore: NotificationStore,
|
||||
private val fabricPrivacy: FabricPrivacy,
|
||||
private val rxBus: RxBusWrapper,
|
||||
private val sp: SP,
|
||||
aapsLogger: AAPSLogger,
|
||||
private val aapsSchedulers: AapsSchedulers,
|
||||
resourceHelper: ResourceHelper,
|
||||
private val config: Config,
|
||||
private val dateUtil: DateUtil,
|
||||
private val translator: Translator,
|
||||
// private val profiler: Profiler,
|
||||
private val profileFunction: ProfileFunction,
|
||||
private val iobCobCalculator: IobCobCalculator,
|
||||
private val repository: AppRepository,
|
||||
private val overviewData: OverviewData,
|
||||
private val overviewMenus: OverviewMenus
|
||||
) : PluginBase(PluginDescription()
|
||||
.mainType(PluginType.GENERAL)
|
||||
.fragmentClass(OverviewFragment::class.qualifiedName)
|
||||
.alwaysVisible(true)
|
||||
.alwaysEnabled(true)
|
||||
.pluginIcon(R.drawable.ic_home)
|
||||
.pluginName(R.string.overview)
|
||||
.shortName(R.string.overview_shortname)
|
||||
.preferencesId(R.xml.pref_overview)
|
||||
.description(R.string.description_overview),
|
||||
aapsLogger, resourceHelper, injector
|
||||
.mainType(PluginType.GENERAL)
|
||||
.fragmentClass(OverviewFragment::class.qualifiedName)
|
||||
.alwaysVisible(true)
|
||||
.alwaysEnabled(true)
|
||||
.pluginIcon(R.drawable.ic_home)
|
||||
.pluginName(R.string.overview)
|
||||
.shortName(R.string.overview_shortname)
|
||||
.preferencesId(R.xml.pref_overview)
|
||||
.description(R.string.description_overview),
|
||||
aapsLogger, resourceHelper, injector
|
||||
), Overview {
|
||||
|
||||
private var disposable: CompositeDisposable = CompositeDisposable()
|
||||
|
||||
override val overviewBus = RxBusWrapper(aapsSchedulers)
|
||||
|
||||
class DeviationDataPoint(x: Double, y: Double, var color: Int, scale: Scale) : ScaledDataPoint(x, y, scale)
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
overviewMenus.loadGraphConfig()
|
||||
overviewData.initRange()
|
||||
|
||||
notificationStore.createNotificationChannel()
|
||||
disposable += rxBus
|
||||
.toObservable(EventNewNotification::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.subscribe({ n ->
|
||||
if (notificationStore.add(n.notification))
|
||||
rxBus.send(EventRefreshOverview("EventNewNotification"))
|
||||
}, fabricPrivacy::logException)
|
||||
.toObservable(EventNewNotification::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.subscribe({ n ->
|
||||
if (notificationStore.add(n.notification))
|
||||
rxBus.send(EventRefreshOverview("EventNewNotification"))
|
||||
}, fabricPrivacy::logException)
|
||||
disposable += rxBus
|
||||
.toObservable(EventDismissNotification::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.subscribe({ n ->
|
||||
if (notificationStore.remove(n.id))
|
||||
rxBus.send(EventRefreshOverview("EventDismissNotification"))
|
||||
}, fabricPrivacy::logException)
|
||||
.toObservable(EventDismissNotification::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.subscribe({ n ->
|
||||
if (notificationStore.remove(n.id))
|
||||
rxBus.send(EventRefreshOverview("EventDismissNotification"))
|
||||
}, fabricPrivacy::logException)
|
||||
disposable += rxBus
|
||||
.toObservable(EventIobCalculationProgress::class.java)
|
||||
.observeOn(aapsSchedulers.main)
|
||||
.subscribe({ overviewData.calcProgress = it.progress; overviewBus.send(EventUpdateOverview("EventIobCalculationProgress", OverviewData.Property.CALC_PROGRESS)) }, fabricPrivacy::logException)
|
||||
disposable += rxBus
|
||||
.toObservable(EventTempBasalChange::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.subscribe({ loadTemporaryBasal("EventTempBasalChange") }, fabricPrivacy::logException)
|
||||
disposable += rxBus
|
||||
.toObservable(EventExtendedBolusChange::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.subscribe({ loadExtendedBolus("EventExtendedBolusChange") }, fabricPrivacy::logException)
|
||||
disposable += rxBus
|
||||
.toObservable(EventNewBG::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.subscribe({ loadBg("EventNewBG") }, fabricPrivacy::logException)
|
||||
disposable += rxBus
|
||||
.toObservable(EventTempTargetChange::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.subscribe({ loadTemporaryTarget("EventTempTargetChange") }, fabricPrivacy::logException)
|
||||
disposable += rxBus
|
||||
.toObservable(EventTreatmentChange::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.subscribe({
|
||||
loadIobCobResults("EventTreatmentChange")
|
||||
overviewData.prepareTreatmentsData("EventTreatmentChange")
|
||||
overviewBus.send(EventUpdateOverview("EventTreatmentChange", OverviewData.Property.GRAPH))
|
||||
}, fabricPrivacy::logException)
|
||||
disposable += rxBus
|
||||
.toObservable(EventTherapyEventChange::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.subscribe({
|
||||
overviewData.prepareTreatmentsData("EventTherapyEventChange")
|
||||
overviewBus.send(EventUpdateOverview("EventTherapyEventChange", OverviewData.Property.GRAPH))
|
||||
}, fabricPrivacy::logException)
|
||||
disposable += rxBus
|
||||
.toObservable(EventBucketedDataCreated::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.subscribe({
|
||||
overviewData.prepareBucketedData("EventBucketedDataCreated")
|
||||
overviewData.prepareBgData("EventBucketedDataCreated")
|
||||
overviewBus.send(EventUpdateOverview("EventBucketedDataCreated", OverviewData.Property.GRAPH))
|
||||
}, fabricPrivacy::logException)
|
||||
disposable += rxBus
|
||||
.toObservable(EventLoopInvoked::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.subscribe({ overviewData.preparePredictions("EventLoopInvoked") }, fabricPrivacy::logException)
|
||||
disposable.add(rxBus
|
||||
.toObservable(EventNewBasalProfile::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.subscribe({ loadProfile("EventNewBasalProfile") }, fabricPrivacy::logException))
|
||||
disposable.add(rxBus
|
||||
.toObservable(EventAutosensCalculationFinished::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.subscribe({
|
||||
if (it.cause !is EventCustomCalculationFinished) refreshLoop("EventAutosensCalculationFinished")
|
||||
}, fabricPrivacy::logException))
|
||||
|
||||
Thread { loadAll("onResume") }.start()
|
||||
}
|
||||
|
||||
override fun onStop() {
|
||||
|
@ -91,55 +172,144 @@ class OverviewPlugin @Inject constructor(
|
|||
}
|
||||
|
||||
override fun configuration(): JSONObject =
|
||||
JSONObject()
|
||||
.putString(R.string.key_quickwizard, sp, resourceHelper)
|
||||
.putInt(R.string.key_eatingsoon_duration, sp, resourceHelper)
|
||||
.putDouble(R.string.key_eatingsoon_target, sp, resourceHelper)
|
||||
.putInt(R.string.key_activity_duration, sp, resourceHelper)
|
||||
.putDouble(R.string.key_activity_target, sp, resourceHelper)
|
||||
.putInt(R.string.key_hypo_duration, sp, resourceHelper)
|
||||
.putDouble(R.string.key_hypo_target, sp, resourceHelper)
|
||||
.putDouble(R.string.key_low_mark, sp, resourceHelper)
|
||||
.putDouble(R.string.key_high_mark, sp, resourceHelper)
|
||||
.putDouble(R.string.key_statuslights_cage_warning, sp, resourceHelper)
|
||||
.putDouble(R.string.key_statuslights_cage_critical, sp, resourceHelper)
|
||||
.putDouble(R.string.key_statuslights_iage_warning, sp, resourceHelper)
|
||||
.putDouble(R.string.key_statuslights_iage_critical, sp, resourceHelper)
|
||||
.putDouble(R.string.key_statuslights_sage_warning, sp, resourceHelper)
|
||||
.putDouble(R.string.key_statuslights_sage_critical, sp, resourceHelper)
|
||||
.putDouble(R.string.key_statuslights_sbat_warning, sp, resourceHelper)
|
||||
.putDouble(R.string.key_statuslights_sbat_critical, sp, resourceHelper)
|
||||
.putDouble(R.string.key_statuslights_bage_warning, sp, resourceHelper)
|
||||
.putDouble(R.string.key_statuslights_bage_critical, sp, resourceHelper)
|
||||
.putDouble(R.string.key_statuslights_res_warning, sp, resourceHelper)
|
||||
.putDouble(R.string.key_statuslights_res_critical, sp, resourceHelper)
|
||||
.putDouble(R.string.key_statuslights_bat_warning, sp, resourceHelper)
|
||||
.putDouble(R.string.key_statuslights_bat_critical, sp, resourceHelper)
|
||||
JSONObject()
|
||||
.putString(R.string.key_quickwizard, sp, resourceHelper)
|
||||
.putInt(R.string.key_eatingsoon_duration, sp, resourceHelper)
|
||||
.putDouble(R.string.key_eatingsoon_target, sp, resourceHelper)
|
||||
.putInt(R.string.key_activity_duration, sp, resourceHelper)
|
||||
.putDouble(R.string.key_activity_target, sp, resourceHelper)
|
||||
.putInt(R.string.key_hypo_duration, sp, resourceHelper)
|
||||
.putDouble(R.string.key_hypo_target, sp, resourceHelper)
|
||||
.putDouble(R.string.key_low_mark, sp, resourceHelper)
|
||||
.putDouble(R.string.key_high_mark, sp, resourceHelper)
|
||||
.putDouble(R.string.key_statuslights_cage_warning, sp, resourceHelper)
|
||||
.putDouble(R.string.key_statuslights_cage_critical, sp, resourceHelper)
|
||||
.putDouble(R.string.key_statuslights_iage_warning, sp, resourceHelper)
|
||||
.putDouble(R.string.key_statuslights_iage_critical, sp, resourceHelper)
|
||||
.putDouble(R.string.key_statuslights_sage_warning, sp, resourceHelper)
|
||||
.putDouble(R.string.key_statuslights_sage_critical, sp, resourceHelper)
|
||||
.putDouble(R.string.key_statuslights_sbat_warning, sp, resourceHelper)
|
||||
.putDouble(R.string.key_statuslights_sbat_critical, sp, resourceHelper)
|
||||
.putDouble(R.string.key_statuslights_bage_warning, sp, resourceHelper)
|
||||
.putDouble(R.string.key_statuslights_bage_critical, sp, resourceHelper)
|
||||
.putDouble(R.string.key_statuslights_res_warning, sp, resourceHelper)
|
||||
.putDouble(R.string.key_statuslights_res_critical, sp, resourceHelper)
|
||||
.putDouble(R.string.key_statuslights_bat_warning, sp, resourceHelper)
|
||||
.putDouble(R.string.key_statuslights_bat_critical, sp, resourceHelper)
|
||||
|
||||
override fun applyConfiguration(configuration: JSONObject) {
|
||||
configuration
|
||||
.storeString(R.string.key_quickwizard, sp, resourceHelper)
|
||||
.storeInt(R.string.key_eatingsoon_duration, sp, resourceHelper)
|
||||
.storeDouble(R.string.key_eatingsoon_target, sp, resourceHelper)
|
||||
.storeInt(R.string.key_activity_duration, sp, resourceHelper)
|
||||
.storeDouble(R.string.key_activity_target, sp, resourceHelper)
|
||||
.storeInt(R.string.key_hypo_duration, sp, resourceHelper)
|
||||
.storeDouble(R.string.key_hypo_target, sp, resourceHelper)
|
||||
.storeDouble(R.string.key_low_mark, sp, resourceHelper)
|
||||
.storeDouble(R.string.key_high_mark, sp, resourceHelper)
|
||||
.storeDouble(R.string.key_statuslights_cage_warning, sp, resourceHelper)
|
||||
.storeDouble(R.string.key_statuslights_cage_critical, sp, resourceHelper)
|
||||
.storeDouble(R.string.key_statuslights_iage_warning, sp, resourceHelper)
|
||||
.storeDouble(R.string.key_statuslights_iage_critical, sp, resourceHelper)
|
||||
.storeDouble(R.string.key_statuslights_sage_warning, sp, resourceHelper)
|
||||
.storeDouble(R.string.key_statuslights_sage_critical, sp, resourceHelper)
|
||||
.storeDouble(R.string.key_statuslights_sbat_warning, sp, resourceHelper)
|
||||
.storeDouble(R.string.key_statuslights_sbat_critical, sp, resourceHelper)
|
||||
.storeDouble(R.string.key_statuslights_bage_warning, sp, resourceHelper)
|
||||
.storeDouble(R.string.key_statuslights_bage_critical, sp, resourceHelper)
|
||||
.storeDouble(R.string.key_statuslights_res_warning, sp, resourceHelper)
|
||||
.storeDouble(R.string.key_statuslights_res_critical, sp, resourceHelper)
|
||||
.storeDouble(R.string.key_statuslights_bat_warning, sp, resourceHelper)
|
||||
.storeDouble(R.string.key_statuslights_bat_critical, sp, resourceHelper)
|
||||
.storeString(R.string.key_quickwizard, sp, resourceHelper)
|
||||
.storeInt(R.string.key_eatingsoon_duration, sp, resourceHelper)
|
||||
.storeDouble(R.string.key_eatingsoon_target, sp, resourceHelper)
|
||||
.storeInt(R.string.key_activity_duration, sp, resourceHelper)
|
||||
.storeDouble(R.string.key_activity_target, sp, resourceHelper)
|
||||
.storeInt(R.string.key_hypo_duration, sp, resourceHelper)
|
||||
.storeDouble(R.string.key_hypo_target, sp, resourceHelper)
|
||||
.storeDouble(R.string.key_low_mark, sp, resourceHelper)
|
||||
.storeDouble(R.string.key_high_mark, sp, resourceHelper)
|
||||
.storeDouble(R.string.key_statuslights_cage_warning, sp, resourceHelper)
|
||||
.storeDouble(R.string.key_statuslights_cage_critical, sp, resourceHelper)
|
||||
.storeDouble(R.string.key_statuslights_iage_warning, sp, resourceHelper)
|
||||
.storeDouble(R.string.key_statuslights_iage_critical, sp, resourceHelper)
|
||||
.storeDouble(R.string.key_statuslights_sage_warning, sp, resourceHelper)
|
||||
.storeDouble(R.string.key_statuslights_sage_critical, sp, resourceHelper)
|
||||
.storeDouble(R.string.key_statuslights_sbat_warning, sp, resourceHelper)
|
||||
.storeDouble(R.string.key_statuslights_sbat_critical, sp, resourceHelper)
|
||||
.storeDouble(R.string.key_statuslights_bage_warning, sp, resourceHelper)
|
||||
.storeDouble(R.string.key_statuslights_bage_critical, sp, resourceHelper)
|
||||
.storeDouble(R.string.key_statuslights_res_warning, sp, resourceHelper)
|
||||
.storeDouble(R.string.key_statuslights_res_critical, sp, resourceHelper)
|
||||
.storeDouble(R.string.key_statuslights_bat_warning, sp, resourceHelper)
|
||||
.storeDouble(R.string.key_statuslights_bat_critical, sp, resourceHelper)
|
||||
}
|
||||
|
||||
@Volatile
|
||||
var runningRefresh = false
|
||||
override fun refreshLoop(from: String) {
|
||||
if (runningRefresh) return
|
||||
runningRefresh = true
|
||||
loadIobCobResults(from)
|
||||
overviewBus.send(EventUpdateOverview(from, OverviewData.Property.BG))
|
||||
overviewBus.send(EventUpdateOverview(from, OverviewData.Property.TIME))
|
||||
overviewBus.send(EventUpdateOverview(from, OverviewData.Property.TEMPORARY_BASAL))
|
||||
overviewBus.send(EventUpdateOverview(from, OverviewData.Property.EXTENDED_BOLUS))
|
||||
overviewBus.send(EventUpdateOverview(from, OverviewData.Property.IOB_COB))
|
||||
overviewBus.send(EventUpdateOverview(from, OverviewData.Property.TEMPORARY_TARGET))
|
||||
overviewBus.send(EventUpdateOverview(from, OverviewData.Property.SENSITIVITY))
|
||||
loadAsData(from)
|
||||
overviewData.preparePredictions(from)
|
||||
overviewData.prepareBasalData(from)
|
||||
overviewData.prepareTemporaryTargetData(from)
|
||||
overviewData.prepareTreatmentsData(from)
|
||||
overviewData.prepareIobAutosensData(from)
|
||||
overviewBus.send(EventUpdateOverview(from, OverviewData.Property.GRAPH))
|
||||
aapsLogger.debug(LTag.UI, "refreshLoop finished")
|
||||
runningRefresh = false
|
||||
}
|
||||
|
||||
@Suppress("SameParameterValue")
|
||||
private fun loadAll(from: String) {
|
||||
loadBg(from)
|
||||
loadProfile(from)
|
||||
loadTemporaryBasal(from)
|
||||
loadExtendedBolus(from)
|
||||
loadTemporaryTarget(from)
|
||||
loadIobCobResults(from)
|
||||
loadAsData(from)
|
||||
overviewData.prepareBasalData(from)
|
||||
overviewData.prepareTemporaryTargetData(from)
|
||||
overviewData.prepareTreatmentsData(from)
|
||||
// prepareIobAutosensData(from)
|
||||
// preparePredictions(from)
|
||||
overviewBus.send(EventUpdateOverview(from, OverviewData.Property.GRAPH))
|
||||
aapsLogger.debug(LTag.UI, "loadAll finished")
|
||||
}
|
||||
|
||||
private fun loadProfile(from: String) {
|
||||
overviewData.profile = profileFunction.getProfile()
|
||||
overviewData.profileName = profileFunction.getProfileName()
|
||||
overviewData.profileNameWithRemainingTime = profileFunction.getProfileNameWithRemainingTime()
|
||||
overviewBus.send(EventUpdateOverview(from, OverviewData.Property.PROFILE))
|
||||
}
|
||||
|
||||
private fun loadTemporaryBasal(from: String) {
|
||||
overviewData.temporaryBasal = iobCobCalculator.getTempBasalIncludingConvertedExtended(dateUtil.now())
|
||||
overviewBus.send(EventUpdateOverview(from, OverviewData.Property.TEMPORARY_BASAL))
|
||||
}
|
||||
|
||||
private fun loadExtendedBolus(from: String) {
|
||||
overviewData.extendedBolus = iobCobCalculator.getExtendedBolus(dateUtil.now())
|
||||
overviewBus.send(EventUpdateOverview(from, OverviewData.Property.EXTENDED_BOLUS))
|
||||
}
|
||||
|
||||
private fun loadTemporaryTarget(from: String) {
|
||||
val tempTarget = repository.getTemporaryTargetActiveAt(dateUtil.now()).blockingGet()
|
||||
if (tempTarget is ValueWrapper.Existing) overviewData.temporaryTarget = tempTarget.value
|
||||
else overviewData.temporaryTarget = null
|
||||
overviewBus.send(EventUpdateOverview(from, OverviewData.Property.TEMPORARY_TARGET))
|
||||
}
|
||||
|
||||
private fun loadAsData(from: String) {
|
||||
overviewData.lastAutosensData = iobCobCalculator.ads.getLastAutosensData("Overview", aapsLogger, dateUtil)
|
||||
overviewBus.send(EventUpdateOverview(from, OverviewData.Property.SENSITIVITY))
|
||||
}
|
||||
|
||||
private fun loadBg(from: String) {
|
||||
val gvWrapped = repository.getLastGlucoseValueWrapped().blockingGet()
|
||||
if (gvWrapped is ValueWrapper.Existing) overviewData.lastBg = gvWrapped.value
|
||||
else overviewData.lastBg = null
|
||||
overviewBus.send(EventUpdateOverview(from, OverviewData.Property.BG))
|
||||
}
|
||||
|
||||
private fun loadIobCobResults(from: String) {
|
||||
overviewData.bolusIob = iobCobCalculator.calculateIobFromBolus().round()
|
||||
overviewData.basalIob = iobCobCalculator.calculateIobFromTempBasalsIncludingConvertedExtended().round()
|
||||
overviewData.cobInfo = iobCobCalculator.getCobInfo(false, "Overview COB")
|
||||
val lastCarbs = repository.getLastCarbsRecordWrapped().blockingGet()
|
||||
overviewData.lastCarbsTime = if (lastCarbs is ValueWrapper.Existing) lastCarbs.value.timestamp else 0L
|
||||
|
||||
overviewBus.send(EventUpdateOverview(from, OverviewData.Property.IOB_COB))
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
package info.nightscout.androidaps.plugins.general.overview.events
|
||||
|
||||
import info.nightscout.androidaps.events.Event
|
||||
import info.nightscout.androidaps.plugins.general.overview.OverviewData
|
||||
|
||||
class EventUpdateOverview(val from: String, val what: OverviewData.Property) : Event()
|
|
@ -4,52 +4,39 @@ import android.graphics.Color
|
|||
import android.graphics.DashPathEffect
|
||||
import android.graphics.Paint
|
||||
import com.jjoe64.graphview.GraphView
|
||||
import com.jjoe64.graphview.series.BarGraphSeries
|
||||
import com.jjoe64.graphview.series.DataPoint
|
||||
import com.jjoe64.graphview.series.LineGraphSeries
|
||||
import com.jjoe64.graphview.series.Series
|
||||
import dagger.android.HasAndroidInjector
|
||||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.data.IobTotal
|
||||
import info.nightscout.androidaps.database.AppRepository
|
||||
import info.nightscout.androidaps.database.ValueWrapper
|
||||
import info.nightscout.androidaps.database.entities.Bolus
|
||||
import info.nightscout.androidaps.database.entities.GlucoseValue
|
||||
import info.nightscout.androidaps.extensions.target
|
||||
import info.nightscout.androidaps.interfaces.*
|
||||
import info.nightscout.androidaps.interfaces.GlucoseUnit
|
||||
import info.nightscout.androidaps.interfaces.ProfileFunction
|
||||
import info.nightscout.androidaps.logging.AAPSLogger
|
||||
import info.nightscout.androidaps.logging.LTag
|
||||
import info.nightscout.androidaps.plugins.aps.openAPSSMB.SMBDefaults
|
||||
import info.nightscout.androidaps.plugins.general.overview.graphExtensions.*
|
||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensResult
|
||||
import info.nightscout.androidaps.utils.*
|
||||
import info.nightscout.androidaps.plugins.general.overview.OverviewData
|
||||
import info.nightscout.androidaps.plugins.general.overview.graphExtensions.AreaGraphSeries
|
||||
import info.nightscout.androidaps.plugins.general.overview.graphExtensions.DoubleDataPoint
|
||||
import info.nightscout.androidaps.plugins.general.overview.graphExtensions.TimeAsXAxisLabelFormatter
|
||||
import info.nightscout.androidaps.utils.DefaultValueHelper
|
||||
import info.nightscout.androidaps.utils.Round
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||
import java.util.*
|
||||
import javax.inject.Inject
|
||||
import kotlin.math.abs
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
|
||||
class GraphData(
|
||||
injector: HasAndroidInjector,
|
||||
private val graph: GraphView,
|
||||
private val iobCobCalculator: IobCobCalculator
|
||||
private val overviewData: OverviewData
|
||||
) {
|
||||
|
||||
// IobCobCalculatorPlugin Cannot be injected: HistoryBrowser
|
||||
@Inject lateinit var aapsLogger: AAPSLogger
|
||||
@Inject lateinit var profileFunction: ProfileFunction
|
||||
@Inject lateinit var resourceHelper: ResourceHelper
|
||||
@Inject lateinit var activePlugin: ActivePlugin
|
||||
@Inject lateinit var databaseHelper: DatabaseHelperInterface
|
||||
@Inject lateinit var repository: AppRepository
|
||||
@Inject lateinit var dateUtil: DateUtil
|
||||
@Inject lateinit var defaultValueHelper: DefaultValueHelper
|
||||
@Inject lateinit var translator: Translator
|
||||
|
||||
var maxY = Double.MIN_VALUE
|
||||
private var maxY = Double.MIN_VALUE
|
||||
private var minY = Double.MAX_VALUE
|
||||
private var bgReadingsArray: List<GlucoseValue>? = null
|
||||
private val units: GlucoseUnit
|
||||
private val series: MutableList<Series<*>> = ArrayList()
|
||||
|
||||
|
@ -58,587 +45,142 @@ class GraphData(
|
|||
units = profileFunction.getUnits()
|
||||
}
|
||||
|
||||
fun addBucketedData(fromTime: Long, toTime: Long) {
|
||||
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 < fromTime || inMemoryGlucoseValue.timestamp > toTime) continue
|
||||
bucketedListArray.add(InMemoryGlucoseValueDataPoint(inMemoryGlucoseValue, profileFunction, resourceHelper))
|
||||
}
|
||||
addSeries(PointsWithLabelGraphSeries(Array(bucketedListArray.size) { i -> bucketedListArray[i] }))
|
||||
fun addBucketedData() {
|
||||
addSeries(overviewData.bucketedGraphSeries)
|
||||
}
|
||||
|
||||
fun addBgReadings(fromTime: Long, toTime: Long, highLine: Double, predictions: MutableList<GlucoseValueDataPoint>?) {
|
||||
var maxBgValue = Double.MIN_VALUE
|
||||
bgReadingsArray = repository.compatGetBgReadingsDataFromTime(fromTime, toTime, false).blockingGet()
|
||||
if (bgReadingsArray?.isEmpty() != false) {
|
||||
aapsLogger.debug("No BG data.")
|
||||
maxY = if (units == GlucoseUnit.MGDL) 180.0 else 10.0
|
||||
minY = 0.0
|
||||
return
|
||||
}
|
||||
val bgListArray: MutableList<DataPointWithLabelInterface> = 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))
|
||||
}
|
||||
if (predictions != null) {
|
||||
predictions.sortWith(Comparator { o1: GlucoseValueDataPoint, o2: GlucoseValueDataPoint -> o1.x.compareTo(o2.x) })
|
||||
for (prediction in predictions) if (prediction.data.value >= 40) bgListArray.add(prediction)
|
||||
}
|
||||
maxBgValue = Profile.fromMgdlToUnits(maxBgValue, units)
|
||||
maxBgValue = addUpperChartMargin(maxBgValue)
|
||||
if (highLine > maxBgValue) maxBgValue = highLine
|
||||
maxY = maxBgValue
|
||||
fun addBgReadings(addPredictions: Boolean) {
|
||||
maxY = if (overviewData.bgReadingsArray.isEmpty()) {
|
||||
if (units == GlucoseUnit.MGDL) 180.0 else 10.0
|
||||
} else overviewData.maxBgValue
|
||||
minY = 0.0
|
||||
addSeries(PointsWithLabelGraphSeries(Array(bgListArray.size) { i -> bgListArray[i] }))
|
||||
addSeries(overviewData.bgReadingGraphSeries)
|
||||
if (addPredictions) addSeries(overviewData.predictionsGraphSeries)
|
||||
}
|
||||
|
||||
private fun addUpperChartMargin(maxBgValue: Double) =
|
||||
if (units == GlucoseUnit.MGDL) Round.roundTo(maxBgValue, 40.0) + 80 else Round.roundTo(maxBgValue, 2.0) + 4
|
||||
|
||||
fun addInRangeArea(fromTime: Long, toTime: Long, lowLine: Double, highLine: Double) {
|
||||
val inRangeAreaSeries: AreaGraphSeries<DoubleDataPoint>
|
||||
val inRangeAreaDataPoints = arrayOf(
|
||||
DoubleDataPoint(fromTime.toDouble(), lowLine, highLine),
|
||||
DoubleDataPoint(toTime.toDouble(), lowLine, highLine)
|
||||
)
|
||||
inRangeAreaSeries = AreaGraphSeries(inRangeAreaDataPoints)
|
||||
inRangeAreaSeries.color = 0
|
||||
inRangeAreaSeries.isDrawBackground = true
|
||||
inRangeAreaSeries.backgroundColor = resourceHelper.gc(R.color.inrangebackground)
|
||||
addSeries(inRangeAreaSeries)
|
||||
}
|
||||
|
||||
// scale in % of vertical size (like 0.3)
|
||||
fun addBasals(fromTime: Long, toTime: Long, scale: Double) {
|
||||
var maxBasalValueFound = 0.0
|
||||
val basalScale = Scale()
|
||||
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 = 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
|
||||
addSeries(LineGraphSeries(Array(baseBasalArray.size) { i -> baseBasalArray[i] }).also {
|
||||
addSeries(AreaGraphSeries(inRangeAreaDataPoints).also {
|
||||
it.color = 0
|
||||
it.isDrawBackground = true
|
||||
it.backgroundColor = resourceHelper.gc(R.color.basebasal)
|
||||
it.thickness = 0
|
||||
})
|
||||
addSeries(LineGraphSeries(Array(tempBasalArray.size) { i -> tempBasalArray[i] }).also {
|
||||
it.isDrawBackground = true
|
||||
it.backgroundColor = resourceHelper.gc(R.color.tempbasal)
|
||||
it.thickness = 0
|
||||
})
|
||||
addSeries(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)
|
||||
})
|
||||
})
|
||||
addSeries(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)
|
||||
})
|
||||
})
|
||||
basalScale.setMultiplier(maxY * scale / maxBasalValueFound)
|
||||
}
|
||||
|
||||
fun addTargetLine(fromTime: Long, toTimeParam: Long, profile: Profile, lastRun: LoopInterface.LastRun?) {
|
||||
var toTime = toTimeParam
|
||||
val targetsSeriesArray: MutableList<DataPoint> = ArrayList()
|
||||
var lastTarget = -1.0
|
||||
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
|
||||
addSeries(LineGraphSeries(Array(targetsSeriesArray.size) { i -> targetsSeriesArray[i] }).also {
|
||||
it.isDrawBackground = false
|
||||
it.color = resourceHelper.gc(R.color.tempTargetBackground)
|
||||
it.thickness = 2
|
||||
it.backgroundColor = resourceHelper.gc(R.color.inrangebackground)
|
||||
})
|
||||
}
|
||||
|
||||
fun addTreatments(fromTime: Long, endTime: Long) {
|
||||
val filteredTreatments: MutableList<DataPointWithLabelInterface> = 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 { maxY = maxOf(maxY, it) }
|
||||
|
||||
addSeries(PointsWithLabelGraphSeries(filteredTreatments.toTypedArray()))
|
||||
fun addBasals() {
|
||||
val scale = defaultValueHelper.determineLowLine() / maxY / 1.2
|
||||
addSeries(overviewData.baseBasalGraphSeries)
|
||||
addSeries(overviewData.tempBasalGraphSeries)
|
||||
addSeries(overviewData.basalLineGraphSeries)
|
||||
addSeries(overviewData.absoluteBasalGraphSeries)
|
||||
overviewData.basalScale.multiplier = maxY * scale / overviewData.maxBasalValueFound
|
||||
}
|
||||
|
||||
private fun getNearestBg(date: Long): Double {
|
||||
bgReadingsArray?.let { bgReadingsArray ->
|
||||
for (reading in bgReadingsArray) {
|
||||
if (reading.timestamp > date) continue
|
||||
return Profile.fromMgdlToUnits(reading.value, units)
|
||||
}
|
||||
return if (bgReadingsArray.isNotEmpty()) Profile.fromMgdlToUnits(bgReadingsArray[0].value, units) else Profile.fromMgdlToUnits(100.0, units)
|
||||
} ?: return Profile.fromMgdlToUnits(100.0, units)
|
||||
fun addTargetLine() {
|
||||
addSeries(overviewData.temporaryTargetSeries)
|
||||
}
|
||||
|
||||
fun addActivity(fromTime: Long, toTime: Long, useForScale: Boolean, scale: Double) {
|
||||
val actArrayHist: MutableList<ScaledDataPoint> = ArrayList()
|
||||
val actArrayPrediction: MutableList<ScaledDataPoint> = ArrayList()
|
||||
val now = System.currentTimeMillis().toDouble()
|
||||
val actScale = Scale()
|
||||
var total: IobTotal
|
||||
var maxIAValue = 0.0
|
||||
var time = fromTime
|
||||
while (time <= toTime) {
|
||||
val profile = profileFunction.getProfile(time)
|
||||
if (profile == null) {
|
||||
time += 5 * 60 * 1000L
|
||||
continue
|
||||
}
|
||||
total = iobCobCalculator.calculateFromTreatmentsAndTemps(time, profile)
|
||||
val act: Double = total.activity
|
||||
if (time <= now) actArrayHist.add(ScaledDataPoint(time, act, actScale)) else actArrayPrediction.add(ScaledDataPoint(time, act, actScale))
|
||||
maxIAValue = max(maxIAValue, abs(act))
|
||||
time += 5 * 60 * 1000L
|
||||
}
|
||||
addSeries(FixedLineGraphSeries(Array(actArrayHist.size) { i -> actArrayHist[i] }).also {
|
||||
it.isDrawBackground = false
|
||||
it.color = resourceHelper.gc(R.color.activity)
|
||||
it.thickness = 3
|
||||
})
|
||||
addSeries(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)
|
||||
})
|
||||
})
|
||||
if (useForScale) {
|
||||
maxY = maxIAValue
|
||||
minY = -maxIAValue
|
||||
}
|
||||
actScale.setMultiplier(maxY * scale / maxIAValue)
|
||||
fun addTreatments() {
|
||||
maxY = maxOf(maxY, overviewData.maxTreatmentsValue)
|
||||
addSeries(overviewData.treatmentsSeries)
|
||||
}
|
||||
|
||||
fun addActivity(scale: Double) {
|
||||
addSeries(overviewData.activitySeries)
|
||||
addSeries(overviewData.activityPredictionSeries)
|
||||
overviewData.actScale.multiplier = maxY * scale / overviewData.maxIAValue
|
||||
}
|
||||
|
||||
//Function below show -BGI to be able to compare curves with deviations
|
||||
fun addMinusBGI(fromTime: Long, toTime: Long, useForScale: Boolean, scale: Double, devBgiScale: Boolean) {
|
||||
val bgiArrayHist: MutableList<ScaledDataPoint> = ArrayList()
|
||||
val bgiArrayPrediction: MutableList<ScaledDataPoint> = ArrayList()
|
||||
val now = System.currentTimeMillis().toDouble()
|
||||
val bgiScale = Scale()
|
||||
var total: IobTotal
|
||||
var maxBGIValue = 0.0
|
||||
var time = fromTime
|
||||
while (time <= toTime) {
|
||||
val profile = profileFunction.getProfile(time)
|
||||
if (profile == null) {
|
||||
time += 5 * 60 * 1000L
|
||||
continue
|
||||
}
|
||||
val deviation = if (devBgiScale) iobCobCalculator.ads.getAutosensDataAtTime(time)?.deviation
|
||||
?: 0.0 else 0.0
|
||||
|
||||
total = iobCobCalculator.calculateFromTreatmentsAndTemps(time, profile)
|
||||
val bgi: Double = total.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))
|
||||
time += 5 * 60 * 1000L
|
||||
}
|
||||
addSeries(FixedLineGraphSeries(Array(bgiArrayHist.size) { i -> bgiArrayHist[i] }).also {
|
||||
it.isDrawBackground = false
|
||||
it.color = resourceHelper.gc(R.color.bgi)
|
||||
it.thickness = 3
|
||||
})
|
||||
addSeries(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)
|
||||
})
|
||||
})
|
||||
fun addMinusBGI(useForScale: Boolean, scale: Double) {
|
||||
if (useForScale) {
|
||||
maxY = maxBGIValue
|
||||
minY = -maxBGIValue
|
||||
maxY = overviewData.maxBGIValue
|
||||
minY = -overviewData.maxBGIValue
|
||||
}
|
||||
bgiScale.setMultiplier(maxY * scale / maxBGIValue)
|
||||
overviewData.bgiScale.multiplier = maxY * scale / overviewData.maxBGIValue
|
||||
addSeries(overviewData.minusBgiSeries)
|
||||
addSeries(overviewData.minusBgiHistSeries)
|
||||
}
|
||||
|
||||
// scale in % of vertical size (like 0.3)
|
||||
fun addIob(fromTime: Long, toTime: Long, useForScale: Boolean, scale: Double, showPrediction: Boolean, absScale: Boolean) {
|
||||
val iobSeries: FixedLineGraphSeries<ScaledDataPoint?>
|
||||
val iobArray: MutableList<ScaledDataPoint> = ArrayList()
|
||||
var maxIobValueFound = Double.MIN_VALUE
|
||||
var lastIob = 0.0
|
||||
val iobScale = Scale()
|
||||
var time = fromTime
|
||||
while (time <= toTime) {
|
||||
val profile = profileFunction.getProfile(time)
|
||||
if (profile == null) {
|
||||
time += 5 * 60 * 1000L
|
||||
continue
|
||||
}
|
||||
var iob = 0.0
|
||||
var absIob = 0.0
|
||||
iob = iobCobCalculator.calculateFromTreatmentsAndTemps(time, profile).iob
|
||||
if (absScale) absIob = iobCobCalculator.calculateAbsInsulinFromTreatmentsAndTemps(time).iob
|
||||
if (abs(lastIob - iob) > 0.02) {
|
||||
if (abs(lastIob - iob) > 0.2) iobArray.add(ScaledDataPoint(time, lastIob, iobScale))
|
||||
iobArray.add(ScaledDataPoint(time, iob, iobScale))
|
||||
maxIobValueFound = if (absScale) max(maxIobValueFound, abs(absIob)) else max(maxIobValueFound, abs(iob))
|
||||
lastIob = iob
|
||||
}
|
||||
time += 5 * 60 * 1000L
|
||||
}
|
||||
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
|
||||
}
|
||||
if (showPrediction) {
|
||||
val autosensData = iobCobCalculator.getLastAutosensDataWithWaitForCalculationFinish("GraphData")
|
||||
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)))
|
||||
maxIobValueFound = max(maxIobValueFound, abs(i.iob))
|
||||
}
|
||||
addSeries(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)))
|
||||
maxIobValueFound = max(maxIobValueFound, abs(i.iob))
|
||||
}
|
||||
addSeries(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))
|
||||
}
|
||||
fun addIob(useForScale: Boolean, scale: Double) {
|
||||
if (useForScale) {
|
||||
maxY = maxIobValueFound
|
||||
minY = -maxIobValueFound
|
||||
maxY = overviewData.maxIobValueFound
|
||||
minY = -overviewData.maxIobValueFound
|
||||
}
|
||||
iobScale.setMultiplier(maxY * scale / maxIobValueFound)
|
||||
addSeries(iobSeries)
|
||||
overviewData.iobScale.multiplier = maxY * scale / overviewData.maxIobValueFound
|
||||
addSeries(overviewData.iobSeries)
|
||||
addSeries(overviewData.iobPredictions1Series)
|
||||
addSeries(overviewData.iobPredictions2Series)
|
||||
}
|
||||
|
||||
// scale in % of vertical size (like 0.3)
|
||||
fun addAbsIob(fromTime: Long, toTime: Long, useForScale: Boolean, scale: Double) {
|
||||
val iobSeries: FixedLineGraphSeries<ScaledDataPoint?>
|
||||
val iobArray: MutableList<ScaledDataPoint> = ArrayList()
|
||||
var maxIobValueFound = Double.MIN_VALUE
|
||||
var lastIob = 0.0
|
||||
val iobScale = Scale()
|
||||
var time = fromTime
|
||||
while (time <= toTime) {
|
||||
val profile = profileFunction.getProfile(time)
|
||||
if (profile == null) {
|
||||
time += 5 * 60 * 1000L
|
||||
continue
|
||||
}
|
||||
var iob = 0.0
|
||||
iob = iobCobCalculator.calculateAbsInsulinFromTreatmentsAndTemps(time).iob
|
||||
if (abs(lastIob - iob) > 0.02) {
|
||||
if (abs(lastIob - iob) > 0.2) iobArray.add(ScaledDataPoint(time, lastIob, iobScale))
|
||||
iobArray.add(ScaledDataPoint(time, iob, iobScale))
|
||||
maxIobValueFound = max(maxIobValueFound, abs(iob))
|
||||
lastIob = iob
|
||||
}
|
||||
time += 5 * 60 * 1000L
|
||||
}
|
||||
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
|
||||
}
|
||||
fun addAbsIob(useForScale: Boolean, scale: Double) {
|
||||
if (useForScale) {
|
||||
maxY = maxIobValueFound
|
||||
minY = -maxIobValueFound
|
||||
maxY = overviewData.maxIobValueFound
|
||||
minY = -overviewData.maxIobValueFound
|
||||
}
|
||||
iobScale.setMultiplier(maxY * scale / maxIobValueFound)
|
||||
addSeries(iobSeries)
|
||||
overviewData.iobScale.multiplier = maxY * scale / overviewData.maxIobValueFound
|
||||
addSeries(overviewData.absIobSeries)
|
||||
}
|
||||
|
||||
// scale in % of vertical size (like 0.3)
|
||||
fun addCob(fromTime: Long, toTime: Long, useForScale: Boolean, scale: Double) {
|
||||
val minFailOverActiveList: MutableList<DataPointWithLabelInterface> = ArrayList()
|
||||
val cobArray: MutableList<ScaledDataPoint> = ArrayList()
|
||||
var maxCobValueFound = 0.0
|
||||
var lastCob = 0
|
||||
val cobScale = Scale()
|
||||
var time = fromTime
|
||||
while (time <= toTime) {
|
||||
iobCobCalculator.ads.getAutosensDataAtTime(time)?.let { autosensData ->
|
||||
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)
|
||||
}
|
||||
}
|
||||
time += 5 * 60 * 1000L
|
||||
}
|
||||
|
||||
// COB
|
||||
addSeries(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
|
||||
})
|
||||
fun addCob(useForScale: Boolean, scale: Double) {
|
||||
if (useForScale) {
|
||||
maxY = maxCobValueFound
|
||||
maxY = overviewData.maxCobValueFound
|
||||
minY = 0.0
|
||||
}
|
||||
cobScale.setMultiplier(maxY * scale / maxCobValueFound)
|
||||
addSeries(PointsWithLabelGraphSeries(Array(minFailOverActiveList.size) { i -> minFailOverActiveList[i] }))
|
||||
overviewData.cobScale.multiplier = maxY * scale / overviewData.maxCobValueFound
|
||||
addSeries(overviewData.cobSeries)
|
||||
addSeries(overviewData.cobMinFailOverSeries)
|
||||
}
|
||||
|
||||
// scale in % of vertical size (like 0.3)
|
||||
fun addDeviations(fromTime: Long, toTime: Long, useForScale: Boolean, scale: Double, devBgiScale: Boolean) {
|
||||
class DeviationDataPoint(x: Double, y: Double, var color: Int, scale: Scale) : ScaledDataPoint(x, y, scale)
|
||||
|
||||
val devArray: MutableList<DeviationDataPoint> = ArrayList()
|
||||
var maxDevValueFound = 0.0
|
||||
val devScale = Scale()
|
||||
var time = fromTime
|
||||
var total: IobTotal
|
||||
|
||||
while (time <= toTime) {
|
||||
// if align Dev Scale with BGI scale, then calculate BGI value, else bgi = 0.0
|
||||
val bgi: Double = if (devBgiScale) {
|
||||
val profile = profileFunction.getProfile(time)
|
||||
if (profile == null) {
|
||||
time += 5 * 60 * 1000L
|
||||
continue
|
||||
}
|
||||
total = iobCobCalculator.calculateFromTreatmentsAndTemps(time, profile)
|
||||
total.activity * profile.getIsfMgdl(time) * 5.0
|
||||
} else 0.0
|
||||
|
||||
iobCobCalculator.ads.getAutosensDataAtTime(time)?.let { autosensData ->
|
||||
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, devScale))
|
||||
maxDevValueFound = max(maxDevValueFound, max(abs(autosensData.deviation), abs(bgi)))
|
||||
}
|
||||
time += 5 * 60 * 1000L
|
||||
}
|
||||
|
||||
// DEVIATIONS
|
||||
addSeries(BarGraphSeries(Array(devArray.size) { i -> devArray[i] }).also {
|
||||
it.setValueDependentColor { data: DeviationDataPoint -> data.color }
|
||||
})
|
||||
fun addDeviations(useForScale: Boolean, scale: Double) {
|
||||
if (useForScale) {
|
||||
maxY = maxDevValueFound
|
||||
maxY = overviewData.maxDevValueFound
|
||||
minY = -maxY
|
||||
}
|
||||
devScale.setMultiplier(maxY * scale / maxDevValueFound)
|
||||
overviewData.devScale.multiplier = maxY * scale / overviewData.maxDevValueFound
|
||||
addSeries(overviewData.deviationsSeries)
|
||||
}
|
||||
|
||||
// scale in % of vertical size (like 0.3)
|
||||
fun addRatio(fromTime: Long, toTime: Long, useForScale: Boolean, scale: Double) {
|
||||
val ratioArray: MutableList<ScaledDataPoint> = ArrayList()
|
||||
var maxRatioValueFound = 5.0 //even if sens data equals 0 for all the period, minimum scale is between 95% and 105%
|
||||
var minRatioValueFound = -maxRatioValueFound
|
||||
val ratioScale = if (useForScale) Scale(100.0) else Scale()
|
||||
var time = fromTime
|
||||
while (time <= toTime) {
|
||||
iobCobCalculator.ads.getAutosensDataAtTime(time)?.let { autosensData ->
|
||||
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))
|
||||
}
|
||||
time += 5 * 60 * 1000L
|
||||
}
|
||||
|
||||
// RATIOS
|
||||
addSeries(LineGraphSeries(Array(ratioArray.size) { i -> ratioArray[i] }).also {
|
||||
it.color = resourceHelper.gc(R.color.ratio)
|
||||
it.thickness = 3
|
||||
})
|
||||
fun addRatio(useForScale: Boolean, scale: Double) {
|
||||
if (useForScale) {
|
||||
maxY = 100.0 + max(maxRatioValueFound, abs(minRatioValueFound))
|
||||
minY = 100.0 - max(maxRatioValueFound, abs(minRatioValueFound))
|
||||
ratioScale.setMultiplier(1.0)
|
||||
} else
|
||||
ratioScale.setMultiplier(maxY * scale / max(maxRatioValueFound, abs(minRatioValueFound)))
|
||||
maxY = 100.0 + max(overviewData.maxRatioValueFound, abs(overviewData.minRatioValueFound))
|
||||
minY = 100.0 - max(overviewData.maxRatioValueFound, abs(overviewData.minRatioValueFound))
|
||||
overviewData.ratioScale.multiplier = 1.0
|
||||
overviewData.ratioScale.shift = 100.0
|
||||
} else {
|
||||
overviewData.ratioScale.multiplier = maxY * scale / max(overviewData.maxRatioValueFound, abs(overviewData.minRatioValueFound))
|
||||
overviewData.ratioScale.shift = 0.0
|
||||
}
|
||||
addSeries(overviewData.ratioSeries)
|
||||
}
|
||||
|
||||
// scale in % of vertical size (like 0.3)
|
||||
fun addDeviationSlope(fromTime: Long, toTime: Long, useForScale: Boolean, scale: Double) {
|
||||
val dsMaxArray: MutableList<ScaledDataPoint> = ArrayList()
|
||||
val dsMinArray: MutableList<ScaledDataPoint> = ArrayList()
|
||||
var maxFromMaxValueFound = 0.0
|
||||
var maxFromMinValueFound = 0.0
|
||||
val dsMaxScale = Scale()
|
||||
val dsMinScale = Scale()
|
||||
var time = fromTime
|
||||
while (time <= toTime) {
|
||||
iobCobCalculator.ads.getAutosensDataAtTime(time)?.let { autosensData ->
|
||||
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
|
||||
}
|
||||
|
||||
// Slopes
|
||||
addSeries(LineGraphSeries(Array(dsMaxArray.size) { i -> dsMaxArray[i] }).also {
|
||||
it.color = resourceHelper.gc(R.color.devslopepos)
|
||||
it.thickness = 3
|
||||
})
|
||||
addSeries(LineGraphSeries(Array(dsMinArray.size) { i -> dsMinArray[i] }).also {
|
||||
it.color = resourceHelper.gc(R.color.devslopeneg)
|
||||
it.thickness = 3
|
||||
})
|
||||
fun addDeviationSlope(useForScale: Boolean, scale: Double, isRatioScale: Boolean = false) {
|
||||
if (useForScale) {
|
||||
maxY = max(maxFromMaxValueFound, maxFromMinValueFound)
|
||||
maxY = max(overviewData.maxFromMaxValueFound, overviewData.maxFromMinValueFound)
|
||||
minY = -maxY
|
||||
}
|
||||
dsMaxScale.setMultiplier(maxY * scale / maxFromMaxValueFound)
|
||||
dsMinScale.setMultiplier(maxY * scale / maxFromMinValueFound)
|
||||
var graphMaxY = maxY
|
||||
if (isRatioScale) {
|
||||
graphMaxY = maxY - 100.0
|
||||
overviewData.dsMinScale.shift = 100.0
|
||||
overviewData.dsMaxScale.shift = 100.0
|
||||
} else {
|
||||
overviewData.dsMinScale.shift = 0.0
|
||||
overviewData.dsMaxScale.shift = 0.0
|
||||
}
|
||||
overviewData.dsMaxScale.multiplier = graphMaxY * scale / overviewData.maxFromMaxValueFound
|
||||
overviewData.dsMinScale.multiplier = graphMaxY * scale / overviewData.maxFromMinValueFound
|
||||
addSeries(overviewData.dsMaxSeries)
|
||||
addSeries(overviewData.dsMinSeries)
|
||||
}
|
||||
|
||||
// scale in % of vertical size (like 0.3)
|
||||
|
@ -695,5 +237,3 @@ class GraphData(
|
|||
}
|
||||
}
|
||||
|
||||
private fun <E : DataPointWithLabelInterface> List<E>.filterTimeframe(fromTime: Long, endTime: Long): List<E> =
|
||||
filter { it.x + it.duration >= fromTime && it.x <= endTime }
|
||||
|
|
|
@ -31,11 +31,11 @@ class TherapyEventDataPoint @Inject constructor(
|
|||
if (data.glucose != null && data.glucose != 0.0) {
|
||||
var mmol = 0.0
|
||||
var mgdl = 0.0
|
||||
if (units == GlucoseUnit.MGDL) {
|
||||
if (data.glucoseUnit == TherapyEvent.GlucoseUnit.MGDL) {
|
||||
mgdl = data.glucose!!
|
||||
mmol = data.glucose!! * Constants.MGDL_TO_MMOLL
|
||||
}
|
||||
if (units == GlucoseUnit.MMOL) {
|
||||
if (data.glucoseUnit == TherapyEvent.GlucoseUnit.MMOL) {
|
||||
mmol = data.glucose!!
|
||||
mgdl = data.glucose!! * Constants.MMOLL_TO_MGDL
|
||||
}
|
||||
|
|
|
@ -11,25 +11,26 @@ import androidx.work.Worker
|
|||
import androidx.work.WorkerParameters
|
||||
import androidx.work.workDataOf
|
||||
import dagger.android.HasAndroidInjector
|
||||
import info.nightscout.androidaps.interfaces.Config
|
||||
import info.nightscout.androidaps.Constants
|
||||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.data.DetailedBolusInfo
|
||||
import info.nightscout.androidaps.interfaces.Profile
|
||||
import info.nightscout.androidaps.database.AppRepository
|
||||
import info.nightscout.androidaps.database.entities.ValueWithUnit
|
||||
import info.nightscout.androidaps.database.entities.OfflineEvent
|
||||
import info.nightscout.androidaps.database.entities.TemporaryTarget
|
||||
import info.nightscout.androidaps.database.entities.UserEntry.Action
|
||||
import info.nightscout.androidaps.database.entities.UserEntry.Sources
|
||||
import info.nightscout.androidaps.database.entities.ValueWithUnit
|
||||
import info.nightscout.androidaps.database.transactions.CancelCurrentOfflineEventIfAnyTransaction
|
||||
import info.nightscout.androidaps.database.transactions.CancelCurrentTemporaryTargetIfAnyTransaction
|
||||
import info.nightscout.androidaps.database.transactions.InsertTemporaryTargetAndCancelCurrentTransaction
|
||||
import info.nightscout.androidaps.database.transactions.InsertAndCancelCurrentOfflineEventTransaction
|
||||
import info.nightscout.androidaps.database.transactions.InsertAndCancelCurrentTemporaryTargetTransaction
|
||||
import info.nightscout.androidaps.events.EventPreferenceChange
|
||||
import info.nightscout.androidaps.events.EventRefreshOverview
|
||||
import info.nightscout.androidaps.extensions.valueToUnitsString
|
||||
import info.nightscout.androidaps.interfaces.*
|
||||
import info.nightscout.androidaps.logging.AAPSLogger
|
||||
import info.nightscout.androidaps.logging.LTag
|
||||
import info.nightscout.androidaps.logging.UserEntryLogger
|
||||
import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin
|
||||
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
||||
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
|
||||
import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientRestart
|
||||
|
@ -41,7 +42,6 @@ import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatusProv
|
|||
import info.nightscout.androidaps.queue.Callback
|
||||
import info.nightscout.androidaps.receivers.DataWorker
|
||||
import info.nightscout.androidaps.utils.*
|
||||
import info.nightscout.androidaps.extensions.valueToUnitsString
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
||||
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
||||
|
@ -72,7 +72,7 @@ class SmsCommunicatorPlugin @Inject constructor(
|
|||
private val fabricPrivacy: FabricPrivacy,
|
||||
private val activePlugin: ActivePlugin,
|
||||
private val commandQueue: CommandQueueProvider,
|
||||
private val loopPlugin: LoopPlugin,
|
||||
private val loop: Loop,
|
||||
private val iobCobCalculator: IobCobCalculator,
|
||||
private val xdripCalibrations: XdripCalibrations,
|
||||
private var otp: OneTimePassword,
|
||||
|
@ -181,6 +181,7 @@ class SmsCommunicatorPlugin @Inject constructor(
|
|||
}
|
||||
|
||||
@Suppress("SpellCheckingInspection")
|
||||
@kotlin.ExperimentalStdlibApi
|
||||
override fun doWork(): Result {
|
||||
val bundle = dataWorker.pickupBundle(inputData.getLong(DataWorker.STORE_KEY, -1))
|
||||
?: return Result.failure(workDataOf("Error" to "missing input data"))
|
||||
|
@ -223,6 +224,7 @@ class SmsCommunicatorPlugin @Inject constructor(
|
|||
return false
|
||||
}
|
||||
|
||||
@kotlin.ExperimentalStdlibApi
|
||||
fun processSms(receivedSms: Sms) {
|
||||
if (!isEnabled(PluginType.GENERAL)) {
|
||||
aapsLogger.debug(LTag.SMS, "Ignoring SMS. Plugin disabled.")
|
||||
|
@ -246,8 +248,8 @@ class SmsCommunicatorPlugin @Inject constructor(
|
|||
T.mins(sp.getLong(R.string.key_smscommunicator_remotebolusmindistance, T.msecs(Constants.remoteBolusMinDistance).mins())).msecs()
|
||||
else Constants.remoteBolusMinDistance
|
||||
|
||||
if (divided.isNotEmpty() && isCommand(divided[0].toUpperCase(Locale.getDefault()), receivedSms.phoneNumber)) {
|
||||
when (divided[0].toUpperCase(Locale.getDefault())) {
|
||||
if (divided.isNotEmpty() && isCommand(divided[0].uppercase(Locale.getDefault()), receivedSms.phoneNumber)) {
|
||||
when (divided[0].uppercase(Locale.getDefault())) {
|
||||
"BG" ->
|
||||
if (divided.size == 1) processBG(receivedSms)
|
||||
else sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.wrongformat)))
|
||||
|
@ -334,17 +336,18 @@ class SmsCommunicatorPlugin @Inject constructor(
|
|||
receivedSms.processed = true
|
||||
}
|
||||
|
||||
@kotlin.ExperimentalStdlibApi
|
||||
private fun processLOOP(divided: Array<String>, receivedSms: Sms) {
|
||||
when (divided[1].toUpperCase(Locale.getDefault())) {
|
||||
when (divided[1].uppercase(Locale.getDefault())) {
|
||||
"DISABLE", "STOP" -> {
|
||||
if (loopPlugin.isEnabled(PluginType.LOOP)) {
|
||||
if (loop.enabled) {
|
||||
val passCode = generatePassCode()
|
||||
val reply = String.format(resourceHelper.gs(R.string.smscommunicator_loopdisablereplywithcode), passCode)
|
||||
receivedSms.processed = true
|
||||
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction() {
|
||||
override fun run() {
|
||||
uel.log(Action.LOOP_DISABLED, Sources.SMS)
|
||||
loopPlugin.setPluginEnabled(PluginType.LOOP, false)
|
||||
loop.enabled = false
|
||||
commandQueue.cancelTempBasal(true, object : Callback() {
|
||||
override fun run() {
|
||||
rxBus.send(EventRefreshOverview("SMS_LOOP_STOP"))
|
||||
|
@ -361,14 +364,14 @@ class SmsCommunicatorPlugin @Inject constructor(
|
|||
}
|
||||
|
||||
"ENABLE", "START" -> {
|
||||
if (!loopPlugin.isEnabled(PluginType.LOOP)) {
|
||||
if (!loop.enabled) {
|
||||
val passCode = generatePassCode()
|
||||
val reply = String.format(resourceHelper.gs(R.string.smscommunicator_loopenablereplywithcode), passCode)
|
||||
receivedSms.processed = true
|
||||
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction() {
|
||||
override fun run() {
|
||||
uel.log(Action.LOOP_ENABLED, Sources.SMS)
|
||||
loopPlugin.setPluginEnabled(PluginType.LOOP, true)
|
||||
loop.enabled= true
|
||||
sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.smscommunicator_loophasbeenenabled)))
|
||||
rxBus.send(EventRefreshOverview("SMS_LOOP_START"))
|
||||
}
|
||||
|
@ -379,8 +382,8 @@ class SmsCommunicatorPlugin @Inject constructor(
|
|||
}
|
||||
|
||||
"STATUS" -> {
|
||||
val reply = if (loopPlugin.isEnabled(PluginType.LOOP)) {
|
||||
if (loopPlugin.isSuspended) String.format(resourceHelper.gs(R.string.loopsuspendedfor), loopPlugin.minutesToEndOfSuspend())
|
||||
val reply = if (loop.enabled) {
|
||||
if (loop.isSuspended) String.format(resourceHelper.gs(R.string.loopsuspendedfor), loop.minutesToEndOfSuspend())
|
||||
else resourceHelper.gs(R.string.smscommunicator_loopisenabled)
|
||||
} else
|
||||
resourceHelper.gs(R.string.loopisdisabled)
|
||||
|
@ -395,7 +398,12 @@ class SmsCommunicatorPlugin @Inject constructor(
|
|||
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction() {
|
||||
override fun run() {
|
||||
uel.log(Action.RESUME, Sources.SMS)
|
||||
loopPlugin.suspendTo(0L)
|
||||
disposable += repository.runTransactionForResult(CancelCurrentOfflineEventIfAnyTransaction(dateUtil.now()))
|
||||
.subscribe({ result ->
|
||||
result.updated.forEach { aapsLogger.debug(LTag.DATABASE, "Updated OfflineEvent $it") }
|
||||
}, {
|
||||
aapsLogger.error(LTag.DATABASE, "Error while saving OfflineEvent", it)
|
||||
})
|
||||
rxBus.send(EventRefreshOverview("SMS_LOOP_RESUME"))
|
||||
commandQueue.cancelTempBasal(true, object : Callback() {
|
||||
override fun run() {
|
||||
|
@ -406,7 +414,6 @@ class SmsCommunicatorPlugin @Inject constructor(
|
|||
}
|
||||
}
|
||||
})
|
||||
loopPlugin.createOfflineEvent(0)
|
||||
sendSMSToAllNumbers(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.smscommunicator_loopresumed)))
|
||||
}
|
||||
})
|
||||
|
@ -431,8 +438,13 @@ class SmsCommunicatorPlugin @Inject constructor(
|
|||
commandQueue.cancelTempBasal(true, object : Callback() {
|
||||
override fun run() {
|
||||
if (result.success) {
|
||||
loopPlugin.suspendTo(dateUtil.now() + anInteger() * 60L * 1000)
|
||||
loopPlugin.createOfflineEvent(anInteger() * 60)
|
||||
disposable += repository.runTransactionForResult(InsertAndCancelCurrentOfflineEventTransaction(dateUtil.now(), T.mins(anInteger().toLong()).msecs(), OfflineEvent.Reason.SUSPEND))
|
||||
.subscribe({ result ->
|
||||
result.updated.forEach { aapsLogger.debug(LTag.DATABASE, "Updated OfflineEvent $it") }
|
||||
result.inserted.forEach { aapsLogger.debug(LTag.DATABASE, "Inserted OfflineEvent $it") }
|
||||
}, {
|
||||
aapsLogger.error(LTag.DATABASE, "Error while saving OfflineEvent", it)
|
||||
})
|
||||
rxBus.send(EventRefreshOverview("SMS_LOOP_SUSPENDED"))
|
||||
val replyText = resourceHelper.gs(R.string.smscommunicator_loopsuspended) + " " +
|
||||
resourceHelper.gs(if (result.success) R.string.smscommunicator_tempbasalcanceled else R.string.smscommunicator_tempbasalcancelfailed)
|
||||
|
@ -453,8 +465,9 @@ class SmsCommunicatorPlugin @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
@kotlin.ExperimentalStdlibApi
|
||||
private fun processNSCLIENT(divided: Array<String>, receivedSms: Sms) {
|
||||
if (divided[1].toUpperCase(Locale.getDefault()) == "RESTART") {
|
||||
if (divided[1].uppercase(Locale.getDefault()) == "RESTART") {
|
||||
rxBus.send(EventNSClientRestart())
|
||||
sendSMS(Sms(receivedSms.phoneNumber, "NSCLIENT RESTART SENT"))
|
||||
receivedSms.processed = true
|
||||
|
@ -462,6 +475,7 @@ class SmsCommunicatorPlugin @Inject constructor(
|
|||
sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.wrongformat)))
|
||||
}
|
||||
|
||||
@kotlin.ExperimentalStdlibApi
|
||||
private fun processHELP(divided: Array<String>, receivedSms: Sms) {
|
||||
when {
|
||||
divided.size == 1 -> {
|
||||
|
@ -469,8 +483,8 @@ class SmsCommunicatorPlugin @Inject constructor(
|
|||
receivedSms.processed = true
|
||||
}
|
||||
|
||||
isCommand(divided[1].toUpperCase(Locale.getDefault()), receivedSms.phoneNumber) -> {
|
||||
commands[divided[1].toUpperCase(Locale.getDefault())]?.let {
|
||||
isCommand(divided[1].uppercase(Locale.getDefault()), receivedSms.phoneNumber) -> {
|
||||
commands[divided[1].uppercase(Locale.getDefault())]?.let {
|
||||
sendSMS(Sms(receivedSms.phoneNumber, it))
|
||||
receivedSms.processed = true
|
||||
}
|
||||
|
@ -507,10 +521,14 @@ class SmsCommunicatorPlugin @Inject constructor(
|
|||
if (!result.success) {
|
||||
sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.smscommunicator_pumpconnectfail)))
|
||||
} else {
|
||||
loopPlugin.suspendTo(0L)
|
||||
disposable += repository.runTransactionForResult(CancelCurrentOfflineEventIfAnyTransaction(dateUtil.now()))
|
||||
.subscribe({ result ->
|
||||
result.updated.forEach { aapsLogger.debug(LTag.DATABASE, "Updated OfflineEvent $it") }
|
||||
}, {
|
||||
aapsLogger.error(LTag.DATABASE, "Error while saving OfflineEvent", it)
|
||||
})
|
||||
sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.smscommunicator_reconnect)))
|
||||
rxBus.send(EventRefreshOverview("SMS_PUMP_START"))
|
||||
loopPlugin.createOfflineEvent(0)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
@ -531,8 +549,8 @@ class SmsCommunicatorPlugin @Inject constructor(
|
|||
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction() {
|
||||
override fun run() {
|
||||
uel.log(Action.DISCONNECT, Sources.SMS)
|
||||
val profile = profileFunction.getProfile()
|
||||
loopPlugin.disconnectPump(duration, profile)
|
||||
val profile = profileFunction.getProfile() ?: return
|
||||
loop.goToZeroTemp(duration, profile, OfflineEvent.Reason.DISCONNECT_PUMP)
|
||||
rxBus.send(EventRefreshOverview("SMS_PUMP_DISCONNECT"))
|
||||
sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.smscommunicator_pumpdisconnected)))
|
||||
}
|
||||
|
@ -544,6 +562,7 @@ class SmsCommunicatorPlugin @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
@kotlin.ExperimentalStdlibApi
|
||||
private fun processPROFILE(divided: Array<String>, receivedSms: Sms) { // load profiles
|
||||
val anInterface = activePlugin.activeProfileSource
|
||||
val store = anInterface.profile
|
||||
|
@ -554,9 +573,9 @@ class SmsCommunicatorPlugin @Inject constructor(
|
|||
}
|
||||
val profileName = profileFunction.getProfileName()
|
||||
val list = store.getProfileList()
|
||||
if (divided[1].toUpperCase(Locale.getDefault()) == "STATUS") {
|
||||
if (divided[1].uppercase(Locale.getDefault()) == "STATUS") {
|
||||
sendSMS(Sms(receivedSms.phoneNumber, profileName))
|
||||
} else if (divided[1].toUpperCase(Locale.getDefault()) == "LIST") {
|
||||
} else if (divided[1].uppercase(Locale.getDefault()) == "LIST") {
|
||||
if (list.isEmpty()) sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.invalidprofile)))
|
||||
else {
|
||||
var reply = ""
|
||||
|
@ -597,8 +616,9 @@ class SmsCommunicatorPlugin @Inject constructor(
|
|||
receivedSms.processed = true
|
||||
}
|
||||
|
||||
@kotlin.ExperimentalStdlibApi
|
||||
private fun processBASAL(divided: Array<String>, receivedSms: Sms) {
|
||||
if (divided[1].toUpperCase(Locale.getDefault()) == "CANCEL" || divided[1].toUpperCase(Locale.getDefault()) == "STOP") {
|
||||
if (divided[1].uppercase(Locale.getDefault()) == "CANCEL" || divided[1].uppercase(Locale.getDefault()) == "STOP") {
|
||||
val passCode = generatePassCode()
|
||||
val reply = String.format(resourceHelper.gs(R.string.smscommunicator_basalstopreplywithcode), passCode)
|
||||
receivedSms.processed = true
|
||||
|
@ -713,8 +733,9 @@ class SmsCommunicatorPlugin @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
@kotlin.ExperimentalStdlibApi
|
||||
private fun processEXTENDED(divided: Array<String>, receivedSms: Sms) {
|
||||
if (divided[1].toUpperCase(Locale.getDefault()) == "CANCEL" || divided[1].toUpperCase(Locale.getDefault()) == "STOP") {
|
||||
if (divided[1].uppercase(Locale.getDefault()) == "CANCEL" || divided[1].uppercase(Locale.getDefault()) == "STOP") {
|
||||
val passCode = generatePassCode()
|
||||
val reply = String.format(resourceHelper.gs(R.string.smscommunicator_extendedstopreplywithcode), passCode)
|
||||
receivedSms.processed = true
|
||||
|
@ -824,7 +845,7 @@ class SmsCommunicatorPlugin @Inject constructor(
|
|||
currentProfile.units == GlucoseUnit.MMOL -> Constants.defaultEatingSoonTTmmol
|
||||
else -> Constants.defaultEatingSoonTTmgdl
|
||||
}
|
||||
disposable += repository.runTransactionForResult(InsertTemporaryTargetAndCancelCurrentTransaction(
|
||||
disposable += repository.runTransactionForResult(InsertAndCancelCurrentTemporaryTargetTransaction(
|
||||
timestamp = dateUtil.now(),
|
||||
duration = TimeUnit.MINUTES.toMillis(eatingSoonTTDuration.toLong()),
|
||||
reason = TemporaryTarget.Reason.EATING_SOON,
|
||||
|
@ -879,11 +900,12 @@ class SmsCommunicatorPlugin @Inject constructor(
|
|||
return retVal
|
||||
}
|
||||
|
||||
@kotlin.ExperimentalStdlibApi
|
||||
private fun processCARBS(divided: Array<String>, receivedSms: Sms) {
|
||||
var grams = SafeParse.stringToInt(divided[1])
|
||||
var time = dateUtil.now()
|
||||
if (divided.size > 2) {
|
||||
time = toTodayTime(divided[2].toUpperCase(Locale.getDefault()))
|
||||
time = toTodayTime(divided[2].uppercase(Locale.getDefault()))
|
||||
if (time == 0L) {
|
||||
sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.wrongformat)))
|
||||
return
|
||||
|
@ -922,6 +944,7 @@ class SmsCommunicatorPlugin @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
@kotlin.ExperimentalStdlibApi
|
||||
private fun processTARGET(divided: Array<String>, receivedSms: Sms) {
|
||||
val isMeal = divided[1].equals("MEAL", ignoreCase = true)
|
||||
val isActivity = divided[1].equals("ACTIVITY", ignoreCase = true)
|
||||
|
@ -929,7 +952,7 @@ class SmsCommunicatorPlugin @Inject constructor(
|
|||
val isStop = divided[1].equals("STOP", ignoreCase = true) || divided[1].equals("CANCEL", ignoreCase = true)
|
||||
if (isMeal || isActivity || isHypo) {
|
||||
val passCode = generatePassCode()
|
||||
val reply = String.format(resourceHelper.gs(R.string.smscommunicator_temptargetwithcode), divided[1].toUpperCase(Locale.getDefault()), passCode)
|
||||
val reply = String.format(resourceHelper.gs(R.string.smscommunicator_temptargetwithcode), divided[1].uppercase(Locale.getDefault()), passCode)
|
||||
receivedSms.processed = true
|
||||
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction() {
|
||||
override fun run() {
|
||||
|
@ -969,7 +992,7 @@ class SmsCommunicatorPlugin @Inject constructor(
|
|||
var tt = sp.getDouble(keyTarget, if (units == GlucoseUnit.MMOL) defaultTargetMMOL else defaultTargetMGDL)
|
||||
tt = Profile.toCurrentUnits(profileFunction, tt)
|
||||
tt = if (tt > 0) tt else if (units == GlucoseUnit.MMOL) defaultTargetMMOL else defaultTargetMGDL
|
||||
disposable += repository.runTransactionForResult(InsertTemporaryTargetAndCancelCurrentTransaction(
|
||||
disposable += repository.runTransactionForResult(InsertAndCancelCurrentTemporaryTargetTransaction(
|
||||
timestamp = dateUtil.now(),
|
||||
duration = TimeUnit.MINUTES.toMillis(ttDuration.toLong()),
|
||||
reason = TemporaryTarget.Reason.EATING_SOON,
|
||||
|
|
|
@ -20,7 +20,7 @@ import info.nightscout.androidaps.database.entities.UserEntry.Sources
|
|||
import info.nightscout.androidaps.database.entities.ValueWithUnit
|
||||
import info.nightscout.androidaps.database.interfaces.end
|
||||
import info.nightscout.androidaps.database.transactions.CancelCurrentTemporaryTargetIfAnyTransaction
|
||||
import info.nightscout.androidaps.database.transactions.InsertTemporaryTargetAndCancelCurrentTransaction
|
||||
import info.nightscout.androidaps.database.transactions.InsertAndCancelCurrentTemporaryTargetTransaction
|
||||
import info.nightscout.androidaps.extensions.total
|
||||
import info.nightscout.androidaps.extensions.valueToUnits
|
||||
import info.nightscout.androidaps.interfaces.*
|
||||
|
@ -572,7 +572,7 @@ class ActionStringHandler @Inject constructor(
|
|||
|
||||
private fun generateTempTarget(duration: Int, low: Double, high: Double) {
|
||||
if (duration != 0) {
|
||||
disposable += repository.runTransactionForResult(InsertTemporaryTargetAndCancelCurrentTransaction(
|
||||
disposable += repository.runTransactionForResult(InsertAndCancelCurrentTemporaryTargetTransaction(
|
||||
timestamp = System.currentTimeMillis(),
|
||||
duration = TimeUnit.MINUTES.toMillis(duration.toLong()),
|
||||
reason = TemporaryTarget.Reason.WEAR,
|
||||
|
|
|
@ -7,7 +7,6 @@ import info.nightscout.androidaps.Constants
|
|||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.data.IobTotal
|
||||
import info.nightscout.androidaps.data.MealData
|
||||
import info.nightscout.androidaps.interfaces.Profile
|
||||
import info.nightscout.androidaps.database.AppRepository
|
||||
import info.nightscout.androidaps.database.ValueWrapper
|
||||
import info.nightscout.androidaps.database.entities.Bolus
|
||||
|
@ -71,7 +70,6 @@ open class IobCobCalculatorPlugin @Inject constructor(
|
|||
private val disposable = CompositeDisposable()
|
||||
|
||||
private var iobTable = LongSparseArray<IobTotal>() // oldest at index 0
|
||||
private var absIobTable = LongSparseArray<IobTotal>() // oldest at index 0, absolute insulin in the body
|
||||
private var basalDataTable = LongSparseArray<BasalData>() // oldest at index 0
|
||||
|
||||
override var ads: AutosensDataStore = AutosensDataStore()
|
||||
|
@ -169,56 +167,37 @@ open class IobCobCalculatorPlugin @Inject constructor(
|
|||
return getBGDataFrom
|
||||
}
|
||||
|
||||
override fun calculateFromTreatmentsAndTemps(fromTime: Long, profile: Profile): IobTotal {
|
||||
synchronized(dataLock) {
|
||||
val now = System.currentTimeMillis()
|
||||
val time = ads.roundUpTime(fromTime)
|
||||
val cacheHit = iobTable[time]
|
||||
if (time < now && cacheHit != null) {
|
||||
//og.debug(">>> calculateFromTreatmentsAndTemps Cache hit " + new Date(time).toLocaleString());
|
||||
return cacheHit
|
||||
} // else log.debug(">>> calculateFromTreatmentsAndTemps Cache miss " + new Date(time).toLocaleString());
|
||||
val bolusIob = calculateIobFromBolusToTime(time).round()
|
||||
val basalIob = calculateIobToTimeFromTempBasalsIncludingConvertedExtended(time).round()
|
||||
// OpenAPSSMB only
|
||||
// Add expected zero temp basal for next 240 minutes
|
||||
val basalIobWithZeroTemp = basalIob.copy()
|
||||
val t = TemporaryBasal(
|
||||
timestamp = now + 60 * 1000L,
|
||||
duration = 240,
|
||||
rate = 0.0,
|
||||
isAbsolute = true,
|
||||
type = TemporaryBasal.Type.NORMAL)
|
||||
if (t.timestamp < time) {
|
||||
val calc = t.iobCalc(time, profile, activePlugin.activeInsulin)
|
||||
basalIobWithZeroTemp.plus(calc)
|
||||
}
|
||||
basalIob.iobWithZeroTemp = IobTotal.combine(bolusIob, basalIobWithZeroTemp).round()
|
||||
val iobTotal = IobTotal.combine(bolusIob, basalIob).round()
|
||||
if (time < System.currentTimeMillis()) {
|
||||
override fun calculateFromTreatmentsAndTemps(toTime: Long, profile: Profile): IobTotal {
|
||||
val now = System.currentTimeMillis()
|
||||
val time = ads.roundUpTime(toTime)
|
||||
val cacheHit = iobTable[time]
|
||||
if (time < now && cacheHit != null) {
|
||||
//og.debug(">>> calculateFromTreatmentsAndTemps Cache hit " + new Date(time).toLocaleString());
|
||||
return cacheHit
|
||||
} // else log.debug(">>> calculateFromTreatmentsAndTemps Cache miss " + new Date(time).toLocaleString());
|
||||
val bolusIob = calculateIobFromBolusToTime(time).round()
|
||||
val basalIob = calculateIobToTimeFromTempBasalsIncludingConvertedExtended(time).round()
|
||||
// OpenAPSSMB only
|
||||
// Add expected zero temp basal for next 240 minutes
|
||||
val basalIobWithZeroTemp = basalIob.copy()
|
||||
val t = TemporaryBasal(
|
||||
timestamp = now + 60 * 1000L,
|
||||
duration = 240,
|
||||
rate = 0.0,
|
||||
isAbsolute = true,
|
||||
type = TemporaryBasal.Type.NORMAL)
|
||||
if (t.timestamp < time) {
|
||||
val calc = t.iobCalc(time, profile, activePlugin.activeInsulin)
|
||||
basalIobWithZeroTemp.plus(calc)
|
||||
}
|
||||
basalIob.iobWithZeroTemp = IobTotal.combine(bolusIob, basalIobWithZeroTemp).round()
|
||||
val iobTotal = IobTotal.combine(bolusIob, basalIob).round()
|
||||
if (time < System.currentTimeMillis()) {
|
||||
synchronized(dataLock) {
|
||||
iobTable.put(time, iobTotal)
|
||||
}
|
||||
return iobTotal
|
||||
}
|
||||
}
|
||||
|
||||
override fun calculateAbsInsulinFromTreatmentsAndTemps(fromTime: Long): IobTotal {
|
||||
synchronized(dataLock) {
|
||||
val now = System.currentTimeMillis()
|
||||
val time = ads.roundUpTime(fromTime)
|
||||
val cacheHit = absIobTable[time]
|
||||
if (time < now && cacheHit != null) {
|
||||
//log.debug(">>> calculateFromTreatmentsAndTemps Cache hit " + new Date(time).toLocaleString());
|
||||
return cacheHit
|
||||
} // else log.debug(">>> calculateFromTreatmentsAndTemps Cache miss " + new Date(time).toLocaleString());
|
||||
val bolusIob = calculateIobFromBolusToTime(time).round()
|
||||
val basalIob = calculateAbsoluteIobTempBasals(time).round()
|
||||
val iobTotal = IobTotal.combine(bolusIob, basalIob).round()
|
||||
if (time < System.currentTimeMillis()) {
|
||||
absIobTable.put(time, iobTotal)
|
||||
}
|
||||
return iobTotal
|
||||
}
|
||||
return iobTotal
|
||||
}
|
||||
|
||||
private fun calculateFromTreatmentsAndTemps(time: Long, lastAutosensResult: AutosensResult, exercise_mode: Boolean, half_basal_exercise_target: Int, isTempTarget: Boolean): IobTotal {
|
||||
|
@ -246,28 +225,28 @@ open class IobCobCalculatorPlugin @Inject constructor(
|
|||
}
|
||||
|
||||
override fun getBasalData(profile: Profile, fromTime: Long): BasalData {
|
||||
synchronized(dataLock) {
|
||||
val now = System.currentTimeMillis()
|
||||
val time = ads.roundUpTime(fromTime)
|
||||
var retVal = basalDataTable[time]
|
||||
if (retVal == null) {
|
||||
//log.debug(">>> getBasalData Cache miss " + new Date(time).toLocaleString());
|
||||
retVal = BasalData()
|
||||
val tb = getTempBasalIncludingConvertedExtended(time)
|
||||
retVal.basal = profile.getBasal(time)
|
||||
if (tb != null) {
|
||||
retVal.isTempBasalRunning = true
|
||||
retVal.tempBasalAbsolute = tb.convertedToAbsolute(time, profile)
|
||||
} else {
|
||||
retVal.isTempBasalRunning = false
|
||||
retVal.tempBasalAbsolute = retVal.basal
|
||||
}
|
||||
if (time < now) {
|
||||
val now = System.currentTimeMillis()
|
||||
val time = ads.roundUpTime(fromTime)
|
||||
var retVal = basalDataTable[time]
|
||||
if (retVal == null) {
|
||||
//log.debug(">>> getBasalData Cache miss " + new Date(time).toLocaleString());
|
||||
retVal = BasalData()
|
||||
val tb = getTempBasalIncludingConvertedExtended(time)
|
||||
retVal.basal = profile.getBasal(time)
|
||||
if (tb != null) {
|
||||
retVal.isTempBasalRunning = true
|
||||
retVal.tempBasalAbsolute = tb.convertedToAbsolute(time, profile)
|
||||
} else {
|
||||
retVal.isTempBasalRunning = false
|
||||
retVal.tempBasalAbsolute = retVal.basal
|
||||
}
|
||||
if (time < now) {
|
||||
synchronized(dataLock) {
|
||||
basalDataTable.append(time, retVal)
|
||||
}
|
||||
} //else log.debug(">>> getBasalData Cache hit " + new Date(time).toLocaleString());
|
||||
return retVal
|
||||
}
|
||||
}
|
||||
} //else log.debug(">>> getBasalData Cache hit " + new Date(time).toLocaleString());
|
||||
return retVal
|
||||
}
|
||||
|
||||
override fun getLastAutosensDataWithWaitForCalculationFinish(reason: String): AutosensData? {
|
||||
|
@ -408,14 +387,6 @@ open class IobCobCalculatorPlugin @Inject constructor(
|
|||
break
|
||||
}
|
||||
}
|
||||
for (index in absIobTable.size() - 1 downTo 0) {
|
||||
if (absIobTable.keyAt(index) > time) {
|
||||
aapsLogger.debug(LTag.AUTOSENS, "Removing from absIobTable: " + dateUtil.dateAndTimeAndSecondsString(absIobTable.keyAt(index)))
|
||||
absIobTable.removeAt(index)
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
for (index in basalDataTable.size() - 1 downTo 0) {
|
||||
if (basalDataTable.keyAt(index) > time) {
|
||||
aapsLogger.debug(LTag.AUTOSENS, "Removing from basalDataTable: " + dateUtil.dateAndTimeAndSecondsString(basalDataTable.keyAt(index)))
|
||||
|
@ -459,8 +430,8 @@ open class IobCobCalculatorPlugin @Inject constructor(
|
|||
* Time range to the past for IOB calculation
|
||||
* @return milliseconds
|
||||
*/
|
||||
fun range(): Long = ((profileFunction.getProfile()?.dia
|
||||
?: Constants.defaultDIA) * 60 * 60 * 1000).toLong()
|
||||
fun range(): Long = ((/*overviewData.rangeToDisplay + */(profileFunction.getProfile()?.dia
|
||||
?: Constants.defaultDIA)) * 60 * 60 * 1000).toLong()
|
||||
|
||||
override fun calculateIobFromBolus(): IobTotal = calculateIobFromBolusToTime(dateUtil.now())
|
||||
|
||||
|
@ -533,6 +504,7 @@ open class IobCobCalculatorPlugin @Inject constructor(
|
|||
}
|
||||
|
||||
override fun getTempBasalIncludingConvertedExtended(timestamp: Long): TemporaryBasal? {
|
||||
|
||||
val tb = repository.getTemporaryBasalActiveAt(timestamp).blockingGet()
|
||||
if (tb is ValueWrapper.Existing) return tb.value
|
||||
val eb = repository.getExtendedBolusActiveAt(timestamp).blockingGet()
|
||||
|
@ -542,7 +514,7 @@ open class IobCobCalculatorPlugin @Inject constructor(
|
|||
return null
|
||||
}
|
||||
|
||||
override fun calculateAbsoluteIobTempBasals(toTime: Long): IobTotal {
|
||||
override fun calculateAbsoluteIobFromBaseBasals(toTime: Long): IobTotal {
|
||||
val total = IobTotal(toTime)
|
||||
var i = toTime - range()
|
||||
while (i < toTime) {
|
||||
|
@ -551,8 +523,7 @@ open class IobCobCalculatorPlugin @Inject constructor(
|
|||
i += T.mins(5).msecs()
|
||||
continue
|
||||
}
|
||||
val runningTBR = getTempBasalIncludingConvertedExtended(i)
|
||||
val running = runningTBR?.convertedToAbsolute(i, profile) ?: profile.getBasal(i)
|
||||
val running = profile.getBasal(i)
|
||||
val bolus = Bolus(
|
||||
timestamp = i,
|
||||
amount = running * 5.0 / 60.0,
|
||||
|
|
|
@ -82,7 +82,7 @@ class IobCobOref1Thread internal constructor(
|
|||
//log.debug("Locking calculateSensitivityData");
|
||||
val oldestTimeWithData = iobCobCalculatorPlugin.calculateDetectionStart(end, limitDataToOldestAvailable)
|
||||
if (bgDataReload) {
|
||||
iobCobCalculatorPlugin.ads.loadBgData(end, repository, aapsLogger, dateUtil)
|
||||
iobCobCalculatorPlugin.ads.loadBgData(end, repository, aapsLogger, dateUtil, rxBus)
|
||||
iobCobCalculatorPlugin.clearCache()
|
||||
}
|
||||
// work on local copy and set back when finished
|
||||
|
@ -99,7 +99,7 @@ class IobCobOref1Thread internal constructor(
|
|||
// start from oldest to be able sub cob
|
||||
for (i in bucketedData.size - 4 downTo 0) {
|
||||
val progress = i.toString() + if (buildHelper.isDev()) " ($from)" else ""
|
||||
rxBus.send(EventIobCalculationProgress(progress))
|
||||
rxBus.send(EventIobCalculationProgress(progress, cause))
|
||||
if (iobCobCalculatorPlugin.stopCalculationTrigger) {
|
||||
iobCobCalculatorPlugin.stopCalculationTrigger = false
|
||||
aapsLogger.debug(LTag.AUTOSENS, "Aborting calculation thread (trigger): $from")
|
||||
|
@ -325,7 +325,7 @@ class IobCobOref1Thread internal constructor(
|
|||
}.start()
|
||||
} finally {
|
||||
mWakeLock?.release()
|
||||
rxBus.send(EventIobCalculationProgress(""))
|
||||
rxBus.send(EventIobCalculationProgress("", cause))
|
||||
aapsLogger.debug(LTag.AUTOSENS, "AUTOSENSDATA thread ended: $from")
|
||||
profiler.log(LTag.AUTOSENS, "IobCobOref1Thread", start)
|
||||
}
|
||||
|
|
|
@ -81,7 +81,7 @@ class IobCobThread @Inject internal constructor(
|
|||
//log.debug("Locking calculateSensitivityData");
|
||||
val oldestTimeWithData = iobCobCalculatorPlugin.calculateDetectionStart(end, limitDataToOldestAvailable)
|
||||
if (bgDataReload) {
|
||||
iobCobCalculatorPlugin.ads.loadBgData(end, repository, aapsLogger, dateUtil)
|
||||
iobCobCalculatorPlugin.ads.loadBgData(end, repository, aapsLogger, dateUtil, rxBus)
|
||||
iobCobCalculatorPlugin.clearCache()
|
||||
}
|
||||
// work on local copy and set back when finished
|
||||
|
@ -98,7 +98,7 @@ class IobCobThread @Inject internal constructor(
|
|||
// start from oldest to be able sub cob
|
||||
for (i in bucketedData.size - 4 downTo 0) {
|
||||
val progress = i.toString() + if (buildHelper.isDev()) " ($from)" else ""
|
||||
rxBus.send(EventIobCalculationProgress(progress))
|
||||
rxBus.send(EventIobCalculationProgress(progress, cause))
|
||||
if (iobCobCalculatorPlugin.stopCalculationTrigger) {
|
||||
iobCobCalculatorPlugin.stopCalculationTrigger = false
|
||||
aapsLogger.debug(LTag.AUTOSENS, "Aborting calculation thread (trigger): $from")
|
||||
|
@ -272,7 +272,7 @@ class IobCobThread @Inject internal constructor(
|
|||
}.start()
|
||||
} finally {
|
||||
mWakeLock?.release()
|
||||
rxBus.send(EventIobCalculationProgress(""))
|
||||
rxBus.send(EventIobCalculationProgress("", cause))
|
||||
aapsLogger.debug(LTag.AUTOSENS, "AUTOSENSDATA thread ended: $from")
|
||||
profiler.log(LTag.AUTOSENS, "IobCobThread", start)
|
||||
}
|
||||
|
|
|
@ -2,4 +2,4 @@ package info.nightscout.androidaps.plugins.iob.iobCobCalculator.events
|
|||
|
||||
import info.nightscout.androidaps.events.Event
|
||||
|
||||
class EventIobCalculationProgress(var progress: String) : Event()
|
||||
class EventIobCalculationProgress(val progress: String, val cause: Event?) : Event()
|
|
@ -54,6 +54,9 @@ class LocalProfileFragment : DaggerFragment() {
|
|||
private val save = Runnable {
|
||||
doEdit()
|
||||
basalView?.updateLabel(resourceHelper.gs(R.string.basal_label) + ": " + sumLabel())
|
||||
localProfilePlugin.profile?.getSpecificProfile(spinner?.selectedItem.toString())?.let {
|
||||
binding.basalGraph.show(ProfileSealed.Pure(it))
|
||||
}
|
||||
}
|
||||
|
||||
private val textWatch = object : TextWatcher {
|
||||
|
@ -67,7 +70,7 @@ class LocalProfileFragment : DaggerFragment() {
|
|||
}
|
||||
|
||||
private fun sumLabel(): String {
|
||||
val profile = localProfilePlugin.createProfileStore().getDefaultProfile()
|
||||
val profile = localProfilePlugin.profile?.getDefaultProfile()
|
||||
val sum = profile?.let { ProfileSealed.Pure(profile).baseBasalSum() } ?: 0.0
|
||||
return " ∑" + DecimalFormatter.to2Decimal(sum) + resourceHelper.gs(R.string.insulin_unit_shortname)
|
||||
}
|
||||
|
@ -124,7 +127,7 @@ class LocalProfileFragment : DaggerFragment() {
|
|||
binding.dia.setParams(currentProfile.dia, hardLimits.minDia(), hardLimits.maxDia(), 0.1, DecimalFormat("0.0"), false, binding.save, textWatch)
|
||||
binding.dia.tag = "LP_DIA"
|
||||
TimeListEdit(context, aapsLogger, dateUtil, view, R.id.ic, "IC", resourceHelper.gs(R.string.ic_label), currentProfile.ic, null, hardLimits.minIC(), hardLimits.maxIC(), 0.1, DecimalFormat("0.0"), save)
|
||||
basalView = TimeListEdit(context, aapsLogger, dateUtil, view, R.id.basal, "BASAL", resourceHelper.gs(R.string.basal_label) + ": " + sumLabel(), currentProfile.basal, null, pumpDescription.basalMinimumRate, 10.0, 0.01, DecimalFormat("0.00"), save)
|
||||
basalView = TimeListEdit(context, aapsLogger, dateUtil, view, R.id.basal_holder, "BASAL", resourceHelper.gs(R.string.basal_label) + ": " + sumLabel(), currentProfile.basal, null, pumpDescription.basalMinimumRate, 10.0, 0.01, DecimalFormat("0.00"), save)
|
||||
if (units == Constants.MGDL) {
|
||||
TimeListEdit(context, aapsLogger, dateUtil, view, R.id.isf, "ISF", resourceHelper.gs(R.string.isf_label), currentProfile.isf, null, HardLimits.MIN_ISF, HardLimits.MAX_ISF, 1.0, DecimalFormat("0"), save)
|
||||
TimeListEdit(context, aapsLogger, dateUtil, view, R.id.target, "TARGET", resourceHelper.gs(R.string.target_label), currentProfile.targetLow, currentProfile.targetHigh, HardLimits.VERY_HARD_LIMIT_TARGET_BG[0].toDouble(), HardLimits.VERY_HARD_LIMIT_TARGET_BG[1].toDouble(), 1.0, DecimalFormat("0"), save)
|
||||
|
@ -162,6 +165,9 @@ class LocalProfileFragment : DaggerFragment() {
|
|||
}
|
||||
}
|
||||
})
|
||||
localProfilePlugin.profile?.getSpecificProfile(spinner?.selectedItem.toString())?.let {
|
||||
binding.basalGraph.show(ProfileSealed.Pure(it))
|
||||
}
|
||||
|
||||
binding.profileAdd.setOnClickListener {
|
||||
if (localProfilePlugin.isEdited) {
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
package info.nightscout.androidaps.plugins.profile.local
|
||||
|
||||
import android.content.Context
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
import androidx.work.Worker
|
||||
import androidx.work.WorkerParameters
|
||||
import androidx.work.workDataOf
|
||||
import dagger.android.HasAndroidInjector
|
||||
import info.nightscout.androidaps.Constants
|
||||
import info.nightscout.androidaps.R
|
||||
|
@ -12,7 +16,8 @@ import info.nightscout.androidaps.interfaces.*
|
|||
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.nsclient.NSUpload
|
||||
import info.nightscout.androidaps.plugins.profile.local.events.EventLocalProfileChanged
|
||||
import info.nightscout.androidaps.receivers.DataWorker
|
||||
import info.nightscout.androidaps.utils.DateUtil
|
||||
import info.nightscout.androidaps.utils.DecimalFormatter
|
||||
import info.nightscout.androidaps.utils.HardLimits
|
||||
|
@ -22,6 +27,7 @@ import info.nightscout.androidaps.utils.sharedPreferences.SP
|
|||
import org.json.JSONArray
|
||||
import org.json.JSONException
|
||||
import org.json.JSONObject
|
||||
import java.lang.Integer.min
|
||||
import java.util.*
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
@ -35,7 +41,6 @@ class LocalProfilePlugin @Inject constructor(
|
|||
resourceHelper: ResourceHelper,
|
||||
private val sp: SP,
|
||||
private val profileFunction: ProfileFunction,
|
||||
private val nsUpload: NSUpload,
|
||||
private val activePlugin: ActivePlugin,
|
||||
private val hardLimits: HardLimits,
|
||||
private val dateUtil: DateUtil
|
||||
|
@ -134,6 +139,7 @@ class LocalProfilePlugin @Inject constructor(
|
|||
}
|
||||
sp.putInt(Constants.LOCAL_PROFILE + "_profiles", numOfProfiles)
|
||||
|
||||
sp.putLong(R.string.key_local_profile_last_change, dateUtil.now())
|
||||
createAndStoreConvertedProfile()
|
||||
isEdited = false
|
||||
aapsLogger.debug(LTag.PROFILE, "Storing settings: " + rawProfile?.data.toString())
|
||||
|
@ -143,12 +149,9 @@ class LocalProfilePlugin @Inject constructor(
|
|||
val name = it.name ?: "."
|
||||
if (name.contains(".")) namesOK = false
|
||||
}
|
||||
if (namesOK)
|
||||
rawProfile?.let { nsUpload.uploadProfileStore(it.data) }
|
||||
else
|
||||
activity?.let {
|
||||
OKDialog.show(it, "", resourceHelper.gs(R.string.profilenamecontainsdot))
|
||||
}
|
||||
if (!namesOK) activity?.let {
|
||||
OKDialog.show(it, "", resourceHelper.gs(R.string.profilenamecontainsdot))
|
||||
}
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
|
@ -167,61 +170,64 @@ class LocalProfilePlugin @Inject constructor(
|
|||
p.dia = sp.getDouble(localProfileNumbered + "dia", Constants.defaultDIA)
|
||||
try {
|
||||
p.ic = JSONArray(sp.getString(localProfileNumbered + "ic", defaultArray))
|
||||
} catch (e1: JSONException) {
|
||||
try {
|
||||
p.ic = JSONArray(defaultArray)
|
||||
} catch (ignored: JSONException) {
|
||||
}
|
||||
aapsLogger.error("Exception", e1)
|
||||
}
|
||||
|
||||
try {
|
||||
p.isf = JSONArray(sp.getString(localProfileNumbered + "isf", defaultArray))
|
||||
} catch (e1: JSONException) {
|
||||
try {
|
||||
p.isf = JSONArray(defaultArray)
|
||||
} catch (ignored: JSONException) {
|
||||
}
|
||||
aapsLogger.error("Exception", e1)
|
||||
}
|
||||
|
||||
try {
|
||||
p.basal = JSONArray(sp.getString(localProfileNumbered + "basal", defaultArray))
|
||||
} catch (e1: JSONException) {
|
||||
try {
|
||||
p.basal = JSONArray(defaultArray)
|
||||
} catch (ignored: JSONException) {
|
||||
}
|
||||
aapsLogger.error("Exception", e1)
|
||||
}
|
||||
|
||||
try {
|
||||
p.targetLow = JSONArray(sp.getString(localProfileNumbered + "targetlow", defaultArray))
|
||||
} catch (e1: JSONException) {
|
||||
try {
|
||||
p.targetLow = JSONArray(defaultArray)
|
||||
} catch (ignored: JSONException) {
|
||||
}
|
||||
aapsLogger.error("Exception", e1)
|
||||
}
|
||||
|
||||
try {
|
||||
p.targetHigh = JSONArray(sp.getString(localProfileNumbered + "targethigh", defaultArray))
|
||||
} catch (e1: JSONException) {
|
||||
try {
|
||||
p.targetHigh = JSONArray(defaultArray)
|
||||
} catch (ignored: JSONException) {
|
||||
}
|
||||
aapsLogger.error("Exception", e1)
|
||||
profiles.add(p)
|
||||
} catch (e: JSONException) {
|
||||
aapsLogger.error("Exception", e)
|
||||
}
|
||||
|
||||
profiles.add(p)
|
||||
}
|
||||
// create at least one profile if doesn't exist
|
||||
if (profiles.size < 1) profiles.add(defaultProfile())
|
||||
isEdited = false
|
||||
numOfProfiles = profiles.size
|
||||
createAndStoreConvertedProfile()
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
fun loadFromStore(store: ProfileStore) {
|
||||
try {
|
||||
val newProfiles: ArrayList<SingleProfile> = ArrayList()
|
||||
for (p in store.getProfileList()) {
|
||||
store.getSpecificProfile(p.toString())?.let {
|
||||
val sp = copyFrom(it, p.toString())
|
||||
sp.name = p.toString()
|
||||
newProfiles.add(sp)
|
||||
}
|
||||
}
|
||||
if (newProfiles.size > 0) {
|
||||
profiles = newProfiles
|
||||
numOfProfiles = profiles.size
|
||||
currentProfileIndex = 0
|
||||
isEdited = false
|
||||
createAndStoreConvertedProfile()
|
||||
aapsLogger.debug(LTag.PROFILE, "Accepted ${profiles.size} profiles")
|
||||
rxBus.send(EventLocalProfileChanged())
|
||||
} else
|
||||
aapsLogger.debug(LTag.PROFILE, "ProfileStore not accepted")
|
||||
} catch (e: Exception) {
|
||||
aapsLogger.error("Error loading ProfileStore", e)
|
||||
}
|
||||
}
|
||||
|
||||
private fun defaultProfile(): SingleProfile =
|
||||
SingleProfile().also { p ->
|
||||
p.name = Constants.LOCAL_PROFILE
|
||||
p.mgdl = profileFunction.getUnits() == GlucoseUnit.MGDL
|
||||
p.dia = Constants.defaultDIA
|
||||
try {
|
||||
p.ic = JSONArray(defaultArray)
|
||||
p.isf = JSONArray(defaultArray)
|
||||
p.basal = JSONArray(defaultArray)
|
||||
p.targetLow = JSONArray(defaultArray)
|
||||
p.targetHigh = JSONArray(defaultArray)
|
||||
} catch (e: JSONException) {
|
||||
aapsLogger.error("Exception", e)
|
||||
}
|
||||
}
|
||||
|
||||
fun copyFrom(pureProfile: PureProfile, newName: String): SingleProfile {
|
||||
var verifiedName = newName
|
||||
if (rawProfile?.getSpecificProfile(newName) != null) {
|
||||
|
@ -364,7 +370,8 @@ class LocalProfilePlugin @Inject constructor(
|
|||
}
|
||||
}
|
||||
if (numOfProfiles > 0) json.put("defaultProfile", currentProfile()?.name)
|
||||
json.put("startDate", dateUtil.toISOAsUTC(dateUtil.now()))
|
||||
val startDate = sp.getLong(R.string.key_local_profile_last_change, dateUtil.now())
|
||||
json.put("startDate", dateUtil.toISOAsUTC(startDate))
|
||||
json.put("store", store)
|
||||
} catch (e: JSONException) {
|
||||
aapsLogger.error("Unhandled exception", e)
|
||||
|
@ -380,4 +387,44 @@ class LocalProfilePlugin @Inject constructor(
|
|||
get() = rawProfile?.getDefaultProfile()?.let {
|
||||
DecimalFormatter.to2Decimal(ProfileSealed.Pure(it).percentageBasalSum()) + "U "
|
||||
} ?: "INVALID"
|
||||
|
||||
// cannot be inner class because of needed injection
|
||||
class NSProfileWorker(
|
||||
context: Context,
|
||||
params: WorkerParameters
|
||||
) : Worker(context, params) {
|
||||
|
||||
@Inject lateinit var injector: HasAndroidInjector
|
||||
@Inject lateinit var aapsLogger: AAPSLogger
|
||||
@Inject lateinit var rxBus: RxBusWrapper
|
||||
@Inject lateinit var dateUtil: DateUtil
|
||||
@Inject lateinit var dataWorker: DataWorker
|
||||
@Inject lateinit var sp: SP
|
||||
@Inject lateinit var config: Config
|
||||
@Inject lateinit var localProfilePlugin: LocalProfilePlugin
|
||||
|
||||
init {
|
||||
(context.applicationContext as HasAndroidInjector).androidInjector().inject(this)
|
||||
}
|
||||
|
||||
override fun doWork(): Result {
|
||||
val profileJson = dataWorker.pickupJSONObject(inputData.getLong(DataWorker.STORE_KEY, -1))
|
||||
?: return Result.failure(workDataOf("Error" to "missing input data"))
|
||||
if (sp.getBoolean(R.string.key_ns_receive_profile_store, false) || config.NSCLIENT) {
|
||||
val store = ProfileStore(injector, profileJson, dateUtil)
|
||||
val startDate = store.getStartDate()
|
||||
val lastLocalChange = sp.getLong(R.string.key_local_profile_last_change, 0)
|
||||
aapsLogger.debug(LTag.PROFILE, "Received profileStore: StartDate: $startDate Local last modification: $lastLocalChange")
|
||||
@Suppress("LiftReturnOrAssignment")
|
||||
if (startDate > lastLocalChange || startDate % 1000 == 0L) {// whole second means edited in NS
|
||||
localProfilePlugin.loadFromStore(store)
|
||||
aapsLogger.debug(LTag.PROFILE, "Received profileStore: $profileJson")
|
||||
return Result.success(workDataOf("Data" to profileJson.toString().substring(0..min(5000, profileJson.length()))))
|
||||
} else
|
||||
return Result.success(workDataOf("Result" to "Unchanged. Ignoring"))
|
||||
}
|
||||
return Result.success(workDataOf("Result" to "Sync not enabled"))
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,170 +0,0 @@
|
|||
package info.nightscout.androidaps.plugins.profile.ns
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.AdapterView
|
||||
import android.widget.ArrayAdapter
|
||||
import dagger.android.support.DaggerFragment
|
||||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.data.ProfileSealed
|
||||
import info.nightscout.androidaps.database.entities.UserEntry.Action
|
||||
import info.nightscout.androidaps.database.entities.UserEntry.Sources
|
||||
import info.nightscout.androidaps.database.entities.ValueWithUnit
|
||||
import info.nightscout.androidaps.databinding.NsprofileFragmentBinding
|
||||
import info.nightscout.androidaps.interfaces.ActivePlugin
|
||||
import info.nightscout.androidaps.interfaces.Config
|
||||
import info.nightscout.androidaps.interfaces.ProfileFunction
|
||||
import info.nightscout.androidaps.logging.UserEntryLogger
|
||||
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
||||
import info.nightscout.androidaps.plugins.profile.ns.events.EventNSProfileUpdateGUI
|
||||
import info.nightscout.androidaps.utils.DateUtil
|
||||
import info.nightscout.androidaps.utils.DecimalFormatter
|
||||
import info.nightscout.androidaps.utils.FabricPrivacy
|
||||
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
||||
import io.reactivex.disposables.CompositeDisposable
|
||||
import io.reactivex.rxkotlin.plusAssign
|
||||
import javax.inject.Inject
|
||||
|
||||
class NSProfileFragment : DaggerFragment() {
|
||||
|
||||
@Inject lateinit var rxBus: RxBusWrapper
|
||||
@Inject lateinit var resourceHelper: ResourceHelper
|
||||
@Inject lateinit var fabricPrivacy: FabricPrivacy
|
||||
@Inject lateinit var profileFunction: ProfileFunction
|
||||
@Inject lateinit var nsProfilePlugin: NSProfilePlugin
|
||||
@Inject lateinit var aapsSchedulers: AapsSchedulers
|
||||
@Inject lateinit var dateUtil: DateUtil
|
||||
@Inject lateinit var uel: UserEntryLogger
|
||||
@Inject lateinit var activePlugin: ActivePlugin
|
||||
@Inject lateinit var config: Config
|
||||
|
||||
private var disposable: CompositeDisposable = CompositeDisposable()
|
||||
|
||||
private var _binding: NsprofileFragmentBinding? = null
|
||||
|
||||
// This property is only valid between onCreateView and
|
||||
// onDestroyView.
|
||||
private val binding get() = _binding!!
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
|
||||
savedInstanceState: Bundle?): View {
|
||||
_binding = NsprofileFragmentBinding.inflate(inflater, container, false)
|
||||
return binding.root
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
binding.profileviewer.closeLayout.close.visibility = View.GONE // not needed for fragment
|
||||
|
||||
binding.profileswitch.setOnClickListener {
|
||||
val name = binding.spinner.selectedItem?.toString() ?: ""
|
||||
nsProfilePlugin.profile?.let { store ->
|
||||
store.getSpecificProfile(name)?.let {
|
||||
activity?.let { activity ->
|
||||
OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.nsprofile),
|
||||
resourceHelper.gs(R.string.activate_profile) + ": " + name + " ?", Runnable {
|
||||
uel.log(Action.PROFILE_SWITCH, Sources.NSProfile,
|
||||
ValueWithUnit.SimpleString(name),
|
||||
ValueWithUnit.Percent(100))
|
||||
profileFunction.createProfileSwitch(store, name, 0, 100, 0, dateUtil.now())
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
binding.spinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
|
||||
override fun onNothingSelected(parent: AdapterView<*>?) {
|
||||
if (_binding == null) return
|
||||
binding.profileviewer.invalidprofile.visibility = View.VISIBLE
|
||||
binding.profileviewer.noprofile.visibility = View.VISIBLE
|
||||
binding.profileviewer.units.text = ""
|
||||
binding.profileviewer.dia.text = ""
|
||||
binding.profileviewer.activeprofile.text = ""
|
||||
binding.profileviewer.ic.text = ""
|
||||
binding.profileviewer.isf.text = ""
|
||||
binding.profileviewer.basal.text = ""
|
||||
binding.profileviewer.basaltotal.text = ""
|
||||
binding.profileviewer.target.text = ""
|
||||
binding.profileswitch.visibility = View.GONE
|
||||
}
|
||||
|
||||
override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
|
||||
if (_binding == null) return
|
||||
val name = binding.spinner.getItemAtPosition(position).toString()
|
||||
|
||||
binding.profileswitch.visibility = View.GONE
|
||||
|
||||
nsProfilePlugin.profile?.let { store ->
|
||||
store.getSpecificProfile(name)?.let { profile ->
|
||||
if (_binding == null) return
|
||||
val pss = ProfileSealed.Pure(profile)
|
||||
binding.profileviewer.units.text = pss.units.asText
|
||||
binding.profileviewer.dia.text = resourceHelper.gs(R.string.format_hours, pss.dia)
|
||||
binding.profileviewer.activeprofile.text = name
|
||||
binding.profileviewer.ic.text = pss.getIcList(resourceHelper, dateUtil)
|
||||
binding.profileviewer.isf.text = pss.getIsfList(resourceHelper, dateUtil)
|
||||
binding.profileviewer.basal.text = pss.getBasalList(resourceHelper, dateUtil)
|
||||
binding.profileviewer.basaltotal.text = String.format(resourceHelper.gs(R.string.profile_total), DecimalFormatter.to2Decimal(pss.baseBasalSum()))
|
||||
binding.profileviewer.target.text = pss.getTargetList(resourceHelper, dateUtil)
|
||||
binding.profileviewer.basalGraph.show(pss)
|
||||
if (pss.isValid("NSProfileFragment", activePlugin.activePump, config, resourceHelper, rxBus)) {
|
||||
binding.profileviewer.invalidprofile.visibility = View.GONE
|
||||
binding.profileswitch.visibility = View.VISIBLE
|
||||
} else {
|
||||
binding.profileviewer.invalidprofile.visibility = View.VISIBLE
|
||||
binding.profileswitch.visibility = View.GONE
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
disposable += rxBus
|
||||
.toObservable(EventNSProfileUpdateGUI::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
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
fun updateGUI() {
|
||||
if (_binding == null) return
|
||||
binding.profileviewer.noprofile.visibility = View.VISIBLE
|
||||
|
||||
nsProfilePlugin.profile?.let { profileStore ->
|
||||
context?.let { context ->
|
||||
val profileList = profileStore.getProfileList()
|
||||
val adapter = ArrayAdapter(context, R.layout.spinner_centered, profileList)
|
||||
binding.spinner.adapter = adapter
|
||||
// set selected to actual profile
|
||||
for (p in profileList.indices) {
|
||||
if (profileList[p] == profileFunction.getProfileName())
|
||||
binding.spinner.setSelection(p)
|
||||
}
|
||||
binding.profileviewer.noprofile.visibility = View.GONE
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,110 +0,0 @@
|
|||
package info.nightscout.androidaps.plugins.profile.ns
|
||||
|
||||
import android.content.Context
|
||||
import androidx.work.Worker
|
||||
import androidx.work.WorkerParameters
|
||||
import androidx.work.workDataOf
|
||||
import dagger.android.HasAndroidInjector
|
||||
import info.nightscout.androidaps.interfaces.Config
|
||||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.events.EventProfileStoreChanged
|
||||
import info.nightscout.androidaps.interfaces.PluginBase
|
||||
import info.nightscout.androidaps.interfaces.PluginDescription
|
||||
import info.nightscout.androidaps.interfaces.PluginType
|
||||
import info.nightscout.androidaps.interfaces.ProfileSource
|
||||
import info.nightscout.androidaps.interfaces.ProfileStore
|
||||
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.nsclient.events.EventNSClientRestart
|
||||
import info.nightscout.androidaps.plugins.profile.ns.events.EventNSProfileUpdateGUI
|
||||
import info.nightscout.androidaps.receivers.DataWorker
|
||||
import info.nightscout.androidaps.utils.DateUtil
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
||||
import org.json.JSONObject
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
class NSProfilePlugin @Inject constructor(
|
||||
injector: HasAndroidInjector,
|
||||
aapsLogger: AAPSLogger,
|
||||
private val rxBus: RxBusWrapper,
|
||||
resourceHelper: ResourceHelper,
|
||||
private val sp: SP,
|
||||
private val dateUtil: DateUtil,
|
||||
config: Config
|
||||
) : PluginBase(PluginDescription()
|
||||
.mainType(PluginType.PROFILE)
|
||||
.fragmentClass(NSProfileFragment::class.java.name)
|
||||
.pluginIcon(R.drawable.ic_nightscout_profile)
|
||||
.pluginName(R.string.nsprofile)
|
||||
.shortName(R.string.profileviewer_shortname)
|
||||
.alwaysEnabled(config.NSCLIENT)
|
||||
.alwaysVisible(config.NSCLIENT)
|
||||
.showInList(!config.NSCLIENT)
|
||||
.description(R.string.description_profile_nightscout),
|
||||
aapsLogger, resourceHelper, injector
|
||||
), ProfileSource {
|
||||
|
||||
override var profile: ProfileStore? = null
|
||||
|
||||
override val profileName: String?
|
||||
get() = profile?.getDefaultProfileName()
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
loadNSProfile()
|
||||
}
|
||||
|
||||
private fun storeNSProfile() {
|
||||
sp.putString("profile", profile!!.data.toString())
|
||||
aapsLogger.debug(LTag.PROFILE, "Storing profile")
|
||||
}
|
||||
|
||||
private fun loadNSProfile() {
|
||||
aapsLogger.debug(LTag.PROFILE, "Loading stored profile")
|
||||
val profileString = sp.getStringOrNull("profile", null)
|
||||
if (profileString != null) {
|
||||
aapsLogger.debug(LTag.PROFILE, "Loaded profile: $profileString")
|
||||
profile = ProfileStore(injector, JSONObject(profileString), dateUtil)
|
||||
} else {
|
||||
aapsLogger.debug(LTag.PROFILE, "Stored profile not found")
|
||||
// force restart of nsclient to fetch profile
|
||||
rxBus.send(EventNSClientRestart())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// cannot be inner class because of needed injection
|
||||
class NSProfileWorker(
|
||||
context: Context,
|
||||
params: WorkerParameters
|
||||
) : Worker(context, params) {
|
||||
|
||||
@Inject lateinit var injector: HasAndroidInjector
|
||||
@Inject lateinit var nsProfilePlugin: NSProfilePlugin
|
||||
@Inject lateinit var aapsLogger: AAPSLogger
|
||||
@Inject lateinit var rxBus: RxBusWrapper
|
||||
@Inject lateinit var dateUtil: DateUtil
|
||||
@Inject lateinit var dataWorker: DataWorker
|
||||
|
||||
init {
|
||||
(context.applicationContext as HasAndroidInjector).androidInjector().inject(this)
|
||||
}
|
||||
|
||||
override fun doWork(): Result {
|
||||
val profileString = dataWorker.pickupJSONObject(inputData.getLong(DataWorker.STORE_KEY, -1))
|
||||
?: return Result.failure(workDataOf("Error" to "missing input data"))
|
||||
nsProfilePlugin.profile = ProfileStore(injector, profileString, dateUtil)
|
||||
nsProfilePlugin.storeNSProfile()
|
||||
if (nsProfilePlugin.isEnabled()) {
|
||||
rxBus.send(EventProfileStoreChanged())
|
||||
rxBus.send(EventNSProfileUpdateGUI())
|
||||
}
|
||||
aapsLogger.debug(LTag.PROFILE, "Received profileStore: ${nsProfilePlugin.profile}")
|
||||
return Result.success()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,5 +0,0 @@
|
|||
package info.nightscout.androidaps.plugins.profile.ns.events
|
||||
|
||||
import info.nightscout.androidaps.events.EventUpdateGui
|
||||
|
||||
class EventNSProfileUpdateGUI : EventUpdateGui()
|
|
@ -3,7 +3,6 @@ package info.nightscout.androidaps.plugins.pump.mdi
|
|||
import dagger.android.HasAndroidInjector
|
||||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.data.DetailedBolusInfo
|
||||
import info.nightscout.androidaps.interfaces.Profile
|
||||
import info.nightscout.androidaps.data.PumpEnactResult
|
||||
import info.nightscout.androidaps.interfaces.*
|
||||
import info.nightscout.androidaps.logging.AAPSLogger
|
||||
|
@ -12,7 +11,6 @@ import info.nightscout.androidaps.plugins.common.ManufacturerType
|
|||
import info.nightscout.androidaps.plugins.pump.common.defs.PumpType
|
||||
import info.nightscout.androidaps.utils.DateUtil
|
||||
import info.nightscout.androidaps.utils.InstanceId.instanceId
|
||||
import info.nightscout.androidaps.utils.T
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||
import org.json.JSONException
|
||||
import org.json.JSONObject
|
||||
|
@ -61,7 +59,7 @@ class MDIPlugin @Inject constructor(
|
|||
override fun waitForDisconnectionInSeconds(): Int = 0
|
||||
override fun stopConnecting() {}
|
||||
override fun getPumpStatus(reason: String) {}
|
||||
override fun setNewBasalProfile(profile: Profile): PumpEnactResult = PumpEnactResult(injector).success(true)
|
||||
override fun setNewBasalProfile(profile: Profile): PumpEnactResult = PumpEnactResult(injector).success(true).enacted(true)
|
||||
override fun isThisProfileSet(profile: Profile): Boolean = false
|
||||
override fun lastDataTime(): Long = System.currentTimeMillis()
|
||||
override val baseBasalRate: Double = 0.0
|
||||
|
@ -84,7 +82,7 @@ class MDIPlugin @Inject constructor(
|
|||
pumpSerial = serialNumber())
|
||||
if (detailedBolusInfo.carbs > 0)
|
||||
pumpSync.syncCarbsWithTimestamp(
|
||||
timestamp = detailedBolusInfo.timestamp + T.mins(detailedBolusInfo.carbTime.toLong()).msecs(),
|
||||
timestamp = detailedBolusInfo.carbsTimestamp ?: detailedBolusInfo.timestamp,
|
||||
amount = detailedBolusInfo.carbs,
|
||||
pumpId = null,
|
||||
pumpType = PumpType.MDI,
|
||||
|
|
|
@ -4,12 +4,12 @@ import android.os.SystemClock
|
|||
import androidx.preference.PreferenceFragmentCompat
|
||||
import androidx.preference.SwitchPreference
|
||||
import dagger.android.HasAndroidInjector
|
||||
import info.nightscout.androidaps.interfaces.Config
|
||||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.data.DetailedBolusInfo
|
||||
import info.nightscout.androidaps.interfaces.Profile
|
||||
import info.nightscout.androidaps.data.PumpEnactResult
|
||||
import info.nightscout.androidaps.events.EventPreferenceChange
|
||||
import info.nightscout.androidaps.extensions.convertedToAbsolute
|
||||
import info.nightscout.androidaps.extensions.plannedRemainingMinutes
|
||||
import info.nightscout.androidaps.interfaces.*
|
||||
import info.nightscout.androidaps.logging.AAPSLogger
|
||||
import info.nightscout.androidaps.logging.LTag
|
||||
|
@ -25,8 +25,6 @@ import info.nightscout.androidaps.utils.FabricPrivacy
|
|||
import info.nightscout.androidaps.utils.InstanceId.instanceId
|
||||
import info.nightscout.androidaps.utils.T
|
||||
import info.nightscout.androidaps.utils.TimeChangeType
|
||||
import info.nightscout.androidaps.extensions.convertedToAbsolute
|
||||
import info.nightscout.androidaps.extensions.plannedRemainingMinutes
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
||||
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
||||
|
@ -139,7 +137,6 @@ open class VirtualPumpPlugin @Inject constructor(
|
|||
override fun isHandshakeInProgress(): Boolean = false
|
||||
|
||||
override fun connect(reason: String) {
|
||||
//if (!Config.NSCLIENT) NSUpload.uploadDeviceStatus()
|
||||
lastDataTime = System.currentTimeMillis()
|
||||
}
|
||||
|
||||
|
@ -152,16 +149,14 @@ open class VirtualPumpPlugin @Inject constructor(
|
|||
|
||||
override fun setNewBasalProfile(profile: Profile): PumpEnactResult {
|
||||
lastDataTime = System.currentTimeMillis()
|
||||
rxBus.send(EventNewNotification(Notification(Notification.PROFILE_SET_OK, resourceHelper.gs(R.string.profile_set_ok), Notification.INFO, 60)))
|
||||
// Do nothing here. we are using database profile
|
||||
val result = PumpEnactResult(injector)
|
||||
result.success = true
|
||||
val notification = Notification(Notification.PROFILE_SET_OK, resourceHelper.gs(R.string.profile_set_ok), Notification.INFO, 60)
|
||||
rxBus.send(EventNewNotification(notification))
|
||||
return result
|
||||
return PumpEnactResult(injector).success(true).enacted(true)
|
||||
}
|
||||
|
||||
override fun isThisProfileSet(profile: Profile): Boolean {
|
||||
return true
|
||||
val running = pumpSync.expectedPumpState().profile
|
||||
return running?.isEqual(profile) ?: false
|
||||
}
|
||||
|
||||
override fun lastDataTime(): Long {
|
||||
|
@ -211,7 +206,7 @@ open class VirtualPumpPlugin @Inject constructor(
|
|||
pumpSerial = serialNumber())
|
||||
if (detailedBolusInfo.carbs > 0)
|
||||
pumpSync.syncCarbsWithTimestamp(
|
||||
timestamp = detailedBolusInfo.timestamp + T.mins(detailedBolusInfo.carbTime.toLong()).msecs(),
|
||||
timestamp = detailedBolusInfo.carbsTimestamp ?: detailedBolusInfo.timestamp,
|
||||
amount = detailedBolusInfo.carbs,
|
||||
pumpId = null,
|
||||
pumpType = pumpType ?: PumpType.GENERIC_AAPS,
|
||||
|
@ -400,7 +395,7 @@ open class VirtualPumpPlugin @Inject constructor(
|
|||
aapsLogger.debug(LTag.PUMP, "Pump in configuration: $pumpType, PumpType object: $pumpTypeNew")
|
||||
if (this.pumpType == pumpTypeNew) return
|
||||
aapsLogger.debug(LTag.PUMP, "New pump configuration found ($pumpTypeNew), changing from previous (${this.pumpType})")
|
||||
pumpDescription.setPumpDescription(pumpTypeNew)
|
||||
pumpDescription.fillFor(pumpTypeNew)
|
||||
this.pumpType = pumpTypeNew
|
||||
}
|
||||
|
||||
|
|
|
@ -8,7 +8,6 @@ import androidx.work.Worker
|
|||
import androidx.work.WorkerParameters
|
||||
import androidx.work.workDataOf
|
||||
import dagger.android.HasAndroidInjector
|
||||
import info.nightscout.androidaps.interfaces.Config
|
||||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.activities.RequestDexcomPermissionActivity
|
||||
import info.nightscout.androidaps.database.AppRepository
|
||||
|
@ -18,10 +17,8 @@ import info.nightscout.androidaps.database.entities.UserEntry.Action
|
|||
import info.nightscout.androidaps.database.entities.UserEntry.Sources
|
||||
import info.nightscout.androidaps.database.entities.ValueWithUnit
|
||||
import info.nightscout.androidaps.database.transactions.CgmSourceTransaction
|
||||
import info.nightscout.androidaps.interfaces.BgSource
|
||||
import info.nightscout.androidaps.interfaces.PluginBase
|
||||
import info.nightscout.androidaps.interfaces.PluginDescription
|
||||
import info.nightscout.androidaps.interfaces.PluginType
|
||||
import info.nightscout.androidaps.extensions.fromConstant
|
||||
import info.nightscout.androidaps.interfaces.*
|
||||
import info.nightscout.androidaps.logging.AAPSLogger
|
||||
import info.nightscout.androidaps.logging.LTag
|
||||
import info.nightscout.androidaps.logging.UserEntryLogger
|
||||
|
@ -97,7 +94,7 @@ class DexcomPlugin @Inject constructor(
|
|||
override fun doWork(): Result {
|
||||
var ret = Result.success()
|
||||
|
||||
if (!dexcomPlugin.isEnabled(PluginType.BGSOURCE)) return Result.success()
|
||||
if (!dexcomPlugin.isEnabled(PluginType.BGSOURCE)) return Result.success(workDataOf("Result" to "Plugin not enabled"))
|
||||
val bundle = dataWorker.pickupBundle(inputData.getLong(DataWorker.STORE_KEY, -1))
|
||||
?: return Result.failure(workDataOf("Error" to "missing input data"))
|
||||
try {
|
||||
|
@ -126,11 +123,12 @@ class DexcomPlugin @Inject constructor(
|
|||
meters.getBundle(i.toString())?.let {
|
||||
val timestamp = it.getLong("timestamp") * 1000
|
||||
val now = dateUtil.now()
|
||||
val value = it.getInt("meterValue").toDouble()
|
||||
if (timestamp > now - T.months(1).msecs() && timestamp < now) {
|
||||
calibrations.add(CgmSourceTransaction.Calibration(
|
||||
timestamp = it.getLong("timestamp") * 1000,
|
||||
value = it.getInt("meterValue").toDouble(),
|
||||
glucoseUnit = TherapyEvent.GlucoseUnit.MGDL
|
||||
value = value,
|
||||
glucoseUnit = TherapyEvent.GlucoseUnit.fromConstant(Profile.unit(value))
|
||||
))
|
||||
}
|
||||
}
|
||||
|
@ -158,14 +156,14 @@ class DexcomPlugin @Inject constructor(
|
|||
}
|
||||
result.sensorInsertionsInserted.forEach {
|
||||
uel.log(Action.CAREPORTAL,
|
||||
Sources.BG,
|
||||
Sources.Dexcom,
|
||||
ValueWithUnit.Timestamp(it.timestamp),
|
||||
ValueWithUnit.TherapyEventType(it.type))
|
||||
aapsLogger.debug(LTag.DATABASE, "Inserted sensor insertion $it")
|
||||
}
|
||||
result.calibrationsInserted.forEach {
|
||||
uel.log(Action.CAREPORTAL,
|
||||
Sources.BG,
|
||||
Sources.Dexcom,
|
||||
ValueWithUnit.Timestamp(it.timestamp),
|
||||
ValueWithUnit.TherapyEventType(it.type))
|
||||
aapsLogger.debug(LTag.DATABASE, "Inserted calibration $it")
|
||||
|
|
|
@ -69,7 +69,7 @@ class EversensePlugin @Inject constructor(
|
|||
override fun doWork(): Result {
|
||||
var ret = Result.success()
|
||||
|
||||
if (!eversensePlugin.isEnabled(PluginType.BGSOURCE)) return Result.success()
|
||||
if (!eversensePlugin.isEnabled(PluginType.BGSOURCE)) return Result.success(workDataOf("Result" to "Plugin not enabled"))
|
||||
val bundle = dataWorker.pickupBundle(inputData.getLong(DataWorker.STORE_KEY, -1))
|
||||
?: return Result.failure(workDataOf("Error" to "missing input data"))
|
||||
if (bundle.containsKey("currentCalibrationPhase")) aapsLogger.debug(LTag.BGSOURCE, "currentCalibrationPhase: " + bundle.getString("currentCalibrationPhase"))
|
||||
|
|
|
@ -56,7 +56,7 @@ class GlimpPlugin @Inject constructor(
|
|||
override fun doWork(): Result {
|
||||
var ret = Result.success()
|
||||
|
||||
if (!glimpPlugin.isEnabled(PluginType.BGSOURCE)) return Result.success()
|
||||
if (!glimpPlugin.isEnabled(PluginType.BGSOURCE)) return Result.success(workDataOf("Result" to "Plugin not enabled"))
|
||||
aapsLogger.debug(LTag.BGSOURCE, "Received Glimp Data: $inputData}")
|
||||
val glucoseValues = mutableListOf<CgmSourceTransaction.TransactionGlucoseValue>()
|
||||
glucoseValues += CgmSourceTransaction.TransactionGlucoseValue(
|
||||
|
|
|
@ -5,12 +5,12 @@ import androidx.work.Worker
|
|||
import androidx.work.WorkerParameters
|
||||
import androidx.work.workDataOf
|
||||
import dagger.android.HasAndroidInjector
|
||||
import info.nightscout.androidaps.interfaces.Config
|
||||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.database.AppRepository
|
||||
import info.nightscout.androidaps.database.entities.GlucoseValue
|
||||
import info.nightscout.androidaps.database.transactions.CgmSourceTransaction
|
||||
import info.nightscout.androidaps.interfaces.BgSource
|
||||
import info.nightscout.androidaps.interfaces.Config
|
||||
import info.nightscout.androidaps.interfaces.PluginBase
|
||||
import info.nightscout.androidaps.interfaces.PluginDescription
|
||||
import info.nightscout.androidaps.interfaces.PluginType
|
||||
|
@ -115,7 +115,7 @@ class NSClientSourcePlugin @Inject constructor(
|
|||
override fun doWork(): Result {
|
||||
var ret = Result.success()
|
||||
|
||||
if (!nsClientSourcePlugin.isEnabled() && !sp.getBoolean(R.string.key_ns_autobackfill, true) && !dexcomPlugin.isEnabled()) return Result.success()
|
||||
if (!nsClientSourcePlugin.isEnabled() && !sp.getBoolean(R.string.key_ns_receive_cgm, true) && !dexcomPlugin.isEnabled()) return Result.success(workDataOf("Result" to "Sync not enabled"))
|
||||
|
||||
val sgvs = dataWorker.pickupJSONArray(inputData.getLong(DataWorker.STORE_KEY, -1))
|
||||
?: return Result.failure(workDataOf("Error" to "missing input data"))
|
||||
|
|
|
@ -60,7 +60,7 @@ class PoctechPlugin @Inject constructor(
|
|||
override fun doWork(): Result {
|
||||
var ret = Result.success()
|
||||
|
||||
if (!poctechPlugin.isEnabled(PluginType.BGSOURCE)) return Result.success()
|
||||
if (!poctechPlugin.isEnabled(PluginType.BGSOURCE)) return Result.success(workDataOf("Result" to "Plugin not enabled"))
|
||||
aapsLogger.debug(LTag.BGSOURCE, "Received Poctech Data $inputData")
|
||||
try {
|
||||
val glucoseValues = mutableListOf<CgmSourceTransaction.TransactionGlucoseValue>()
|
||||
|
|
|
@ -59,7 +59,7 @@ class TomatoPlugin @Inject constructor(
|
|||
override fun doWork(): Result {
|
||||
var ret = Result.success()
|
||||
|
||||
if (!tomatoPlugin.isEnabled(PluginType.BGSOURCE)) return Result.success()
|
||||
if (!tomatoPlugin.isEnabled(PluginType.BGSOURCE)) return Result.success(workDataOf("Result" to "Plugin not enabled"))
|
||||
val glucoseValues = mutableListOf<CgmSourceTransaction.TransactionGlucoseValue>()
|
||||
glucoseValues += CgmSourceTransaction.TransactionGlucoseValue(
|
||||
timestamp = inputData.getLong("com.fanqies.tomatofn.Extras.Time", 0),
|
||||
|
|
|
@ -73,7 +73,7 @@ class XdripPlugin @Inject constructor(
|
|||
override fun doWork(): Result {
|
||||
var ret = Result.success()
|
||||
|
||||
if (!xdripPlugin.isEnabled(PluginType.BGSOURCE)) return Result.success()
|
||||
if (!xdripPlugin.isEnabled(PluginType.BGSOURCE)) return Result.success(workDataOf("Result" to "Plugin not enabled"))
|
||||
val bundle = dataWorker.pickupBundle(inputData.getLong(DataWorker.STORE_KEY, -1))
|
||||
?: return Result.failure(workDataOf("Error" to "missing input data"))
|
||||
|
||||
|
|
|
@ -105,25 +105,10 @@ public class TreatmentService extends OrmLiteBaseService<DatabaseHelper> impleme
|
|||
return wrapped.queryForAll();
|
||||
}
|
||||
|
||||
public void delete(Treatment data) throws SQLException {
|
||||
wrapped.delete(data);
|
||||
openHumansUploader.enqueueTreatment(data, true);
|
||||
}
|
||||
|
||||
public void create(Treatment data) throws SQLException {
|
||||
wrapped.create(data);
|
||||
openHumansUploader.enqueueTreatment(data);
|
||||
}
|
||||
|
||||
public Treatment queryForId(long id) throws SQLException {
|
||||
return wrapped.queryForId(id);
|
||||
}
|
||||
|
||||
public void update(Treatment data) throws SQLException {
|
||||
wrapped.update(data);
|
||||
openHumansUploader.enqueueTreatment(data);
|
||||
}
|
||||
|
||||
public QueryBuilder<Treatment, Long> queryBuilder() {
|
||||
return wrapped.queryBuilder();
|
||||
}
|
||||
|
|
|
@ -26,7 +26,6 @@ import info.nightscout.androidaps.interfaces.TreatmentServiceInterface;
|
|||
import info.nightscout.androidaps.interfaces.TreatmentsInterface;
|
||||
import info.nightscout.androidaps.logging.AAPSLogger;
|
||||
import info.nightscout.androidaps.plugins.bus.RxBusWrapper;
|
||||
import info.nightscout.androidaps.plugins.general.nsclient.NSUpload;
|
||||
import info.nightscout.androidaps.utils.DateUtil;
|
||||
import info.nightscout.androidaps.utils.FabricPrivacy;
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper;
|
||||
|
@ -37,12 +36,10 @@ import io.reactivex.disposables.CompositeDisposable;
|
|||
@Singleton
|
||||
public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface {
|
||||
|
||||
private final AapsSchedulers aapsSchedulers;
|
||||
private final SP sp;
|
||||
private final RxBusWrapper rxBus;
|
||||
private final ProfileFunction profileFunction;
|
||||
private final ActivePlugin activePlugin;
|
||||
private final NSUpload nsUpload;
|
||||
private final FabricPrivacy fabricPrivacy;
|
||||
private final DateUtil dateUtil;
|
||||
private final DatabaseHelperInterface databaseHelper;
|
||||
|
@ -63,7 +60,6 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface
|
|||
SP sp,
|
||||
ProfileFunction profileFunction,
|
||||
ActivePlugin activePlugin,
|
||||
NSUpload nsUpload,
|
||||
FabricPrivacy fabricPrivacy,
|
||||
DateUtil dateUtil,
|
||||
DatabaseHelperInterface databaseHelper,
|
||||
|
@ -71,7 +67,6 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface
|
|||
) {
|
||||
super(new PluginDescription()
|
||||
.mainType(PluginType.TREATMENT)
|
||||
.fragmentClass(TreatmentsFragment.class.getName())
|
||||
.pluginIcon(R.drawable.ic_treatments)
|
||||
.pluginName(R.string.treatments)
|
||||
.shortName(R.string.treatments_shortname)
|
||||
|
@ -81,13 +76,11 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface
|
|||
aapsLogger, resourceHelper, injector
|
||||
);
|
||||
this.rxBus = rxBus;
|
||||
this.aapsSchedulers = aapsSchedulers;
|
||||
this.sp = sp;
|
||||
this.profileFunction = profileFunction;
|
||||
this.activePlugin = activePlugin;
|
||||
this.fabricPrivacy = fabricPrivacy;
|
||||
this.dateUtil = dateUtil;
|
||||
this.nsUpload = nsUpload;
|
||||
this.databaseHelper = databaseHelper;
|
||||
this.repository = repository;
|
||||
}
|
||||
|
|
|
@ -86,7 +86,6 @@ open class CommandQueue @Inject constructor(
|
|||
ErrorHelperActivity.runAlarm(context, result.comment, resourceHelper.gs(R.string.failedupdatebasalprofile), R.raw.boluserror)
|
||||
}
|
||||
if (result.enacted) {
|
||||
rxBus.send(EventNewBasalProfile())
|
||||
repository.createEffectiveProfileSwitch(
|
||||
EffectiveProfileSwitch(
|
||||
timestamp = dateUtil.now(),
|
||||
|
@ -104,6 +103,7 @@ open class CommandQueue @Inject constructor(
|
|||
insulinConfiguration = it.insulinConfiguration
|
||||
)
|
||||
)
|
||||
rxBus.send(EventNewBasalProfile())
|
||||
}
|
||||
}
|
||||
})
|
||||
|
@ -566,11 +566,12 @@ open class CommandQueue @Inject constructor(
|
|||
return HtmlHelper.fromHtml(s)
|
||||
}
|
||||
|
||||
override fun isThisProfileSet(profile: Profile): Boolean {
|
||||
val result = activePlugin.activePump.isThisProfileSet(profile)
|
||||
override fun isThisProfileSet(requestedProfile: Profile): Boolean {
|
||||
val runningProfile = profileFunction.getProfile() ?: return false
|
||||
val result = activePlugin.activePump.isThisProfileSet(requestedProfile) && requestedProfile.isEqual(runningProfile)
|
||||
if (!result) {
|
||||
aapsLogger.debug(LTag.PUMPQUEUE, "Current profile: ${profileFunction.getProfile()}")
|
||||
aapsLogger.debug(LTag.PUMPQUEUE, "New profile: $profile")
|
||||
aapsLogger.debug(LTag.PUMPQUEUE, "New profile: $requestedProfile")
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ import info.nightscout.androidaps.data.PumpEnactResult
|
|||
import info.nightscout.androidaps.database.ValueWrapper
|
||||
import info.nightscout.androidaps.interfaces.ActivePlugin
|
||||
import info.nightscout.androidaps.interfaces.CommandQueueProvider
|
||||
import info.nightscout.androidaps.interfaces.Config
|
||||
import info.nightscout.androidaps.interfaces.PluginType
|
||||
import info.nightscout.androidaps.interfaces.Profile
|
||||
import info.nightscout.androidaps.logging.LTag
|
||||
|
@ -25,9 +26,10 @@ class CommandSetProfile constructor(
|
|||
@Inject lateinit var activePlugin: ActivePlugin
|
||||
@Inject lateinit var dateUtil: DateUtil
|
||||
@Inject lateinit var commandQueue: CommandQueueProvider
|
||||
@Inject lateinit var config: Config
|
||||
|
||||
override fun execute() {
|
||||
if (commandQueue.isThisProfileSet(profile)) {
|
||||
if (commandQueue.isThisProfileSet(profile) && repository.getEffectiveProfileSwitchActiveAt(dateUtil.now()).blockingGet() is ValueWrapper.Existing) {
|
||||
aapsLogger.debug(LTag.PUMPQUEUE, "Correct profile already set. profile: $profile")
|
||||
callback?.result(PumpEnactResult(injector).success(true).enacted(false))?.run()
|
||||
return
|
||||
|
@ -37,7 +39,7 @@ class CommandSetProfile constructor(
|
|||
callback?.result(r)?.run()
|
||||
// Send SMS notification if ProfileSwitch is coming from NS
|
||||
val profileSwitch = repository.getEffectiveProfileSwitchActiveAt(dateUtil.now()).blockingGet()
|
||||
if (profileSwitch is ValueWrapper.Existing && r.enacted && hasNsId) {
|
||||
if (profileSwitch is ValueWrapper.Existing && r.enacted && hasNsId && !config.NSCLIENT) {
|
||||
if (smsCommunicatorPlugin.isEnabled(PluginType.GENERAL))
|
||||
smsCommunicatorPlugin.sendNotificationToAllNumbers(resourceHelper.gs(R.string.profile_set_ok))
|
||||
}
|
||||
|
|
|
@ -119,17 +119,18 @@ class KeepAliveReceiver : DaggerBroadcastReceiver() {
|
|||
private fun checkPump() {
|
||||
val pump = activePlugin.activePump
|
||||
val ps = profileFunction.getRequestedProfile() ?: return
|
||||
val profile = ProfileSealed.PS(ps)
|
||||
val requestedProfile = ProfileSealed.PS(ps)
|
||||
val runningProfile = profileFunction.getProfile()
|
||||
val lastConnection = pump.lastDataTime()
|
||||
val isStatusOutdated = lastConnection + STATUS_UPDATE_FREQUENCY < System.currentTimeMillis()
|
||||
val isBasalOutdated = abs(profile.getBasal() - pump.baseBasalRate) > pump.pumpDescription.basalStep
|
||||
val isBasalOutdated = abs(requestedProfile.getBasal() - pump.baseBasalRate) > pump.pumpDescription.basalStep
|
||||
aapsLogger.debug(LTag.CORE, "Last connection: " + dateUtil.dateAndTimeString(lastConnection))
|
||||
// sometimes keep alive broadcast stops
|
||||
// as as workaround test if readStatus was requested before an alarm is generated
|
||||
if (lastReadStatus != 0L && lastReadStatus > System.currentTimeMillis() - T.mins(5).msecs()) {
|
||||
localAlertUtils.checkPumpUnreachableAlarm(lastConnection, isStatusOutdated, loopPlugin.isDisconnected)
|
||||
}
|
||||
if (!pump.isThisProfileSet(profile) && !commandQueue.isRunning(Command.CommandType.BASAL_PROFILE)) {
|
||||
if (runningProfile == null || ((!pump.isThisProfileSet(requestedProfile) || !requestedProfile.isEqual(runningProfile)) && !commandQueue.isRunning(Command.CommandType.BASAL_PROFILE))) {
|
||||
rxBus.send(EventProfileSwitchChanged())
|
||||
} else if (isStatusOutdated && !pump.isBusy()) {
|
||||
lastReadStatus = System.currentTimeMillis()
|
||||
|
|
|
@ -19,11 +19,8 @@ import info.nightscout.androidaps.plugins.constraints.objectives.ObjectivesFragm
|
|||
import info.nightscout.androidaps.plugins.constraints.objectives.ObjectivesPlugin
|
||||
import info.nightscout.androidaps.plugins.general.nsclient.NSClientPlugin
|
||||
import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientStatus
|
||||
import info.nightscout.androidaps.plugins.general.nsclient.services.NSClientService
|
||||
import info.nightscout.androidaps.plugins.profile.local.LocalProfileFragment
|
||||
import info.nightscout.androidaps.plugins.profile.local.LocalProfilePlugin
|
||||
import info.nightscout.androidaps.plugins.profile.ns.NSProfileFragment
|
||||
import info.nightscout.androidaps.plugins.profile.ns.NSProfilePlugin
|
||||
import info.nightscout.androidaps.plugins.pump.common.events.EventRileyLinkDeviceStatusChange
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.OmnipodDashPumpPlugin
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.eros.OmnipodErosPumpPlugin
|
||||
|
@ -53,7 +50,6 @@ class SWDefinition @Inject constructor(
|
|||
private val configBuilder: ConfigBuilder,
|
||||
private val loopPlugin: LoopPlugin,
|
||||
private val nsClientPlugin: NSClientPlugin,
|
||||
private val nsProfilePlugin: NSProfilePlugin,
|
||||
private val importExportPrefs: ImportExportPrefs,
|
||||
private val androidPermission: AndroidPermission,
|
||||
private val cryptoUtil: CryptoUtil,
|
||||
|
@ -189,8 +185,8 @@ class SWDefinition @Inject constructor(
|
|||
.label(R.string.status)
|
||||
.initialStatus(nsClientPlugin.status)
|
||||
)
|
||||
.validator { nsClientPlugin.nsClientService != null && NSClientService.isConnected && NSClientService.hasWriteAuth }
|
||||
.visibility { !(nsClientPlugin.nsClientService != null && NSClientService.isConnected && NSClientService.hasWriteAuth) }
|
||||
.validator { nsClientPlugin.nsClientService?.isConnected == true && nsClientPlugin.nsClientService?.hasWriteAuth == true }
|
||||
.visibility { !(nsClientPlugin.nsClientService?.isConnected == true && nsClientPlugin.nsClientService?.hasWriteAuth == true) }
|
||||
private val screenPatientName = SWScreen(injector, R.string.patient_name)
|
||||
.skippable(true)
|
||||
.add(SWInfoText(injector)
|
||||
|
@ -254,27 +250,14 @@ class SWDefinition @Inject constructor(
|
|||
.option(PluginType.BGSOURCE, R.string.configbuilder_bgsource_description)
|
||||
.label(R.string.configbuilder_bgsource))
|
||||
.add(SWBreak(injector))
|
||||
private val screenProfile = SWScreen(injector, R.string.configbuilder_profile)
|
||||
.skippable(false)
|
||||
.add(SWInfoText(injector)
|
||||
.label(R.string.setupwizard_profile_description))
|
||||
.add(SWBreak(injector))
|
||||
.add(SWPlugin(injector, this)
|
||||
.option(PluginType.PROFILE, R.string.configbuilder_profile_description)
|
||||
.label(R.string.configbuilder_profile))
|
||||
private val screenNsProfile = SWScreen(injector, R.string.nsprofile)
|
||||
.skippable(false)
|
||||
.add(SWInfoText(injector)
|
||||
.label(R.string.adjustprofileinns))
|
||||
.add(SWFragment(injector, this)
|
||||
.add(NSProfileFragment()))
|
||||
.validator { nsProfilePlugin.profile?.getDefaultProfile()?.let { ProfileSealed.Pure(it).isValid("StartupWizard", activePlugin.activePump, config, resourceHelper, rxBus) } ?: false }
|
||||
.visibility { nsProfilePlugin.isEnabled() }
|
||||
private val screenLocalProfile = SWScreen(injector, R.string.localprofile)
|
||||
.skippable(false)
|
||||
.add(SWFragment(injector, this)
|
||||
.add(LocalProfileFragment()))
|
||||
.validator { localProfilePlugin.profile?.getDefaultProfile()?.let { ProfileSealed.Pure(it).isValid("StartupWizard", activePlugin.activePump, config, resourceHelper, rxBus) } ?: false }
|
||||
.validator {
|
||||
localProfilePlugin.profile?.getDefaultProfile()?.let { ProfileSealed.Pure(it).isValid("StartupWizard", activePlugin.activePump, config, resourceHelper, rxBus) }
|
||||
?: false
|
||||
}
|
||||
.visibility { localProfilePlugin.isEnabled() }
|
||||
private val screenProfileSwitch = SWScreen(injector, R.string.careportal_profileswitch)
|
||||
.skippable(false)
|
||||
|
@ -399,8 +382,6 @@ class SWDefinition @Inject constructor(
|
|||
.add(screenAge)
|
||||
.add(screenInsulin)
|
||||
.add(screenBgSource)
|
||||
.add(screenProfile)
|
||||
.add(screenNsProfile)
|
||||
.add(screenLocalProfile)
|
||||
.add(screenProfileSwitch)
|
||||
.add(screenPump)
|
||||
|
@ -428,8 +409,6 @@ class SWDefinition @Inject constructor(
|
|||
.add(screenAge)
|
||||
.add(screenInsulin)
|
||||
.add(screenBgSource)
|
||||
.add(screenProfile)
|
||||
.add(screenNsProfile)
|
||||
.add(screenLocalProfile)
|
||||
.add(screenProfileSwitch)
|
||||
.add(screenPump)
|
||||
|
|
|
@ -17,14 +17,15 @@ class JSONFormatter @Inject constructor(
|
|||
private val aapsLogger: AAPSLogger
|
||||
) {
|
||||
|
||||
@kotlin.ExperimentalStdlibApi
|
||||
fun format(jsonString: String?): Spanned {
|
||||
jsonString ?: return fromHtml("")
|
||||
val visitor = JsonVisitor(1, '\t')
|
||||
return try {
|
||||
when {
|
||||
jsonString == "undefined" -> fromHtml("undefined")
|
||||
jsonString.toByteArray()[0] == '['.toByte() -> fromHtml(visitor.visit(JSONArray(jsonString), 0))
|
||||
else -> fromHtml(visitor.visit(JSONObject(jsonString), 0))
|
||||
jsonString == "undefined" -> fromHtml("undefined")
|
||||
jsonString.toByteArray()[0] == '['.code.toByte() -> fromHtml(visitor.visit(JSONArray(jsonString), 0))
|
||||
else -> fromHtml(visitor.visit(JSONObject(jsonString), 0))
|
||||
}
|
||||
} catch (e: JSONException) {
|
||||
aapsLogger.error("Unhandled exception", e)
|
||||
|
|
|
@ -10,9 +10,12 @@ class TrendCalculator @Inject constructor(
|
|||
private val repository: AppRepository
|
||||
) {
|
||||
|
||||
fun getTrendArrow(glucoseValue: GlucoseValue): GlucoseValue.TrendArrow =
|
||||
if (glucoseValue.trendArrow != GlucoseValue.TrendArrow.NONE) glucoseValue.trendArrow
|
||||
else calculateDirection(glucoseValue)
|
||||
fun getTrendArrow(glucoseValue: GlucoseValue?): GlucoseValue.TrendArrow =
|
||||
when {
|
||||
glucoseValue?.trendArrow == null -> GlucoseValue.TrendArrow.NONE
|
||||
glucoseValue.trendArrow != GlucoseValue.TrendArrow.NONE -> glucoseValue.trendArrow
|
||||
else -> calculateDirection(glucoseValue)
|
||||
}
|
||||
|
||||
private fun calculateDirection(glucoseValue: GlucoseValue): GlucoseValue.TrendArrow {
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@ import info.nightscout.androidaps.data.DetailedBolusInfo
|
|||
import info.nightscout.androidaps.interfaces.Profile
|
||||
import info.nightscout.androidaps.database.AppRepository
|
||||
import info.nightscout.androidaps.database.entities.BolusCalculatorResult
|
||||
import info.nightscout.androidaps.database.entities.OfflineEvent
|
||||
import info.nightscout.androidaps.database.entities.ValueWithUnit
|
||||
import info.nightscout.androidaps.database.entities.TemporaryTarget
|
||||
import info.nightscout.androidaps.database.entities.UserEntry.Action
|
||||
|
@ -374,7 +375,7 @@ class BolusWizard @Inject constructor(
|
|||
if (useSuperBolus) {
|
||||
uel.log(Action.SUPERBOLUS_TBR, Sources.WizardDialog)
|
||||
if (loopPlugin.isEnabled(PluginType.LOOP)) {
|
||||
loopPlugin.superBolusTo(System.currentTimeMillis() + 2 * 60L * 60 * 1000)
|
||||
loopPlugin.goToZeroTemp(2 * 60, profile, OfflineEvent.Reason.SUPER_BOLUS)
|
||||
rxBus.send(EventRefreshOverview("WizardDialog"))
|
||||
}
|
||||
|
||||
|
@ -408,7 +409,7 @@ class BolusWizard @Inject constructor(
|
|||
context = ctx
|
||||
mgdlGlucose = Profile.toMgdl(bg, profile.units)
|
||||
glucoseType = DetailedBolusInfo.MeterType.MANUAL
|
||||
carbTime = this@BolusWizard.carbTime
|
||||
carbsTimestamp = dateUtil.now() + T.mins(this@BolusWizard.carbTime.toLong()).msecs()
|
||||
bolusCalculatorResult = createBolusCalculatorResult()
|
||||
notes = this@BolusWizard.notes
|
||||
if (insulin > 0 || carbs > 0) {
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context="info.nightscout.androidaps.historyBrowser.HistoryBrowseActivity">
|
||||
tools:context="info.nightscout.androidaps.activities.HistoryBrowseActivity">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
|
@ -72,7 +72,7 @@
|
|||
android:layout_weight="1">
|
||||
|
||||
<com.jjoe64.graphview.GraphView
|
||||
android:id="@+id/bggraph"
|
||||
android:id="@+id/bg_graph"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue