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 {
|
defaultConfig {
|
||||||
multiDexEnabled true
|
multiDexEnabled true
|
||||||
versionCode 1500
|
versionCode 1500
|
||||||
version "2.8.2.1-dev-e3"
|
version "2.8.2.1-dev-e5"
|
||||||
buildConfigField "String", "VERSION", '"' + version + '"'
|
buildConfigField "String", "VERSION", '"' + version + '"'
|
||||||
buildConfigField "String", "BUILDVERSION", '"' + generateGitBuild() + '-' + generateDate() + '"'
|
buildConfigField "String", "BUILDVERSION", '"' + generateGitBuild() + '-' + generateDate() + '"'
|
||||||
buildConfigField "String", "REMOTE", '"' + generateGitRemote() + '"'
|
buildConfigField "String", "REMOTE", '"' + generateGitRemote() + '"'
|
||||||
|
@ -186,6 +186,7 @@ dependencies {
|
||||||
implementation project(':danars')
|
implementation project(':danars')
|
||||||
implementation project(':danar')
|
implementation project(':danar')
|
||||||
implementation project(':insight')
|
implementation project(':insight')
|
||||||
|
implementation project(':pump-common')
|
||||||
implementation project(':rileylink')
|
implementation project(':rileylink')
|
||||||
implementation project(':medtronic')
|
implementation project(':medtronic')
|
||||||
implementation project(':omnipod-common')
|
implementation project(':omnipod-common')
|
||||||
|
@ -197,8 +198,6 @@ dependencies {
|
||||||
/* Dagger2 - We are going to use dagger.android which includes
|
/* Dagger2 - We are going to use dagger.android which includes
|
||||||
* support for Activity and fragment injection so we need to include
|
* support for Activity and fragment injection so we need to include
|
||||||
* the following dependencies */
|
* the following dependencies */
|
||||||
|
|
||||||
|
|
||||||
annotationProcessor "com.google.dagger:dagger-compiler:$dagger_version"
|
annotationProcessor "com.google.dagger:dagger-compiler:$dagger_version"
|
||||||
annotationProcessor "com.google.dagger:dagger-android-processor:$dagger_version"
|
annotationProcessor "com.google.dagger:dagger-android-processor:$dagger_version"
|
||||||
kapt "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>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
<activity android:name=".plugins.general.maintenance.activities.PrefImportListActivity" />
|
<activity android:name=".plugins.general.maintenance.activities.PrefImportListActivity" />
|
||||||
<activity android:name=".historyBrowser.HistoryBrowseActivity" />
|
<activity android:name=".activities.HistoryBrowseActivity" />
|
||||||
|
<activity android:name=".activities.TreatmentsActivity" />
|
||||||
<activity android:name=".activities.SurveyActivity" />
|
<activity android:name=".activities.SurveyActivity" />
|
||||||
<activity android:name=".activities.ProfileHelperActivity"
|
<activity android:name=".activities.ProfileHelperActivity"
|
||||||
android:theme="@style/ProfileHelperAppTheme" />
|
android:theme="@style/ProfileHelperAppTheme" />
|
||||||
|
|
|
@ -27,18 +27,14 @@ import com.google.firebase.crashlytics.FirebaseCrashlytics
|
||||||
import com.joanzapata.iconify.Iconify
|
import com.joanzapata.iconify.Iconify
|
||||||
import com.joanzapata.iconify.fonts.FontAwesomeModule
|
import com.joanzapata.iconify.fonts.FontAwesomeModule
|
||||||
import dev.doubledot.doki.ui.DokiActivity
|
import dev.doubledot.doki.ui.DokiActivity
|
||||||
import info.nightscout.androidaps.activities.NoSplashAppCompatActivity
|
import info.nightscout.androidaps.activities.*
|
||||||
import info.nightscout.androidaps.activities.PreferencesActivity
|
|
||||||
import info.nightscout.androidaps.activities.ProfileHelperActivity
|
|
||||||
import info.nightscout.androidaps.activities.SingleFragmentActivity
|
|
||||||
import info.nightscout.androidaps.activities.StatsActivity
|
|
||||||
import info.nightscout.androidaps.database.entities.UserEntry.Action
|
import info.nightscout.androidaps.database.entities.UserEntry.Action
|
||||||
import info.nightscout.androidaps.database.entities.UserEntry.Sources
|
import info.nightscout.androidaps.database.entities.UserEntry.Sources
|
||||||
import info.nightscout.androidaps.databinding.ActivityMainBinding
|
import info.nightscout.androidaps.databinding.ActivityMainBinding
|
||||||
import info.nightscout.androidaps.events.EventAppExit
|
import info.nightscout.androidaps.events.EventAppExit
|
||||||
import info.nightscout.androidaps.events.EventPreferenceChange
|
import info.nightscout.androidaps.events.EventPreferenceChange
|
||||||
import info.nightscout.androidaps.events.EventRebuildTabs
|
import info.nightscout.androidaps.events.EventRebuildTabs
|
||||||
import info.nightscout.androidaps.historyBrowser.HistoryBrowseActivity
|
import info.nightscout.androidaps.activities.HistoryBrowseActivity
|
||||||
import info.nightscout.androidaps.interfaces.ActivePlugin
|
import info.nightscout.androidaps.interfaces.ActivePlugin
|
||||||
import info.nightscout.androidaps.interfaces.Config
|
import info.nightscout.androidaps.interfaces.Config
|
||||||
import info.nightscout.androidaps.interfaces.IconsProvider
|
import info.nightscout.androidaps.interfaces.IconsProvider
|
||||||
|
@ -99,6 +95,7 @@ class MainActivity : NoSplashAppCompatActivity() {
|
||||||
|
|
||||||
private lateinit var binding: ActivityMainBinding
|
private lateinit var binding: ActivityMainBinding
|
||||||
|
|
||||||
|
@kotlin.ExperimentalStdlibApi
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
Iconify.with(FontAwesomeModule())
|
Iconify.with(FontAwesomeModule())
|
||||||
|
@ -290,6 +287,11 @@ class MainActivity : NoSplashAppCompatActivity() {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
R.id.nav_treatments -> {
|
||||||
|
startActivity(Intent(this, TreatmentsActivity::class.java))
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
R.id.nav_setupwizard -> {
|
R.id.nav_setupwizard -> {
|
||||||
protectionCheck.queryProtection(this, ProtectionCheck.Protection.PREFERENCES, {
|
protectionCheck.queryProtection(this, ProtectionCheck.Protection.PREFERENCES, {
|
||||||
startActivity(Intent(this, SetupWizardActivity::class.java))
|
startActivity(Intent(this, SetupWizardActivity::class.java))
|
||||||
|
@ -359,11 +361,12 @@ class MainActivity : NoSplashAppCompatActivity() {
|
||||||
// Correct place for calling setUserStats() would be probably MainApp
|
// Correct place for calling setUserStats() would be probably MainApp
|
||||||
// but we need to have it called at least once a day. Thus this location
|
// but we need to have it called at least once a day. Thus this location
|
||||||
|
|
||||||
|
@kotlin.ExperimentalStdlibApi
|
||||||
private fun setUserStats() {
|
private fun setUserStats() {
|
||||||
if (!fabricPrivacy.fabricEnabled()) return
|
if (!fabricPrivacy.fabricEnabled()) return
|
||||||
val closedLoopEnabled = if (constraintChecker.isClosedLoopAllowed().value()) "CLOSED_LOOP_ENABLED" else "CLOSED_LOOP_DISABLED"
|
val closedLoopEnabled = if (constraintChecker.isClosedLoopAllowed().value()) "CLOSED_LOOP_ENABLED" else "CLOSED_LOOP_DISABLED"
|
||||||
// Size is limited to 36 chars
|
// Size is limited to 36 chars
|
||||||
val remote = BuildConfig.REMOTE.toLowerCase(Locale.getDefault())
|
val remote = BuildConfig.REMOTE.lowercase(Locale.getDefault())
|
||||||
.replace("https://", "")
|
.replace("https://", "")
|
||||||
.replace("http://", "")
|
.replace("http://", "")
|
||||||
.replace(".git", "")
|
.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() {
|
class RequestDexcomPermissionActivity : DialogAppCompatActivity() {
|
||||||
@Inject lateinit var dexcomPlugin: DexcomPlugin
|
@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?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
requestPermissions(arrayOf(DexcomPlugin.PERMISSION), requestCode)
|
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.os.Bundle
|
||||||
import android.view.LayoutInflater
|
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.fragment.app.FragmentTransaction
|
import androidx.fragment.app.FragmentTransaction
|
||||||
import dagger.android.support.DaggerFragment
|
|
||||||
import info.nightscout.androidaps.R
|
import info.nightscout.androidaps.R
|
||||||
|
import info.nightscout.androidaps.activities.fragments.*
|
||||||
import info.nightscout.androidaps.databinding.TreatmentsFragmentBinding
|
import info.nightscout.androidaps.databinding.TreatmentsFragmentBinding
|
||||||
import info.nightscout.androidaps.events.EventExtendedBolusChange
|
|
||||||
import info.nightscout.androidaps.interfaces.ActivePlugin
|
|
||||||
import info.nightscout.androidaps.interfaces.IobCobCalculator
|
|
||||||
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
|
||||||
import info.nightscout.androidaps.plugins.treatments.fragments.*
|
|
||||||
import info.nightscout.androidaps.utils.DateUtil
|
|
||||||
import info.nightscout.androidaps.utils.FabricPrivacy
|
|
||||||
import info.nightscout.androidaps.utils.buildHelper.BuildHelper
|
|
||||||
import info.nightscout.androidaps.extensions.toVisibility
|
import info.nightscout.androidaps.extensions.toVisibility
|
||||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
import info.nightscout.androidaps.interfaces.ActivePlugin
|
||||||
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
import info.nightscout.androidaps.utils.buildHelper.BuildHelper
|
||||||
import io.reactivex.disposables.CompositeDisposable
|
|
||||||
import io.reactivex.rxkotlin.plusAssign
|
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class TreatmentsFragment : DaggerFragment() {
|
class TreatmentsActivity : NoSplashAppCompatActivity() {
|
||||||
|
|
||||||
@Inject lateinit var rxBus: RxBusWrapper
|
|
||||||
@Inject lateinit var resourceHelper: ResourceHelper
|
|
||||||
@Inject lateinit var fabricPrivacy: FabricPrivacy
|
|
||||||
@Inject lateinit var activePlugin: ActivePlugin
|
|
||||||
@Inject lateinit var iobCobCalculator: IobCobCalculator
|
|
||||||
@Inject lateinit var aapsSchedulers: AapsSchedulers
|
|
||||||
@Inject lateinit var buildHelper: BuildHelper
|
@Inject lateinit var buildHelper: BuildHelper
|
||||||
@Inject lateinit var dateUtil: DateUtil
|
@Inject lateinit var activePlugin: ActivePlugin
|
||||||
|
|
||||||
private val disposable = CompositeDisposable()
|
private lateinit var binding: TreatmentsFragmentBinding
|
||||||
|
|
||||||
private var _binding: TreatmentsFragmentBinding? = null
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
// This property is only valid between onCreateView and
|
binding = TreatmentsFragmentBinding.inflate(layoutInflater)
|
||||||
// onDestroyView.
|
setContentView(binding.root)
|
||||||
private val binding get() = _binding!!
|
|
||||||
|
|
||||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View =
|
|
||||||
TreatmentsFragmentBinding.inflate(inflater, container, false).also { _binding = it }.root
|
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
|
||||||
super.onViewCreated(view, savedInstanceState)
|
|
||||||
|
|
||||||
binding.tempBasals.visibility = buildHelper.isEngineeringMode().toVisibility()
|
binding.tempBasals.visibility = buildHelper.isEngineeringMode().toVisibility()
|
||||||
binding.extendedBoluses.visibility = (buildHelper.isEngineeringMode() && !activePlugin.activePump.isFakingTempsByExtendedBoluses).toVisibility()
|
binding.extendedBoluses.visibility = (buildHelper.isEngineeringMode() && !activePlugin.activePump.isFakingTempsByExtendedBoluses).toVisibility()
|
||||||
|
@ -84,33 +59,10 @@ class TreatmentsFragment : DaggerFragment() {
|
||||||
setBackgroundColorOnSelected(binding.treatments)
|
setBackgroundColorOnSelected(binding.treatments)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Synchronized
|
|
||||||
override fun onResume() {
|
|
||||||
super.onResume()
|
|
||||||
disposable += rxBus
|
|
||||||
.toObservable(EventExtendedBolusChange::class.java)
|
|
||||||
.observeOn(aapsSchedulers.main)
|
|
||||||
.subscribe({ updateGui() }, fabricPrivacy::logException)
|
|
||||||
updateGui()
|
|
||||||
}
|
|
||||||
|
|
||||||
@Synchronized
|
|
||||||
override fun onPause() {
|
|
||||||
super.onPause()
|
|
||||||
disposable.clear()
|
|
||||||
}
|
|
||||||
|
|
||||||
@Synchronized
|
|
||||||
override fun onDestroyView() {
|
|
||||||
super.onDestroyView()
|
|
||||||
_binding = null
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun setFragment(selectedFragment: Fragment) {
|
private fun setFragment(selectedFragment: Fragment) {
|
||||||
childFragmentManager.beginTransaction()
|
supportFragmentManager.beginTransaction()
|
||||||
.replace(R.id.fragment_container, selectedFragment) // f2_container is your FrameLayout container
|
.replace(R.id.fragment_container, selectedFragment)
|
||||||
.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
|
.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE)
|
||||||
.addToBackStack(null)
|
|
||||||
.commit()
|
.commit()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -125,8 +77,4 @@ class TreatmentsFragment : DaggerFragment() {
|
||||||
selected.setBackgroundColor(resourceHelper.gc(R.color.tabBgColorSelected))
|
selected.setBackgroundColor(resourceHelper.gc(R.color.tabBgColorSelected))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateGui() {
|
|
||||||
if (_binding == null) return
|
|
||||||
binding.extendedBoluses.visibility = (activePlugin.activePump.pumpDescription.isExtendedBolusCapable || iobCobCalculator.getExtendedBolus(dateUtil.now()) != null).toVisibility()
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package info.nightscout.androidaps.plugins.treatments.fragments
|
package info.nightscout.androidaps.activities.fragments
|
||||||
|
|
||||||
import android.graphics.Paint
|
import android.graphics.Paint
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
@ -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
|
if (nsUploadOnly) binding.refreshFromNightscout.visibility = View.GONE
|
||||||
binding.showInvalidated.setOnCheckedChangeListener { _, _ ->
|
binding.showInvalidated.setOnCheckedChangeListener { _, _ ->
|
||||||
rxBus.send(EventTreatmentUpdateGui())
|
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.graphics.Paint
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
@ -25,7 +25,7 @@ import info.nightscout.androidaps.logging.UserEntryLogger
|
||||||
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
||||||
import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientRestart
|
import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientRestart
|
||||||
import info.nightscout.androidaps.plugins.treatments.events.EventTreatmentUpdateGui
|
import info.nightscout.androidaps.plugins.treatments.events.EventTreatmentUpdateGui
|
||||||
import info.nightscout.androidaps.plugins.treatments.fragments.TreatmentsCareportalFragment.RecyclerViewAdapter.TherapyEventsViewHolder
|
import info.nightscout.androidaps.activities.fragments.TreatmentsCareportalFragment.RecyclerViewAdapter.TherapyEventsViewHolder
|
||||||
import info.nightscout.androidaps.utils.DateUtil
|
import info.nightscout.androidaps.utils.DateUtil
|
||||||
import info.nightscout.androidaps.utils.FabricPrivacy
|
import info.nightscout.androidaps.utils.FabricPrivacy
|
||||||
import info.nightscout.androidaps.utils.T
|
import info.nightscout.androidaps.utils.T
|
||||||
|
@ -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
|
if (nsUploadOnly) binding.refreshFromNightscout.visibility = View.GONE
|
||||||
binding.showInvalidated.setOnCheckedChangeListener { _, _ ->
|
binding.showInvalidated.setOnCheckedChangeListener { _, _ ->
|
||||||
rxBus.send(EventTreatmentUpdateGui())
|
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.annotation.SuppressLint
|
||||||
import android.content.DialogInterface
|
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.ExtendedBolus
|
||||||
import info.nightscout.androidaps.database.entities.UserEntry.Action
|
import info.nightscout.androidaps.database.entities.UserEntry.Action
|
||||||
import info.nightscout.androidaps.database.entities.UserEntry.Sources
|
import info.nightscout.androidaps.database.entities.UserEntry.Sources
|
||||||
|
import info.nightscout.androidaps.database.entities.ValueWithUnit
|
||||||
import info.nightscout.androidaps.database.interfaces.end
|
import info.nightscout.androidaps.database.interfaces.end
|
||||||
import info.nightscout.androidaps.database.transactions.InvalidateExtendedBolusTransaction
|
import info.nightscout.androidaps.database.transactions.InvalidateExtendedBolusTransaction
|
||||||
import info.nightscout.androidaps.databinding.TreatmentsExtendedbolusFragmentBinding
|
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.LTag
|
||||||
import info.nightscout.androidaps.logging.UserEntryLogger
|
import info.nightscout.androidaps.logging.UserEntryLogger
|
||||||
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
||||||
import info.nightscout.androidaps.plugins.treatments.fragments.TreatmentsExtendedBolusesFragment.RecyclerViewAdapter.ExtendedBolusesViewHolder
|
import info.nightscout.androidaps.activities.fragments.TreatmentsExtendedBolusesFragment.RecyclerViewAdapter.ExtendedBolusesViewHolder
|
||||||
import info.nightscout.androidaps.utils.DateUtil
|
import info.nightscout.androidaps.utils.DateUtil
|
||||||
import info.nightscout.androidaps.utils.FabricPrivacy
|
import info.nightscout.androidaps.utils.FabricPrivacy
|
||||||
import info.nightscout.androidaps.utils.T
|
import info.nightscout.androidaps.utils.T
|
||||||
|
@ -157,7 +158,11 @@ class TreatmentsExtendedBolusesFragment : DaggerFragment() {
|
||||||
${resourceHelper.gs(R.string.extended_bolus)}
|
${resourceHelper.gs(R.string.extended_bolus)}
|
||||||
${resourceHelper.gs(R.string.date)}: ${dateUtil.dateAndTimeString(extendedBolus.timestamp)}
|
${resourceHelper.gs(R.string.date)}: ${dateUtil.dateAndTimeString(extendedBolus.timestamp)}
|
||||||
""".trimIndent(), { _: DialogInterface, _: Int ->
|
""".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))
|
disposable += repository.runTransactionForResult(InvalidateExtendedBolusTransaction(extendedBolus.id))
|
||||||
.subscribe(
|
.subscribe(
|
||||||
{ aapsLogger.debug(LTag.DATABASE, "Removed extended bolus $extendedBolus") },
|
{ 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.graphics.Paint
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
@ -21,18 +21,16 @@ import info.nightscout.androidaps.dialogs.ProfileViewerDialog
|
||||||
import info.nightscout.androidaps.events.EventProfileSwitchChanged
|
import info.nightscout.androidaps.events.EventProfileSwitchChanged
|
||||||
import info.nightscout.androidaps.extensions.getCustomizedName
|
import info.nightscout.androidaps.extensions.getCustomizedName
|
||||||
import info.nightscout.androidaps.extensions.toVisibility
|
import info.nightscout.androidaps.extensions.toVisibility
|
||||||
import info.nightscout.androidaps.interfaces.UploadQueueInterface
|
|
||||||
import info.nightscout.androidaps.logging.AAPSLogger
|
import info.nightscout.androidaps.logging.AAPSLogger
|
||||||
import info.nightscout.androidaps.logging.LTag
|
import info.nightscout.androidaps.logging.LTag
|
||||||
import info.nightscout.androidaps.logging.UserEntryLogger
|
import info.nightscout.androidaps.logging.UserEntryLogger
|
||||||
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
||||||
import info.nightscout.androidaps.plugins.general.nsclient.NSUpload
|
|
||||||
import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientRestart
|
import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientRestart
|
||||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventNewHistoryData
|
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventNewHistoryData
|
||||||
import info.nightscout.androidaps.plugins.profile.local.LocalProfilePlugin
|
import info.nightscout.androidaps.plugins.profile.local.LocalProfilePlugin
|
||||||
import info.nightscout.androidaps.plugins.profile.local.events.EventLocalProfileChanged
|
import info.nightscout.androidaps.plugins.profile.local.events.EventLocalProfileChanged
|
||||||
import info.nightscout.androidaps.plugins.treatments.events.EventTreatmentUpdateGui
|
import info.nightscout.androidaps.plugins.treatments.events.EventTreatmentUpdateGui
|
||||||
import info.nightscout.androidaps.plugins.treatments.fragments.TreatmentsProfileSwitchFragment.RecyclerProfileViewAdapter.ProfileSwitchViewHolder
|
import info.nightscout.androidaps.activities.fragments.TreatmentsProfileSwitchFragment.RecyclerProfileViewAdapter.ProfileSwitchViewHolder
|
||||||
import info.nightscout.androidaps.utils.DateUtil
|
import info.nightscout.androidaps.utils.DateUtil
|
||||||
import info.nightscout.androidaps.utils.FabricPrivacy
|
import info.nightscout.androidaps.utils.FabricPrivacy
|
||||||
import info.nightscout.androidaps.utils.T
|
import info.nightscout.androidaps.utils.T
|
||||||
|
@ -55,8 +53,6 @@ class TreatmentsProfileSwitchFragment : DaggerFragment() {
|
||||||
@Inject lateinit var localProfilePlugin: LocalProfilePlugin
|
@Inject lateinit var localProfilePlugin: LocalProfilePlugin
|
||||||
@Inject lateinit var resourceHelper: ResourceHelper
|
@Inject lateinit var resourceHelper: ResourceHelper
|
||||||
@Inject lateinit var fabricPrivacy: FabricPrivacy
|
@Inject lateinit var fabricPrivacy: FabricPrivacy
|
||||||
@Inject lateinit var nsUpload: NSUpload
|
|
||||||
@Inject lateinit var uploadQueue: UploadQueueInterface
|
|
||||||
@Inject lateinit var dateUtil: DateUtil
|
@Inject lateinit var dateUtil: DateUtil
|
||||||
@Inject lateinit var buildHelper: BuildHelper
|
@Inject lateinit var buildHelper: BuildHelper
|
||||||
@Inject lateinit var aapsSchedulers: AapsSchedulers
|
@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 { _, _ ->
|
binding.showInvalidated.setOnCheckedChangeListener { _, _ ->
|
||||||
rxBus.send(EventTreatmentUpdateGui())
|
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.annotation.SuppressLint
|
||||||
import android.content.DialogInterface
|
import android.content.DialogInterface
|
||||||
|
@ -23,14 +23,13 @@ import info.nightscout.androidaps.databinding.TreatmentsTemptargetFragmentBindin
|
||||||
import info.nightscout.androidaps.databinding.TreatmentsTemptargetItemBinding
|
import info.nightscout.androidaps.databinding.TreatmentsTemptargetItemBinding
|
||||||
import info.nightscout.androidaps.events.EventTempTargetChange
|
import info.nightscout.androidaps.events.EventTempTargetChange
|
||||||
import info.nightscout.androidaps.interfaces.ProfileFunction
|
import info.nightscout.androidaps.interfaces.ProfileFunction
|
||||||
import info.nightscout.androidaps.interfaces.UploadQueueInterface
|
|
||||||
import info.nightscout.androidaps.logging.AAPSLogger
|
import info.nightscout.androidaps.logging.AAPSLogger
|
||||||
import info.nightscout.androidaps.logging.LTag
|
import info.nightscout.androidaps.logging.LTag
|
||||||
import info.nightscout.androidaps.logging.UserEntryLogger
|
import info.nightscout.androidaps.logging.UserEntryLogger
|
||||||
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
||||||
import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientRestart
|
import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientRestart
|
||||||
import info.nightscout.androidaps.plugins.treatments.events.EventTreatmentUpdateGui
|
import info.nightscout.androidaps.plugins.treatments.events.EventTreatmentUpdateGui
|
||||||
import info.nightscout.androidaps.plugins.treatments.fragments.TreatmentsTempTargetFragment.RecyclerViewAdapter.TempTargetsViewHolder
|
import info.nightscout.androidaps.activities.fragments.TreatmentsTempTargetFragment.RecyclerViewAdapter.TempTargetsViewHolder
|
||||||
import info.nightscout.androidaps.utils.DateUtil
|
import info.nightscout.androidaps.utils.DateUtil
|
||||||
import info.nightscout.androidaps.utils.FabricPrivacy
|
import info.nightscout.androidaps.utils.FabricPrivacy
|
||||||
import info.nightscout.androidaps.utils.T
|
import info.nightscout.androidaps.utils.T
|
||||||
|
@ -58,7 +57,6 @@ class TreatmentsTempTargetFragment : DaggerFragment() {
|
||||||
@Inject lateinit var aapsLogger: AAPSLogger
|
@Inject lateinit var aapsLogger: AAPSLogger
|
||||||
@Inject lateinit var profileFunction: ProfileFunction
|
@Inject lateinit var profileFunction: ProfileFunction
|
||||||
@Inject lateinit var resourceHelper: ResourceHelper
|
@Inject lateinit var resourceHelper: ResourceHelper
|
||||||
@Inject lateinit var uploadQueue: UploadQueueInterface
|
|
||||||
@Inject lateinit var fabricPrivacy: FabricPrivacy
|
@Inject lateinit var fabricPrivacy: FabricPrivacy
|
||||||
@Inject lateinit var translator: Translator
|
@Inject lateinit var translator: Translator
|
||||||
@Inject lateinit var dateUtil: DateUtil
|
@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
|
if (nsUploadOnly) binding.refreshFromNightscout.visibility = View.INVISIBLE
|
||||||
binding.showInvalidated.setOnCheckedChangeListener { _, _ ->
|
binding.showInvalidated.setOnCheckedChangeListener { _, _ ->
|
||||||
rxBus.send(EventTreatmentUpdateGui())
|
rxBus.send(EventTreatmentUpdateGui())
|
||||||
|
@ -151,7 +149,7 @@ class TreatmentsTempTargetFragment : DaggerFragment() {
|
||||||
_binding = null
|
_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 dbRecord = repository.getTemporaryTargetActiveAt(dateUtil.now()).blockingGet()
|
||||||
private val currentlyActiveTarget = if (dbRecord is ValueWrapper.Existing) dbRecord.value else null
|
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.content.DialogInterface
|
||||||
import android.graphics.Paint
|
import android.graphics.Paint
|
||||||
|
@ -12,12 +12,15 @@ import dagger.android.support.DaggerFragment
|
||||||
import info.nightscout.androidaps.R
|
import info.nightscout.androidaps.R
|
||||||
import info.nightscout.androidaps.data.IobTotal
|
import info.nightscout.androidaps.data.IobTotal
|
||||||
import info.nightscout.androidaps.database.AppRepository
|
import info.nightscout.androidaps.database.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.TemporaryBasal
|
||||||
import info.nightscout.androidaps.database.entities.UserEntry.*
|
import info.nightscout.androidaps.database.entities.UserEntry.*
|
||||||
import info.nightscout.androidaps.database.entities.UserEntry.Action
|
import info.nightscout.androidaps.database.entities.UserEntry.Action
|
||||||
import info.nightscout.androidaps.database.entities.UserEntry.Sources
|
import info.nightscout.androidaps.database.entities.UserEntry.Sources
|
||||||
import info.nightscout.androidaps.database.entities.ValueWithUnit
|
import info.nightscout.androidaps.database.entities.ValueWithUnit
|
||||||
import info.nightscout.androidaps.database.interfaces.end
|
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.database.transactions.InvalidateTemporaryBasalTransaction
|
||||||
import info.nightscout.androidaps.databinding.TreatmentsTempbasalsFragmentBinding
|
import info.nightscout.androidaps.databinding.TreatmentsTempbasalsFragmentBinding
|
||||||
import info.nightscout.androidaps.databinding.TreatmentsTempbasalsItemBinding
|
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.LTag
|
||||||
import info.nightscout.androidaps.logging.UserEntryLogger
|
import info.nightscout.androidaps.logging.UserEntryLogger
|
||||||
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
||||||
import info.nightscout.androidaps.plugins.treatments.fragments.TreatmentsTemporaryBasalsFragment.RecyclerViewAdapter.TempBasalsViewHolder
|
import info.nightscout.androidaps.activities.fragments.TreatmentsTemporaryBasalsFragment.RecyclerViewAdapter.TempBasalsViewHolder
|
||||||
import info.nightscout.androidaps.utils.DateUtil
|
import info.nightscout.androidaps.utils.DateUtil
|
||||||
import info.nightscout.androidaps.utils.FabricPrivacy
|
import info.nightscout.androidaps.utils.FabricPrivacy
|
||||||
import info.nightscout.androidaps.utils.T
|
import info.nightscout.androidaps.utils.T
|
||||||
|
@ -42,6 +45,7 @@ import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||||
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
||||||
import io.reactivex.disposables.CompositeDisposable
|
import io.reactivex.disposables.CompositeDisposable
|
||||||
import io.reactivex.rxkotlin.plusAssign
|
import io.reactivex.rxkotlin.plusAssign
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import kotlin.math.abs
|
import kotlin.math.abs
|
||||||
|
|
||||||
|
@ -194,21 +198,41 @@ class TreatmentsTemporaryBasalsFragment : DaggerFragment() {
|
||||||
init {
|
init {
|
||||||
binding.remove.setOnClickListener { v: View ->
|
binding.remove.setOnClickListener { v: View ->
|
||||||
val tempBasal = v.tag as TemporaryBasal
|
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())
|
val profile = profileFunction.getProfile(dateUtil.now())
|
||||||
?: return@setOnClickListener
|
?: return@setOnClickListener
|
||||||
context?.let {
|
context?.let {
|
||||||
OKDialog.showConfirmation(it, resourceHelper.gs(R.string.removerecord),
|
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)}
|
${resourceHelper.gs(R.string.date)}: ${dateUtil.dateAndTimeString(tempBasal.timestamp)}
|
||||||
""".trimIndent(),
|
""".trimIndent(),
|
||||||
{ _: DialogInterface?, _: Int ->
|
{ _: DialogInterface?, _: Int ->
|
||||||
|
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,
|
uel.log(Action.TEMP_BASAL_REMOVED, Sources.Treatments,
|
||||||
ValueWithUnit.Timestamp(tempBasal.timestamp))
|
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))
|
disposable += repository.runTransactionForResult(InvalidateTemporaryBasalTransaction(tempBasal.id))
|
||||||
.subscribe(
|
.subscribe(
|
||||||
{ aapsLogger.debug(LTag.DATABASE, "Removed temporary basal $tempBasal") },
|
{ aapsLogger.debug(LTag.DATABASE, "Removed temporary basal $tempBasal") },
|
||||||
{ aapsLogger.error(LTag.DATABASE, "Error while invalidating temporary basal", it) })
|
{ aapsLogger.error(LTag.DATABASE, "Error while invalidating temporary basal", it) })
|
||||||
|
}
|
||||||
}, null)
|
}, null)
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package info.nightscout.androidaps.plugins.treatments.fragments
|
package info.nightscout.androidaps.activities.fragments
|
||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
|
@ -1,7 +1,5 @@
|
||||||
package info.nightscout.androidaps.data.defaultProfile
|
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.data.PureProfile
|
||||||
import info.nightscout.androidaps.extensions.pureProfileFromJson
|
import info.nightscout.androidaps.extensions.pureProfileFromJson
|
||||||
import info.nightscout.androidaps.interfaces.GlucoseUnit
|
import info.nightscout.androidaps.interfaces.GlucoseUnit
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package info.nightscout.androidaps.data.defaultProfile
|
package info.nightscout.androidaps.data.defaultProfile
|
||||||
|
|
||||||
import dagger.android.HasAndroidInjector
|
import dagger.android.HasAndroidInjector
|
||||||
import info.nightscout.androidaps.data.ProfileImplOld
|
|
||||||
import info.nightscout.androidaps.data.PureProfile
|
import info.nightscout.androidaps.data.PureProfile
|
||||||
import info.nightscout.androidaps.extensions.pureProfileFromJson
|
import info.nightscout.androidaps.extensions.pureProfileFromJson
|
||||||
import info.nightscout.androidaps.interfaces.GlucoseUnit
|
import info.nightscout.androidaps.interfaces.GlucoseUnit
|
||||||
|
|
|
@ -75,12 +75,16 @@ class CompatDBHelper @Inject constructor(
|
||||||
rxBus.send(EventFoodDatabaseChanged())
|
rxBus.send(EventFoodDatabaseChanged())
|
||||||
}
|
}
|
||||||
it.filterIsInstance<ProfileSwitch>().firstOrNull()?.let {
|
it.filterIsInstance<ProfileSwitch>().firstOrNull()?.let {
|
||||||
aapsLogger.debug(LTag.DATABASE, "Firing EventProfileNeedsUpdate")
|
aapsLogger.debug(LTag.DATABASE, "Firing EventProfileSwitchChanged")
|
||||||
rxBus.send(EventProfileSwitchChanged())
|
rxBus.send(EventProfileSwitchChanged())
|
||||||
}
|
}
|
||||||
it.filterIsInstance<EffectiveProfileSwitch>().firstOrNull()?.let {
|
it.filterIsInstance<EffectiveProfileSwitch>().firstOrNull()?.let {
|
||||||
aapsLogger.debug(LTag.DATABASE, "Firing EventProfileNeedsUpdate")
|
aapsLogger.debug(LTag.DATABASE, "Firing EventProfileSwitchChanged")
|
||||||
rxBus.send(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.DatabaseUtils;
|
||||||
import android.database.sqlite.SQLiteDatabase;
|
import android.database.sqlite.SQLiteDatabase;
|
||||||
|
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
|
|
||||||
import com.j256.ormlite.android.apptools.OrmLiteSqliteOpenHelper;
|
import com.j256.ormlite.android.apptools.OrmLiteSqliteOpenHelper;
|
||||||
import com.j256.ormlite.dao.CloseableIterator;
|
import com.j256.ormlite.dao.CloseableIterator;
|
||||||
import com.j256.ormlite.dao.Dao;
|
import com.j256.ormlite.dao.Dao;
|
||||||
|
@ -20,19 +18,14 @@ import java.sql.SQLException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.Executors;
|
|
||||||
import java.util.concurrent.ScheduledExecutorService;
|
|
||||||
import java.util.concurrent.ScheduledFuture;
|
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
import info.nightscout.androidaps.events.EventRefreshOverview;
|
import info.nightscout.androidaps.events.EventRefreshOverview;
|
||||||
import info.nightscout.androidaps.interfaces.ActivePlugin;
|
import info.nightscout.androidaps.interfaces.ActivePlugin;
|
||||||
import info.nightscout.androidaps.interfaces.DatabaseHelperInterface;
|
|
||||||
import info.nightscout.androidaps.logging.AAPSLogger;
|
import info.nightscout.androidaps.logging.AAPSLogger;
|
||||||
import info.nightscout.androidaps.logging.LTag;
|
import info.nightscout.androidaps.logging.LTag;
|
||||||
import info.nightscout.androidaps.plugins.bus.RxBusWrapper;
|
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.general.openhumans.OpenHumansUploader;
|
||||||
import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpPlugin;
|
import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpPlugin;
|
||||||
import info.nightscout.androidaps.utils.DateUtil;
|
import info.nightscout.androidaps.utils.DateUtil;
|
||||||
|
@ -51,12 +44,9 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
|
||||||
@Inject VirtualPumpPlugin virtualPumpPlugin;
|
@Inject VirtualPumpPlugin virtualPumpPlugin;
|
||||||
@Inject OpenHumansUploader openHumansUploader;
|
@Inject OpenHumansUploader openHumansUploader;
|
||||||
@Inject ActivePlugin activePlugin;
|
@Inject ActivePlugin activePlugin;
|
||||||
@Inject NSUpload nsUpload;
|
|
||||||
@Inject DateUtil dateUtil;
|
@Inject DateUtil dateUtil;
|
||||||
|
|
||||||
public static final String DATABASE_NAME = "AndroidAPSDb";
|
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;
|
private static final int DATABASE_VERSION = 13;
|
||||||
|
|
||||||
|
@ -76,19 +66,8 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
|
||||||
public void onCreate(SQLiteDatabase database, ConnectionSource connectionSource) {
|
public void onCreate(SQLiteDatabase database, ConnectionSource connectionSource) {
|
||||||
try {
|
try {
|
||||||
aapsLogger.info(LTag.DATABASE, "onCreate");
|
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, OmnipodHistoryRecord.class);
|
||||||
TableUtils.createTableIfNotExists(connectionSource, OHQueueItem.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) {
|
} catch (SQLException e) {
|
||||||
aapsLogger.error("Can't create database", e);
|
aapsLogger.error("Can't create database", e);
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
|
@ -103,22 +82,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
|
||||||
|
|
||||||
if (oldVersion < 7) {
|
if (oldVersion < 7) {
|
||||||
aapsLogger.info(LTag.DATABASE, "onUpgrade");
|
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);
|
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);
|
TableUtils.createTableIfNotExists(connectionSource, OHQueueItem.class);
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
|
@ -149,15 +113,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
|
||||||
|
|
||||||
public void resetDatabases() {
|
public void resetDatabases() {
|
||||||
try {
|
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.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);
|
TableUtils.createTableIfNotExists(connectionSource, OmnipodHistoryRecord.class);
|
||||||
updateEarliestDataChange(0);
|
updateEarliestDataChange(0);
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
|
@ -177,34 +133,6 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
|
||||||
|
|
||||||
// ------------------ getDao -------------------------------------------
|
// ------------------ 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 {
|
private Dao<OmnipodHistoryRecord, Long> getDaoPodHistory() throws SQLException {
|
||||||
return getDao(OmnipodHistoryRecord.class);
|
return getDao(OmnipodHistoryRecord.class);
|
||||||
}
|
}
|
||||||
|
@ -213,76 +141,6 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
|
||||||
return getDao(OHQueueItem.class);
|
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) {
|
public static void updateEarliestDataChange(long newDate) {
|
||||||
if (earliestDataChange == null) {
|
if (earliestDataChange == null) {
|
||||||
earliestDataChange = newDate;
|
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 ---------------
|
// ---------------- Food handling ---------------
|
||||||
|
|
||||||
// ---------------- PodHistory handling ---------------
|
// ---------------- PodHistory handling ---------------
|
||||||
|
@ -924,14 +293,4 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
|
||||||
}
|
}
|
||||||
return 0L;
|
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 com.j256.ormlite.dao.CloseableIterator;
|
||||||
|
|
||||||
import org.json.JSONObject;
|
|
||||||
|
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
@ -23,61 +21,24 @@ public class DatabaseHelperProvider implements DatabaseHelperInterface {
|
||||||
@Inject DatabaseHelperProvider() {
|
@Inject DatabaseHelperProvider() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override public void createOrUpdate(@NonNull DanaRHistoryRecord record) {
|
|
||||||
MainApp.Companion.getDbHelper().createOrUpdate(record);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public void createOrUpdate(@NonNull OmnipodHistoryRecord record) {
|
@Override public void createOrUpdate(@NonNull OmnipodHistoryRecord record) {
|
||||||
MainApp.Companion.getDbHelper().createOrUpdate(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) {
|
@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) {
|
@Nullable @Override public TemporaryBasal findTempBasalByPumpId(long id) {
|
||||||
return MainApp.Companion.getDbHelper().findTempBasalByPumpId(id);
|
// return MainApp.Companion.getDbHelper().findTempBasalByPumpId(id);
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Deprecated
|
@Deprecated
|
||||||
@NonNull @Override public List<TemporaryBasal> getTemporaryBasalsDataFromTime(long mills, boolean ascending) {
|
@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) {
|
@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);
|
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) {
|
@Override public void delete(@NonNull ExtendedBolus extendedBolus) {
|
||||||
MainApp.Companion.getDbHelper().delete(extendedBolus);
|
// MainApp.Companion.getDbHelper().delete(extendedBolus);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable @Override public ExtendedBolus getExtendedBolusByPumpId(long pumpId) {
|
@Nullable @Override public ExtendedBolus getExtendedBolusByPumpId(long pumpId) {
|
||||||
return MainApp.Companion.getDbHelper().getExtendedBolusByPumpId(pumpId);
|
// return MainApp.Companion.getDbHelper().getExtendedBolusByPumpId(pumpId);
|
||||||
}
|
return null;
|
||||||
|
|
||||||
@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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override public void resetDatabases() {
|
@Override public void resetDatabases() {
|
||||||
|
@ -140,10 +78,6 @@ public class DatabaseHelperProvider implements DatabaseHelperInterface {
|
||||||
MainApp.Companion.getDbHelper().clearOpenHumansQueue();
|
MainApp.Companion.getDbHelper().clearOpenHumansQueue();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override public long getCountOfAllRows() {
|
|
||||||
return MainApp.Companion.getDbHelper().getCountOfAllRows();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public void removeAllOHQueueItemsWithIdSmallerThan(long id) {
|
@Override public void removeAllOHQueueItemsWithIdSmallerThan(long id) {
|
||||||
MainApp.Companion.getDbHelper().removeAllOHQueueItemsWithIdSmallerThan(id);
|
MainApp.Companion.getDbHelper().removeAllOHQueueItemsWithIdSmallerThan(id);
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ import dagger.Module
|
||||||
import dagger.android.ContributesAndroidInjector
|
import dagger.android.ContributesAndroidInjector
|
||||||
import info.nightscout.androidaps.MainActivity
|
import info.nightscout.androidaps.MainActivity
|
||||||
import info.nightscout.androidaps.activities.*
|
import info.nightscout.androidaps.activities.*
|
||||||
import info.nightscout.androidaps.historyBrowser.HistoryBrowseActivity
|
import info.nightscout.androidaps.activities.HistoryBrowseActivity
|
||||||
import info.nightscout.androidaps.plugins.general.maintenance.activities.LogSettingActivity
|
import info.nightscout.androidaps.plugins.general.maintenance.activities.LogSettingActivity
|
||||||
import info.nightscout.androidaps.plugins.general.openhumans.OpenHumansLoginActivity
|
import info.nightscout.androidaps.plugins.general.openhumans.OpenHumansLoginActivity
|
||||||
import info.nightscout.androidaps.plugins.general.overview.activities.QuickWizardListActivity
|
import info.nightscout.androidaps.plugins.general.overview.activities.QuickWizardListActivity
|
||||||
|
@ -15,6 +15,7 @@ import info.nightscout.androidaps.setupwizard.SetupWizardActivity
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
abstract class ActivitiesModule {
|
abstract class ActivitiesModule {
|
||||||
|
|
||||||
|
@ContributesAndroidInjector abstract fun contributesTreatmentsActivity(): TreatmentsActivity
|
||||||
@ContributesAndroidInjector abstract fun contributesHistoryBrowseActivity(): HistoryBrowseActivity
|
@ContributesAndroidInjector abstract fun contributesHistoryBrowseActivity(): HistoryBrowseActivity
|
||||||
@ContributesAndroidInjector abstract fun contributesLogSettingActivity(): LogSettingActivity
|
@ContributesAndroidInjector abstract fun contributesLogSettingActivity(): LogSettingActivity
|
||||||
@ContributesAndroidInjector abstract fun contributeMainActivity(): MainActivity
|
@ContributesAndroidInjector abstract fun contributeMainActivity(): MainActivity
|
||||||
|
|
|
@ -7,12 +7,15 @@ import dagger.android.AndroidInjector
|
||||||
import info.nightscout.androidaps.MainApp
|
import info.nightscout.androidaps.MainApp
|
||||||
import info.nightscout.androidaps.automation.di.AutomationModule
|
import info.nightscout.androidaps.automation.di.AutomationModule
|
||||||
import info.nightscout.androidaps.combo.di.ComboModule
|
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.dana.di.DanaModule
|
||||||
import info.nightscout.androidaps.danar.di.DanaRModule
|
import info.nightscout.androidaps.danar.di.DanaRModule
|
||||||
import info.nightscout.androidaps.danars.di.DanaRSModule
|
import info.nightscout.androidaps.danars.di.DanaRSModule
|
||||||
import info.nightscout.androidaps.danars.di.InsightModule
|
|
||||||
import info.nightscout.androidaps.database.DatabaseModule
|
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.common.di.RileyLinkModule
|
||||||
import info.nightscout.androidaps.plugins.pump.medtronic.di.MedtronicModule
|
import info.nightscout.androidaps.plugins.pump.medtronic.di.MedtronicModule
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.dagger.OmnipodDashModule
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.dagger.OmnipodDashModule
|
||||||
|
@ -35,6 +38,7 @@ import javax.inject.Singleton
|
||||||
CommandQueueModule::class,
|
CommandQueueModule::class,
|
||||||
ObjectivesModule::class,
|
ObjectivesModule::class,
|
||||||
WizardModule::class,
|
WizardModule::class,
|
||||||
|
PumpCommonModule::class,
|
||||||
RileyLinkModule::class,
|
RileyLinkModule::class,
|
||||||
MedtronicModule::class,
|
MedtronicModule::class,
|
||||||
OmnipodDashModule::class,
|
OmnipodDashModule::class,
|
||||||
|
@ -47,10 +51,12 @@ import javax.inject.Singleton
|
||||||
UIModule::class,
|
UIModule::class,
|
||||||
CoreModule::class,
|
CoreModule::class,
|
||||||
DanaModule::class,
|
DanaModule::class,
|
||||||
|
DanaHistoryModule::class,
|
||||||
DanaRModule::class,
|
DanaRModule::class,
|
||||||
DanaRSModule::class,
|
DanaRSModule::class,
|
||||||
ComboModule::class,
|
ComboModule::class,
|
||||||
InsightModule::class,
|
InsightModule::class,
|
||||||
|
InsightDatabaseModule::class,
|
||||||
WorkersModule::class,
|
WorkersModule::class,
|
||||||
OHUploaderModule::class
|
OHUploaderModule::class
|
||||||
]
|
]
|
||||||
|
|
|
@ -6,32 +6,34 @@ import dagger.Lazy
|
||||||
import dagger.Module
|
import dagger.Module
|
||||||
import dagger.Provides
|
import dagger.Provides
|
||||||
import dagger.android.HasAndroidInjector
|
import dagger.android.HasAndroidInjector
|
||||||
import info.nightscout.androidaps.interfaces.Config
|
|
||||||
import info.nightscout.androidaps.MainApp
|
import info.nightscout.androidaps.MainApp
|
||||||
|
import info.nightscout.androidaps.database.AppRepository
|
||||||
import info.nightscout.androidaps.db.DatabaseHelperProvider
|
import info.nightscout.androidaps.db.DatabaseHelperProvider
|
||||||
import info.nightscout.androidaps.interfaces.*
|
import info.nightscout.androidaps.interfaces.*
|
||||||
import info.nightscout.androidaps.logging.AAPSLogger
|
import info.nightscout.androidaps.logging.AAPSLogger
|
||||||
import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin
|
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.ConfigBuilderPlugin
|
||||||
import info.nightscout.androidaps.plugins.configBuilder.PluginStore
|
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.maintenance.ImportExportPrefsImpl
|
||||||
import info.nightscout.androidaps.plugins.general.nsclient.DataSyncSelectorImplementation
|
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.general.smsCommunicator.SmsCommunicatorPlugin
|
||||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin
|
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin
|
||||||
import info.nightscout.androidaps.plugins.pump.PumpSyncImplementation
|
import info.nightscout.androidaps.plugins.pump.PumpSyncImplementation
|
||||||
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin
|
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin
|
||||||
import info.nightscout.androidaps.queue.CommandQueue
|
import info.nightscout.androidaps.queue.CommandQueue
|
||||||
|
import info.nightscout.androidaps.utils.DateUtil
|
||||||
import info.nightscout.androidaps.utils.androidNotification.NotificationHolderImpl
|
import info.nightscout.androidaps.utils.androidNotification.NotificationHolderImpl
|
||||||
import info.nightscout.androidaps.utils.buildHelper.ConfigImpl
|
import info.nightscout.androidaps.utils.buildHelper.ConfigImpl
|
||||||
import info.nightscout.androidaps.utils.resources.IconsProviderImplementation
|
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.AapsSchedulers
|
||||||
import info.nightscout.androidaps.utils.rx.DefaultAapsSchedulers
|
import info.nightscout.androidaps.utils.rx.DefaultAapsSchedulers
|
||||||
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
||||||
import info.nightscout.androidaps.utils.storage.FileStorage
|
import info.nightscout.androidaps.utils.storage.FileStorage
|
||||||
import info.nightscout.androidaps.utils.storage.Storage
|
import info.nightscout.androidaps.utils.storage.Storage
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
|
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
@Module(includes = [
|
@Module(includes = [
|
||||||
AppModule.AppBindings::class
|
AppModule.AppBindings::class
|
||||||
|
@ -64,32 +66,32 @@ open class AppModule {
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@Singleton
|
@Singleton
|
||||||
fun providesUploadQueue(
|
fun provideProfileFunction(aapsLogger: AAPSLogger, sp: SP, resourceHelper: ResourceHelper, activePlugin: ActivePlugin, repository: AppRepository, dateUtil: DateUtil): ProfileFunction {
|
||||||
aapsLogger: AAPSLogger,
|
return ProfileFunctionImplementation(aapsLogger, sp, resourceHelper, activePlugin, repository, dateUtil)
|
||||||
databaseHelper: DatabaseHelperInterface,
|
}
|
||||||
context: Context,
|
|
||||||
sp: SP,
|
|
||||||
rxBus: RxBusWrapper
|
|
||||||
): UploadQueueAdminInterface = UploadQueue(aapsLogger, databaseHelper, context, sp, rxBus)
|
|
||||||
|
|
||||||
@Module
|
@Module
|
||||||
interface AppBindings {
|
interface AppBindings {
|
||||||
|
|
||||||
@Binds fun bindContext(mainApp: MainApp): Context
|
@Binds fun bindContext(mainApp: MainApp): Context
|
||||||
@Binds fun bindInjector(mainApp: MainApp): HasAndroidInjector
|
@Binds fun bindInjector(mainApp: MainApp): HasAndroidInjector
|
||||||
@Binds fun bindActivePluginProvider(pluginStore: PluginStore): ActivePlugin
|
@Binds fun bindActivePluginProvider(pluginStore: PluginStore): ActivePlugin
|
||||||
@Binds fun bindCommandQueueProvider(commandQueue: CommandQueue): CommandQueueProvider
|
@Binds fun bindCommandQueueProvider(commandQueue: CommandQueue): CommandQueueProvider
|
||||||
@Binds fun bindConfigInterface(config: ConfigImpl): Config
|
@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 bindTreatmentsInterface(treatmentsPlugin: TreatmentsPlugin): TreatmentsInterface
|
||||||
|
|
||||||
@Binds fun bindDatabaseHelperInterface(databaseHelperProvider: DatabaseHelperProvider): DatabaseHelperInterface
|
@Binds fun bindDatabaseHelperInterface(databaseHelperProvider: DatabaseHelperProvider): DatabaseHelperInterface
|
||||||
@Binds fun bindNotificationHolderInterface(notificationHolder: NotificationHolderImpl): NotificationHolder
|
@Binds fun bindNotificationHolderInterface(notificationHolder: NotificationHolderImpl): NotificationHolder
|
||||||
@Binds fun bindImportExportPrefsInterface(importExportPrefs: ImportExportPrefsImpl): ImportExportPrefs
|
@Binds fun bindImportExportPrefsInterface(importExportPrefs: ImportExportPrefsImpl): ImportExportPrefs
|
||||||
@Binds fun bindIconsProviderInterface(iconsProvider: IconsProviderImplementation): IconsProvider
|
@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 bindIobCobCalculatorInterface(iobCobCalculatorPlugin: IobCobCalculatorPlugin): IobCobCalculator
|
||||||
@Binds fun bindSmsCommunicatorInterface(smsCommunicatorPlugin: SmsCommunicatorPlugin): SmsCommunicator
|
@Binds fun bindSmsCommunicatorInterface(smsCommunicatorPlugin: SmsCommunicatorPlugin): SmsCommunicator
|
||||||
@Binds fun bindUploadQueueAdminInterfaceToUploadQueue(uploadQueueAdminInterface: UploadQueueAdminInterface) : UploadQueueInterface
|
|
||||||
@Binds fun bindDataSyncSelector(dataSyncSelectorImplementation: DataSyncSelectorImplementation): DataSyncSelector
|
@Binds fun bindDataSyncSelector(dataSyncSelectorImplementation: DataSyncSelectorImplementation): DataSyncSelector
|
||||||
|
|
||||||
@Binds fun bindPumpSync(pumpSyncImplementation: PumpSyncImplementation): PumpSync
|
@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.general.wear.WearFragment
|
||||||
import info.nightscout.androidaps.plugins.insulin.InsulinFragment
|
import info.nightscout.androidaps.plugins.insulin.InsulinFragment
|
||||||
import info.nightscout.androidaps.plugins.profile.local.LocalProfileFragment
|
import info.nightscout.androidaps.plugins.profile.local.LocalProfileFragment
|
||||||
import info.nightscout.androidaps.plugins.profile.ns.NSProfileFragment
|
|
||||||
import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpFragment
|
import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpFragment
|
||||||
import info.nightscout.androidaps.plugins.source.BGSourceFragment
|
import info.nightscout.androidaps.plugins.source.BGSourceFragment
|
||||||
import info.nightscout.androidaps.plugins.treatments.TreatmentsFragment
|
import info.nightscout.androidaps.activities.fragments.*
|
||||||
import info.nightscout.androidaps.plugins.treatments.fragments.*
|
|
||||||
import info.nightscout.androidaps.utils.protection.PasswordCheck
|
import info.nightscout.androidaps.utils.protection.PasswordCheck
|
||||||
|
|
||||||
@Module
|
@Module
|
||||||
|
@ -46,8 +44,7 @@ abstract class FragmentsModule {
|
||||||
@ContributesAndroidInjector abstract fun contributesAutomationFragment(): AutomationFragment
|
@ContributesAndroidInjector abstract fun contributesAutomationFragment(): AutomationFragment
|
||||||
@ContributesAndroidInjector abstract fun contributesBGSourceFragment(): BGSourceFragment
|
@ContributesAndroidInjector abstract fun contributesBGSourceFragment(): BGSourceFragment
|
||||||
|
|
||||||
@ContributesAndroidInjector
|
@ContributesAndroidInjector abstract fun contributesConfigBuilderFragment(): ConfigBuilderFragment
|
||||||
abstract fun contributesConfigBuilderFragment(): ConfigBuilderFragment
|
|
||||||
|
|
||||||
@ContributesAndroidInjector abstract fun contributesFoodFragment(): FoodFragment
|
@ContributesAndroidInjector abstract fun contributesFoodFragment(): FoodFragment
|
||||||
@ContributesAndroidInjector abstract fun contributesInsulinFragment(): InsulinFragment
|
@ContributesAndroidInjector abstract fun contributesInsulinFragment(): InsulinFragment
|
||||||
|
@ -58,14 +55,11 @@ abstract class FragmentsModule {
|
||||||
@ContributesAndroidInjector abstract fun contributesOverviewFragment(): OverviewFragment
|
@ContributesAndroidInjector abstract fun contributesOverviewFragment(): OverviewFragment
|
||||||
@ContributesAndroidInjector abstract fun contributesLoopFragment(): LoopFragment
|
@ContributesAndroidInjector abstract fun contributesLoopFragment(): LoopFragment
|
||||||
@ContributesAndroidInjector abstract fun contributesMaintenanceFragment(): MaintenanceFragment
|
@ContributesAndroidInjector abstract fun contributesMaintenanceFragment(): MaintenanceFragment
|
||||||
@ContributesAndroidInjector abstract fun contributesNSProfileFragment(): NSProfileFragment
|
|
||||||
@ContributesAndroidInjector abstract fun contributesNSClientFragment(): NSClientFragment
|
@ContributesAndroidInjector abstract fun contributesNSClientFragment(): NSClientFragment
|
||||||
@ContributesAndroidInjector
|
@ContributesAndroidInjector abstract fun contributesSmsCommunicatorFragment(): SmsCommunicatorFragment
|
||||||
abstract fun contributesSmsCommunicatorFragment(): SmsCommunicatorFragment
|
|
||||||
@ContributesAndroidInjector abstract fun contributesWearFragment(): WearFragment
|
@ContributesAndroidInjector abstract fun contributesWearFragment(): WearFragment
|
||||||
|
|
||||||
@ContributesAndroidInjector abstract fun contributesTidepoolFragment(): TidepoolFragment
|
@ContributesAndroidInjector abstract fun contributesTidepoolFragment(): TidepoolFragment
|
||||||
@ContributesAndroidInjector abstract fun contributesTreatmentsFragment(): TreatmentsFragment
|
|
||||||
@ContributesAndroidInjector abstract fun contributesTreatmentsBolusFragment(): TreatmentsBolusCarbsFragment
|
@ContributesAndroidInjector abstract fun contributesTreatmentsBolusFragment(): TreatmentsBolusCarbsFragment
|
||||||
@ContributesAndroidInjector abstract fun contributesTreatmentsTemporaryBasalsFragment(): TreatmentsTemporaryBasalsFragment
|
@ContributesAndroidInjector abstract fun contributesTreatmentsTemporaryBasalsFragment(): TreatmentsTemporaryBasalsFragment
|
||||||
@ContributesAndroidInjector abstract fun contributesTreatmentsTempTargetFragment(): TreatmentsTempTargetFragment
|
@ContributesAndroidInjector abstract fun contributesTreatmentsTempTargetFragment(): TreatmentsTempTargetFragment
|
||||||
|
@ -85,8 +79,7 @@ abstract class FragmentsModule {
|
||||||
@ContributesAndroidInjector abstract fun contributesEditEventDialog(): EditEventDialog
|
@ContributesAndroidInjector abstract fun contributesEditEventDialog(): EditEventDialog
|
||||||
@ContributesAndroidInjector abstract fun contributesEditTriggerDialog(): EditTriggerDialog
|
@ContributesAndroidInjector abstract fun contributesEditTriggerDialog(): EditTriggerDialog
|
||||||
|
|
||||||
@ContributesAndroidInjector
|
@ContributesAndroidInjector abstract fun contributesEditQuickWizardDialog(): EditQuickWizardDialog
|
||||||
abstract fun contributesEditQuickWizardDialog(): EditQuickWizardDialog
|
|
||||||
|
|
||||||
@ContributesAndroidInjector abstract fun contributesExtendedBolusDialog(): ExtendedBolusDialog
|
@ContributesAndroidInjector abstract fun contributesExtendedBolusDialog(): ExtendedBolusDialog
|
||||||
@ContributesAndroidInjector abstract fun contributesFillDialog(): FillDialog
|
@ContributesAndroidInjector abstract fun contributesFillDialog(): FillDialog
|
||||||
|
@ -102,8 +95,7 @@ abstract class FragmentsModule {
|
||||||
@ContributesAndroidInjector abstract fun contributesWizardDialog(): WizardDialog
|
@ContributesAndroidInjector abstract fun contributesWizardDialog(): WizardDialog
|
||||||
@ContributesAndroidInjector abstract fun contributesWizardInfoDialog(): WizardInfoDialog
|
@ContributesAndroidInjector abstract fun contributesWizardInfoDialog(): WizardInfoDialog
|
||||||
|
|
||||||
@ContributesAndroidInjector
|
@ContributesAndroidInjector abstract fun contributesExchangeAuthTokenDialog(): OpenHumansLoginActivity.ExchangeAuthTokenDialog
|
||||||
abstract fun contributesExchangeAuthTokenDialot(): OpenHumansLoginActivity.ExchangeAuthTokenDialog
|
|
||||||
|
|
||||||
@ContributesAndroidInjector abstract fun contributesPasswordCheck(): PasswordCheck
|
@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.insulin.InsulinOrefUltraRapidActingPlugin
|
||||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin
|
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin
|
||||||
import info.nightscout.androidaps.plugins.profile.local.LocalProfilePlugin
|
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.combo.ComboPlugin
|
||||||
import info.nightscout.androidaps.plugins.pump.insight.LocalInsightPlugin
|
import info.nightscout.androidaps.plugins.pump.insight.LocalInsightPlugin
|
||||||
import info.nightscout.androidaps.plugins.pump.mdi.MDIPlugin
|
import info.nightscout.androidaps.plugins.pump.mdi.MDIPlugin
|
||||||
|
@ -151,11 +150,11 @@ abstract class PluginsModule {
|
||||||
@IntKey(140)
|
@IntKey(140)
|
||||||
abstract fun bindComboPlugin(plugin: ComboPlugin): PluginBase
|
abstract fun bindComboPlugin(plugin: ComboPlugin): PluginBase
|
||||||
|
|
||||||
@Binds
|
// @Binds
|
||||||
@PumpDriver
|
// @PumpDriver
|
||||||
@IntoMap
|
// @IntoMap
|
||||||
@IntKey(150)
|
// @IntKey(150)
|
||||||
abstract fun bindMedtronicPumpPlugin(plugin: MedtronicPumpPlugin): PluginBase
|
// abstract fun bindMedtronicPumpPlugin(plugin: MedtronicPumpPlugin): PluginBase
|
||||||
|
|
||||||
@Binds
|
@Binds
|
||||||
@PumpDriver
|
@PumpDriver
|
||||||
|
@ -202,12 +201,6 @@ abstract class PluginsModule {
|
||||||
@Binds
|
@Binds
|
||||||
@AllConfigs
|
@AllConfigs
|
||||||
@IntoMap
|
@IntoMap
|
||||||
@IntKey(230)
|
|
||||||
abstract fun bindNSProfilePlugin(plugin: NSProfilePlugin): PluginBase
|
|
||||||
|
|
||||||
@Binds
|
|
||||||
@NotNSClient
|
|
||||||
@IntoMap
|
|
||||||
@IntKey(240)
|
@IntKey(240)
|
||||||
abstract fun bindLocalProfilePlugin(plugin: LocalProfilePlugin): PluginBase
|
abstract fun bindLocalProfilePlugin(plugin: LocalProfilePlugin): PluginBase
|
||||||
|
|
||||||
|
@ -355,11 +348,11 @@ abstract class PluginsModule {
|
||||||
@IntKey(470)
|
@IntKey(470)
|
||||||
abstract fun bindRandomBgPlugin(plugin: RandomBgPlugin): PluginBase
|
abstract fun bindRandomBgPlugin(plugin: RandomBgPlugin): PluginBase
|
||||||
|
|
||||||
@Binds
|
// @Binds
|
||||||
@NotNSClient
|
// @NotNSClient
|
||||||
@IntoMap
|
// @IntoMap
|
||||||
@IntKey(480)
|
// @IntKey(480)
|
||||||
abstract fun bindOpenHumansPlugin(plugin: OpenHumansUploader): PluginBase
|
// abstract fun bindOpenHumansPlugin(plugin: OpenHumansUploader): PluginBase
|
||||||
|
|
||||||
@Binds
|
@Binds
|
||||||
@AllConfigs
|
@AllConfigs
|
||||||
|
|
|
@ -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.NSClientRemoveWorker
|
||||||
import info.nightscout.androidaps.plugins.general.nsclient.NSClientUpdateRemoveAckWorker
|
import info.nightscout.androidaps.plugins.general.nsclient.NSClientUpdateRemoveAckWorker
|
||||||
import info.nightscout.androidaps.plugins.general.smsCommunicator.SmsCommunicatorPlugin
|
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.*
|
import info.nightscout.androidaps.plugins.source.*
|
||||||
|
|
||||||
@Module
|
@Module
|
||||||
|
@ -24,7 +24,7 @@ abstract class WorkersModule {
|
||||||
@ContributesAndroidInjector abstract fun contributesTomatoWorker(): TomatoPlugin.TomatoWorker
|
@ContributesAndroidInjector abstract fun contributesTomatoWorker(): TomatoPlugin.TomatoWorker
|
||||||
@ContributesAndroidInjector abstract fun contributesEversenseWorker(): EversensePlugin.EversenseWorker
|
@ContributesAndroidInjector abstract fun contributesEversenseWorker(): EversensePlugin.EversenseWorker
|
||||||
@ContributesAndroidInjector abstract fun contributesNSClientSourceWorker(): NSClientSourcePlugin.NSClientSourceWorker
|
@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 contributesSmsCommunicatorWorker(): SmsCommunicatorPlugin.SmsCommunicatorWorker
|
||||||
@ContributesAndroidInjector abstract fun contributesNSClientWorker(): NSClientAddUpdateWorker
|
@ContributesAndroidInjector abstract fun contributesNSClientWorker(): NSClientAddUpdateWorker
|
||||||
@ContributesAndroidInjector abstract fun contributesNSClientAddAckWorker(): NSClientAddAckWorker
|
@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.Action
|
||||||
import info.nightscout.androidaps.database.entities.UserEntry.Sources
|
import info.nightscout.androidaps.database.entities.UserEntry.Sources
|
||||||
import info.nightscout.androidaps.database.entities.ValueWithUnit
|
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.databinding.DialogCarbsBinding
|
||||||
import info.nightscout.androidaps.extensions.formatColor
|
import info.nightscout.androidaps.extensions.formatColor
|
||||||
import info.nightscout.androidaps.interfaces.Constraint
|
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.LTag
|
||||||
import info.nightscout.androidaps.logging.UserEntryLogger
|
import info.nightscout.androidaps.logging.UserEntryLogger
|
||||||
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
|
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
|
||||||
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin
|
|
||||||
import info.nightscout.androidaps.queue.Callback
|
import info.nightscout.androidaps.queue.Callback
|
||||||
import info.nightscout.androidaps.queue.CommandQueue
|
import info.nightscout.androidaps.queue.CommandQueue
|
||||||
import info.nightscout.androidaps.utils.*
|
import info.nightscout.androidaps.utils.*
|
||||||
|
@ -47,7 +46,6 @@ class CarbsDialog : DialogFragmentWithDate() {
|
||||||
@Inject lateinit var resourceHelper: ResourceHelper
|
@Inject lateinit var resourceHelper: ResourceHelper
|
||||||
@Inject lateinit var constraintChecker: ConstraintChecker
|
@Inject lateinit var constraintChecker: ConstraintChecker
|
||||||
@Inject lateinit var defaultValueHelper: DefaultValueHelper
|
@Inject lateinit var defaultValueHelper: DefaultValueHelper
|
||||||
@Inject lateinit var treatmentsPlugin: TreatmentsPlugin
|
|
||||||
@Inject lateinit var profileFunction: ProfileFunction
|
@Inject lateinit var profileFunction: ProfileFunction
|
||||||
@Inject lateinit var iobCobCalculator: IobCobCalculator
|
@Inject lateinit var iobCobCalculator: IobCobCalculator
|
||||||
@Inject lateinit var uel: UserEntryLogger
|
@Inject lateinit var uel: UserEntryLogger
|
||||||
|
@ -228,7 +226,7 @@ class CarbsDialog : DialogFragmentWithDate() {
|
||||||
ValueWithUnit.TherapyEventTTReason(TemporaryTarget.Reason.ACTIVITY),
|
ValueWithUnit.TherapyEventTTReason(TemporaryTarget.Reason.ACTIVITY),
|
||||||
ValueWithUnit.fromGlucoseUnit(activityTT, units.asText),
|
ValueWithUnit.fromGlucoseUnit(activityTT, units.asText),
|
||||||
ValueWithUnit.Minute(activityTTDuration))
|
ValueWithUnit.Minute(activityTTDuration))
|
||||||
disposable += repository.runTransactionForResult(InsertTemporaryTargetAndCancelCurrentTransaction(
|
disposable += repository.runTransactionForResult(InsertAndCancelCurrentTemporaryTargetTransaction(
|
||||||
timestamp = System.currentTimeMillis(),
|
timestamp = System.currentTimeMillis(),
|
||||||
duration = TimeUnit.MINUTES.toMillis(activityTTDuration.toLong()),
|
duration = TimeUnit.MINUTES.toMillis(activityTTDuration.toLong()),
|
||||||
reason = TemporaryTarget.Reason.ACTIVITY,
|
reason = TemporaryTarget.Reason.ACTIVITY,
|
||||||
|
@ -247,7 +245,7 @@ class CarbsDialog : DialogFragmentWithDate() {
|
||||||
ValueWithUnit.TherapyEventTTReason(TemporaryTarget.Reason.EATING_SOON),
|
ValueWithUnit.TherapyEventTTReason(TemporaryTarget.Reason.EATING_SOON),
|
||||||
ValueWithUnit.fromGlucoseUnit(eatingSoonTT, units.asText),
|
ValueWithUnit.fromGlucoseUnit(eatingSoonTT, units.asText),
|
||||||
ValueWithUnit.Minute(eatingSoonTTDuration))
|
ValueWithUnit.Minute(eatingSoonTTDuration))
|
||||||
disposable += repository.runTransactionForResult(InsertTemporaryTargetAndCancelCurrentTransaction(
|
disposable += repository.runTransactionForResult(InsertAndCancelCurrentTemporaryTargetTransaction(
|
||||||
timestamp = System.currentTimeMillis(),
|
timestamp = System.currentTimeMillis(),
|
||||||
duration = TimeUnit.MINUTES.toMillis(eatingSoonTTDuration.toLong()),
|
duration = TimeUnit.MINUTES.toMillis(eatingSoonTTDuration.toLong()),
|
||||||
reason = TemporaryTarget.Reason.EATING_SOON,
|
reason = TemporaryTarget.Reason.EATING_SOON,
|
||||||
|
@ -266,7 +264,7 @@ class CarbsDialog : DialogFragmentWithDate() {
|
||||||
ValueWithUnit.TherapyEventTTReason(TemporaryTarget.Reason.HYPOGLYCEMIA),
|
ValueWithUnit.TherapyEventTTReason(TemporaryTarget.Reason.HYPOGLYCEMIA),
|
||||||
ValueWithUnit.fromGlucoseUnit(hypoTT, units.asText),
|
ValueWithUnit.fromGlucoseUnit(hypoTT, units.asText),
|
||||||
ValueWithUnit.Minute(hypoTTDuration))
|
ValueWithUnit.Minute(hypoTTDuration))
|
||||||
disposable += repository.runTransactionForResult(InsertTemporaryTargetAndCancelCurrentTransaction(
|
disposable += repository.runTransactionForResult(InsertAndCancelCurrentTemporaryTargetTransaction(
|
||||||
timestamp = System.currentTimeMillis(),
|
timestamp = System.currentTimeMillis(),
|
||||||
duration = TimeUnit.MINUTES.toMillis(hypoTTDuration.toLong()),
|
duration = TimeUnit.MINUTES.toMillis(hypoTTDuration.toLong()),
|
||||||
reason = TemporaryTarget.Reason.HYPOGLYCEMIA,
|
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.TemporaryTarget
|
||||||
import info.nightscout.androidaps.database.entities.UserEntry.Action
|
import info.nightscout.androidaps.database.entities.UserEntry.Action
|
||||||
import info.nightscout.androidaps.database.entities.UserEntry.Sources
|
import info.nightscout.androidaps.database.entities.UserEntry.Sources
|
||||||
import info.nightscout.androidaps.database.transactions.InsertTemporaryTargetAndCancelCurrentTransaction
|
import info.nightscout.androidaps.database.transactions.InsertAndCancelCurrentTemporaryTargetTransaction
|
||||||
import info.nightscout.androidaps.databinding.DialogInsulinBinding
|
import info.nightscout.androidaps.databinding.DialogInsulinBinding
|
||||||
import info.nightscout.androidaps.logging.LTag
|
import info.nightscout.androidaps.logging.LTag
|
||||||
import info.nightscout.androidaps.logging.UserEntryLogger
|
import info.nightscout.androidaps.logging.UserEntryLogger
|
||||||
|
@ -186,7 +186,7 @@ class InsulinDialog : DialogFragmentWithDate() {
|
||||||
ValueWithUnit.TherapyEventTTReason(TemporaryTarget.Reason.EATING_SOON),
|
ValueWithUnit.TherapyEventTTReason(TemporaryTarget.Reason.EATING_SOON),
|
||||||
ValueWithUnit.fromGlucoseUnit(eatingSoonTT, units.asText),
|
ValueWithUnit.fromGlucoseUnit(eatingSoonTT, units.asText),
|
||||||
ValueWithUnit.Minute(eatingSoonTTDuration))
|
ValueWithUnit.Minute(eatingSoonTTDuration))
|
||||||
disposable += repository.runTransactionForResult(InsertTemporaryTargetAndCancelCurrentTransaction(
|
disposable += repository.runTransactionForResult(InsertAndCancelCurrentTemporaryTargetTransaction(
|
||||||
timestamp = System.currentTimeMillis(),
|
timestamp = System.currentTimeMillis(),
|
||||||
duration = TimeUnit.MINUTES.toMillis(eatingSoonTTDuration.toLong()),
|
duration = TimeUnit.MINUTES.toMillis(eatingSoonTTDuration.toLong()),
|
||||||
reason = TemporaryTarget.Reason.EATING_SOON,
|
reason = TemporaryTarget.Reason.EATING_SOON,
|
||||||
|
|
|
@ -12,9 +12,13 @@ import androidx.fragment.app.FragmentManager
|
||||||
import dagger.android.support.DaggerDialogFragment
|
import dagger.android.support.DaggerDialogFragment
|
||||||
import info.nightscout.androidaps.R
|
import info.nightscout.androidaps.R
|
||||||
import info.nightscout.androidaps.activities.ErrorHelperActivity
|
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.ValueWithUnit
|
||||||
import info.nightscout.androidaps.database.entities.UserEntry.Action
|
import info.nightscout.androidaps.database.entities.UserEntry.Action
|
||||||
import info.nightscout.androidaps.database.entities.UserEntry.Sources
|
import info.nightscout.androidaps.database.entities.UserEntry.Sources
|
||||||
|
import info.nightscout.androidaps.database.transactions.CancelCurrentOfflineEventIfAnyTransaction
|
||||||
|
import info.nightscout.androidaps.database.transactions.InsertAndCancelCurrentOfflineEventTransaction
|
||||||
import info.nightscout.androidaps.databinding.DialogLoopBinding
|
import info.nightscout.androidaps.databinding.DialogLoopBinding
|
||||||
import info.nightscout.androidaps.events.EventPreferenceChange
|
import info.nightscout.androidaps.events.EventPreferenceChange
|
||||||
import info.nightscout.androidaps.events.EventRefreshOverview
|
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.ToastUtils
|
||||||
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
|
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
|
||||||
import info.nightscout.androidaps.extensions.toVisibility
|
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.resources.ResourceHelper
|
||||||
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
||||||
|
import io.reactivex.disposables.CompositeDisposable
|
||||||
|
import io.reactivex.rxkotlin.plusAssign
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class LoopDialog : DaggerDialogFragment() {
|
class LoopDialog : DaggerDialogFragment() {
|
||||||
|
@ -48,6 +57,8 @@ class LoopDialog : DaggerDialogFragment() {
|
||||||
@Inject lateinit var commandQueue: CommandQueueProvider
|
@Inject lateinit var commandQueue: CommandQueueProvider
|
||||||
@Inject lateinit var configBuilder: ConfigBuilder
|
@Inject lateinit var configBuilder: ConfigBuilder
|
||||||
@Inject lateinit var uel: UserEntryLogger
|
@Inject lateinit var uel: UserEntryLogger
|
||||||
|
@Inject lateinit var dateUtil: DateUtil
|
||||||
|
@Inject lateinit var repository: AppRepository
|
||||||
|
|
||||||
private var showOkCancel: Boolean = true
|
private var showOkCancel: Boolean = true
|
||||||
private var _binding: DialogLoopBinding? = null
|
private var _binding: DialogLoopBinding? = null
|
||||||
|
@ -58,6 +69,8 @@ class LoopDialog : DaggerDialogFragment() {
|
||||||
// onDestroyView.
|
// onDestroyView.
|
||||||
private val binding get() = _binding!!
|
private val binding get() = _binding!!
|
||||||
|
|
||||||
|
val disposable = CompositeDisposable()
|
||||||
|
|
||||||
override fun onStart() {
|
override fun onStart() {
|
||||||
super.onStart()
|
super.onStart()
|
||||||
dialog?.window?.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
|
dialog?.window?.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
|
||||||
|
@ -118,6 +131,7 @@ class LoopDialog : DaggerDialogFragment() {
|
||||||
super.onDestroyView()
|
super.onDestroyView()
|
||||||
_binding = null
|
_binding = null
|
||||||
loopHandler.removeCallbacksAndMessages(null)
|
loopHandler.removeCallbacksAndMessages(null)
|
||||||
|
disposable.clear()
|
||||||
}
|
}
|
||||||
|
|
||||||
var task: Runnable? = null
|
var task: Runnable? = null
|
||||||
|
@ -196,6 +210,7 @@ class LoopDialog : DaggerDialogFragment() {
|
||||||
binding.overviewDisconnectButtons.visibility = View.GONE
|
binding.overviewDisconnectButtons.visibility = View.GONE
|
||||||
binding.overviewReconnect.visibility = View.VISIBLE
|
binding.overviewReconnect.visibility = View.VISIBLE
|
||||||
}
|
}
|
||||||
|
binding.overviewLoop.visibility = (!loopPlugin.isSuspended && !loopPlugin.isDisconnected).toVisibility()
|
||||||
}
|
}
|
||||||
val profile = profileFunction.getProfile()
|
val profile = profileFunction.getProfile()
|
||||||
val profileStore = activePlugin.activeProfileSource.profile
|
val profileStore = activePlugin.activeProfileSource.profile
|
||||||
|
@ -237,7 +252,6 @@ class LoopDialog : DaggerDialogFragment() {
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onClick(v: View): Boolean {
|
fun onClick(v: View): Boolean {
|
||||||
val profile = profileFunction.getProfile() ?: return true
|
|
||||||
when (v.id) {
|
when (v.id) {
|
||||||
R.id.overview_closeloop -> {
|
R.id.overview_closeloop -> {
|
||||||
uel.log(Action.CLOSED_LOOP_MODE, Sources.LoopDialog)
|
uel.log(Action.CLOSED_LOOP_MODE, Sources.LoopDialog)
|
||||||
|
@ -273,7 +287,13 @@ 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
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -283,13 +303,23 @@ class LoopDialog : DaggerDialogFragment() {
|
||||||
loopPlugin.setFragmentVisible(PluginType.LOOP, true)
|
loopPlugin.setFragmentVisible(PluginType.LOOP, true)
|
||||||
configBuilder.storeSettings("EnablingLoop")
|
configBuilder.storeSettings("EnablingLoop")
|
||||||
rxBus.send(EventRefreshOverview("suspendmenu"))
|
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
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.overview_resume, R.id.overview_reconnect -> {
|
R.id.overview_resume, R.id.overview_reconnect -> {
|
||||||
uel.log(if (v.id == R.id.overview_resume) Action.RESUME else Action.RECONNECT, Sources.LoopDialog)
|
uel.log(if (v.id == R.id.overview_resume) Action.RESUME else Action.RECONNECT, Sources.LoopDialog)
|
||||||
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("suspendmenu"))
|
rxBus.send(EventRefreshOverview("suspendmenu"))
|
||||||
commandQueue.cancelTempBasal(true, object : Callback() {
|
commandQueue.cancelTempBasal(true, object : Callback() {
|
||||||
override fun run() {
|
override fun run() {
|
||||||
|
@ -299,55 +329,96 @@ class LoopDialog : DaggerDialogFragment() {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
sp.putBoolean(R.string.key_objectiveusereconnect, true)
|
sp.putBoolean(R.string.key_objectiveusereconnect, true)
|
||||||
loopPlugin.createOfflineEvent(0)
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.overview_suspend_1h -> {
|
R.id.overview_suspend_1h -> {
|
||||||
uel.log(Action.SUSPEND, Sources.LoopDialog, ValueWithUnit.Hour(1))
|
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"))
|
rxBus.send(EventRefreshOverview("suspendmenu"))
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.overview_suspend_2h -> {
|
R.id.overview_suspend_2h -> {
|
||||||
uel.log(Action.SUSPEND, Sources.LoopDialog, ValueWithUnit.Hour(2))
|
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"))
|
rxBus.send(EventRefreshOverview("suspendmenu"))
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.overview_suspend_3h -> {
|
R.id.overview_suspend_3h -> {
|
||||||
uel.log(Action.SUSPEND, Sources.LoopDialog, ValueWithUnit.Hour(3))
|
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"))
|
rxBus.send(EventRefreshOverview("suspendmenu"))
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.overview_suspend_10h -> {
|
R.id.overview_suspend_10h -> {
|
||||||
uel.log(Action.SUSPEND, Sources.LoopDialog, ValueWithUnit.Hour(10))
|
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"))
|
rxBus.send(EventRefreshOverview("suspendmenu"))
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.overview_disconnect_15m -> {
|
R.id.overview_disconnect_15m -> {
|
||||||
uel.log(Action.DISCONNECT, Sources.LoopDialog, ValueWithUnit.Minute(15))
|
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"))
|
rxBus.send(EventRefreshOverview("suspendmenu"))
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.overview_disconnect_30m -> {
|
R.id.overview_disconnect_30m -> {
|
||||||
uel.log(Action.DISCONNECT, Sources.LoopDialog, ValueWithUnit.Minute(30))
|
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"))
|
rxBus.send(EventRefreshOverview("suspendmenu"))
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.overview_disconnect_1h -> {
|
R.id.overview_disconnect_1h -> {
|
||||||
uel.log(Action.DISCONNECT, Sources.LoopDialog, ValueWithUnit.Hour(1))
|
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)
|
sp.putBoolean(R.string.key_objectiveusedisconnect, true)
|
||||||
rxBus.send(EventRefreshOverview("suspendmenu"))
|
rxBus.send(EventRefreshOverview("suspendmenu"))
|
||||||
return true
|
return true
|
||||||
|
@ -355,14 +426,26 @@ class LoopDialog : DaggerDialogFragment() {
|
||||||
|
|
||||||
R.id.overview_disconnect_2h -> {
|
R.id.overview_disconnect_2h -> {
|
||||||
uel.log(Action.DISCONNECT, Sources.LoopDialog, ValueWithUnit.Hour(2))
|
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"))
|
rxBus.send(EventRefreshOverview("suspendmenu"))
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.overview_disconnect_3h -> {
|
R.id.overview_disconnect_3h -> {
|
||||||
uel.log(Action.DISCONNECT, Sources.LoopDialog, ValueWithUnit.Hour(3))
|
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"))
|
rxBus.send(EventRefreshOverview("suspendmenu"))
|
||||||
return true
|
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.Action
|
||||||
import info.nightscout.androidaps.database.entities.UserEntry.Sources
|
import info.nightscout.androidaps.database.entities.UserEntry.Sources
|
||||||
import info.nightscout.androidaps.database.transactions.CancelCurrentTemporaryTargetIfAnyTransaction
|
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.databinding.DialogTemptargetBinding
|
||||||
import info.nightscout.androidaps.interfaces.GlucoseUnit
|
import info.nightscout.androidaps.interfaces.GlucoseUnit
|
||||||
import info.nightscout.androidaps.interfaces.ProfileFunction
|
import info.nightscout.androidaps.interfaces.ProfileFunction
|
||||||
|
@ -196,7 +196,7 @@ class TempTargetDialog : DialogFragmentWithDate() {
|
||||||
aapsLogger.error(LTag.DATABASE, "Error while saving temporary target", it)
|
aapsLogger.error(LTag.DATABASE, "Error while saving temporary target", it)
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
disposable += repository.runTransactionForResult(InsertTemporaryTargetAndCancelCurrentTransaction(
|
disposable += repository.runTransactionForResult(InsertAndCancelCurrentTemporaryTargetTransaction(
|
||||||
timestamp = eventTime,
|
timestamp = eventTime,
|
||||||
duration = TimeUnit.MINUTES.toMillis(duration.toLong()),
|
duration = TimeUnit.MINUTES.toMillis(duration.toLong()),
|
||||||
reason = when (reason) {
|
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.interfaces.Profile
|
||||||
import info.nightscout.androidaps.data.PumpEnactResult
|
import info.nightscout.androidaps.data.PumpEnactResult
|
||||||
import info.nightscout.androidaps.database.AppRepository
|
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.Action
|
||||||
import info.nightscout.androidaps.database.entities.UserEntry.Sources
|
import info.nightscout.androidaps.database.entities.UserEntry.Sources
|
||||||
import info.nightscout.androidaps.database.entities.ValueWithUnit
|
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.database.transactions.InsertTherapyEventAnnouncementTransaction
|
||||||
import info.nightscout.androidaps.events.EventAcceptOpenLoopChange
|
import info.nightscout.androidaps.events.EventAcceptOpenLoopChange
|
||||||
import info.nightscout.androidaps.events.EventAutosensCalculationFinished
|
import info.nightscout.androidaps.events.EventAutosensCalculationFinished
|
||||||
import info.nightscout.androidaps.events.EventNewBG
|
import info.nightscout.androidaps.events.EventNewBG
|
||||||
import info.nightscout.androidaps.events.EventTempTargetChange
|
import info.nightscout.androidaps.events.EventTempTargetChange
|
||||||
import info.nightscout.androidaps.interfaces.*
|
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.AAPSLogger
|
||||||
import info.nightscout.androidaps.logging.LTag
|
import info.nightscout.androidaps.logging.LTag
|
||||||
import info.nightscout.androidaps.logging.UserEntryLogger
|
import info.nightscout.androidaps.logging.UserEntryLogger
|
||||||
|
@ -54,6 +55,7 @@ import info.nightscout.androidaps.extensions.buildDeviceStatus
|
||||||
import info.nightscout.androidaps.extensions.convertedToAbsolute
|
import info.nightscout.androidaps.extensions.convertedToAbsolute
|
||||||
import info.nightscout.androidaps.extensions.convertedToPercent
|
import info.nightscout.androidaps.extensions.convertedToPercent
|
||||||
import info.nightscout.androidaps.extensions.plannedRemainingMinutes
|
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.resources.ResourceHelper
|
||||||
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
||||||
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
||||||
|
@ -95,7 +97,7 @@ open class LoopPlugin @Inject constructor(
|
||||||
.enableByDefault(config.APS)
|
.enableByDefault(config.APS)
|
||||||
.description(R.string.description_loop),
|
.description(R.string.description_loop),
|
||||||
aapsLogger, resourceHelper, injector
|
aapsLogger, resourceHelper, injector
|
||||||
), LoopInterface {
|
), Loop {
|
||||||
|
|
||||||
private val disposable = CompositeDisposable()
|
private val disposable = CompositeDisposable()
|
||||||
private var lastBgTriggeredRun: Long = 0
|
private var lastBgTriggeredRun: Long = 0
|
||||||
|
@ -157,48 +159,19 @@ open class LoopPlugin @Inject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun suspendTo(endTime: Long) {
|
override fun minutesToEndOfSuspend(): Int {
|
||||||
sp.putLong("loopSuspendedTill", endTime)
|
val offlineEventWrapped = repository.getOfflineEventActiveAt(dateUtil.now()).blockingGet()
|
||||||
sp.putBoolean("isSuperBolus", false)
|
return if (offlineEventWrapped is ValueWrapper.Existing) T.msecs(offlineEventWrapped.value.timestamp + offlineEventWrapped.value.duration - dateUtil.now()).mins().toInt()
|
||||||
sp.putBoolean("isDisconnected", false)
|
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
|
override val isSuspended: Boolean
|
||||||
get() {
|
get() = repository.getOfflineEventActiveAt(dateUtil.now()).blockingGet() is ValueWrapper.Existing
|
||||||
val loopSuspendedTill = sp.getLong("loopSuspendedTill", 0L)
|
|
||||||
if (loopSuspendedTill == 0L) return false
|
override var enabled: Boolean
|
||||||
val now = System.currentTimeMillis()
|
get() = isEnabled()
|
||||||
if (loopSuspendedTill <= now) { // time exceeded
|
set(value) { setPluginEnabled(PluginType.LOOP, value)}
|
||||||
suspendTo(0L)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
val isLGS: Boolean
|
val isLGS: Boolean
|
||||||
get() {
|
get() {
|
||||||
val closedLoopEnabled = constraintChecker.isClosedLoopAllowed()
|
val closedLoopEnabled = constraintChecker.isClosedLoopAllowed()
|
||||||
|
@ -210,30 +183,16 @@ open class LoopPlugin @Inject constructor(
|
||||||
return isLGS
|
return isLGS
|
||||||
}
|
}
|
||||||
|
|
||||||
// time exceeded
|
|
||||||
val isSuperBolus: Boolean
|
val isSuperBolus: Boolean
|
||||||
get() {
|
get() {
|
||||||
val loopSuspendedTill = sp.getLong("loopSuspendedTill", 0L)
|
val offlineEventWrapped = repository.getOfflineEventActiveAt(dateUtil.now()).blockingGet()
|
||||||
if (loopSuspendedTill == 0L) return false
|
return offlineEventWrapped is ValueWrapper.Existing && offlineEventWrapped.value.reason == OfflineEvent.Reason.SUPER_BOLUS
|
||||||
val now = System.currentTimeMillis()
|
|
||||||
if (loopSuspendedTill <= now) { // time exceeded
|
|
||||||
suspendTo(0L)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return sp.getBoolean("isSuperBolus", false)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// time exceeded
|
|
||||||
val isDisconnected: Boolean
|
val isDisconnected: Boolean
|
||||||
get() {
|
get() {
|
||||||
val loopSuspendedTill = sp.getLong("loopSuspendedTill", 0L)
|
val offlineEventWrapped = repository.getOfflineEventActiveAt(dateUtil.now()).blockingGet()
|
||||||
if (loopSuspendedTill == 0L) return false
|
return offlineEventWrapped is ValueWrapper.Existing && offlineEventWrapped.value.reason == OfflineEvent.Reason.DISCONNECT_PUMP
|
||||||
val now = System.currentTimeMillis()
|
|
||||||
if (loopSuspendedTill <= now) { // time exceeded
|
|
||||||
suspendTo(0L)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return sp.getBoolean("isDisconnected", false)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("SameParameterValue")
|
@Suppress("SameParameterValue")
|
||||||
|
@ -286,7 +245,7 @@ open class LoopPlugin @Inject constructor(
|
||||||
if (apsResult == null) {
|
if (apsResult == null) {
|
||||||
rxBus.send(EventLoopSetLastRunGui(resourceHelper.gs(R.string.noapsselected)))
|
rxBus.send(EventLoopSetLastRunGui(resourceHelper.gs(R.string.noapsselected)))
|
||||||
return
|
return
|
||||||
}
|
} else rxBus.send(EventLoopInvoked())
|
||||||
|
|
||||||
// Prepare for pumps using % basals
|
// Prepare for pumps using % basals
|
||||||
if (pump.pumpDescription.tempBasalStyle == PumpDescription.PERCENT && allowPercentage()) {
|
if (pump.pumpDescription.tempBasalStyle == PumpDescription.PERCENT && allowPercentage()) {
|
||||||
|
@ -403,7 +362,7 @@ open class LoopPlugin @Inject constructor(
|
||||||
val waiting = PumpEnactResult(injector)
|
val waiting = PumpEnactResult(injector)
|
||||||
waiting.queued = true
|
waiting.queued = true
|
||||||
if (resultAfterConstraints.tempBasalRequested) lastRun.tbrSetByPump = waiting
|
if (resultAfterConstraints.tempBasalRequested) lastRun.tbrSetByPump = waiting
|
||||||
if (resultAfterConstraints.bolusRequested) lastRun.smbSetByPump = waiting
|
if (resultAfterConstraints.bolusRequested()) lastRun.smbSetByPump = waiting
|
||||||
rxBus.send(EventLoopUpdateGui())
|
rxBus.send(EventLoopUpdateGui())
|
||||||
fabricPrivacy.logCustom("APSRequest")
|
fabricPrivacy.logCustom("APSRequest")
|
||||||
applyTBRRequest(resultAfterConstraints, profile, object : Callback() {
|
applyTBRRequest(resultAfterConstraints, profile, object : Callback() {
|
||||||
|
@ -600,7 +559,7 @@ open class LoopPlugin @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun applySMBRequest(request: APSResult, callback: Callback?) {
|
private fun applySMBRequest(request: APSResult, callback: Callback?) {
|
||||||
if (!request.bolusRequested) {
|
if (!request.bolusRequested()) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
val pump = activePlugin.activePump
|
val pump = activePlugin.activePump
|
||||||
|
@ -641,11 +600,17 @@ open class LoopPlugin @Inject constructor(
|
||||||
return virtualPumpPlugin.isEnabled(PluginType.PUMP)
|
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
|
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) {
|
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() {
|
override fun run() {
|
||||||
if (!result.success) {
|
if (!result.success) {
|
||||||
ErrorHelperActivity.runAlarm(context, result.comment, resourceHelper.gs(R.string.tempbasaldeliveryerror), info.nightscout.androidaps.dana.R.raw.boluserror)
|
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 {
|
} 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() {
|
override fun run() {
|
||||||
if (!result.success) {
|
if (!result.success) {
|
||||||
ErrorHelperActivity.runAlarm(context, result.comment, resourceHelper.gs(R.string.tempbasaldeliveryerror), info.nightscout.androidaps.dana.R.raw.boluserror)
|
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) {
|
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() {
|
commandQueue.cancelTempBasal(true, object : Callback() {
|
||||||
override fun run() {
|
override fun run() {
|
||||||
if (!result.success) {
|
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 {
|
companion object {
|
||||||
|
|
|
@ -40,7 +40,6 @@ class DetermineBasalResultAMA private constructor(injector: HasAndroidInjector)
|
||||||
tempBasalRequested = false
|
tempBasalRequested = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
bolusRequested = false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun newAndClone(injector: HasAndroidInjector): DetermineBasalResultAMA {
|
override fun newAndClone(injector: HasAndroidInjector): DetermineBasalResultAMA {
|
||||||
|
|
|
@ -58,6 +58,7 @@ class OpenAPSAMAFragment : DaggerFragment() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Synchronized
|
@Synchronized
|
||||||
|
@kotlin.ExperimentalStdlibApi
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
super.onResume()
|
super.onResume()
|
||||||
|
|
||||||
|
@ -90,6 +91,7 @@ class OpenAPSAMAFragment : DaggerFragment() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Synchronized
|
@Synchronized
|
||||||
|
@kotlin.ExperimentalStdlibApi
|
||||||
private fun updateGUI() {
|
private fun updateGUI() {
|
||||||
if (_binding == null) return
|
if (_binding == null) return
|
||||||
openAPSAMAPlugin.lastAPSResult?.let { lastAPSResult ->
|
openAPSAMAPlugin.lastAPSResult?.let { lastAPSResult ->
|
||||||
|
|
|
@ -35,7 +35,6 @@ class DetermineBasalResultSMB private constructor(injector: HasAndroidInjector)
|
||||||
duration = -1
|
duration = -1
|
||||||
}
|
}
|
||||||
if (result.has("units")) {
|
if (result.has("units")) {
|
||||||
bolusRequested = true
|
|
||||||
smb = result.getDouble("units")
|
smb = result.getDouble("units")
|
||||||
} else {
|
} else {
|
||||||
smb = 0.0
|
smb = 0.0
|
||||||
|
|
|
@ -59,6 +59,7 @@ class OpenAPSSMBFragment : DaggerFragment() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Synchronized
|
@Synchronized
|
||||||
|
@kotlin.ExperimentalStdlibApi
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
super.onResume()
|
super.onResume()
|
||||||
disposable += rxBus
|
disposable += rxBus
|
||||||
|
@ -90,6 +91,7 @@ class OpenAPSSMBFragment : DaggerFragment() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Synchronized
|
@Synchronized
|
||||||
|
@kotlin.ExperimentalStdlibApi
|
||||||
fun updateGUI() {
|
fun updateGUI() {
|
||||||
if (_binding == null) return
|
if (_binding == null) return
|
||||||
openAPSSMBPlugin.lastAPSResult?.let { lastAPSResult ->
|
openAPSSMBPlugin.lastAPSResult?.let { lastAPSResult ->
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package info.nightscout.androidaps.plugins.configBuilder
|
package info.nightscout.androidaps.plugins.configBuilder
|
||||||
|
|
||||||
|
import androidx.collection.LongSparseArray
|
||||||
import info.nightscout.androidaps.Constants
|
import info.nightscout.androidaps.Constants
|
||||||
import info.nightscout.androidaps.core.R
|
import info.nightscout.androidaps.core.R
|
||||||
import info.nightscout.androidaps.data.ProfileSealed
|
import info.nightscout.androidaps.data.ProfileSealed
|
||||||
|
@ -35,6 +36,8 @@ class ProfileFunctionImplementation @Inject constructor(
|
||||||
private val dateUtil: DateUtil
|
private val dateUtil: DateUtil
|
||||||
) : ProfileFunction {
|
) : ProfileFunction {
|
||||||
|
|
||||||
|
val cache = LongSparseArray<Profile>()
|
||||||
|
|
||||||
private val disposable = CompositeDisposable()
|
private val disposable = CompositeDisposable()
|
||||||
|
|
||||||
override fun getProfileName(): String =
|
override fun getProfileName(): String =
|
||||||
|
@ -65,10 +68,20 @@ class ProfileFunctionImplementation @Inject constructor(
|
||||||
getProfile(dateUtil.now())
|
getProfile(dateUtil.now())
|
||||||
|
|
||||||
override fun getProfile(time: Long): Profile? {
|
override fun getProfile(time: Long): Profile? {
|
||||||
|
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")
|
// aapsLogger.debug("XXXXXXXXXXXXXXX getProfile called for $time")
|
||||||
val ps = repository.getEffectiveProfileSwitchActiveAt(time).blockingGet()
|
val ps = repository.getEffectiveProfileSwitchActiveAt(time).blockingGet()
|
||||||
return if (ps is ValueWrapper.Existing) ProfileSealed.EPS(ps.value)
|
if (ps is ValueWrapper.Existing) {
|
||||||
else null
|
val sealed = ProfileSealed.EPS(ps.value)
|
||||||
|
cache.put(rounded, sealed)
|
||||||
|
return sealed
|
||||||
|
}
|
||||||
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getRequestedProfile(): ProfileSwitch? = repository.getActiveProfileSwitch(dateUtil.now())
|
override fun getRequestedProfile(): ProfileSwitch? = repository.getActiveProfileSwitch(dateUtil.now())
|
||||||
|
@ -91,7 +104,8 @@ class ProfileFunctionImplementation @Inject constructor(
|
||||||
timeshift = T.hours(timeShiftInHours.toLong()).msecs(),
|
timeshift = T.hours(timeShiftInHours.toLong()).msecs(),
|
||||||
percentage = percentage,
|
percentage = percentage,
|
||||||
duration = T.mins(durationInMinutes.toLong()).msecs(),
|
duration = T.mins(durationInMinutes.toLong()).msecs(),
|
||||||
insulinConfiguration = activePlugin.activeInsulin.insulinConfiguration)
|
insulinConfiguration = activePlugin.activeInsulin.insulinConfiguration.also { it.insulinEndTime = (pureProfile.dia * 3600 * 1000).toLong() }
|
||||||
|
)
|
||||||
disposable += repository.runTransactionForResult(InsertOrUpdateProfileSwitch(ps))
|
disposable += repository.runTransactionForResult(InsertOrUpdateProfileSwitch(ps))
|
||||||
.subscribe({ result ->
|
.subscribe({ result ->
|
||||||
result.inserted.forEach { aapsLogger.debug(LTag.DATABASE, "Inserted ProfileSwitch $it") }
|
result.inserted.forEach { aapsLogger.debug(LTag.DATABASE, "Inserted ProfileSwitch $it") }
|
|
@ -120,9 +120,10 @@ class ObjectivesPlugin @Inject constructor(
|
||||||
sp.putBoolean(R.string.key_objectiveusescale, false)
|
sp.putBoolean(R.string.key_objectiveusescale, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@kotlin.ExperimentalStdlibApi
|
||||||
fun completeObjectives(activity: FragmentActivity, request: String) {
|
fun completeObjectives(activity: FragmentActivity, request: String) {
|
||||||
val requestCode = sp.getString(R.string.key_objectives_request_code, "")
|
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/"
|
if (!url.endsWith("/")) url = "$url/"
|
||||||
@Suppress("DEPRECATION") val hashNS = Hashing.sha1().hashString(url + BuildConfig.APPLICATION_ID + "/" + requestCode, Charsets.UTF_8).toString()
|
@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)) {
|
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.R
|
||||||
import info.nightscout.androidaps.plugins.constraints.objectives.ObjectivesPlugin
|
import info.nightscout.androidaps.plugins.constraints.objectives.ObjectivesPlugin
|
||||||
import info.nightscout.androidaps.plugins.general.nsclient.NSClientPlugin
|
import info.nightscout.androidaps.plugins.general.nsclient.NSClientPlugin
|
||||||
import info.nightscout.androidaps.plugins.general.nsclient.services.NSClientService
|
|
||||||
import info.nightscout.androidaps.utils.T
|
import info.nightscout.androidaps.utils.T
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
@ -28,8 +27,9 @@ class Objective3 @Inject constructor(injector: HasAndroidInjector) : Objective(i
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun specialActionEnabled(): Boolean =
|
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) {
|
override fun specialAction(activity: FragmentActivity, input: String) {
|
||||||
objectivesPlugin.completeObjectives(activity, input)
|
objectivesPlugin.completeObjectives(activity, input)
|
||||||
}
|
}
|
||||||
|
|
|
@ -152,12 +152,13 @@ class SignatureVerifierPlugin @Inject constructor(
|
||||||
return sb.toString()
|
return sb.toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@kotlin.ExperimentalStdlibApi
|
||||||
fun singleCharUnMap(shortHash: String): String {
|
fun singleCharUnMap(shortHash: String): String {
|
||||||
val array = ByteArray(shortHash.length)
|
val array = ByteArray(shortHash.length)
|
||||||
val sb = StringBuilder()
|
val sb = StringBuilder()
|
||||||
for (i in array.indices) {
|
for (i in array.indices) {
|
||||||
if (i != 0) sb.append(":")
|
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()
|
return sb.toString()
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,6 @@ import android.widget.LinearLayout
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import dagger.android.support.DaggerFragment
|
import dagger.android.support.DaggerFragment
|
||||||
import info.nightscout.androidaps.interfaces.Config
|
|
||||||
import info.nightscout.androidaps.Constants
|
import info.nightscout.androidaps.Constants
|
||||||
import info.nightscout.androidaps.R
|
import info.nightscout.androidaps.R
|
||||||
import info.nightscout.androidaps.activities.ErrorHelperActivity
|
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.Action
|
||||||
import info.nightscout.androidaps.database.entities.UserEntry.Sources
|
import info.nightscout.androidaps.database.entities.UserEntry.Sources
|
||||||
import info.nightscout.androidaps.dialogs.*
|
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.toStringMedium
|
||||||
import info.nightscout.androidaps.extensions.toStringShort
|
import info.nightscout.androidaps.extensions.toStringShort
|
||||||
import info.nightscout.androidaps.extensions.toVisibility
|
import info.nightscout.androidaps.extensions.toVisibility
|
||||||
import info.nightscout.androidaps.historyBrowser.HistoryBrowseActivity
|
import info.nightscout.androidaps.activities.HistoryBrowseActivity
|
||||||
import info.nightscout.androidaps.interfaces.ActivePlugin
|
import info.nightscout.androidaps.interfaces.ActivePlugin
|
||||||
import info.nightscout.androidaps.interfaces.CommandQueueProvider
|
import info.nightscout.androidaps.interfaces.CommandQueueProvider
|
||||||
|
import info.nightscout.androidaps.interfaces.Config
|
||||||
import info.nightscout.androidaps.interfaces.IobCobCalculator
|
import info.nightscout.androidaps.interfaces.IobCobCalculator
|
||||||
import info.nightscout.androidaps.interfaces.ProfileFunction
|
import info.nightscout.androidaps.interfaces.ProfileFunction
|
||||||
import info.nightscout.androidaps.logging.AAPSLogger
|
import info.nightscout.androidaps.logging.AAPSLogger
|
||||||
|
@ -229,10 +233,6 @@ class ActionsFragment : DaggerFragment() {
|
||||||
.toObservable(EventInitializationChanged::class.java)
|
.toObservable(EventInitializationChanged::class.java)
|
||||||
.observeOn(aapsSchedulers.main)
|
.observeOn(aapsSchedulers.main)
|
||||||
.subscribe({ updateGui() }, fabricPrivacy::logException)
|
.subscribe({ updateGui() }, fabricPrivacy::logException)
|
||||||
disposable += rxBus
|
|
||||||
.toObservable(EventRefreshOverview::class.java)
|
|
||||||
.observeOn(aapsSchedulers.main)
|
|
||||||
.subscribe({ updateGui() }, fabricPrivacy::logException)
|
|
||||||
disposable += rxBus
|
disposable += rxBus
|
||||||
.toObservable(EventExtendedBolusChange::class.java)
|
.toObservable(EventExtendedBolusChange::class.java)
|
||||||
.observeOn(aapsSchedulers.main)
|
.observeOn(aapsSchedulers.main)
|
||||||
|
|
|
@ -67,6 +67,7 @@ class FoodFragment : DaggerFragment() {
|
||||||
return binding.root
|
return binding.root
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@kotlin.ExperimentalStdlibApi
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
|
||||||
|
@ -128,6 +129,7 @@ class FoodFragment : DaggerFragment() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Synchronized
|
@Synchronized
|
||||||
|
@kotlin.ExperimentalStdlibApi
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
super.onResume()
|
super.onResume()
|
||||||
disposable.add(rxBus
|
disposable.add(rxBus
|
||||||
|
@ -139,6 +141,7 @@ class FoodFragment : DaggerFragment() {
|
||||||
swapAdapter()
|
swapAdapter()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@kotlin.ExperimentalStdlibApi
|
||||||
private fun swapAdapter() {
|
private fun swapAdapter() {
|
||||||
disposable += repository
|
disposable += repository
|
||||||
.getFoodData()
|
.getFoodData()
|
||||||
|
@ -199,6 +202,7 @@ class FoodFragment : DaggerFragment() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@kotlin.ExperimentalStdlibApi
|
||||||
private fun filterData() {
|
private fun filterData() {
|
||||||
val textFilter = binding.filter.text.toString()
|
val textFilter = binding.filter.text.toString()
|
||||||
val categoryFilter = binding.category.selectedItem?.toString()
|
val categoryFilter = binding.category.selectedItem?.toString()
|
||||||
|
@ -210,7 +214,7 @@ class FoodFragment : DaggerFragment() {
|
||||||
if (f.category == null || f.subCategory == null) continue
|
if (f.category == null || f.subCategory == null) continue
|
||||||
if (subcategoryFilter != resourceHelper.gs(R.string.none) && f.subCategory != subcategoryFilter) continue
|
if (subcategoryFilter != resourceHelper.gs(R.string.none) && f.subCategory != subcategoryFilter) continue
|
||||||
if (categoryFilter != resourceHelper.gs(R.string.none) && f.category != categoryFilter) 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)
|
newFiltered.add(f)
|
||||||
}
|
}
|
||||||
filtered = newFiltered
|
filtered = newFiltered
|
||||||
|
|
|
@ -7,13 +7,14 @@ import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import dagger.android.support.DaggerFragment
|
import dagger.android.support.DaggerFragment
|
||||||
import info.nightscout.androidaps.R
|
import info.nightscout.androidaps.R
|
||||||
|
import info.nightscout.androidaps.dana.database.DanaHistoryDatabase
|
||||||
import info.nightscout.androidaps.database.AppRepository
|
import info.nightscout.androidaps.database.AppRepository
|
||||||
import info.nightscout.androidaps.database.entities.UserEntry.Action
|
import info.nightscout.androidaps.database.entities.UserEntry.Action
|
||||||
import info.nightscout.androidaps.database.entities.UserEntry.Sources
|
import info.nightscout.androidaps.database.entities.UserEntry.Sources
|
||||||
import info.nightscout.androidaps.databinding.MaintenanceFragmentBinding
|
import info.nightscout.androidaps.databinding.MaintenanceFragmentBinding
|
||||||
import info.nightscout.androidaps.events.EventNewBG
|
import info.nightscout.androidaps.events.EventNewBG
|
||||||
|
import info.nightscout.androidaps.insight.database.InsightDatabase
|
||||||
import info.nightscout.androidaps.interfaces.DataSyncSelector
|
import info.nightscout.androidaps.interfaces.DataSyncSelector
|
||||||
import info.nightscout.androidaps.interfaces.DatabaseHelperInterface
|
|
||||||
import info.nightscout.androidaps.interfaces.ImportExportPrefs
|
import info.nightscout.androidaps.interfaces.ImportExportPrefs
|
||||||
import info.nightscout.androidaps.interfaces.PumpSync
|
import info.nightscout.androidaps.interfaces.PumpSync
|
||||||
import info.nightscout.androidaps.logging.AAPSLogger
|
import info.nightscout.androidaps.logging.AAPSLogger
|
||||||
|
@ -38,7 +39,8 @@ class MaintenanceFragment : DaggerFragment() {
|
||||||
@Inject lateinit var importExportPrefs: ImportExportPrefs
|
@Inject lateinit var importExportPrefs: ImportExportPrefs
|
||||||
@Inject lateinit var aapsSchedulers: AapsSchedulers
|
@Inject lateinit var aapsSchedulers: AapsSchedulers
|
||||||
@Inject lateinit var repository: AppRepository
|
@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 uel: UserEntryLogger
|
||||||
@Inject lateinit var dataSyncSelector: DataSyncSelector
|
@Inject lateinit var dataSyncSelector: DataSyncSelector
|
||||||
@Inject lateinit var pumpSync: PumpSync
|
@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 {
|
OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.maintenance), resourceHelper.gs(R.string.reset_db_confirm), Runnable {
|
||||||
compositeDisposable.add(
|
compositeDisposable.add(
|
||||||
fromAction {
|
fromAction {
|
||||||
databaseHelper.resetDatabases()
|
|
||||||
repository.clearDatabases()
|
repository.clearDatabases()
|
||||||
|
danaHistoryDatabase.clearAllTables()
|
||||||
|
insightDatabase.clearAllTables()
|
||||||
dataSyncSelector.resetToNextFullSync()
|
dataSyncSelector.resetToNextFullSync()
|
||||||
pumpSync.connectNewPump()
|
pumpSync.connectNewPump()
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,14 +2,15 @@ package info.nightscout.androidaps.plugins.general.nsclient
|
||||||
|
|
||||||
import info.nightscout.androidaps.R
|
import info.nightscout.androidaps.R
|
||||||
import info.nightscout.androidaps.database.AppRepository
|
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.database.entities.*
|
||||||
|
import info.nightscout.androidaps.extensions.toJson
|
||||||
import info.nightscout.androidaps.interfaces.ActivePlugin
|
import info.nightscout.androidaps.interfaces.ActivePlugin
|
||||||
import info.nightscout.androidaps.interfaces.DataSyncSelector
|
import info.nightscout.androidaps.interfaces.DataSyncSelector
|
||||||
import info.nightscout.androidaps.interfaces.ProfileFunction
|
import info.nightscout.androidaps.interfaces.ProfileFunction
|
||||||
import info.nightscout.androidaps.logging.AAPSLogger
|
import info.nightscout.androidaps.logging.AAPSLogger
|
||||||
import info.nightscout.androidaps.logging.LTag
|
import info.nightscout.androidaps.logging.LTag
|
||||||
import info.nightscout.androidaps.extensions.toJson
|
import info.nightscout.androidaps.plugins.profile.local.LocalProfilePlugin
|
||||||
import info.nightscout.androidaps.utils.DateUtil
|
import info.nightscout.androidaps.utils.DateUtil
|
||||||
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
@ -21,9 +22,28 @@ class DataSyncSelectorImplementation @Inject constructor(
|
||||||
private val profileFunction: ProfileFunction,
|
private val profileFunction: ProfileFunction,
|
||||||
private val nsClientPlugin: NSClientPlugin,
|
private val nsClientPlugin: NSClientPlugin,
|
||||||
private val activePlugin: ActivePlugin,
|
private val activePlugin: ActivePlugin,
|
||||||
private val appRepository: AppRepository
|
private val appRepository: AppRepository,
|
||||||
|
private val localProfilePlugin: LocalProfilePlugin
|
||||||
) : DataSyncSelector {
|
) : 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() {
|
override fun resetToNextFullSync() {
|
||||||
sp.remove(R.string.key_ns_temporary_target_last_synced_id)
|
sp.remove(R.string.key_ns_temporary_target_last_synced_id)
|
||||||
sp.remove(R.string.key_ns_glucose_value_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_extended_bolus_last_synced_id)
|
||||||
sp.remove(R.string.key_ns_therapy_event_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_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) {
|
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 {
|
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 ->
|
appRepository.getNextSyncElementBolus(startId).blockingGet()?.let { bolus ->
|
||||||
aapsLogger.info(LTag.DATABASE, "Loading Bolus data Start: $startId ID: ${bolus.first.id} HistoryID: ${bolus.second} ")
|
aapsLogger.info(LTag.DATABASE, "Loading Bolus data Start: $startId ID: ${bolus.first.id} HistoryID: ${bolus.second} ")
|
||||||
when {
|
when {
|
||||||
// removed and not uploaded yet = ignore
|
// without nsId = create new
|
||||||
!bolus.first.isValid && bolus.first.interfaceIDs.nightscoutId == null -> Any()
|
bolus.first.interfaceIDs.nightscoutId == null ->
|
||||||
// removed and already uploaded = send for removal
|
nsClientPlugin.nsClientService?.dbAdd("treatments", bolus.first.toJson(true, dateUtil), DataSyncSelector.PairBolus(bolus.first, bolus.second), "$startId/$lastDbId")
|
||||||
!bolus.first.isValid && bolus.first.interfaceIDs.nightscoutId != null ->
|
// with nsId = update
|
||||||
nsClientPlugin.nsClientService?.dbRemove("treatments", bolus.first.interfaceIDs.nightscoutId, DataSyncSelector.PairBolus(bolus.first, bolus.second))
|
bolus.first.interfaceIDs.nightscoutId != null ->
|
||||||
// existing without nsId = create new
|
nsClientPlugin.nsClientService?.dbUpdate("treatments", bolus.first.interfaceIDs.nightscoutId, bolus.first.toJson(false, dateUtil), DataSyncSelector.PairBolus(bolus.first, bolus.second), "$startId/$lastDbId")
|
||||||
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))
|
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
@ -93,22 +121,28 @@ class DataSyncSelectorImplementation @Inject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private var lastCarbsId = -1L
|
||||||
|
private var lastCarbsTime = -1L
|
||||||
override fun processChangedCarbsCompat(): Boolean {
|
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 ->
|
appRepository.getNextSyncElementCarbs(startId).blockingGet()?.let { carb ->
|
||||||
aapsLogger.info(LTag.DATABASE, "Loading Carbs data Start: $startId ID: ${carb.first.id} HistoryID: ${carb.second} ")
|
aapsLogger.info(LTag.DATABASE, "Loading Carbs data Start: $startId ID: ${carb.first.id} HistoryID: ${carb.second} ")
|
||||||
when {
|
when {
|
||||||
// removed and not uploaded yet = ignore
|
// without nsId = create new
|
||||||
!carb.first.isValid && carb.first.interfaceIDs.nightscoutId == null -> Any()
|
carb.first.interfaceIDs.nightscoutId == null ->
|
||||||
// removed and already uploaded = send for removal
|
nsClientPlugin.nsClientService?.dbAdd("treatments", carb.first.toJson(true, dateUtil), DataSyncSelector.PairCarbs(carb.first, carb.second), "$startId/$lastDbId")
|
||||||
!carb.first.isValid && carb.first.interfaceIDs.nightscoutId != null ->
|
// with nsId = update
|
||||||
nsClientPlugin.nsClientService?.dbRemove("treatments", carb.first.interfaceIDs.nightscoutId, DataSyncSelector.PairCarbs(carb.first, carb.second))
|
carb.first.interfaceIDs.nightscoutId != null ->
|
||||||
// existing without nsId = create new
|
nsClientPlugin.nsClientService?.dbUpdate("treatments", carb.first.interfaceIDs.nightscoutId, carb.first.toJson(false, dateUtil), DataSyncSelector.PairCarbs(carb.first, carb.second), "$startId/$lastDbId")
|
||||||
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))
|
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
@ -130,22 +164,28 @@ class DataSyncSelectorImplementation @Inject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private var lastBcrId = -1L
|
||||||
|
private var lastBcrTime = -1L
|
||||||
override fun processChangedBolusCalculatorResultsCompat(): Boolean {
|
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 ->
|
appRepository.getNextSyncElementBolusCalculatorResult(startId).blockingGet()?.let { bolusCalculatorResult ->
|
||||||
aapsLogger.info(LTag.DATABASE, "Loading BolusCalculatorResult data Start: $startId ID: ${bolusCalculatorResult.first.id} HistoryID: ${bolusCalculatorResult.second} ")
|
aapsLogger.info(LTag.DATABASE, "Loading BolusCalculatorResult data Start: $startId ID: ${bolusCalculatorResult.first.id} HistoryID: ${bolusCalculatorResult.second} ")
|
||||||
when {
|
when {
|
||||||
// removed and not uploaded yet = ignore
|
// without nsId = create new
|
||||||
!bolusCalculatorResult.first.isValid && bolusCalculatorResult.first.interfaceIDs.nightscoutId == null -> Any()
|
bolusCalculatorResult.first.interfaceIDs.nightscoutId == null ->
|
||||||
// removed and already uploaded = send for removal
|
nsClientPlugin.nsClientService?.dbAdd("treatments", bolusCalculatorResult.first.toJson(true, dateUtil), DataSyncSelector.PairBolusCalculatorResult(bolusCalculatorResult.first, bolusCalculatorResult.second), "$startId/$lastDbId")
|
||||||
!bolusCalculatorResult.first.isValid && bolusCalculatorResult.first.interfaceIDs.nightscoutId != null ->
|
// with nsId = update
|
||||||
nsClientPlugin.nsClientService?.dbRemove("treatments", bolusCalculatorResult.first.interfaceIDs.nightscoutId, DataSyncSelector.PairBolusCalculatorResult(bolusCalculatorResult.first, bolusCalculatorResult.second))
|
bolusCalculatorResult.first.interfaceIDs.nightscoutId != null ->
|
||||||
// existing without nsId = create new
|
nsClientPlugin.nsClientService?.dbUpdate("treatments", bolusCalculatorResult.first.interfaceIDs.nightscoutId, bolusCalculatorResult.first.toJson(false, dateUtil), DataSyncSelector.PairBolusCalculatorResult(bolusCalculatorResult.first, bolusCalculatorResult.second), "$startId/$lastDbId")
|
||||||
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))
|
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
@ -167,22 +207,28 @@ class DataSyncSelectorImplementation @Inject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private var lastTtId = -1L
|
||||||
|
private var lastTtTime = -1L
|
||||||
override fun processChangedTempTargetsCompat(): Boolean {
|
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 ->
|
appRepository.getNextSyncElementTemporaryTarget(startId).blockingGet()?.let { tt ->
|
||||||
aapsLogger.info(LTag.DATABASE, "Loading TemporaryTarget data Start: $startId ID: ${tt.first.id} HistoryID: ${tt.second} ")
|
aapsLogger.info(LTag.DATABASE, "Loading TemporaryTarget data Start: $startId ID: ${tt.first.id} HistoryID: ${tt.second} ")
|
||||||
when {
|
when {
|
||||||
// removed and not uploaded yet = ignore
|
// without nsId = create new
|
||||||
!tt.first.isValid && tt.first.interfaceIDs.nightscoutId == null -> Any()
|
tt.first.interfaceIDs.nightscoutId == null ->
|
||||||
// removed and already uploaded = send for removal
|
nsClientPlugin.nsClientService?.dbAdd("treatments", tt.first.toJson(true, profileFunction.getUnits(), dateUtil), DataSyncSelector.PairTemporaryTarget(tt.first, tt.second), "$startId/$lastDbId")
|
||||||
!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))
|
|
||||||
// existing with nsId = update
|
// existing with nsId = update
|
||||||
tt.first.isValid && tt.first.interfaceIDs.nightscoutId != null ->
|
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))
|
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
|
return true
|
||||||
}
|
}
|
||||||
|
@ -204,22 +250,28 @@ class DataSyncSelectorImplementation @Inject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private var lastFoodId = -1L
|
||||||
|
private var lastFoodTime = -1L
|
||||||
override fun processChangedFoodsCompat(): Boolean {
|
override fun processChangedFoodsCompat(): Boolean {
|
||||||
val startId = sp.getLong(R.string.key_ns_food_last_synced_id, 0)
|
val lastDbIdWrapped = appRepository.getLastFoodIdWrapped().blockingGet()
|
||||||
appRepository.getNextSyncElementFood(startId).blockingGet()?.let { tt ->
|
val lastDbId = if (lastDbIdWrapped is ValueWrapper.Existing) lastDbIdWrapped.value else 0L
|
||||||
aapsLogger.info(LTag.DATABASE, "Loading Food data Start: $startId ID: ${tt.first.id} HistoryID: ${tt.second} ")
|
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 {
|
when {
|
||||||
// removed and not uploaded yet = ignore
|
// without nsId = create new
|
||||||
!tt.first.isValid && tt.first.interfaceIDs.nightscoutId == null -> Any()
|
food.first.interfaceIDs.nightscoutId == null ->
|
||||||
// removed and already uploaded = send for removal
|
nsClientPlugin.nsClientService?.dbAdd("food", food.first.toJson(true), DataSyncSelector.PairFood(food.first, food.second), "$startId/$lastDbId")
|
||||||
!tt.first.isValid && tt.first.interfaceIDs.nightscoutId != null ->
|
// with nsId = update
|
||||||
nsClientPlugin.nsClientService?.dbRemove("food", tt.first.interfaceIDs.nightscoutId, DataSyncSelector.PairFood(tt.first, tt.second))
|
food.first.interfaceIDs.nightscoutId != null ->
|
||||||
// existing without nsId = create new
|
nsClientPlugin.nsClientService?.dbUpdate("food", food.first.interfaceIDs.nightscoutId, food.first.toJson(false), DataSyncSelector.PairFood(food.first, food.second), "$startId/$lastDbId")
|
||||||
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))
|
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
@ -241,25 +293,35 @@ class DataSyncSelectorImplementation @Inject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private var lastGvId = -1L
|
||||||
|
private var lastGvTime = -1L
|
||||||
override fun processChangedGlucoseValuesCompat(): Boolean {
|
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 ->
|
appRepository.getNextSyncElementGlucoseValue(startId).blockingGet()?.let { gv ->
|
||||||
aapsLogger.info(LTag.DATABASE, "Loading GlucoseValue data Start: $startId ID: ${gv.first.id} HistoryID: ${gv.second} ")
|
aapsLogger.info(LTag.DATABASE, "Loading GlucoseValue data Start: $startId ID: ${gv.first.id} HistoryID: ${gv.second} ")
|
||||||
if (activePlugin.activeBgSource.shouldUploadToNs(gv.first)) {
|
if (activePlugin.activeBgSource.shouldUploadToNs(gv.first)) {
|
||||||
when {
|
when {
|
||||||
// removed and not uploaded yet = ignore
|
// without nsId = create new
|
||||||
!gv.first.isValid && gv.first.interfaceIDs.nightscoutId == null -> Any()
|
gv.first.interfaceIDs.nightscoutId == null ->
|
||||||
// removed and already uploaded = send for removal
|
nsClientPlugin.nsClientService?.dbAdd("entries", gv.first.toJson(true, dateUtil), DataSyncSelector.PairGlucoseValue(gv.first, gv.second), "$startId/$lastDbId")
|
||||||
!gv.first.isValid && gv.first.interfaceIDs.nightscoutId != null ->
|
// with nsId = update
|
||||||
nsClientPlugin.nsClientService?.dbRemove("entries", gv.first.interfaceIDs.nightscoutId, DataSyncSelector.PairGlucoseValue(gv.first, gv.second))
|
gv.first.interfaceIDs.nightscoutId != null ->
|
||||||
// existing without nsId = create new
|
nsClientPlugin.nsClientService?.dbUpdate("entries", gv.first.interfaceIDs.nightscoutId, gv.first.toJson(false, dateUtil), DataSyncSelector.PairGlucoseValue(gv.first, gv.second), "$startId/$lastDbId")
|
||||||
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))
|
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
|
} else {
|
||||||
|
confirmLastGlucoseValueIdIfGreater(gv.second)
|
||||||
|
lastGvId = -1
|
||||||
|
processChangedGlucoseValuesCompat()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
|
@ -280,22 +342,28 @@ class DataSyncSelectorImplementation @Inject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private var lastTeId = -1L
|
||||||
|
private var lastTeTime = -1L
|
||||||
override fun processChangedTherapyEventsCompat(): Boolean {
|
override fun processChangedTherapyEventsCompat(): Boolean {
|
||||||
val startId = sp.getLong(R.string.key_ns_therapy_event_last_synced_id, 0)
|
val lastDbIdWrapped = appRepository.getLastTherapyEventIdWrapped().blockingGet()
|
||||||
appRepository.getNextSyncElementTherapyEvent(startId).blockingGet()?.let { tt ->
|
val lastDbId = if (lastDbIdWrapped is ValueWrapper.Existing) lastDbIdWrapped.value else 0L
|
||||||
aapsLogger.info(LTag.DATABASE, "Loading TherapyEvents data Start: $startId ID: ${tt.first.id} HistoryID: ${tt.second} ")
|
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 {
|
when {
|
||||||
// removed and not uploaded yet = ignore
|
// without nsId = create new
|
||||||
!tt.first.isValid && tt.first.interfaceIDs.nightscoutId == null -> Any()
|
te.first.interfaceIDs.nightscoutId == null ->
|
||||||
// removed and already uploaded = send for removal
|
nsClientPlugin.nsClientService?.dbAdd("treatments", te.first.toJson(true), DataSyncSelector.PairTherapyEvent(te.first, te.second), "$startId/$lastDbId")
|
||||||
!tt.first.isValid && tt.first.interfaceIDs.nightscoutId != null ->
|
// nsId = update
|
||||||
nsClientPlugin.nsClientService?.dbRemove("treatments", tt.first.interfaceIDs.nightscoutId, DataSyncSelector.PairTherapyEvent(tt.first, tt.second))
|
te.first.interfaceIDs.nightscoutId != null ->
|
||||||
// existing without nsId = create new
|
nsClientPlugin.nsClientService?.dbUpdate("treatments", te.first.interfaceIDs.nightscoutId, te.first.toJson(false), DataSyncSelector.PairTherapyEvent(te.first, te.second), "$startId/$lastDbId")
|
||||||
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))
|
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
@ -316,14 +384,25 @@ class DataSyncSelectorImplementation @Inject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private var lastDsId = -1L
|
||||||
|
private var lastDsTime = -1L
|
||||||
override fun processChangedDeviceStatusesCompat(): Boolean {
|
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 ->
|
appRepository.getNextSyncElementDeviceStatus(startId).blockingGet()?.let { deviceStatus ->
|
||||||
aapsLogger.info(LTag.DATABASE, "Loading DeviceStatus data Start: $startId ID: ${deviceStatus.id}")
|
aapsLogger.info(LTag.DATABASE, "Loading DeviceStatus data Start: $startId ID: ${deviceStatus.id}")
|
||||||
when {
|
when {
|
||||||
// without nsId = create new
|
// without nsId = create new
|
||||||
deviceStatus.interfaceIDs.nightscoutId == null ->
|
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
|
// with nsId = ignore
|
||||||
deviceStatus.interfaceIDs.nightscoutId != null -> Any()
|
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 {
|
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 ->
|
appRepository.getNextSyncElementTemporaryBasal(startId).blockingGet()?.let { tb ->
|
||||||
aapsLogger.info(LTag.DATABASE, "Loading TemporaryBasal data Start: $startId ID: ${tb.first.id} HistoryID: ${tb.second} ")
|
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 {
|
when {
|
||||||
// removed and not uploaded yet = ignore
|
// without nsId = create new
|
||||||
!tb.first.isValid && tb.first.interfaceIDs.nightscoutId == null -> Any()
|
tb.first.interfaceIDs.nightscoutId == null ->
|
||||||
// removed and already uploaded = send for removal
|
nsClientPlugin.nsClientService?.dbAdd("treatments", tb.first.toJson(true, profile, dateUtil, useAbsolute), DataSyncSelector.PairTemporaryBasal(tb.first, tb.second), "$startId/$lastDbId")
|
||||||
!tb.first.isValid && tb.first.interfaceIDs.nightscoutId != null ->
|
// with nsId = update
|
||||||
nsClientPlugin.nsClientService?.dbRemove("treatments", tb.first.interfaceIDs.nightscoutId, DataSyncSelector.PairTemporaryBasal(tb.first, tb.second))
|
tb.first.interfaceIDs.nightscoutId != null ->
|
||||||
// existing without nsId = create new
|
nsClientPlugin.nsClientService?.dbUpdate("treatments", tb.first.interfaceIDs.nightscoutId, tb.first.toJson(false, profile, dateUtil, useAbsolute), DataSyncSelector.PairTemporaryBasal(tb.first, tb.second), "$startId/$lastDbId")
|
||||||
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))
|
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
|
} else {
|
||||||
|
confirmLastTemporaryBasalIdIfGreater(tb.second)
|
||||||
|
lastTbrId = -1
|
||||||
|
processChangedTemporaryBasalsCompat()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
|
@ -386,25 +477,37 @@ class DataSyncSelectorImplementation @Inject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private var lastEbId = -1L
|
||||||
|
private var lastEbTime = -1L
|
||||||
override fun processChangedExtendedBolusesCompat(): Boolean {
|
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 ->
|
appRepository.getNextSyncElementExtendedBolus(startId).blockingGet()?.let { eb ->
|
||||||
aapsLogger.info(LTag.DATABASE, "Loading ExtendedBolus data Start: $startId ID: ${eb.first.id} HistoryID: ${eb.second} ")
|
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 {
|
when {
|
||||||
// removed and not uploaded yet = ignore
|
// without nsId = create new
|
||||||
!eb.first.isValid && eb.first.interfaceIDs.nightscoutId == null -> Any()
|
eb.first.interfaceIDs.nightscoutId == null ->
|
||||||
// removed and already uploaded = send for removal
|
nsClientPlugin.nsClientService?.dbAdd("treatments", eb.first.toJson(true, profile, dateUtil, useAbsolute), DataSyncSelector.PairExtendedBolus(eb.first, eb.second), "$startId/$lastDbId")
|
||||||
!eb.first.isValid && eb.first.interfaceIDs.nightscoutId != null ->
|
// with nsId = update
|
||||||
nsClientPlugin.nsClientService?.dbRemove("treatments", eb.first.interfaceIDs.nightscoutId, DataSyncSelector.PairExtendedBolus(eb.first, eb.second))
|
eb.first.interfaceIDs.nightscoutId != null ->
|
||||||
// existing without nsId = create new
|
nsClientPlugin.nsClientService?.dbUpdate("treatments", eb.first.interfaceIDs.nightscoutId, eb.first.toJson(false, profile, dateUtil, useAbsolute), DataSyncSelector.PairExtendedBolus(eb.first, eb.second), "$startId/$lastDbId")
|
||||||
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))
|
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
|
} else {
|
||||||
|
confirmLastExtendedBolusIdIfGreater(eb.second)
|
||||||
|
lastEbId = -1
|
||||||
|
processChangedExtendedBolusesCompat()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
|
@ -424,25 +527,88 @@ class DataSyncSelectorImplementation @Inject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private var lastPsId = -1L
|
||||||
|
private var lastPsTime = -1L
|
||||||
override fun processChangedProfileSwitchesCompat(): Boolean {
|
override fun processChangedProfileSwitchesCompat(): Boolean {
|
||||||
val startId = sp.getLong(R.string.key_ns_profile_switch_last_synced_id, 0)
|
val lastDbIdWrapped = appRepository.getLastProfileSwitchIdWrapped().blockingGet()
|
||||||
appRepository.getNextSyncElementProfileSwitch(startId).blockingGet()?.let { eb ->
|
val lastDbId = if (lastDbIdWrapped is ValueWrapper.Existing) lastDbIdWrapped.value else 0L
|
||||||
aapsLogger.info(LTag.DATABASE, "Loading ProfileSwitch data Start: $startId ID: ${eb.first.id} HistoryID: ${eb.second} ")
|
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 {
|
when {
|
||||||
// removed and not uploaded yet = ignore
|
// without nsId = create new
|
||||||
!eb.first.isValid && eb.first.interfaceIDs.nightscoutId == null -> Any()
|
ps.first.interfaceIDs.nightscoutId == null ->
|
||||||
// removed and already uploaded = send for removal
|
nsClientPlugin.nsClientService?.dbAdd("treatments", ps.first.toJson(true, dateUtil), DataSyncSelector.PairProfileSwitch(ps.first, ps.second), "$startId/$lastDbId")
|
||||||
!eb.first.isValid && eb.first.interfaceIDs.nightscoutId != null ->
|
// with nsId = update
|
||||||
nsClientPlugin.nsClientService?.dbRemove("treatments", eb.first.interfaceIDs.nightscoutId, DataSyncSelector.PairProfileSwitch(eb.first, eb.second))
|
ps.first.interfaceIDs.nightscoutId != null ->
|
||||||
// existing without nsId = create new
|
nsClientPlugin.nsClientService?.dbUpdate("treatments", ps.first.interfaceIDs.nightscoutId, ps.first.toJson(false, dateUtil), DataSyncSelector.PairProfileSwitch(ps.first, ps.second), "$startId/$lastDbId")
|
||||||
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))
|
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return false
|
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()), "")
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -206,7 +206,7 @@ class NSClientAddAckWorker(
|
||||||
.blockingGet()
|
.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
|
// Send new if waiting
|
||||||
dataSyncSelector.processChangedTemporaryBasalsCompat()
|
dataSyncSelector.processChangedExtendedBolusesCompat()
|
||||||
}
|
}
|
||||||
|
|
||||||
is PairProfileSwitch -> {
|
is PairProfileSwitch -> {
|
||||||
|
@ -225,7 +225,7 @@ class NSClientAddAckWorker(
|
||||||
.blockingGet()
|
.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
|
// Send new if waiting
|
||||||
dataSyncSelector.processChangedTemporaryBasalsCompat()
|
dataSyncSelector.processChangedProfileSwitchesCompat()
|
||||||
}
|
}
|
||||||
|
|
||||||
is DeviceStatus -> {
|
is DeviceStatus -> {
|
||||||
|
@ -246,6 +246,31 @@ class NSClientAddAckWorker(
|
||||||
// Send new if waiting
|
// Send new if waiting
|
||||||
dataSyncSelector.processChangedDeviceStatusesCompat()
|
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
|
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.entities.ValueWithUnit
|
||||||
import info.nightscout.androidaps.database.transactions.*
|
import info.nightscout.androidaps.database.transactions.*
|
||||||
import info.nightscout.androidaps.extensions.*
|
import info.nightscout.androidaps.extensions.*
|
||||||
|
import info.nightscout.androidaps.interfaces.ActivePlugin
|
||||||
import info.nightscout.androidaps.interfaces.Config
|
import info.nightscout.androidaps.interfaces.Config
|
||||||
import info.nightscout.androidaps.logging.AAPSLogger
|
import info.nightscout.androidaps.logging.AAPSLogger
|
||||||
import info.nightscout.androidaps.logging.LTag
|
import info.nightscout.androidaps.logging.LTag
|
||||||
|
@ -43,13 +44,11 @@ class NSClientAddUpdateWorker(
|
||||||
@Inject lateinit var dateUtil: DateUtil
|
@Inject lateinit var dateUtil: DateUtil
|
||||||
@Inject lateinit var config: Config
|
@Inject lateinit var config: Config
|
||||||
@Inject lateinit var repository: AppRepository
|
@Inject lateinit var repository: AppRepository
|
||||||
|
@Inject lateinit var activePlugin: ActivePlugin
|
||||||
@Inject lateinit var rxBus: RxBusWrapper
|
@Inject lateinit var rxBus: RxBusWrapper
|
||||||
@Inject lateinit var uel: UserEntryLogger
|
@Inject lateinit var uel: UserEntryLogger
|
||||||
|
|
||||||
override fun doWork(): Result {
|
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))
|
val treatments = dataWorker.pickupJSONArray(inputData.getLong(DataWorker.STORE_KEY, -1))
|
||||||
?: return Result.failure(workDataOf("Error" to "missing input data"))
|
?: return Result.failure(workDataOf("Error" to "missing input data"))
|
||||||
|
|
||||||
|
@ -73,6 +72,7 @@ class NSClientAddUpdateWorker(
|
||||||
if (mills > latestDateInReceivedData) latestDateInReceivedData = mills
|
if (mills > latestDateInReceivedData) latestDateInReceivedData = mills
|
||||||
|
|
||||||
if (insulin > 0) {
|
if (insulin > 0) {
|
||||||
|
if (sp.getBoolean(R.string.key_ns_receive_insulin, false) && buildHelper.isEngineeringMode() || config.NSCLIENT) {
|
||||||
bolusFromJson(json)?.let { bolus ->
|
bolusFromJson(json)?.let { bolus ->
|
||||||
repository.runTransactionForResult(SyncNsBolusTransaction(bolus, invalidateByNsOnly = false))
|
repository.runTransactionForResult(SyncNsBolusTransaction(bolus, invalidateByNsOnly = false))
|
||||||
.doOnError {
|
.doOnError {
|
||||||
|
@ -101,7 +101,9 @@ class NSClientAddUpdateWorker(
|
||||||
}
|
}
|
||||||
} ?: aapsLogger.error("Error parsing bolus json $json")
|
} ?: aapsLogger.error("Error parsing bolus json $json")
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (carbs > 0) {
|
if (carbs > 0) {
|
||||||
|
if (sp.getBoolean(R.string.key_ns_receive_carbs, false) && buildHelper.isEngineeringMode() || config.NSCLIENT) {
|
||||||
carbsFromJson(json)?.let { carb ->
|
carbsFromJson(json)?.let { carb ->
|
||||||
repository.runTransactionForResult(SyncNsCarbsTransaction(carb, invalidateByNsOnly = false))
|
repository.runTransactionForResult(SyncNsCarbsTransaction(carb, invalidateByNsOnly = false))
|
||||||
.doOnError {
|
.doOnError {
|
||||||
|
@ -130,6 +132,7 @@ class NSClientAddUpdateWorker(
|
||||||
}
|
}
|
||||||
} ?: aapsLogger.error("Error parsing bolus json $json")
|
} ?: aapsLogger.error("Error parsing bolus json $json")
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// Convert back emulated TBR -> EB
|
// Convert back emulated TBR -> EB
|
||||||
if (eventType == TherapyEvent.Type.TEMPORARY_BASAL.text && json.has("extendedEmulated")) {
|
if (eventType == TherapyEvent.Type.TEMPORARY_BASAL.text && json.has("extendedEmulated")) {
|
||||||
val ebJson = json.getJSONObject("extendedEmulated")
|
val ebJson = json.getJSONObject("extendedEmulated")
|
||||||
|
@ -140,6 +143,7 @@ class NSClientAddUpdateWorker(
|
||||||
when {
|
when {
|
||||||
insulin > 0 || carbs > 0 -> Any()
|
insulin > 0 || carbs > 0 -> Any()
|
||||||
eventType == TherapyEvent.Type.TEMPORARY_TARGET.text ->
|
eventType == TherapyEvent.Type.TEMPORARY_TARGET.text ->
|
||||||
|
if (sp.getBoolean(R.string.key_ns_receive_temp_target, false) && buildHelper.isEngineeringMode() || config.NSCLIENT) {
|
||||||
temporaryTargetFromJson(json)?.let { temporaryTarget ->
|
temporaryTargetFromJson(json)?.let { temporaryTarget ->
|
||||||
repository.runTransactionForResult(SyncNsTemporaryTargetTransaction(temporaryTarget, invalidateByNsOnly = false))
|
repository.runTransactionForResult(SyncNsTemporaryTargetTransaction(temporaryTarget, invalidateByNsOnly = false))
|
||||||
.doOnError {
|
.doOnError {
|
||||||
|
@ -180,6 +184,7 @@ class NSClientAddUpdateWorker(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} ?: aapsLogger.error("Error parsing TT json $json")
|
} ?: aapsLogger.error("Error parsing TT json $json")
|
||||||
|
}
|
||||||
eventType == TherapyEvent.Type.CANNULA_CHANGE.text ||
|
eventType == TherapyEvent.Type.CANNULA_CHANGE.text ||
|
||||||
eventType == TherapyEvent.Type.INSULIN_CHANGE.text ||
|
eventType == TherapyEvent.Type.INSULIN_CHANGE.text ||
|
||||||
eventType == TherapyEvent.Type.SENSOR_CHANGE.text ||
|
eventType == TherapyEvent.Type.SENSOR_CHANGE.text ||
|
||||||
|
@ -188,8 +193,8 @@ class NSClientAddUpdateWorker(
|
||||||
eventType == TherapyEvent.Type.ANNOUNCEMENT.text ||
|
eventType == TherapyEvent.Type.ANNOUNCEMENT.text ||
|
||||||
eventType == TherapyEvent.Type.QUESTION.text ||
|
eventType == TherapyEvent.Type.QUESTION.text ||
|
||||||
eventType == TherapyEvent.Type.EXERCISE.text ||
|
eventType == TherapyEvent.Type.EXERCISE.text ||
|
||||||
eventType == TherapyEvent.Type.APS_OFFLINE.text ||
|
|
||||||
eventType == TherapyEvent.Type.PUMP_BATTERY_CHANGE.text ->
|
eventType == TherapyEvent.Type.PUMP_BATTERY_CHANGE.text ->
|
||||||
|
if (sp.getBoolean(R.string.key_ns_receive_therapy_events, false) || config.NSCLIENT) {
|
||||||
therapyEventFromJson(json)?.let { therapyEvent ->
|
therapyEventFromJson(json)?.let { therapyEvent ->
|
||||||
repository.runTransactionForResult(SyncNsTherapyEventTransaction(therapyEvent, invalidateByNsOnly = false))
|
repository.runTransactionForResult(SyncNsTherapyEventTransaction(therapyEvent, invalidateByNsOnly = false))
|
||||||
.doOnError {
|
.doOnError {
|
||||||
|
@ -224,7 +229,9 @@ class NSClientAddUpdateWorker(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} ?: aapsLogger.error("Error parsing TherapyEvent json $json")
|
} ?: aapsLogger.error("Error parsing TherapyEvent json $json")
|
||||||
|
}
|
||||||
eventType == TherapyEvent.Type.COMBO_BOLUS.text ->
|
eventType == TherapyEvent.Type.COMBO_BOLUS.text ->
|
||||||
|
if (config.NSCLIENT) {
|
||||||
extendedBolusFromJson(json)?.let { extendedBolus ->
|
extendedBolusFromJson(json)?.let { extendedBolus ->
|
||||||
repository.runTransactionForResult(SyncNsExtendedBolusTransaction(extendedBolus, invalidateByNsOnly = false))
|
repository.runTransactionForResult(SyncNsExtendedBolusTransaction(extendedBolus, invalidateByNsOnly = false))
|
||||||
.doOnError {
|
.doOnError {
|
||||||
|
@ -265,7 +272,9 @@ class NSClientAddUpdateWorker(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} ?: aapsLogger.error("Error parsing ExtendedBolus json $json")
|
} ?: aapsLogger.error("Error parsing ExtendedBolus json $json")
|
||||||
|
}
|
||||||
eventType == TherapyEvent.Type.TEMPORARY_BASAL.text ->
|
eventType == TherapyEvent.Type.TEMPORARY_BASAL.text ->
|
||||||
|
if (config.NSCLIENT) {
|
||||||
temporaryBasalFromJson(json)?.let { temporaryBasal ->
|
temporaryBasalFromJson(json)?.let { temporaryBasal ->
|
||||||
repository.runTransactionForResult(SyncNsTemporaryBasalTransaction(temporaryBasal, invalidateByNsOnly = false))
|
repository.runTransactionForResult(SyncNsTemporaryBasalTransaction(temporaryBasal, invalidateByNsOnly = false))
|
||||||
.doOnError {
|
.doOnError {
|
||||||
|
@ -277,7 +286,7 @@ class NSClientAddUpdateWorker(
|
||||||
result.inserted.forEach {
|
result.inserted.forEach {
|
||||||
uel.log(Action.TEMP_BASAL, Sources.NSClient,
|
uel.log(Action.TEMP_BASAL, Sources.NSClient,
|
||||||
ValueWithUnit.Timestamp(it.timestamp),
|
ValueWithUnit.Timestamp(it.timestamp),
|
||||||
ValueWithUnit.UnitPerHour(it.rate),
|
if (it.isAbsolute) ValueWithUnit.UnitPerHour(it.rate) else ValueWithUnit.Percent(it.rate.toInt()),
|
||||||
ValueWithUnit.Minute(TimeUnit.MILLISECONDS.toMinutes(it.duration).toInt())
|
ValueWithUnit.Minute(TimeUnit.MILLISECONDS.toMinutes(it.duration).toInt())
|
||||||
)
|
)
|
||||||
aapsLogger.debug(LTag.DATABASE, "Inserted TemporaryBasal $it")
|
aapsLogger.debug(LTag.DATABASE, "Inserted TemporaryBasal $it")
|
||||||
|
@ -285,7 +294,7 @@ class NSClientAddUpdateWorker(
|
||||||
result.invalidated.forEach {
|
result.invalidated.forEach {
|
||||||
uel.log(Action.TEMP_BASAL_REMOVED, Sources.NSClient,
|
uel.log(Action.TEMP_BASAL_REMOVED, Sources.NSClient,
|
||||||
ValueWithUnit.Timestamp(it.timestamp),
|
ValueWithUnit.Timestamp(it.timestamp),
|
||||||
ValueWithUnit.UnitPerHour(it.rate),
|
if (it.isAbsolute) ValueWithUnit.UnitPerHour(it.rate) else ValueWithUnit.Percent(it.rate.toInt()),
|
||||||
ValueWithUnit.Minute(TimeUnit.MILLISECONDS.toMinutes(it.duration).toInt())
|
ValueWithUnit.Minute(TimeUnit.MILLISECONDS.toMinutes(it.duration).toInt())
|
||||||
)
|
)
|
||||||
aapsLogger.debug(LTag.DATABASE, "Invalidated TemporaryBasal $it")
|
aapsLogger.debug(LTag.DATABASE, "Invalidated TemporaryBasal $it")
|
||||||
|
@ -293,7 +302,7 @@ class NSClientAddUpdateWorker(
|
||||||
result.ended.forEach {
|
result.ended.forEach {
|
||||||
uel.log(Action.CANCEL_TEMP_BASAL, Sources.NSClient,
|
uel.log(Action.CANCEL_TEMP_BASAL, Sources.NSClient,
|
||||||
ValueWithUnit.Timestamp(it.timestamp),
|
ValueWithUnit.Timestamp(it.timestamp),
|
||||||
ValueWithUnit.UnitPerHour(it.rate),
|
if (it.isAbsolute) ValueWithUnit.UnitPerHour(it.rate) else ValueWithUnit.Percent(it.rate.toInt()),
|
||||||
ValueWithUnit.Minute(TimeUnit.MILLISECONDS.toMinutes(it.duration).toInt())
|
ValueWithUnit.Minute(TimeUnit.MILLISECONDS.toMinutes(it.duration).toInt())
|
||||||
)
|
)
|
||||||
aapsLogger.debug(LTag.DATABASE, "Ended TemporaryBasal $it")
|
aapsLogger.debug(LTag.DATABASE, "Ended TemporaryBasal $it")
|
||||||
|
@ -303,8 +312,10 @@ class NSClientAddUpdateWorker(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} ?: aapsLogger.error("Error parsing TemporaryBasal json $json")
|
} ?: aapsLogger.error("Error parsing TemporaryBasal json $json")
|
||||||
|
}
|
||||||
eventType == TherapyEvent.Type.PROFILE_SWITCH.text ->
|
eventType == TherapyEvent.Type.PROFILE_SWITCH.text ->
|
||||||
profileSwitchFromJson(json, dateUtil)?.let { profileSwitch ->
|
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))
|
repository.runTransactionForResult(SyncNsProfileSwitchTransaction(profileSwitch, invalidateByNsOnly = false))
|
||||||
.doOnError {
|
.doOnError {
|
||||||
aapsLogger.error(LTag.DATABASE, "Error while saving ProfileSwitch", it)
|
aapsLogger.error(LTag.DATABASE, "Error while saving ProfileSwitch", it)
|
||||||
|
@ -326,8 +337,47 @@ class NSClientAddUpdateWorker(
|
||||||
aapsLogger.debug(LTag.DATABASE, "Updated nsId ProfileSwitch $it")
|
aapsLogger.debug(LTag.DATABASE, "Updated nsId ProfileSwitch $it")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} ?: aapsLogger.error("Error parsing TemporaryBasal json $json")
|
} ?: 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()))
|
||||||
|
}
|
||||||
|
.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 (sp.getBoolean(R.string.key_ns_receive_therapy_events, false) || config.NSCLIENT)
|
||||||
if (eventType == TherapyEvent.Type.ANNOUNCEMENT.text) {
|
if (eventType == TherapyEvent.Type.ANNOUNCEMENT.text) {
|
||||||
val date = safeGetLong(json, "mills")
|
val date = safeGetLong(json, "mills")
|
||||||
val now = System.currentTimeMillis()
|
val now = System.currentTimeMillis()
|
||||||
|
|
|
@ -12,14 +12,11 @@ import info.nightscout.androidaps.database.entities.UserEntry.Action
|
||||||
import info.nightscout.androidaps.database.entities.UserEntry.Sources
|
import info.nightscout.androidaps.database.entities.UserEntry.Sources
|
||||||
import info.nightscout.androidaps.databinding.NsClientFragmentBinding
|
import info.nightscout.androidaps.databinding.NsClientFragmentBinding
|
||||||
import info.nightscout.androidaps.interfaces.DataSyncSelector
|
import info.nightscout.androidaps.interfaces.DataSyncSelector
|
||||||
import info.nightscout.androidaps.interfaces.UploadQueueAdminInterface
|
|
||||||
import info.nightscout.androidaps.logging.UserEntryLogger
|
import info.nightscout.androidaps.logging.UserEntryLogger
|
||||||
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
||||||
import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientNewLog
|
|
||||||
import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientRestart
|
import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientRestart
|
||||||
import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientUpdateGUI
|
import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientUpdateGUI
|
||||||
import info.nightscout.androidaps.utils.FabricPrivacy
|
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.alertDialogs.OKDialog
|
||||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||||
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
||||||
|
@ -33,7 +30,6 @@ class NSClientFragment : DaggerFragment() {
|
||||||
@Inject lateinit var sp: SP
|
@Inject lateinit var sp: SP
|
||||||
@Inject lateinit var resourceHelper: ResourceHelper
|
@Inject lateinit var resourceHelper: ResourceHelper
|
||||||
@Inject lateinit var rxBus: RxBusWrapper
|
@Inject lateinit var rxBus: RxBusWrapper
|
||||||
@Inject lateinit var uploadQueue: UploadQueueAdminInterface
|
|
||||||
@Inject lateinit var fabricPrivacy: FabricPrivacy
|
@Inject lateinit var fabricPrivacy: FabricPrivacy
|
||||||
@Inject lateinit var aapsSchedulers: AapsSchedulers
|
@Inject lateinit var aapsSchedulers: AapsSchedulers
|
||||||
@Inject lateinit var dataSyncSelector: DataSyncSelector
|
@Inject lateinit var dataSyncSelector: DataSyncSelector
|
||||||
|
@ -72,18 +68,6 @@ class NSClientFragment : DaggerFragment() {
|
||||||
binding.restart.paintFlags = binding.restart.paintFlags or Paint.UNDERLINE_TEXT_FLAG
|
binding.restart.paintFlags = binding.restart.paintFlags or Paint.UNDERLINE_TEXT_FLAG
|
||||||
binding.deliverNow.setOnClickListener { nsClientPlugin.resend("GUI") }
|
binding.deliverNow.setOnClickListener { nsClientPlugin.resend("GUI") }
|
||||||
binding.deliverNow.paintFlags = binding.deliverNow.paintFlags or Paint.UNDERLINE_TEXT_FLAG
|
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 {
|
binding.fullSync.setOnClickListener {
|
||||||
context?.let { context ->
|
context?.let { context ->
|
||||||
OKDialog.showConfirmation(context, resourceHelper.gs(R.string.nsclientinternal), resourceHelper.gs(R.string.full_sync), Runnable {
|
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
|
binding.log.text = nsClientPlugin.textLog
|
||||||
if (nsClientPlugin.autoscroll) binding.logScrollview.fullScroll(ScrollView.FOCUS_DOWN)
|
if (nsClientPlugin.autoscroll) binding.logScrollview.fullScroll(ScrollView.FOCUS_DOWN)
|
||||||
binding.url.text = nsClientPlugin.url()
|
binding.url.text = nsClientPlugin.url()
|
||||||
binding.queue.text = fromHtml(resourceHelper.gs(R.string.queue) + " <b>" + uploadQueue.size() + "</b>")
|
|
||||||
binding.status.text = nsClientPlugin.status
|
binding.status.text = nsClientPlugin.status
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -8,13 +8,13 @@ import dagger.android.HasAndroidInjector
|
||||||
import info.nightscout.androidaps.R
|
import info.nightscout.androidaps.R
|
||||||
import info.nightscout.androidaps.database.AppRepository
|
import info.nightscout.androidaps.database.AppRepository
|
||||||
import info.nightscout.androidaps.database.transactions.SyncNsTherapyEventTransaction
|
import info.nightscout.androidaps.database.transactions.SyncNsTherapyEventTransaction
|
||||||
|
import info.nightscout.androidaps.extensions.therapyEventFromNsMbg
|
||||||
import info.nightscout.androidaps.interfaces.Config
|
import info.nightscout.androidaps.interfaces.Config
|
||||||
import info.nightscout.androidaps.logging.AAPSLogger
|
import info.nightscout.androidaps.logging.AAPSLogger
|
||||||
import info.nightscout.androidaps.logging.LTag
|
import info.nightscout.androidaps.logging.LTag
|
||||||
import info.nightscout.androidaps.plugins.general.nsclient.data.NSMbg
|
import info.nightscout.androidaps.plugins.general.nsclient.data.NSMbg
|
||||||
import info.nightscout.androidaps.receivers.DataWorker
|
import info.nightscout.androidaps.receivers.DataWorker
|
||||||
import info.nightscout.androidaps.utils.buildHelper.BuildHelper
|
import info.nightscout.androidaps.utils.buildHelper.BuildHelper
|
||||||
import info.nightscout.androidaps.extensions.therapyEventFromNsMbg
|
|
||||||
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
@ -33,8 +33,8 @@ class NSClientMbgWorker(
|
||||||
override fun doWork(): Result {
|
override fun doWork(): Result {
|
||||||
var ret = Result.success()
|
var ret = Result.success()
|
||||||
|
|
||||||
val acceptNSData = !sp.getBoolean(R.string.key_ns_upload_only, true) && buildHelper.isEngineeringMode() || config.NSCLIENT
|
val acceptNSData = sp.getBoolean(R.string.key_ns_receive_therapy_events, false) || config.NSCLIENT
|
||||||
if (!acceptNSData) return ret
|
if (!acceptNSData) return Result.success(workDataOf("Result" to "Sync not enabled"))
|
||||||
|
|
||||||
val mbgArray = dataWorker.pickupJSONArray(inputData.getLong(DataWorker.STORE_KEY, -1))
|
val mbgArray = dataWorker.pickupJSONArray(inputData.getLong(DataWorker.STORE_KEY, -1))
|
||||||
?: return Result.failure(workDataOf("Error" to "missing input data"))
|
?: return Result.failure(workDataOf("Error" to "missing input data"))
|
||||||
|
|
|
@ -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
|
@Inject lateinit var uel: UserEntryLogger
|
||||||
|
|
||||||
override fun doWork(): Result {
|
override fun doWork(): Result {
|
||||||
val acceptNSData = !sp.getBoolean(R.string.key_ns_upload_only, true) && buildHelper.isEngineeringMode() || config.NSCLIENT
|
// Do not accept removed data over WS. Only invalidated trough NSClient
|
||||||
if (!acceptNSData) return Result.success()
|
@Suppress("ConstantConditionIf")
|
||||||
|
if (true) return Result.success()
|
||||||
|
|
||||||
var ret = Result.success()
|
var ret = Result.success()
|
||||||
|
|
||||||
|
|
|
@ -39,7 +39,7 @@ class NSClientUpdateRemoveAckWorker(
|
||||||
is PairTemporaryTarget -> {
|
is PairTemporaryTarget -> {
|
||||||
val pair = ack.originalObject
|
val pair = ack.originalObject
|
||||||
dataSyncSelector.confirmLastTempTargetsIdIfGreater(pair.updateRecordId)
|
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
|
// Send new if waiting
|
||||||
dataSyncSelector.processChangedTempTargetsCompat()
|
dataSyncSelector.processChangedTempTargetsCompat()
|
||||||
ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
|
ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
|
||||||
|
@ -48,7 +48,7 @@ class NSClientUpdateRemoveAckWorker(
|
||||||
is PairGlucoseValue -> {
|
is PairGlucoseValue -> {
|
||||||
val pair = ack.originalObject
|
val pair = ack.originalObject
|
||||||
dataSyncSelector.confirmLastGlucoseValueIdIfGreater(pair.updateRecordId)
|
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
|
// Send new if waiting
|
||||||
dataSyncSelector.processChangedGlucoseValuesCompat()
|
dataSyncSelector.processChangedGlucoseValuesCompat()
|
||||||
ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
|
ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
|
||||||
|
@ -57,7 +57,7 @@ class NSClientUpdateRemoveAckWorker(
|
||||||
is PairFood -> {
|
is PairFood -> {
|
||||||
val pair = ack.originalObject
|
val pair = ack.originalObject
|
||||||
dataSyncSelector.confirmLastFoodIdIfGreater(pair.updateRecordId)
|
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
|
// Send new if waiting
|
||||||
dataSyncSelector.processChangedFoodsCompat()
|
dataSyncSelector.processChangedFoodsCompat()
|
||||||
ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
|
ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
|
||||||
|
@ -66,7 +66,7 @@ class NSClientUpdateRemoveAckWorker(
|
||||||
is PairTherapyEvent -> {
|
is PairTherapyEvent -> {
|
||||||
val pair = ack.originalObject
|
val pair = ack.originalObject
|
||||||
dataSyncSelector.confirmLastTherapyEventIdIfGreater(pair.updateRecordId)
|
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
|
// Send new if waiting
|
||||||
dataSyncSelector.processChangedTherapyEventsCompat()
|
dataSyncSelector.processChangedTherapyEventsCompat()
|
||||||
ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
|
ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
|
||||||
|
@ -75,7 +75,7 @@ class NSClientUpdateRemoveAckWorker(
|
||||||
is PairBolus -> {
|
is PairBolus -> {
|
||||||
val pair = ack.originalObject
|
val pair = ack.originalObject
|
||||||
dataSyncSelector.confirmLastBolusIdIfGreater(pair.updateRecordId)
|
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
|
// Send new if waiting
|
||||||
dataSyncSelector.processChangedBolusesCompat()
|
dataSyncSelector.processChangedBolusesCompat()
|
||||||
ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
|
ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
|
||||||
|
@ -84,7 +84,7 @@ class NSClientUpdateRemoveAckWorker(
|
||||||
is PairCarbs -> {
|
is PairCarbs -> {
|
||||||
val pair = ack.originalObject
|
val pair = ack.originalObject
|
||||||
dataSyncSelector.confirmLastCarbsIdIfGreater(pair.updateRecordId)
|
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
|
// Send new if waiting
|
||||||
dataSyncSelector.processChangedCarbsCompat()
|
dataSyncSelector.processChangedCarbsCompat()
|
||||||
ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
|
ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
|
||||||
|
@ -93,7 +93,7 @@ class NSClientUpdateRemoveAckWorker(
|
||||||
is PairBolusCalculatorResult -> {
|
is PairBolusCalculatorResult -> {
|
||||||
val pair = ack.originalObject
|
val pair = ack.originalObject
|
||||||
dataSyncSelector.confirmLastBolusCalculatorResultsIdIfGreater(pair.updateRecordId)
|
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
|
// Send new if waiting
|
||||||
dataSyncSelector.processChangedBolusCalculatorResultsCompat()
|
dataSyncSelector.processChangedBolusCalculatorResultsCompat()
|
||||||
ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
|
ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
|
||||||
|
@ -102,7 +102,7 @@ class NSClientUpdateRemoveAckWorker(
|
||||||
is PairTemporaryBasal -> {
|
is PairTemporaryBasal -> {
|
||||||
val pair = ack.originalObject
|
val pair = ack.originalObject
|
||||||
dataSyncSelector.confirmLastTemporaryBasalIdIfGreater(pair.updateRecordId)
|
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
|
// Send new if waiting
|
||||||
dataSyncSelector.processChangedTemporaryBasalsCompat()
|
dataSyncSelector.processChangedTemporaryBasalsCompat()
|
||||||
ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
|
ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
|
||||||
|
@ -111,7 +111,7 @@ class NSClientUpdateRemoveAckWorker(
|
||||||
is PairExtendedBolus -> {
|
is PairExtendedBolus -> {
|
||||||
val pair = ack.originalObject
|
val pair = ack.originalObject
|
||||||
dataSyncSelector.confirmLastExtendedBolusIdIfGreater(pair.updateRecordId)
|
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
|
// Send new if waiting
|
||||||
dataSyncSelector.processChangedExtendedBolusesCompat()
|
dataSyncSelector.processChangedExtendedBolusesCompat()
|
||||||
ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
|
ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
|
||||||
|
@ -120,11 +120,20 @@ class NSClientUpdateRemoveAckWorker(
|
||||||
is PairProfileSwitch -> {
|
is PairProfileSwitch -> {
|
||||||
val pair = ack.originalObject
|
val pair = ack.originalObject
|
||||||
dataSyncSelector.confirmLastProfileSwitchIdIfGreater(pair.updateRecordId)
|
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
|
// Send new if waiting
|
||||||
dataSyncSelector.processChangedProfileSwitchesCompat()
|
dataSyncSelector.processChangedProfileSwitchesCompat()
|
||||||
ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
|
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
|
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.*
|
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 = """
|
private val allowedKeys = """
|
||||||
absorption
|
absorption
|
||||||
absorption_maxtime
|
absorption_maxtime
|
||||||
|
@ -206,4 +208,4 @@ private val allowedKeys = """
|
||||||
xdripstatus
|
xdripstatus
|
||||||
xdripstatus_detailediob
|
xdripstatus_detailediob
|
||||||
xdripstatus_showbgi
|
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
|
@Inject
|
||||||
lateinit var resourceHelper: ResourceHelper
|
lateinit var resourceHelper: ResourceHelper
|
||||||
|
|
||||||
|
@kotlin.ExperimentalStdlibApi
|
||||||
override fun createWork(): Single<Result> = Single.defer {
|
override fun createWork(): Single<Result> = Single.defer {
|
||||||
|
|
||||||
// Here we inject every time we create work
|
// Here we inject every time we create work
|
||||||
|
|
|
@ -178,24 +178,24 @@ class OpenHumansUploader @Inject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmOverloads
|
// @JvmOverloads
|
||||||
fun enqueueTreatment(treatment: Treatment?, deleted: Boolean = false) = treatment?.let {
|
// fun enqueueTreatment(treatment: Treatment?, deleted: Boolean = false) = treatment?.let {
|
||||||
insertQueueItem("Treatments") {
|
// insertQueueItem("Treatments") {
|
||||||
put("date", treatment.date)
|
// put("date", treatment.date)
|
||||||
put("isValid", treatment.isValid)
|
// put("isValid", treatment.isValid)
|
||||||
put("source", treatment.source)
|
// put("source", treatment.source)
|
||||||
put("nsId", treatment._id)
|
// put("nsId", treatment._id)
|
||||||
put("boluscalc", treatment.boluscalc)
|
// put("boluscalc", treatment.boluscalc)
|
||||||
put("carbs", treatment.carbs)
|
// put("carbs", treatment.carbs)
|
||||||
put("dia", treatment.dia)
|
// put("dia", treatment.dia)
|
||||||
put("insulin", treatment.insulin)
|
// put("insulin", treatment.insulin)
|
||||||
put("insulinInterfaceID", treatment.insulinInterfaceID)
|
// put("insulinInterfaceID", treatment.insulinInterfaceID)
|
||||||
put("isSMB", treatment.isSMB)
|
// put("isSMB", treatment.isSMB)
|
||||||
put("mealBolus", treatment.mealBolus)
|
// put("mealBolus", treatment.mealBolus)
|
||||||
put("bolusCalcJson", treatment.getBoluscalc())
|
// put("bolusCalcJson", treatment.getBoluscalc())
|
||||||
put("isDeletion", deleted)
|
// put("isDeletion", deleted)
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
@JvmOverloads
|
@JvmOverloads
|
||||||
fun enqueueTherapyEvent(therapyEvent: TherapyEvent, deleted: Boolean = false) = insertQueueItem("TherapyEvents") {
|
fun enqueueTherapyEvent(therapyEvent: TherapyEvent, deleted: Boolean = false) = insertQueueItem("TherapyEvents") {
|
||||||
|
@ -210,17 +210,17 @@ class OpenHumansUploader @Inject constructor(
|
||||||
put("isDeletion", deleted)
|
put("isDeletion", deleted)
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmOverloads
|
// @JvmOverloads
|
||||||
fun enqueueExtendedBolus(extendedBolus: ExtendedBolus, deleted: Boolean = false) = insertQueueItem("ExtendedBoluses") {
|
// fun enqueueExtendedBolus(extendedBolus: ExtendedBolus, deleted: Boolean = false) = insertQueueItem("ExtendedBoluses") {
|
||||||
put("date", extendedBolus.date)
|
// put("date", extendedBolus.date)
|
||||||
put("isValid", extendedBolus.isValid)
|
// put("isValid", extendedBolus.isValid)
|
||||||
put("source", extendedBolus.source)
|
// put("source", extendedBolus.source)
|
||||||
put("nsId", extendedBolus._id)
|
// put("nsId", extendedBolus._id)
|
||||||
put("pumpId", extendedBolus.pumpId)
|
// put("pumpId", extendedBolus.pumpId)
|
||||||
put("insulin", extendedBolus.insulin)
|
// put("insulin", extendedBolus.insulin)
|
||||||
put("durationInMinutes", extendedBolus.durationInMinutes)
|
// put("durationInMinutes", extendedBolus.durationInMinutes)
|
||||||
put("isDeletion", deleted)
|
// put("isDeletion", deleted)
|
||||||
}
|
// }
|
||||||
|
|
||||||
// @JvmOverloads
|
// @JvmOverloads
|
||||||
// fun enqueueProfileSwitch(profileSwitch: ProfileSwitch, deleted: Boolean = false) = insertQueueItem("ProfileSwitches") {
|
// fun enqueueProfileSwitch(profileSwitch: ProfileSwitch, deleted: Boolean = false) = insertQueueItem("ProfileSwitches") {
|
||||||
|
@ -244,22 +244,22 @@ class OpenHumansUploader @Inject constructor(
|
||||||
// put("double", tdd.total)
|
// put("double", tdd.total)
|
||||||
// }
|
// }
|
||||||
|
|
||||||
@JvmOverloads
|
// @JvmOverloads
|
||||||
fun enqueueTemporaryBasal(temporaryBasal: TemporaryBasal?, deleted: Boolean = false) = temporaryBasal?.let {
|
// fun enqueueTemporaryBasal(temporaryBasal: TemporaryBasal?, deleted: Boolean = false) = temporaryBasal?.let {
|
||||||
insertQueueItem("TemporaryBasals") {
|
// insertQueueItem("TemporaryBasals") {
|
||||||
put("date", temporaryBasal.date)
|
// put("date", temporaryBasal.date)
|
||||||
put("isValid", temporaryBasal.isValid)
|
// put("isValid", temporaryBasal.isValid)
|
||||||
put("source", temporaryBasal.source)
|
// put("source", temporaryBasal.source)
|
||||||
put("nsId", temporaryBasal._id)
|
// put("nsId", temporaryBasal._id)
|
||||||
put("pumpId", temporaryBasal.pumpId)
|
// put("pumpId", temporaryBasal.pumpId)
|
||||||
put("durationInMinutes", temporaryBasal.durationInMinutes)
|
// put("durationInMinutes", temporaryBasal.durationInMinutes)
|
||||||
put("durationInMinutes", temporaryBasal.durationInMinutes)
|
// put("durationInMinutes", temporaryBasal.durationInMinutes)
|
||||||
put("isAbsolute", temporaryBasal.isAbsolute)
|
// put("isAbsolute", temporaryBasal.isAbsolute)
|
||||||
put("percentRate", temporaryBasal.percentRate)
|
// put("percentRate", temporaryBasal.percentRate)
|
||||||
put("absoluteRate", temporaryBasal.absoluteRate)
|
// put("absoluteRate", temporaryBasal.absoluteRate)
|
||||||
put("isDeletion", deleted)
|
// put("isDeletion", deleted)
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
@JvmOverloads
|
@JvmOverloads
|
||||||
fun enqueueTempTarget(tempTarget: TemporaryTarget?, deleted: Boolean = false) = tempTarget?.let {
|
fun enqueueTempTarget(tempTarget: TemporaryTarget?, deleted: Boolean = false) = tempTarget?.let {
|
||||||
|
@ -439,6 +439,7 @@ class OpenHumansUploader @Inject constructor(
|
||||||
notificationManager.notify(FAILURE_NOTIFICATION_ID, notification)
|
notificationManager.notify(FAILURE_NOTIFICATION_ID, notification)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@kotlin.ExperimentalStdlibApi
|
||||||
fun uploadDataSegmentally(): Completable =
|
fun uploadDataSegmentally(): Completable =
|
||||||
uploadData(UPLOAD_SEGMENT_SIZE)
|
uploadData(UPLOAD_SEGMENT_SIZE)
|
||||||
.repeatUntil { databaseHelper.getOHQueueSize() == 0L }
|
.repeatUntil { databaseHelper.getOHQueueSize() == 0L }
|
||||||
|
@ -452,6 +453,7 @@ class OpenHumansUploader @Inject constructor(
|
||||||
aapsLogger.error(LTag.OHUPLOADER, "Segmental upload exceptional", it)
|
aapsLogger.error(LTag.OHUPLOADER, "Segmental upload exceptional", it)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@kotlin.ExperimentalStdlibApi
|
||||||
@Suppress("SameParameterValue")
|
@Suppress("SameParameterValue")
|
||||||
private fun uploadData(maxEntries: Long): Completable = gatherData(maxEntries)
|
private fun uploadData(maxEntries: Long): Completable = gatherData(maxEntries)
|
||||||
.flatMap { data -> refreshAccessTokensIfNeeded().map { accessToken -> accessToken to data } }
|
.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 {
|
private fun gatherData(maxEntries: Long) = Single.defer {
|
||||||
val items = databaseHelper.getAllOHQueueItems(maxEntries)
|
val items = databaseHelper.getAllOHQueueItems(maxEntries)
|
||||||
val baos = ByteArrayOutputStream()
|
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.graphics.drawable.AnimationDrawable
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.os.Handler
|
import android.os.Handler
|
||||||
|
import android.os.HandlerThread
|
||||||
import android.util.DisplayMetrics
|
import android.util.DisplayMetrics
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
@ -19,25 +20,27 @@ import android.widget.LinearLayout
|
||||||
import android.widget.RelativeLayout
|
import android.widget.RelativeLayout
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import androidx.core.text.toSpanned
|
import androidx.core.text.toSpanned
|
||||||
import androidx.lifecycle.lifecycleScope
|
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import com.jjoe64.graphview.GraphView
|
import com.jjoe64.graphview.GraphView
|
||||||
import dagger.android.HasAndroidInjector
|
import dagger.android.HasAndroidInjector
|
||||||
import dagger.android.support.DaggerFragment
|
import dagger.android.support.DaggerFragment
|
||||||
import info.nightscout.androidaps.interfaces.Config
|
|
||||||
import info.nightscout.androidaps.Constants
|
import info.nightscout.androidaps.Constants
|
||||||
import info.nightscout.androidaps.R
|
import info.nightscout.androidaps.R
|
||||||
import info.nightscout.androidaps.interfaces.Profile
|
|
||||||
import info.nightscout.androidaps.database.AppRepository
|
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.Action
|
||||||
import info.nightscout.androidaps.database.entities.UserEntry.Sources
|
import info.nightscout.androidaps.database.entities.UserEntry.Sources
|
||||||
import info.nightscout.androidaps.database.interfaces.end
|
import info.nightscout.androidaps.database.interfaces.end
|
||||||
import info.nightscout.androidaps.databinding.OverviewFragmentBinding
|
import info.nightscout.androidaps.databinding.OverviewFragmentBinding
|
||||||
import info.nightscout.androidaps.dialogs.*
|
import info.nightscout.androidaps.dialogs.*
|
||||||
import info.nightscout.androidaps.events.*
|
import info.nightscout.androidaps.events.EventAcceptOpenLoopChange
|
||||||
import info.nightscout.androidaps.extensions.*
|
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.interfaces.*
|
||||||
import info.nightscout.androidaps.logging.AAPSLogger
|
import info.nightscout.androidaps.logging.AAPSLogger
|
||||||
import info.nightscout.androidaps.logging.UserEntryLogger
|
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.configBuilder.ConstraintChecker
|
||||||
import info.nightscout.androidaps.plugins.general.nsclient.data.NSDeviceStatus
|
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.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.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.overview.notifications.NotificationStore
|
||||||
import info.nightscout.androidaps.plugins.general.wear.events.EventWearInitiateAction
|
import info.nightscout.androidaps.plugins.general.wear.events.EventWearInitiateAction
|
||||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatusProvider
|
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.pump.common.defs.PumpType
|
||||||
import info.nightscout.androidaps.plugins.source.DexcomPlugin
|
import info.nightscout.androidaps.plugins.source.DexcomPlugin
|
||||||
import info.nightscout.androidaps.plugins.source.XdripPlugin
|
import info.nightscout.androidaps.plugins.source.XdripPlugin
|
||||||
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin
|
|
||||||
import info.nightscout.androidaps.queue.CommandQueue
|
import info.nightscout.androidaps.queue.CommandQueue
|
||||||
import info.nightscout.androidaps.skins.SkinProvider
|
import info.nightscout.androidaps.skins.SkinProvider
|
||||||
import info.nightscout.androidaps.utils.*
|
import info.nightscout.androidaps.utils.*
|
||||||
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
|
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
|
||||||
import info.nightscout.androidaps.utils.buildHelper.BuildHelper
|
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.protection.ProtectionCheck
|
||||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||||
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
||||||
|
@ -70,15 +70,11 @@ import info.nightscout.androidaps.utils.sharedPreferences.SP
|
||||||
import info.nightscout.androidaps.utils.ui.UIRunnable
|
import info.nightscout.androidaps.utils.ui.UIRunnable
|
||||||
import info.nightscout.androidaps.utils.wizard.QuickWizard
|
import info.nightscout.androidaps.utils.wizard.QuickWizard
|
||||||
import io.reactivex.disposables.CompositeDisposable
|
import io.reactivex.disposables.CompositeDisposable
|
||||||
import kotlinx.coroutines.Dispatchers
|
import io.reactivex.rxkotlin.plusAssign
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import kotlinx.coroutines.withContext
|
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import kotlin.collections.ArrayList
|
import kotlin.collections.ArrayList
|
||||||
import kotlin.math.abs
|
import kotlin.math.abs
|
||||||
import kotlin.math.ceil
|
|
||||||
import kotlin.math.max
|
|
||||||
import kotlin.math.min
|
import kotlin.math.min
|
||||||
|
|
||||||
class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickListener {
|
class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickListener {
|
||||||
|
@ -96,7 +92,6 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
|
||||||
@Inject lateinit var nsDeviceStatus: NSDeviceStatus
|
@Inject lateinit var nsDeviceStatus: NSDeviceStatus
|
||||||
@Inject lateinit var loopPlugin: LoopPlugin
|
@Inject lateinit var loopPlugin: LoopPlugin
|
||||||
@Inject lateinit var activePlugin: ActivePlugin
|
@Inject lateinit var activePlugin: ActivePlugin
|
||||||
@Inject lateinit var treatmentsPlugin: TreatmentsPlugin
|
|
||||||
@Inject lateinit var iobCobCalculator: IobCobCalculator
|
@Inject lateinit var iobCobCalculator: IobCobCalculator
|
||||||
@Inject lateinit var dexcomPlugin: DexcomPlugin
|
@Inject lateinit var dexcomPlugin: DexcomPlugin
|
||||||
@Inject lateinit var dexcomMediator: DexcomPlugin.DexcomMediator
|
@Inject lateinit var dexcomMediator: DexcomPlugin.DexcomMediator
|
||||||
|
@ -112,10 +107,11 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
|
||||||
@Inject lateinit var trendCalculator: TrendCalculator
|
@Inject lateinit var trendCalculator: TrendCalculator
|
||||||
@Inject lateinit var config: Config
|
@Inject lateinit var config: Config
|
||||||
@Inject lateinit var dateUtil: DateUtil
|
@Inject lateinit var dateUtil: DateUtil
|
||||||
@Inject lateinit var databaseHelper: DatabaseHelperInterface
|
|
||||||
@Inject lateinit var uel: UserEntryLogger
|
@Inject lateinit var uel: UserEntryLogger
|
||||||
@Inject lateinit var repository: AppRepository
|
@Inject lateinit var repository: AppRepository
|
||||||
@Inject lateinit var glucoseStatusProvider: GlucoseStatusProvider
|
@Inject lateinit var glucoseStatusProvider: GlucoseStatusProvider
|
||||||
|
@Inject lateinit var overviewData: OverviewData
|
||||||
|
@Inject lateinit var overviewPlugin: OverviewPlugin
|
||||||
|
|
||||||
private val disposable = CompositeDisposable()
|
private val disposable = CompositeDisposable()
|
||||||
|
|
||||||
|
@ -123,17 +119,14 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
|
||||||
private var smallHeight = false
|
private var smallHeight = false
|
||||||
private lateinit var dm: DisplayMetrics
|
private lateinit var dm: DisplayMetrics
|
||||||
private var axisWidth: Int = 0
|
private var axisWidth: Int = 0
|
||||||
private var rangeToDisplay = 6 // for graph
|
|
||||||
private var loopHandler = Handler()
|
|
||||||
private var refreshLoop: Runnable? = null
|
private var refreshLoop: Runnable? = null
|
||||||
|
private lateinit var handler: Handler
|
||||||
|
|
||||||
private val secondaryGraphs = ArrayList<GraphView>()
|
private val secondaryGraphs = ArrayList<GraphView>()
|
||||||
private val secondaryGraphsLabel = ArrayList<TextView>()
|
private val secondaryGraphsLabel = ArrayList<TextView>()
|
||||||
|
|
||||||
private var carbAnimation: AnimationDrawable? = null
|
private var carbAnimation: AnimationDrawable? = null
|
||||||
|
|
||||||
private val graphLock = Object()
|
|
||||||
|
|
||||||
private var _binding: OverviewFragmentBinding? = null
|
private var _binding: OverviewFragmentBinding? = null
|
||||||
|
|
||||||
// This property is only valid between onCreateView and
|
// 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?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
handler = Handler(HandlerThread(this::class.simpleName + "Handler").also { it.start() }.looper)
|
||||||
|
|
||||||
// pre-process landscape mode
|
// pre-process landscape mode
|
||||||
val screenWidth = dm.widthPixels
|
val screenWidth = dm.widthPixels
|
||||||
|
@ -175,13 +169,14 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
|
||||||
carbAnimation?.setEnterFadeDuration(1200)
|
carbAnimation?.setEnterFadeDuration(1200)
|
||||||
carbAnimation?.setExitFadeDuration(1200)
|
carbAnimation?.setExitFadeDuration(1200)
|
||||||
|
|
||||||
rangeToDisplay = sp.getInt(R.string.key_rangetodisplay, 6)
|
|
||||||
|
|
||||||
binding.graphsLayout.bgGraph.setOnLongClickListener {
|
binding.graphsLayout.bgGraph.setOnLongClickListener {
|
||||||
rangeToDisplay += 6
|
overviewData.rangeToDisplay += 6
|
||||||
rangeToDisplay = if (rangeToDisplay > 24) 6 else rangeToDisplay
|
overviewData.rangeToDisplay = if (overviewData.rangeToDisplay > 24) 6 else overviewData.rangeToDisplay
|
||||||
sp.putInt(R.string.key_rangetodisplay, rangeToDisplay)
|
sp.putInt(R.string.key_rangetodisplay, overviewData.rangeToDisplay)
|
||||||
updateGUI("rangeChange")
|
overviewData.initRange()
|
||||||
|
updateGUI("rangeChange", OverviewData.Property.GRAPH)
|
||||||
|
rxBus.send(EventPreferenceChange(resourceHelper, R.string.key_rangetodisplay))
|
||||||
sp.putBoolean(R.string.key_objectiveusescale, true)
|
sp.putBoolean(R.string.key_objectiveusescale, true)
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
@ -210,55 +205,32 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
|
||||||
override fun onPause() {
|
override fun onPause() {
|
||||||
super.onPause()
|
super.onPause()
|
||||||
disposable.clear()
|
disposable.clear()
|
||||||
loopHandler.removeCallbacksAndMessages(null)
|
handler.removeCallbacksAndMessages(null)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Synchronized
|
@Synchronized
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
super.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
|
disposable.add(rxBus
|
||||||
.toObservable(EventRefreshOverview::class.java)
|
.toObservable(EventRefreshOverview::class.java)
|
||||||
.observeOn(aapsSchedulers.main)
|
.observeOn(aapsSchedulers.io)
|
||||||
.subscribe({
|
.subscribe({
|
||||||
if (it.now) updateGUI(it.from)
|
if (it.now) overviewPlugin.refreshLoop(it.from)
|
||||||
else scheduleUpdateGUI(it.from)
|
else scheduleUpdateGUI(it.from)
|
||||||
}, fabricPrivacy::logException))
|
}, 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
|
disposable.add(rxBus
|
||||||
.toObservable(EventAcceptOpenLoopChange::class.java)
|
.toObservable(EventAcceptOpenLoopChange::class.java)
|
||||||
.observeOn(aapsSchedulers.io)
|
.observeOn(aapsSchedulers.io)
|
||||||
.subscribe({ scheduleUpdateGUI("EventAcceptOpenLoopChange") }, fabricPrivacy::logException))
|
.subscribe({ scheduleUpdateGUI("EventAcceptOpenLoopChange") }, fabricPrivacy::logException))
|
||||||
disposable.add(rxBus
|
|
||||||
.toObservable(EventTherapyEventChange::class.java)
|
|
||||||
.observeOn(aapsSchedulers.io)
|
|
||||||
.subscribe({ scheduleUpdateGUI("EventCareportalEventChange") }, fabricPrivacy::logException))
|
|
||||||
disposable.add(rxBus
|
disposable.add(rxBus
|
||||||
.toObservable(EventInitializationChanged::class.java)
|
.toObservable(EventInitializationChanged::class.java)
|
||||||
.observeOn(aapsSchedulers.io)
|
.observeOn(aapsSchedulers.main)
|
||||||
.subscribe({ scheduleUpdateGUI("EventInitializationChanged") }, fabricPrivacy::logException))
|
.subscribe({ updateGUI("EventInitializationChanged", OverviewData.Property.TIME) }, 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))
|
|
||||||
disposable.add(rxBus
|
disposable.add(rxBus
|
||||||
.toObservable(EventPreferenceChange::class.java)
|
.toObservable(EventPreferenceChange::class.java)
|
||||||
.observeOn(aapsSchedulers.io)
|
.observeOn(aapsSchedulers.io)
|
||||||
|
@ -271,18 +243,14 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
|
||||||
.toObservable(EventPumpStatusChanged::class.java)
|
.toObservable(EventPumpStatusChanged::class.java)
|
||||||
.observeOn(aapsSchedulers.main)
|
.observeOn(aapsSchedulers.main)
|
||||||
.subscribe({ updatePumpStatus(it) }, fabricPrivacy::logException))
|
.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 {
|
refreshLoop = Runnable {
|
||||||
scheduleUpdateGUI("refreshLoop")
|
overviewPlugin.refreshLoop("refreshLoop")
|
||||||
loopHandler.postDelayed(refreshLoop, 60 * 1000L)
|
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
|
@Synchronized
|
||||||
|
@ -342,6 +310,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
|
||||||
R.id.accept_temp_button -> {
|
R.id.accept_temp_button -> {
|
||||||
profileFunction.getProfile() ?: return
|
profileFunction.getProfile() ?: return
|
||||||
if (loopPlugin.isEnabled(PluginType.LOOP)) {
|
if (loopPlugin.isEnabled(PluginType.LOOP)) {
|
||||||
|
handler.post {
|
||||||
val lastRun = loopPlugin.lastRun
|
val lastRun = loopPlugin.lastRun
|
||||||
loopPlugin.invoke("Accept temp button", false)
|
loopPlugin.invoke("Accept temp button", false)
|
||||||
if (lastRun?.lastAPSRun != null && lastRun.constraintsProcessed?.isChangeRequested == true) {
|
if (lastRun?.lastAPSRun != null && lastRun.constraintsProcessed?.isChangeRequested == true) {
|
||||||
|
@ -352,12 +321,13 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
|
||||||
binding.buttonsLayout.acceptTempButton.visibility = View.GONE
|
binding.buttonsLayout.acceptTempButton.visibility = View.GONE
|
||||||
(context?.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager).cancel(Constants.notificationID)
|
(context?.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager).cancel(Constants.notificationID)
|
||||||
rxBus.send(EventWearInitiateAction("cancelChangeRequest"))
|
rxBus.send(EventWearInitiateAction("cancelChangeRequest"))
|
||||||
loopPlugin.acceptChangeRequest()
|
Thread { loopPlugin.acceptChangeRequest() }.run()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
R.id.aps_mode -> {
|
R.id.aps_mode -> {
|
||||||
protectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, UIRunnable {
|
protectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, UIRunnable {
|
||||||
|
@ -490,133 +460,11 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun prepareGraphsIfNeeded(numOfGraphs: Int) {
|
private fun processAps() {
|
||||||
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()
|
|
||||||
val pump = activePlugin.activePump
|
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
|
// aps mode
|
||||||
|
val closedLoopEnabled = constraintChecker.isClosedLoopAllowed()
|
||||||
if (config.APS && pump.pumpDescription.isTempBasalCapable) {
|
if (config.APS && pump.pumpDescription.isTempBasalCapable) {
|
||||||
binding.infoLayout.apsMode.visibility = View.VISIBLE
|
binding.infoLayout.apsMode.visibility = View.VISIBLE
|
||||||
binding.infoLayout.timeLayout.visibility = View.GONE
|
binding.infoLayout.timeLayout.visibility = View.GONE
|
||||||
|
@ -677,15 +525,194 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
|
||||||
binding.infoLayout.timeLayout.visibility = View.VISIBLE
|
binding.infoLayout.timeLayout.visibility = View.VISIBLE
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// pump status from ns
|
||||||
|
binding.pump.text = nsDeviceStatus.pumpStatus
|
||||||
|
binding.pump.setOnClickListener { activity?.let { OKDialog.show(it, resourceHelper.gs(R.string.pump), nsDeviceStatus.extendedPumpStatus) } }
|
||||||
|
|
||||||
|
// OpenAPS status from ns
|
||||||
|
binding.openaps.text = nsDeviceStatus.openApsStatus
|
||||||
|
binding.openaps.setOnClickListener { activity?.let { OKDialog.show(it, resourceHelper.gs(R.string.openaps), nsDeviceStatus.extendedOpenApsStatus) } }
|
||||||
|
|
||||||
|
// Uploader status from ns
|
||||||
|
binding.uploader.text = nsDeviceStatus.uploaderStatusSpanned
|
||||||
|
binding.uploader.setOnClickListener { activity?.let { OKDialog.show(it, resourceHelper.gs(R.string.uploader), nsDeviceStatus.extendedUploaderStatus) } }
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
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 {
|
||||||
|
binding.infoLayout.deltaLarge.text = ""
|
||||||
|
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.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) + ")"
|
||||||
|
}
|
||||||
|
|
||||||
|
OverviewData.Property.PROFILE -> {
|
||||||
|
binding.loopPumpStatusLayout.activeProfile.text = overviewData.profileNameWithRemainingTime
|
||||||
|
?: ""
|
||||||
|
binding.loopPumpStatusLayout.activeProfile.setBackgroundColor(overviewData.profileBackgroundColor)
|
||||||
|
binding.loopPumpStatusLayout.activeProfile.setTextColor(overviewData.profileTextColor)
|
||||||
|
}
|
||||||
|
|
||||||
|
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) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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()
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
if (carbAnimation?.isRunning == false)
|
||||||
|
carbAnimation?.start()
|
||||||
|
} else {
|
||||||
|
carbAnimation?.stop()
|
||||||
|
carbAnimation?.selectDrawable(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
OverviewData.Property.TEMPORARY_TARGET -> {
|
||||||
// temp target
|
// temp target
|
||||||
val tempTarget: ValueWrapper<TemporaryTarget> = repository.getTemporaryTargetActiveAt(dateUtil.now()).blockingGet()
|
if (overviewData.temporaryTarget?.isInProgress(dateUtil) == false) overviewData.temporaryTarget = null
|
||||||
if (tempTarget is ValueWrapper.Existing) {
|
val tempTarget = overviewData.temporaryTarget
|
||||||
|
if (tempTarget != null) {
|
||||||
binding.loopPumpStatusLayout.tempTarget.setTextColor(resourceHelper.gc(R.color.ribbonTextWarning))
|
binding.loopPumpStatusLayout.tempTarget.setTextColor(resourceHelper.gc(R.color.ribbonTextWarning))
|
||||||
binding.loopPumpStatusLayout.tempTarget.setBackgroundColor(resourceHelper.gc(R.color.ribbonWarning))
|
binding.loopPumpStatusLayout.tempTarget.setBackgroundColor(resourceHelper.gc(R.color.ribbonWarning))
|
||||||
binding.loopPumpStatusLayout.tempTarget.text = Profile.toTargetRangeString(tempTarget.value.lowTarget, tempTarget.value.highTarget, GlucoseUnit.MGDL, units) + " " + dateUtil.untilString(tempTarget.value.end, resourceHelper)
|
binding.loopPumpStatusLayout.tempTarget.text = Profile.toTargetRangeString(tempTarget.lowTarget, tempTarget.highTarget, GlucoseUnit.MGDL, units) + " " + dateUtil.untilString(tempTarget.end, resourceHelper)
|
||||||
} else {
|
} else {
|
||||||
// If the target is not the same as set in the profile then oref has overridden it
|
// If the target is not the same as set in the profile then oref has overridden it
|
||||||
val targetUsed = lastRun?.constraintsProcessed?.targetBG ?: 0.0
|
overviewData.profile?.let { profile ->
|
||||||
|
val targetUsed = loopPlugin.lastRun?.constraintsProcessed?.targetBG ?: 0.0
|
||||||
|
|
||||||
if (targetUsed != 0.0 && abs(profile.getTargetMgdl() - targetUsed) > 0.01) {
|
if (targetUsed != 0.0 && abs(profile.getTargetMgdl() - targetUsed) > 0.01) {
|
||||||
aapsLogger.debug("Adjusted target. Profile: ${profile.getTargetMgdl()} APS: $targetUsed")
|
aapsLogger.debug("Adjusted target. Profile: ${profile.getTargetMgdl()} APS: $targetUsed")
|
||||||
|
@ -698,197 +725,36 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
|
||||||
binding.loopPumpStatusLayout.tempTarget.text = Profile.toTargetRangeString(profile.getTargetLowMgdl(), profile.getTargetHighMgdl(), GlucoseUnit.MGDL, units)
|
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
|
OverviewData.Property.GRAPH -> {
|
||||||
binding.statusLightsLayout.statusLights.visibility = (sp.getBoolean(R.string.key_show_statuslights, true) || config.NSCLIENT).toVisibility()
|
val graphData = GraphData(injector, binding.graphsLayout.bgGraph, overviewData)
|
||||||
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) } }
|
|
||||||
|
|
||||||
// OpenAPS status from ns
|
|
||||||
binding.openaps.text = nsDeviceStatus.openApsStatus
|
|
||||||
binding.openaps.setOnClickListener { activity?.let { OKDialog.show(it, resourceHelper.gs(R.string.openaps), nsDeviceStatus.extendedOpenApsStatus) } }
|
|
||||||
|
|
||||||
// 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
|
val menuChartSettings = overviewMenus.setting
|
||||||
prepareGraphsIfNeeded(menuChartSettings.size)
|
graphData.addInRangeArea(overviewData.fromTime, overviewData.endTime, defaultValueHelper.determineLowLine(), defaultValueHelper.determineHighLine())
|
||||||
val graphData = GraphData(injector, binding.graphsLayout.bgGraph, iobCobCalculator)
|
graphData.addBgReadings(menuChartSettings[0][OverviewMenus.CharType.PRE.ordinal])
|
||||||
val secondaryGraphsData: ArrayList<GraphData> = ArrayList()
|
if (buildHelper.isDev()) graphData.addBucketedData()
|
||||||
|
graphData.addTreatments()
|
||||||
// do preparation in different thread
|
if (menuChartSettings[0][OverviewMenus.CharType.ACT.ordinal])
|
||||||
withContext(Dispatchers.Default) {
|
graphData.addActivity(0.8)
|
||||||
// align to hours
|
if (pump.pumpDescription.isTempBasalCapable && menuChartSettings[0][OverviewMenus.CharType.BAS.ordinal])
|
||||||
val calendar = Calendar.getInstance()
|
graphData.addBasals()
|
||||||
calendar.timeInMillis = System.currentTimeMillis()
|
graphData.addTargetLine()
|
||||||
calendar[Calendar.MILLISECOND] = 0
|
graphData.addNowLine(dateUtil.now())
|
||||||
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()
|
|
||||||
} 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
|
|
||||||
}
|
|
||||||
val now = System.currentTimeMillis()
|
|
||||||
|
|
||||||
// ------------------ 1st graph
|
|
||||||
|
|
||||||
// **** In range Area ****
|
|
||||||
graphData.addInRangeArea(fromTime, endTime, lowLine, highLine)
|
|
||||||
|
|
||||||
// **** 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)
|
|
||||||
|
|
||||||
// Treatments
|
|
||||||
graphData.addTreatments(fromTime, endTime)
|
|
||||||
|
|
||||||
// set manual x bounds to have nice steps
|
// set manual x bounds to have nice steps
|
||||||
graphData.setNumVerticalLabels()
|
graphData.setNumVerticalLabels()
|
||||||
graphData.formatAxis(fromTime, endTime)
|
graphData.formatAxis(overviewData.fromTime, overviewData.endTime)
|
||||||
|
|
||||||
|
graphData.performUpdate()
|
||||||
|
|
||||||
if (menuChartSettings[0][OverviewMenus.CharType.ACT.ordinal])
|
// 2nd graphs
|
||||||
graphData.addActivity(fromTime, endTime, false, 0.8)
|
prepareGraphsIfNeeded(menuChartSettings.size)
|
||||||
|
val secondaryGraphsData: ArrayList<GraphData> = ArrayList()
|
||||||
|
|
||||||
// add basal data
|
val now = System.currentTimeMillis()
|
||||||
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)) {
|
for (g in 0 until min(secondaryGraphs.size, menuChartSettings.size + 1)) {
|
||||||
val secondGraphData = GraphData(injector, secondaryGraphs[g], iobCobCalculator)
|
val secondGraphData = GraphData(injector, secondaryGraphs[g], overviewData)
|
||||||
var useABSForScale = false
|
var useABSForScale = false
|
||||||
var useIobForScale = false
|
var useIobForScale = false
|
||||||
var useCobForScale = false
|
var useCobForScale = false
|
||||||
|
@ -905,27 +771,21 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
|
||||||
menuChartSettings[g + 1][OverviewMenus.CharType.SEN.ordinal] -> useRatioForScale = true
|
menuChartSettings[g + 1][OverviewMenus.CharType.SEN.ordinal] -> useRatioForScale = true
|
||||||
menuChartSettings[g + 1][OverviewMenus.CharType.DEVSLOPE.ordinal] -> useDSForScale = 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]
|
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.ABS.ordinal]) secondGraphData.addAbsIob(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.IOB.ordinal]) secondGraphData.addIob(useIobForScale, 1.0)
|
||||||
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.COB.ordinal]) secondGraphData.addCob(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.DEV.ordinal]) secondGraphData.addDeviations(useDevForScale, 1.0)
|
||||||
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.BGI.ordinal]) secondGraphData.addMinusBGI(useBGIForScale, if (alignDevBgiScale) 1.0 else 0.8)
|
||||||
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.SEN.ordinal]) secondGraphData.addRatio(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)
|
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
|
// set manual x bounds to have nice steps
|
||||||
secondGraphData.formatAxis(fromTime, endTime)
|
secondGraphData.formatAxis(overviewData.fromTime, overviewData.endTime)
|
||||||
secondGraphData.addNowLine(now)
|
secondGraphData.addNowLine(now)
|
||||||
secondaryGraphsData.add(secondGraphData)
|
secondaryGraphsData.add(secondGraphData)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
// finally enforce drawing of graphs in UI thread
|
|
||||||
graphData.performUpdate()
|
|
||||||
synchronized(graphLock) {
|
|
||||||
for (g in 0 until min(secondaryGraphs.size, menuChartSettings.size + 1)) {
|
for (g in 0 until min(secondaryGraphs.size, menuChartSettings.size + 1)) {
|
||||||
secondaryGraphsLabel[g].text = overviewMenus.enabledTypes(g + 1)
|
secondaryGraphsLabel[g].text = overviewMenus.enabledTypes(g + 1)
|
||||||
secondaryGraphs[g].visibility = (
|
secondaryGraphs[g].visibility = (
|
||||||
|
@ -940,6 +800,23 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
|
||||||
secondaryGraphsData[g].performUpdate()
|
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)
|
||||||
|
} ?: ""
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,6 +46,7 @@ class OverviewMenus @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
const val MAX_GRAPHS = 5 // including main
|
const val MAX_GRAPHS = 5 // including main
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,8 +59,6 @@ class OverviewMenus @Inject constructor(
|
||||||
return r.toString()
|
return r.toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private var _setting: MutableList<Array<Boolean>> = ArrayList()
|
private var _setting: MutableList<Array<Boolean>> = ArrayList()
|
||||||
|
|
||||||
val setting: List<Array<Boolean>>
|
val setting: List<Array<Boolean>>
|
||||||
|
@ -71,7 +70,7 @@ class OverviewMenus @Inject constructor(
|
||||||
aapsLogger.debug(sts)
|
aapsLogger.debug(sts)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun loadGraphConfig() {
|
fun loadGraphConfig() {
|
||||||
val sts = sp.getString(R.string.key_graphconfig, "")
|
val sts = sp.getString(R.string.key_graphconfig, "")
|
||||||
if (sts.isNotEmpty()) {
|
if (sts.isNotEmpty()) {
|
||||||
_setting = Gson().fromJson(sts, Array<Array<Boolean>>::class.java).toMutableList()
|
_setting = Gson().fromJson(sts, Array<Array<Boolean>>::class.java).toMutableList()
|
||||||
|
@ -88,7 +87,6 @@ class OverviewMenus @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setupChartMenu(chartButton: ImageButton) {
|
fun setupChartMenu(chartButton: ImageButton) {
|
||||||
loadGraphConfig()
|
|
||||||
val settingsCopy = setting
|
val settingsCopy = setting
|
||||||
val numOfGraphs = settingsCopy.size // 1 main + x secondary
|
val numOfGraphs = settingsCopy.size // 1 main + x secondary
|
||||||
|
|
||||||
|
@ -100,6 +98,8 @@ class OverviewMenus @Inject constructor(
|
||||||
}
|
}
|
||||||
val popup = PopupMenu(v.context, v)
|
val popup = PopupMenu(v.context, v)
|
||||||
|
|
||||||
|
val used = arrayListOf<Int>()
|
||||||
|
|
||||||
for (g in 0 until numOfGraphs) {
|
for (g in 0 until numOfGraphs) {
|
||||||
if (g != 0 && g < 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 -------")
|
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
|
var insert = true
|
||||||
if (m == CharType.PRE) insert = predictionsAvailable
|
if (m == CharType.PRE) insert = predictionsAvailable
|
||||||
if (m == CharType.DEVSLOPE) insert = buildHelper.isDev()
|
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) {
|
if (insert) {
|
||||||
val item = popup.menu.add(Menu.NONE, m.ordinal + 100 * (g + 1), Menu.NONE, resourceHelper.gs(m.nameId))
|
val item = popup.menu.add(Menu.NONE, m.ordinal + 100 * (g + 1), Menu.NONE, resourceHelper.gs(m.nameId))
|
||||||
val title = item.title
|
val title = item.title
|
||||||
|
@ -120,6 +124,7 @@ class OverviewMenus @Inject constructor(
|
||||||
item.title = s
|
item.title = s
|
||||||
item.isCheckable = true
|
item.isCheckable = true
|
||||||
item.isChecked = settingsCopy[g][m.ordinal]
|
item.isChecked = settingsCopy[g][m.ordinal]
|
||||||
|
if (settingsCopy[g][m.ordinal]) used.add(m.ordinal)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -131,17 +136,21 @@ class OverviewMenus @Inject constructor(
|
||||||
|
|
||||||
popup.setOnMenuItemClickListener {
|
popup.setOnMenuItemClickListener {
|
||||||
// id < 100 graph header - divider 1, 2, 3 .....
|
// id < 100 graph header - divider 1, 2, 3 .....
|
||||||
if (it.itemId == numOfGraphs) {
|
when {
|
||||||
|
it.itemId == numOfGraphs -> {
|
||||||
// add new empty
|
// add new empty
|
||||||
_setting.add(Array(CharType.values().size) { false })
|
_setting.add(Array(CharType.values().size) { false })
|
||||||
} else if (it.itemId < 100) {
|
}
|
||||||
|
it.itemId < 100 -> {
|
||||||
// remove graph
|
// remove graph
|
||||||
_setting.removeAt(it.itemId)
|
_setting.removeAt(it.itemId)
|
||||||
} else {
|
}
|
||||||
|
else -> {
|
||||||
val graphNumber = it.itemId / 100 - 1
|
val graphNumber = it.itemId / 100 - 1
|
||||||
val item = it.itemId % 100
|
val item = it.itemId % 100
|
||||||
_setting[graphNumber][item] = !it.isChecked
|
_setting[graphNumber][item] = !it.isChecked
|
||||||
}
|
}
|
||||||
|
}
|
||||||
storeGraphConfig()
|
storeGraphConfig()
|
||||||
setupChartMenu(chartButton)
|
setupChartMenu(chartButton)
|
||||||
rxBus.send(EventRefreshOverview("OnMenuItemClickListener", now = true))
|
rxBus.send(EventRefreshOverview("OnMenuItemClickListener", now = true))
|
||||||
|
@ -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.PreferenceFragmentCompat
|
||||||
import androidx.preference.SwitchPreference
|
import androidx.preference.SwitchPreference
|
||||||
import dagger.android.HasAndroidInjector
|
import dagger.android.HasAndroidInjector
|
||||||
import info.nightscout.androidaps.interfaces.Config
|
|
||||||
import info.nightscout.androidaps.R
|
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.extensions.*
|
||||||
import info.nightscout.androidaps.interfaces.Overview
|
import info.nightscout.androidaps.interfaces.*
|
||||||
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.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.bus.RxBusWrapper
|
||||||
import info.nightscout.androidaps.plugins.general.overview.events.EventDismissNotification
|
import info.nightscout.androidaps.plugins.general.overview.events.EventDismissNotification
|
||||||
import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification
|
import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification
|
||||||
|
import info.nightscout.androidaps.plugins.general.overview.events.EventUpdateOverview
|
||||||
|
import info.nightscout.androidaps.plugins.general.overview.graphExtensions.Scale
|
||||||
|
import info.nightscout.androidaps.plugins.general.overview.graphExtensions.ScaledDataPoint
|
||||||
import info.nightscout.androidaps.plugins.general.overview.notifications.NotificationStore
|
import info.nightscout.androidaps.plugins.general.overview.notifications.NotificationStore
|
||||||
|
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.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.FabricPrivacy
|
||||||
|
import info.nightscout.androidaps.utils.Translator
|
||||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||||
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
||||||
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
||||||
|
@ -36,7 +43,15 @@ class OverviewPlugin @Inject constructor(
|
||||||
aapsLogger: AAPSLogger,
|
aapsLogger: AAPSLogger,
|
||||||
private val aapsSchedulers: AapsSchedulers,
|
private val aapsSchedulers: AapsSchedulers,
|
||||||
resourceHelper: ResourceHelper,
|
resourceHelper: ResourceHelper,
|
||||||
private val config: Config
|
private val config: Config,
|
||||||
|
private val dateUtil: DateUtil,
|
||||||
|
private val 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()
|
) : PluginBase(PluginDescription()
|
||||||
.mainType(PluginType.GENERAL)
|
.mainType(PluginType.GENERAL)
|
||||||
.fragmentClass(OverviewFragment::class.qualifiedName)
|
.fragmentClass(OverviewFragment::class.qualifiedName)
|
||||||
|
@ -52,8 +67,15 @@ class OverviewPlugin @Inject constructor(
|
||||||
|
|
||||||
private var disposable: CompositeDisposable = CompositeDisposable()
|
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() {
|
override fun onStart() {
|
||||||
super.onStart()
|
super.onStart()
|
||||||
|
overviewMenus.loadGraphConfig()
|
||||||
|
overviewData.initRange()
|
||||||
|
|
||||||
notificationStore.createNotificationChannel()
|
notificationStore.createNotificationChannel()
|
||||||
disposable += rxBus
|
disposable += rxBus
|
||||||
.toObservable(EventNewNotification::class.java)
|
.toObservable(EventNewNotification::class.java)
|
||||||
|
@ -69,6 +91,65 @@ class OverviewPlugin @Inject constructor(
|
||||||
if (notificationStore.remove(n.id))
|
if (notificationStore.remove(n.id))
|
||||||
rxBus.send(EventRefreshOverview("EventDismissNotification"))
|
rxBus.send(EventRefreshOverview("EventDismissNotification"))
|
||||||
}, fabricPrivacy::logException)
|
}, 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() {
|
override fun onStop() {
|
||||||
|
@ -142,4 +223,93 @@ class OverviewPlugin @Inject constructor(
|
||||||
.storeDouble(R.string.key_statuslights_bat_warning, sp, resourceHelper)
|
.storeDouble(R.string.key_statuslights_bat_warning, sp, resourceHelper)
|
||||||
.storeDouble(R.string.key_statuslights_bat_critical, sp, resourceHelper)
|
.storeDouble(R.string.key_statuslights_bat_critical, sp, resourceHelper)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Volatile
|
||||||
|
var runningRefresh = false
|
||||||
|
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.DashPathEffect
|
||||||
import android.graphics.Paint
|
import android.graphics.Paint
|
||||||
import com.jjoe64.graphview.GraphView
|
import com.jjoe64.graphview.GraphView
|
||||||
import com.jjoe64.graphview.series.BarGraphSeries
|
|
||||||
import com.jjoe64.graphview.series.DataPoint
|
import com.jjoe64.graphview.series.DataPoint
|
||||||
import com.jjoe64.graphview.series.LineGraphSeries
|
import com.jjoe64.graphview.series.LineGraphSeries
|
||||||
import com.jjoe64.graphview.series.Series
|
import com.jjoe64.graphview.series.Series
|
||||||
import dagger.android.HasAndroidInjector
|
import dagger.android.HasAndroidInjector
|
||||||
import info.nightscout.androidaps.R
|
import info.nightscout.androidaps.R
|
||||||
import info.nightscout.androidaps.data.IobTotal
|
import info.nightscout.androidaps.interfaces.GlucoseUnit
|
||||||
import info.nightscout.androidaps.database.AppRepository
|
import info.nightscout.androidaps.interfaces.ProfileFunction
|
||||||
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.logging.AAPSLogger
|
import info.nightscout.androidaps.logging.AAPSLogger
|
||||||
import info.nightscout.androidaps.logging.LTag
|
import info.nightscout.androidaps.plugins.general.overview.OverviewData
|
||||||
import info.nightscout.androidaps.plugins.aps.openAPSSMB.SMBDefaults
|
import info.nightscout.androidaps.plugins.general.overview.graphExtensions.AreaGraphSeries
|
||||||
import info.nightscout.androidaps.plugins.general.overview.graphExtensions.*
|
import info.nightscout.androidaps.plugins.general.overview.graphExtensions.DoubleDataPoint
|
||||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensResult
|
import info.nightscout.androidaps.plugins.general.overview.graphExtensions.TimeAsXAxisLabelFormatter
|
||||||
import info.nightscout.androidaps.utils.*
|
import info.nightscout.androidaps.utils.DefaultValueHelper
|
||||||
|
import info.nightscout.androidaps.utils.Round
|
||||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import kotlin.math.abs
|
import kotlin.math.abs
|
||||||
import kotlin.math.max
|
import kotlin.math.max
|
||||||
import kotlin.math.min
|
|
||||||
|
|
||||||
class GraphData(
|
class GraphData(
|
||||||
injector: HasAndroidInjector,
|
injector: HasAndroidInjector,
|
||||||
private val graph: GraphView,
|
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 aapsLogger: AAPSLogger
|
||||||
@Inject lateinit var profileFunction: ProfileFunction
|
@Inject lateinit var profileFunction: ProfileFunction
|
||||||
@Inject lateinit var resourceHelper: ResourceHelper
|
@Inject lateinit var resourceHelper: ResourceHelper
|
||||||
@Inject lateinit var 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 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 minY = Double.MAX_VALUE
|
||||||
private var bgReadingsArray: List<GlucoseValue>? = null
|
|
||||||
private val units: GlucoseUnit
|
private val units: GlucoseUnit
|
||||||
private val series: MutableList<Series<*>> = ArrayList()
|
private val series: MutableList<Series<*>> = ArrayList()
|
||||||
|
|
||||||
|
@ -58,587 +45,142 @@ class GraphData(
|
||||||
units = profileFunction.getUnits()
|
units = profileFunction.getUnits()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun addBucketedData(fromTime: Long, toTime: Long) {
|
fun addBucketedData() {
|
||||||
val bucketedData = iobCobCalculator.ads.getBucketedDataTableCopy() ?: return
|
addSeries(overviewData.bucketedGraphSeries)
|
||||||
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 addBgReadings(fromTime: Long, toTime: Long, highLine: Double, predictions: MutableList<GlucoseValueDataPoint>?) {
|
fun addBgReadings(addPredictions: Boolean) {
|
||||||
var maxBgValue = Double.MIN_VALUE
|
maxY = if (overviewData.bgReadingsArray.isEmpty()) {
|
||||||
bgReadingsArray = repository.compatGetBgReadingsDataFromTime(fromTime, toTime, false).blockingGet()
|
if (units == GlucoseUnit.MGDL) 180.0 else 10.0
|
||||||
if (bgReadingsArray?.isEmpty() != false) {
|
} else overviewData.maxBgValue
|
||||||
aapsLogger.debug("No BG data.")
|
|
||||||
maxY = if (units == GlucoseUnit.MGDL) 180.0 else 10.0
|
|
||||||
minY = 0.0
|
minY = 0.0
|
||||||
return
|
addSeries(overviewData.bgReadingGraphSeries)
|
||||||
|
if (addPredictions) addSeries(overviewData.predictionsGraphSeries)
|
||||||
}
|
}
|
||||||
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
|
|
||||||
minY = 0.0
|
|
||||||
addSeries(PointsWithLabelGraphSeries(Array(bgListArray.size) { i -> bgListArray[i] }))
|
|
||||||
}
|
|
||||||
|
|
||||||
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) {
|
fun addInRangeArea(fromTime: Long, toTime: Long, lowLine: Double, highLine: Double) {
|
||||||
val inRangeAreaSeries: AreaGraphSeries<DoubleDataPoint>
|
|
||||||
val inRangeAreaDataPoints = arrayOf(
|
val inRangeAreaDataPoints = arrayOf(
|
||||||
DoubleDataPoint(fromTime.toDouble(), lowLine, highLine),
|
DoubleDataPoint(fromTime.toDouble(), lowLine, highLine),
|
||||||
DoubleDataPoint(toTime.toDouble(), lowLine, highLine)
|
DoubleDataPoint(toTime.toDouble(), lowLine, highLine)
|
||||||
)
|
)
|
||||||
inRangeAreaSeries = AreaGraphSeries(inRangeAreaDataPoints)
|
addSeries(AreaGraphSeries(inRangeAreaDataPoints).also {
|
||||||
inRangeAreaSeries.color = 0
|
it.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 {
|
|
||||||
it.isDrawBackground = true
|
it.isDrawBackground = true
|
||||||
it.backgroundColor = resourceHelper.gc(R.color.basebasal)
|
it.backgroundColor = resourceHelper.gc(R.color.inrangebackground)
|
||||||
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
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fun addTreatments(fromTime: Long, endTime: Long) {
|
fun addBasals() {
|
||||||
val filteredTreatments: MutableList<DataPointWithLabelInterface> = ArrayList()
|
val scale = defaultValueHelper.determineLowLine() / maxY / 1.2
|
||||||
repository.getBolusesIncludingInvalidFromTimeToTime(fromTime, endTime, true).blockingGet()
|
addSeries(overviewData.baseBasalGraphSeries)
|
||||||
.map { BolusDataPoint(it, resourceHelper, activePlugin, defaultValueHelper) }
|
addSeries(overviewData.tempBasalGraphSeries)
|
||||||
.filter { it.data.type != Bolus.Type.SMB || it.data.isValid }
|
addSeries(overviewData.basalLineGraphSeries)
|
||||||
.forEach {
|
addSeries(overviewData.absoluteBasalGraphSeries)
|
||||||
it.y = getNearestBg(it.x.toLong())
|
overviewData.basalScale.multiplier = maxY * scale / overviewData.maxBasalValueFound
|
||||||
filteredTreatments.add(it)
|
|
||||||
}
|
|
||||||
repository.getCarbsIncludingInvalidFromTimeToTimeExpanded(fromTime, endTime, true).blockingGet()
|
|
||||||
.map { CarbsDataPoint(it, resourceHelper) }
|
|
||||||
.forEach {
|
|
||||||
it.y = getNearestBg(it.x.toLong())
|
|
||||||
filteredTreatments.add(it)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ProfileSwitch
|
fun addTargetLine() {
|
||||||
repository.getEffectiveProfileSwitchDataFromTimeToTime(fromTime, endTime, true).blockingGet()
|
addSeries(overviewData.temporaryTargetSeries)
|
||||||
.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
|
fun addTreatments() {
|
||||||
repository.compatGetTherapyEventDataFromToTime(fromTime - T.hours(6).msecs(), endTime).blockingGet()
|
maxY = maxOf(maxY, overviewData.maxTreatmentsValue)
|
||||||
.map { TherapyEventDataPoint(it, resourceHelper, profileFunction, translator) }
|
addSeries(overviewData.treatmentsSeries)
|
||||||
.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
|
fun addActivity(scale: Double) {
|
||||||
filteredTreatments.map { it.y }
|
addSeries(overviewData.activitySeries)
|
||||||
.maxOrNull()
|
addSeries(overviewData.activityPredictionSeries)
|
||||||
?.let(::addUpperChartMargin)
|
overviewData.actScale.multiplier = maxY * scale / overviewData.maxIAValue
|
||||||
?.let { maxY = maxOf(maxY, it) }
|
|
||||||
|
|
||||||
addSeries(PointsWithLabelGraphSeries(filteredTreatments.toTypedArray()))
|
|
||||||
}
|
|
||||||
|
|
||||||
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 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)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//Function below show -BGI to be able to compare curves with deviations
|
//Function below show -BGI to be able to compare curves with deviations
|
||||||
fun addMinusBGI(fromTime: Long, toTime: Long, useForScale: Boolean, scale: Double, devBgiScale: Boolean) {
|
fun addMinusBGI(useForScale: Boolean, scale: Double) {
|
||||||
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)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
if (useForScale) {
|
if (useForScale) {
|
||||||
maxY = maxBGIValue
|
maxY = overviewData.maxBGIValue
|
||||||
minY = -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)
|
// scale in % of vertical size (like 0.3)
|
||||||
fun addIob(fromTime: Long, toTime: Long, useForScale: Boolean, scale: Double, showPrediction: Boolean, absScale: Boolean) {
|
fun addIob(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
|
|
||||||
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))
|
|
||||||
}
|
|
||||||
if (useForScale) {
|
if (useForScale) {
|
||||||
maxY = maxIobValueFound
|
maxY = overviewData.maxIobValueFound
|
||||||
minY = -maxIobValueFound
|
minY = -overviewData.maxIobValueFound
|
||||||
}
|
}
|
||||||
iobScale.setMultiplier(maxY * scale / maxIobValueFound)
|
overviewData.iobScale.multiplier = maxY * scale / overviewData.maxIobValueFound
|
||||||
addSeries(iobSeries)
|
addSeries(overviewData.iobSeries)
|
||||||
|
addSeries(overviewData.iobPredictions1Series)
|
||||||
|
addSeries(overviewData.iobPredictions2Series)
|
||||||
}
|
}
|
||||||
|
|
||||||
// scale in % of vertical size (like 0.3)
|
// scale in % of vertical size (like 0.3)
|
||||||
fun addAbsIob(fromTime: Long, toTime: Long, useForScale: Boolean, scale: Double) {
|
fun addAbsIob(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
|
|
||||||
}
|
|
||||||
if (useForScale) {
|
if (useForScale) {
|
||||||
maxY = maxIobValueFound
|
maxY = overviewData.maxIobValueFound
|
||||||
minY = -maxIobValueFound
|
minY = -overviewData.maxIobValueFound
|
||||||
}
|
}
|
||||||
iobScale.setMultiplier(maxY * scale / maxIobValueFound)
|
overviewData.iobScale.multiplier = maxY * scale / overviewData.maxIobValueFound
|
||||||
addSeries(iobSeries)
|
addSeries(overviewData.absIobSeries)
|
||||||
}
|
}
|
||||||
|
|
||||||
// scale in % of vertical size (like 0.3)
|
// scale in % of vertical size (like 0.3)
|
||||||
fun addCob(fromTime: Long, toTime: Long, useForScale: Boolean, scale: Double) {
|
fun addCob(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
|
|
||||||
})
|
|
||||||
if (useForScale) {
|
if (useForScale) {
|
||||||
maxY = maxCobValueFound
|
maxY = overviewData.maxCobValueFound
|
||||||
minY = 0.0
|
minY = 0.0
|
||||||
}
|
}
|
||||||
cobScale.setMultiplier(maxY * scale / maxCobValueFound)
|
overviewData.cobScale.multiplier = maxY * scale / overviewData.maxCobValueFound
|
||||||
addSeries(PointsWithLabelGraphSeries(Array(minFailOverActiveList.size) { i -> minFailOverActiveList[i] }))
|
addSeries(overviewData.cobSeries)
|
||||||
|
addSeries(overviewData.cobMinFailOverSeries)
|
||||||
}
|
}
|
||||||
|
|
||||||
// scale in % of vertical size (like 0.3)
|
// scale in % of vertical size (like 0.3)
|
||||||
fun addDeviations(fromTime: Long, toTime: Long, useForScale: Boolean, scale: Double, devBgiScale: Boolean) {
|
fun addDeviations(useForScale: Boolean, scale: Double) {
|
||||||
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 }
|
|
||||||
})
|
|
||||||
if (useForScale) {
|
if (useForScale) {
|
||||||
maxY = maxDevValueFound
|
maxY = overviewData.maxDevValueFound
|
||||||
minY = -maxY
|
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)
|
// scale in % of vertical size (like 0.3)
|
||||||
fun addRatio(fromTime: Long, toTime: Long, useForScale: Boolean, scale: Double) {
|
fun addRatio(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
|
|
||||||
})
|
|
||||||
if (useForScale) {
|
if (useForScale) {
|
||||||
maxY = 100.0 + max(maxRatioValueFound, abs(minRatioValueFound))
|
maxY = 100.0 + max(overviewData.maxRatioValueFound, abs(overviewData.minRatioValueFound))
|
||||||
minY = 100.0 - max(maxRatioValueFound, abs(minRatioValueFound))
|
minY = 100.0 - max(overviewData.maxRatioValueFound, abs(overviewData.minRatioValueFound))
|
||||||
ratioScale.setMultiplier(1.0)
|
overviewData.ratioScale.multiplier = 1.0
|
||||||
} else
|
overviewData.ratioScale.shift = 100.0
|
||||||
ratioScale.setMultiplier(maxY * scale / max(maxRatioValueFound, abs(minRatioValueFound)))
|
} 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)
|
// scale in % of vertical size (like 0.3)
|
||||||
fun addDeviationSlope(fromTime: Long, toTime: Long, useForScale: Boolean, scale: Double) {
|
fun addDeviationSlope(useForScale: Boolean, scale: Double, isRatioScale: Boolean = false) {
|
||||||
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
|
|
||||||
})
|
|
||||||
if (useForScale) {
|
if (useForScale) {
|
||||||
maxY = max(maxFromMaxValueFound, maxFromMinValueFound)
|
maxY = max(overviewData.maxFromMaxValueFound, overviewData.maxFromMinValueFound)
|
||||||
minY = -maxY
|
minY = -maxY
|
||||||
}
|
}
|
||||||
dsMaxScale.setMultiplier(maxY * scale / maxFromMaxValueFound)
|
var graphMaxY = maxY
|
||||||
dsMinScale.setMultiplier(maxY * scale / maxFromMinValueFound)
|
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)
|
// 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) {
|
if (data.glucose != null && data.glucose != 0.0) {
|
||||||
var mmol = 0.0
|
var mmol = 0.0
|
||||||
var mgdl = 0.0
|
var mgdl = 0.0
|
||||||
if (units == GlucoseUnit.MGDL) {
|
if (data.glucoseUnit == TherapyEvent.GlucoseUnit.MGDL) {
|
||||||
mgdl = data.glucose!!
|
mgdl = data.glucose!!
|
||||||
mmol = data.glucose!! * Constants.MGDL_TO_MMOLL
|
mmol = data.glucose!! * Constants.MGDL_TO_MMOLL
|
||||||
}
|
}
|
||||||
if (units == GlucoseUnit.MMOL) {
|
if (data.glucoseUnit == TherapyEvent.GlucoseUnit.MMOL) {
|
||||||
mmol = data.glucose!!
|
mmol = data.glucose!!
|
||||||
mgdl = data.glucose!! * Constants.MMOLL_TO_MGDL
|
mgdl = data.glucose!! * Constants.MMOLL_TO_MGDL
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,25 +11,26 @@ import androidx.work.Worker
|
||||||
import androidx.work.WorkerParameters
|
import androidx.work.WorkerParameters
|
||||||
import androidx.work.workDataOf
|
import androidx.work.workDataOf
|
||||||
import dagger.android.HasAndroidInjector
|
import dagger.android.HasAndroidInjector
|
||||||
import info.nightscout.androidaps.interfaces.Config
|
|
||||||
import info.nightscout.androidaps.Constants
|
import info.nightscout.androidaps.Constants
|
||||||
import info.nightscout.androidaps.R
|
import info.nightscout.androidaps.R
|
||||||
import info.nightscout.androidaps.data.DetailedBolusInfo
|
import info.nightscout.androidaps.data.DetailedBolusInfo
|
||||||
import info.nightscout.androidaps.interfaces.Profile
|
|
||||||
import info.nightscout.androidaps.database.AppRepository
|
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.TemporaryTarget
|
||||||
import info.nightscout.androidaps.database.entities.UserEntry.Action
|
import info.nightscout.androidaps.database.entities.UserEntry.Action
|
||||||
import info.nightscout.androidaps.database.entities.UserEntry.Sources
|
import info.nightscout.androidaps.database.entities.UserEntry.Sources
|
||||||
|
import info.nightscout.androidaps.database.entities.ValueWithUnit
|
||||||
|
import info.nightscout.androidaps.database.transactions.CancelCurrentOfflineEventIfAnyTransaction
|
||||||
import info.nightscout.androidaps.database.transactions.CancelCurrentTemporaryTargetIfAnyTransaction
|
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.EventPreferenceChange
|
||||||
import info.nightscout.androidaps.events.EventRefreshOverview
|
import info.nightscout.androidaps.events.EventRefreshOverview
|
||||||
|
import info.nightscout.androidaps.extensions.valueToUnitsString
|
||||||
import info.nightscout.androidaps.interfaces.*
|
import info.nightscout.androidaps.interfaces.*
|
||||||
import info.nightscout.androidaps.logging.AAPSLogger
|
import info.nightscout.androidaps.logging.AAPSLogger
|
||||||
import info.nightscout.androidaps.logging.LTag
|
import info.nightscout.androidaps.logging.LTag
|
||||||
import info.nightscout.androidaps.logging.UserEntryLogger
|
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.bus.RxBusWrapper
|
||||||
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
|
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
|
||||||
import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientRestart
|
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.queue.Callback
|
||||||
import info.nightscout.androidaps.receivers.DataWorker
|
import info.nightscout.androidaps.receivers.DataWorker
|
||||||
import info.nightscout.androidaps.utils.*
|
import info.nightscout.androidaps.utils.*
|
||||||
import info.nightscout.androidaps.extensions.valueToUnitsString
|
|
||||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||||
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
||||||
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
||||||
|
@ -72,7 +72,7 @@ class SmsCommunicatorPlugin @Inject constructor(
|
||||||
private val fabricPrivacy: FabricPrivacy,
|
private val fabricPrivacy: FabricPrivacy,
|
||||||
private val activePlugin: ActivePlugin,
|
private val activePlugin: ActivePlugin,
|
||||||
private val commandQueue: CommandQueueProvider,
|
private val commandQueue: CommandQueueProvider,
|
||||||
private val loopPlugin: LoopPlugin,
|
private val loop: Loop,
|
||||||
private val iobCobCalculator: IobCobCalculator,
|
private val iobCobCalculator: IobCobCalculator,
|
||||||
private val xdripCalibrations: XdripCalibrations,
|
private val xdripCalibrations: XdripCalibrations,
|
||||||
private var otp: OneTimePassword,
|
private var otp: OneTimePassword,
|
||||||
|
@ -181,6 +181,7 @@ class SmsCommunicatorPlugin @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("SpellCheckingInspection")
|
@Suppress("SpellCheckingInspection")
|
||||||
|
@kotlin.ExperimentalStdlibApi
|
||||||
override fun doWork(): Result {
|
override fun doWork(): Result {
|
||||||
val bundle = dataWorker.pickupBundle(inputData.getLong(DataWorker.STORE_KEY, -1))
|
val bundle = dataWorker.pickupBundle(inputData.getLong(DataWorker.STORE_KEY, -1))
|
||||||
?: return Result.failure(workDataOf("Error" to "missing input data"))
|
?: return Result.failure(workDataOf("Error" to "missing input data"))
|
||||||
|
@ -223,6 +224,7 @@ class SmsCommunicatorPlugin @Inject constructor(
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@kotlin.ExperimentalStdlibApi
|
||||||
fun processSms(receivedSms: Sms) {
|
fun processSms(receivedSms: Sms) {
|
||||||
if (!isEnabled(PluginType.GENERAL)) {
|
if (!isEnabled(PluginType.GENERAL)) {
|
||||||
aapsLogger.debug(LTag.SMS, "Ignoring SMS. Plugin disabled.")
|
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()
|
T.mins(sp.getLong(R.string.key_smscommunicator_remotebolusmindistance, T.msecs(Constants.remoteBolusMinDistance).mins())).msecs()
|
||||||
else Constants.remoteBolusMinDistance
|
else Constants.remoteBolusMinDistance
|
||||||
|
|
||||||
if (divided.isNotEmpty() && isCommand(divided[0].toUpperCase(Locale.getDefault()), receivedSms.phoneNumber)) {
|
if (divided.isNotEmpty() && isCommand(divided[0].uppercase(Locale.getDefault()), receivedSms.phoneNumber)) {
|
||||||
when (divided[0].toUpperCase(Locale.getDefault())) {
|
when (divided[0].uppercase(Locale.getDefault())) {
|
||||||
"BG" ->
|
"BG" ->
|
||||||
if (divided.size == 1) processBG(receivedSms)
|
if (divided.size == 1) processBG(receivedSms)
|
||||||
else sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.wrongformat)))
|
else sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.wrongformat)))
|
||||||
|
@ -334,17 +336,18 @@ class SmsCommunicatorPlugin @Inject constructor(
|
||||||
receivedSms.processed = true
|
receivedSms.processed = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@kotlin.ExperimentalStdlibApi
|
||||||
private fun processLOOP(divided: Array<String>, receivedSms: Sms) {
|
private fun processLOOP(divided: Array<String>, receivedSms: Sms) {
|
||||||
when (divided[1].toUpperCase(Locale.getDefault())) {
|
when (divided[1].uppercase(Locale.getDefault())) {
|
||||||
"DISABLE", "STOP" -> {
|
"DISABLE", "STOP" -> {
|
||||||
if (loopPlugin.isEnabled(PluginType.LOOP)) {
|
if (loop.enabled) {
|
||||||
val passCode = generatePassCode()
|
val passCode = generatePassCode()
|
||||||
val reply = String.format(resourceHelper.gs(R.string.smscommunicator_loopdisablereplywithcode), passCode)
|
val reply = String.format(resourceHelper.gs(R.string.smscommunicator_loopdisablereplywithcode), passCode)
|
||||||
receivedSms.processed = true
|
receivedSms.processed = true
|
||||||
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction() {
|
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction() {
|
||||||
override fun run() {
|
override fun run() {
|
||||||
uel.log(Action.LOOP_DISABLED, Sources.SMS)
|
uel.log(Action.LOOP_DISABLED, Sources.SMS)
|
||||||
loopPlugin.setPluginEnabled(PluginType.LOOP, false)
|
loop.enabled = false
|
||||||
commandQueue.cancelTempBasal(true, object : Callback() {
|
commandQueue.cancelTempBasal(true, object : Callback() {
|
||||||
override fun run() {
|
override fun run() {
|
||||||
rxBus.send(EventRefreshOverview("SMS_LOOP_STOP"))
|
rxBus.send(EventRefreshOverview("SMS_LOOP_STOP"))
|
||||||
|
@ -361,14 +364,14 @@ class SmsCommunicatorPlugin @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
"ENABLE", "START" -> {
|
"ENABLE", "START" -> {
|
||||||
if (!loopPlugin.isEnabled(PluginType.LOOP)) {
|
if (!loop.enabled) {
|
||||||
val passCode = generatePassCode()
|
val passCode = generatePassCode()
|
||||||
val reply = String.format(resourceHelper.gs(R.string.smscommunicator_loopenablereplywithcode), passCode)
|
val reply = String.format(resourceHelper.gs(R.string.smscommunicator_loopenablereplywithcode), passCode)
|
||||||
receivedSms.processed = true
|
receivedSms.processed = true
|
||||||
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction() {
|
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction() {
|
||||||
override fun run() {
|
override fun run() {
|
||||||
uel.log(Action.LOOP_ENABLED, Sources.SMS)
|
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)))
|
sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.smscommunicator_loophasbeenenabled)))
|
||||||
rxBus.send(EventRefreshOverview("SMS_LOOP_START"))
|
rxBus.send(EventRefreshOverview("SMS_LOOP_START"))
|
||||||
}
|
}
|
||||||
|
@ -379,8 +382,8 @@ class SmsCommunicatorPlugin @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
"STATUS" -> {
|
"STATUS" -> {
|
||||||
val reply = if (loopPlugin.isEnabled(PluginType.LOOP)) {
|
val reply = if (loop.enabled) {
|
||||||
if (loopPlugin.isSuspended) String.format(resourceHelper.gs(R.string.loopsuspendedfor), loopPlugin.minutesToEndOfSuspend())
|
if (loop.isSuspended) String.format(resourceHelper.gs(R.string.loopsuspendedfor), loop.minutesToEndOfSuspend())
|
||||||
else resourceHelper.gs(R.string.smscommunicator_loopisenabled)
|
else resourceHelper.gs(R.string.smscommunicator_loopisenabled)
|
||||||
} else
|
} else
|
||||||
resourceHelper.gs(R.string.loopisdisabled)
|
resourceHelper.gs(R.string.loopisdisabled)
|
||||||
|
@ -395,7 +398,12 @@ class SmsCommunicatorPlugin @Inject constructor(
|
||||||
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction() {
|
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction() {
|
||||||
override fun run() {
|
override fun run() {
|
||||||
uel.log(Action.RESUME, Sources.SMS)
|
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"))
|
rxBus.send(EventRefreshOverview("SMS_LOOP_RESUME"))
|
||||||
commandQueue.cancelTempBasal(true, object : Callback() {
|
commandQueue.cancelTempBasal(true, object : Callback() {
|
||||||
override fun run() {
|
override fun run() {
|
||||||
|
@ -406,7 +414,6 @@ class SmsCommunicatorPlugin @Inject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
loopPlugin.createOfflineEvent(0)
|
|
||||||
sendSMSToAllNumbers(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.smscommunicator_loopresumed)))
|
sendSMSToAllNumbers(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.smscommunicator_loopresumed)))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -431,8 +438,13 @@ class SmsCommunicatorPlugin @Inject constructor(
|
||||||
commandQueue.cancelTempBasal(true, object : Callback() {
|
commandQueue.cancelTempBasal(true, object : Callback() {
|
||||||
override fun run() {
|
override fun run() {
|
||||||
if (result.success) {
|
if (result.success) {
|
||||||
loopPlugin.suspendTo(dateUtil.now() + anInteger() * 60L * 1000)
|
disposable += repository.runTransactionForResult(InsertAndCancelCurrentOfflineEventTransaction(dateUtil.now(), T.mins(anInteger().toLong()).msecs(), OfflineEvent.Reason.SUSPEND))
|
||||||
loopPlugin.createOfflineEvent(anInteger() * 60)
|
.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"))
|
rxBus.send(EventRefreshOverview("SMS_LOOP_SUSPENDED"))
|
||||||
val replyText = resourceHelper.gs(R.string.smscommunicator_loopsuspended) + " " +
|
val replyText = resourceHelper.gs(R.string.smscommunicator_loopsuspended) + " " +
|
||||||
resourceHelper.gs(if (result.success) R.string.smscommunicator_tempbasalcanceled else R.string.smscommunicator_tempbasalcancelfailed)
|
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) {
|
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())
|
rxBus.send(EventNSClientRestart())
|
||||||
sendSMS(Sms(receivedSms.phoneNumber, "NSCLIENT RESTART SENT"))
|
sendSMS(Sms(receivedSms.phoneNumber, "NSCLIENT RESTART SENT"))
|
||||||
receivedSms.processed = true
|
receivedSms.processed = true
|
||||||
|
@ -462,6 +475,7 @@ class SmsCommunicatorPlugin @Inject constructor(
|
||||||
sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.wrongformat)))
|
sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.wrongformat)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@kotlin.ExperimentalStdlibApi
|
||||||
private fun processHELP(divided: Array<String>, receivedSms: Sms) {
|
private fun processHELP(divided: Array<String>, receivedSms: Sms) {
|
||||||
when {
|
when {
|
||||||
divided.size == 1 -> {
|
divided.size == 1 -> {
|
||||||
|
@ -469,8 +483,8 @@ class SmsCommunicatorPlugin @Inject constructor(
|
||||||
receivedSms.processed = true
|
receivedSms.processed = true
|
||||||
}
|
}
|
||||||
|
|
||||||
isCommand(divided[1].toUpperCase(Locale.getDefault()), receivedSms.phoneNumber) -> {
|
isCommand(divided[1].uppercase(Locale.getDefault()), receivedSms.phoneNumber) -> {
|
||||||
commands[divided[1].toUpperCase(Locale.getDefault())]?.let {
|
commands[divided[1].uppercase(Locale.getDefault())]?.let {
|
||||||
sendSMS(Sms(receivedSms.phoneNumber, it))
|
sendSMS(Sms(receivedSms.phoneNumber, it))
|
||||||
receivedSms.processed = true
|
receivedSms.processed = true
|
||||||
}
|
}
|
||||||
|
@ -507,10 +521,14 @@ class SmsCommunicatorPlugin @Inject constructor(
|
||||||
if (!result.success) {
|
if (!result.success) {
|
||||||
sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.smscommunicator_pumpconnectfail)))
|
sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.smscommunicator_pumpconnectfail)))
|
||||||
} else {
|
} 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)))
|
sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.smscommunicator_reconnect)))
|
||||||
rxBus.send(EventRefreshOverview("SMS_PUMP_START"))
|
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() {
|
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction() {
|
||||||
override fun run() {
|
override fun run() {
|
||||||
uel.log(Action.DISCONNECT, Sources.SMS)
|
uel.log(Action.DISCONNECT, Sources.SMS)
|
||||||
val profile = profileFunction.getProfile()
|
val profile = profileFunction.getProfile() ?: return
|
||||||
loopPlugin.disconnectPump(duration, profile)
|
loop.goToZeroTemp(duration, profile, OfflineEvent.Reason.DISCONNECT_PUMP)
|
||||||
rxBus.send(EventRefreshOverview("SMS_PUMP_DISCONNECT"))
|
rxBus.send(EventRefreshOverview("SMS_PUMP_DISCONNECT"))
|
||||||
sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.smscommunicator_pumpdisconnected)))
|
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
|
private fun processPROFILE(divided: Array<String>, receivedSms: Sms) { // load profiles
|
||||||
val anInterface = activePlugin.activeProfileSource
|
val anInterface = activePlugin.activeProfileSource
|
||||||
val store = anInterface.profile
|
val store = anInterface.profile
|
||||||
|
@ -554,9 +573,9 @@ class SmsCommunicatorPlugin @Inject constructor(
|
||||||
}
|
}
|
||||||
val profileName = profileFunction.getProfileName()
|
val profileName = profileFunction.getProfileName()
|
||||||
val list = store.getProfileList()
|
val list = store.getProfileList()
|
||||||
if (divided[1].toUpperCase(Locale.getDefault()) == "STATUS") {
|
if (divided[1].uppercase(Locale.getDefault()) == "STATUS") {
|
||||||
sendSMS(Sms(receivedSms.phoneNumber, profileName))
|
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)))
|
if (list.isEmpty()) sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.invalidprofile)))
|
||||||
else {
|
else {
|
||||||
var reply = ""
|
var reply = ""
|
||||||
|
@ -597,8 +616,9 @@ class SmsCommunicatorPlugin @Inject constructor(
|
||||||
receivedSms.processed = true
|
receivedSms.processed = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@kotlin.ExperimentalStdlibApi
|
||||||
private fun processBASAL(divided: Array<String>, receivedSms: Sms) {
|
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 passCode = generatePassCode()
|
||||||
val reply = String.format(resourceHelper.gs(R.string.smscommunicator_basalstopreplywithcode), passCode)
|
val reply = String.format(resourceHelper.gs(R.string.smscommunicator_basalstopreplywithcode), passCode)
|
||||||
receivedSms.processed = true
|
receivedSms.processed = true
|
||||||
|
@ -713,8 +733,9 @@ class SmsCommunicatorPlugin @Inject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@kotlin.ExperimentalStdlibApi
|
||||||
private fun processEXTENDED(divided: Array<String>, receivedSms: Sms) {
|
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 passCode = generatePassCode()
|
||||||
val reply = String.format(resourceHelper.gs(R.string.smscommunicator_extendedstopreplywithcode), passCode)
|
val reply = String.format(resourceHelper.gs(R.string.smscommunicator_extendedstopreplywithcode), passCode)
|
||||||
receivedSms.processed = true
|
receivedSms.processed = true
|
||||||
|
@ -824,7 +845,7 @@ class SmsCommunicatorPlugin @Inject constructor(
|
||||||
currentProfile.units == GlucoseUnit.MMOL -> Constants.defaultEatingSoonTTmmol
|
currentProfile.units == GlucoseUnit.MMOL -> Constants.defaultEatingSoonTTmmol
|
||||||
else -> Constants.defaultEatingSoonTTmgdl
|
else -> Constants.defaultEatingSoonTTmgdl
|
||||||
}
|
}
|
||||||
disposable += repository.runTransactionForResult(InsertTemporaryTargetAndCancelCurrentTransaction(
|
disposable += repository.runTransactionForResult(InsertAndCancelCurrentTemporaryTargetTransaction(
|
||||||
timestamp = dateUtil.now(),
|
timestamp = dateUtil.now(),
|
||||||
duration = TimeUnit.MINUTES.toMillis(eatingSoonTTDuration.toLong()),
|
duration = TimeUnit.MINUTES.toMillis(eatingSoonTTDuration.toLong()),
|
||||||
reason = TemporaryTarget.Reason.EATING_SOON,
|
reason = TemporaryTarget.Reason.EATING_SOON,
|
||||||
|
@ -879,11 +900,12 @@ class SmsCommunicatorPlugin @Inject constructor(
|
||||||
return retVal
|
return retVal
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@kotlin.ExperimentalStdlibApi
|
||||||
private fun processCARBS(divided: Array<String>, receivedSms: Sms) {
|
private fun processCARBS(divided: Array<String>, receivedSms: Sms) {
|
||||||
var grams = SafeParse.stringToInt(divided[1])
|
var grams = SafeParse.stringToInt(divided[1])
|
||||||
var time = dateUtil.now()
|
var time = dateUtil.now()
|
||||||
if (divided.size > 2) {
|
if (divided.size > 2) {
|
||||||
time = toTodayTime(divided[2].toUpperCase(Locale.getDefault()))
|
time = toTodayTime(divided[2].uppercase(Locale.getDefault()))
|
||||||
if (time == 0L) {
|
if (time == 0L) {
|
||||||
sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.wrongformat)))
|
sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.wrongformat)))
|
||||||
return
|
return
|
||||||
|
@ -922,6 +944,7 @@ class SmsCommunicatorPlugin @Inject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@kotlin.ExperimentalStdlibApi
|
||||||
private fun processTARGET(divided: Array<String>, receivedSms: Sms) {
|
private fun processTARGET(divided: Array<String>, receivedSms: Sms) {
|
||||||
val isMeal = divided[1].equals("MEAL", ignoreCase = true)
|
val isMeal = divided[1].equals("MEAL", ignoreCase = true)
|
||||||
val isActivity = divided[1].equals("ACTIVITY", 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)
|
val isStop = divided[1].equals("STOP", ignoreCase = true) || divided[1].equals("CANCEL", ignoreCase = true)
|
||||||
if (isMeal || isActivity || isHypo) {
|
if (isMeal || isActivity || isHypo) {
|
||||||
val passCode = generatePassCode()
|
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
|
receivedSms.processed = true
|
||||||
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction() {
|
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction() {
|
||||||
override fun run() {
|
override fun run() {
|
||||||
|
@ -969,7 +992,7 @@ class SmsCommunicatorPlugin @Inject constructor(
|
||||||
var tt = sp.getDouble(keyTarget, if (units == GlucoseUnit.MMOL) defaultTargetMMOL else defaultTargetMGDL)
|
var tt = sp.getDouble(keyTarget, if (units == GlucoseUnit.MMOL) defaultTargetMMOL else defaultTargetMGDL)
|
||||||
tt = Profile.toCurrentUnits(profileFunction, tt)
|
tt = Profile.toCurrentUnits(profileFunction, tt)
|
||||||
tt = if (tt > 0) tt else if (units == GlucoseUnit.MMOL) defaultTargetMMOL else defaultTargetMGDL
|
tt = if (tt > 0) tt else if (units == GlucoseUnit.MMOL) defaultTargetMMOL else defaultTargetMGDL
|
||||||
disposable += repository.runTransactionForResult(InsertTemporaryTargetAndCancelCurrentTransaction(
|
disposable += repository.runTransactionForResult(InsertAndCancelCurrentTemporaryTargetTransaction(
|
||||||
timestamp = dateUtil.now(),
|
timestamp = dateUtil.now(),
|
||||||
duration = TimeUnit.MINUTES.toMillis(ttDuration.toLong()),
|
duration = TimeUnit.MINUTES.toMillis(ttDuration.toLong()),
|
||||||
reason = TemporaryTarget.Reason.EATING_SOON,
|
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.entities.ValueWithUnit
|
||||||
import info.nightscout.androidaps.database.interfaces.end
|
import info.nightscout.androidaps.database.interfaces.end
|
||||||
import info.nightscout.androidaps.database.transactions.CancelCurrentTemporaryTargetIfAnyTransaction
|
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.total
|
||||||
import info.nightscout.androidaps.extensions.valueToUnits
|
import info.nightscout.androidaps.extensions.valueToUnits
|
||||||
import info.nightscout.androidaps.interfaces.*
|
import info.nightscout.androidaps.interfaces.*
|
||||||
|
@ -572,7 +572,7 @@ class ActionStringHandler @Inject constructor(
|
||||||
|
|
||||||
private fun generateTempTarget(duration: Int, low: Double, high: Double) {
|
private fun generateTempTarget(duration: Int, low: Double, high: Double) {
|
||||||
if (duration != 0) {
|
if (duration != 0) {
|
||||||
disposable += repository.runTransactionForResult(InsertTemporaryTargetAndCancelCurrentTransaction(
|
disposable += repository.runTransactionForResult(InsertAndCancelCurrentTemporaryTargetTransaction(
|
||||||
timestamp = System.currentTimeMillis(),
|
timestamp = System.currentTimeMillis(),
|
||||||
duration = TimeUnit.MINUTES.toMillis(duration.toLong()),
|
duration = TimeUnit.MINUTES.toMillis(duration.toLong()),
|
||||||
reason = TemporaryTarget.Reason.WEAR,
|
reason = TemporaryTarget.Reason.WEAR,
|
||||||
|
|
|
@ -7,7 +7,6 @@ import info.nightscout.androidaps.Constants
|
||||||
import info.nightscout.androidaps.R
|
import info.nightscout.androidaps.R
|
||||||
import info.nightscout.androidaps.data.IobTotal
|
import info.nightscout.androidaps.data.IobTotal
|
||||||
import info.nightscout.androidaps.data.MealData
|
import info.nightscout.androidaps.data.MealData
|
||||||
import info.nightscout.androidaps.interfaces.Profile
|
|
||||||
import info.nightscout.androidaps.database.AppRepository
|
import info.nightscout.androidaps.database.AppRepository
|
||||||
import info.nightscout.androidaps.database.ValueWrapper
|
import info.nightscout.androidaps.database.ValueWrapper
|
||||||
import info.nightscout.androidaps.database.entities.Bolus
|
import info.nightscout.androidaps.database.entities.Bolus
|
||||||
|
@ -71,7 +70,6 @@ open class IobCobCalculatorPlugin @Inject constructor(
|
||||||
private val disposable = CompositeDisposable()
|
private val disposable = CompositeDisposable()
|
||||||
|
|
||||||
private var iobTable = LongSparseArray<IobTotal>() // oldest at index 0
|
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
|
private var basalDataTable = LongSparseArray<BasalData>() // oldest at index 0
|
||||||
|
|
||||||
override var ads: AutosensDataStore = AutosensDataStore()
|
override var ads: AutosensDataStore = AutosensDataStore()
|
||||||
|
@ -169,10 +167,9 @@ open class IobCobCalculatorPlugin @Inject constructor(
|
||||||
return getBGDataFrom
|
return getBGDataFrom
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun calculateFromTreatmentsAndTemps(fromTime: Long, profile: Profile): IobTotal {
|
override fun calculateFromTreatmentsAndTemps(toTime: Long, profile: Profile): IobTotal {
|
||||||
synchronized(dataLock) {
|
|
||||||
val now = System.currentTimeMillis()
|
val now = System.currentTimeMillis()
|
||||||
val time = ads.roundUpTime(fromTime)
|
val time = ads.roundUpTime(toTime)
|
||||||
val cacheHit = iobTable[time]
|
val cacheHit = iobTable[time]
|
||||||
if (time < now && cacheHit != null) {
|
if (time < now && cacheHit != null) {
|
||||||
//og.debug(">>> calculateFromTreatmentsAndTemps Cache hit " + new Date(time).toLocaleString());
|
//og.debug(">>> calculateFromTreatmentsAndTemps Cache hit " + new Date(time).toLocaleString());
|
||||||
|
@ -196,30 +193,12 @@ open class IobCobCalculatorPlugin @Inject constructor(
|
||||||
basalIob.iobWithZeroTemp = IobTotal.combine(bolusIob, basalIobWithZeroTemp).round()
|
basalIob.iobWithZeroTemp = IobTotal.combine(bolusIob, basalIobWithZeroTemp).round()
|
||||||
val iobTotal = IobTotal.combine(bolusIob, basalIob).round()
|
val iobTotal = IobTotal.combine(bolusIob, basalIob).round()
|
||||||
if (time < System.currentTimeMillis()) {
|
if (time < System.currentTimeMillis()) {
|
||||||
|
synchronized(dataLock) {
|
||||||
iobTable.put(time, iobTotal)
|
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 {
|
private fun calculateFromTreatmentsAndTemps(time: Long, lastAutosensResult: AutosensResult, exercise_mode: Boolean, half_basal_exercise_target: Int, isTempTarget: Boolean): IobTotal {
|
||||||
val now = dateUtil.now()
|
val now = dateUtil.now()
|
||||||
|
@ -246,7 +225,6 @@ open class IobCobCalculatorPlugin @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getBasalData(profile: Profile, fromTime: Long): BasalData {
|
override fun getBasalData(profile: Profile, fromTime: Long): BasalData {
|
||||||
synchronized(dataLock) {
|
|
||||||
val now = System.currentTimeMillis()
|
val now = System.currentTimeMillis()
|
||||||
val time = ads.roundUpTime(fromTime)
|
val time = ads.roundUpTime(fromTime)
|
||||||
var retVal = basalDataTable[time]
|
var retVal = basalDataTable[time]
|
||||||
|
@ -263,12 +241,13 @@ open class IobCobCalculatorPlugin @Inject constructor(
|
||||||
retVal.tempBasalAbsolute = retVal.basal
|
retVal.tempBasalAbsolute = retVal.basal
|
||||||
}
|
}
|
||||||
if (time < now) {
|
if (time < now) {
|
||||||
|
synchronized(dataLock) {
|
||||||
basalDataTable.append(time, retVal)
|
basalDataTable.append(time, retVal)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} //else log.debug(">>> getBasalData Cache hit " + new Date(time).toLocaleString());
|
} //else log.debug(">>> getBasalData Cache hit " + new Date(time).toLocaleString());
|
||||||
return retVal
|
return retVal
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
override fun getLastAutosensDataWithWaitForCalculationFinish(reason: String): AutosensData? {
|
override fun getLastAutosensDataWithWaitForCalculationFinish(reason: String): AutosensData? {
|
||||||
if (thread?.isAlive == true) {
|
if (thread?.isAlive == true) {
|
||||||
|
@ -408,14 +387,6 @@ open class IobCobCalculatorPlugin @Inject constructor(
|
||||||
break
|
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) {
|
for (index in basalDataTable.size() - 1 downTo 0) {
|
||||||
if (basalDataTable.keyAt(index) > time) {
|
if (basalDataTable.keyAt(index) > time) {
|
||||||
aapsLogger.debug(LTag.AUTOSENS, "Removing from basalDataTable: " + dateUtil.dateAndTimeAndSecondsString(basalDataTable.keyAt(index)))
|
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
|
* Time range to the past for IOB calculation
|
||||||
* @return milliseconds
|
* @return milliseconds
|
||||||
*/
|
*/
|
||||||
fun range(): Long = ((profileFunction.getProfile()?.dia
|
fun range(): Long = ((/*overviewData.rangeToDisplay + */(profileFunction.getProfile()?.dia
|
||||||
?: Constants.defaultDIA) * 60 * 60 * 1000).toLong()
|
?: Constants.defaultDIA)) * 60 * 60 * 1000).toLong()
|
||||||
|
|
||||||
override fun calculateIobFromBolus(): IobTotal = calculateIobFromBolusToTime(dateUtil.now())
|
override fun calculateIobFromBolus(): IobTotal = calculateIobFromBolusToTime(dateUtil.now())
|
||||||
|
|
||||||
|
@ -533,6 +504,7 @@ open class IobCobCalculatorPlugin @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getTempBasalIncludingConvertedExtended(timestamp: Long): TemporaryBasal? {
|
override fun getTempBasalIncludingConvertedExtended(timestamp: Long): TemporaryBasal? {
|
||||||
|
|
||||||
val tb = repository.getTemporaryBasalActiveAt(timestamp).blockingGet()
|
val tb = repository.getTemporaryBasalActiveAt(timestamp).blockingGet()
|
||||||
if (tb is ValueWrapper.Existing) return tb.value
|
if (tb is ValueWrapper.Existing) return tb.value
|
||||||
val eb = repository.getExtendedBolusActiveAt(timestamp).blockingGet()
|
val eb = repository.getExtendedBolusActiveAt(timestamp).blockingGet()
|
||||||
|
@ -542,7 +514,7 @@ open class IobCobCalculatorPlugin @Inject constructor(
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun calculateAbsoluteIobTempBasals(toTime: Long): IobTotal {
|
override fun calculateAbsoluteIobFromBaseBasals(toTime: Long): IobTotal {
|
||||||
val total = IobTotal(toTime)
|
val total = IobTotal(toTime)
|
||||||
var i = toTime - range()
|
var i = toTime - range()
|
||||||
while (i < toTime) {
|
while (i < toTime) {
|
||||||
|
@ -551,8 +523,7 @@ open class IobCobCalculatorPlugin @Inject constructor(
|
||||||
i += T.mins(5).msecs()
|
i += T.mins(5).msecs()
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
val runningTBR = getTempBasalIncludingConvertedExtended(i)
|
val running = profile.getBasal(i)
|
||||||
val running = runningTBR?.convertedToAbsolute(i, profile) ?: profile.getBasal(i)
|
|
||||||
val bolus = Bolus(
|
val bolus = Bolus(
|
||||||
timestamp = i,
|
timestamp = i,
|
||||||
amount = running * 5.0 / 60.0,
|
amount = running * 5.0 / 60.0,
|
||||||
|
|
|
@ -82,7 +82,7 @@ class IobCobOref1Thread internal constructor(
|
||||||
//log.debug("Locking calculateSensitivityData");
|
//log.debug("Locking calculateSensitivityData");
|
||||||
val oldestTimeWithData = iobCobCalculatorPlugin.calculateDetectionStart(end, limitDataToOldestAvailable)
|
val oldestTimeWithData = iobCobCalculatorPlugin.calculateDetectionStart(end, limitDataToOldestAvailable)
|
||||||
if (bgDataReload) {
|
if (bgDataReload) {
|
||||||
iobCobCalculatorPlugin.ads.loadBgData(end, repository, aapsLogger, dateUtil)
|
iobCobCalculatorPlugin.ads.loadBgData(end, repository, aapsLogger, dateUtil, rxBus)
|
||||||
iobCobCalculatorPlugin.clearCache()
|
iobCobCalculatorPlugin.clearCache()
|
||||||
}
|
}
|
||||||
// work on local copy and set back when finished
|
// 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
|
// start from oldest to be able sub cob
|
||||||
for (i in bucketedData.size - 4 downTo 0) {
|
for (i in bucketedData.size - 4 downTo 0) {
|
||||||
val progress = i.toString() + if (buildHelper.isDev()) " ($from)" else ""
|
val progress = i.toString() + if (buildHelper.isDev()) " ($from)" else ""
|
||||||
rxBus.send(EventIobCalculationProgress(progress))
|
rxBus.send(EventIobCalculationProgress(progress, cause))
|
||||||
if (iobCobCalculatorPlugin.stopCalculationTrigger) {
|
if (iobCobCalculatorPlugin.stopCalculationTrigger) {
|
||||||
iobCobCalculatorPlugin.stopCalculationTrigger = false
|
iobCobCalculatorPlugin.stopCalculationTrigger = false
|
||||||
aapsLogger.debug(LTag.AUTOSENS, "Aborting calculation thread (trigger): $from")
|
aapsLogger.debug(LTag.AUTOSENS, "Aborting calculation thread (trigger): $from")
|
||||||
|
@ -325,7 +325,7 @@ class IobCobOref1Thread internal constructor(
|
||||||
}.start()
|
}.start()
|
||||||
} finally {
|
} finally {
|
||||||
mWakeLock?.release()
|
mWakeLock?.release()
|
||||||
rxBus.send(EventIobCalculationProgress(""))
|
rxBus.send(EventIobCalculationProgress("", cause))
|
||||||
aapsLogger.debug(LTag.AUTOSENS, "AUTOSENSDATA thread ended: $from")
|
aapsLogger.debug(LTag.AUTOSENS, "AUTOSENSDATA thread ended: $from")
|
||||||
profiler.log(LTag.AUTOSENS, "IobCobOref1Thread", start)
|
profiler.log(LTag.AUTOSENS, "IobCobOref1Thread", start)
|
||||||
}
|
}
|
||||||
|
|
|
@ -81,7 +81,7 @@ class IobCobThread @Inject internal constructor(
|
||||||
//log.debug("Locking calculateSensitivityData");
|
//log.debug("Locking calculateSensitivityData");
|
||||||
val oldestTimeWithData = iobCobCalculatorPlugin.calculateDetectionStart(end, limitDataToOldestAvailable)
|
val oldestTimeWithData = iobCobCalculatorPlugin.calculateDetectionStart(end, limitDataToOldestAvailable)
|
||||||
if (bgDataReload) {
|
if (bgDataReload) {
|
||||||
iobCobCalculatorPlugin.ads.loadBgData(end, repository, aapsLogger, dateUtil)
|
iobCobCalculatorPlugin.ads.loadBgData(end, repository, aapsLogger, dateUtil, rxBus)
|
||||||
iobCobCalculatorPlugin.clearCache()
|
iobCobCalculatorPlugin.clearCache()
|
||||||
}
|
}
|
||||||
// work on local copy and set back when finished
|
// 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
|
// start from oldest to be able sub cob
|
||||||
for (i in bucketedData.size - 4 downTo 0) {
|
for (i in bucketedData.size - 4 downTo 0) {
|
||||||
val progress = i.toString() + if (buildHelper.isDev()) " ($from)" else ""
|
val progress = i.toString() + if (buildHelper.isDev()) " ($from)" else ""
|
||||||
rxBus.send(EventIobCalculationProgress(progress))
|
rxBus.send(EventIobCalculationProgress(progress, cause))
|
||||||
if (iobCobCalculatorPlugin.stopCalculationTrigger) {
|
if (iobCobCalculatorPlugin.stopCalculationTrigger) {
|
||||||
iobCobCalculatorPlugin.stopCalculationTrigger = false
|
iobCobCalculatorPlugin.stopCalculationTrigger = false
|
||||||
aapsLogger.debug(LTag.AUTOSENS, "Aborting calculation thread (trigger): $from")
|
aapsLogger.debug(LTag.AUTOSENS, "Aborting calculation thread (trigger): $from")
|
||||||
|
@ -272,7 +272,7 @@ class IobCobThread @Inject internal constructor(
|
||||||
}.start()
|
}.start()
|
||||||
} finally {
|
} finally {
|
||||||
mWakeLock?.release()
|
mWakeLock?.release()
|
||||||
rxBus.send(EventIobCalculationProgress(""))
|
rxBus.send(EventIobCalculationProgress("", cause))
|
||||||
aapsLogger.debug(LTag.AUTOSENS, "AUTOSENSDATA thread ended: $from")
|
aapsLogger.debug(LTag.AUTOSENS, "AUTOSENSDATA thread ended: $from")
|
||||||
profiler.log(LTag.AUTOSENS, "IobCobThread", start)
|
profiler.log(LTag.AUTOSENS, "IobCobThread", start)
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,4 +2,4 @@ package info.nightscout.androidaps.plugins.iob.iobCobCalculator.events
|
||||||
|
|
||||||
import info.nightscout.androidaps.events.Event
|
import info.nightscout.androidaps.events.Event
|
||||||
|
|
||||||
class EventIobCalculationProgress(var progress: String) : Event()
|
class EventIobCalculationProgress(val progress: String, val cause: Event?) : Event()
|
|
@ -54,6 +54,9 @@ class LocalProfileFragment : DaggerFragment() {
|
||||||
private val save = Runnable {
|
private val save = Runnable {
|
||||||
doEdit()
|
doEdit()
|
||||||
basalView?.updateLabel(resourceHelper.gs(R.string.basal_label) + ": " + sumLabel())
|
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 {
|
private val textWatch = object : TextWatcher {
|
||||||
|
@ -67,7 +70,7 @@ class LocalProfileFragment : DaggerFragment() {
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun sumLabel(): String {
|
private fun sumLabel(): String {
|
||||||
val profile = localProfilePlugin.createProfileStore().getDefaultProfile()
|
val profile = localProfilePlugin.profile?.getDefaultProfile()
|
||||||
val sum = profile?.let { ProfileSealed.Pure(profile).baseBasalSum() } ?: 0.0
|
val sum = profile?.let { ProfileSealed.Pure(profile).baseBasalSum() } ?: 0.0
|
||||||
return " ∑" + DecimalFormatter.to2Decimal(sum) + resourceHelper.gs(R.string.insulin_unit_shortname)
|
return " ∑" + DecimalFormatter.to2Decimal(sum) + resourceHelper.gs(R.string.insulin_unit_shortname)
|
||||||
}
|
}
|
||||||
|
@ -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.setParams(currentProfile.dia, hardLimits.minDia(), hardLimits.maxDia(), 0.1, DecimalFormat("0.0"), false, binding.save, textWatch)
|
||||||
binding.dia.tag = "LP_DIA"
|
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)
|
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) {
|
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.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)
|
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 {
|
binding.profileAdd.setOnClickListener {
|
||||||
if (localProfilePlugin.isEdited) {
|
if (localProfilePlugin.isEdited) {
|
||||||
|
|
|
@ -1,6 +1,10 @@
|
||||||
package info.nightscout.androidaps.plugins.profile.local
|
package info.nightscout.androidaps.plugins.profile.local
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
import androidx.fragment.app.FragmentActivity
|
import androidx.fragment.app.FragmentActivity
|
||||||
|
import androidx.work.Worker
|
||||||
|
import androidx.work.WorkerParameters
|
||||||
|
import androidx.work.workDataOf
|
||||||
import dagger.android.HasAndroidInjector
|
import dagger.android.HasAndroidInjector
|
||||||
import info.nightscout.androidaps.Constants
|
import info.nightscout.androidaps.Constants
|
||||||
import info.nightscout.androidaps.R
|
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.AAPSLogger
|
||||||
import info.nightscout.androidaps.logging.LTag
|
import info.nightscout.androidaps.logging.LTag
|
||||||
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
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.DateUtil
|
||||||
import info.nightscout.androidaps.utils.DecimalFormatter
|
import info.nightscout.androidaps.utils.DecimalFormatter
|
||||||
import info.nightscout.androidaps.utils.HardLimits
|
import info.nightscout.androidaps.utils.HardLimits
|
||||||
|
@ -22,6 +27,7 @@ import info.nightscout.androidaps.utils.sharedPreferences.SP
|
||||||
import org.json.JSONArray
|
import org.json.JSONArray
|
||||||
import org.json.JSONException
|
import org.json.JSONException
|
||||||
import org.json.JSONObject
|
import org.json.JSONObject
|
||||||
|
import java.lang.Integer.min
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
|
@ -35,7 +41,6 @@ class LocalProfilePlugin @Inject constructor(
|
||||||
resourceHelper: ResourceHelper,
|
resourceHelper: ResourceHelper,
|
||||||
private val sp: SP,
|
private val sp: SP,
|
||||||
private val profileFunction: ProfileFunction,
|
private val profileFunction: ProfileFunction,
|
||||||
private val nsUpload: NSUpload,
|
|
||||||
private val activePlugin: ActivePlugin,
|
private val activePlugin: ActivePlugin,
|
||||||
private val hardLimits: HardLimits,
|
private val hardLimits: HardLimits,
|
||||||
private val dateUtil: DateUtil
|
private val dateUtil: DateUtil
|
||||||
|
@ -134,6 +139,7 @@ class LocalProfilePlugin @Inject constructor(
|
||||||
}
|
}
|
||||||
sp.putInt(Constants.LOCAL_PROFILE + "_profiles", numOfProfiles)
|
sp.putInt(Constants.LOCAL_PROFILE + "_profiles", numOfProfiles)
|
||||||
|
|
||||||
|
sp.putLong(R.string.key_local_profile_last_change, dateUtil.now())
|
||||||
createAndStoreConvertedProfile()
|
createAndStoreConvertedProfile()
|
||||||
isEdited = false
|
isEdited = false
|
||||||
aapsLogger.debug(LTag.PROFILE, "Storing settings: " + rawProfile?.data.toString())
|
aapsLogger.debug(LTag.PROFILE, "Storing settings: " + rawProfile?.data.toString())
|
||||||
|
@ -143,10 +149,7 @@ class LocalProfilePlugin @Inject constructor(
|
||||||
val name = it.name ?: "."
|
val name = it.name ?: "."
|
||||||
if (name.contains(".")) namesOK = false
|
if (name.contains(".")) namesOK = false
|
||||||
}
|
}
|
||||||
if (namesOK)
|
if (!namesOK) activity?.let {
|
||||||
rawProfile?.let { nsUpload.uploadProfileStore(it.data) }
|
|
||||||
else
|
|
||||||
activity?.let {
|
|
||||||
OKDialog.show(it, "", resourceHelper.gs(R.string.profilenamecontainsdot))
|
OKDialog.show(it, "", resourceHelper.gs(R.string.profilenamecontainsdot))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -167,61 +170,64 @@ class LocalProfilePlugin @Inject constructor(
|
||||||
p.dia = sp.getDouble(localProfileNumbered + "dia", Constants.defaultDIA)
|
p.dia = sp.getDouble(localProfileNumbered + "dia", Constants.defaultDIA)
|
||||||
try {
|
try {
|
||||||
p.ic = JSONArray(sp.getString(localProfileNumbered + "ic", defaultArray))
|
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))
|
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))
|
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))
|
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))
|
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)
|
profiles.add(p)
|
||||||
|
} catch (e: JSONException) {
|
||||||
|
aapsLogger.error("Exception", e)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
// create at least one profile if doesn't exist
|
||||||
|
if (profiles.size < 1) profiles.add(defaultProfile())
|
||||||
isEdited = false
|
isEdited = false
|
||||||
numOfProfiles = profiles.size
|
numOfProfiles = profiles.size
|
||||||
createAndStoreConvertedProfile()
|
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 {
|
fun copyFrom(pureProfile: PureProfile, newName: String): SingleProfile {
|
||||||
var verifiedName = newName
|
var verifiedName = newName
|
||||||
if (rawProfile?.getSpecificProfile(newName) != null) {
|
if (rawProfile?.getSpecificProfile(newName) != null) {
|
||||||
|
@ -364,7 +370,8 @@ class LocalProfilePlugin @Inject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (numOfProfiles > 0) json.put("defaultProfile", currentProfile()?.name)
|
if (numOfProfiles > 0) json.put("defaultProfile", currentProfile()?.name)
|
||||||
json.put("startDate", dateUtil.toISOAsUTC(dateUtil.now()))
|
val startDate = sp.getLong(R.string.key_local_profile_last_change, dateUtil.now())
|
||||||
|
json.put("startDate", dateUtil.toISOAsUTC(startDate))
|
||||||
json.put("store", store)
|
json.put("store", store)
|
||||||
} catch (e: JSONException) {
|
} catch (e: JSONException) {
|
||||||
aapsLogger.error("Unhandled exception", e)
|
aapsLogger.error("Unhandled exception", e)
|
||||||
|
@ -380,4 +387,44 @@ class LocalProfilePlugin @Inject constructor(
|
||||||
get() = rawProfile?.getDefaultProfile()?.let {
|
get() = rawProfile?.getDefaultProfile()?.let {
|
||||||
DecimalFormatter.to2Decimal(ProfileSealed.Pure(it).percentageBasalSum()) + "U "
|
DecimalFormatter.to2Decimal(ProfileSealed.Pure(it).percentageBasalSum()) + "U "
|
||||||
} ?: "INVALID"
|
} ?: "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 dagger.android.HasAndroidInjector
|
||||||
import info.nightscout.androidaps.R
|
import info.nightscout.androidaps.R
|
||||||
import info.nightscout.androidaps.data.DetailedBolusInfo
|
import info.nightscout.androidaps.data.DetailedBolusInfo
|
||||||
import info.nightscout.androidaps.interfaces.Profile
|
|
||||||
import info.nightscout.androidaps.data.PumpEnactResult
|
import info.nightscout.androidaps.data.PumpEnactResult
|
||||||
import info.nightscout.androidaps.interfaces.*
|
import info.nightscout.androidaps.interfaces.*
|
||||||
import info.nightscout.androidaps.logging.AAPSLogger
|
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.plugins.pump.common.defs.PumpType
|
||||||
import info.nightscout.androidaps.utils.DateUtil
|
import info.nightscout.androidaps.utils.DateUtil
|
||||||
import info.nightscout.androidaps.utils.InstanceId.instanceId
|
import info.nightscout.androidaps.utils.InstanceId.instanceId
|
||||||
import info.nightscout.androidaps.utils.T
|
|
||||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||||
import org.json.JSONException
|
import org.json.JSONException
|
||||||
import org.json.JSONObject
|
import org.json.JSONObject
|
||||||
|
@ -61,7 +59,7 @@ class MDIPlugin @Inject constructor(
|
||||||
override fun waitForDisconnectionInSeconds(): Int = 0
|
override fun waitForDisconnectionInSeconds(): Int = 0
|
||||||
override fun stopConnecting() {}
|
override fun stopConnecting() {}
|
||||||
override fun getPumpStatus(reason: String) {}
|
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 isThisProfileSet(profile: Profile): Boolean = false
|
||||||
override fun lastDataTime(): Long = System.currentTimeMillis()
|
override fun lastDataTime(): Long = System.currentTimeMillis()
|
||||||
override val baseBasalRate: Double = 0.0
|
override val baseBasalRate: Double = 0.0
|
||||||
|
@ -84,7 +82,7 @@ class MDIPlugin @Inject constructor(
|
||||||
pumpSerial = serialNumber())
|
pumpSerial = serialNumber())
|
||||||
if (detailedBolusInfo.carbs > 0)
|
if (detailedBolusInfo.carbs > 0)
|
||||||
pumpSync.syncCarbsWithTimestamp(
|
pumpSync.syncCarbsWithTimestamp(
|
||||||
timestamp = detailedBolusInfo.timestamp + T.mins(detailedBolusInfo.carbTime.toLong()).msecs(),
|
timestamp = detailedBolusInfo.carbsTimestamp ?: detailedBolusInfo.timestamp,
|
||||||
amount = detailedBolusInfo.carbs,
|
amount = detailedBolusInfo.carbs,
|
||||||
pumpId = null,
|
pumpId = null,
|
||||||
pumpType = PumpType.MDI,
|
pumpType = PumpType.MDI,
|
||||||
|
|
|
@ -4,12 +4,12 @@ import android.os.SystemClock
|
||||||
import androidx.preference.PreferenceFragmentCompat
|
import androidx.preference.PreferenceFragmentCompat
|
||||||
import androidx.preference.SwitchPreference
|
import androidx.preference.SwitchPreference
|
||||||
import dagger.android.HasAndroidInjector
|
import dagger.android.HasAndroidInjector
|
||||||
import info.nightscout.androidaps.interfaces.Config
|
|
||||||
import info.nightscout.androidaps.R
|
import info.nightscout.androidaps.R
|
||||||
import info.nightscout.androidaps.data.DetailedBolusInfo
|
import info.nightscout.androidaps.data.DetailedBolusInfo
|
||||||
import info.nightscout.androidaps.interfaces.Profile
|
|
||||||
import info.nightscout.androidaps.data.PumpEnactResult
|
import info.nightscout.androidaps.data.PumpEnactResult
|
||||||
import info.nightscout.androidaps.events.EventPreferenceChange
|
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.interfaces.*
|
||||||
import info.nightscout.androidaps.logging.AAPSLogger
|
import info.nightscout.androidaps.logging.AAPSLogger
|
||||||
import info.nightscout.androidaps.logging.LTag
|
import info.nightscout.androidaps.logging.LTag
|
||||||
|
@ -25,8 +25,6 @@ import info.nightscout.androidaps.utils.FabricPrivacy
|
||||||
import info.nightscout.androidaps.utils.InstanceId.instanceId
|
import info.nightscout.androidaps.utils.InstanceId.instanceId
|
||||||
import info.nightscout.androidaps.utils.T
|
import info.nightscout.androidaps.utils.T
|
||||||
import info.nightscout.androidaps.utils.TimeChangeType
|
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.resources.ResourceHelper
|
||||||
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
||||||
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
||||||
|
@ -139,7 +137,6 @@ open class VirtualPumpPlugin @Inject constructor(
|
||||||
override fun isHandshakeInProgress(): Boolean = false
|
override fun isHandshakeInProgress(): Boolean = false
|
||||||
|
|
||||||
override fun connect(reason: String) {
|
override fun connect(reason: String) {
|
||||||
//if (!Config.NSCLIENT) NSUpload.uploadDeviceStatus()
|
|
||||||
lastDataTime = System.currentTimeMillis()
|
lastDataTime = System.currentTimeMillis()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -152,16 +149,14 @@ open class VirtualPumpPlugin @Inject constructor(
|
||||||
|
|
||||||
override fun setNewBasalProfile(profile: Profile): PumpEnactResult {
|
override fun setNewBasalProfile(profile: Profile): PumpEnactResult {
|
||||||
lastDataTime = System.currentTimeMillis()
|
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
|
// Do nothing here. we are using database profile
|
||||||
val result = PumpEnactResult(injector)
|
return PumpEnactResult(injector).success(true).enacted(true)
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun isThisProfileSet(profile: Profile): Boolean {
|
override fun isThisProfileSet(profile: Profile): Boolean {
|
||||||
return true
|
val running = pumpSync.expectedPumpState().profile
|
||||||
|
return running?.isEqual(profile) ?: false
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun lastDataTime(): Long {
|
override fun lastDataTime(): Long {
|
||||||
|
@ -211,7 +206,7 @@ open class VirtualPumpPlugin @Inject constructor(
|
||||||
pumpSerial = serialNumber())
|
pumpSerial = serialNumber())
|
||||||
if (detailedBolusInfo.carbs > 0)
|
if (detailedBolusInfo.carbs > 0)
|
||||||
pumpSync.syncCarbsWithTimestamp(
|
pumpSync.syncCarbsWithTimestamp(
|
||||||
timestamp = detailedBolusInfo.timestamp + T.mins(detailedBolusInfo.carbTime.toLong()).msecs(),
|
timestamp = detailedBolusInfo.carbsTimestamp ?: detailedBolusInfo.timestamp,
|
||||||
amount = detailedBolusInfo.carbs,
|
amount = detailedBolusInfo.carbs,
|
||||||
pumpId = null,
|
pumpId = null,
|
||||||
pumpType = pumpType ?: PumpType.GENERIC_AAPS,
|
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")
|
aapsLogger.debug(LTag.PUMP, "Pump in configuration: $pumpType, PumpType object: $pumpTypeNew")
|
||||||
if (this.pumpType == pumpTypeNew) return
|
if (this.pumpType == pumpTypeNew) return
|
||||||
aapsLogger.debug(LTag.PUMP, "New pump configuration found ($pumpTypeNew), changing from previous (${this.pumpType})")
|
aapsLogger.debug(LTag.PUMP, "New pump configuration found ($pumpTypeNew), changing from previous (${this.pumpType})")
|
||||||
pumpDescription.setPumpDescription(pumpTypeNew)
|
pumpDescription.fillFor(pumpTypeNew)
|
||||||
this.pumpType = pumpTypeNew
|
this.pumpType = pumpTypeNew
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,6 @@ import androidx.work.Worker
|
||||||
import androidx.work.WorkerParameters
|
import androidx.work.WorkerParameters
|
||||||
import androidx.work.workDataOf
|
import androidx.work.workDataOf
|
||||||
import dagger.android.HasAndroidInjector
|
import dagger.android.HasAndroidInjector
|
||||||
import info.nightscout.androidaps.interfaces.Config
|
|
||||||
import info.nightscout.androidaps.R
|
import info.nightscout.androidaps.R
|
||||||
import info.nightscout.androidaps.activities.RequestDexcomPermissionActivity
|
import info.nightscout.androidaps.activities.RequestDexcomPermissionActivity
|
||||||
import info.nightscout.androidaps.database.AppRepository
|
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.UserEntry.Sources
|
||||||
import info.nightscout.androidaps.database.entities.ValueWithUnit
|
import info.nightscout.androidaps.database.entities.ValueWithUnit
|
||||||
import info.nightscout.androidaps.database.transactions.CgmSourceTransaction
|
import info.nightscout.androidaps.database.transactions.CgmSourceTransaction
|
||||||
import info.nightscout.androidaps.interfaces.BgSource
|
import info.nightscout.androidaps.extensions.fromConstant
|
||||||
import info.nightscout.androidaps.interfaces.PluginBase
|
import info.nightscout.androidaps.interfaces.*
|
||||||
import info.nightscout.androidaps.interfaces.PluginDescription
|
|
||||||
import info.nightscout.androidaps.interfaces.PluginType
|
|
||||||
import info.nightscout.androidaps.logging.AAPSLogger
|
import info.nightscout.androidaps.logging.AAPSLogger
|
||||||
import info.nightscout.androidaps.logging.LTag
|
import info.nightscout.androidaps.logging.LTag
|
||||||
import info.nightscout.androidaps.logging.UserEntryLogger
|
import info.nightscout.androidaps.logging.UserEntryLogger
|
||||||
|
@ -97,7 +94,7 @@ class DexcomPlugin @Inject constructor(
|
||||||
override fun doWork(): Result {
|
override fun doWork(): Result {
|
||||||
var ret = Result.success()
|
var ret = Result.success()
|
||||||
|
|
||||||
if (!dexcomPlugin.isEnabled(PluginType.BGSOURCE)) return Result.success()
|
if (!dexcomPlugin.isEnabled(PluginType.BGSOURCE)) return Result.success(workDataOf("Result" to "Plugin not enabled"))
|
||||||
val bundle = dataWorker.pickupBundle(inputData.getLong(DataWorker.STORE_KEY, -1))
|
val bundle = dataWorker.pickupBundle(inputData.getLong(DataWorker.STORE_KEY, -1))
|
||||||
?: return Result.failure(workDataOf("Error" to "missing input data"))
|
?: return Result.failure(workDataOf("Error" to "missing input data"))
|
||||||
try {
|
try {
|
||||||
|
@ -126,11 +123,12 @@ class DexcomPlugin @Inject constructor(
|
||||||
meters.getBundle(i.toString())?.let {
|
meters.getBundle(i.toString())?.let {
|
||||||
val timestamp = it.getLong("timestamp") * 1000
|
val timestamp = it.getLong("timestamp") * 1000
|
||||||
val now = dateUtil.now()
|
val now = dateUtil.now()
|
||||||
|
val value = it.getInt("meterValue").toDouble()
|
||||||
if (timestamp > now - T.months(1).msecs() && timestamp < now) {
|
if (timestamp > now - T.months(1).msecs() && timestamp < now) {
|
||||||
calibrations.add(CgmSourceTransaction.Calibration(
|
calibrations.add(CgmSourceTransaction.Calibration(
|
||||||
timestamp = it.getLong("timestamp") * 1000,
|
timestamp = it.getLong("timestamp") * 1000,
|
||||||
value = it.getInt("meterValue").toDouble(),
|
value = value,
|
||||||
glucoseUnit = TherapyEvent.GlucoseUnit.MGDL
|
glucoseUnit = TherapyEvent.GlucoseUnit.fromConstant(Profile.unit(value))
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -158,14 +156,14 @@ class DexcomPlugin @Inject constructor(
|
||||||
}
|
}
|
||||||
result.sensorInsertionsInserted.forEach {
|
result.sensorInsertionsInserted.forEach {
|
||||||
uel.log(Action.CAREPORTAL,
|
uel.log(Action.CAREPORTAL,
|
||||||
Sources.BG,
|
Sources.Dexcom,
|
||||||
ValueWithUnit.Timestamp(it.timestamp),
|
ValueWithUnit.Timestamp(it.timestamp),
|
||||||
ValueWithUnit.TherapyEventType(it.type))
|
ValueWithUnit.TherapyEventType(it.type))
|
||||||
aapsLogger.debug(LTag.DATABASE, "Inserted sensor insertion $it")
|
aapsLogger.debug(LTag.DATABASE, "Inserted sensor insertion $it")
|
||||||
}
|
}
|
||||||
result.calibrationsInserted.forEach {
|
result.calibrationsInserted.forEach {
|
||||||
uel.log(Action.CAREPORTAL,
|
uel.log(Action.CAREPORTAL,
|
||||||
Sources.BG,
|
Sources.Dexcom,
|
||||||
ValueWithUnit.Timestamp(it.timestamp),
|
ValueWithUnit.Timestamp(it.timestamp),
|
||||||
ValueWithUnit.TherapyEventType(it.type))
|
ValueWithUnit.TherapyEventType(it.type))
|
||||||
aapsLogger.debug(LTag.DATABASE, "Inserted calibration $it")
|
aapsLogger.debug(LTag.DATABASE, "Inserted calibration $it")
|
||||||
|
|
|
@ -69,7 +69,7 @@ class EversensePlugin @Inject constructor(
|
||||||
override fun doWork(): Result {
|
override fun doWork(): Result {
|
||||||
var ret = Result.success()
|
var ret = Result.success()
|
||||||
|
|
||||||
if (!eversensePlugin.isEnabled(PluginType.BGSOURCE)) return Result.success()
|
if (!eversensePlugin.isEnabled(PluginType.BGSOURCE)) return Result.success(workDataOf("Result" to "Plugin not enabled"))
|
||||||
val bundle = dataWorker.pickupBundle(inputData.getLong(DataWorker.STORE_KEY, -1))
|
val bundle = dataWorker.pickupBundle(inputData.getLong(DataWorker.STORE_KEY, -1))
|
||||||
?: return Result.failure(workDataOf("Error" to "missing input data"))
|
?: return Result.failure(workDataOf("Error" to "missing input data"))
|
||||||
if (bundle.containsKey("currentCalibrationPhase")) aapsLogger.debug(LTag.BGSOURCE, "currentCalibrationPhase: " + bundle.getString("currentCalibrationPhase"))
|
if (bundle.containsKey("currentCalibrationPhase")) aapsLogger.debug(LTag.BGSOURCE, "currentCalibrationPhase: " + bundle.getString("currentCalibrationPhase"))
|
||||||
|
|
|
@ -56,7 +56,7 @@ class GlimpPlugin @Inject constructor(
|
||||||
override fun doWork(): Result {
|
override fun doWork(): Result {
|
||||||
var ret = Result.success()
|
var ret = Result.success()
|
||||||
|
|
||||||
if (!glimpPlugin.isEnabled(PluginType.BGSOURCE)) return Result.success()
|
if (!glimpPlugin.isEnabled(PluginType.BGSOURCE)) return Result.success(workDataOf("Result" to "Plugin not enabled"))
|
||||||
aapsLogger.debug(LTag.BGSOURCE, "Received Glimp Data: $inputData}")
|
aapsLogger.debug(LTag.BGSOURCE, "Received Glimp Data: $inputData}")
|
||||||
val glucoseValues = mutableListOf<CgmSourceTransaction.TransactionGlucoseValue>()
|
val glucoseValues = mutableListOf<CgmSourceTransaction.TransactionGlucoseValue>()
|
||||||
glucoseValues += CgmSourceTransaction.TransactionGlucoseValue(
|
glucoseValues += CgmSourceTransaction.TransactionGlucoseValue(
|
||||||
|
|
|
@ -5,12 +5,12 @@ import androidx.work.Worker
|
||||||
import androidx.work.WorkerParameters
|
import androidx.work.WorkerParameters
|
||||||
import androidx.work.workDataOf
|
import androidx.work.workDataOf
|
||||||
import dagger.android.HasAndroidInjector
|
import dagger.android.HasAndroidInjector
|
||||||
import info.nightscout.androidaps.interfaces.Config
|
|
||||||
import info.nightscout.androidaps.R
|
import info.nightscout.androidaps.R
|
||||||
import info.nightscout.androidaps.database.AppRepository
|
import info.nightscout.androidaps.database.AppRepository
|
||||||
import info.nightscout.androidaps.database.entities.GlucoseValue
|
import info.nightscout.androidaps.database.entities.GlucoseValue
|
||||||
import info.nightscout.androidaps.database.transactions.CgmSourceTransaction
|
import info.nightscout.androidaps.database.transactions.CgmSourceTransaction
|
||||||
import info.nightscout.androidaps.interfaces.BgSource
|
import info.nightscout.androidaps.interfaces.BgSource
|
||||||
|
import info.nightscout.androidaps.interfaces.Config
|
||||||
import info.nightscout.androidaps.interfaces.PluginBase
|
import info.nightscout.androidaps.interfaces.PluginBase
|
||||||
import info.nightscout.androidaps.interfaces.PluginDescription
|
import info.nightscout.androidaps.interfaces.PluginDescription
|
||||||
import info.nightscout.androidaps.interfaces.PluginType
|
import info.nightscout.androidaps.interfaces.PluginType
|
||||||
|
@ -115,7 +115,7 @@ class NSClientSourcePlugin @Inject constructor(
|
||||||
override fun doWork(): Result {
|
override fun doWork(): Result {
|
||||||
var ret = Result.success()
|
var ret = Result.success()
|
||||||
|
|
||||||
if (!nsClientSourcePlugin.isEnabled() && !sp.getBoolean(R.string.key_ns_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))
|
val sgvs = dataWorker.pickupJSONArray(inputData.getLong(DataWorker.STORE_KEY, -1))
|
||||||
?: return Result.failure(workDataOf("Error" to "missing input data"))
|
?: return Result.failure(workDataOf("Error" to "missing input data"))
|
||||||
|
|
|
@ -60,7 +60,7 @@ class PoctechPlugin @Inject constructor(
|
||||||
override fun doWork(): Result {
|
override fun doWork(): Result {
|
||||||
var ret = Result.success()
|
var ret = Result.success()
|
||||||
|
|
||||||
if (!poctechPlugin.isEnabled(PluginType.BGSOURCE)) return Result.success()
|
if (!poctechPlugin.isEnabled(PluginType.BGSOURCE)) return Result.success(workDataOf("Result" to "Plugin not enabled"))
|
||||||
aapsLogger.debug(LTag.BGSOURCE, "Received Poctech Data $inputData")
|
aapsLogger.debug(LTag.BGSOURCE, "Received Poctech Data $inputData")
|
||||||
try {
|
try {
|
||||||
val glucoseValues = mutableListOf<CgmSourceTransaction.TransactionGlucoseValue>()
|
val glucoseValues = mutableListOf<CgmSourceTransaction.TransactionGlucoseValue>()
|
||||||
|
|
|
@ -59,7 +59,7 @@ class TomatoPlugin @Inject constructor(
|
||||||
override fun doWork(): Result {
|
override fun doWork(): Result {
|
||||||
var ret = Result.success()
|
var ret = Result.success()
|
||||||
|
|
||||||
if (!tomatoPlugin.isEnabled(PluginType.BGSOURCE)) return Result.success()
|
if (!tomatoPlugin.isEnabled(PluginType.BGSOURCE)) return Result.success(workDataOf("Result" to "Plugin not enabled"))
|
||||||
val glucoseValues = mutableListOf<CgmSourceTransaction.TransactionGlucoseValue>()
|
val glucoseValues = mutableListOf<CgmSourceTransaction.TransactionGlucoseValue>()
|
||||||
glucoseValues += CgmSourceTransaction.TransactionGlucoseValue(
|
glucoseValues += CgmSourceTransaction.TransactionGlucoseValue(
|
||||||
timestamp = inputData.getLong("com.fanqies.tomatofn.Extras.Time", 0),
|
timestamp = inputData.getLong("com.fanqies.tomatofn.Extras.Time", 0),
|
||||||
|
|
|
@ -73,7 +73,7 @@ class XdripPlugin @Inject constructor(
|
||||||
override fun doWork(): Result {
|
override fun doWork(): Result {
|
||||||
var ret = Result.success()
|
var ret = Result.success()
|
||||||
|
|
||||||
if (!xdripPlugin.isEnabled(PluginType.BGSOURCE)) return Result.success()
|
if (!xdripPlugin.isEnabled(PluginType.BGSOURCE)) return Result.success(workDataOf("Result" to "Plugin not enabled"))
|
||||||
val bundle = dataWorker.pickupBundle(inputData.getLong(DataWorker.STORE_KEY, -1))
|
val bundle = dataWorker.pickupBundle(inputData.getLong(DataWorker.STORE_KEY, -1))
|
||||||
?: return Result.failure(workDataOf("Error" to "missing input data"))
|
?: return Result.failure(workDataOf("Error" to "missing input data"))
|
||||||
|
|
||||||
|
|
|
@ -105,25 +105,10 @@ public class TreatmentService extends OrmLiteBaseService<DatabaseHelper> impleme
|
||||||
return wrapped.queryForAll();
|
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 {
|
public Treatment queryForId(long id) throws SQLException {
|
||||||
return wrapped.queryForId(id);
|
return wrapped.queryForId(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void update(Treatment data) throws SQLException {
|
|
||||||
wrapped.update(data);
|
|
||||||
openHumansUploader.enqueueTreatment(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
public QueryBuilder<Treatment, Long> queryBuilder() {
|
public QueryBuilder<Treatment, Long> queryBuilder() {
|
||||||
return wrapped.queryBuilder();
|
return wrapped.queryBuilder();
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,6 @@ import info.nightscout.androidaps.interfaces.TreatmentServiceInterface;
|
||||||
import info.nightscout.androidaps.interfaces.TreatmentsInterface;
|
import info.nightscout.androidaps.interfaces.TreatmentsInterface;
|
||||||
import info.nightscout.androidaps.logging.AAPSLogger;
|
import info.nightscout.androidaps.logging.AAPSLogger;
|
||||||
import info.nightscout.androidaps.plugins.bus.RxBusWrapper;
|
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.DateUtil;
|
||||||
import info.nightscout.androidaps.utils.FabricPrivacy;
|
import info.nightscout.androidaps.utils.FabricPrivacy;
|
||||||
import info.nightscout.androidaps.utils.resources.ResourceHelper;
|
import info.nightscout.androidaps.utils.resources.ResourceHelper;
|
||||||
|
@ -37,12 +36,10 @@ import io.reactivex.disposables.CompositeDisposable;
|
||||||
@Singleton
|
@Singleton
|
||||||
public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface {
|
public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface {
|
||||||
|
|
||||||
private final AapsSchedulers aapsSchedulers;
|
|
||||||
private final SP sp;
|
private final SP sp;
|
||||||
private final RxBusWrapper rxBus;
|
private final RxBusWrapper rxBus;
|
||||||
private final ProfileFunction profileFunction;
|
private final ProfileFunction profileFunction;
|
||||||
private final ActivePlugin activePlugin;
|
private final ActivePlugin activePlugin;
|
||||||
private final NSUpload nsUpload;
|
|
||||||
private final FabricPrivacy fabricPrivacy;
|
private final FabricPrivacy fabricPrivacy;
|
||||||
private final DateUtil dateUtil;
|
private final DateUtil dateUtil;
|
||||||
private final DatabaseHelperInterface databaseHelper;
|
private final DatabaseHelperInterface databaseHelper;
|
||||||
|
@ -63,7 +60,6 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface
|
||||||
SP sp,
|
SP sp,
|
||||||
ProfileFunction profileFunction,
|
ProfileFunction profileFunction,
|
||||||
ActivePlugin activePlugin,
|
ActivePlugin activePlugin,
|
||||||
NSUpload nsUpload,
|
|
||||||
FabricPrivacy fabricPrivacy,
|
FabricPrivacy fabricPrivacy,
|
||||||
DateUtil dateUtil,
|
DateUtil dateUtil,
|
||||||
DatabaseHelperInterface databaseHelper,
|
DatabaseHelperInterface databaseHelper,
|
||||||
|
@ -71,7 +67,6 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface
|
||||||
) {
|
) {
|
||||||
super(new PluginDescription()
|
super(new PluginDescription()
|
||||||
.mainType(PluginType.TREATMENT)
|
.mainType(PluginType.TREATMENT)
|
||||||
.fragmentClass(TreatmentsFragment.class.getName())
|
|
||||||
.pluginIcon(R.drawable.ic_treatments)
|
.pluginIcon(R.drawable.ic_treatments)
|
||||||
.pluginName(R.string.treatments)
|
.pluginName(R.string.treatments)
|
||||||
.shortName(R.string.treatments_shortname)
|
.shortName(R.string.treatments_shortname)
|
||||||
|
@ -81,13 +76,11 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface
|
||||||
aapsLogger, resourceHelper, injector
|
aapsLogger, resourceHelper, injector
|
||||||
);
|
);
|
||||||
this.rxBus = rxBus;
|
this.rxBus = rxBus;
|
||||||
this.aapsSchedulers = aapsSchedulers;
|
|
||||||
this.sp = sp;
|
this.sp = sp;
|
||||||
this.profileFunction = profileFunction;
|
this.profileFunction = profileFunction;
|
||||||
this.activePlugin = activePlugin;
|
this.activePlugin = activePlugin;
|
||||||
this.fabricPrivacy = fabricPrivacy;
|
this.fabricPrivacy = fabricPrivacy;
|
||||||
this.dateUtil = dateUtil;
|
this.dateUtil = dateUtil;
|
||||||
this.nsUpload = nsUpload;
|
|
||||||
this.databaseHelper = databaseHelper;
|
this.databaseHelper = databaseHelper;
|
||||||
this.repository = repository;
|
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)
|
ErrorHelperActivity.runAlarm(context, result.comment, resourceHelper.gs(R.string.failedupdatebasalprofile), R.raw.boluserror)
|
||||||
}
|
}
|
||||||
if (result.enacted) {
|
if (result.enacted) {
|
||||||
rxBus.send(EventNewBasalProfile())
|
|
||||||
repository.createEffectiveProfileSwitch(
|
repository.createEffectiveProfileSwitch(
|
||||||
EffectiveProfileSwitch(
|
EffectiveProfileSwitch(
|
||||||
timestamp = dateUtil.now(),
|
timestamp = dateUtil.now(),
|
||||||
|
@ -104,6 +103,7 @@ open class CommandQueue @Inject constructor(
|
||||||
insulinConfiguration = it.insulinConfiguration
|
insulinConfiguration = it.insulinConfiguration
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
rxBus.send(EventNewBasalProfile())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -566,11 +566,12 @@ open class CommandQueue @Inject constructor(
|
||||||
return HtmlHelper.fromHtml(s)
|
return HtmlHelper.fromHtml(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun isThisProfileSet(profile: Profile): Boolean {
|
override fun isThisProfileSet(requestedProfile: Profile): Boolean {
|
||||||
val result = activePlugin.activePump.isThisProfileSet(profile)
|
val runningProfile = profileFunction.getProfile() ?: return false
|
||||||
|
val result = activePlugin.activePump.isThisProfileSet(requestedProfile) && requestedProfile.isEqual(runningProfile)
|
||||||
if (!result) {
|
if (!result) {
|
||||||
aapsLogger.debug(LTag.PUMPQUEUE, "Current profile: ${profileFunction.getProfile()}")
|
aapsLogger.debug(LTag.PUMPQUEUE, "Current profile: ${profileFunction.getProfile()}")
|
||||||
aapsLogger.debug(LTag.PUMPQUEUE, "New profile: $profile")
|
aapsLogger.debug(LTag.PUMPQUEUE, "New profile: $requestedProfile")
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ import info.nightscout.androidaps.data.PumpEnactResult
|
||||||
import info.nightscout.androidaps.database.ValueWrapper
|
import info.nightscout.androidaps.database.ValueWrapper
|
||||||
import info.nightscout.androidaps.interfaces.ActivePlugin
|
import info.nightscout.androidaps.interfaces.ActivePlugin
|
||||||
import info.nightscout.androidaps.interfaces.CommandQueueProvider
|
import info.nightscout.androidaps.interfaces.CommandQueueProvider
|
||||||
|
import info.nightscout.androidaps.interfaces.Config
|
||||||
import info.nightscout.androidaps.interfaces.PluginType
|
import info.nightscout.androidaps.interfaces.PluginType
|
||||||
import info.nightscout.androidaps.interfaces.Profile
|
import info.nightscout.androidaps.interfaces.Profile
|
||||||
import info.nightscout.androidaps.logging.LTag
|
import info.nightscout.androidaps.logging.LTag
|
||||||
|
@ -25,9 +26,10 @@ class CommandSetProfile constructor(
|
||||||
@Inject lateinit var activePlugin: ActivePlugin
|
@Inject lateinit var activePlugin: ActivePlugin
|
||||||
@Inject lateinit var dateUtil: DateUtil
|
@Inject lateinit var dateUtil: DateUtil
|
||||||
@Inject lateinit var commandQueue: CommandQueueProvider
|
@Inject lateinit var commandQueue: CommandQueueProvider
|
||||||
|
@Inject lateinit var config: Config
|
||||||
|
|
||||||
override fun execute() {
|
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")
|
aapsLogger.debug(LTag.PUMPQUEUE, "Correct profile already set. profile: $profile")
|
||||||
callback?.result(PumpEnactResult(injector).success(true).enacted(false))?.run()
|
callback?.result(PumpEnactResult(injector).success(true).enacted(false))?.run()
|
||||||
return
|
return
|
||||||
|
@ -37,7 +39,7 @@ class CommandSetProfile constructor(
|
||||||
callback?.result(r)?.run()
|
callback?.result(r)?.run()
|
||||||
// Send SMS notification if ProfileSwitch is coming from NS
|
// Send SMS notification if ProfileSwitch is coming from NS
|
||||||
val profileSwitch = repository.getEffectiveProfileSwitchActiveAt(dateUtil.now()).blockingGet()
|
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))
|
if (smsCommunicatorPlugin.isEnabled(PluginType.GENERAL))
|
||||||
smsCommunicatorPlugin.sendNotificationToAllNumbers(resourceHelper.gs(R.string.profile_set_ok))
|
smsCommunicatorPlugin.sendNotificationToAllNumbers(resourceHelper.gs(R.string.profile_set_ok))
|
||||||
}
|
}
|
||||||
|
|
|
@ -119,17 +119,18 @@ class KeepAliveReceiver : DaggerBroadcastReceiver() {
|
||||||
private fun checkPump() {
|
private fun checkPump() {
|
||||||
val pump = activePlugin.activePump
|
val pump = activePlugin.activePump
|
||||||
val ps = profileFunction.getRequestedProfile() ?: return
|
val ps = profileFunction.getRequestedProfile() ?: return
|
||||||
val profile = ProfileSealed.PS(ps)
|
val requestedProfile = ProfileSealed.PS(ps)
|
||||||
|
val runningProfile = profileFunction.getProfile()
|
||||||
val lastConnection = pump.lastDataTime()
|
val lastConnection = pump.lastDataTime()
|
||||||
val isStatusOutdated = lastConnection + STATUS_UPDATE_FREQUENCY < System.currentTimeMillis()
|
val isStatusOutdated = lastConnection + STATUS_UPDATE_FREQUENCY < System.currentTimeMillis()
|
||||||
val isBasalOutdated = abs(profile.getBasal() - pump.baseBasalRate) > pump.pumpDescription.basalStep
|
val isBasalOutdated = abs(requestedProfile.getBasal() - pump.baseBasalRate) > pump.pumpDescription.basalStep
|
||||||
aapsLogger.debug(LTag.CORE, "Last connection: " + dateUtil.dateAndTimeString(lastConnection))
|
aapsLogger.debug(LTag.CORE, "Last connection: " + dateUtil.dateAndTimeString(lastConnection))
|
||||||
// sometimes keep alive broadcast stops
|
// sometimes keep alive broadcast stops
|
||||||
// as as workaround test if readStatus was requested before an alarm is generated
|
// as as workaround test if readStatus was requested before an alarm is generated
|
||||||
if (lastReadStatus != 0L && lastReadStatus > System.currentTimeMillis() - T.mins(5).msecs()) {
|
if (lastReadStatus != 0L && lastReadStatus > System.currentTimeMillis() - T.mins(5).msecs()) {
|
||||||
localAlertUtils.checkPumpUnreachableAlarm(lastConnection, isStatusOutdated, loopPlugin.isDisconnected)
|
localAlertUtils.checkPumpUnreachableAlarm(lastConnection, isStatusOutdated, loopPlugin.isDisconnected)
|
||||||
}
|
}
|
||||||
if (!pump.isThisProfileSet(profile) && !commandQueue.isRunning(Command.CommandType.BASAL_PROFILE)) {
|
if (runningProfile == null || ((!pump.isThisProfileSet(requestedProfile) || !requestedProfile.isEqual(runningProfile)) && !commandQueue.isRunning(Command.CommandType.BASAL_PROFILE))) {
|
||||||
rxBus.send(EventProfileSwitchChanged())
|
rxBus.send(EventProfileSwitchChanged())
|
||||||
} else if (isStatusOutdated && !pump.isBusy()) {
|
} else if (isStatusOutdated && !pump.isBusy()) {
|
||||||
lastReadStatus = System.currentTimeMillis()
|
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.constraints.objectives.ObjectivesPlugin
|
||||||
import info.nightscout.androidaps.plugins.general.nsclient.NSClientPlugin
|
import info.nightscout.androidaps.plugins.general.nsclient.NSClientPlugin
|
||||||
import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientStatus
|
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.LocalProfileFragment
|
||||||
import info.nightscout.androidaps.plugins.profile.local.LocalProfilePlugin
|
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.common.events.EventRileyLinkDeviceStatusChange
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.OmnipodDashPumpPlugin
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.OmnipodDashPumpPlugin
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.eros.OmnipodErosPumpPlugin
|
import info.nightscout.androidaps.plugins.pump.omnipod.eros.OmnipodErosPumpPlugin
|
||||||
|
@ -53,7 +50,6 @@ class SWDefinition @Inject constructor(
|
||||||
private val configBuilder: ConfigBuilder,
|
private val configBuilder: ConfigBuilder,
|
||||||
private val loopPlugin: LoopPlugin,
|
private val loopPlugin: LoopPlugin,
|
||||||
private val nsClientPlugin: NSClientPlugin,
|
private val nsClientPlugin: NSClientPlugin,
|
||||||
private val nsProfilePlugin: NSProfilePlugin,
|
|
||||||
private val importExportPrefs: ImportExportPrefs,
|
private val importExportPrefs: ImportExportPrefs,
|
||||||
private val androidPermission: AndroidPermission,
|
private val androidPermission: AndroidPermission,
|
||||||
private val cryptoUtil: CryptoUtil,
|
private val cryptoUtil: CryptoUtil,
|
||||||
|
@ -189,8 +185,8 @@ class SWDefinition @Inject constructor(
|
||||||
.label(R.string.status)
|
.label(R.string.status)
|
||||||
.initialStatus(nsClientPlugin.status)
|
.initialStatus(nsClientPlugin.status)
|
||||||
)
|
)
|
||||||
.validator { nsClientPlugin.nsClientService != null && NSClientService.isConnected && NSClientService.hasWriteAuth }
|
.validator { nsClientPlugin.nsClientService?.isConnected == true && nsClientPlugin.nsClientService?.hasWriteAuth == true }
|
||||||
.visibility { !(nsClientPlugin.nsClientService != null && NSClientService.isConnected && NSClientService.hasWriteAuth) }
|
.visibility { !(nsClientPlugin.nsClientService?.isConnected == true && nsClientPlugin.nsClientService?.hasWriteAuth == true) }
|
||||||
private val screenPatientName = SWScreen(injector, R.string.patient_name)
|
private val screenPatientName = SWScreen(injector, R.string.patient_name)
|
||||||
.skippable(true)
|
.skippable(true)
|
||||||
.add(SWInfoText(injector)
|
.add(SWInfoText(injector)
|
||||||
|
@ -254,27 +250,14 @@ class SWDefinition @Inject constructor(
|
||||||
.option(PluginType.BGSOURCE, R.string.configbuilder_bgsource_description)
|
.option(PluginType.BGSOURCE, R.string.configbuilder_bgsource_description)
|
||||||
.label(R.string.configbuilder_bgsource))
|
.label(R.string.configbuilder_bgsource))
|
||||||
.add(SWBreak(injector))
|
.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)
|
private val screenLocalProfile = SWScreen(injector, R.string.localprofile)
|
||||||
.skippable(false)
|
.skippable(false)
|
||||||
.add(SWFragment(injector, this)
|
.add(SWFragment(injector, this)
|
||||||
.add(LocalProfileFragment()))
|
.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() }
|
.visibility { localProfilePlugin.isEnabled() }
|
||||||
private val screenProfileSwitch = SWScreen(injector, R.string.careportal_profileswitch)
|
private val screenProfileSwitch = SWScreen(injector, R.string.careportal_profileswitch)
|
||||||
.skippable(false)
|
.skippable(false)
|
||||||
|
@ -399,8 +382,6 @@ class SWDefinition @Inject constructor(
|
||||||
.add(screenAge)
|
.add(screenAge)
|
||||||
.add(screenInsulin)
|
.add(screenInsulin)
|
||||||
.add(screenBgSource)
|
.add(screenBgSource)
|
||||||
.add(screenProfile)
|
|
||||||
.add(screenNsProfile)
|
|
||||||
.add(screenLocalProfile)
|
.add(screenLocalProfile)
|
||||||
.add(screenProfileSwitch)
|
.add(screenProfileSwitch)
|
||||||
.add(screenPump)
|
.add(screenPump)
|
||||||
|
@ -428,8 +409,6 @@ class SWDefinition @Inject constructor(
|
||||||
.add(screenAge)
|
.add(screenAge)
|
||||||
.add(screenInsulin)
|
.add(screenInsulin)
|
||||||
.add(screenBgSource)
|
.add(screenBgSource)
|
||||||
.add(screenProfile)
|
|
||||||
.add(screenNsProfile)
|
|
||||||
.add(screenLocalProfile)
|
.add(screenLocalProfile)
|
||||||
.add(screenProfileSwitch)
|
.add(screenProfileSwitch)
|
||||||
.add(screenPump)
|
.add(screenPump)
|
||||||
|
|
|
@ -17,13 +17,14 @@ class JSONFormatter @Inject constructor(
|
||||||
private val aapsLogger: AAPSLogger
|
private val aapsLogger: AAPSLogger
|
||||||
) {
|
) {
|
||||||
|
|
||||||
|
@kotlin.ExperimentalStdlibApi
|
||||||
fun format(jsonString: String?): Spanned {
|
fun format(jsonString: String?): Spanned {
|
||||||
jsonString ?: return fromHtml("")
|
jsonString ?: return fromHtml("")
|
||||||
val visitor = JsonVisitor(1, '\t')
|
val visitor = JsonVisitor(1, '\t')
|
||||||
return try {
|
return try {
|
||||||
when {
|
when {
|
||||||
jsonString == "undefined" -> fromHtml("undefined")
|
jsonString == "undefined" -> fromHtml("undefined")
|
||||||
jsonString.toByteArray()[0] == '['.toByte() -> fromHtml(visitor.visit(JSONArray(jsonString), 0))
|
jsonString.toByteArray()[0] == '['.code.toByte() -> fromHtml(visitor.visit(JSONArray(jsonString), 0))
|
||||||
else -> fromHtml(visitor.visit(JSONObject(jsonString), 0))
|
else -> fromHtml(visitor.visit(JSONObject(jsonString), 0))
|
||||||
}
|
}
|
||||||
} catch (e: JSONException) {
|
} catch (e: JSONException) {
|
||||||
|
|
|
@ -10,9 +10,12 @@ class TrendCalculator @Inject constructor(
|
||||||
private val repository: AppRepository
|
private val repository: AppRepository
|
||||||
) {
|
) {
|
||||||
|
|
||||||
fun getTrendArrow(glucoseValue: GlucoseValue): GlucoseValue.TrendArrow =
|
fun getTrendArrow(glucoseValue: GlucoseValue?): GlucoseValue.TrendArrow =
|
||||||
if (glucoseValue.trendArrow != GlucoseValue.TrendArrow.NONE) glucoseValue.trendArrow
|
when {
|
||||||
else calculateDirection(glucoseValue)
|
glucoseValue?.trendArrow == null -> GlucoseValue.TrendArrow.NONE
|
||||||
|
glucoseValue.trendArrow != GlucoseValue.TrendArrow.NONE -> glucoseValue.trendArrow
|
||||||
|
else -> calculateDirection(glucoseValue)
|
||||||
|
}
|
||||||
|
|
||||||
private fun calculateDirection(glucoseValue: GlucoseValue): GlucoseValue.TrendArrow {
|
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.interfaces.Profile
|
||||||
import info.nightscout.androidaps.database.AppRepository
|
import info.nightscout.androidaps.database.AppRepository
|
||||||
import info.nightscout.androidaps.database.entities.BolusCalculatorResult
|
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.ValueWithUnit
|
||||||
import info.nightscout.androidaps.database.entities.TemporaryTarget
|
import info.nightscout.androidaps.database.entities.TemporaryTarget
|
||||||
import info.nightscout.androidaps.database.entities.UserEntry.Action
|
import info.nightscout.androidaps.database.entities.UserEntry.Action
|
||||||
|
@ -374,7 +375,7 @@ class BolusWizard @Inject constructor(
|
||||||
if (useSuperBolus) {
|
if (useSuperBolus) {
|
||||||
uel.log(Action.SUPERBOLUS_TBR, Sources.WizardDialog)
|
uel.log(Action.SUPERBOLUS_TBR, Sources.WizardDialog)
|
||||||
if (loopPlugin.isEnabled(PluginType.LOOP)) {
|
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"))
|
rxBus.send(EventRefreshOverview("WizardDialog"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -408,7 +409,7 @@ class BolusWizard @Inject constructor(
|
||||||
context = ctx
|
context = ctx
|
||||||
mgdlGlucose = Profile.toMgdl(bg, profile.units)
|
mgdlGlucose = Profile.toMgdl(bg, profile.units)
|
||||||
glucoseType = DetailedBolusInfo.MeterType.MANUAL
|
glucoseType = DetailedBolusInfo.MeterType.MANUAL
|
||||||
carbTime = this@BolusWizard.carbTime
|
carbsTimestamp = dateUtil.now() + T.mins(this@BolusWizard.carbTime.toLong()).msecs()
|
||||||
bolusCalculatorResult = createBolusCalculatorResult()
|
bolusCalculatorResult = createBolusCalculatorResult()
|
||||||
notes = this@BolusWizard.notes
|
notes = this@BolusWizard.notes
|
||||||
if (insulin > 0 || carbs > 0) {
|
if (insulin > 0 || carbs > 0) {
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
tools:context="info.nightscout.androidaps.historyBrowser.HistoryBrowseActivity">
|
tools:context="info.nightscout.androidaps.activities.HistoryBrowseActivity">
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
@ -72,7 +72,7 @@
|
||||||
android:layout_weight="1">
|
android:layout_weight="1">
|
||||||
|
|
||||||
<com.jjoe64.graphview.GraphView
|
<com.jjoe64.graphview.GraphView
|
||||||
android:id="@+id/bggraph"
|
android:id="@+id/bg_graph"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="match_parent" />
|
android:layout_height="match_parent" />
|
||||||
|
|
||||||
|
|
|
@ -51,6 +51,7 @@
|
||||||
|
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
|
android:id="@+id/overview_loop"
|
||||||
android:layout_width="fill_parent"
|
android:layout_width="fill_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue