Merge branch 'nightscout:dev' into dev
This commit is contained in:
commit
b57ca6f94c
1619 changed files with 60155 additions and 30621 deletions
|
@ -68,6 +68,6 @@ workflows:
|
||||||
# Inside the workflow, you provide the jobs you want to run, e.g this workflow runs the build-and-test job above.
|
# 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.
|
# 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
|
# For more details on extending your workflow, see the configuration docs: https://circleci.com/docs/2.0/configuration-reference/#workflows
|
||||||
sample:
|
dotests:
|
||||||
jobs:
|
jobs:
|
||||||
- build-and-test
|
- build-and-test
|
5
.editorconfig
Normal file
5
.editorconfig
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
root = true
|
||||||
|
|
||||||
|
|
||||||
|
[*{kt,kts}]
|
||||||
|
disabled_rules=no-wildcard-imports
|
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -11,8 +11,6 @@ build/
|
||||||
.idea/*
|
.idea/*
|
||||||
!.idea/codeStyles/
|
!.idea/codeStyles/
|
||||||
full/
|
full/
|
||||||
debug/
|
|
||||||
release/
|
|
||||||
app/com.crashlytics.settings.json
|
app/com.crashlytics.settings.json
|
||||||
app/session_analytics.tap
|
app/session_analytics.tap
|
||||||
.project
|
.project
|
||||||
|
|
|
@ -1,11 +1,13 @@
|
||||||
<component name="ProjectCodeStyleConfiguration">
|
<component name="ProjectCodeStyleConfiguration">
|
||||||
<code_scheme name="Project" version="173">
|
<code_scheme name="Project" version="173">
|
||||||
<option name="AUTODETECT_INDENTS" value="false" />
|
<option name="AUTODETECT_INDENTS" value="false" />
|
||||||
|
<option name="WRAP_WHEN_TYPING_REACHES_RIGHT_MARGIN" value="true" />
|
||||||
<JetCodeStyleSettings>
|
<JetCodeStyleSettings>
|
||||||
<option name="ALIGN_IN_COLUMNS_CASE_BRANCH" value="true" />
|
<option name="ALIGN_IN_COLUMNS_CASE_BRANCH" value="true" />
|
||||||
<option name="NAME_COUNT_TO_USE_STAR_IMPORT" value="6" />
|
<option name="NAME_COUNT_TO_USE_STAR_IMPORT" value="6" />
|
||||||
<option name="NAME_COUNT_TO_USE_STAR_IMPORT_FOR_MEMBERS" value="6" />
|
<option name="NAME_COUNT_TO_USE_STAR_IMPORT_FOR_MEMBERS" value="6" />
|
||||||
<option name="BLANK_LINES_AROUND_BLOCK_WHEN_BRANCHES" value="1" />
|
<option name="BLANK_LINES_AROUND_BLOCK_WHEN_BRANCHES" value="1" />
|
||||||
|
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
|
||||||
</JetCodeStyleSettings>
|
</JetCodeStyleSettings>
|
||||||
<codeStyleSettings language="JAVA">
|
<codeStyleSettings language="JAVA">
|
||||||
<option name="METHOD_ANNOTATION_WRAP" value="0" />
|
<option name="METHOD_ANNOTATION_WRAP" value="0" />
|
||||||
|
@ -124,14 +126,22 @@
|
||||||
</arrangement>
|
</arrangement>
|
||||||
</codeStyleSettings>
|
</codeStyleSettings>
|
||||||
<codeStyleSettings language="kotlin">
|
<codeStyleSettings language="kotlin">
|
||||||
|
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
|
||||||
|
<option name="RIGHT_MARGIN" value="120" />
|
||||||
<option name="LINE_COMMENT_AT_FIRST_COLUMN" value="false" />
|
<option name="LINE_COMMENT_AT_FIRST_COLUMN" value="false" />
|
||||||
<option name="LINE_COMMENT_ADD_SPACE" value="true" />
|
<option name="LINE_COMMENT_ADD_SPACE" value="true" />
|
||||||
<option name="KEEP_BLANK_LINES_IN_DECLARATIONS" value="1" />
|
<option name="KEEP_BLANK_LINES_IN_DECLARATIONS" value="1" />
|
||||||
<option name="KEEP_BLANK_LINES_IN_CODE" value="1" />
|
<option name="KEEP_BLANK_LINES_IN_CODE" value="1" />
|
||||||
<option name="KEEP_BLANK_LINES_BEFORE_RBRACE" value="1" />
|
<option name="KEEP_BLANK_LINES_BEFORE_RBRACE" value="1" />
|
||||||
<option name="BLANK_LINES_AFTER_CLASS_HEADER" value="1" />
|
<option name="BLANK_LINES_AFTER_CLASS_HEADER" value="1" />
|
||||||
|
<option name="ALIGN_MULTILINE_PARAMETERS_IN_CALLS" value="true" />
|
||||||
|
<option name="ASSIGNMENT_WRAP" value="5" />
|
||||||
<option name="METHOD_ANNOTATION_WRAP" value="5" />
|
<option name="METHOD_ANNOTATION_WRAP" value="5" />
|
||||||
<option name="FIELD_ANNOTATION_WRAP" value="0" />
|
<option name="CLASS_ANNOTATION_WRAP" value="1" />
|
||||||
|
<option name="FIELD_ANNOTATION_WRAP" value="1" />
|
||||||
|
<option name="PARAMETER_ANNOTATION_WRAP" value="1" />
|
||||||
|
<option name="VARIABLE_ANNOTATION_WRAP" value="1" />
|
||||||
|
<option name="ENUM_CONSTANTS_WRAP" value="5" />
|
||||||
<indentOptions>
|
<indentOptions>
|
||||||
<option name="CONTINUATION_INDENT_SIZE" value="4" />
|
<option name="CONTINUATION_INDENT_SIZE" value="4" />
|
||||||
</indentOptions>
|
</indentOptions>
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
<dictionary name="project-dictionary">
|
<dictionary name="project-dictionary">
|
||||||
<words>
|
<words>
|
||||||
<w>aaps</w>
|
<w>aaps</w>
|
||||||
|
<w>abcdef</w>
|
||||||
<w>acked</w>
|
<w>acked</w>
|
||||||
<w>actionstring</w>
|
<w>actionstring</w>
|
||||||
<w>allowednumbers</w>
|
<w>allowednumbers</w>
|
||||||
|
@ -14,8 +15,10 @@
|
||||||
<w>basals</w>
|
<w>basals</w>
|
||||||
<w>bgcheck</w>
|
<w>bgcheck</w>
|
||||||
<w>bgsource</w>
|
<w>bgsource</w>
|
||||||
|
<w>boluscalc</w>
|
||||||
<w>bolusing</w>
|
<w>bolusing</w>
|
||||||
<w>carb</w>
|
<w>carb</w>
|
||||||
|
<w>carbratio</w>
|
||||||
<w>carbs</w>
|
<w>carbs</w>
|
||||||
<w>carbsreq</w>
|
<w>carbsreq</w>
|
||||||
<w>careportal</w>
|
<w>careportal</w>
|
||||||
|
@ -46,6 +49,7 @@
|
||||||
<w>medtronic</w>
|
<w>medtronic</w>
|
||||||
<w>mgdl</w>
|
<w>mgdl</w>
|
||||||
<w>mmol</w>
|
<w>mmol</w>
|
||||||
|
<w>motol</w>
|
||||||
<w>multiwave</w>
|
<w>multiwave</w>
|
||||||
<w>netinsulin</w>
|
<w>netinsulin</w>
|
||||||
<w>netratio</w>
|
<w>netratio</w>
|
||||||
|
@ -55,9 +59,14 @@
|
||||||
<w>okcancel</w>
|
<w>okcancel</w>
|
||||||
<w>omnipod</w>
|
<w>omnipod</w>
|
||||||
<w>openaps</w>
|
<w>openaps</w>
|
||||||
|
<w>openhumans</w>
|
||||||
<w>oref</w>
|
<w>oref</w>
|
||||||
|
<w>otpauth</w>
|
||||||
<w>passcode</w>
|
<w>passcode</w>
|
||||||
|
<w>pdus</w>
|
||||||
|
<w>philoul</w>
|
||||||
<w>poctech</w>
|
<w>poctech</w>
|
||||||
|
<w>pred</w>
|
||||||
<w>profileswitch</w>
|
<w>profileswitch</w>
|
||||||
<w>pumpbtcomm</w>
|
<w>pumpbtcomm</w>
|
||||||
<w>quickwizard</w>
|
<w>quickwizard</w>
|
||||||
|
@ -66,14 +75,18 @@
|
||||||
<w>refresheventsfromnightscout</w>
|
<w>refresheventsfromnightscout</w>
|
||||||
<w>rileylink</w>
|
<w>rileylink</w>
|
||||||
<w>roboelectric</w>
|
<w>roboelectric</w>
|
||||||
|
<w>sgvs</w>
|
||||||
<w>sitechange</w>
|
<w>sitechange</w>
|
||||||
<w>smscommunicator</w>
|
<w>smscommunicator</w>
|
||||||
|
<w>sntp</w>
|
||||||
<w>sooil</w>
|
<w>sooil</w>
|
||||||
<w>soundid</w>
|
<w>soundid</w>
|
||||||
<w>splitted</w>
|
<w>splitted</w>
|
||||||
|
<w>ssid</w>
|
||||||
<w>superbolus</w>
|
<w>superbolus</w>
|
||||||
<w>targethigh</w>
|
<w>targethigh</w>
|
||||||
<w>targetlow</w>
|
<w>targetlow</w>
|
||||||
|
<w>tbrs</w>
|
||||||
<w>tdds</w>
|
<w>tdds</w>
|
||||||
<w>tempbasal</w>
|
<w>tempbasal</w>
|
||||||
<w>tempbasals</w>
|
<w>tempbasals</w>
|
||||||
|
@ -82,9 +95,11 @@
|
||||||
<w>tidepool</w>
|
<w>tidepool</w>
|
||||||
<w>timeshift</w>
|
<w>timeshift</w>
|
||||||
<w>tirs</w>
|
<w>tirs</w>
|
||||||
|
<w>totp</w>
|
||||||
<w>uart</w>
|
<w>uart</w>
|
||||||
<w>wizzardpage</w>
|
<w>wizzardpage</w>
|
||||||
<w>xdrip</w>
|
<w>xdrip</w>
|
||||||
|
<w>xstream</w>
|
||||||
<w>ypso</w>
|
<w>ypso</w>
|
||||||
<w>ypsomed</w>
|
<w>ypsomed</w>
|
||||||
<w>ypsopump</w>
|
<w>ypsopump</w>
|
||||||
|
|
|
@ -1,26 +1,24 @@
|
||||||
apply plugin: 'com.android.application'
|
apply plugin: 'com.android.application'
|
||||||
apply plugin: 'kotlin-android'
|
apply plugin: 'kotlin-android'
|
||||||
apply plugin: 'kotlin-kapt'
|
apply plugin: 'kotlin-kapt'
|
||||||
|
apply plugin: 'kotlin-allopen'
|
||||||
apply plugin: 'com.google.gms.google-services'
|
apply plugin: 'com.google.gms.google-services'
|
||||||
apply plugin: 'com.hiya.jacoco-android'
|
apply plugin: 'com.hiya.jacoco-android'
|
||||||
apply plugin: 'com.google.firebase.crashlytics'
|
apply plugin: 'com.google.firebase.crashlytics'
|
||||||
|
|
||||||
apply from: "${project.rootDir}/gradle/android_dependencies.gradle"
|
apply from: "${project.rootDir}/gradle/android_dependencies.gradle"
|
||||||
|
apply from: "${project.rootDir}/gradle/jacoco_global.gradle"
|
||||||
jacoco {
|
|
||||||
toolVersion = "0.8.6"
|
|
||||||
}
|
|
||||||
|
|
||||||
tasks.withType(Test) {
|
|
||||||
jacoco.includeNoLocationClasses = true
|
|
||||||
jacoco.excludes = ['jdk.internal.*']
|
|
||||||
}
|
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
google()
|
google()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
allOpen {
|
||||||
|
// allows mocking for classes w/o directly opening them for release builds
|
||||||
|
annotation 'info.nightscout.androidaps.annotations.OpenForTesting'
|
||||||
|
}
|
||||||
|
|
||||||
def generateGitBuild = { ->
|
def generateGitBuild = { ->
|
||||||
StringBuilder stringBuilder = new StringBuilder()
|
StringBuilder stringBuilder = new StringBuilder()
|
||||||
try {
|
try {
|
||||||
|
@ -111,7 +109,7 @@ android {
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
multiDexEnabled true
|
multiDexEnabled true
|
||||||
versionCode 1500
|
versionCode 1500
|
||||||
version "2.8.2.1-dev-e4"
|
version "2.8.2.4-dev"
|
||||||
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,19 +184,20 @@ 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')
|
||||||
implementation project(':omnipod-eros')
|
implementation project(':omnipod-eros')
|
||||||
implementation project(':omnipod-dash')
|
implementation project(':omnipod-dash')
|
||||||
|
implementation project(':diaconn')
|
||||||
|
implementation project(':openhumans')
|
||||||
|
|
||||||
implementation fileTree(include: ['*.jar'], dir: 'libs')
|
implementation fileTree(include: ['*.jar'], dir: 'libs')
|
||||||
|
|
||||||
/* 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"
|
||||||
|
|
|
@ -1,42 +1,7 @@
|
||||||
package info.nightscout.androidaps
|
package info.nightscout.androidaps
|
||||||
|
|
||||||
import android.os.SystemClock
|
|
||||||
import android.view.View
|
|
||||||
import android.view.ViewGroup
|
|
||||||
import androidx.test.espresso.Espresso.onData
|
|
||||||
import androidx.test.espresso.Espresso.onView
|
|
||||||
import androidx.test.espresso.action.ViewActions
|
|
||||||
import androidx.test.espresso.action.ViewActions.click
|
|
||||||
import androidx.test.espresso.action.ViewActions.scrollTo
|
|
||||||
import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
|
|
||||||
import androidx.test.espresso.matcher.ViewMatchers.withClassName
|
|
||||||
import androidx.test.espresso.matcher.ViewMatchers.withId
|
|
||||||
import androidx.test.espresso.matcher.ViewMatchers.withTagValue
|
|
||||||
import androidx.test.espresso.matcher.ViewMatchers.withText
|
|
||||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||||
import androidx.test.filters.LargeTest
|
import androidx.test.filters.LargeTest
|
||||||
import androidx.test.rule.ActivityTestRule
|
|
||||||
import androidx.test.rule.GrantPermissionRule
|
|
||||||
import info.nightscout.androidaps.interfaces.PluginType
|
|
||||||
import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin
|
|
||||||
import info.nightscout.androidaps.plugins.aps.openAPSSMB.OpenAPSSMBPlugin
|
|
||||||
import info.nightscout.androidaps.plugins.constraints.objectives.ObjectivesPlugin
|
|
||||||
import info.nightscout.androidaps.plugins.profile.local.LocalProfilePlugin
|
|
||||||
import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpPlugin
|
|
||||||
import info.nightscout.androidaps.plugins.sensitivity.SensitivityOref1Plugin
|
|
||||||
import info.nightscout.androidaps.plugins.source.RandomBgPlugin
|
|
||||||
import info.nightscout.androidaps.setupwizard.SetupWizardActivity
|
|
||||||
import info.nightscout.androidaps.utils.HardLimits
|
|
||||||
import info.nightscout.androidaps.utils.extensions.isRunningTest
|
|
||||||
import org.hamcrest.CoreMatchers.allOf
|
|
||||||
import org.hamcrest.Description
|
|
||||||
import org.hamcrest.Matcher
|
|
||||||
import org.hamcrest.Matchers
|
|
||||||
import org.hamcrest.TypeSafeMatcher
|
|
||||||
import org.junit.Assert
|
|
||||||
import org.junit.Before
|
|
||||||
import org.junit.Rule
|
|
||||||
import org.junit.Test
|
|
||||||
import org.junit.runner.RunWith
|
import org.junit.runner.RunWith
|
||||||
|
|
||||||
@LargeTest
|
@LargeTest
|
||||||
|
|
|
@ -52,7 +52,8 @@
|
||||||
android:name="com.google.android.gms.car.application"
|
android:name="com.google.android.gms.car.application"
|
||||||
android:resource="@xml/automotive_app_desc" />
|
android:resource="@xml/automotive_app_desc" />
|
||||||
|
|
||||||
<activity android:name=".MainActivity">
|
<activity android:name=".MainActivity"
|
||||||
|
android:exported="true">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.VIEW" />
|
<action android:name="android.intent.action.VIEW" />
|
||||||
<action android:name="android.intent.action.MAIN" />
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
@ -60,7 +61,8 @@
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
<activity android:name=".activities.PreferencesActivity" />
|
<activity android:name=".activities.PreferencesActivity" />
|
||||||
<activity android:name=".plugins.general.overview.activities.QuickWizardListActivity">
|
<activity android:name=".plugins.general.overview.activities.QuickWizardListActivity"
|
||||||
|
android:exported="false">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="info.nightscout.androidaps.plugins.general.overview.activities.QuickWizardListActivity" />
|
<action android:name="info.nightscout.androidaps.plugins.general.overview.activities.QuickWizardListActivity" />
|
||||||
|
|
||||||
|
@ -68,7 +70,7 @@
|
||||||
</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.TreatmentsActivity" />
|
||||||
<activity android:name=".activities.SurveyActivity" />
|
<activity android:name=".activities.SurveyActivity" />
|
||||||
<activity android:name=".activities.ProfileHelperActivity"
|
<activity android:name=".activities.ProfileHelperActivity"
|
||||||
|
@ -115,11 +117,11 @@
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</receiver>
|
</receiver>
|
||||||
|
|
||||||
<!-- Receiver keepalive, scheduled every 30 min -->
|
<!-- Receiver keep alive, scheduled every 30 min -->
|
||||||
<receiver android:name=".receivers.KeepAliveReceiver" />
|
<receiver android:name=".receivers.KeepAliveReceiver" />
|
||||||
|
|
||||||
<!-- Receive ignore 5m, 15m, 30m requests for carb notifications -->
|
<!-- Receive ignore 5m, 15m, 30m requests for carb notifications -->
|
||||||
<receiver android:name=".plugins.aps.loop.CarbSuggestionReceiver"></receiver>
|
<receiver android:name=".plugins.aps.loop.CarbSuggestionReceiver" />
|
||||||
|
|
||||||
<!-- Auto start -->
|
<!-- Auto start -->
|
||||||
<receiver
|
<receiver
|
||||||
|
@ -241,20 +243,6 @@
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<activity android:name=".plugins.general.openhumans.OpenHumansLoginActivity"
|
|
||||||
android:launchMode="singleTop">
|
|
||||||
<intent-filter>
|
|
||||||
<action android:name="android.intent.action.VIEW" />
|
|
||||||
|
|
||||||
<category android:name="android.intent.category.DEFAULT" />
|
|
||||||
<category android:name="android.intent.category.BROWSABLE" />
|
|
||||||
|
|
||||||
<data
|
|
||||||
android:host="setup-openhumans"
|
|
||||||
android:scheme="androidaps" />
|
|
||||||
</intent-filter>
|
|
||||||
</activity>
|
|
||||||
|
|
||||||
<uses-library android:name="org.apache.http.legacy" android:required="false"/>
|
<uses-library android:name="org.apache.http.legacy" android:required="false"/>
|
||||||
|
|
||||||
</application>
|
</application>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<configuration>
|
<configuration>
|
||||||
<!-- Create a file appender for a log in the application's data directory -->
|
<!-- Create a file appender for a log in the application's data directory -->
|
||||||
<property name="EXT_FILES_DIR" scope="context"
|
<property name="EXT_FILES_DIR" scope="context"
|
||||||
value="${EXT_DIR:-/sdcard}/Android/data/${PACKAGE_NAME}/files" />
|
value="${EXT_DIR:-/sdcard}/AAPS/logs/${PACKAGE_NAME}" />
|
||||||
<appender name="file" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
<appender name="file" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||||
<file>${EXT_FILES_DIR}/AndroidAPS.log</file>
|
<file>${EXT_FILES_DIR}/AndroidAPS.log</file>
|
||||||
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||||
|
|
|
@ -34,7 +34,7 @@ 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
|
||||||
|
@ -95,7 +95,6 @@ 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())
|
||||||
|
@ -166,7 +165,7 @@ class MainActivity : NoSplashAppCompatActivity() {
|
||||||
actionBarDrawerToggle.syncState()
|
actionBarDrawerToggle.syncState()
|
||||||
}
|
}
|
||||||
|
|
||||||
public override fun onDestroy() {
|
override fun onDestroy() {
|
||||||
super.onDestroy()
|
super.onDestroy()
|
||||||
disposable.clear()
|
disposable.clear()
|
||||||
}
|
}
|
||||||
|
@ -361,7 +360,6 @@ 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"
|
||||||
|
|
|
@ -6,7 +6,6 @@ import android.content.IntentFilter
|
||||||
import android.net.ConnectivityManager
|
import android.net.ConnectivityManager
|
||||||
import android.net.wifi.WifiManager
|
import android.net.wifi.WifiManager
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import com.j256.ormlite.android.apptools.OpenHelperManager
|
|
||||||
import dagger.android.AndroidInjector
|
import dagger.android.AndroidInjector
|
||||||
import dagger.android.DaggerApplication
|
import dagger.android.DaggerApplication
|
||||||
import info.nightscout.androidaps.database.AppRepository
|
import info.nightscout.androidaps.database.AppRepository
|
||||||
|
@ -15,11 +14,10 @@ import info.nightscout.androidaps.database.entities.UserEntry
|
||||||
import info.nightscout.androidaps.database.transactions.InsertIfNewByTimestampTherapyEventTransaction
|
import info.nightscout.androidaps.database.transactions.InsertIfNewByTimestampTherapyEventTransaction
|
||||||
import info.nightscout.androidaps.database.transactions.VersionChangeTransaction
|
import info.nightscout.androidaps.database.transactions.VersionChangeTransaction
|
||||||
import info.nightscout.androidaps.db.CompatDBHelper
|
import info.nightscout.androidaps.db.CompatDBHelper
|
||||||
import info.nightscout.androidaps.db.DatabaseHelper
|
import info.nightscout.androidaps.di.StaticInjector
|
||||||
import info.nightscout.androidaps.db.StaticInjector
|
|
||||||
import info.nightscout.androidaps.dependencyInjection.DaggerAppComponent
|
import info.nightscout.androidaps.dependencyInjection.DaggerAppComponent
|
||||||
import info.nightscout.androidaps.interfaces.ConfigBuilder
|
|
||||||
import info.nightscout.androidaps.interfaces.Config
|
import info.nightscout.androidaps.interfaces.Config
|
||||||
|
import info.nightscout.androidaps.interfaces.ConfigBuilder
|
||||||
import info.nightscout.androidaps.interfaces.PluginBase
|
import info.nightscout.androidaps.interfaces.PluginBase
|
||||||
import info.nightscout.androidaps.logging.AAPSLogger
|
import info.nightscout.androidaps.logging.AAPSLogger
|
||||||
import info.nightscout.androidaps.logging.LTag
|
import info.nightscout.androidaps.logging.LTag
|
||||||
|
@ -34,6 +32,7 @@ import info.nightscout.androidaps.receivers.TimeDateOrTZChangeReceiver
|
||||||
import info.nightscout.androidaps.utils.ActivityMonitor
|
import info.nightscout.androidaps.utils.ActivityMonitor
|
||||||
import info.nightscout.androidaps.utils.DateUtil
|
import info.nightscout.androidaps.utils.DateUtil
|
||||||
import info.nightscout.androidaps.utils.locale.LocaleHelper.update
|
import info.nightscout.androidaps.utils.locale.LocaleHelper.update
|
||||||
|
import info.nightscout.androidaps.utils.protection.PasswordCheck
|
||||||
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
||||||
import io.reactivex.disposables.CompositeDisposable
|
import io.reactivex.disposables.CompositeDisposable
|
||||||
import io.reactivex.rxkotlin.plusAssign
|
import io.reactivex.rxkotlin.plusAssign
|
||||||
|
@ -58,12 +57,12 @@ class MainApp : DaggerApplication() {
|
||||||
@Inject lateinit var dateUtil: DateUtil
|
@Inject lateinit var dateUtil: DateUtil
|
||||||
@Inject lateinit var staticInjector: StaticInjector// TODO avoid , here fake only to initialize
|
@Inject lateinit var staticInjector: StaticInjector// TODO avoid , here fake only to initialize
|
||||||
@Inject lateinit var uel: UserEntryLogger
|
@Inject lateinit var uel: UserEntryLogger
|
||||||
|
@Inject lateinit var passwordCheck: PasswordCheck
|
||||||
|
|
||||||
override fun onCreate() {
|
override fun onCreate() {
|
||||||
super.onCreate()
|
super.onCreate()
|
||||||
aapsLogger.debug("onCreate")
|
aapsLogger.debug("onCreate")
|
||||||
update(this)
|
update(this)
|
||||||
dbHelper = OpenHelperManager.getHelper(this, DatabaseHelper::class.java)
|
|
||||||
|
|
||||||
var gitRemote: String? = BuildConfig.REMOTE
|
var gitRemote: String? = BuildConfig.REMOTE
|
||||||
var commitHash: String? = BuildConfig.HEAD
|
var commitHash: String? = BuildConfig.HEAD
|
||||||
|
@ -90,6 +89,7 @@ class MainApp : DaggerApplication() {
|
||||||
keepAliveManager.setAlarm(this)
|
keepAliveManager.setAlarm(this)
|
||||||
doMigrations()
|
doMigrations()
|
||||||
uel.log(UserEntry.Action.START_AAPS, UserEntry.Sources.Aaps)
|
uel.log(UserEntry.Action.START_AAPS, UserEntry.Sources.Aaps)
|
||||||
|
passwordCheck.passwordResetCheck(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun doMigrations() {
|
private fun doMigrations() {
|
||||||
|
@ -134,9 +134,4 @@ class MainApp : DaggerApplication() {
|
||||||
keepAliveManager.cancelAlarm(this)
|
keepAliveManager.cancelAlarm(this)
|
||||||
super.onTerminate()
|
super.onTerminate()
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
|
||||||
|
|
||||||
lateinit var dbHelper: DatabaseHelper
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -0,0 +1,406 @@
|
||||||
|
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 {
|
||||||
|
adjustTimeRange(overviewData.fromTime - T.hours(rangeToDisplay.toLong()).msecs())
|
||||||
|
loadAll("onClickLeft")
|
||||||
|
}
|
||||||
|
binding.right.setOnClickListener {
|
||||||
|
adjustTimeRange(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()
|
||||||
|
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.R)
|
||||||
|
display?.getRealMetrics(dm)
|
||||||
|
else
|
||||||
|
@Suppress("DEPRECATION") 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onPause() {
|
||||||
|
super.onPause()
|
||||||
|
disposable.clear()
|
||||||
|
iobCobCalculator.stopCalculation("onPause")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Synchronized
|
||||||
|
override fun onDestroy() {
|
||||||
|
destroyed = true
|
||||||
|
super.onDestroy()
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
||||||
|
updateDate()
|
||||||
|
Thread {
|
||||||
|
overviewData.prepareBgData("$from")
|
||||||
|
overviewData.prepareTreatmentsData(from)
|
||||||
|
rxBus.send(EventRefreshOverview("loadAll_$from"))
|
||||||
|
overviewData.prepareTemporaryTargetData(from)
|
||||||
|
rxBus.send(EventRefreshOverview("loadAll_$from"))
|
||||||
|
overviewData.prepareBasalData(from)
|
||||||
|
rxBus.send(EventRefreshOverview(from))
|
||||||
|
aapsLogger.debug(LTag.UI, "loadAll $from finished")
|
||||||
|
runCalculation(from)
|
||||||
|
}.start()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setTime(start: Long) {
|
||||||
|
GregorianCalendar().also { calendar ->
|
||||||
|
calendar.timeInMillis = start
|
||||||
|
calendar[Calendar.MILLISECOND] = 0
|
||||||
|
calendar[Calendar.SECOND] = 0
|
||||||
|
calendar[Calendar.MINUTE] = 0
|
||||||
|
calendar[Calendar.HOUR_OF_DAY] -= (calendar[Calendar.HOUR_OF_DAY] % rangeToDisplay)
|
||||||
|
adjustTimeRange(calendar.timeInMillis)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun adjustTimeRange(start: Long) {
|
||||||
|
overviewData.fromTime = start
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
fun updateDate() {
|
||||||
|
binding.date.text = dateUtil.dateAndTimeString(overviewData.fromTime)
|
||||||
|
binding.zoom.text = rangeToDisplay.toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("UNUSED_PARAMETER")
|
||||||
|
@SuppressLint("SetTextI18n")
|
||||||
|
fun updateGUI(from: String) {
|
||||||
|
aapsLogger.debug(LTag.UI, "updateGui $from")
|
||||||
|
|
||||||
|
updateDate()
|
||||||
|
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -14,11 +14,13 @@ import info.nightscout.androidaps.danaRKorean.DanaRKoreanPlugin
|
||||||
import info.nightscout.androidaps.danaRv2.DanaRv2Plugin
|
import info.nightscout.androidaps.danaRv2.DanaRv2Plugin
|
||||||
import info.nightscout.androidaps.danar.DanaRPlugin
|
import info.nightscout.androidaps.danar.DanaRPlugin
|
||||||
import info.nightscout.androidaps.danars.DanaRSPlugin
|
import info.nightscout.androidaps.danars.DanaRSPlugin
|
||||||
|
import info.nightscout.androidaps.diaconn.DiaconnG8Plugin
|
||||||
import info.nightscout.androidaps.interfaces.Profile
|
import info.nightscout.androidaps.interfaces.Profile
|
||||||
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.interfaces.PluginBase
|
import info.nightscout.androidaps.interfaces.PluginBase
|
||||||
import info.nightscout.androidaps.interfaces.ProfileFunction
|
import info.nightscout.androidaps.interfaces.ProfileFunction
|
||||||
|
import info.nightscout.androidaps.plugin.general.openhumans.OpenHumansUploader
|
||||||
import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin
|
import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin
|
||||||
import info.nightscout.androidaps.plugins.aps.openAPSAMA.OpenAPSAMAPlugin
|
import info.nightscout.androidaps.plugins.aps.openAPSAMA.OpenAPSAMAPlugin
|
||||||
import info.nightscout.androidaps.plugins.aps.openAPSSMB.OpenAPSSMBPlugin
|
import info.nightscout.androidaps.plugins.aps.openAPSSMB.OpenAPSSMBPlugin
|
||||||
|
@ -29,7 +31,6 @@ import info.nightscout.androidaps.plugins.general.automation.AutomationPlugin
|
||||||
import info.nightscout.androidaps.plugins.general.maintenance.MaintenancePlugin
|
import info.nightscout.androidaps.plugins.general.maintenance.MaintenancePlugin
|
||||||
import info.nightscout.androidaps.plugins.general.nsclient.NSClientPlugin
|
import info.nightscout.androidaps.plugins.general.nsclient.NSClientPlugin
|
||||||
import info.nightscout.androidaps.plugins.general.nsclient.data.NSSettingsStatus
|
import info.nightscout.androidaps.plugins.general.nsclient.data.NSSettingsStatus
|
||||||
import info.nightscout.androidaps.plugins.general.openhumans.OpenHumansUploader
|
|
||||||
import info.nightscout.androidaps.plugins.general.smsCommunicator.SmsCommunicatorPlugin
|
import info.nightscout.androidaps.plugins.general.smsCommunicator.SmsCommunicatorPlugin
|
||||||
import info.nightscout.androidaps.plugins.general.tidepool.TidepoolPlugin
|
import info.nightscout.androidaps.plugins.general.tidepool.TidepoolPlugin
|
||||||
import info.nightscout.androidaps.plugins.general.wear.WearPlugin
|
import info.nightscout.androidaps.plugins.general.wear.WearPlugin
|
||||||
|
@ -99,6 +100,7 @@ class MyPreferenceFragment : PreferenceFragmentCompat(), OnSharedPreferenceChang
|
||||||
@Inject lateinit var passwordCheck: PasswordCheck
|
@Inject lateinit var passwordCheck: PasswordCheck
|
||||||
@Inject lateinit var nsSettingStatus: NSSettingsStatus
|
@Inject lateinit var nsSettingStatus: NSSettingsStatus
|
||||||
@Inject lateinit var openHumansUploader: OpenHumansUploader
|
@Inject lateinit var openHumansUploader: OpenHumansUploader
|
||||||
|
@Inject lateinit var diaconnG8Plugin: DiaconnG8Plugin
|
||||||
|
|
||||||
override fun onAttach(context: Context) {
|
override fun onAttach(context: Context) {
|
||||||
AndroidSupportInjection.inject(this)
|
AndroidSupportInjection.inject(this)
|
||||||
|
@ -173,6 +175,7 @@ class MyPreferenceFragment : PreferenceFragmentCompat(), OnSharedPreferenceChang
|
||||||
addPreferencesFromResourceIfEnabled(localInsightPlugin, rootKey, config.PUMPDRIVERS)
|
addPreferencesFromResourceIfEnabled(localInsightPlugin, rootKey, config.PUMPDRIVERS)
|
||||||
addPreferencesFromResourceIfEnabled(comboPlugin, rootKey, config.PUMPDRIVERS)
|
addPreferencesFromResourceIfEnabled(comboPlugin, rootKey, config.PUMPDRIVERS)
|
||||||
addPreferencesFromResourceIfEnabled(medtronicPumpPlugin, rootKey, config.PUMPDRIVERS)
|
addPreferencesFromResourceIfEnabled(medtronicPumpPlugin, rootKey, config.PUMPDRIVERS)
|
||||||
|
addPreferencesFromResourceIfEnabled(diaconnG8Plugin, rootKey, config.PUMPDRIVERS)
|
||||||
addPreferencesFromResource(R.xml.pref_pump, rootKey, config.PUMPDRIVERS)
|
addPreferencesFromResource(R.xml.pref_pump, rootKey, config.PUMPDRIVERS)
|
||||||
addPreferencesFromResourceIfEnabled(virtualPumpPlugin, rootKey)
|
addPreferencesFromResourceIfEnabled(virtualPumpPlugin, rootKey)
|
||||||
addPreferencesFromResourceIfEnabled(insulinOrefFreePeakPlugin, rootKey)
|
addPreferencesFromResourceIfEnabled(insulinOrefFreePeakPlugin, rootKey)
|
||||||
|
@ -182,7 +185,7 @@ class MyPreferenceFragment : PreferenceFragmentCompat(), OnSharedPreferenceChang
|
||||||
addPreferencesFromResourceIfEnabled(automationPlugin, rootKey)
|
addPreferencesFromResourceIfEnabled(automationPlugin, rootKey)
|
||||||
addPreferencesFromResourceIfEnabled(wearPlugin, rootKey)
|
addPreferencesFromResourceIfEnabled(wearPlugin, rootKey)
|
||||||
addPreferencesFromResourceIfEnabled(statusLinePlugin, rootKey)
|
addPreferencesFromResourceIfEnabled(statusLinePlugin, rootKey)
|
||||||
addPreferencesFromResource(R.xml.pref_alerts, rootKey) // TODO not organized well
|
addPreferencesFromResource(R.xml.pref_alerts, rootKey)
|
||||||
addPreferencesFromResource(R.xml.pref_datachoices, rootKey)
|
addPreferencesFromResource(R.xml.pref_datachoices, rootKey)
|
||||||
addPreferencesFromResourceIfEnabled(maintenancePlugin, rootKey)
|
addPreferencesFromResourceIfEnabled(maintenancePlugin, rootKey)
|
||||||
addPreferencesFromResourceIfEnabled(openHumansUploader, rootKey)
|
addPreferencesFromResourceIfEnabled(openHumansUploader, rootKey)
|
||||||
|
|
|
@ -7,10 +7,8 @@ import javax.inject.Inject
|
||||||
class RequestDexcomPermissionActivity : DialogAppCompatActivity() {
|
class RequestDexcomPermissionActivity : DialogAppCompatActivity() {
|
||||||
@Inject lateinit var dexcomPlugin: DexcomPlugin
|
@Inject lateinit var dexcomPlugin: DexcomPlugin
|
||||||
|
|
||||||
@kotlin.ExperimentalStdlibApi
|
|
||||||
private val requestCode = "AndroidAPS <3".map { it.code }.sum()
|
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)
|
||||||
|
|
|
@ -19,7 +19,7 @@ class SingleFragmentActivity : DaggerAppCompatActivityWithResult() {
|
||||||
|
|
||||||
private var plugin: PluginBase? = null
|
private var plugin: PluginBase? = null
|
||||||
|
|
||||||
public override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
setContentView(R.layout.activity_single_fragment)
|
setContentView(R.layout.activity_single_fragment)
|
||||||
plugin = pluginStore.plugins[intent.getIntExtra("plugin", -1)]
|
plugin = pluginStore.plugins[intent.getIntExtra("plugin", -1)]
|
||||||
|
@ -52,7 +52,7 @@ class SingleFragmentActivity : DaggerAppCompatActivityWithResult() {
|
||||||
return super.onCreateOptionsMenu(menu)
|
return super.onCreateOptionsMenu(menu)
|
||||||
}
|
}
|
||||||
|
|
||||||
public override fun attachBaseContext(newBase: Context) {
|
override fun attachBaseContext(newBase: Context) {
|
||||||
super.attachBaseContext(LocaleHelper.wrap(newBase))
|
super.attachBaseContext(LocaleHelper.wrap(newBase))
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,5 +1,6 @@
|
||||||
package info.nightscout.androidaps.activities
|
package info.nightscout.androidaps.activities
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import info.nightscout.androidaps.R
|
import info.nightscout.androidaps.R
|
||||||
import info.nightscout.androidaps.database.entities.UserEntry.Action
|
import info.nightscout.androidaps.database.entities.UserEntry.Action
|
||||||
|
@ -21,14 +22,28 @@ class StatsActivity : NoSplashAppCompatActivity() {
|
||||||
|
|
||||||
private lateinit var binding: ActivityStatsBinding
|
private lateinit var binding: ActivityStatsBinding
|
||||||
|
|
||||||
|
@SuppressLint("SetTextI18n")
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
binding = ActivityStatsBinding.inflate(layoutInflater)
|
binding = ActivityStatsBinding.inflate(layoutInflater)
|
||||||
setContentView(binding.root)
|
setContentView(binding.root)
|
||||||
|
|
||||||
binding.tdds.text = tddCalculator.stats()
|
binding.tdds.text = getString(R.string.tdd) + ": " + getString(R.string.calculation_in_progress)
|
||||||
binding.tir.text = tirCalculator.stats()
|
binding.tir.text = getString(R.string.tir) + ": " + getString(R.string.calculation_in_progress)
|
||||||
binding.activity.text = activityMonitor.stats()
|
binding.activity.text = getString(R.string.activitymonitor) + ": " + getString(R.string.calculation_in_progress)
|
||||||
|
|
||||||
|
Thread {
|
||||||
|
val tdds = tddCalculator.stats()
|
||||||
|
runOnUiThread { binding.tdds.text = tdds }
|
||||||
|
}.start()
|
||||||
|
Thread {
|
||||||
|
val tir = tirCalculator.stats()
|
||||||
|
runOnUiThread { binding.tir.text = tir }
|
||||||
|
}.start()
|
||||||
|
Thread {
|
||||||
|
val activity = activityMonitor.stats()
|
||||||
|
runOnUiThread { binding.activity.text = activity }
|
||||||
|
}.start()
|
||||||
|
|
||||||
binding.ok.setOnClickListener { finish() }
|
binding.ok.setOnClickListener { finish() }
|
||||||
binding.reset.setOnClickListener {
|
binding.reset.setOnClickListener {
|
||||||
|
|
|
@ -31,7 +31,7 @@ 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.events.EventTreatmentUpdateGui
|
||||||
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
|
||||||
|
|
|
@ -24,7 +24,7 @@ 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.events.EventTreatmentUpdateGui
|
||||||
import info.nightscout.androidaps.activities.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
|
||||||
|
|
|
@ -29,7 +29,7 @@ import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientR
|
||||||
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.events.EventTreatmentUpdateGui
|
||||||
import info.nightscout.androidaps.activities.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
|
||||||
|
|
|
@ -28,7 +28,7 @@ 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.events.EventTreatmentUpdateGui
|
||||||
import info.nightscout.androidaps.activities.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
|
||||||
|
|
|
@ -190,7 +190,6 @@ class TreatmentsTemporaryBasalsFragment : DaggerFragment() {
|
||||||
|
|
||||||
override fun getItemCount(): Int = tempBasalList.size
|
override fun getItemCount(): Int = tempBasalList.size
|
||||||
|
|
||||||
@Deprecated("remove remove functionality after finish")
|
|
||||||
inner class TempBasalsViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
|
inner class TempBasalsViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
|
||||||
|
|
||||||
val binding = TreatmentsTempbasalsItemBinding.bind(itemView)
|
val binding = TreatmentsTempbasalsItemBinding.bind(itemView)
|
||||||
|
|
|
@ -19,7 +19,7 @@ import info.nightscout.androidaps.interfaces.ImportExportPrefs
|
||||||
import info.nightscout.androidaps.interfaces.ProfileFunction
|
import info.nightscout.androidaps.interfaces.ProfileFunction
|
||||||
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.events.EventTreatmentUpdateGui
|
import info.nightscout.androidaps.events.EventTreatmentUpdateGui
|
||||||
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
|
||||||
|
|
|
@ -11,6 +11,7 @@ import org.json.JSONObject
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
|
import kotlin.math.abs
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
class DefaultProfile @Inject constructor(val dateUtil: DateUtil) {
|
class DefaultProfile @Inject constructor(val dateUtil: DateUtil) {
|
||||||
|
@ -120,12 +121,12 @@ class DefaultProfile @Inject constructor(val dateUtil: DateUtil) {
|
||||||
val high = map.ceilingEntry(key)
|
val high = map.ceilingEntry(key)
|
||||||
var res: Array<Double>? = null
|
var res: Array<Double>? = null
|
||||||
if (low != null && high != null) {
|
if (low != null && high != null) {
|
||||||
res = if (Math.abs(key - low.key) < Math.abs(key - high.key))
|
res = if (abs(key - low.key) < abs(key - high.key))
|
||||||
low.value
|
low.value
|
||||||
else
|
else
|
||||||
high.value
|
high.value
|
||||||
} else if (low != null || high != null) {
|
} else if (low != null || high != null) {
|
||||||
res = if (low != null) low.value else high.value
|
res = if (low != null) low.value else high!!.value
|
||||||
}
|
}
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
|
@ -82,5 +82,9 @@ class CompatDBHelper @Inject constructor(
|
||||||
aapsLogger.debug(LTag.DATABASE, "Firing EventProfileSwitchChanged")
|
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())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,296 +0,0 @@
|
||||||
package info.nightscout.androidaps.db;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.database.DatabaseUtils;
|
|
||||||
import android.database.sqlite.SQLiteDatabase;
|
|
||||||
|
|
||||||
import com.j256.ormlite.android.apptools.OrmLiteSqliteOpenHelper;
|
|
||||||
import com.j256.ormlite.dao.CloseableIterator;
|
|
||||||
import com.j256.ormlite.dao.Dao;
|
|
||||||
import com.j256.ormlite.stmt.DeleteBuilder;
|
|
||||||
import com.j256.ormlite.stmt.PreparedQuery;
|
|
||||||
import com.j256.ormlite.stmt.QueryBuilder;
|
|
||||||
import com.j256.ormlite.stmt.Where;
|
|
||||||
import com.j256.ormlite.support.ConnectionSource;
|
|
||||||
import com.j256.ormlite.table.TableUtils;
|
|
||||||
|
|
||||||
import java.sql.SQLException;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import javax.inject.Inject;
|
|
||||||
|
|
||||||
import info.nightscout.androidaps.events.EventRefreshOverview;
|
|
||||||
import info.nightscout.androidaps.interfaces.ActivePlugin;
|
|
||||||
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.openhumans.OpenHumansUploader;
|
|
||||||
import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpPlugin;
|
|
||||||
import info.nightscout.androidaps.utils.DateUtil;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This Helper contains all resource to provide a central DB management functionality. Only methods handling
|
|
||||||
* data-structure (and not the DB content) should be contained in here (meaning DDL and not SQL).
|
|
||||||
* <p>
|
|
||||||
* This class can safely be called from Services, but should not call Services to avoid circular dependencies.
|
|
||||||
* One major issue with this (right now) are the scheduled events, which are put into the service. Therefor all
|
|
||||||
* direct calls to the corresponding methods (eg. resetDatabases) should be done by a central service.
|
|
||||||
*/
|
|
||||||
public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
|
|
||||||
@Inject AAPSLogger aapsLogger;
|
|
||||||
@Inject RxBusWrapper rxBus;
|
|
||||||
@Inject VirtualPumpPlugin virtualPumpPlugin;
|
|
||||||
@Inject OpenHumansUploader openHumansUploader;
|
|
||||||
@Inject ActivePlugin activePlugin;
|
|
||||||
@Inject DateUtil dateUtil;
|
|
||||||
|
|
||||||
public static final String DATABASE_NAME = "AndroidAPSDb";
|
|
||||||
|
|
||||||
private static final int DATABASE_VERSION = 13;
|
|
||||||
|
|
||||||
public static Long earliestDataChange = null;
|
|
||||||
|
|
||||||
private int oldVersion = 0;
|
|
||||||
private int newVersion = 0;
|
|
||||||
|
|
||||||
public DatabaseHelper(Context context) {
|
|
||||||
super(context, DATABASE_NAME, null, DATABASE_VERSION);
|
|
||||||
StaticInjector.Companion.getInstance().androidInjector().inject(this);
|
|
||||||
onCreate(getWritableDatabase(), getConnectionSource());
|
|
||||||
//onUpgrade(getWritableDatabase(), getConnectionSource(), 1,1);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onCreate(SQLiteDatabase database, ConnectionSource connectionSource) {
|
|
||||||
try {
|
|
||||||
aapsLogger.info(LTag.DATABASE, "onCreate");
|
|
||||||
TableUtils.createTableIfNotExists(connectionSource, OmnipodHistoryRecord.class);
|
|
||||||
TableUtils.createTableIfNotExists(connectionSource, OHQueueItem.class);
|
|
||||||
} catch (SQLException e) {
|
|
||||||
aapsLogger.error("Can't create database", e);
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onUpgrade(SQLiteDatabase database, ConnectionSource connectionSource, int oldVersion, int newVersion) {
|
|
||||||
try {
|
|
||||||
this.oldVersion = oldVersion;
|
|
||||||
this.newVersion = newVersion;
|
|
||||||
|
|
||||||
if (oldVersion < 7) {
|
|
||||||
aapsLogger.info(LTag.DATABASE, "onUpgrade");
|
|
||||||
onCreate(database, connectionSource);
|
|
||||||
}
|
|
||||||
TableUtils.createTableIfNotExists(connectionSource, OHQueueItem.class);
|
|
||||||
} catch (SQLException e) {
|
|
||||||
aapsLogger.error("Can't drop databases", e);
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {
|
|
||||||
aapsLogger.info(LTag.DATABASE, "Do nothing for downgrading...");
|
|
||||||
aapsLogger.info(LTag.DATABASE, "oldVersion: {}, newVersion: {}", oldVersion, newVersion);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getOldVersion() {
|
|
||||||
return oldVersion;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getNewVersion() {
|
|
||||||
return newVersion;
|
|
||||||
}
|
|
||||||
|
|
||||||
public long size(String database) {
|
|
||||||
return DatabaseUtils.queryNumEntries(getReadableDatabase(), database);
|
|
||||||
}
|
|
||||||
|
|
||||||
// --------------------- DB resets ---------------------
|
|
||||||
|
|
||||||
public void resetDatabases() {
|
|
||||||
try {
|
|
||||||
TableUtils.dropTable(connectionSource, OmnipodHistoryRecord.class, true);
|
|
||||||
TableUtils.createTableIfNotExists(connectionSource, OmnipodHistoryRecord.class);
|
|
||||||
updateEarliestDataChange(0);
|
|
||||||
} catch (SQLException e) {
|
|
||||||
aapsLogger.error("Unhandled exception", e);
|
|
||||||
}
|
|
||||||
virtualPumpPlugin.setFakingStatus(true);
|
|
||||||
new java.util.Timer().schedule(
|
|
||||||
new java.util.TimerTask() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
rxBus.send(new EventRefreshOverview("resetDatabases", false));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
3000
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ------------------ getDao -------------------------------------------
|
|
||||||
|
|
||||||
private Dao<OmnipodHistoryRecord, Long> getDaoPodHistory() throws SQLException {
|
|
||||||
return getDao(OmnipodHistoryRecord.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
private Dao<OHQueueItem, Long> getDaoOpenHumansQueue() throws SQLException {
|
|
||||||
return getDao(OHQueueItem.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void updateEarliestDataChange(long newDate) {
|
|
||||||
if (earliestDataChange == null) {
|
|
||||||
earliestDataChange = newDate;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (newDate < earliestDataChange) {
|
|
||||||
earliestDataChange = newDate;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---------------- Food handling ---------------
|
|
||||||
|
|
||||||
// ---------------- PodHistory handling ---------------
|
|
||||||
|
|
||||||
public void createOrUpdate(OmnipodHistoryRecord omnipodHistoryRecord) {
|
|
||||||
try {
|
|
||||||
getDaoPodHistory().createOrUpdate(omnipodHistoryRecord);
|
|
||||||
} catch (SQLException e) {
|
|
||||||
aapsLogger.error("Unhandled exception", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<OmnipodHistoryRecord> getAllOmnipodHistoryRecordsFromTimeStamp(long from, boolean ascending) {
|
|
||||||
try {
|
|
||||||
Dao<OmnipodHistoryRecord, Long> daoPodHistory = getDaoPodHistory();
|
|
||||||
List<OmnipodHistoryRecord> podHistories;
|
|
||||||
QueryBuilder<OmnipodHistoryRecord, Long> queryBuilder = daoPodHistory.queryBuilder();
|
|
||||||
queryBuilder.orderBy("date", ascending);
|
|
||||||
//queryBuilder.limit(100L);
|
|
||||||
Where where = queryBuilder.where();
|
|
||||||
where.ge("date", from);
|
|
||||||
PreparedQuery<OmnipodHistoryRecord> preparedQuery = queryBuilder.prepare();
|
|
||||||
podHistories = daoPodHistory.query(preparedQuery);
|
|
||||||
return podHistories;
|
|
||||||
} catch (SQLException e) {
|
|
||||||
aapsLogger.error("Unhandled exception", e);
|
|
||||||
}
|
|
||||||
return new ArrayList<>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public OmnipodHistoryRecord findOmnipodHistoryRecordByPumpId(long pumpId) {
|
|
||||||
try {
|
|
||||||
Dao<OmnipodHistoryRecord, Long> daoPodHistory = getDaoPodHistory();
|
|
||||||
QueryBuilder<OmnipodHistoryRecord, Long> queryBuilder = daoPodHistory.queryBuilder();
|
|
||||||
queryBuilder.orderBy("date", false);
|
|
||||||
Where<OmnipodHistoryRecord, Long> where = queryBuilder.where();
|
|
||||||
where.eq("pumpId", pumpId);
|
|
||||||
PreparedQuery<OmnipodHistoryRecord> preparedQuery = queryBuilder.prepare();
|
|
||||||
return daoPodHistory.queryForFirst(preparedQuery);
|
|
||||||
} catch (SQLException e) {
|
|
||||||
aapsLogger.error("Unhandled exception", e);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
TODO implement again for database branch // Copied from xDrip+
|
|
||||||
String calculateDirection(BgReading bgReading) {
|
|
||||||
// Rework to get bgreaings from internal DB and calculate on that base
|
|
||||||
|
|
||||||
List<BgReading> bgReadingsList = MainApp.getDbHelper().getAllBgreadingsDataFromTime(bgReading.date - T.mins(10).msecs(), false);
|
|
||||||
if (bgReadingsList == null || bgReadingsList.size() < 2)
|
|
||||||
return "NONE";
|
|
||||||
BgReading current = bgReadingsList.get(1);
|
|
||||||
BgReading previous = bgReadingsList.get(0);
|
|
||||||
|
|
||||||
if (bgReadingsList.get(1).date < bgReadingsList.get(0).date) {
|
|
||||||
current = bgReadingsList.get(0);
|
|
||||||
previous = bgReadingsList.get(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
double slope;
|
|
||||||
|
|
||||||
// Avoid division by 0
|
|
||||||
if (current.date == previous.date)
|
|
||||||
slope = 0;
|
|
||||||
else
|
|
||||||
slope = (previous.value - current.value) / (previous.date - current.date);
|
|
||||||
|
|
||||||
// aapsLogger.error(LTag.GLUCOSE, "Slope is :" + slope + " delta " + (previous.value - current.value) + " date difference " + (current.date - previous.date));
|
|
||||||
|
|
||||||
double slope_by_minute = slope * 60000;
|
|
||||||
String arrow = "NONE";
|
|
||||||
|
|
||||||
if (slope_by_minute <= (-3.5)) {
|
|
||||||
arrow = "DoubleDown";
|
|
||||||
} else if (slope_by_minute <= (-2)) {
|
|
||||||
arrow = "SingleDown";
|
|
||||||
} else if (slope_by_minute <= (-1)) {
|
|
||||||
arrow = "FortyFiveDown";
|
|
||||||
} else if (slope_by_minute <= (1)) {
|
|
||||||
arrow = "Flat";
|
|
||||||
} else if (slope_by_minute <= (2)) {
|
|
||||||
arrow = "FortyFiveUp";
|
|
||||||
} else if (slope_by_minute <= (3.5)) {
|
|
||||||
arrow = "SingleUp";
|
|
||||||
} else if (slope_by_minute <= (40)) {
|
|
||||||
arrow = "DoubleUp";
|
|
||||||
}
|
|
||||||
// aapsLogger.error(LTag.GLUCOSE, "Direction set to: " + arrow);
|
|
||||||
return arrow;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
// ---------------- Open Humans Queue handling ---------------
|
|
||||||
|
|
||||||
public void clearOpenHumansQueue() {
|
|
||||||
try {
|
|
||||||
TableUtils.clearTable(connectionSource, OHQueueItem.class);
|
|
||||||
} catch (SQLException e) {
|
|
||||||
aapsLogger.error("Unhandled exception", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void createOrUpdate(OHQueueItem item) {
|
|
||||||
try {
|
|
||||||
getDaoOpenHumansQueue().createOrUpdate(item);
|
|
||||||
} catch (SQLException e) {
|
|
||||||
aapsLogger.error("Unhandled exception", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void removeAllOHQueueItemsWithIdSmallerThan(long id) {
|
|
||||||
try {
|
|
||||||
DeleteBuilder<OHQueueItem, Long> deleteBuilder = getDaoOpenHumansQueue().deleteBuilder();
|
|
||||||
deleteBuilder.where().le("id", id);
|
|
||||||
deleteBuilder.delete();
|
|
||||||
} catch (SQLException e) {
|
|
||||||
aapsLogger.error("Unhandled exception", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<OHQueueItem> getAllOHQueueItems(Long maxEntries) {
|
|
||||||
try {
|
|
||||||
return getDaoOpenHumansQueue()
|
|
||||||
.queryBuilder()
|
|
||||||
.orderBy("id", true)
|
|
||||||
.limit(maxEntries)
|
|
||||||
.query();
|
|
||||||
} catch (SQLException e) {
|
|
||||||
aapsLogger.error("Unhandled exception", e);
|
|
||||||
}
|
|
||||||
return Collections.emptyList();
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getOHQueueSize() {
|
|
||||||
try {
|
|
||||||
return getDaoOpenHumansQueue().countOf();
|
|
||||||
} catch (SQLException e) {
|
|
||||||
aapsLogger.error("Unhandled exception", e);
|
|
||||||
}
|
|
||||||
return 0L;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,84 +0,0 @@
|
||||||
package info.nightscout.androidaps.db;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
|
|
||||||
import com.j256.ormlite.dao.CloseableIterator;
|
|
||||||
|
|
||||||
import java.sql.SQLException;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import javax.inject.Inject;
|
|
||||||
import javax.inject.Singleton;
|
|
||||||
|
|
||||||
import info.nightscout.androidaps.MainApp;
|
|
||||||
import info.nightscout.androidaps.interfaces.DatabaseHelperInterface;
|
|
||||||
|
|
||||||
@Deprecated
|
|
||||||
@Singleton
|
|
||||||
public class DatabaseHelperProvider implements DatabaseHelperInterface {
|
|
||||||
|
|
||||||
@Inject DatabaseHelperProvider() {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public void createOrUpdate(@NonNull OmnipodHistoryRecord record) {
|
|
||||||
MainApp.Companion.getDbHelper().createOrUpdate(record);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public boolean createOrUpdate(@NonNull TemporaryBasal tempBasal) {
|
|
||||||
// return MainApp.Companion.getDbHelper().createOrUpdate(tempBasal);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable @Override public TemporaryBasal findTempBasalByPumpId(long id) {
|
|
||||||
// return MainApp.Companion.getDbHelper().findTempBasalByPumpId(id);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Deprecated
|
|
||||||
@NonNull @Override public List<TemporaryBasal> getTemporaryBasalsDataFromTime(long mills, boolean ascending) {
|
|
||||||
// return MainApp.Companion.getDbHelper().getTemporaryBasalsDataFromTime(mills, ascending);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull @Override public List<OmnipodHistoryRecord> getAllOmnipodHistoryRecordsFromTimestamp(long timestamp, boolean ascending) {
|
|
||||||
return MainApp.Companion.getDbHelper().getAllOmnipodHistoryRecordsFromTimeStamp(timestamp, ascending);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable @Override public OmnipodHistoryRecord findOmnipodHistoryRecordByPumpId(long pumpId) {
|
|
||||||
return MainApp.Companion.getDbHelper().findOmnipodHistoryRecordByPumpId(pumpId);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public void delete(@NonNull ExtendedBolus extendedBolus) {
|
|
||||||
// MainApp.Companion.getDbHelper().delete(extendedBolus);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable @Override public ExtendedBolus getExtendedBolusByPumpId(long pumpId) {
|
|
||||||
// return MainApp.Companion.getDbHelper().getExtendedBolusByPumpId(pumpId);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public void resetDatabases() {
|
|
||||||
MainApp.Companion.getDbHelper().resetDatabases();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public void createOrUpdate(@NonNull OHQueueItem record) {
|
|
||||||
MainApp.Companion.getDbHelper().createOrUpdate(record);
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull @Override public List<OHQueueItem> getAllOHQueueItems(long maxEntries) {
|
|
||||||
return MainApp.Companion.getDbHelper().getAllOHQueueItems(maxEntries);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public long getOHQueueSize() {
|
|
||||||
return MainApp.Companion.getDbHelper().getOHQueueSize();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public void clearOpenHumansQueue() {
|
|
||||||
MainApp.Companion.getDbHelper().clearOpenHumansQueue();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public void removeAllOHQueueItemsWithIdSmallerThan(long id) {
|
|
||||||
MainApp.Companion.getDbHelper().removeAllOHQueueItemsWithIdSmallerThan(id);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,2 +0,0 @@
|
||||||
package info.nightscout.androidaps.db
|
|
||||||
|
|
|
@ -4,9 +4,8 @@ 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.overview.activities.QuickWizardListActivity
|
import info.nightscout.androidaps.plugins.general.overview.activities.QuickWizardListActivity
|
||||||
import info.nightscout.androidaps.plugins.general.smsCommunicator.activities.SmsCommunicatorOtpActivity
|
import info.nightscout.androidaps.plugins.general.smsCommunicator.activities.SmsCommunicatorOtpActivity
|
||||||
import info.nightscout.androidaps.setupwizard.SetupWizardActivity
|
import info.nightscout.androidaps.setupwizard.SetupWizardActivity
|
||||||
|
@ -28,6 +27,5 @@ abstract class ActivitiesModule {
|
||||||
@ContributesAndroidInjector abstract fun contributesStatsActivity(): StatsActivity
|
@ContributesAndroidInjector abstract fun contributesStatsActivity(): StatsActivity
|
||||||
@ContributesAndroidInjector abstract fun contributesSurveyActivity(): SurveyActivity
|
@ContributesAndroidInjector abstract fun contributesSurveyActivity(): SurveyActivity
|
||||||
@ContributesAndroidInjector abstract fun contributesDefaultProfileActivity(): ProfileHelperActivity
|
@ContributesAndroidInjector abstract fun contributesDefaultProfileActivity(): ProfileHelperActivity
|
||||||
@ContributesAndroidInjector abstract fun contributesOpenHumansLoginActivity(): OpenHumansLoginActivity
|
|
||||||
|
|
||||||
}
|
}
|
|
@ -8,15 +8,19 @@ 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.dana.di.DanaHistoryModule
|
import info.nightscout.androidaps.dana.di.DanaHistoryModule
|
||||||
import info.nightscout.androidaps.di.CoreModule
|
|
||||||
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.database.DatabaseModule
|
import info.nightscout.androidaps.database.DatabaseModule
|
||||||
|
import info.nightscout.androidaps.di.CoreModule
|
||||||
|
import info.nightscout.androidaps.diaconn.di.DiaconnG8Module
|
||||||
import info.nightscout.androidaps.insight.di.InsightDatabaseModule
|
import info.nightscout.androidaps.insight.di.InsightDatabaseModule
|
||||||
import info.nightscout.androidaps.insight.di.InsightModule
|
import info.nightscout.androidaps.insight.di.InsightModule
|
||||||
|
import info.nightscout.androidaps.plugin.general.openhumans.dagger.OpenHumansModule
|
||||||
|
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.eros.dagger.OmnipodErosModule
|
import info.nightscout.androidaps.plugins.pump.omnipod.eros.dagger.OmnipodErosModule
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
|
|
||||||
|
@ -36,8 +40,10 @@ 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,
|
||||||
OmnipodErosModule::class,
|
OmnipodErosModule::class,
|
||||||
APSModule::class,
|
APSModule::class,
|
||||||
PreferencesModule::class,
|
PreferencesModule::class,
|
||||||
|
@ -54,7 +60,8 @@ import javax.inject.Singleton
|
||||||
InsightModule::class,
|
InsightModule::class,
|
||||||
InsightDatabaseModule::class,
|
InsightDatabaseModule::class,
|
||||||
WorkersModule::class,
|
WorkersModule::class,
|
||||||
OHUploaderModule::class
|
DiaconnG8Module::class,
|
||||||
|
OpenHumansModule::class
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
interface AppComponent : AndroidInjector<MainApp> {
|
interface AppComponent : AndroidInjector<MainApp> {
|
||||||
|
|
|
@ -8,22 +8,25 @@ import dagger.Provides
|
||||||
import dagger.android.HasAndroidInjector
|
import dagger.android.HasAndroidInjector
|
||||||
import info.nightscout.androidaps.MainApp
|
import info.nightscout.androidaps.MainApp
|
||||||
import info.nightscout.androidaps.database.AppRepository
|
import info.nightscout.androidaps.database.AppRepository
|
||||||
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.configBuilder.ProfileFunctionImplementation
|
||||||
import info.nightscout.androidaps.plugins.general.maintenance.ImportExportPrefsImpl
|
import info.nightscout.androidaps.plugins.general.maintenance.ImportExportPrefsImpl
|
||||||
|
import info.nightscout.androidaps.plugins.general.maintenance.PrefFileListProvider
|
||||||
import info.nightscout.androidaps.plugins.general.nsclient.DataSyncSelectorImplementation
|
import info.nightscout.androidaps.plugins.general.nsclient.DataSyncSelectorImplementation
|
||||||
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.queue.CommandQueue
|
import info.nightscout.androidaps.queue.CommandQueue
|
||||||
import info.nightscout.androidaps.utils.DateUtil
|
import info.nightscout.androidaps.utils.DateUtil
|
||||||
|
import info.nightscout.androidaps.utils.HardLimits
|
||||||
import info.nightscout.androidaps.utils.androidNotification.NotificationHolderImpl
|
import info.nightscout.androidaps.utils.androidNotification.NotificationHolderImpl
|
||||||
|
import info.nightscout.androidaps.utils.buildHelper.BuildHelper
|
||||||
|
import info.nightscout.androidaps.utils.buildHelper.BuildHelperImpl
|
||||||
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.resources.ResourceHelper
|
||||||
|
@ -56,9 +59,11 @@ open class AppModule {
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@Singleton
|
@Singleton
|
||||||
fun provideStorage(): Storage {
|
fun provideStorage(): Storage = FileStorage()
|
||||||
return FileStorage()
|
|
||||||
}
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
fun provideBuildHelper(config: Config, fileListProvider: PrefFileListProvider): BuildHelper = BuildHelperImpl(config, fileListProvider)
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@Singleton
|
@Singleton
|
||||||
|
@ -66,29 +71,35 @@ open class AppModule {
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@Singleton
|
@Singleton
|
||||||
fun provideProfileFunction(aapsLogger: AAPSLogger, sp: SP, resourceHelper: ResourceHelper, activePlugin: ActivePlugin, repository: AppRepository, dateUtil: DateUtil): ProfileFunction {
|
fun provideProfileFunction(
|
||||||
return ProfileFunctionImplementation(aapsLogger, sp, resourceHelper, activePlugin, repository, dateUtil)
|
aapsLogger: AAPSLogger, sp: SP, rxBus: RxBusWrapper, resourceHelper:
|
||||||
}
|
ResourceHelper, activePlugin:
|
||||||
|
ActivePlugin, repository: AppRepository, dateUtil: DateUtil, config: Config, hardLimits: HardLimits
|
||||||
|
): ProfileFunction =
|
||||||
|
ProfileFunctionImplementation(
|
||||||
|
aapsLogger, sp, rxBus, resourceHelper, activePlugin, repository, dateUtil,
|
||||||
|
config, hardLimits
|
||||||
|
)
|
||||||
|
|
||||||
@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 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 bindDataSyncSelector(dataSyncSelectorImplementation: DataSyncSelectorImplementation): DataSyncSelector
|
@Binds fun bindDataSyncSelector(dataSyncSelectorImplementation: DataSyncSelectorImplementation): DataSyncSelector
|
||||||
@Binds fun bindPumpSync(pumpSyncImplementation: PumpSyncImplementation): PumpSync
|
|
||||||
|
|
||||||
|
@Binds fun bindPumpSync(pumpSyncImplementation: PumpSyncImplementation): PumpSync
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,9 +2,7 @@ package info.nightscout.androidaps.dependencyInjection
|
||||||
|
|
||||||
import dagger.Module
|
import dagger.Module
|
||||||
import dagger.android.ContributesAndroidInjector
|
import dagger.android.ContributesAndroidInjector
|
||||||
import info.nightscout.androidaps.db.DatabaseHelper
|
|
||||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus
|
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus
|
||||||
import info.nightscout.androidaps.plugins.treatments.TreatmentService
|
|
||||||
import info.nightscout.androidaps.utils.wizard.BolusWizard
|
import info.nightscout.androidaps.utils.wizard.BolusWizard
|
||||||
import info.nightscout.androidaps.utils.wizard.QuickWizardEntry
|
import info.nightscout.androidaps.utils.wizard.QuickWizardEntry
|
||||||
|
|
||||||
|
@ -14,9 +12,6 @@ abstract class DataClassesModule {
|
||||||
|
|
||||||
@ContributesAndroidInjector abstract fun glucoseStatusInjector(): GlucoseStatus
|
@ContributesAndroidInjector abstract fun glucoseStatusInjector(): GlucoseStatus
|
||||||
|
|
||||||
@ContributesAndroidInjector abstract fun databaseHelperInjector(): DatabaseHelper
|
|
||||||
@ContributesAndroidInjector abstract fun treatmentServiceInjector(): TreatmentService
|
|
||||||
|
|
||||||
@ContributesAndroidInjector abstract fun bolusWizardInjector(): BolusWizard
|
@ContributesAndroidInjector abstract fun bolusWizardInjector(): BolusWizard
|
||||||
@ContributesAndroidInjector abstract fun quickWizardEntryInjector(): QuickWizardEntry
|
@ContributesAndroidInjector abstract fun quickWizardEntryInjector(): QuickWizardEntry
|
||||||
}
|
}
|
|
@ -20,8 +20,6 @@ import info.nightscout.androidaps.plugins.general.automation.dialogs.EditTrigger
|
||||||
import info.nightscout.androidaps.plugins.general.food.FoodFragment
|
import info.nightscout.androidaps.plugins.general.food.FoodFragment
|
||||||
import info.nightscout.androidaps.plugins.general.maintenance.MaintenanceFragment
|
import info.nightscout.androidaps.plugins.general.maintenance.MaintenanceFragment
|
||||||
import info.nightscout.androidaps.plugins.general.nsclient.NSClientFragment
|
import info.nightscout.androidaps.plugins.general.nsclient.NSClientFragment
|
||||||
import info.nightscout.androidaps.plugins.general.openhumans.OpenHumansFragment
|
|
||||||
import info.nightscout.androidaps.plugins.general.openhumans.OpenHumansLoginActivity
|
|
||||||
import info.nightscout.androidaps.plugins.general.overview.OverviewFragment
|
import info.nightscout.androidaps.plugins.general.overview.OverviewFragment
|
||||||
import info.nightscout.androidaps.plugins.general.overview.dialogs.EditQuickWizardDialog
|
import info.nightscout.androidaps.plugins.general.overview.dialogs.EditQuickWizardDialog
|
||||||
import info.nightscout.androidaps.plugins.general.smsCommunicator.SmsCommunicatorFragment
|
import info.nightscout.androidaps.plugins.general.smsCommunicator.SmsCommunicatorFragment
|
||||||
|
@ -70,8 +68,6 @@ abstract class FragmentsModule {
|
||||||
|
|
||||||
@ContributesAndroidInjector abstract fun contributesVirtualPumpFragment(): VirtualPumpFragment
|
@ContributesAndroidInjector abstract fun contributesVirtualPumpFragment(): VirtualPumpFragment
|
||||||
|
|
||||||
@ContributesAndroidInjector abstract fun contributesOpenHumansFragment(): OpenHumansFragment
|
|
||||||
|
|
||||||
@ContributesAndroidInjector abstract fun contributesCalibrationDialog(): CalibrationDialog
|
@ContributesAndroidInjector abstract fun contributesCalibrationDialog(): CalibrationDialog
|
||||||
@ContributesAndroidInjector abstract fun contributesCarbsDialog(): CarbsDialog
|
@ContributesAndroidInjector abstract fun contributesCarbsDialog(): CarbsDialog
|
||||||
@ContributesAndroidInjector abstract fun contributesCareDialog(): CareDialog
|
@ContributesAndroidInjector abstract fun contributesCareDialog(): CareDialog
|
||||||
|
@ -95,7 +91,5 @@ abstract class FragmentsModule {
|
||||||
@ContributesAndroidInjector abstract fun contributesWizardDialog(): WizardDialog
|
@ContributesAndroidInjector abstract fun contributesWizardDialog(): WizardDialog
|
||||||
@ContributesAndroidInjector abstract fun contributesWizardInfoDialog(): WizardInfoDialog
|
@ContributesAndroidInjector abstract fun contributesWizardInfoDialog(): WizardInfoDialog
|
||||||
|
|
||||||
@ContributesAndroidInjector abstract fun contributesExchangeAuthTokenDialog(): OpenHumansLoginActivity.ExchangeAuthTokenDialog
|
|
||||||
|
|
||||||
@ContributesAndroidInjector abstract fun contributesPasswordCheck(): PasswordCheck
|
@ContributesAndroidInjector abstract fun contributesPasswordCheck(): PasswordCheck
|
||||||
}
|
}
|
|
@ -1,12 +0,0 @@
|
||||||
package info.nightscout.androidaps.dependencyInjection
|
|
||||||
|
|
||||||
import dagger.Module
|
|
||||||
import dagger.android.ContributesAndroidInjector
|
|
||||||
import info.nightscout.androidaps.plugins.general.openhumans.OHUploadWorker
|
|
||||||
|
|
||||||
@Module
|
|
||||||
@Suppress("unused")
|
|
||||||
abstract class OHUploaderModule {
|
|
||||||
|
|
||||||
@ContributesAndroidInjector abstract fun contributesOHUploadWorkerInjector(): OHUploadWorker
|
|
||||||
}
|
|
|
@ -17,7 +17,6 @@ abstract class ObjectivesModule {
|
||||||
@ContributesAndroidInjector abstract fun objective5Injector(): Objective5
|
@ContributesAndroidInjector abstract fun objective5Injector(): Objective5
|
||||||
@ContributesAndroidInjector abstract fun objective6Injector(): Objective6
|
@ContributesAndroidInjector abstract fun objective6Injector(): Objective6
|
||||||
@ContributesAndroidInjector abstract fun objective7Injector(): Objective7
|
@ContributesAndroidInjector abstract fun objective7Injector(): Objective7
|
||||||
@ContributesAndroidInjector abstract fun objective8Injector(): Objective8
|
|
||||||
@ContributesAndroidInjector abstract fun objective9Injector(): Objective9
|
@ContributesAndroidInjector abstract fun objective9Injector(): Objective9
|
||||||
@ContributesAndroidInjector abstract fun objective10Injector(): Objective10
|
@ContributesAndroidInjector abstract fun objective10Injector(): Objective10
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,9 @@ import info.nightscout.androidaps.danaRKorean.DanaRKoreanPlugin
|
||||||
import info.nightscout.androidaps.danaRv2.DanaRv2Plugin
|
import info.nightscout.androidaps.danaRv2.DanaRv2Plugin
|
||||||
import info.nightscout.androidaps.danar.DanaRPlugin
|
import info.nightscout.androidaps.danar.DanaRPlugin
|
||||||
import info.nightscout.androidaps.danars.DanaRSPlugin
|
import info.nightscout.androidaps.danars.DanaRSPlugin
|
||||||
|
import info.nightscout.androidaps.diaconn.DiaconnG8Plugin
|
||||||
import info.nightscout.androidaps.interfaces.PluginBase
|
import info.nightscout.androidaps.interfaces.PluginBase
|
||||||
|
import info.nightscout.androidaps.plugin.general.openhumans.OpenHumansUploader
|
||||||
import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin
|
import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin
|
||||||
import info.nightscout.androidaps.plugins.aps.openAPSAMA.OpenAPSAMAPlugin
|
import info.nightscout.androidaps.plugins.aps.openAPSAMA.OpenAPSAMAPlugin
|
||||||
import info.nightscout.androidaps.plugins.aps.openAPSSMB.OpenAPSSMBPlugin
|
import info.nightscout.androidaps.plugins.aps.openAPSSMB.OpenAPSSMBPlugin
|
||||||
|
@ -25,7 +27,6 @@ import info.nightscout.androidaps.plugins.general.dataBroadcaster.DataBroadcastP
|
||||||
import info.nightscout.androidaps.plugins.general.food.FoodPlugin
|
import info.nightscout.androidaps.plugins.general.food.FoodPlugin
|
||||||
import info.nightscout.androidaps.plugins.general.maintenance.MaintenancePlugin
|
import info.nightscout.androidaps.plugins.general.maintenance.MaintenancePlugin
|
||||||
import info.nightscout.androidaps.plugins.general.nsclient.NSClientPlugin
|
import info.nightscout.androidaps.plugins.general.nsclient.NSClientPlugin
|
||||||
import info.nightscout.androidaps.plugins.general.openhumans.OpenHumansUploader
|
|
||||||
import info.nightscout.androidaps.plugins.general.overview.OverviewPlugin
|
import info.nightscout.androidaps.plugins.general.overview.OverviewPlugin
|
||||||
import info.nightscout.androidaps.plugins.general.persistentNotification.PersistentNotificationPlugin
|
import info.nightscout.androidaps.plugins.general.persistentNotification.PersistentNotificationPlugin
|
||||||
import info.nightscout.androidaps.plugins.general.smsCommunicator.SmsCommunicatorPlugin
|
import info.nightscout.androidaps.plugins.general.smsCommunicator.SmsCommunicatorPlugin
|
||||||
|
@ -41,13 +42,11 @@ 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
|
||||||
import info.nightscout.androidaps.plugins.pump.medtronic.MedtronicPumpPlugin
|
import info.nightscout.androidaps.plugins.pump.medtronic.MedtronicPumpPlugin
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.eros.OmnipodErosPumpPlugin
|
|
||||||
import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpPlugin
|
import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpPlugin
|
||||||
import info.nightscout.androidaps.plugins.sensitivity.SensitivityAAPSPlugin
|
import info.nightscout.androidaps.plugins.sensitivity.SensitivityAAPSPlugin
|
||||||
import info.nightscout.androidaps.plugins.sensitivity.SensitivityOref1Plugin
|
import info.nightscout.androidaps.plugins.sensitivity.SensitivityOref1Plugin
|
||||||
import info.nightscout.androidaps.plugins.sensitivity.SensitivityWeightedAveragePlugin
|
import info.nightscout.androidaps.plugins.sensitivity.SensitivityWeightedAveragePlugin
|
||||||
import info.nightscout.androidaps.plugins.source.*
|
import info.nightscout.androidaps.plugins.source.*
|
||||||
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin
|
|
||||||
import javax.inject.Qualifier
|
import javax.inject.Qualifier
|
||||||
|
|
||||||
@Module
|
@Module
|
||||||
|
@ -149,11 +148,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
|
||||||
|
@ -161,6 +160,12 @@ abstract class PluginsModule {
|
||||||
// @IntKey(155)
|
// @IntKey(155)
|
||||||
// abstract fun bindOmnipodPumpPlugin(plugin: OmnipodErosPumpPlugin): PluginBase
|
// abstract fun bindOmnipodPumpPlugin(plugin: OmnipodErosPumpPlugin): PluginBase
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
@PumpDriver
|
||||||
|
@IntoMap
|
||||||
|
@IntKey(155)
|
||||||
|
abstract fun bindDiaconnG8Plugin(plugin: DiaconnG8Plugin): PluginBase
|
||||||
|
|
||||||
@Binds
|
@Binds
|
||||||
@NotNSClient
|
@NotNSClient
|
||||||
@IntoMap
|
@IntoMap
|
||||||
|
@ -203,12 +208,6 @@ abstract class PluginsModule {
|
||||||
@IntKey(250)
|
@IntKey(250)
|
||||||
abstract fun bindAutomationPlugin(plugin: AutomationPlugin): PluginBase
|
abstract fun bindAutomationPlugin(plugin: AutomationPlugin): PluginBase
|
||||||
|
|
||||||
@Binds
|
|
||||||
@AllConfigs
|
|
||||||
@IntoMap
|
|
||||||
@IntKey(260)
|
|
||||||
abstract fun bindTreatmentsPlugin(plugin: TreatmentsPlugin): PluginBase
|
|
||||||
|
|
||||||
@Binds
|
@Binds
|
||||||
@AllConfigs
|
@AllConfigs
|
||||||
@IntoMap
|
@IntoMap
|
||||||
|
@ -347,6 +346,12 @@ abstract class PluginsModule {
|
||||||
// @IntKey(480)
|
// @IntKey(480)
|
||||||
// abstract fun bindOpenHumansPlugin(plugin: OpenHumansUploader): PluginBase
|
// abstract fun bindOpenHumansPlugin(plugin: OpenHumansUploader): PluginBase
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
@NotNSClient
|
||||||
|
@IntoMap
|
||||||
|
@IntKey(480)
|
||||||
|
abstract fun bindsOpenHumansPlugin(plugin: OpenHumansUploader): PluginBase
|
||||||
|
|
||||||
@Binds
|
@Binds
|
||||||
@AllConfigs
|
@AllConfigs
|
||||||
@IntoMap
|
@IntoMap
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -191,7 +191,7 @@ class FillDialog : DialogFragmentWithDate() {
|
||||||
commandQueue.bolus(detailedBolusInfo, object : Callback() {
|
commandQueue.bolus(detailedBolusInfo, object : Callback() {
|
||||||
override fun run() {
|
override fun run() {
|
||||||
if (!result.success) {
|
if (!result.success) {
|
||||||
ErrorHelperActivity.runAlarm(ctx, result.comment, resourceHelper.gs(R.string.treatmentdeliveryerror), info.nightscout.androidaps.dana.R.raw.boluserror)
|
ErrorHelperActivity.runAlarm(ctx, result.comment, resourceHelper.gs(R.string.treatmentdeliveryerror), R.raw.boluserror)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -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,
|
||||||
|
@ -224,7 +224,7 @@ class InsulinDialog : DialogFragmentWithDate() {
|
||||||
commandQueue.bolus(detailedBolusInfo, object : Callback() {
|
commandQueue.bolus(detailedBolusInfo, object : Callback() {
|
||||||
override fun run() {
|
override fun run() {
|
||||||
if (!result.success) {
|
if (!result.success) {
|
||||||
ErrorHelperActivity.runAlarm(ctx, result.comment, resourceHelper.gs(R.string.treatmentdeliveryerror), info.nightscout.androidaps.dana.R.raw.boluserror)
|
ErrorHelperActivity.runAlarm(ctx, result.comment, resourceHelper.gs(R.string.treatmentdeliveryerror), R.raw.boluserror)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -3,6 +3,7 @@ package info.nightscout.androidaps.dialogs
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.os.Handler
|
import android.os.Handler
|
||||||
|
import android.os.Looper
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
|
@ -12,9 +13,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 +34,14 @@ 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.plugins.constraints.objectives.ObjectivesPlugin
|
||||||
|
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,19 +59,27 @@ 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
|
||||||
|
@Inject lateinit var objectivePlugin: ObjectivesPlugin
|
||||||
|
|
||||||
private var showOkCancel: Boolean = true
|
private var showOkCancel: Boolean = true
|
||||||
private var _binding: DialogLoopBinding? = null
|
private var _binding: DialogLoopBinding? = null
|
||||||
private var loopHandler = Handler()
|
private var loopHandler = Handler(Looper.getMainLooper())
|
||||||
private var refreshDialog: Runnable? = null
|
private lateinit var refreshDialog: Runnable
|
||||||
|
|
||||||
// This property is only valid between onCreateView and
|
// This property is only valid between onCreateView and
|
||||||
// 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
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onSaveInstanceState(savedInstanceState: Bundle) {
|
override fun onSaveInstanceState(savedInstanceState: Bundle) {
|
||||||
|
@ -118,6 +137,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
|
||||||
|
@ -141,21 +161,74 @@ class LoopDialog : DaggerDialogFragment() {
|
||||||
aapsLogger.debug("UpdateGUI from $from")
|
aapsLogger.debug("UpdateGUI from $from")
|
||||||
val pumpDescription: PumpDescription = activePlugin.activePump.pumpDescription
|
val pumpDescription: PumpDescription = activePlugin.activePump.pumpDescription
|
||||||
val closedLoopAllowed = constraintChecker.isClosedLoopAllowed(Constraint(true))
|
val closedLoopAllowed = constraintChecker.isClosedLoopAllowed(Constraint(true))
|
||||||
|
val closedLoopAllowed2 = objectivePlugin.objectives[ObjectivesPlugin.MAXIOB_OBJECTIVE].isCompleted
|
||||||
val lgsEnabled = constraintChecker.isLgsAllowed(Constraint(true))
|
val lgsEnabled = constraintChecker.isLgsAllowed(Constraint(true))
|
||||||
val apsMode = sp.getString(R.string.key_aps_mode, "open")
|
val apsMode = sp.getString(R.string.key_aps_mode, "open")
|
||||||
if (profileFunction.isProfileValid("LoopDialogUpdateGUI")) {
|
val pump = activePlugin.activePump
|
||||||
if (loopPlugin.isEnabled(PluginType.LOOP)) {
|
|
||||||
|
binding.overviewDisconnect15m.visibility = pumpDescription.tempDurationStep15mAllowed.toVisibility()
|
||||||
|
binding.overviewDisconnect30m.visibility = pumpDescription.tempDurationStep30mAllowed.toVisibility()
|
||||||
when {
|
when {
|
||||||
closedLoopAllowed.value() -> {
|
pump.isSuspended() -> {
|
||||||
binding.overviewCloseloop.visibility = (apsMode != "closed").toVisibility()
|
binding.overviewLoop.visibility = View.GONE
|
||||||
binding.overviewLgsloop.visibility = (apsMode != "lgs").toVisibility()
|
binding.overviewSuspend.visibility = View.GONE
|
||||||
binding.overviewOpenloop.visibility = (apsMode != "open").toVisibility()
|
binding.overviewPump.visibility = View.GONE
|
||||||
}
|
}
|
||||||
|
|
||||||
lgsEnabled.value() -> {
|
!profileFunction.isProfileValid("LoopDialogUpdateGUI") -> {
|
||||||
|
binding.overviewLoop.visibility = View.GONE
|
||||||
|
binding.overviewSuspend.visibility = View.GONE
|
||||||
|
binding.overviewPump.visibility = View.GONE
|
||||||
|
}
|
||||||
|
|
||||||
|
loopPlugin.isDisconnected -> {
|
||||||
|
binding.overviewLoop.visibility = View.GONE
|
||||||
|
binding.overviewSuspend.visibility = View.GONE
|
||||||
|
binding.overviewPump.visibility = View.VISIBLE
|
||||||
|
binding.overviewPumpHeader.text = resourceHelper.gs(R.string.reconnect)
|
||||||
|
binding.overviewDisconnectButtons.visibility = View.VISIBLE
|
||||||
|
binding.overviewReconnect.visibility = View.VISIBLE
|
||||||
|
}
|
||||||
|
|
||||||
|
!loopPlugin.isEnabled(PluginType.LOOP) -> {
|
||||||
|
binding.overviewLoop.visibility = View.VISIBLE
|
||||||
|
binding.overviewEnable.visibility = View.VISIBLE
|
||||||
|
binding.overviewDisable.visibility = View.GONE
|
||||||
|
binding.overviewSuspend.visibility = View.GONE
|
||||||
|
binding.overviewPump.visibility = View.VISIBLE
|
||||||
|
binding.overviewReconnect.visibility = View.GONE
|
||||||
|
}
|
||||||
|
|
||||||
|
loopPlugin.isSuspended -> {
|
||||||
|
binding.overviewLoop.visibility = View.GONE
|
||||||
|
binding.overviewSuspend.visibility = View.VISIBLE
|
||||||
|
binding.overviewSuspendHeader.text = resourceHelper.gs(R.string.resumeloop)
|
||||||
|
binding.overviewSuspendButtons.visibility = View.VISIBLE
|
||||||
|
binding.overviewResume.visibility = View.VISIBLE
|
||||||
|
binding.overviewPump.visibility = View.GONE
|
||||||
|
binding.overviewReconnect.visibility = View.GONE
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> {
|
||||||
|
binding.overviewLoop.visibility = View.VISIBLE
|
||||||
|
binding.overviewEnable.visibility = View.GONE
|
||||||
|
when {
|
||||||
|
apsMode == "closed" -> {
|
||||||
binding.overviewCloseloop.visibility = View.GONE
|
binding.overviewCloseloop.visibility = View.GONE
|
||||||
binding.overviewLgsloop.visibility = (apsMode != "lgs").toVisibility()
|
binding.overviewLgsloop.visibility = View.VISIBLE
|
||||||
binding.overviewOpenloop.visibility = (apsMode != "open").toVisibility()
|
binding.overviewOpenloop.visibility = View.VISIBLE
|
||||||
|
}
|
||||||
|
|
||||||
|
apsMode == "lgs" -> {
|
||||||
|
binding.overviewCloseloop.visibility = closedLoopAllowed.value().toVisibility() //show Close loop button only if Close loop allowed
|
||||||
|
binding.overviewLgsloop.visibility = View.GONE
|
||||||
|
binding.overviewOpenloop.visibility = View.VISIBLE
|
||||||
|
}
|
||||||
|
|
||||||
|
apsMode == "open" -> {
|
||||||
|
binding.overviewCloseloop.visibility = closedLoopAllowed2.toVisibility() //show CloseLoop button only if Objective 6 is completed (closedLoopAllowed always false in open loop mode)
|
||||||
|
binding.overviewLgsloop.visibility = lgsEnabled.value().toVisibility()
|
||||||
|
binding.overviewOpenloop.visibility = View.GONE
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> {
|
else -> {
|
||||||
|
@ -164,49 +237,18 @@ class LoopDialog : DaggerDialogFragment() {
|
||||||
binding.overviewOpenloop.visibility = View.GONE
|
binding.overviewOpenloop.visibility = View.GONE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
binding.overviewEnable.visibility = View.GONE
|
binding.overviewSuspend.visibility = View.VISIBLE
|
||||||
binding.overviewDisable.visibility = View.VISIBLE
|
|
||||||
if (!loopPlugin.isSuspended) {
|
|
||||||
binding.overviewSuspendHeader.text = resourceHelper.gs(R.string.suspendloop)
|
binding.overviewSuspendHeader.text = resourceHelper.gs(R.string.suspendloop)
|
||||||
binding.overviewResume.visibility = View.GONE
|
|
||||||
binding.overviewSuspendButtons.visibility = View.VISIBLE
|
binding.overviewSuspendButtons.visibility = View.VISIBLE
|
||||||
binding.overviewSuspend.visibility = View.VISIBLE
|
binding.overviewResume.visibility = View.GONE
|
||||||
} else {
|
|
||||||
if (!loopPlugin.isDisconnected) {
|
binding.overviewPump.visibility = View.VISIBLE
|
||||||
binding.overviewSuspendHeader.text = resourceHelper.gs(R.string.resumeloop)
|
|
||||||
binding.overviewResume.visibility = View.VISIBLE
|
|
||||||
binding.overviewSuspendButtons.visibility = View.GONE
|
|
||||||
binding.overviewSuspend.visibility = View.VISIBLE
|
|
||||||
} else
|
|
||||||
binding.overviewSuspend.visibility = View.GONE
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
binding.overviewEnable.visibility = View.VISIBLE
|
|
||||||
binding.overviewDisable.visibility = View.GONE
|
|
||||||
binding.overviewSuspend.visibility = View.GONE
|
|
||||||
}
|
|
||||||
if (!loopPlugin.isDisconnected) {
|
|
||||||
binding.overviewPumpHeader.text = resourceHelper.gs(R.string.disconnectpump)
|
binding.overviewPumpHeader.text = resourceHelper.gs(R.string.disconnectpump)
|
||||||
binding.overviewDisconnect15m.visibility = pumpDescription.tempDurationStep15mAllowed.toVisibility()
|
|
||||||
binding.overviewDisconnect30m.visibility = pumpDescription.tempDurationStep30mAllowed.toVisibility()
|
|
||||||
binding.overviewDisconnectButtons.visibility = View.VISIBLE
|
binding.overviewDisconnectButtons.visibility = View.VISIBLE
|
||||||
binding.overviewReconnect.visibility = View.GONE
|
binding.overviewReconnect.visibility = View.GONE
|
||||||
} else {
|
|
||||||
binding.overviewPumpHeader.text = resourceHelper.gs(R.string.reconnect)
|
|
||||||
binding.overviewDisconnectButtons.visibility = View.GONE
|
|
||||||
binding.overviewReconnect.visibility = View.VISIBLE
|
|
||||||
}
|
|
||||||
binding.overviewLoop.visibility = (!loopPlugin.isSuspended && !loopPlugin.isDisconnected).toVisibility()
|
|
||||||
}
|
|
||||||
val profile = profileFunction.getProfile()
|
|
||||||
val profileStore = activePlugin.activeProfileSource.profile
|
|
||||||
|
|
||||||
if (profile == null || profileStore == null) {
|
|
||||||
ToastUtils.showToastInUiThread(ctx, resourceHelper.gs(R.string.noprofile))
|
|
||||||
dismiss()
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun onClickOkCancelEnabled(v: View): Boolean {
|
private fun onClickOkCancelEnabled(v: View): Boolean {
|
||||||
|
@ -238,7 +280,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)
|
||||||
|
@ -266,7 +307,7 @@ class LoopDialog : DaggerDialogFragment() {
|
||||||
loopPlugin.setPluginEnabled(PluginType.LOOP, false)
|
loopPlugin.setPluginEnabled(PluginType.LOOP, false)
|
||||||
loopPlugin.setFragmentVisible(PluginType.LOOP, false)
|
loopPlugin.setFragmentVisible(PluginType.LOOP, false)
|
||||||
configBuilder.storeSettings("DisablingLoop")
|
configBuilder.storeSettings("DisablingLoop")
|
||||||
rxBus.send(EventRefreshOverview("suspendmenu"))
|
rxBus.send(EventRefreshOverview("suspend_menu"))
|
||||||
commandQueue.cancelTempBasal(true, object : Callback() {
|
commandQueue.cancelTempBasal(true, object : Callback() {
|
||||||
override fun run() {
|
override fun run() {
|
||||||
if (!result.success) {
|
if (!result.success) {
|
||||||
|
@ -274,7 +315,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,88 +330,106 @@ class LoopDialog : DaggerDialogFragment() {
|
||||||
loopPlugin.setPluginEnabled(PluginType.LOOP, true)
|
loopPlugin.setPluginEnabled(PluginType.LOOP, true)
|
||||||
loopPlugin.setFragmentVisible(PluginType.LOOP, true)
|
loopPlugin.setFragmentVisible(PluginType.LOOP, true)
|
||||||
configBuilder.storeSettings("EnablingLoop")
|
configBuilder.storeSettings("EnablingLoop")
|
||||||
rxBus.send(EventRefreshOverview("suspendmenu"))
|
rxBus.send(EventRefreshOverview("suspend_menu"))
|
||||||
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()))
|
||||||
rxBus.send(EventRefreshOverview("suspendmenu"))
|
.subscribe({ result ->
|
||||||
|
result.updated.forEach { aapsLogger.debug(LTag.DATABASE, "Updated OfflineEvent $it") }
|
||||||
|
}, {
|
||||||
|
aapsLogger.error(LTag.DATABASE, "Error while saving OfflineEvent", it)
|
||||||
|
})
|
||||||
|
rxBus.send(EventRefreshOverview("suspend_menu"))
|
||||||
commandQueue.cancelTempBasal(true, object : Callback() {
|
commandQueue.cancelTempBasal(true, object : Callback() {
|
||||||
override fun run() {
|
override fun run() {
|
||||||
if (!result.success) {
|
if (!result.success) {
|
||||||
ErrorHelperActivity.runAlarm(ctx, result.comment, resourceHelper.gs(R.string.tempbasaldeliveryerror), info.nightscout.androidaps.dana.R.raw.boluserror)
|
ErrorHelperActivity.runAlarm(ctx, result.comment, resourceHelper.gs(R.string.tempbasaldeliveryerror), R.raw.boluserror)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
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)
|
loopPlugin.suspendLoop(T.hours(1).mins().toInt())
|
||||||
rxBus.send(EventRefreshOverview("suspendmenu"))
|
rxBus.send(EventRefreshOverview("suspend_menu"))
|
||||||
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)
|
loopPlugin.suspendLoop(T.hours(2).mins().toInt())
|
||||||
rxBus.send(EventRefreshOverview("suspendmenu"))
|
rxBus.send(EventRefreshOverview("suspend_menu"))
|
||||||
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)
|
loopPlugin.suspendLoop(T.hours(3).mins().toInt())
|
||||||
rxBus.send(EventRefreshOverview("suspendmenu"))
|
rxBus.send(EventRefreshOverview("suspend_menu"))
|
||||||
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)
|
loopPlugin.suspendLoop(T.hours(10).mins().toInt())
|
||||||
rxBus.send(EventRefreshOverview("suspendmenu"))
|
rxBus.send(EventRefreshOverview("suspend_menu"))
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.overview_disconnect_15m -> {
|
R.id.overview_disconnect_15m -> {
|
||||||
|
profileFunction.getProfile()?.let { profile ->
|
||||||
uel.log(Action.DISCONNECT, Sources.LoopDialog, ValueWithUnit.Minute(15))
|
uel.log(Action.DISCONNECT, Sources.LoopDialog, ValueWithUnit.Minute(15))
|
||||||
loopPlugin.disconnectPump(15, profile)
|
loopPlugin.goToZeroTemp(T.mins(15).mins().toInt(), profile, OfflineEvent.Reason.DISCONNECT_PUMP)
|
||||||
rxBus.send(EventRefreshOverview("suspendmenu"))
|
rxBus.send(EventRefreshOverview("suspend_menu"))
|
||||||
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.overview_disconnect_30m -> {
|
R.id.overview_disconnect_30m -> {
|
||||||
|
profileFunction.getProfile()?.let { profile ->
|
||||||
uel.log(Action.DISCONNECT, Sources.LoopDialog, ValueWithUnit.Minute(30))
|
uel.log(Action.DISCONNECT, Sources.LoopDialog, ValueWithUnit.Minute(30))
|
||||||
loopPlugin.disconnectPump(30, profile)
|
loopPlugin.goToZeroTemp(T.mins(30).mins().toInt(), profile, OfflineEvent.Reason.DISCONNECT_PUMP)
|
||||||
rxBus.send(EventRefreshOverview("suspendmenu"))
|
rxBus.send(EventRefreshOverview("suspend_menu"))
|
||||||
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.overview_disconnect_1h -> {
|
R.id.overview_disconnect_1h -> {
|
||||||
|
profileFunction.getProfile()?.let { profile ->
|
||||||
uel.log(Action.DISCONNECT, Sources.LoopDialog, ValueWithUnit.Hour(1))
|
uel.log(Action.DISCONNECT, Sources.LoopDialog, ValueWithUnit.Hour(1))
|
||||||
loopPlugin.disconnectPump(60, profile)
|
loopPlugin.goToZeroTemp(T.hours(1).mins().toInt(), profile, OfflineEvent.Reason.DISCONNECT_PUMP)
|
||||||
sp.putBoolean(R.string.key_objectiveusedisconnect, true)
|
rxBus.send(EventRefreshOverview("suspend_menu"))
|
||||||
rxBus.send(EventRefreshOverview("suspendmenu"))
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.overview_disconnect_2h -> {
|
R.id.overview_disconnect_2h -> {
|
||||||
|
profileFunction.getProfile()?.let { profile ->
|
||||||
uel.log(Action.DISCONNECT, Sources.LoopDialog, ValueWithUnit.Hour(2))
|
uel.log(Action.DISCONNECT, Sources.LoopDialog, ValueWithUnit.Hour(2))
|
||||||
loopPlugin.disconnectPump(120, profile)
|
loopPlugin.goToZeroTemp(T.hours(2).mins().toInt(), profile, OfflineEvent.Reason.DISCONNECT_PUMP)
|
||||||
rxBus.send(EventRefreshOverview("suspendmenu"))
|
rxBus.send(EventRefreshOverview("suspend_menu"))
|
||||||
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.overview_disconnect_3h -> {
|
R.id.overview_disconnect_3h -> {
|
||||||
|
profileFunction.getProfile()?.let { profile ->
|
||||||
uel.log(Action.DISCONNECT, Sources.LoopDialog, ValueWithUnit.Hour(3))
|
uel.log(Action.DISCONNECT, Sources.LoopDialog, ValueWithUnit.Hour(3))
|
||||||
loopPlugin.disconnectPump(180, profile)
|
loopPlugin.goToZeroTemp(T.hours(3).mins().toInt(), profile, OfflineEvent.Reason.DISCONNECT_PUMP)
|
||||||
rxBus.send(EventRefreshOverview("suspendmenu"))
|
rxBus.send(EventRefreshOverview("suspend_menu"))
|
||||||
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -378,7 +443,7 @@ class LoopDialog : DaggerDialogFragment() {
|
||||||
it.commitAllowingStateLoss()
|
it.commitAllowingStateLoss()
|
||||||
}
|
}
|
||||||
} catch (e: IllegalStateException) {
|
} catch (e: IllegalStateException) {
|
||||||
aapsLogger.debug(e.localizedMessage)
|
aapsLogger.debug(e.localizedMessage ?: e.toString())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
package info.nightscout.androidaps.dialogs
|
package info.nightscout.androidaps.dialogs
|
||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.text.Editable
|
||||||
|
import android.text.TextWatcher
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
|
@ -8,20 +10,32 @@ import android.widget.ArrayAdapter
|
||||||
import com.google.common.base.Joiner
|
import com.google.common.base.Joiner
|
||||||
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.ProfileSealed
|
||||||
import info.nightscout.androidaps.database.AppRepository
|
import info.nightscout.androidaps.database.AppRepository
|
||||||
|
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.InsertAndCancelCurrentTemporaryTargetTransaction
|
||||||
import info.nightscout.androidaps.databinding.DialogProfileswitchBinding
|
import info.nightscout.androidaps.databinding.DialogProfileswitchBinding
|
||||||
|
import info.nightscout.androidaps.extensions.toVisibility
|
||||||
import info.nightscout.androidaps.interfaces.ActivePlugin
|
import info.nightscout.androidaps.interfaces.ActivePlugin
|
||||||
|
import info.nightscout.androidaps.interfaces.Config
|
||||||
|
import info.nightscout.androidaps.interfaces.Profile
|
||||||
import info.nightscout.androidaps.interfaces.ProfileFunction
|
import info.nightscout.androidaps.interfaces.ProfileFunction
|
||||||
|
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.utils.DefaultValueHelper
|
||||||
|
import info.nightscout.androidaps.utils.HardLimits
|
||||||
import info.nightscout.androidaps.utils.HtmlHelper
|
import info.nightscout.androidaps.utils.HtmlHelper
|
||||||
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 io.reactivex.disposables.CompositeDisposable
|
import io.reactivex.disposables.CompositeDisposable
|
||||||
|
import io.reactivex.rxkotlin.plusAssign
|
||||||
import java.text.DecimalFormat
|
import java.text.DecimalFormat
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class ProfileSwitchDialog : DialogFragmentWithDate() {
|
class ProfileSwitchDialog : DialogFragmentWithDate() {
|
||||||
|
@ -31,6 +45,10 @@ class ProfileSwitchDialog : DialogFragmentWithDate() {
|
||||||
@Inject lateinit var activePlugin: ActivePlugin
|
@Inject lateinit var activePlugin: ActivePlugin
|
||||||
@Inject lateinit var repository: AppRepository
|
@Inject lateinit var repository: AppRepository
|
||||||
@Inject lateinit var uel: UserEntryLogger
|
@Inject lateinit var uel: UserEntryLogger
|
||||||
|
@Inject lateinit var config: Config
|
||||||
|
@Inject lateinit var hardLimits: HardLimits
|
||||||
|
@Inject lateinit var rxBus: RxBusWrapper
|
||||||
|
@Inject lateinit var defaultValueHelper: DefaultValueHelper
|
||||||
|
|
||||||
private var profileIndex: Int? = null
|
private var profileIndex: Int? = null
|
||||||
|
|
||||||
|
@ -42,6 +60,17 @@ class ProfileSwitchDialog : DialogFragmentWithDate() {
|
||||||
// onDestroyView.
|
// onDestroyView.
|
||||||
private val binding get() = _binding!!
|
private val binding get() = _binding!!
|
||||||
|
|
||||||
|
private val textWatcher: TextWatcher = object : TextWatcher {
|
||||||
|
override fun afterTextChanged(s: Editable) {
|
||||||
|
val isDuration = binding.duration.value > 0
|
||||||
|
val isLowerPercentage = binding.percentage.value < 100
|
||||||
|
binding.ttLayout.visibility = (isDuration && isLowerPercentage).toVisibility()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {}
|
||||||
|
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {}
|
||||||
|
}
|
||||||
|
|
||||||
override fun onSaveInstanceState(savedInstanceState: Bundle) {
|
override fun onSaveInstanceState(savedInstanceState: Bundle) {
|
||||||
super.onSaveInstanceState(savedInstanceState)
|
super.onSaveInstanceState(savedInstanceState)
|
||||||
savedInstanceState.putDouble("duration", binding.duration.value)
|
savedInstanceState.putDouble("duration", binding.duration.value)
|
||||||
|
@ -63,9 +92,11 @@ class ProfileSwitchDialog : DialogFragmentWithDate() {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
|
||||||
binding.duration.setParams(savedInstanceState?.getDouble("duration")
|
binding.duration.setParams(savedInstanceState?.getDouble("duration")
|
||||||
?: 0.0, 0.0, Constants.MAX_PROFILE_SWITCH_DURATION, 10.0, DecimalFormat("0"), false, binding.okcancel.ok)
|
?: 0.0, 0.0, Constants.MAX_PROFILE_SWITCH_DURATION, 10.0, DecimalFormat("0"), false, binding.okcancel.ok,
|
||||||
|
textWatcher)
|
||||||
binding.percentage.setParams(savedInstanceState?.getDouble("percentage")
|
binding.percentage.setParams(savedInstanceState?.getDouble("percentage")
|
||||||
?: 100.0, Constants.CPP_MIN_PERCENTAGE.toDouble(), Constants.CPP_MAX_PERCENTAGE.toDouble(), 5.0, DecimalFormat("0"), false, binding.okcancel.ok)
|
?: 100.0, Constants.CPP_MIN_PERCENTAGE.toDouble(), Constants.CPP_MAX_PERCENTAGE.toDouble(), 5.0,
|
||||||
|
DecimalFormat("0"), false, binding.okcancel.ok, textWatcher)
|
||||||
binding.timeshift.setParams(savedInstanceState?.getDouble("timeshift")
|
binding.timeshift.setParams(savedInstanceState?.getDouble("timeshift")
|
||||||
?: 0.0, Constants.CPP_MIN_TIMESHIFT.toDouble(), Constants.CPP_MAX_TIMESHIFT.toDouble(), 1.0, DecimalFormat("0"), false, binding.okcancel.ok)
|
?: 0.0, Constants.CPP_MIN_TIMESHIFT.toDouble(), Constants.CPP_MAX_TIMESHIFT.toDouble(), 1.0, DecimalFormat("0"), false, binding.okcancel.ok)
|
||||||
|
|
||||||
|
@ -97,6 +128,7 @@ class ProfileSwitchDialog : DialogFragmentWithDate() {
|
||||||
binding.reuselayout.visibility = View.GONE
|
binding.reuselayout.visibility = View.GONE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
binding.ttLayout.visibility = View.GONE
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroyView() {
|
override fun onDestroyView() {
|
||||||
|
@ -128,7 +160,16 @@ class ProfileSwitchDialog : DialogFragmentWithDate() {
|
||||||
if (eventTimeChanged)
|
if (eventTimeChanged)
|
||||||
actions.add(resourceHelper.gs(R.string.time) + ": " + dateUtil.dateAndTimeString(eventTime))
|
actions.add(resourceHelper.gs(R.string.time) + ": " + dateUtil.dateAndTimeString(eventTime))
|
||||||
|
|
||||||
|
val isTT = binding.duration.value > 0 && binding.percentage.value < 100 && binding.tt.isChecked
|
||||||
|
val target = defaultValueHelper.determineActivityTT()
|
||||||
|
val units = profileFunction.getUnits()
|
||||||
|
if (isTT)
|
||||||
|
actions.add(resourceHelper.gs(R.string.careportal_temporarytarget) + ": " + resourceHelper.gs(R.string.activity))
|
||||||
|
|
||||||
activity?.let { activity ->
|
activity?.let { activity ->
|
||||||
|
val ps = profileFunction.buildProfileSwitch(profileStore, profileName, duration, percent, timeShift, eventTime)
|
||||||
|
val validity = ProfileSealed.PS(ps).isValid(resourceHelper.gs(R.string.careportal_profileswitch), activePlugin.activePump, config, resourceHelper, rxBus, hardLimits)
|
||||||
|
if (validity.isValid)
|
||||||
OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.careportal_profileswitch), HtmlHelper.fromHtml(Joiner.on("<br/>").join(actions)), {
|
OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.careportal_profileswitch), HtmlHelper.fromHtml(Joiner.on("<br/>").join(actions)), {
|
||||||
profileFunction.createProfileSwitch(profileStore,
|
profileFunction.createProfileSwitch(profileStore,
|
||||||
profileName = profileName,
|
profileName = profileName,
|
||||||
|
@ -144,7 +185,33 @@ class ProfileSwitchDialog : DialogFragmentWithDate() {
|
||||||
ValueWithUnit.Percent(percent),
|
ValueWithUnit.Percent(percent),
|
||||||
ValueWithUnit.Hour(timeShift).takeIf { timeShift != 0 },
|
ValueWithUnit.Hour(timeShift).takeIf { timeShift != 0 },
|
||||||
ValueWithUnit.Minute(duration).takeIf { duration != 0 })
|
ValueWithUnit.Minute(duration).takeIf { duration != 0 })
|
||||||
|
if (isTT) {
|
||||||
|
disposable += repository.runTransactionForResult(
|
||||||
|
InsertAndCancelCurrentTemporaryTargetTransaction(
|
||||||
|
timestamp = eventTime,
|
||||||
|
duration = TimeUnit.MINUTES.toMillis(duration.toLong()),
|
||||||
|
reason = TemporaryTarget.Reason.ACTIVITY,
|
||||||
|
lowTarget = Profile.toMgdl(target, profileFunction.getUnits()),
|
||||||
|
highTarget = Profile.toMgdl(target, profileFunction.getUnits())
|
||||||
|
)
|
||||||
|
).subscribe({ result ->
|
||||||
|
result.inserted.forEach { aapsLogger.debug(LTag.DATABASE, "Inserted temp target $it") }
|
||||||
|
result.updated.forEach { aapsLogger.debug(LTag.DATABASE, "Updated temp target $it") }
|
||||||
|
}, {
|
||||||
|
aapsLogger.error(LTag.DATABASE, "Error while saving temporary target", it)
|
||||||
})
|
})
|
||||||
|
uel.log(Action.TT, Sources.TTDialog, ValueWithUnit.Timestamp(eventTime).takeIf { eventTimeChanged }, ValueWithUnit.TherapyEventTTReason(
|
||||||
|
TemporaryTarget.Reason.ACTIVITY), ValueWithUnit.fromGlucoseUnit(target, units.asText), ValueWithUnit.Minute(duration))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
else {
|
||||||
|
OKDialog.show(
|
||||||
|
activity,
|
||||||
|
resourceHelper.gs(R.string.careportal_profileswitch),
|
||||||
|
HtmlHelper.fromHtml(Joiner.on("<br/>").join(validity.reasons))
|
||||||
|
)
|
||||||
|
return false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
|
@ -119,7 +119,7 @@ class TempBasalDialog : DialogFragmentWithDate() {
|
||||||
val callback: Callback = object : Callback() {
|
val callback: Callback = object : Callback() {
|
||||||
override fun run() {
|
override fun run() {
|
||||||
if (!result.success) {
|
if (!result.success) {
|
||||||
ErrorHelperActivity.runAlarm(ctx, result.comment, resourceHelper.gs(R.string.tempbasaldeliveryerror), info.nightscout.androidaps.dana.R.raw.boluserror)
|
ErrorHelperActivity.runAlarm(ctx, result.comment, resourceHelper.gs(R.string.tempbasaldeliveryerror), R.raw.boluserror)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -174,7 +174,7 @@ class TreatmentDialog : DialogFragmentWithDate() {
|
||||||
commandQueue.bolus(detailedBolusInfo, object : Callback() {
|
commandQueue.bolus(detailedBolusInfo, object : Callback() {
|
||||||
override fun run() {
|
override fun run() {
|
||||||
if (!result.success) {
|
if (!result.success) {
|
||||||
ErrorHelperActivity.runAlarm(ctx, result.comment, resourceHelper.gs(R.string.treatmentdeliveryerror), info.nightscout.androidaps.dana.R.raw.boluserror)
|
ErrorHelperActivity.runAlarm(ctx, result.comment, resourceHelper.gs(R.string.treatmentdeliveryerror), R.raw.boluserror)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -384,7 +384,7 @@ class WizardDialog : DaggerDialogFragment() {
|
||||||
it.commitAllowingStateLoss()
|
it.commitAllowingStateLoss()
|
||||||
}
|
}
|
||||||
} catch (e: IllegalStateException) {
|
} catch (e: IllegalStateException) {
|
||||||
aapsLogger.debug(e.localizedMessage)
|
aapsLogger.debug(e.localizedMessage ?: "")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
package info.nightscout.androidaps.events
|
||||||
|
|
||||||
|
class EventTreatmentUpdateGui : EventUpdateGui()
|
|
@ -1,379 +0,0 @@
|
||||||
package info.nightscout.androidaps.historyBrowser
|
|
||||||
|
|
||||||
import android.app.DatePickerDialog
|
|
||||||
import android.graphics.Color
|
|
||||||
import android.os.Bundle
|
|
||||||
import android.util.DisplayMetrics
|
|
||||||
import android.view.ViewGroup
|
|
||||||
import android.widget.LinearLayout
|
|
||||||
import android.widget.RelativeLayout
|
|
||||||
import android.widget.TextView
|
|
||||||
import androidx.lifecycle.lifecycleScope
|
|
||||||
import com.jjoe64.graphview.GraphView
|
|
||||||
import dagger.android.HasAndroidInjector
|
|
||||||
import info.nightscout.androidaps.R
|
|
||||||
import info.nightscout.androidaps.activities.NoSplashAppCompatActivity
|
|
||||||
import info.nightscout.androidaps.databinding.ActivityHistorybrowseBinding
|
|
||||||
import info.nightscout.androidaps.events.EventAutosensCalculationFinished
|
|
||||||
import info.nightscout.androidaps.events.EventCustomCalculationFinished
|
|
||||||
import info.nightscout.androidaps.events.EventRefreshOverview
|
|
||||||
import info.nightscout.androidaps.extensions.toVisibility
|
|
||||||
import info.nightscout.androidaps.interfaces.ActivePlugin
|
|
||||||
import info.nightscout.androidaps.interfaces.ProfileFunction
|
|
||||||
import info.nightscout.androidaps.logging.AAPSLogger
|
|
||||||
import info.nightscout.androidaps.logging.LTag
|
|
||||||
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
|
||||||
import info.nightscout.androidaps.plugins.general.overview.OverviewMenus
|
|
||||||
import info.nightscout.androidaps.plugins.general.overview.graphData.GraphData
|
|
||||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventIobCalculationProgress
|
|
||||||
import info.nightscout.androidaps.utils.DateUtil
|
|
||||||
import info.nightscout.androidaps.utils.DefaultValueHelper
|
|
||||||
import info.nightscout.androidaps.utils.FabricPrivacy
|
|
||||||
import info.nightscout.androidaps.utils.T
|
|
||||||
import info.nightscout.androidaps.utils.buildHelper.BuildHelper
|
|
||||||
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
|
||||||
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
|
||||||
import io.reactivex.disposables.CompositeDisposable
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import kotlinx.coroutines.withContext
|
|
||||||
import java.util.*
|
|
||||||
import javax.inject.Inject
|
|
||||||
|
|
||||||
class HistoryBrowseActivity : NoSplashAppCompatActivity() {
|
|
||||||
|
|
||||||
@Inject lateinit var injector: HasAndroidInjector
|
|
||||||
@Inject lateinit var aapsLogger: AAPSLogger
|
|
||||||
@Inject lateinit var aapsSchedulers: AapsSchedulers
|
|
||||||
@Inject lateinit var rxBus: RxBusWrapper
|
|
||||||
@Inject lateinit var sp: SP
|
|
||||||
@Inject lateinit var profileFunction: ProfileFunction
|
|
||||||
@Inject lateinit var defaultValueHelper: DefaultValueHelper
|
|
||||||
@Inject lateinit var iobCobCalculatorPluginHistory: IobCobCalculatorPluginHistory
|
|
||||||
@Inject lateinit var activePlugin: ActivePlugin
|
|
||||||
@Inject lateinit var buildHelper: BuildHelper
|
|
||||||
@Inject lateinit var fabricPrivacy: FabricPrivacy
|
|
||||||
@Inject lateinit var overviewMenus: OverviewMenus
|
|
||||||
@Inject lateinit var dateUtil: DateUtil
|
|
||||||
|
|
||||||
private val disposable = CompositeDisposable()
|
|
||||||
|
|
||||||
private val secondaryGraphs = ArrayList<GraphView>()
|
|
||||||
private val secondaryGraphsLabel = ArrayList<TextView>()
|
|
||||||
|
|
||||||
private var axisWidth: Int = 0
|
|
||||||
private var rangeToDisplay = 24 // for graph
|
|
||||||
private var start: Long = 0
|
|
||||||
|
|
||||||
private val graphLock = Object()
|
|
||||||
|
|
||||||
private var eventCustomCalculationFinished = EventCustomCalculationFinished()
|
|
||||||
|
|
||||||
private lateinit var binding: ActivityHistorybrowseBinding
|
|
||||||
private var destroyed = false
|
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
|
||||||
super.onCreate(savedInstanceState)
|
|
||||||
binding = ActivityHistorybrowseBinding.inflate(layoutInflater)
|
|
||||||
setContentView(binding.root)
|
|
||||||
|
|
||||||
binding.left.setOnClickListener {
|
|
||||||
start -= T.hours(rangeToDisplay.toLong()).msecs()
|
|
||||||
runCalculation("onClickLeft")
|
|
||||||
}
|
|
||||||
binding.right.setOnClickListener {
|
|
||||||
start += T.hours(rangeToDisplay.toLong()).msecs()
|
|
||||||
runCalculation("onClickRight")
|
|
||||||
}
|
|
||||||
binding.end.setOnClickListener {
|
|
||||||
val calendar = Calendar.getInstance()
|
|
||||||
calendar.timeInMillis = System.currentTimeMillis()
|
|
||||||
calendar[Calendar.MILLISECOND] = 0
|
|
||||||
calendar[Calendar.SECOND] = 0
|
|
||||||
calendar[Calendar.MINUTE] = 0
|
|
||||||
calendar[Calendar.HOUR_OF_DAY] = 0
|
|
||||||
start = calendar.timeInMillis
|
|
||||||
runCalculation("onClickEnd")
|
|
||||||
}
|
|
||||||
binding.zoom.setOnClickListener {
|
|
||||||
rangeToDisplay += 6
|
|
||||||
rangeToDisplay = if (rangeToDisplay > 24) 6 else rangeToDisplay
|
|
||||||
updateGUI("rangeChange", false)
|
|
||||||
}
|
|
||||||
binding.zoom.setOnLongClickListener {
|
|
||||||
val calendar = Calendar.getInstance()
|
|
||||||
calendar.timeInMillis = start
|
|
||||||
calendar[Calendar.MILLISECOND] = 0
|
|
||||||
calendar[Calendar.SECOND] = 0
|
|
||||||
calendar[Calendar.MINUTE] = 0
|
|
||||||
calendar[Calendar.HOUR_OF_DAY] = 0
|
|
||||||
start = calendar.timeInMillis
|
|
||||||
runCalculation("onLongClickZoom")
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
// create an OnDateSetListener
|
|
||||||
val dateSetListener = DatePickerDialog.OnDateSetListener { _, year, monthOfYear, dayOfMonth ->
|
|
||||||
val cal = Calendar.getInstance()
|
|
||||||
cal.timeInMillis = start
|
|
||||||
cal[Calendar.YEAR] = year
|
|
||||||
cal[Calendar.MONTH] = monthOfYear
|
|
||||||
cal[Calendar.DAY_OF_MONTH] = dayOfMonth
|
|
||||||
cal[Calendar.MILLISECOND] = 0
|
|
||||||
cal[Calendar.SECOND] = 0
|
|
||||||
cal[Calendar.MINUTE] = 0
|
|
||||||
cal[Calendar.HOUR_OF_DAY] = 0
|
|
||||||
start = cal.timeInMillis
|
|
||||||
binding.date.text = dateUtil.dateAndTimeString(start)
|
|
||||||
runCalculation("onClickDate")
|
|
||||||
}
|
|
||||||
|
|
||||||
binding.date.setOnClickListener {
|
|
||||||
val cal = Calendar.getInstance()
|
|
||||||
cal.timeInMillis = start
|
|
||||||
DatePickerDialog(this, dateSetListener,
|
|
||||||
cal.get(Calendar.YEAR),
|
|
||||||
cal.get(Calendar.MONTH),
|
|
||||||
cal.get(Calendar.DAY_OF_MONTH)
|
|
||||||
).show()
|
|
||||||
}
|
|
||||||
|
|
||||||
val dm = DisplayMetrics()
|
|
||||||
windowManager?.defaultDisplay?.getMetrics(dm)
|
|
||||||
|
|
||||||
axisWidth = if (dm.densityDpi <= 120) 3 else if (dm.densityDpi <= 160) 10 else if (dm.densityDpi <= 320) 35 else if (dm.densityDpi <= 420) 50 else if (dm.densityDpi <= 560) 70 else 80
|
|
||||||
binding.bggraph.gridLabelRenderer?.gridColor = resourceHelper.gc(R.color.graphgrid)
|
|
||||||
binding.bggraph.gridLabelRenderer?.reloadStyles()
|
|
||||||
binding.bggraph.gridLabelRenderer?.labelVerticalWidth = axisWidth
|
|
||||||
|
|
||||||
overviewMenus.setupChartMenu(binding.chartMenuButton)
|
|
||||||
prepareGraphsIfNeeded(overviewMenus.setting.size)
|
|
||||||
savedInstanceState?.let { bundle ->
|
|
||||||
rangeToDisplay = bundle.getInt("rangeToDisplay", 0)
|
|
||||||
start = bundle.getLong("start", 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public override fun onPause() {
|
|
||||||
super.onPause()
|
|
||||||
disposable.clear()
|
|
||||||
iobCobCalculatorPluginHistory.stopCalculation("onPause")
|
|
||||||
}
|
|
||||||
|
|
||||||
@Synchronized
|
|
||||||
override fun onDestroy() {
|
|
||||||
destroyed = true
|
|
||||||
super.onDestroy()
|
|
||||||
}
|
|
||||||
|
|
||||||
public override fun onResume() {
|
|
||||||
super.onResume()
|
|
||||||
disposable.add(rxBus
|
|
||||||
.toObservable(EventAutosensCalculationFinished::class.java)
|
|
||||||
.observeOn(aapsSchedulers.io)
|
|
||||||
.subscribe({
|
|
||||||
// catch only events from iobCobCalculatorPluginHistory
|
|
||||||
if (it.cause is EventCustomCalculationFinished) {
|
|
||||||
updateGUI("EventAutosensCalculationFinished", bgOnly = false)
|
|
||||||
}
|
|
||||||
}, fabricPrivacy::logException)
|
|
||||||
)
|
|
||||||
disposable.add(rxBus
|
|
||||||
.toObservable(EventIobCalculationProgress::class.java)
|
|
||||||
.observeOn(aapsSchedulers.main)
|
|
||||||
.subscribe({ binding.overviewIobcalculationprogess.text = it.progress }, fabricPrivacy::logException)
|
|
||||||
)
|
|
||||||
disposable.add(rxBus
|
|
||||||
.toObservable(EventRefreshOverview::class.java)
|
|
||||||
.observeOn(aapsSchedulers.main)
|
|
||||||
.subscribe({
|
|
||||||
if (it.now) {
|
|
||||||
updateGUI("EventRefreshOverview", bgOnly = false)
|
|
||||||
}
|
|
||||||
}, fabricPrivacy::logException)
|
|
||||||
)
|
|
||||||
if (start == 0L) {
|
|
||||||
// set start of current day
|
|
||||||
val calendar = Calendar.getInstance()
|
|
||||||
calendar.timeInMillis = System.currentTimeMillis()
|
|
||||||
calendar[Calendar.MILLISECOND] = 0
|
|
||||||
calendar[Calendar.SECOND] = 0
|
|
||||||
calendar[Calendar.MINUTE] = 0
|
|
||||||
calendar[Calendar.HOUR_OF_DAY] = 0
|
|
||||||
start = calendar.timeInMillis
|
|
||||||
runCalculation("onResume")
|
|
||||||
} else {
|
|
||||||
updateGUI("onResume", bgOnly = false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onSaveInstanceState(outState: Bundle) {
|
|
||||||
super.onSaveInstanceState(outState)
|
|
||||||
outState.putInt("rangeToDisplay", rangeToDisplay)
|
|
||||||
outState.putLong("start", start)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun prepareGraphsIfNeeded(numOfGraphs: Int) {
|
|
||||||
synchronized(graphLock) {
|
|
||||||
if (numOfGraphs != secondaryGraphs.size - 1) {
|
|
||||||
//aapsLogger.debug("New secondary graph count ${numOfGraphs-1}")
|
|
||||||
// rebuild needed
|
|
||||||
secondaryGraphs.clear()
|
|
||||||
secondaryGraphsLabel.clear()
|
|
||||||
binding.iobGraph.removeAllViews()
|
|
||||||
for (i in 1 until numOfGraphs) {
|
|
||||||
val relativeLayout = RelativeLayout(this)
|
|
||||||
relativeLayout.layoutParams = RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
|
|
||||||
|
|
||||||
val graph = GraphView(this)
|
|
||||||
graph.layoutParams = LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, resourceHelper.dpToPx(100)).also { it.setMargins(0, resourceHelper.dpToPx(15), 0, resourceHelper.dpToPx(10)) }
|
|
||||||
graph.gridLabelRenderer?.gridColor = resourceHelper.gc(R.color.graphgrid)
|
|
||||||
graph.gridLabelRenderer?.reloadStyles()
|
|
||||||
graph.gridLabelRenderer?.isHorizontalLabelsVisible = false
|
|
||||||
graph.gridLabelRenderer?.labelVerticalWidth = axisWidth
|
|
||||||
graph.gridLabelRenderer?.numVerticalLabels = 3
|
|
||||||
graph.viewport.backgroundColor = Color.argb(20, 255, 255, 255) // 8% of gray
|
|
||||||
relativeLayout.addView(graph)
|
|
||||||
|
|
||||||
val label = TextView(this)
|
|
||||||
val layoutParams = RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT).also { it.setMargins(resourceHelper.dpToPx(30), resourceHelper.dpToPx(25), 0, 0) }
|
|
||||||
layoutParams.addRule(RelativeLayout.ALIGN_PARENT_TOP)
|
|
||||||
layoutParams.addRule(RelativeLayout.ALIGN_PARENT_LEFT)
|
|
||||||
label.layoutParams = layoutParams
|
|
||||||
relativeLayout.addView(label)
|
|
||||||
secondaryGraphsLabel.add(label)
|
|
||||||
|
|
||||||
binding.iobGraph.addView(relativeLayout)
|
|
||||||
secondaryGraphs.add(graph)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun runCalculation(from: String) {
|
|
||||||
lifecycleScope.launch(Dispatchers.Default) {
|
|
||||||
val end = start + T.hours(rangeToDisplay.toLong()).msecs()
|
|
||||||
iobCobCalculatorPluginHistory.stopCalculation(from)
|
|
||||||
iobCobCalculatorPluginHistory.clearCache()
|
|
||||||
iobCobCalculatorPluginHistory.runCalculation(from, end, bgDataReload = true, limitDataToOldestAvailable = false, cause = eventCustomCalculationFinished)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Synchronized
|
|
||||||
fun updateGUI(from: String, bgOnly: Boolean) {
|
|
||||||
val menuChartSettings = overviewMenus.setting
|
|
||||||
prepareGraphsIfNeeded(menuChartSettings.size)
|
|
||||||
aapsLogger.debug(LTag.UI, "updateGUI from: $from")
|
|
||||||
val pump = activePlugin.activePump
|
|
||||||
val profile = profileFunction.getProfile()
|
|
||||||
|
|
||||||
val lowLine = defaultValueHelper.determineLowLine()
|
|
||||||
val highLine = defaultValueHelper.determineHighLine()
|
|
||||||
|
|
||||||
lifecycleScope.launch(Dispatchers.Main) {
|
|
||||||
binding.noprofile.visibility = (profile == null).toVisibility()
|
|
||||||
profile ?: return@launch
|
|
||||||
|
|
||||||
if (destroyed) return@launch
|
|
||||||
binding.date.text = dateUtil.dateAndTimeString(start)
|
|
||||||
binding.zoom.text = rangeToDisplay.toString()
|
|
||||||
val graphData = GraphData(injector, binding.bggraph)
|
|
||||||
val secondaryGraphsData: ArrayList<GraphData> = ArrayList()
|
|
||||||
|
|
||||||
// do preparation in different thread
|
|
||||||
withContext(Dispatchers.Default) {
|
|
||||||
val fromTime: Long = start + T.secs(100).msecs()
|
|
||||||
val toTime: Long = start + T.hours(rangeToDisplay.toLong()).msecs() + T.secs(100).msecs()
|
|
||||||
aapsLogger.debug(LTag.UI, "Period: " + dateUtil.dateAndTimeString(fromTime) + " - " + dateUtil.dateAndTimeString(toTime))
|
|
||||||
val pointer = System.currentTimeMillis()
|
|
||||||
|
|
||||||
// **** In range Area ****
|
|
||||||
graphData.addInRangeArea(fromTime, toTime, lowLine, highLine)
|
|
||||||
|
|
||||||
// **** BG ****
|
|
||||||
// graphData.addBgReadings(fromTime, toTime, highLine, null)
|
|
||||||
// if (buildHelper.isDev()) graphData.addBucketedData(fromTime, toTime)
|
|
||||||
|
|
||||||
// add target line
|
|
||||||
// graphData.addTargetLine(fromTime, toTime, profile, null)
|
|
||||||
|
|
||||||
// **** NOW line ****
|
|
||||||
graphData.addNowLine(pointer)
|
|
||||||
|
|
||||||
if (!bgOnly) {
|
|
||||||
// Treatments
|
|
||||||
// graphData.addTreatments(fromTime, toTime)
|
|
||||||
if (menuChartSettings[0][OverviewMenus.CharType.ACT.ordinal])
|
|
||||||
// graphData.addActivity(fromTime, toTime, false, 0.8)
|
|
||||||
|
|
||||||
// add basal data
|
|
||||||
if (pump.pumpDescription.isTempBasalCapable && menuChartSettings[0][OverviewMenus.CharType.BAS.ordinal]) {
|
|
||||||
// graphData.addBasals(fromTime, toTime, lowLine / graphData.maxY / 1.2)
|
|
||||||
}
|
|
||||||
// ------------------ 2nd graph
|
|
||||||
synchronized(graphLock) {
|
|
||||||
for (g in 0 until secondaryGraphs.size) {
|
|
||||||
val secondGraphData = GraphData(injector, secondaryGraphs[g])
|
|
||||||
var useIobForScale = false
|
|
||||||
var useCobForScale = false
|
|
||||||
var useDevForScale = false
|
|
||||||
var useRatioForScale = false
|
|
||||||
var useDSForScale = false
|
|
||||||
var useBGIForScale = false
|
|
||||||
var useABSForScale = false
|
|
||||||
when {
|
|
||||||
menuChartSettings[g + 1][OverviewMenus.CharType.IOB.ordinal] -> useIobForScale = true
|
|
||||||
menuChartSettings[g + 1][OverviewMenus.CharType.COB.ordinal] -> useCobForScale = true
|
|
||||||
menuChartSettings[g + 1][OverviewMenus.CharType.DEV.ordinal] -> useDevForScale = true
|
|
||||||
menuChartSettings[g + 1][OverviewMenus.CharType.SEN.ordinal] -> useRatioForScale = true
|
|
||||||
menuChartSettings[g + 1][OverviewMenus.CharType.BGI.ordinal] -> useBGIForScale = true
|
|
||||||
menuChartSettings[g + 1][OverviewMenus.CharType.ABS.ordinal] -> useABSForScale = true
|
|
||||||
menuChartSettings[g + 1][OverviewMenus.CharType.DEVSLOPE.ordinal] -> useDSForScale = true
|
|
||||||
}
|
|
||||||
|
|
||||||
val alignIobScale = menuChartSettings[g + 1][OverviewMenus.CharType.ABS.ordinal] && menuChartSettings[g + 1][OverviewMenus.CharType.IOB.ordinal]
|
|
||||||
val alignDevBgiScale = menuChartSettings[g + 1][OverviewMenus.CharType.DEV.ordinal] && menuChartSettings[g + 1][OverviewMenus.CharType.BGI.ordinal]
|
|
||||||
|
|
||||||
// if (menuChartSettings[g + 1][OverviewMenus.CharType.ABS.ordinal]) secondGraphData.addAbsIob(fromTime, toTime, useABSForScale, 1.0)
|
|
||||||
// if (menuChartSettings[g + 1][OverviewMenus.CharType.IOB.ordinal]) secondGraphData.addIob(fromTime, toTime, useIobForScale, 1.0, menuChartSettings[g + 1][OverviewMenus.CharType.PRE.ordinal], alignIobScale)
|
|
||||||
// if (menuChartSettings[g + 1][OverviewMenus.CharType.COB.ordinal]) secondGraphData.addCob(fromTime, toTime, useCobForScale, if (useCobForScale) 1.0 else 0.5)
|
|
||||||
// if (menuChartSettings[g + 1][OverviewMenus.CharType.DEV.ordinal]) secondGraphData.addDeviations(fromTime, toTime, useDevForScale, 1.0, alignDevBgiScale)
|
|
||||||
// if (menuChartSettings[g + 1][OverviewMenus.CharType.SEN.ordinal]) secondGraphData.addRatio(fromTime, toTime, useRatioForScale, 1.0)
|
|
||||||
// if (menuChartSettings[g + 1][OverviewMenus.CharType.BGI.ordinal]) secondGraphData.addMinusBGI(fromTime, toTime, useBGIForScale, if (alignDevBgiScale) 1.0 else 0.8, alignDevBgiScale)
|
|
||||||
// if (menuChartSettings[g + 1][OverviewMenus.CharType.DEVSLOPE.ordinal] && buildHelper.isDev()) secondGraphData.addDeviationSlope(fromTime, toTime, useDSForScale, 1.0)
|
|
||||||
|
|
||||||
// set manual x bounds to have nice steps
|
|
||||||
secondGraphData.formatAxis(fromTime, toTime)
|
|
||||||
secondGraphData.addNowLine(pointer)
|
|
||||||
secondaryGraphsData.add(secondGraphData)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// set manual x bounds to have nice steps
|
|
||||||
graphData.setNumVerticalLabels()
|
|
||||||
graphData.formatAxis(fromTime, toTime)
|
|
||||||
}
|
|
||||||
// finally enforce drawing of graphs in UI thread
|
|
||||||
graphData.performUpdate()
|
|
||||||
if (!bgOnly)
|
|
||||||
synchronized(graphLock) {
|
|
||||||
for (g in 0 until secondaryGraphs.size) {
|
|
||||||
secondaryGraphsLabel[g].text = overviewMenus.enabledTypes(g + 1)
|
|
||||||
secondaryGraphs[g].visibility = (!bgOnly && (
|
|
||||||
menuChartSettings[g + 1][OverviewMenus.CharType.IOB.ordinal] ||
|
|
||||||
menuChartSettings[g + 1][OverviewMenus.CharType.COB.ordinal] ||
|
|
||||||
menuChartSettings[g + 1][OverviewMenus.CharType.DEV.ordinal] ||
|
|
||||||
menuChartSettings[g + 1][OverviewMenus.CharType.SEN.ordinal] ||
|
|
||||||
menuChartSettings[g + 1][OverviewMenus.CharType.ACT.ordinal] ||
|
|
||||||
menuChartSettings[g + 1][OverviewMenus.CharType.ABS.ordinal] ||
|
|
||||||
menuChartSettings[g + 1][OverviewMenus.CharType.DEVSLOPE.ordinal]
|
|
||||||
)).toVisibility()
|
|
||||||
secondaryGraphsData[g].performUpdate()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,6 +1,6 @@
|
||||||
package info.nightscout.androidaps.plugins.aps.logger
|
package info.nightscout.androidaps.plugins.aps.logger
|
||||||
|
|
||||||
import info.nightscout.androidaps.db.StaticInjector
|
import info.nightscout.androidaps.di.StaticInjector
|
||||||
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 org.mozilla.javascript.ScriptableObject
|
import org.mozilla.javascript.ScriptableObject
|
||||||
|
|
|
@ -12,22 +12,24 @@ import androidx.core.app.NotificationCompat
|
||||||
import dagger.android.HasAndroidInjector
|
import dagger.android.HasAndroidInjector
|
||||||
import info.nightscout.androidaps.*
|
import info.nightscout.androidaps.*
|
||||||
import info.nightscout.androidaps.activities.ErrorHelperActivity
|
import info.nightscout.androidaps.activities.ErrorHelperActivity
|
||||||
|
import info.nightscout.androidaps.annotations.OpenForTesting
|
||||||
import info.nightscout.androidaps.data.DetailedBolusInfo
|
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
|
||||||
|
@ -44,7 +46,6 @@ import info.nightscout.androidaps.plugins.general.wear.events.EventWearConfirmAc
|
||||||
import info.nightscout.androidaps.plugins.general.wear.events.EventWearInitiateAction
|
import info.nightscout.androidaps.plugins.general.wear.events.EventWearInitiateAction
|
||||||
import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpPlugin
|
import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpPlugin
|
||||||
import info.nightscout.androidaps.queue.Callback
|
import info.nightscout.androidaps.queue.Callback
|
||||||
import info.nightscout.androidaps.queue.commands.Command
|
|
||||||
import info.nightscout.androidaps.receivers.ReceiverStatusStore
|
import info.nightscout.androidaps.receivers.ReceiverStatusStore
|
||||||
import info.nightscout.androidaps.utils.DateUtil
|
import info.nightscout.androidaps.utils.DateUtil
|
||||||
import info.nightscout.androidaps.utils.FabricPrivacy
|
import info.nightscout.androidaps.utils.FabricPrivacy
|
||||||
|
@ -64,8 +65,9 @@ import javax.inject.Inject
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
import kotlin.math.abs
|
import kotlin.math.abs
|
||||||
|
|
||||||
|
@OpenForTesting
|
||||||
@Singleton
|
@Singleton
|
||||||
open class LoopPlugin @Inject constructor(
|
class LoopPlugin @Inject constructor(
|
||||||
injector: HasAndroidInjector,
|
injector: HasAndroidInjector,
|
||||||
aapsLogger: AAPSLogger,
|
aapsLogger: AAPSLogger,
|
||||||
private val aapsSchedulers: AapsSchedulers,
|
private val aapsSchedulers: AapsSchedulers,
|
||||||
|
@ -96,7 +98,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
|
||||||
|
@ -158,48 +160,21 @@ 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) {
|
||||||
suspendTo(0L)
|
setPluginEnabled(PluginType.LOOP, value)
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val isLGS: Boolean
|
val isLGS: Boolean
|
||||||
get() {
|
get() {
|
||||||
val closedLoopEnabled = constraintChecker.isClosedLoopAllowed()
|
val closedLoopEnabled = constraintChecker.isClosedLoopAllowed()
|
||||||
|
@ -211,30 +186,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")
|
||||||
|
@ -251,6 +212,17 @@ open class LoopPlugin @Inject constructor(
|
||||||
invoke(initiator, allowNotification, false)
|
invoke(initiator, allowNotification, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Synchronized
|
||||||
|
fun isEmptyQueue(): Boolean {
|
||||||
|
val maxMinutes = 2L
|
||||||
|
val start = dateUtil.now()
|
||||||
|
while (start + T.mins(maxMinutes).msecs() > dateUtil.now()) {
|
||||||
|
if (commandQueue.size() == 0 && commandQueue.performing() == null) return true
|
||||||
|
SystemClock.sleep(100)
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
@Synchronized
|
@Synchronized
|
||||||
operator fun invoke(initiator: String, allowNotification: Boolean, tempBasalFallback: Boolean) {
|
operator fun invoke(initiator: String, allowNotification: Boolean, tempBasalFallback: Boolean) {
|
||||||
try {
|
try {
|
||||||
|
@ -289,6 +261,12 @@ open class LoopPlugin @Inject constructor(
|
||||||
return
|
return
|
||||||
} else rxBus.send(EventLoopInvoked())
|
} else rxBus.send(EventLoopInvoked())
|
||||||
|
|
||||||
|
if (!isEmptyQueue()) {
|
||||||
|
aapsLogger.debug(LTag.APS, resourceHelper.gs(R.string.pumpbusy))
|
||||||
|
rxBus.send(EventLoopSetLastRunGui(resourceHelper.gs(R.string.pumpbusy)))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// Prepare for pumps using % basals
|
// Prepare for pumps using % basals
|
||||||
if (pump.pumpDescription.tempBasalStyle == PumpDescription.PERCENT && allowPercentage()) {
|
if (pump.pumpDescription.tempBasalStyle == PumpDescription.PERCENT && allowPercentage()) {
|
||||||
apsResult.usePercent = true
|
apsResult.usePercent = true
|
||||||
|
@ -353,15 +331,15 @@ open class LoopPlugin @Inject constructor(
|
||||||
if (sp.getBoolean(R.string.key_enable_carbs_required_alert_local, true) && sp.getBoolean(R.string.key_raise_notifications_as_android_notifications, true)) {
|
if (sp.getBoolean(R.string.key_enable_carbs_required_alert_local, true) && sp.getBoolean(R.string.key_raise_notifications_as_android_notifications, true)) {
|
||||||
val intentAction5m = Intent(context, CarbSuggestionReceiver::class.java)
|
val intentAction5m = Intent(context, CarbSuggestionReceiver::class.java)
|
||||||
intentAction5m.putExtra("ignoreDuration", 5)
|
intentAction5m.putExtra("ignoreDuration", 5)
|
||||||
val pendingIntent5m = PendingIntent.getBroadcast(context, 1, intentAction5m, PendingIntent.FLAG_UPDATE_CURRENT)
|
val pendingIntent5m = PendingIntent.getBroadcast(context, 1, intentAction5m, PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT)
|
||||||
val actionIgnore5m = NotificationCompat.Action(R.drawable.ic_notif_aaps, resourceHelper.gs(R.string.ignore5m, "Ignore 5m"), pendingIntent5m)
|
val actionIgnore5m = NotificationCompat.Action(R.drawable.ic_notif_aaps, resourceHelper.gs(R.string.ignore5m, "Ignore 5m"), pendingIntent5m)
|
||||||
val intentAction15m = Intent(context, CarbSuggestionReceiver::class.java)
|
val intentAction15m = Intent(context, CarbSuggestionReceiver::class.java)
|
||||||
intentAction15m.putExtra("ignoreDuration", 15)
|
intentAction15m.putExtra("ignoreDuration", 15)
|
||||||
val pendingIntent15m = PendingIntent.getBroadcast(context, 1, intentAction15m, PendingIntent.FLAG_UPDATE_CURRENT)
|
val pendingIntent15m = PendingIntent.getBroadcast(context, 1, intentAction15m, PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT)
|
||||||
val actionIgnore15m = NotificationCompat.Action(R.drawable.ic_notif_aaps, resourceHelper.gs(R.string.ignore15m, "Ignore 15m"), pendingIntent15m)
|
val actionIgnore15m = NotificationCompat.Action(R.drawable.ic_notif_aaps, resourceHelper.gs(R.string.ignore15m, "Ignore 15m"), pendingIntent15m)
|
||||||
val intentAction30m = Intent(context, CarbSuggestionReceiver::class.java)
|
val intentAction30m = Intent(context, CarbSuggestionReceiver::class.java)
|
||||||
intentAction30m.putExtra("ignoreDuration", 30)
|
intentAction30m.putExtra("ignoreDuration", 30)
|
||||||
val pendingIntent30m = PendingIntent.getBroadcast(context, 1, intentAction30m, PendingIntent.FLAG_UPDATE_CURRENT)
|
val pendingIntent30m = PendingIntent.getBroadcast(context, 1, intentAction30m, PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT)
|
||||||
val actionIgnore30m = NotificationCompat.Action(R.drawable.ic_notif_aaps, resourceHelper.gs(R.string.ignore30m, "Ignore 30m"), pendingIntent30m)
|
val actionIgnore30m = NotificationCompat.Action(R.drawable.ic_notif_aaps, resourceHelper.gs(R.string.ignore30m, "Ignore 30m"), pendingIntent30m)
|
||||||
val builder = NotificationCompat.Builder(context, CHANNEL_ID)
|
val builder = NotificationCompat.Builder(context, CHANNEL_ID)
|
||||||
builder.setSmallIcon(R.drawable.notif_icon)
|
builder.setSmallIcon(R.drawable.notif_icon)
|
||||||
|
@ -399,8 +377,7 @@ open class LoopPlugin @Inject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (resultAfterConstraints.isChangeRequested
|
if (resultAfterConstraints.isChangeRequested
|
||||||
&& !commandQueue.bolusInQueue()
|
&& !commandQueue.bolusInQueue()) {
|
||||||
&& !commandQueue.isRunning(Command.CommandType.BOLUS)) {
|
|
||||||
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
|
||||||
|
@ -483,7 +460,7 @@ open class LoopPlugin @Inject constructor(
|
||||||
stackBuilder.addParentStack(MainActivity::class.java)
|
stackBuilder.addParentStack(MainActivity::class.java)
|
||||||
// Adds the Intent that starts the Activity to the top of the stack
|
// Adds the Intent that starts the Activity to the top of the stack
|
||||||
stackBuilder.addNextIntent(resultIntent)
|
stackBuilder.addNextIntent(resultIntent)
|
||||||
val resultPendingIntent = stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT)
|
val resultPendingIntent = stackBuilder.getPendingIntent(0, PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT)
|
||||||
builder.setContentIntent(resultPendingIntent)
|
builder.setContentIntent(resultPendingIntent)
|
||||||
builder.setVibrate(longArrayOf(1000, 1000, 1000, 1000, 1000))
|
builder.setVibrate(longArrayOf(1000, 1000, 1000, 1000, 1000))
|
||||||
val mNotificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
val mNotificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
||||||
|
@ -642,22 +619,28 @@ 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), R.raw.boluserror)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
} 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), R.raw.boluserror)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -666,37 +649,28 @@ open class LoopPlugin @Inject constructor(
|
||||||
commandQueue.cancelExtended(object : Callback() {
|
commandQueue.cancelExtended(object : Callback() {
|
||||||
override fun run() {
|
override fun run() {
|
||||||
if (!result.success) {
|
if (!result.success) {
|
||||||
ErrorHelperActivity.runAlarm(context, result.comment, resourceHelper.gs(R.string.extendedbolusdeliveryerror), info.nightscout.androidaps.dana.R.raw.boluserror)
|
ErrorHelperActivity.runAlarm(context, result.comment, resourceHelper.gs(R.string.extendedbolusdeliveryerror), R.raw.boluserror)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
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) {
|
||||||
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), R.raw.boluserror)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
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 {
|
||||||
|
|
|
@ -17,7 +17,6 @@ import info.nightscout.androidaps.plugins.aps.logger.LoggerCallback
|
||||||
import info.nightscout.androidaps.plugins.aps.loop.ScriptReader
|
import info.nightscout.androidaps.plugins.aps.loop.ScriptReader
|
||||||
import info.nightscout.androidaps.plugins.aps.openAPSSMB.SMBDefaults
|
import info.nightscout.androidaps.plugins.aps.openAPSSMB.SMBDefaults
|
||||||
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
|
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
|
||||||
import info.nightscout.androidaps.plugins.general.openhumans.OpenHumansUploader
|
|
||||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus
|
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus
|
||||||
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
||||||
import org.json.JSONArray
|
import org.json.JSONArray
|
||||||
|
@ -40,7 +39,6 @@ class DetermineBasalAdapterAMAJS internal constructor(scriptReader: ScriptReader
|
||||||
@Inject lateinit var sp: SP
|
@Inject lateinit var sp: SP
|
||||||
@Inject lateinit var profileFunction: ProfileFunction
|
@Inject lateinit var profileFunction: ProfileFunction
|
||||||
@Inject lateinit var iobCobCalculator: IobCobCalculator
|
@Inject lateinit var iobCobCalculator: IobCobCalculator
|
||||||
@Inject lateinit var openHumansUploader: OpenHumansUploader
|
|
||||||
|
|
||||||
private val mScriptReader: ScriptReader
|
private val mScriptReader: ScriptReader
|
||||||
private var profile = JSONObject()
|
private var profile = JSONObject()
|
||||||
|
@ -116,7 +114,6 @@ class DetermineBasalAdapterAMAJS internal constructor(scriptReader: ScriptReader
|
||||||
aapsLogger.debug(LTag.APS, "Result: $result")
|
aapsLogger.debug(LTag.APS, "Result: $result")
|
||||||
try {
|
try {
|
||||||
val resultJson = JSONObject(result)
|
val resultJson = JSONObject(result)
|
||||||
openHumansUploader.enqueueAMAData(profile, glucoseStatus, iobData, mealData, currentTemp, autosensData, resultJson)
|
|
||||||
determineBasalResultAMA = DetermineBasalResultAMA(injector, jsResult, resultJson)
|
determineBasalResultAMA = DetermineBasalResultAMA(injector, jsResult, resultJson)
|
||||||
} catch (e: JSONException) {
|
} catch (e: JSONException) {
|
||||||
aapsLogger.error(LTag.APS, "Unhandled exception", e)
|
aapsLogger.error(LTag.APS, "Unhandled exception", e)
|
||||||
|
|
|
@ -58,7 +58,6 @@ class OpenAPSAMAFragment : DaggerFragment() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Synchronized
|
@Synchronized
|
||||||
@kotlin.ExperimentalStdlibApi
|
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
super.onResume()
|
super.onResume()
|
||||||
|
|
||||||
|
@ -91,7 +90,6 @@ 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 ->
|
||||||
|
|
|
@ -3,6 +3,7 @@ package info.nightscout.androidaps.plugins.aps.openAPSAMA
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import dagger.android.HasAndroidInjector
|
import dagger.android.HasAndroidInjector
|
||||||
import info.nightscout.androidaps.R
|
import info.nightscout.androidaps.R
|
||||||
|
import info.nightscout.androidaps.annotations.OpenForTesting
|
||||||
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.ValueWrapper
|
import info.nightscout.androidaps.database.ValueWrapper
|
||||||
|
@ -27,8 +28,9 @@ import org.json.JSONException
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
|
|
||||||
|
@OpenForTesting
|
||||||
@Singleton
|
@Singleton
|
||||||
open class OpenAPSAMAPlugin @Inject constructor(
|
class OpenAPSAMAPlugin @Inject constructor(
|
||||||
injector: HasAndroidInjector,
|
injector: HasAndroidInjector,
|
||||||
aapsLogger: AAPSLogger,
|
aapsLogger: AAPSLogger,
|
||||||
private val rxBus: RxBusWrapper,
|
private val rxBus: RxBusWrapper,
|
||||||
|
@ -123,11 +125,11 @@ open class OpenAPSAMAPlugin @Inject constructor(
|
||||||
maxBg = hardLimits.verifyHardLimits(tempTarget.value.highTarget, R.string.temp_target_high_target, HardLimits.VERY_HARD_LIMIT_TEMP_MAX_BG[0].toDouble(), HardLimits.VERY_HARD_LIMIT_TEMP_MAX_BG[1].toDouble())
|
maxBg = hardLimits.verifyHardLimits(tempTarget.value.highTarget, R.string.temp_target_high_target, HardLimits.VERY_HARD_LIMIT_TEMP_MAX_BG[0].toDouble(), HardLimits.VERY_HARD_LIMIT_TEMP_MAX_BG[1].toDouble())
|
||||||
targetBg = hardLimits.verifyHardLimits(tempTarget.value.target(), R.string.temp_target_value, HardLimits.VERY_HARD_LIMIT_TEMP_TARGET_BG[0].toDouble(), HardLimits.VERY_HARD_LIMIT_TEMP_TARGET_BG[1].toDouble())
|
targetBg = hardLimits.verifyHardLimits(tempTarget.value.target(), R.string.temp_target_value, HardLimits.VERY_HARD_LIMIT_TEMP_TARGET_BG[0].toDouble(), HardLimits.VERY_HARD_LIMIT_TEMP_TARGET_BG[1].toDouble())
|
||||||
}
|
}
|
||||||
if (!hardLimits.checkOnlyHardLimits(profile.dia, R.string.profile_dia, hardLimits.minDia(), hardLimits.maxDia())) return
|
if (!hardLimits.checkHardLimits(profile.dia, R.string.profile_dia, hardLimits.minDia(), hardLimits.maxDia())) return
|
||||||
if (!hardLimits.checkOnlyHardLimits(profile.getIcTimeFromMidnight(Profile.secondsFromMidnight()), R.string.profile_carbs_ratio_value, hardLimits.minIC(), hardLimits.maxIC())) return
|
if (!hardLimits.checkHardLimits(profile.getIcTimeFromMidnight(Profile.secondsFromMidnight()), R.string.profile_carbs_ratio_value, hardLimits.minIC(), hardLimits.maxIC())) return
|
||||||
if (!hardLimits.checkOnlyHardLimits(profile.getIsfMgdl(), R.string.profile_sensitivity_value, HardLimits.MIN_ISF, HardLimits.MAX_ISF)) return
|
if (!hardLimits.checkHardLimits(profile.getIsfMgdl(), R.string.profile_sensitivity_value, HardLimits.MIN_ISF, HardLimits.MAX_ISF)) return
|
||||||
if (!hardLimits.checkOnlyHardLimits(profile.getMaxDailyBasal(), R.string.profile_max_daily_basal_value, 0.02, hardLimits.maxBasal())) return
|
if (!hardLimits.checkHardLimits(profile.getMaxDailyBasal(), R.string.profile_max_daily_basal_value, 0.02, hardLimits.maxBasal())) return
|
||||||
if (!hardLimits.checkOnlyHardLimits(pump.baseBasalRate, R.string.current_basal_value, 0.01, hardLimits.maxBasal())) return
|
if (!hardLimits.checkHardLimits(pump.baseBasalRate, R.string.current_basal_value, 0.01, hardLimits.maxBasal())) return
|
||||||
startPart = System.currentTimeMillis()
|
startPart = System.currentTimeMillis()
|
||||||
if (constraintChecker.isAutosensModeEnabled().value()) {
|
if (constraintChecker.isAutosensModeEnabled().value()) {
|
||||||
val autosensData = iobCobCalculator.getLastAutosensDataWithWaitForCalculationFinish("OpenAPSPlugin")
|
val autosensData = iobCobCalculator.getLastAutosensDataWithWaitForCalculationFinish("OpenAPSPlugin")
|
||||||
|
|
|
@ -17,7 +17,6 @@ import info.nightscout.androidaps.logging.LTag
|
||||||
import info.nightscout.androidaps.plugins.aps.logger.LoggerCallback
|
import info.nightscout.androidaps.plugins.aps.logger.LoggerCallback
|
||||||
import info.nightscout.androidaps.plugins.aps.loop.ScriptReader
|
import info.nightscout.androidaps.plugins.aps.loop.ScriptReader
|
||||||
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
|
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
|
||||||
import info.nightscout.androidaps.plugins.general.openhumans.OpenHumansUploader
|
|
||||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus
|
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus
|
||||||
import info.nightscout.androidaps.utils.SafeParse
|
import info.nightscout.androidaps.utils.SafeParse
|
||||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||||
|
@ -41,7 +40,6 @@ class DetermineBasalAdapterSMBJS internal constructor(private val scriptReader:
|
||||||
@Inject lateinit var profileFunction: ProfileFunction
|
@Inject lateinit var profileFunction: ProfileFunction
|
||||||
@Inject lateinit var iobCobCalculator: IobCobCalculator
|
@Inject lateinit var iobCobCalculator: IobCobCalculator
|
||||||
@Inject lateinit var activePlugin: ActivePlugin
|
@Inject lateinit var activePlugin: ActivePlugin
|
||||||
@Inject lateinit var openHumansUploader: OpenHumansUploader
|
|
||||||
|
|
||||||
private var profile = JSONObject()
|
private var profile = JSONObject()
|
||||||
private var mGlucoseStatus = JSONObject()
|
private var mGlucoseStatus = JSONObject()
|
||||||
|
@ -129,7 +127,6 @@ class DetermineBasalAdapterSMBJS internal constructor(private val scriptReader:
|
||||||
aapsLogger.debug(LTag.APS, "Result: $result")
|
aapsLogger.debug(LTag.APS, "Result: $result")
|
||||||
try {
|
try {
|
||||||
val resultJson = JSONObject(result)
|
val resultJson = JSONObject(result)
|
||||||
openHumansUploader.enqueueSMBData(profile, mGlucoseStatus, iobData, mealData, currentTemp, autosensData, microBolusAllowed, smbAlwaysAllowed, resultJson)
|
|
||||||
determineBasalResultSMB = DetermineBasalResultSMB(injector, resultJson)
|
determineBasalResultSMB = DetermineBasalResultSMB(injector, resultJson)
|
||||||
} catch (e: JSONException) {
|
} catch (e: JSONException) {
|
||||||
aapsLogger.error(LTag.APS, "Unhandled exception", e)
|
aapsLogger.error(LTag.APS, "Unhandled exception", e)
|
||||||
|
|
|
@ -59,7 +59,6 @@ class OpenAPSSMBFragment : DaggerFragment() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Synchronized
|
@Synchronized
|
||||||
@kotlin.ExperimentalStdlibApi
|
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
super.onResume()
|
super.onResume()
|
||||||
disposable += rxBus
|
disposable += rxBus
|
||||||
|
@ -91,7 +90,6 @@ 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 ->
|
||||||
|
|
|
@ -5,6 +5,7 @@ import androidx.preference.PreferenceFragmentCompat
|
||||||
import androidx.preference.SwitchPreference
|
import androidx.preference.SwitchPreference
|
||||||
import dagger.android.HasAndroidInjector
|
import dagger.android.HasAndroidInjector
|
||||||
import info.nightscout.androidaps.R
|
import info.nightscout.androidaps.R
|
||||||
|
import info.nightscout.androidaps.annotations.OpenForTesting
|
||||||
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.extensions.target
|
import info.nightscout.androidaps.extensions.target
|
||||||
|
@ -27,8 +28,9 @@ import info.nightscout.androidaps.utils.sharedPreferences.SP
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
|
|
||||||
|
@OpenForTesting
|
||||||
@Singleton
|
@Singleton
|
||||||
open class OpenAPSSMBPlugin @Inject constructor(
|
class OpenAPSSMBPlugin @Inject constructor(
|
||||||
injector: HasAndroidInjector,
|
injector: HasAndroidInjector,
|
||||||
aapsLogger: AAPSLogger,
|
aapsLogger: AAPSLogger,
|
||||||
private val rxBus: RxBusWrapper,
|
private val rxBus: RxBusWrapper,
|
||||||
|
@ -128,11 +130,11 @@ open class OpenAPSSMBPlugin @Inject constructor(
|
||||||
maxBg = hardLimits.verifyHardLimits(tempTarget.value.highTarget, R.string.temp_target_high_target, HardLimits.VERY_HARD_LIMIT_TEMP_MAX_BG[0].toDouble(), HardLimits.VERY_HARD_LIMIT_TEMP_MAX_BG[1].toDouble())
|
maxBg = hardLimits.verifyHardLimits(tempTarget.value.highTarget, R.string.temp_target_high_target, HardLimits.VERY_HARD_LIMIT_TEMP_MAX_BG[0].toDouble(), HardLimits.VERY_HARD_LIMIT_TEMP_MAX_BG[1].toDouble())
|
||||||
targetBg = hardLimits.verifyHardLimits(tempTarget.value.target(), R.string.temp_target_value, HardLimits.VERY_HARD_LIMIT_TEMP_TARGET_BG[0].toDouble(), HardLimits.VERY_HARD_LIMIT_TEMP_TARGET_BG[1].toDouble())
|
targetBg = hardLimits.verifyHardLimits(tempTarget.value.target(), R.string.temp_target_value, HardLimits.VERY_HARD_LIMIT_TEMP_TARGET_BG[0].toDouble(), HardLimits.VERY_HARD_LIMIT_TEMP_TARGET_BG[1].toDouble())
|
||||||
}
|
}
|
||||||
if (!hardLimits.checkOnlyHardLimits(profile.dia, R.string.profile_dia, hardLimits.minDia(), hardLimits.maxDia())) return
|
if (!hardLimits.checkHardLimits(profile.dia, R.string.profile_dia, hardLimits.minDia(), hardLimits.maxDia())) return
|
||||||
if (!hardLimits.checkOnlyHardLimits(profile.getIcTimeFromMidnight(Profile.secondsFromMidnight()), R.string.profile_carbs_ratio_value, hardLimits.minIC(), hardLimits.maxIC())) return
|
if (!hardLimits.checkHardLimits(profile.getIcTimeFromMidnight(Profile.secondsFromMidnight()), R.string.profile_carbs_ratio_value, hardLimits.minIC(), hardLimits.maxIC())) return
|
||||||
if (!hardLimits.checkOnlyHardLimits(profile.getIsfMgdl(), R.string.profile_sensitivity_value, HardLimits.MIN_ISF, HardLimits.MAX_ISF)) return
|
if (!hardLimits.checkHardLimits(profile.getIsfMgdl(), R.string.profile_sensitivity_value, HardLimits.MIN_ISF, HardLimits.MAX_ISF)) return
|
||||||
if (!hardLimits.checkOnlyHardLimits(profile.getMaxDailyBasal(), R.string.profile_max_daily_basal_value, 0.02, hardLimits.maxBasal())) return
|
if (!hardLimits.checkHardLimits(profile.getMaxDailyBasal(), R.string.profile_max_daily_basal_value, 0.02, hardLimits.maxBasal())) return
|
||||||
if (!hardLimits.checkOnlyHardLimits(pump.baseBasalRate, R.string.current_basal_value, 0.01, hardLimits.maxBasal())) return
|
if (!hardLimits.checkHardLimits(pump.baseBasalRate, R.string.current_basal_value, 0.01, hardLimits.maxBasal())) return
|
||||||
startPart = System.currentTimeMillis()
|
startPart = System.currentTimeMillis()
|
||||||
if (constraintChecker.isAutosensModeEnabled().value()) {
|
if (constraintChecker.isAutosensModeEnabled().value()) {
|
||||||
val autosensData = iobCobCalculator.getLastAutosensDataWithWaitForCalculationFinish("OpenAPSPlugin")
|
val autosensData = iobCobCalculator.getLastAutosensDataWithWaitForCalculationFinish("OpenAPSPlugin")
|
||||||
|
|
|
@ -114,7 +114,6 @@ class ConfigBuilderFragment : DaggerFragment() {
|
||||||
createViewsForPlugins(R.string.configbuilder_loop, R.string.configbuilder_loop_description, PluginType.LOOP, activePlugin.getSpecificPluginsVisibleInList(PluginType.LOOP))
|
createViewsForPlugins(R.string.configbuilder_loop, R.string.configbuilder_loop_description, PluginType.LOOP, activePlugin.getSpecificPluginsVisibleInList(PluginType.LOOP))
|
||||||
createViewsForPlugins(R.string.constraints, R.string.configbuilder_constraints_description, PluginType.CONSTRAINTS, activePlugin.getSpecificPluginsVisibleInList(PluginType.CONSTRAINTS))
|
createViewsForPlugins(R.string.constraints, R.string.configbuilder_constraints_description, PluginType.CONSTRAINTS, activePlugin.getSpecificPluginsVisibleInList(PluginType.CONSTRAINTS))
|
||||||
}
|
}
|
||||||
createViewsForPlugins(R.string.configbuilder_treatments, R.string.configbuilder_treatments_description, PluginType.TREATMENT, activePlugin.getSpecificPluginsVisibleInList(PluginType.TREATMENT))
|
|
||||||
createViewsForPlugins(R.string.configbuilder_general, R.string.configbuilder_general_description, PluginType.GENERAL, activePlugin.getSpecificPluginsVisibleInList(PluginType.GENERAL))
|
createViewsForPlugins(R.string.configbuilder_general, R.string.configbuilder_general_description, PluginType.GENERAL, activePlugin.getSpecificPluginsVisibleInList(PluginType.GENERAL))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -139,22 +138,16 @@ class ConfigBuilderFragment : DaggerFragment() {
|
||||||
|
|
||||||
@Suppress("InflateParams")
|
@Suppress("InflateParams")
|
||||||
val baseView: LinearLayout = fragment.layoutInflater.inflate(R.layout.configbuilder_single_plugin, null) as LinearLayout
|
val baseView: LinearLayout = fragment.layoutInflater.inflate(R.layout.configbuilder_single_plugin, null) as LinearLayout
|
||||||
private val enabledExclusive: RadioButton
|
private val enabledExclusive: RadioButton = baseView.findViewById(R.id.plugin_enabled_exclusive)
|
||||||
private val enabledInclusive: CheckBox
|
private val enabledInclusive: CheckBox = baseView.findViewById(R.id.plugin_enabled_inclusive)
|
||||||
private val pluginIcon: ImageView
|
private val pluginIcon: ImageView = baseView.findViewById(R.id.plugin_icon)
|
||||||
private val pluginName: TextView
|
private val pluginIcon2: ImageView = baseView.findViewById(R.id.plugin_icon2)
|
||||||
private val pluginDescription: TextView
|
private val pluginName: TextView = baseView.findViewById(R.id.plugin_name)
|
||||||
private val pluginPreferences: ImageButton
|
private val pluginDescription: TextView = baseView.findViewById(R.id.plugin_description)
|
||||||
private val pluginVisibility: CheckBox
|
private val pluginPreferences: ImageButton = baseView.findViewById(R.id.plugin_preferences)
|
||||||
|
private val pluginVisibility: CheckBox = baseView.findViewById(R.id.plugin_visibility)
|
||||||
|
|
||||||
init {
|
init {
|
||||||
enabledExclusive = baseView.findViewById(R.id.plugin_enabled_exclusive)
|
|
||||||
enabledInclusive = baseView.findViewById(R.id.plugin_enabled_inclusive)
|
|
||||||
pluginIcon = baseView.findViewById(R.id.plugin_icon)
|
|
||||||
pluginName = baseView.findViewById(R.id.plugin_name)
|
|
||||||
pluginDescription = baseView.findViewById(R.id.plugin_description)
|
|
||||||
pluginPreferences = baseView.findViewById(R.id.plugin_preferences)
|
|
||||||
pluginVisibility = baseView.findViewById(R.id.plugin_visibility)
|
|
||||||
|
|
||||||
pluginVisibility.setOnClickListener {
|
pluginVisibility.setOnClickListener {
|
||||||
plugin.setFragmentVisible(pluginType, pluginVisibility.isChecked)
|
plugin.setFragmentVisible(pluginType, pluginVisibility.isChecked)
|
||||||
|
@ -192,6 +185,12 @@ class ConfigBuilderFragment : DaggerFragment() {
|
||||||
if (plugin.menuIcon != -1) {
|
if (plugin.menuIcon != -1) {
|
||||||
pluginIcon.visibility = View.VISIBLE
|
pluginIcon.visibility = View.VISIBLE
|
||||||
pluginIcon.setImageDrawable(context?.let { ContextCompat.getDrawable(it, plugin.menuIcon) })
|
pluginIcon.setImageDrawable(context?.let { ContextCompat.getDrawable(it, plugin.menuIcon) })
|
||||||
|
if (plugin.menuIcon2 != -1) {
|
||||||
|
pluginIcon2.visibility = View.VISIBLE
|
||||||
|
pluginIcon2.setImageDrawable(context?.let { ContextCompat.getDrawable(it, plugin.menuIcon2) })
|
||||||
|
} else {
|
||||||
|
pluginIcon2.visibility = View.GONE
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
pluginIcon.visibility = View.GONE
|
pluginIcon.visibility = View.GONE
|
||||||
}
|
}
|
||||||
|
|
|
@ -120,7 +120,6 @@ class ConfigBuilderPlugin @Inject constructor(
|
||||||
for (p in activePlugin.getPluginsList()) {
|
for (p in activePlugin.getPluginsList()) {
|
||||||
aapsLogger.debug(LTag.CONFIGBUILDER, p.name + ":" +
|
aapsLogger.debug(LTag.CONFIGBUILDER, p.name + ":" +
|
||||||
(if (p.isEnabled(PluginType.GENERAL)) " GENERAL" else "") +
|
(if (p.isEnabled(PluginType.GENERAL)) " GENERAL" else "") +
|
||||||
(if (p.isEnabled(PluginType.TREATMENT)) " TREATMENT" else "") +
|
|
||||||
(if (p.isEnabled(PluginType.SENSITIVITY)) " SENSITIVITY" else "") +
|
(if (p.isEnabled(PluginType.SENSITIVITY)) " SENSITIVITY" else "") +
|
||||||
(if (p.isEnabled(PluginType.PROFILE)) " PROFILE" else "") +
|
(if (p.isEnabled(PluginType.PROFILE)) " PROFILE" else "") +
|
||||||
(if (p.isEnabled(PluginType.APS)) " APS" else "") +
|
(if (p.isEnabled(PluginType.APS)) " APS" else "") +
|
||||||
|
@ -135,7 +134,12 @@ class ConfigBuilderPlugin @Inject constructor(
|
||||||
|
|
||||||
// Ask when switching to physical pump plugin
|
// Ask when switching to physical pump plugin
|
||||||
fun switchAllowed(changedPlugin: PluginBase, newState: Boolean, activity: FragmentActivity?, type: PluginType) {
|
fun switchAllowed(changedPlugin: PluginBase, newState: Boolean, activity: FragmentActivity?, type: PluginType) {
|
||||||
if (changedPlugin.getType() == PluginType.PUMP && changedPlugin.name != resourceHelper.gs(R.string.virtualpump)) confirmPumpPluginActivation(changedPlugin, newState, activity, type) else performPluginSwitch(changedPlugin, newState, type)
|
if (changedPlugin.getType() == PluginType.PUMP && changedPlugin.name != resourceHelper.gs(R.string.virtualpump))
|
||||||
|
confirmPumpPluginActivation(changedPlugin, newState, activity, type)
|
||||||
|
else if (changedPlugin.getType() == PluginType.PUMP) {
|
||||||
|
performPluginSwitch(changedPlugin, newState, type)
|
||||||
|
pumpSync.connectNewPump()
|
||||||
|
} else performPluginSwitch(changedPlugin, newState, type)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun confirmPumpPluginActivation(changedPlugin: PluginBase, newState: Boolean, activity: FragmentActivity?, type: PluginType) {
|
private fun confirmPumpPluginActivation(changedPlugin: PluginBase, newState: Boolean, activity: FragmentActivity?, type: PluginType) {
|
||||||
|
@ -185,7 +189,6 @@ class ConfigBuilderPlugin @Inject constructor(
|
||||||
PluginType.APS -> pluginsInCategory = activePlugin.getSpecificPluginsListByInterface(APS::class.java)
|
PluginType.APS -> pluginsInCategory = activePlugin.getSpecificPluginsListByInterface(APS::class.java)
|
||||||
PluginType.PROFILE -> pluginsInCategory = activePlugin.getSpecificPluginsListByInterface(ProfileSource::class.java)
|
PluginType.PROFILE -> pluginsInCategory = activePlugin.getSpecificPluginsListByInterface(ProfileSource::class.java)
|
||||||
PluginType.BGSOURCE -> pluginsInCategory = activePlugin.getSpecificPluginsListByInterface(BgSource::class.java)
|
PluginType.BGSOURCE -> pluginsInCategory = activePlugin.getSpecificPluginsListByInterface(BgSource::class.java)
|
||||||
PluginType.TREATMENT -> pluginsInCategory = activePlugin.getSpecificPluginsListByInterface(TreatmentsInterface::class.java)
|
|
||||||
PluginType.PUMP -> pluginsInCategory = activePlugin.getSpecificPluginsListByInterface(Pump::class.java)
|
PluginType.PUMP -> pluginsInCategory = activePlugin.getSpecificPluginsListByInterface(Pump::class.java)
|
||||||
|
|
||||||
else -> {
|
else -> {
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
package info.nightscout.androidaps.plugins.configBuilder
|
package info.nightscout.androidaps.plugins.configBuilder
|
||||||
|
|
||||||
import info.nightscout.androidaps.interfaces.Config
|
|
||||||
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
|
||||||
|
@ -21,7 +20,6 @@ class PluginStore @Inject constructor(
|
||||||
private var activeAPSStore: APS? = null
|
private var activeAPSStore: APS? = null
|
||||||
private var activeInsulinStore: Insulin? = null
|
private var activeInsulinStore: Insulin? = null
|
||||||
private var activeSensitivityStore: Sensitivity? = null
|
private var activeSensitivityStore: Sensitivity? = null
|
||||||
private var activeTreatmentsStore: TreatmentsInterface? = null
|
|
||||||
|
|
||||||
fun loadDefaults() {
|
fun loadDefaults() {
|
||||||
verifySelectionInCategories()
|
verifySelectionInCategories()
|
||||||
|
@ -121,16 +119,6 @@ class PluginStore @Inject constructor(
|
||||||
aapsLogger.debug(LTag.CONFIGBUILDER, "Defaulting PumpInterface")
|
aapsLogger.debug(LTag.CONFIGBUILDER, "Defaulting PumpInterface")
|
||||||
}
|
}
|
||||||
setFragmentVisibilities((activePumpStore as PluginBase).name, pluginsInCategory, PluginType.PUMP)
|
setFragmentVisibilities((activePumpStore as PluginBase).name, pluginsInCategory, PluginType.PUMP)
|
||||||
|
|
||||||
// PluginType.TREATMENT
|
|
||||||
pluginsInCategory = getSpecificPluginsList(PluginType.TREATMENT)
|
|
||||||
activeTreatmentsStore = getTheOneEnabledInArray(pluginsInCategory, PluginType.TREATMENT) as TreatmentsInterface?
|
|
||||||
if (activeTreatmentsStore == null) {
|
|
||||||
activeTreatmentsStore = getDefaultPlugin(PluginType.TREATMENT) as TreatmentsInterface
|
|
||||||
(activeTreatmentsStore as PluginBase).setPluginEnabled(PluginType.TREATMENT, true)
|
|
||||||
aapsLogger.debug(LTag.CONFIGBUILDER, "Defaulting PumpInterface")
|
|
||||||
}
|
|
||||||
setFragmentVisibilities((activeTreatmentsStore as PluginBase).name, pluginsInCategory, PluginType.TREATMENT)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setFragmentVisibilities(activePluginName: String, pluginsInCategory: ArrayList<PluginBase>,
|
private fun setFragmentVisibilities(activePluginName: String, pluginsInCategory: ArrayList<PluginBase>,
|
||||||
|
@ -175,13 +163,12 @@ class PluginStore @Inject constructor(
|
||||||
get() = activeSensitivityStore
|
get() = activeSensitivityStore
|
||||||
?: checkNotNull(activeSensitivityStore) { "No sensitivity selected" }
|
?: checkNotNull(activeSensitivityStore) { "No sensitivity selected" }
|
||||||
|
|
||||||
override val activeTreatments: TreatmentsInterface
|
|
||||||
get() = activeTreatmentsStore
|
|
||||||
?: checkNotNull(activeTreatmentsStore) { "No treatments selected" }
|
|
||||||
|
|
||||||
override val activeOverview: Overview
|
override val activeOverview: Overview
|
||||||
get() = getSpecificPluginsListByInterface(Overview::class.java).first() as Overview
|
get() = getSpecificPluginsListByInterface(Overview::class.java).first() as Overview
|
||||||
|
|
||||||
|
override val activeSafety: Safety
|
||||||
|
get() = getSpecificPluginsListByInterface(Safety::class.java).first() as Safety
|
||||||
|
|
||||||
override fun getPluginsList(): ArrayList<PluginBase> = ArrayList(plugins)
|
override fun getPluginsList(): ArrayList<PluginBase> = ArrayList(plugins)
|
||||||
|
|
||||||
}
|
}
|
|
@ -9,14 +9,12 @@ import info.nightscout.androidaps.database.ValueWrapper
|
||||||
import info.nightscout.androidaps.database.entities.ProfileSwitch
|
import info.nightscout.androidaps.database.entities.ProfileSwitch
|
||||||
import info.nightscout.androidaps.database.transactions.InsertOrUpdateProfileSwitch
|
import info.nightscout.androidaps.database.transactions.InsertOrUpdateProfileSwitch
|
||||||
import info.nightscout.androidaps.extensions.fromConstant
|
import info.nightscout.androidaps.extensions.fromConstant
|
||||||
import info.nightscout.androidaps.interfaces.ActivePlugin
|
import info.nightscout.androidaps.interfaces.*
|
||||||
import info.nightscout.androidaps.interfaces.GlucoseUnit
|
|
||||||
import info.nightscout.androidaps.interfaces.Profile
|
|
||||||
import info.nightscout.androidaps.interfaces.ProfileFunction
|
|
||||||
import info.nightscout.androidaps.interfaces.ProfileStore
|
|
||||||
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.utils.DateUtil
|
import info.nightscout.androidaps.utils.DateUtil
|
||||||
|
import info.nightscout.androidaps.utils.HardLimits
|
||||||
import info.nightscout.androidaps.utils.T
|
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
|
||||||
|
@ -30,10 +28,13 @@ import javax.inject.Singleton
|
||||||
class ProfileFunctionImplementation @Inject constructor(
|
class ProfileFunctionImplementation @Inject constructor(
|
||||||
private val aapsLogger: AAPSLogger,
|
private val aapsLogger: AAPSLogger,
|
||||||
private val sp: SP,
|
private val sp: SP,
|
||||||
|
private val rxBus: RxBusWrapper,
|
||||||
private val resourceHelper: ResourceHelper,
|
private val resourceHelper: ResourceHelper,
|
||||||
private val activePlugin: ActivePlugin,
|
private val activePlugin: ActivePlugin,
|
||||||
private val repository: AppRepository,
|
private val repository: AppRepository,
|
||||||
private val dateUtil: DateUtil
|
private val dateUtil: DateUtil,
|
||||||
|
private val config: Config,
|
||||||
|
private val hardLimits: HardLimits
|
||||||
) : ProfileFunction {
|
) : ProfileFunction {
|
||||||
|
|
||||||
val cache = LongSparseArray<Profile>()
|
val cache = LongSparseArray<Profile>()
|
||||||
|
@ -67,14 +68,15 @@ class ProfileFunctionImplementation @Inject constructor(
|
||||||
override fun getProfile(): Profile? =
|
override fun getProfile(): Profile? =
|
||||||
getProfile(dateUtil.now())
|
getProfile(dateUtil.now())
|
||||||
|
|
||||||
|
@Synchronized
|
||||||
override fun getProfile(time: Long): Profile? {
|
override fun getProfile(time: Long): Profile? {
|
||||||
val rounded = time - time % 1000
|
val rounded = time - time % 1000
|
||||||
val cached = cache[rounded]
|
val cached = cache[rounded]
|
||||||
if (cached != null) {
|
if (cached != null) {
|
||||||
// aapsLogger.debug("XXXXXXXXXXXXXXX HIT getProfile for $time $rounded")
|
// aapsLogger.debug("HIT getProfile for $time $rounded")
|
||||||
return cached
|
return cached
|
||||||
}
|
}
|
||||||
// aapsLogger.debug("XXXXXXXXXXXXXXX getProfile called for $time")
|
// aapsLogger.debug("getProfile called for $time")
|
||||||
val ps = repository.getEffectiveProfileSwitchActiveAt(time).blockingGet()
|
val ps = repository.getEffectiveProfileSwitchActiveAt(time).blockingGet()
|
||||||
if (ps is ValueWrapper.Existing) {
|
if (ps is ValueWrapper.Existing) {
|
||||||
val sealed = ProfileSealed.EPS(ps.value)
|
val sealed = ProfileSealed.EPS(ps.value)
|
||||||
|
@ -90,10 +92,10 @@ class ProfileFunctionImplementation @Inject constructor(
|
||||||
if (sp.getString(R.string.key_units, Constants.MGDL) == Constants.MGDL) GlucoseUnit.MGDL
|
if (sp.getString(R.string.key_units, Constants.MGDL) == Constants.MGDL) GlucoseUnit.MGDL
|
||||||
else GlucoseUnit.MMOL
|
else GlucoseUnit.MMOL
|
||||||
|
|
||||||
override fun createProfileSwitch(profileStore: ProfileStore, profileName: String, durationInMinutes: Int, percentage: Int, timeShiftInHours: Int, timestamp: Long) {
|
override fun buildProfileSwitch(profileStore: ProfileStore, profileName: String, durationInMinutes: Int, percentage: Int, timeShiftInHours: Int, timestamp: Long) : ProfileSwitch {
|
||||||
val pureProfile = profileStore.getSpecificProfile(profileName)
|
val pureProfile = profileStore.getSpecificProfile(profileName)
|
||||||
?: throw InvalidParameterSpecException(profileName)
|
?: throw InvalidParameterSpecException(profileName)
|
||||||
val ps = ProfileSwitch(
|
return ProfileSwitch(
|
||||||
timestamp = timestamp,
|
timestamp = timestamp,
|
||||||
basalBlocks = pureProfile.basalBlocks,
|
basalBlocks = pureProfile.basalBlocks,
|
||||||
isfBlocks = pureProfile.isfBlocks,
|
isfBlocks = pureProfile.isfBlocks,
|
||||||
|
@ -104,7 +106,14 @@ 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()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun createProfileSwitch(profileStore: ProfileStore, profileName: String, durationInMinutes: Int, percentage: Int, timeShiftInHours: Int, timestamp: Long) {
|
||||||
|
val ps = buildProfileSwitch(profileStore, profileName, durationInMinutes, percentage, timeShiftInHours, timestamp)
|
||||||
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") }
|
||||||
|
@ -114,10 +123,32 @@ class ProfileFunctionImplementation @Inject constructor(
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun createProfileSwitch(durationInMinutes: Int, percentage: Int, timeShiftInHours: Int) {
|
override fun createProfileSwitch(durationInMinutes: Int, percentage: Int, timeShiftInHours: Int): Boolean {
|
||||||
val profileStore = activePlugin.activeProfileSource.profile ?: return
|
val profile = repository.getPermanentProfileSwitch(dateUtil.now())
|
||||||
val profileName = activePlugin.activeProfileSource.profile?.getDefaultProfileName()
|
?: throw InvalidParameterSpecException("No active ProfileSwitch")
|
||||||
?: return
|
val profileStore = activePlugin.activeProfileSource.profile ?: return false
|
||||||
createProfileSwitch(profileStore, profileName, durationInMinutes, percentage, timeShiftInHours, dateUtil.now())
|
val ps = buildProfileSwitch(profileStore, profile.profileName, durationInMinutes, percentage, 0, dateUtil.now())
|
||||||
|
val validity = ProfileSealed.PS(ps).isValid(
|
||||||
|
resourceHelper.gs(info.nightscout.androidaps.automation.R.string.careportal_profileswitch),
|
||||||
|
activePlugin.activePump,
|
||||||
|
config,
|
||||||
|
resourceHelper,
|
||||||
|
rxBus,
|
||||||
|
hardLimits
|
||||||
|
)
|
||||||
|
var returnValue = true
|
||||||
|
if (validity.isValid) {
|
||||||
|
repository.runTransactionForResult(InsertOrUpdateProfileSwitch(ps))
|
||||||
|
.doOnError {
|
||||||
|
aapsLogger.error(LTag.DATABASE, "Error while saving ProfileSwitch", it)
|
||||||
|
returnValue = false
|
||||||
|
}
|
||||||
|
.blockingGet()
|
||||||
|
.also { result ->
|
||||||
|
result.inserted.forEach { aapsLogger.debug(LTag.DATABASE, "Inserted ProfileSwitch $it") }
|
||||||
|
result.updated.forEach { aapsLogger.debug(LTag.DATABASE, "Updated ProfileSwitch $it") }
|
||||||
|
}
|
||||||
|
} else returnValue = false
|
||||||
|
return returnValue
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -45,6 +45,7 @@ class ObjectivesPlugin @Inject constructor(
|
||||||
var objectives: MutableList<Objective> = ArrayList()
|
var objectives: MutableList<Objective> = ArrayList()
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
const val FIRST_OBJECTIVE = 0
|
const val FIRST_OBJECTIVE = 0
|
||||||
@Suppress("unused") const val USAGE_OBJECTIVE = 1
|
@Suppress("unused") const val USAGE_OBJECTIVE = 1
|
||||||
@Suppress("unused") const val EXAM_OBJECTIVE = 2
|
@Suppress("unused") const val EXAM_OBJECTIVE = 2
|
||||||
|
@ -53,40 +54,17 @@ class ObjectivesPlugin @Inject constructor(
|
||||||
const val MAXIOB_ZERO_CL_OBJECTIVE = 5
|
const val MAXIOB_ZERO_CL_OBJECTIVE = 5
|
||||||
@Suppress("unused") const val MAXIOB_OBJECTIVE = 6
|
@Suppress("unused") const val MAXIOB_OBJECTIVE = 6
|
||||||
const val AUTOSENS_OBJECTIVE = 7
|
const val AUTOSENS_OBJECTIVE = 7
|
||||||
const val AMA_OBJECTIVE = 8
|
const val SMB_OBJECTIVE = 8
|
||||||
const val SMB_OBJECTIVE = 9
|
const val AUTO_OBJECTIVE = 9
|
||||||
const val AUTO_OBJECTIVE = 10
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override fun onStart() {
|
public override fun onStart() {
|
||||||
super.onStart()
|
super.onStart()
|
||||||
convertSP()
|
|
||||||
setupObjectives()
|
setupObjectives()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun specialEnableCondition(): Boolean {
|
override fun specialEnableCondition(): Boolean =
|
||||||
return activePlugin.activePump.pumpDescription.isTempBasalCapable
|
activePlugin.activePump.pumpDescription.isTempBasalCapable
|
||||||
}
|
|
||||||
|
|
||||||
// convert 2.3 SP version
|
|
||||||
private fun convertSP() {
|
|
||||||
doConvertSP(0, "config")
|
|
||||||
doConvertSP(1, "openloop")
|
|
||||||
doConvertSP(2, "maxbasal")
|
|
||||||
doConvertSP(3, "maxiobzero")
|
|
||||||
doConvertSP(4, "maxiob")
|
|
||||||
doConvertSP(5, "autosens")
|
|
||||||
doConvertSP(6, "ama")
|
|
||||||
doConvertSP(7, "smb")
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun doConvertSP(number: Int, name: String) {
|
|
||||||
if (!sp.contains("Objectives_" + name + "_started")) {
|
|
||||||
sp.putLong("Objectives_" + name + "_started", sp.getLong("Objectives" + number + "started", 0L))
|
|
||||||
sp.putLong("Objectives_" + name + "_accomplished", sp.getLong("Objectives" + number + "accomplished", 0L))
|
|
||||||
}
|
|
||||||
// TODO: we can remove Objectives1accomplished sometimes later
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun setupObjectives() {
|
private fun setupObjectives() {
|
||||||
objectives.clear()
|
objectives.clear()
|
||||||
|
@ -98,9 +76,9 @@ class ObjectivesPlugin @Inject constructor(
|
||||||
objectives.add(Objective5(injector))
|
objectives.add(Objective5(injector))
|
||||||
objectives.add(Objective6(injector))
|
objectives.add(Objective6(injector))
|
||||||
objectives.add(Objective7(injector))
|
objectives.add(Objective7(injector))
|
||||||
objectives.add(Objective8(injector))
|
|
||||||
objectives.add(Objective9(injector))
|
objectives.add(Objective9(injector))
|
||||||
objectives.add(Objective10(injector))
|
objectives.add(Objective10(injector))
|
||||||
|
// edit companion object if you remove/add Objective
|
||||||
}
|
}
|
||||||
|
|
||||||
fun reset() {
|
fun reset() {
|
||||||
|
@ -120,12 +98,11 @@ 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, "").lowercase(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", "UnstableApiUsage") 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)) {
|
||||||
sp.putLong("Objectives_" + "openloop" + "_started", dateUtil.now())
|
sp.putLong("Objectives_" + "openloop" + "_started", dateUtil.now())
|
||||||
sp.putLong("Objectives_" + "openloop" + "_accomplished", dateUtil.now())
|
sp.putLong("Objectives_" + "openloop" + "_accomplished", dateUtil.now())
|
||||||
|
@ -137,8 +114,6 @@ class ObjectivesPlugin @Inject constructor(
|
||||||
sp.putLong("Objectives_" + "maxiob" + "_accomplished", dateUtil.now())
|
sp.putLong("Objectives_" + "maxiob" + "_accomplished", dateUtil.now())
|
||||||
sp.putLong("Objectives_" + "autosens" + "_started", dateUtil.now())
|
sp.putLong("Objectives_" + "autosens" + "_started", dateUtil.now())
|
||||||
sp.putLong("Objectives_" + "autosens" + "_accomplished", dateUtil.now())
|
sp.putLong("Objectives_" + "autosens" + "_accomplished", dateUtil.now())
|
||||||
sp.putLong("Objectives_" + "ama" + "_started", dateUtil.now())
|
|
||||||
sp.putLong("Objectives_" + "ama" + "_accomplished", dateUtil.now())
|
|
||||||
sp.putLong("Objectives_" + "smb" + "_started", dateUtil.now())
|
sp.putLong("Objectives_" + "smb" + "_started", dateUtil.now())
|
||||||
sp.putLong("Objectives_" + "smb" + "_accomplished", dateUtil.now())
|
sp.putLong("Objectives_" + "smb" + "_accomplished", dateUtil.now())
|
||||||
sp.putLong("Objectives_" + "auto" + "_started", dateUtil.now())
|
sp.putLong("Objectives_" + "auto" + "_started", dateUtil.now())
|
||||||
|
@ -164,49 +139,43 @@ class ObjectivesPlugin @Inject constructor(
|
||||||
*/
|
*/
|
||||||
override fun isLoopInvocationAllowed(value: Constraint<Boolean>): Constraint<Boolean> {
|
override fun isLoopInvocationAllowed(value: Constraint<Boolean>): Constraint<Boolean> {
|
||||||
if (!objectives[FIRST_OBJECTIVE].isStarted)
|
if (!objectives[FIRST_OBJECTIVE].isStarted)
|
||||||
value.set(aapsLogger, false, String.format(resourceHelper.gs(R.string.objectivenotstarted), FIRST_OBJECTIVE + 1), this)
|
value.set(aapsLogger, false, resourceHelper.gs(R.string.objectivenotstarted, FIRST_OBJECTIVE + 1), this)
|
||||||
return value
|
return value
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun isLgsAllowed(value: Constraint<Boolean>): Constraint<Boolean> {
|
override fun isLgsAllowed(value: Constraint<Boolean>): Constraint<Boolean> {
|
||||||
if (!objectives[MAXBASAL_OBJECTIVE].isStarted)
|
if (!objectives[MAXBASAL_OBJECTIVE].isStarted)
|
||||||
value.set(aapsLogger, false, String.format(resourceHelper.gs(R.string.objectivenotstarted), MAXBASAL_OBJECTIVE + 1), this)
|
value.set(aapsLogger, false, resourceHelper.gs(R.string.objectivenotstarted, MAXBASAL_OBJECTIVE + 1), this)
|
||||||
return value
|
return value
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun isClosedLoopAllowed(value: Constraint<Boolean>): Constraint<Boolean> {
|
override fun isClosedLoopAllowed(value: Constraint<Boolean>): Constraint<Boolean> {
|
||||||
if (!objectives[MAXIOB_ZERO_CL_OBJECTIVE].isStarted)
|
if (!objectives[MAXIOB_ZERO_CL_OBJECTIVE].isStarted)
|
||||||
value.set(aapsLogger, false, String.format(resourceHelper.gs(R.string.objectivenotstarted), MAXIOB_ZERO_CL_OBJECTIVE + 1), this)
|
value.set(aapsLogger, false, resourceHelper.gs(R.string.objectivenotstarted, MAXIOB_ZERO_CL_OBJECTIVE + 1), this)
|
||||||
return value
|
return value
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun isAutosensModeEnabled(value: Constraint<Boolean>): Constraint<Boolean> {
|
override fun isAutosensModeEnabled(value: Constraint<Boolean>): Constraint<Boolean> {
|
||||||
if (!objectives[AUTOSENS_OBJECTIVE].isStarted)
|
if (!objectives[AUTOSENS_OBJECTIVE].isStarted)
|
||||||
value.set(aapsLogger, false, String.format(resourceHelper.gs(R.string.objectivenotstarted), AUTOSENS_OBJECTIVE + 1), this)
|
value.set(aapsLogger, false, resourceHelper.gs(R.string.objectivenotstarted, AUTOSENS_OBJECTIVE + 1), this)
|
||||||
return value
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun isAMAModeEnabled(value: Constraint<Boolean>): Constraint<Boolean> {
|
|
||||||
if (!objectives[AMA_OBJECTIVE].isStarted)
|
|
||||||
value.set(aapsLogger, false, String.format(resourceHelper.gs(R.string.objectivenotstarted), AMA_OBJECTIVE + 1), this)
|
|
||||||
return value
|
return value
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun isSMBModeEnabled(value: Constraint<Boolean>): Constraint<Boolean> {
|
override fun isSMBModeEnabled(value: Constraint<Boolean>): Constraint<Boolean> {
|
||||||
if (!objectives[SMB_OBJECTIVE].isStarted)
|
if (!objectives[SMB_OBJECTIVE].isStarted)
|
||||||
value.set(aapsLogger, false, String.format(resourceHelper.gs(R.string.objectivenotstarted), SMB_OBJECTIVE + 1), this)
|
value.set(aapsLogger, false, resourceHelper.gs(R.string.objectivenotstarted, SMB_OBJECTIVE + 1), this)
|
||||||
return value
|
return value
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun applyMaxIOBConstraints(maxIob: Constraint<Double>): Constraint<Double> {
|
override fun applyMaxIOBConstraints(maxIob: Constraint<Double>): Constraint<Double> {
|
||||||
if (objectives[MAXIOB_ZERO_CL_OBJECTIVE].isStarted && !objectives[MAXIOB_ZERO_CL_OBJECTIVE].isAccomplished)
|
if (objectives[MAXIOB_ZERO_CL_OBJECTIVE].isStarted && !objectives[MAXIOB_ZERO_CL_OBJECTIVE].isAccomplished)
|
||||||
maxIob.set(aapsLogger, 0.0, String.format(resourceHelper.gs(R.string.objectivenotfinished), MAXIOB_ZERO_CL_OBJECTIVE + 1), this)
|
maxIob.set(aapsLogger, 0.0, resourceHelper.gs(R.string.objectivenotfinished, MAXIOB_ZERO_CL_OBJECTIVE + 1), this)
|
||||||
return maxIob
|
return maxIob
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun isAutomationEnabled(value: Constraint<Boolean>): Constraint<Boolean> {
|
override fun isAutomationEnabled(value: Constraint<Boolean>): Constraint<Boolean> {
|
||||||
if (!objectives[AUTO_OBJECTIVE].isStarted)
|
if (!objectives[AUTO_OBJECTIVE].isStarted)
|
||||||
value.set(aapsLogger, false, String.format(resourceHelper.gs(R.string.objectivenotstarted), AUTO_OBJECTIVE + 1), this)
|
value.set(aapsLogger, false, resourceHelper.gs(R.string.objectivenotstarted, AUTO_OBJECTIVE + 1), this)
|
||||||
return value
|
return value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,7 +29,6 @@ class Objective3 @Inject constructor(injector: HasAndroidInjector) : Objective(i
|
||||||
override fun specialActionEnabled(): Boolean =
|
override fun specialActionEnabled(): Boolean =
|
||||||
nsClientPlugin.nsClientService?.isConnected == true && nsClientPlugin.nsClientService?.hasWriteAuth == true
|
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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +0,0 @@
|
||||||
package info.nightscout.androidaps.plugins.constraints.objectives.objectives
|
|
||||||
|
|
||||||
import dagger.android.HasAndroidInjector
|
|
||||||
import info.nightscout.androidaps.R
|
|
||||||
import info.nightscout.androidaps.utils.T
|
|
||||||
|
|
||||||
class Objective8(injector: HasAndroidInjector) : Objective(injector, "ama", R.string.objectives_ama_objective, 0) {
|
|
||||||
|
|
||||||
init {
|
|
||||||
tasks.add(MinimumDurationTask(this, T.days(28).msecs()))
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -3,6 +3,7 @@ package info.nightscout.androidaps.plugins.constraints.safety
|
||||||
import dagger.android.HasAndroidInjector
|
import dagger.android.HasAndroidInjector
|
||||||
import info.nightscout.androidaps.interfaces.Config
|
import info.nightscout.androidaps.interfaces.Config
|
||||||
import info.nightscout.androidaps.R
|
import info.nightscout.androidaps.R
|
||||||
|
import info.nightscout.androidaps.extensions.*
|
||||||
import info.nightscout.androidaps.interfaces.Profile
|
import info.nightscout.androidaps.interfaces.Profile
|
||||||
import info.nightscout.androidaps.interfaces.*
|
import info.nightscout.androidaps.interfaces.*
|
||||||
import info.nightscout.androidaps.logging.AAPSLogger
|
import info.nightscout.androidaps.logging.AAPSLogger
|
||||||
|
@ -20,6 +21,7 @@ import info.nightscout.androidaps.utils.Round
|
||||||
import info.nightscout.androidaps.utils.buildHelper.BuildHelper
|
import info.nightscout.androidaps.utils.buildHelper.BuildHelper
|
||||||
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 org.json.JSONObject
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
import kotlin.math.floor
|
import kotlin.math.floor
|
||||||
|
@ -49,7 +51,7 @@ class SafetyPlugin @Inject constructor(
|
||||||
.pluginName(R.string.safety)
|
.pluginName(R.string.safety)
|
||||||
.preferencesId(R.xml.pref_safety),
|
.preferencesId(R.xml.pref_safety),
|
||||||
aapsLogger, resourceHelper, injector
|
aapsLogger, resourceHelper, injector
|
||||||
), Constraints {
|
), Constraints, Safety {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constraints interface
|
* Constraints interface
|
||||||
|
@ -186,11 +188,23 @@ class SafetyPlugin @Inject constructor(
|
||||||
|
|
||||||
override fun applyMaxIOBConstraints(maxIob: Constraint<Double>): Constraint<Double> {
|
override fun applyMaxIOBConstraints(maxIob: Constraint<Double>): Constraint<Double> {
|
||||||
val apsMode = sp.getString(R.string.key_aps_mode, "open")
|
val apsMode = sp.getString(R.string.key_aps_mode, "open")
|
||||||
val maxIobPref: Double = if (openAPSSMBPlugin.isEnabled(PluginType.APS)) sp.getDouble(R.string.key_openapssmb_max_iob, 3.0) else sp.getDouble(R.string.key_openapsma_max_iob, 1.5)
|
val maxIobPref: Double = if (openAPSSMBPlugin.isEnabled()) sp.getDouble(R.string.key_openapssmb_max_iob, 3.0) else sp.getDouble(R.string.key_openapsma_max_iob, 1.5)
|
||||||
maxIob.setIfSmaller(aapsLogger, maxIobPref, String.format(resourceHelper.gs(R.string.limitingiob), maxIobPref, resourceHelper.gs(R.string.maxvalueinpreferences)), this)
|
maxIob.setIfSmaller(aapsLogger, maxIobPref, String.format(resourceHelper.gs(R.string.limitingiob), maxIobPref, resourceHelper.gs(R.string.maxvalueinpreferences)), this)
|
||||||
if (openAPSAMAPlugin.isEnabled(PluginType.APS)) maxIob.setIfSmaller(aapsLogger, hardLimits.maxIobAMA(), String.format(resourceHelper.gs(R.string.limitingiob), hardLimits.maxIobAMA(), resourceHelper.gs(R.string.hardlimit)), this)
|
if (openAPSAMAPlugin.isEnabled()) maxIob.setIfSmaller(aapsLogger, hardLimits.maxIobAMA(), String.format(resourceHelper.gs(R.string.limitingiob), hardLimits.maxIobAMA(), resourceHelper.gs(R.string.hardlimit)), this)
|
||||||
if (openAPSSMBPlugin.isEnabled(PluginType.APS)) maxIob.setIfSmaller(aapsLogger, hardLimits.maxIobSMB(), String.format(resourceHelper.gs(R.string.limitingiob), hardLimits.maxIobSMB(), resourceHelper.gs(R.string.hardlimit)), this)
|
if (openAPSSMBPlugin.isEnabled()) maxIob.setIfSmaller(aapsLogger, hardLimits.maxIobSMB(), String.format(resourceHelper.gs(R.string.limitingiob), hardLimits.maxIobSMB(), resourceHelper.gs(R.string.hardlimit)), this)
|
||||||
if (apsMode == "lgs") maxIob.setIfSmaller(aapsLogger, HardLimits.MAX_IOB_LGS, String.format(resourceHelper.gs(R.string.limitingiob), HardLimits.MAX_IOB_LGS, resourceHelper.gs(R.string.lowglucosesuspend)), this)
|
if (apsMode == "lgs") maxIob.setIfSmaller(aapsLogger, HardLimits.MAX_IOB_LGS, String.format(resourceHelper.gs(R.string.limitingiob), HardLimits.MAX_IOB_LGS, resourceHelper.gs(R.string.lowglucosesuspend)), this)
|
||||||
return maxIob
|
return maxIob
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun configuration(): JSONObject =
|
||||||
|
JSONObject()
|
||||||
|
.putString(R.string.key_age, sp, resourceHelper)
|
||||||
|
.putDouble(R.string.key_treatmentssafety_maxbolus, sp, resourceHelper)
|
||||||
|
.putDouble(R.string.key_treatmentssafety_maxcarbs, sp, resourceHelper)
|
||||||
|
|
||||||
|
override fun applyConfiguration(configuration: JSONObject) {
|
||||||
|
configuration.storeString(R.string.key_age, sp, resourceHelper)
|
||||||
|
configuration.storeDouble(R.string.key_treatmentssafety_maxbolus, sp, resourceHelper)
|
||||||
|
configuration.storeDouble(R.string.key_treatmentssafety_maxcarbs, sp, resourceHelper)
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -152,7 +152,6 @@ 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()
|
||||||
|
|
|
@ -5,6 +5,7 @@ import android.os.StatFs
|
||||||
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
|
||||||
|
import info.nightscout.androidaps.annotations.OpenForTesting
|
||||||
import info.nightscout.androidaps.interfaces.Constraint
|
import info.nightscout.androidaps.interfaces.Constraint
|
||||||
import info.nightscout.androidaps.interfaces.Constraints
|
import info.nightscout.androidaps.interfaces.Constraints
|
||||||
import info.nightscout.androidaps.interfaces.PluginBase
|
import info.nightscout.androidaps.interfaces.PluginBase
|
||||||
|
@ -20,8 +21,9 @@ import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
|
|
||||||
|
@OpenForTesting
|
||||||
@Singleton
|
@Singleton
|
||||||
open class StorageConstraintPlugin @Inject constructor(
|
class StorageConstraintPlugin @Inject constructor(
|
||||||
injector: HasAndroidInjector,
|
injector: HasAndroidInjector,
|
||||||
aapsLogger: AAPSLogger,
|
aapsLogger: AAPSLogger,
|
||||||
resourceHelper: ResourceHelper,
|
resourceHelper: ResourceHelper,
|
||||||
|
@ -48,7 +50,7 @@ open class StorageConstraintPlugin @Inject constructor(
|
||||||
return value
|
return value
|
||||||
}
|
}
|
||||||
|
|
||||||
open fun availableInternalMemorySize(): Long {
|
fun availableInternalMemorySize(): Long {
|
||||||
val path = Environment.getDataDirectory()
|
val path = Environment.getDataDirectory()
|
||||||
val stat = StatFs(path.path)
|
val stat = StatFs(path.path)
|
||||||
val blockSize = stat.blockSizeLong
|
val blockSize = stat.blockSizeLong
|
||||||
|
|
|
@ -28,7 +28,8 @@ 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.diaconn.DiaconnG8Plugin
|
||||||
import info.nightscout.androidaps.interfaces.ActivePlugin
|
import info.nightscout.androidaps.interfaces.ActivePlugin
|
||||||
import info.nightscout.androidaps.interfaces.CommandQueueProvider
|
import info.nightscout.androidaps.interfaces.CommandQueueProvider
|
||||||
import info.nightscout.androidaps.interfaces.Config
|
import info.nightscout.androidaps.interfaces.Config
|
||||||
|
@ -114,7 +115,10 @@ class ActionsFragment : DaggerFragment() {
|
||||||
savedInstanceState: Bundle?): View? {
|
savedInstanceState: Bundle?): View? {
|
||||||
//check screen width
|
//check screen width
|
||||||
dm = DisplayMetrics()
|
dm = DisplayMetrics()
|
||||||
activity?.windowManager?.defaultDisplay?.getMetrics(dm)
|
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.R)
|
||||||
|
activity?.display?.getRealMetrics(dm)
|
||||||
|
else
|
||||||
|
@Suppress("DEPRECATION") activity?.windowManager?.defaultDisplay?.getMetrics(dm)
|
||||||
|
|
||||||
val screenWidth = dm.widthPixels
|
val screenWidth = dm.widthPixels
|
||||||
val screenHeight = dm.heightPixels
|
val screenHeight = dm.heightPixels
|
||||||
|
@ -152,7 +156,7 @@ class ActionsFragment : DaggerFragment() {
|
||||||
pbLevelLabel = view.findViewById(R.id.pb_level_label)
|
pbLevelLabel = view.findViewById(R.id.pb_level_label)
|
||||||
|
|
||||||
profileSwitch?.setOnClickListener {
|
profileSwitch?.setOnClickListener {
|
||||||
ProfileSwitchDialog().show(childFragmentManager, "Actions")
|
ProfileSwitchDialog().show(childFragmentManager, "ProfileSwitchDialog")
|
||||||
}
|
}
|
||||||
tempTarget?.setOnClickListener {
|
tempTarget?.setOnClickListener {
|
||||||
TempTargetDialog().show(childFragmentManager, "Actions")
|
TempTargetDialog().show(childFragmentManager, "Actions")
|
||||||
|
@ -304,7 +308,11 @@ class ActionsFragment : DaggerFragment() {
|
||||||
val activeBgSource = activePlugin.activeBgSource
|
val activeBgSource = activePlugin.activeBgSource
|
||||||
historyBrowser?.visibility = (profile != null).toVisibility()
|
historyBrowser?.visibility = (profile != null).toVisibility()
|
||||||
fill?.visibility = (pump.pumpDescription.isRefillingCapable && pump.isInitialized() && !pump.isSuspended()).toVisibility()
|
fill?.visibility = (pump.pumpDescription.isRefillingCapable && pump.isInitialized() && !pump.isSuspended()).toVisibility()
|
||||||
|
if(pump is DiaconnG8Plugin) {
|
||||||
|
pumpBatteryChange?.visibility = (pump.pumpDescription.isBatteryReplaceable && !pump.isBatteryChangeLoggingEnabled()).toVisibility()
|
||||||
|
} else {
|
||||||
pumpBatteryChange?.visibility = (pump.pumpDescription.isBatteryReplaceable || (pump is OmnipodErosPumpPlugin && pump.isUseRileyLinkBatteryLevel && pump.isBatteryChangeLoggingEnabled)).toVisibility()
|
pumpBatteryChange?.visibility = (pump.pumpDescription.isBatteryReplaceable || (pump is OmnipodErosPumpPlugin && pump.isUseRileyLinkBatteryLevel && pump.isBatteryChangeLoggingEnabled)).toVisibility()
|
||||||
|
}
|
||||||
tempTarget?.visibility = (profile != null && config.APS).toVisibility()
|
tempTarget?.visibility = (profile != null && config.APS).toVisibility()
|
||||||
tddStats?.visibility = pump.pumpDescription.supportsTDDs.toVisibility()
|
tddStats?.visibility = pump.pumpDescription.supportsTDDs.toVisibility()
|
||||||
|
|
||||||
|
|
|
@ -67,7 +67,6 @@ 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)
|
||||||
|
|
||||||
|
@ -129,7 +128,6 @@ class FoodFragment : DaggerFragment() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Synchronized
|
@Synchronized
|
||||||
@kotlin.ExperimentalStdlibApi
|
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
super.onResume()
|
super.onResume()
|
||||||
disposable.add(rxBus
|
disposable.add(rxBus
|
||||||
|
@ -141,7 +139,6 @@ class FoodFragment : DaggerFragment() {
|
||||||
swapAdapter()
|
swapAdapter()
|
||||||
}
|
}
|
||||||
|
|
||||||
@kotlin.ExperimentalStdlibApi
|
|
||||||
private fun swapAdapter() {
|
private fun swapAdapter() {
|
||||||
disposable += repository
|
disposable += repository
|
||||||
.getFoodData()
|
.getFoodData()
|
||||||
|
@ -202,7 +199,6 @@ 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()
|
||||||
|
|
|
@ -363,7 +363,7 @@ class ImportExportPrefsImpl @Inject constructor(
|
||||||
override fun exportUserEntriesCsv(activity: FragmentActivity, singleEntries: Single<List<UserEntry>>) {
|
override fun exportUserEntriesCsv(activity: FragmentActivity, singleEntries: Single<List<UserEntry>>) {
|
||||||
val entries = singleEntries.blockingGet()
|
val entries = singleEntries.blockingGet()
|
||||||
prefFileList.ensureExportDirExists()
|
prefFileList.ensureExportDirExists()
|
||||||
val newFile = prefFileList.newExportXmlFile()
|
val newFile = prefFileList.newExportCsvFile()
|
||||||
|
|
||||||
try {
|
try {
|
||||||
classicPrefsFormat.saveCsv(newFile, entries)
|
classicPrefsFormat.saveCsv(newFile, entries)
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package info.nightscout.androidaps.plugins.general.maintenance
|
package info.nightscout.androidaps.plugins.general.maintenance
|
||||||
|
|
||||||
import ch.qos.logback.classic.LoggerContext
|
import ch.qos.logback.classic.LoggerContext
|
||||||
|
import info.nightscout.androidaps.annotations.OpenForTesting
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
|
@ -8,6 +9,7 @@ import javax.inject.Singleton
|
||||||
/**
|
/**
|
||||||
* This class provides several methods for log-handling (eg. sending logs as emails).
|
* This class provides several methods for log-handling (eg. sending logs as emails).
|
||||||
*/
|
*/
|
||||||
|
@OpenForTesting
|
||||||
@Singleton
|
@Singleton
|
||||||
class LoggerUtils @Inject constructor() {
|
class LoggerUtils @Inject constructor() {
|
||||||
|
|
||||||
|
|
|
@ -16,11 +16,13 @@ import info.nightscout.androidaps.events.EventNewBG
|
||||||
import info.nightscout.androidaps.insight.database.InsightDatabase
|
import info.nightscout.androidaps.insight.database.InsightDatabase
|
||||||
import info.nightscout.androidaps.interfaces.DataSyncSelector
|
import info.nightscout.androidaps.interfaces.DataSyncSelector
|
||||||
import info.nightscout.androidaps.interfaces.ImportExportPrefs
|
import info.nightscout.androidaps.interfaces.ImportExportPrefs
|
||||||
|
import info.nightscout.androidaps.interfaces.IobCobCalculator
|
||||||
import info.nightscout.androidaps.interfaces.PumpSync
|
import info.nightscout.androidaps.interfaces.PumpSync
|
||||||
import info.nightscout.androidaps.logging.AAPSLogger
|
import info.nightscout.androidaps.logging.AAPSLogger
|
||||||
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.maintenance.activities.LogSettingActivity
|
import info.nightscout.androidaps.plugins.general.maintenance.activities.LogSettingActivity
|
||||||
|
import info.nightscout.androidaps.plugins.general.overview.OverviewData
|
||||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventNewHistoryData
|
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventNewHistoryData
|
||||||
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
|
||||||
|
@ -44,6 +46,8 @@ class MaintenanceFragment : DaggerFragment() {
|
||||||
@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
|
||||||
|
@Inject lateinit var iobCobCalculator: IobCobCalculator
|
||||||
|
@Inject lateinit var overviewData: OverviewData
|
||||||
|
|
||||||
private val compositeDisposable = CompositeDisposable()
|
private val compositeDisposable = CompositeDisposable()
|
||||||
|
|
||||||
|
@ -63,7 +67,9 @@ class MaintenanceFragment : DaggerFragment() {
|
||||||
binding.logSend.setOnClickListener { maintenancePlugin.sendLogs() }
|
binding.logSend.setOnClickListener { maintenancePlugin.sendLogs() }
|
||||||
binding.logDelete.setOnClickListener {
|
binding.logDelete.setOnClickListener {
|
||||||
uel.log(Action.DELETE_LOGS, Sources.Maintenance)
|
uel.log(Action.DELETE_LOGS, Sources.Maintenance)
|
||||||
maintenancePlugin.deleteLogs()
|
Thread {
|
||||||
|
maintenancePlugin.deleteLogs(5)
|
||||||
|
}.start()
|
||||||
}
|
}
|
||||||
binding.navResetdb.setOnClickListener {
|
binding.navResetdb.setOnClickListener {
|
||||||
activity?.let { activity ->
|
activity?.let { activity ->
|
||||||
|
@ -75,6 +81,9 @@ class MaintenanceFragment : DaggerFragment() {
|
||||||
insightDatabase.clearAllTables()
|
insightDatabase.clearAllTables()
|
||||||
dataSyncSelector.resetToNextFullSync()
|
dataSyncSelector.resetToNextFullSync()
|
||||||
pumpSync.connectNewPump()
|
pumpSync.connectNewPump()
|
||||||
|
overviewData.reset()
|
||||||
|
iobCobCalculator.ads.reset()
|
||||||
|
iobCobCalculator.clearCache()
|
||||||
}
|
}
|
||||||
.subscribeOn(aapsSchedulers.io)
|
.subscribeOn(aapsSchedulers.io)
|
||||||
.observeOn(aapsSchedulers.main)
|
.observeOn(aapsSchedulers.main)
|
||||||
|
|
|
@ -8,8 +8,8 @@ import androidx.preference.PreferenceFragmentCompat
|
||||||
import androidx.preference.SwitchPreference
|
import androidx.preference.SwitchPreference
|
||||||
import dagger.android.HasAndroidInjector
|
import dagger.android.HasAndroidInjector
|
||||||
import info.nightscout.androidaps.BuildConfig
|
import info.nightscout.androidaps.BuildConfig
|
||||||
import info.nightscout.androidaps.interfaces.Config
|
|
||||||
import info.nightscout.androidaps.R
|
import info.nightscout.androidaps.R
|
||||||
|
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
|
||||||
|
@ -35,8 +35,10 @@ class MaintenancePlugin @Inject constructor(
|
||||||
aapsLogger: AAPSLogger,
|
aapsLogger: AAPSLogger,
|
||||||
private val buildHelper: BuildHelper,
|
private val buildHelper: BuildHelper,
|
||||||
private val config: Config,
|
private val config: Config,
|
||||||
|
private val fileListProvider: PrefFileListProvider,
|
||||||
private val loggerUtils: LoggerUtils
|
private val loggerUtils: LoggerUtils
|
||||||
) : PluginBase(PluginDescription()
|
) : PluginBase(
|
||||||
|
PluginDescription()
|
||||||
.mainType(PluginType.GENERAL)
|
.mainType(PluginType.GENERAL)
|
||||||
.fragmentClass(MaintenanceFragment::class.java.name)
|
.fragmentClass(MaintenanceFragment::class.java.name)
|
||||||
.alwaysVisible(false)
|
.alwaysVisible(false)
|
||||||
|
@ -53,11 +55,12 @@ class MaintenancePlugin @Inject constructor(
|
||||||
val recipient = sp.getString(R.string.key_maintenance_logs_email, "logs@androidaps.org")
|
val recipient = sp.getString(R.string.key_maintenance_logs_email, "logs@androidaps.org")
|
||||||
val amount = sp.getInt(R.string.key_maintenance_logs_amount, 2)
|
val amount = sp.getInt(R.string.key_maintenance_logs_amount, 2)
|
||||||
val logs = getLogFiles(amount)
|
val logs = getLogFiles(amount)
|
||||||
val zipDir = context.getExternalFilesDir("exports")
|
val zipDir = fileListProvider.ensureTempDirExists()
|
||||||
val zipFile = File(zipDir, constructName())
|
val zipFile = File(zipDir, constructName())
|
||||||
aapsLogger.debug("zipFile: ${zipFile.absolutePath}")
|
aapsLogger.debug("zipFile: ${zipFile.absolutePath}")
|
||||||
val zip = zipLogs(zipFile, logs)
|
val zip = zipLogs(zipFile, logs)
|
||||||
val attachmentUri = FileProvider.getUriForFile(context, BuildConfig.APPLICATION_ID + ".fileprovider", zip)
|
val attachmentUri =
|
||||||
|
FileProvider.getUriForFile(context, BuildConfig.APPLICATION_ID + ".fileprovider", zip)
|
||||||
val emailIntent: Intent = this.sendMail(attachmentUri, recipient, "Log Export")
|
val emailIntent: Intent = this.sendMail(attachmentUri, recipient, "Log Export")
|
||||||
aapsLogger.debug("sending emailIntent")
|
aapsLogger.debug("sending emailIntent")
|
||||||
context.startActivity(emailIntent)
|
context.startActivity(emailIntent)
|
||||||
|
@ -65,14 +68,15 @@ class MaintenancePlugin @Inject constructor(
|
||||||
|
|
||||||
//todo replace this with a call on startup of the application, specifically to remove
|
//todo replace this with a call on startup of the application, specifically to remove
|
||||||
// unnecessary garbage from the log exports
|
// unnecessary garbage from the log exports
|
||||||
fun deleteLogs() {
|
fun deleteLogs(keep: Int) {
|
||||||
val logDir = File(loggerUtils.logDirectory)
|
val logDir = File(loggerUtils.logDirectory)
|
||||||
val files = logDir.listFiles { _: File?, name: String ->
|
val files = logDir.listFiles { _: File?, name: String ->
|
||||||
(name.startsWith("AndroidAPS") && name.endsWith(".zip"))
|
(name.startsWith("AndroidAPS") && name.endsWith(".zip"))
|
||||||
}
|
}
|
||||||
Arrays.sort(files) { f1: File, f2: File -> f1.name.compareTo(f2.name) }
|
if (files == null || files.isEmpty()) return
|
||||||
|
Arrays.sort(files) { f1: File, f2: File -> f2.name.compareTo(f1.name) }
|
||||||
var delFiles = listOf(*files)
|
var delFiles = listOf(*files)
|
||||||
val amount = sp.getInt(R.string.key_logshipper_amount, 2)
|
val amount = sp.getInt(R.string.key_logshipper_amount, keep)
|
||||||
val keepIndex = amount - 1
|
val keepIndex = amount - 1
|
||||||
if (keepIndex < delFiles.size) {
|
if (keepIndex < delFiles.size) {
|
||||||
delFiles = delFiles.subList(keepIndex, delFiles.size)
|
delFiles = delFiles.subList(keepIndex, delFiles.size)
|
||||||
|
@ -80,11 +84,10 @@ class MaintenancePlugin @Inject constructor(
|
||||||
file.delete()
|
file.delete()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val exportDir = File(loggerUtils.logDirectory, "exports")
|
val exportDir = fileListProvider.ensureTempDirExists()
|
||||||
if (exportDir.exists()) {
|
if (exportDir.exists()) {
|
||||||
val expFiles = exportDir.listFiles()
|
exportDir.listFiles()?.let { expFiles ->
|
||||||
for (file in expFiles) {
|
for (file in expFiles) file.delete()
|
||||||
file.delete()
|
|
||||||
}
|
}
|
||||||
exportDir.delete()
|
exportDir.delete()
|
||||||
}
|
}
|
||||||
|
@ -106,7 +109,7 @@ class MaintenancePlugin @Inject constructor(
|
||||||
(name.startsWith("AndroidAPS")
|
(name.startsWith("AndroidAPS")
|
||||||
&& (name.endsWith(".log")
|
&& (name.endsWith(".log")
|
||||||
|| name.endsWith(".zip") && !name.endsWith(loggerUtils.suffix)))
|
|| name.endsWith(".zip") && !name.endsWith(loggerUtils.suffix)))
|
||||||
}
|
} ?: emptyArray()
|
||||||
Arrays.sort(files) { f1: File, f2: File -> f2.name.compareTo(f1.name) }
|
Arrays.sort(files) { f1: File, f2: File -> f2.name.compareTo(f1.name) }
|
||||||
val result = listOf(*files)
|
val result = listOf(*files)
|
||||||
var toIndex = amount
|
var toIndex = amount
|
||||||
|
@ -192,7 +195,12 @@ class MaintenancePlugin @Inject constructor(
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
private fun sendMail(attachmentUri: Uri, recipient: String, subject: String, body: String): Intent {
|
private fun sendMail(
|
||||||
|
attachmentUri: Uri,
|
||||||
|
recipient: String,
|
||||||
|
subject: String,
|
||||||
|
body: String
|
||||||
|
): Intent {
|
||||||
aapsLogger.debug("sending email to $recipient with subject $subject")
|
aapsLogger.debug("sending email to $recipient with subject $subject")
|
||||||
val emailIntent = Intent(Intent.ACTION_SEND)
|
val emailIntent = Intent(Intent.ACTION_SEND)
|
||||||
emailIntent.type = "text/plain"
|
emailIntent.type = "text/plain"
|
||||||
|
@ -207,7 +215,8 @@ class MaintenancePlugin @Inject constructor(
|
||||||
|
|
||||||
override fun preprocessPreferences(preferenceFragment: PreferenceFragmentCompat) {
|
override fun preprocessPreferences(preferenceFragment: PreferenceFragmentCompat) {
|
||||||
super.preprocessPreferences(preferenceFragment)
|
super.preprocessPreferences(preferenceFragment)
|
||||||
val encryptSwitch = preferenceFragment.findPreference(resourceHelper.gs(R.string.key_maintenance_encrypt_exported_prefs)) as SwitchPreference?
|
val encryptSwitch =
|
||||||
|
preferenceFragment.findPreference(resourceHelper.gs(R.string.key_maintenance_encrypt_exported_prefs)) as SwitchPreference?
|
||||||
?: return
|
?: return
|
||||||
encryptSwitch.isVisible = buildHelper.isEngineeringMode()
|
encryptSwitch.isVisible = buildHelper.isEngineeringMode()
|
||||||
encryptSwitch.isEnabled = buildHelper.isEngineeringMode()
|
encryptSwitch.isEnabled = buildHelper.isEngineeringMode()
|
||||||
|
|
|
@ -34,11 +34,13 @@ class DataSyncSelectorImplementation @Inject constructor(
|
||||||
processChangedTemporaryBasalsCompat()
|
processChangedTemporaryBasalsCompat()
|
||||||
processChangedExtendedBolusesCompat()
|
processChangedExtendedBolusesCompat()
|
||||||
processChangedProfileSwitchesCompat()
|
processChangedProfileSwitchesCompat()
|
||||||
|
processChangedEffectiveProfileSwitchesCompat()
|
||||||
processChangedGlucoseValuesCompat()
|
processChangedGlucoseValuesCompat()
|
||||||
processChangedTempTargetsCompat()
|
processChangedTempTargetsCompat()
|
||||||
processChangedFoodsCompat()
|
processChangedFoodsCompat()
|
||||||
processChangedTherapyEventsCompat()
|
processChangedTherapyEventsCompat()
|
||||||
processChangedDeviceStatusesCompat()
|
processChangedDeviceStatusesCompat()
|
||||||
|
processChangedOfflineEventsCompat()
|
||||||
processChangedProfileStore()
|
processChangedProfileStore()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -55,6 +57,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_effective_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)
|
sp.remove(R.string.key_ns_profile_store_last_synced_timestamp)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -76,8 +80,8 @@ class DataSyncSelectorImplementation @Inject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private var lastBolusId = -1L
|
@Volatile private var lastBolusId = -1L
|
||||||
private var lastBolusTime = -1L
|
@Volatile private var lastBolusTime = -1L
|
||||||
override fun processChangedBolusesCompat(): Boolean {
|
override fun processChangedBolusesCompat(): Boolean {
|
||||||
val lastDbIdWrapped = appRepository.getLastBolusIdWrapped().blockingGet()
|
val lastDbIdWrapped = appRepository.getLastBolusIdWrapped().blockingGet()
|
||||||
val lastDbId = if (lastDbIdWrapped is ValueWrapper.Existing) lastDbIdWrapped.value else 0L
|
val lastDbId = if (lastDbIdWrapped is ValueWrapper.Existing) lastDbIdWrapped.value else 0L
|
||||||
|
@ -119,8 +123,8 @@ class DataSyncSelectorImplementation @Inject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private var lastCarbsId = -1L
|
@Volatile private var lastCarbsId = -1L
|
||||||
private var lastCarbsTime = -1L
|
@Volatile private var lastCarbsTime = -1L
|
||||||
override fun processChangedCarbsCompat(): Boolean {
|
override fun processChangedCarbsCompat(): Boolean {
|
||||||
val lastDbIdWrapped = appRepository.getLastCarbsIdWrapped().blockingGet()
|
val lastDbIdWrapped = appRepository.getLastCarbsIdWrapped().blockingGet()
|
||||||
val lastDbId = if (lastDbIdWrapped is ValueWrapper.Existing) lastDbIdWrapped.value else 0L
|
val lastDbId = if (lastDbIdWrapped is ValueWrapper.Existing) lastDbIdWrapped.value else 0L
|
||||||
|
@ -162,8 +166,8 @@ class DataSyncSelectorImplementation @Inject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private var lastBcrId = -1L
|
@Volatile private var lastBcrId = -1L
|
||||||
private var lastBcrTime = -1L
|
@Volatile private var lastBcrTime = -1L
|
||||||
override fun processChangedBolusCalculatorResultsCompat(): Boolean {
|
override fun processChangedBolusCalculatorResultsCompat(): Boolean {
|
||||||
val lastDbIdWrapped = appRepository.getLastBolusCalculatorResultIdWrapped().blockingGet()
|
val lastDbIdWrapped = appRepository.getLastBolusCalculatorResultIdWrapped().blockingGet()
|
||||||
val lastDbId = if (lastDbIdWrapped is ValueWrapper.Existing) lastDbIdWrapped.value else 0L
|
val lastDbId = if (lastDbIdWrapped is ValueWrapper.Existing) lastDbIdWrapped.value else 0L
|
||||||
|
@ -205,8 +209,8 @@ class DataSyncSelectorImplementation @Inject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private var lastTtId = -1L
|
@Volatile private var lastTtId = -1L
|
||||||
private var lastTtTime = -1L
|
@Volatile private var lastTtTime = -1L
|
||||||
override fun processChangedTempTargetsCompat(): Boolean {
|
override fun processChangedTempTargetsCompat(): Boolean {
|
||||||
val lastDbIdWrapped = appRepository.getLastTempTargetIdWrapped().blockingGet()
|
val lastDbIdWrapped = appRepository.getLastTempTargetIdWrapped().blockingGet()
|
||||||
val lastDbId = if (lastDbIdWrapped is ValueWrapper.Existing) lastDbIdWrapped.value else 0L
|
val lastDbId = if (lastDbIdWrapped is ValueWrapper.Existing) lastDbIdWrapped.value else 0L
|
||||||
|
@ -248,8 +252,8 @@ class DataSyncSelectorImplementation @Inject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private var lastFoodId = -1L
|
@Volatile private var lastFoodId = -1L
|
||||||
private var lastFoodTime = -1L
|
@Volatile private var lastFoodTime = -1L
|
||||||
override fun processChangedFoodsCompat(): Boolean {
|
override fun processChangedFoodsCompat(): Boolean {
|
||||||
val lastDbIdWrapped = appRepository.getLastFoodIdWrapped().blockingGet()
|
val lastDbIdWrapped = appRepository.getLastFoodIdWrapped().blockingGet()
|
||||||
val lastDbId = if (lastDbIdWrapped is ValueWrapper.Existing) lastDbIdWrapped.value else 0L
|
val lastDbId = if (lastDbIdWrapped is ValueWrapper.Existing) lastDbIdWrapped.value else 0L
|
||||||
|
@ -291,8 +295,8 @@ class DataSyncSelectorImplementation @Inject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private var lastGvId = -1L
|
@Volatile private var lastGvId = -1L
|
||||||
private var lastGvTime = -1L
|
@Volatile private var lastGvTime = -1L
|
||||||
override fun processChangedGlucoseValuesCompat(): Boolean {
|
override fun processChangedGlucoseValuesCompat(): Boolean {
|
||||||
val lastDbIdWrapped = appRepository.getLastGlucoseValueIdWrapped().blockingGet()
|
val lastDbIdWrapped = appRepository.getLastGlucoseValueIdWrapped().blockingGet()
|
||||||
val lastDbId = if (lastDbIdWrapped is ValueWrapper.Existing) lastDbIdWrapped.value else 0L
|
val lastDbId = if (lastDbIdWrapped is ValueWrapper.Existing) lastDbIdWrapped.value else 0L
|
||||||
|
@ -340,8 +344,8 @@ class DataSyncSelectorImplementation @Inject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private var lastTeId = -1L
|
@Volatile private var lastTeId = -1L
|
||||||
private var lastTeTime = -1L
|
@Volatile private var lastTeTime = -1L
|
||||||
override fun processChangedTherapyEventsCompat(): Boolean {
|
override fun processChangedTherapyEventsCompat(): Boolean {
|
||||||
val lastDbIdWrapped = appRepository.getLastTherapyEventIdWrapped().blockingGet()
|
val lastDbIdWrapped = appRepository.getLastTherapyEventIdWrapped().blockingGet()
|
||||||
val lastDbId = if (lastDbIdWrapped is ValueWrapper.Existing) lastDbIdWrapped.value else 0L
|
val lastDbId = if (lastDbIdWrapped is ValueWrapper.Existing) lastDbIdWrapped.value else 0L
|
||||||
|
@ -358,10 +362,10 @@ class DataSyncSelectorImplementation @Inject constructor(
|
||||||
when {
|
when {
|
||||||
// without nsId = create new
|
// without nsId = create new
|
||||||
te.first.interfaceIDs.nightscoutId == null ->
|
te.first.interfaceIDs.nightscoutId == null ->
|
||||||
nsClientPlugin.nsClientService?.dbAdd("treatments", te.first.toJson(true), DataSyncSelector.PairTherapyEvent(te.first, te.second), "$startId/$lastDbId")
|
nsClientPlugin.nsClientService?.dbAdd("treatments", te.first.toJson(true, dateUtil), DataSyncSelector.PairTherapyEvent(te.first, te.second), "$startId/$lastDbId")
|
||||||
// nsId = update
|
// nsId = update
|
||||||
te.first.interfaceIDs.nightscoutId != null ->
|
te.first.interfaceIDs.nightscoutId != null ->
|
||||||
nsClientPlugin.nsClientService?.dbUpdate("treatments", te.first.interfaceIDs.nightscoutId, te.first.toJson(false), DataSyncSelector.PairTherapyEvent(te.first, te.second), "$startId/$lastDbId")
|
nsClientPlugin.nsClientService?.dbUpdate("treatments", te.first.interfaceIDs.nightscoutId, te.first.toJson(false, dateUtil), DataSyncSelector.PairTherapyEvent(te.first, te.second), "$startId/$lastDbId")
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
@ -382,8 +386,8 @@ class DataSyncSelectorImplementation @Inject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private var lastDsId = -1L
|
@Volatile private var lastDsId = -1L
|
||||||
private var lastDsTime = -1L
|
@Volatile private var lastDsTime = -1L
|
||||||
override fun processChangedDeviceStatusesCompat(): Boolean {
|
override fun processChangedDeviceStatusesCompat(): Boolean {
|
||||||
val lastDbIdWrapped = appRepository.getLastDeviceStatusIdWrapped().blockingGet()
|
val lastDbIdWrapped = appRepository.getLastDeviceStatusIdWrapped().blockingGet()
|
||||||
val lastDbId = if (lastDbIdWrapped is ValueWrapper.Existing) lastDbIdWrapped.value else 0L
|
val lastDbId = if (lastDbIdWrapped is ValueWrapper.Existing) lastDbIdWrapped.value else 0L
|
||||||
|
@ -424,8 +428,8 @@ class DataSyncSelectorImplementation @Inject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private var lastTbrId = -1L
|
@Volatile private var lastTbrId = -1L
|
||||||
private var lastTbrTime = -1L
|
@Volatile private var lastTbrTime = -1L
|
||||||
override fun processChangedTemporaryBasalsCompat(): Boolean {
|
override fun processChangedTemporaryBasalsCompat(): Boolean {
|
||||||
val useAbsolute = sp.getBoolean(R.string.key_ns_sync_use_absolute, false)
|
val useAbsolute = sp.getBoolean(R.string.key_ns_sync_use_absolute, false)
|
||||||
val lastDbIdWrapped = appRepository.getLastTemporaryBasalIdWrapped().blockingGet()
|
val lastDbIdWrapped = appRepository.getLastTemporaryBasalIdWrapped().blockingGet()
|
||||||
|
@ -475,8 +479,8 @@ class DataSyncSelectorImplementation @Inject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private var lastEbId = -1L
|
@Volatile private var lastEbId = -1L
|
||||||
private var lastEbTime = -1L
|
@Volatile private var lastEbTime = -1L
|
||||||
override fun processChangedExtendedBolusesCompat(): Boolean {
|
override fun processChangedExtendedBolusesCompat(): Boolean {
|
||||||
val useAbsolute = sp.getBoolean(R.string.key_ns_sync_use_absolute, false)
|
val useAbsolute = sp.getBoolean(R.string.key_ns_sync_use_absolute, false)
|
||||||
val lastDbIdWrapped = appRepository.getLastExtendedBolusIdWrapped().blockingGet()
|
val lastDbIdWrapped = appRepository.getLastExtendedBolusIdWrapped().blockingGet()
|
||||||
|
@ -525,8 +529,8 @@ class DataSyncSelectorImplementation @Inject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private var lastPsId = -1L
|
@Volatile private var lastPsId = -1L
|
||||||
private var lastPsTime = -1L
|
@Volatile private var lastPsTime = -1L
|
||||||
override fun processChangedProfileSwitchesCompat(): Boolean {
|
override fun processChangedProfileSwitchesCompat(): Boolean {
|
||||||
val lastDbIdWrapped = appRepository.getLastProfileSwitchIdWrapped().blockingGet()
|
val lastDbIdWrapped = appRepository.getLastProfileSwitchIdWrapped().blockingGet()
|
||||||
val lastDbId = if (lastDbIdWrapped is ValueWrapper.Existing) lastDbIdWrapped.value else 0L
|
val lastDbId = if (lastDbIdWrapped is ValueWrapper.Existing) lastDbIdWrapped.value else 0L
|
||||||
|
@ -553,6 +557,91 @@ class DataSyncSelectorImplementation @Inject constructor(
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun confirmLastEffectiveProfileSwitchIdIfGreater(lastSynced: Long) {
|
||||||
|
if (lastSynced > sp.getLong(R.string.key_ns_effective_profile_switch_last_synced_id, 0)) {
|
||||||
|
aapsLogger.debug(LTag.NSCLIENT, "Setting EffectiveProfileSwitch data sync from $lastSynced")
|
||||||
|
sp.putLong(R.string.key_ns_effective_profile_switch_last_synced_id, lastSynced)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun changedEffectiveProfileSwitch(): List<EffectiveProfileSwitch> {
|
||||||
|
val startId = sp.getLong(R.string.key_ns_effective_profile_switch_last_synced_id, 0)
|
||||||
|
return appRepository.getModifiedEffectiveProfileSwitchDataFromId(startId).blockingGet().also {
|
||||||
|
aapsLogger.debug(LTag.NSCLIENT, "Loading EffectiveProfileSwitch data for sync from $startId. Records ${it.size}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Volatile private var lastEpsId = -1L
|
||||||
|
@Volatile private var lastEpsTime = -1L
|
||||||
|
override fun processChangedEffectiveProfileSwitchesCompat(): Boolean {
|
||||||
|
val lastDbIdWrapped = appRepository.getLastEffectiveProfileSwitchIdWrapped().blockingGet()
|
||||||
|
val lastDbId = if (lastDbIdWrapped is ValueWrapper.Existing) lastDbIdWrapped.value else 0L
|
||||||
|
var startId = sp.getLong(R.string.key_ns_effective_profile_switch_last_synced_id, 0)
|
||||||
|
if (startId > lastDbId) {
|
||||||
|
sp.putLong(R.string.key_ns_effective_profile_switch_last_synced_id, 0)
|
||||||
|
startId = 0
|
||||||
|
}
|
||||||
|
if (startId == lastEpsId && dateUtil.now() - lastEpsTime < 5000) return false
|
||||||
|
lastEpsId = startId
|
||||||
|
lastEpsTime = dateUtil.now()
|
||||||
|
appRepository.getNextSyncElementEffectiveProfileSwitch(startId).blockingGet()?.let { ps ->
|
||||||
|
aapsLogger.info(LTag.DATABASE, "Loading EffectiveProfileSwitch data Start: $startId ID: ${ps.first.id} HistoryID: ${ps.second} ")
|
||||||
|
when {
|
||||||
|
// without nsId = create new
|
||||||
|
ps.first.interfaceIDs.nightscoutId == null ->
|
||||||
|
nsClientPlugin.nsClientService?.dbAdd("treatments", ps.first.toJson(true, dateUtil), DataSyncSelector.PairEffectiveProfileSwitch(ps.first, ps.second), "$startId/$lastDbId")
|
||||||
|
// with nsId = update
|
||||||
|
ps.first.interfaceIDs.nightscoutId != null ->
|
||||||
|
nsClientPlugin.nsClientService?.dbUpdate("treatments", ps.first.interfaceIDs.nightscoutId, ps.first.toJson(false, dateUtil), DataSyncSelector.PairEffectiveProfileSwitch(ps.first, ps.second), "$startId/$lastDbId")
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun confirmLastOfflineEventIdIfGreater(lastSynced: Long) {
|
||||||
|
if (lastSynced > sp.getLong(R.string.key_ns_offline_event_last_synced_id, 0)) {
|
||||||
|
aapsLogger.debug(LTag.NSCLIENT, "Setting OfflineEvent data sync from $lastSynced")
|
||||||
|
sp.putLong(R.string.key_ns_offline_event_last_synced_id, lastSynced)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prepared for v3 (returns all modified after)
|
||||||
|
override fun changedOfflineEvents(): List<OfflineEvent> {
|
||||||
|
val startId = sp.getLong(R.string.key_ns_offline_event_last_synced_id, 0)
|
||||||
|
return appRepository.getModifiedOfflineEventsDataFromId(startId).blockingGet().also {
|
||||||
|
aapsLogger.debug(LTag.NSCLIENT, "Loading OfflineEvent data for sync from $startId. Records ${it.size}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Volatile private var lastOeId = -1L
|
||||||
|
@Volatile 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) {
|
override fun confirmLastProfileStore(lastSynced: Long) {
|
||||||
sp.putLong(R.string.key_ns_profile_store_last_synced_timestamp, lastSynced)
|
sp.putLong(R.string.key_ns_profile_store_last_synced_timestamp, lastSynced)
|
||||||
}
|
}
|
||||||
|
@ -561,9 +650,9 @@ class DataSyncSelectorImplementation @Inject constructor(
|
||||||
val lastSync = sp.getLong(R.string.key_ns_profile_store_last_synced_timestamp, 0)
|
val lastSync = sp.getLong(R.string.key_ns_profile_store_last_synced_timestamp, 0)
|
||||||
val lastChange = sp.getLong(R.string.key_local_profile_last_change, 0)
|
val lastChange = sp.getLong(R.string.key_local_profile_last_change, 0)
|
||||||
if (lastChange == 0L) return
|
if (lastChange == 0L) return
|
||||||
localProfilePlugin.createProfileStore()
|
if (lastChange > lastSync) {
|
||||||
val profileJson = localProfilePlugin.profile?.data ?: return
|
val profileJson = localProfilePlugin.profile?.data ?: return
|
||||||
if (lastChange > lastSync)
|
|
||||||
nsClientPlugin.nsClientService?.dbAdd("profile", profileJson, DataSyncSelector.PairProfileStore(profileJson, dateUtil.now()), "")
|
nsClientPlugin.nsClientService?.dbAdd("profile", profileJson, DataSyncSelector.PairProfileStore(profileJson, dateUtil.now()), "")
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -228,6 +228,25 @@ class NSClientAddAckWorker(
|
||||||
dataSyncSelector.processChangedProfileSwitchesCompat()
|
dataSyncSelector.processChangedProfileSwitchesCompat()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
is PairEffectiveProfileSwitch -> {
|
||||||
|
val pair = ack.originalObject
|
||||||
|
pair.value.interfaceIDs.nightscoutId = ack.id
|
||||||
|
repository.runTransactionForResult(UpdateNsIdEffectiveProfileSwitchTransaction(pair.value))
|
||||||
|
.doOnError { error ->
|
||||||
|
aapsLogger.error(LTag.DATABASE, "Updated ns id of EffectiveProfileSwitch 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 EffectiveProfileSwitch " + pair.value)
|
||||||
|
dataSyncSelector.confirmLastEffectiveProfileSwitchIdIfGreater(pair.updateRecordId)
|
||||||
|
}
|
||||||
|
.blockingGet()
|
||||||
|
rxBus.send(EventNSClientNewLog("DBADD", "Acked EffectiveProfileSwitch " + pair.value.interfaceIDs.nightscoutId))
|
||||||
|
// Send new if waiting
|
||||||
|
dataSyncSelector.processChangedEffectiveProfileSwitchesCompat()
|
||||||
|
}
|
||||||
|
|
||||||
is DeviceStatus -> {
|
is DeviceStatus -> {
|
||||||
val deviceStatus = ack.originalObject
|
val deviceStatus = ack.originalObject
|
||||||
deviceStatus.interfaceIDs.nightscoutId = ack.id
|
deviceStatus.interfaceIDs.nightscoutId = ack.id
|
||||||
|
@ -251,6 +270,26 @@ class NSClientAddAckWorker(
|
||||||
dataSyncSelector.confirmLastProfileStore(ack.originalObject.timestampSync)
|
dataSyncSelector.confirmLastProfileStore(ack.originalObject.timestampSync)
|
||||||
rxBus.send(EventNSClientNewLog("DBADD", "Acked ProfileStore " + ack.id))
|
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
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,6 @@ import info.nightscout.androidaps.receivers.DataWorker
|
||||||
import info.nightscout.androidaps.utils.DateUtil
|
import info.nightscout.androidaps.utils.DateUtil
|
||||||
import info.nightscout.androidaps.utils.JsonHelper
|
import info.nightscout.androidaps.utils.JsonHelper
|
||||||
import info.nightscout.androidaps.utils.JsonHelper.safeGetLong
|
import info.nightscout.androidaps.utils.JsonHelper.safeGetLong
|
||||||
import info.nightscout.androidaps.utils.T
|
|
||||||
import info.nightscout.androidaps.utils.buildHelper.BuildHelper
|
import info.nightscout.androidaps.utils.buildHelper.BuildHelper
|
||||||
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
|
@ -186,6 +185,32 @@ class NSClientAddUpdateWorker(
|
||||||
}
|
}
|
||||||
} ?: aapsLogger.error("Error parsing TT json $json")
|
} ?: aapsLogger.error("Error parsing TT json $json")
|
||||||
}
|
}
|
||||||
|
eventType == TherapyEvent.Type.NOTE.text && json.isEffectiveProfileSwitch() -> // replace this by new Type when available in NS
|
||||||
|
if (sp.getBoolean(R.string.key_ns_receive_profile_switch, false) && buildHelper.isEngineeringMode() || config.NSCLIENT) {
|
||||||
|
effectiveProfileSwitchFromJson(json, dateUtil)?.let { effectiveProfileSwitch ->
|
||||||
|
repository.runTransactionForResult(SyncNsEffectiveProfileSwitchTransaction(effectiveProfileSwitch, invalidateByNsOnly = false))
|
||||||
|
.doOnError {
|
||||||
|
aapsLogger.error(LTag.DATABASE, "Error while saving EffectiveProfileSwitch", it)
|
||||||
|
ret = Result.failure(workDataOf("Error" to it.toString()))
|
||||||
|
}
|
||||||
|
.blockingGet()
|
||||||
|
.also { result ->
|
||||||
|
result.inserted.forEach {
|
||||||
|
uel.log(Action.PROFILE_SWITCH, Sources.NSClient,
|
||||||
|
ValueWithUnit.Timestamp(it.timestamp))
|
||||||
|
aapsLogger.debug(LTag.DATABASE, "Inserted EffectiveProfileSwitch $it")
|
||||||
|
}
|
||||||
|
result.invalidated.forEach {
|
||||||
|
uel.log(Action.PROFILE_SWITCH_REMOVED, Sources.NSClient,
|
||||||
|
ValueWithUnit.Timestamp(it.timestamp))
|
||||||
|
aapsLogger.debug(LTag.DATABASE, "Invalidated EffectiveProfileSwitch $it")
|
||||||
|
}
|
||||||
|
result.updatedNsId.forEach {
|
||||||
|
aapsLogger.debug(LTag.DATABASE, "Updated nsId EffectiveProfileSwitch $it")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} ?: aapsLogger.error("Error parsing EffectiveProfileSwitch 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 ||
|
||||||
|
@ -194,7 +219,7 @@ 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.NOTE.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) {
|
if (sp.getBoolean(R.string.key_ns_receive_therapy_events, false) || config.NSCLIENT) {
|
||||||
therapyEventFromJson(json)?.let { therapyEvent ->
|
therapyEventFromJson(json)?.let { therapyEvent ->
|
||||||
|
@ -341,6 +366,43 @@ class NSClientAddUpdateWorker(
|
||||||
}
|
}
|
||||||
} ?: aapsLogger.error("Error parsing ProfileSwitch 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 (sp.getBoolean(R.string.key_ns_receive_therapy_events, false) || config.NSCLIENT)
|
||||||
if (eventType == TherapyEvent.Type.ANNOUNCEMENT.text) {
|
if (eventType == TherapyEvent.Type.ANNOUNCEMENT.text) {
|
||||||
|
|
|
@ -34,7 +34,7 @@ class NSClientMbgWorker(
|
||||||
var ret = Result.success()
|
var ret = Result.success()
|
||||||
|
|
||||||
val acceptNSData = sp.getBoolean(R.string.key_ns_receive_therapy_events, false) || config.NSCLIENT
|
val acceptNSData = sp.getBoolean(R.string.key_ns_receive_therapy_events, false) || config.NSCLIENT
|
||||||
if (!acceptNSData) return ret
|
if (!acceptNSData) return Result.success(workDataOf("Result" to "Sync not enabled"))
|
||||||
|
|
||||||
val mbgArray = dataWorker.pickupJSONArray(inputData.getLong(DataWorker.STORE_KEY, -1))
|
val mbgArray = dataWorker.pickupJSONArray(inputData.getLong(DataWorker.STORE_KEY, -1))
|
||||||
?: return Result.failure(workDataOf("Error" to "missing input data"))
|
?: return Result.failure(workDataOf("Error" to "missing input data"))
|
||||||
|
|
|
@ -125,6 +125,24 @@ class NSClientUpdateRemoveAckWorker(
|
||||||
dataSyncSelector.processChangedProfileSwitchesCompat()
|
dataSyncSelector.processChangedProfileSwitchesCompat()
|
||||||
ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
|
ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
is PairEffectiveProfileSwitch -> {
|
||||||
|
val pair = ack.originalObject
|
||||||
|
dataSyncSelector.confirmLastEffectiveProfileSwitchIdIfGreater(pair.updateRecordId)
|
||||||
|
rxBus.send(EventNSClientNewLog("DBUPDATE", "Acked EffectiveProfileSwitch " + ack._id))
|
||||||
|
// Send new if waiting
|
||||||
|
dataSyncSelector.processChangedEffectiveProfileSwitchesCompat()
|
||||||
|
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
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,8 +16,8 @@ class NSAddAck(
|
||||||
) : Event(), Ack {
|
) : Event(), Ack {
|
||||||
|
|
||||||
var id: String? = null
|
var id: String? = null
|
||||||
@JvmField var nsClientID: String? = null
|
var nsClientID: String? = null
|
||||||
@JvmField var json: JSONObject? = null
|
var json: JSONObject? = null
|
||||||
override fun call(vararg args: Any) {
|
override fun call(vararg args: Any) {
|
||||||
// Regular response
|
// Regular response
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -3,6 +3,7 @@ package info.nightscout.androidaps.plugins.general.nsclient.data
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import info.nightscout.androidaps.interfaces.Config
|
import info.nightscout.androidaps.interfaces.Config
|
||||||
import info.nightscout.androidaps.R
|
import info.nightscout.androidaps.R
|
||||||
|
import info.nightscout.androidaps.annotations.OpenForTesting
|
||||||
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.logging.AAPSLogger
|
import info.nightscout.androidaps.logging.AAPSLogger
|
||||||
|
@ -113,6 +114,7 @@ import javax.inject.Singleton
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
@Suppress("SpellCheckingInspection")
|
@Suppress("SpellCheckingInspection")
|
||||||
|
@OpenForTesting
|
||||||
@Singleton
|
@Singleton
|
||||||
class NSSettingsStatus @Inject constructor(
|
class NSSettingsStatus @Inject constructor(
|
||||||
private val aapsLogger: AAPSLogger,
|
private val aapsLogger: AAPSLogger,
|
||||||
|
|
|
@ -3,6 +3,7 @@ package info.nightscout.androidaps.plugins.general.nsclient.services
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
|
import android.content.pm.ResolveInfo
|
||||||
import android.os.*
|
import android.os.*
|
||||||
import androidx.work.OneTimeWorkRequest
|
import androidx.work.OneTimeWorkRequest
|
||||||
import com.google.common.base.Charsets
|
import com.google.common.base.Charsets
|
||||||
|
@ -16,7 +17,6 @@ import info.nightscout.androidaps.events.EventConfigBuilderChange
|
||||||
import info.nightscout.androidaps.events.EventPreferenceChange
|
import info.nightscout.androidaps.events.EventPreferenceChange
|
||||||
import info.nightscout.androidaps.interfaces.Config
|
import info.nightscout.androidaps.interfaces.Config
|
||||||
import info.nightscout.androidaps.interfaces.DataSyncSelector
|
import info.nightscout.androidaps.interfaces.DataSyncSelector
|
||||||
import info.nightscout.androidaps.interfaces.DatabaseHelperInterface
|
|
||||||
import info.nightscout.androidaps.interfaces.PluginType
|
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
|
||||||
|
@ -71,7 +71,6 @@ class NSClientService : DaggerService() {
|
||||||
@Inject lateinit var aapsSchedulers: AapsSchedulers
|
@Inject lateinit var aapsSchedulers: AapsSchedulers
|
||||||
@Inject lateinit var nsSettingsStatus: NSSettingsStatus
|
@Inject lateinit var nsSettingsStatus: NSSettingsStatus
|
||||||
@Inject lateinit var nsDeviceStatus: NSDeviceStatus
|
@Inject lateinit var nsDeviceStatus: NSDeviceStatus
|
||||||
@Inject lateinit var databaseHelper: DatabaseHelperInterface
|
|
||||||
@Inject lateinit var rxBus: RxBusWrapper
|
@Inject lateinit var rxBus: RxBusWrapper
|
||||||
@Inject lateinit var resourceHelper: ResourceHelper
|
@Inject lateinit var resourceHelper: ResourceHelper
|
||||||
@Inject lateinit var sp: SP
|
@Inject lateinit var sp: SP
|
||||||
|
@ -113,7 +112,6 @@ class NSClientService : DaggerService() {
|
||||||
var latestDateInReceivedData: Long = 0
|
var latestDateInReceivedData: Long = 0
|
||||||
|
|
||||||
@SuppressLint("WakelockTimeout")
|
@SuppressLint("WakelockTimeout")
|
||||||
@kotlin.ExperimentalStdlibApi
|
|
||||||
override fun onCreate() {
|
override fun onCreate() {
|
||||||
super.onCreate()
|
super.onCreate()
|
||||||
wakeLock = (getSystemService(Context.POWER_SERVICE) as PowerManager).newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "AndroidAPS:NSClientService")
|
wakeLock = (getSystemService(Context.POWER_SERVICE) as PowerManager).newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "AndroidAPS:NSClientService")
|
||||||
|
@ -199,7 +197,7 @@ class NSClientService : DaggerService() {
|
||||||
.build())
|
.build())
|
||||||
}
|
}
|
||||||
|
|
||||||
fun processAuthAck(ack: NSAuthAck) {
|
private fun processAuthAck(ack: NSAuthAck) {
|
||||||
var connectionStatus = "Authenticated ("
|
var connectionStatus = "Authenticated ("
|
||||||
if (ack.read) connectionStatus += "R"
|
if (ack.read) connectionStatus += "R"
|
||||||
if (ack.write) connectionStatus += "W"
|
if (ack.write) connectionStatus += "W"
|
||||||
|
@ -237,7 +235,6 @@ class NSClientService : DaggerService() {
|
||||||
return START_STICKY
|
return START_STICKY
|
||||||
}
|
}
|
||||||
|
|
||||||
@kotlin.ExperimentalStdlibApi
|
|
||||||
fun initialize() {
|
fun initialize() {
|
||||||
dataCounter = 0
|
dataCounter = 0
|
||||||
readPreferences()
|
readPreferences()
|
||||||
|
@ -488,7 +485,7 @@ class NSClientService : DaggerService() {
|
||||||
val intent = Intent(Intents.ACTION_NEW_PROFILE)
|
val intent = Intent(Intents.ACTION_NEW_PROFILE)
|
||||||
intent.putExtras(bundle)
|
intent.putExtras(bundle)
|
||||||
intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES)
|
intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES)
|
||||||
sendBroadcast(intent)
|
broadcast(intent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -516,7 +513,7 @@ class NSClientService : DaggerService() {
|
||||||
val intent = Intent(Intents.ACTION_REMOVED_TREATMENT)
|
val intent = Intent(Intents.ACTION_REMOVED_TREATMENT)
|
||||||
intent.putExtras(bundle)
|
intent.putExtras(bundle)
|
||||||
intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES)
|
intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES)
|
||||||
sendBroadcast(intent)
|
broadcast(intent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (addedOrUpdatedTreatments.length() > 0) {
|
if (addedOrUpdatedTreatments.length() > 0) {
|
||||||
|
@ -533,7 +530,7 @@ class NSClientService : DaggerService() {
|
||||||
val intent = Intent(Intents.ACTION_CHANGED_TREATMENT)
|
val intent = Intent(Intents.ACTION_CHANGED_TREATMENT)
|
||||||
intent.putExtras(bundle)
|
intent.putExtras(bundle)
|
||||||
intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES)
|
intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES)
|
||||||
sendBroadcast(intent)
|
broadcast(intent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -581,7 +578,7 @@ class NSClientService : DaggerService() {
|
||||||
val intent = Intent(Intents.ACTION_NEW_SGV)
|
val intent = Intent(Intents.ACTION_NEW_SGV)
|
||||||
intent.putExtras(bundle)
|
intent.putExtras(bundle)
|
||||||
intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES)
|
intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES)
|
||||||
sendBroadcast(intent)
|
broadcast(intent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -652,7 +649,6 @@ class NSClientService : DaggerService() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@kotlin.ExperimentalStdlibApi
|
|
||||||
fun restart() {
|
fun restart() {
|
||||||
destroy()
|
destroy()
|
||||||
initialize()
|
initialize()
|
||||||
|
@ -721,6 +717,16 @@ class NSClientService : DaggerService() {
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun broadcast(intent: Intent) {
|
||||||
|
val receivers: List<ResolveInfo> = packageManager.queryBroadcastReceivers(intent, 0)
|
||||||
|
for (resolveInfo in receivers)
|
||||||
|
resolveInfo.activityInfo.packageName?.let {
|
||||||
|
intent.setPackage(it)
|
||||||
|
sendBroadcast(intent)
|
||||||
|
aapsLogger.debug(LTag.CORE, "Sending broadcast " + intent.action + " to: " + it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
init {
|
init {
|
||||||
if (handler == null) {
|
if (handler == null) {
|
||||||
val handlerThread = HandlerThread(NSClientService::class.java.simpleName + "Handler")
|
val handlerThread = HandlerThread(NSClientService::class.java.simpleName + "Handler")
|
||||||
|
|
|
@ -1,68 +0,0 @@
|
||||||
package info.nightscout.androidaps.plugins.general.openhumans
|
|
||||||
|
|
||||||
import android.app.Notification
|
|
||||||
import android.content.Context
|
|
||||||
import android.net.wifi.WifiManager
|
|
||||||
import androidx.core.app.NotificationCompat
|
|
||||||
import androidx.work.ForegroundInfo
|
|
||||||
import androidx.work.RxWorker
|
|
||||||
import androidx.work.WorkerParameters
|
|
||||||
import info.nightscout.androidaps.MainApp
|
|
||||||
import info.nightscout.androidaps.plugins.general.openhumans.OpenHumansUploader.Companion.NOTIFICATION_CHANNEL
|
|
||||||
import info.nightscout.androidaps.plugins.general.openhumans.OpenHumansUploader.Companion.UPLOAD_NOTIFICATION_ID
|
|
||||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
|
||||||
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
|
||||||
import io.reactivex.Single
|
|
||||||
import java.util.concurrent.TimeUnit
|
|
||||||
import javax.inject.Inject
|
|
||||||
|
|
||||||
class OHUploadWorker(context: Context, workerParameters: WorkerParameters)
|
|
||||||
: RxWorker(context, workerParameters) {
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
lateinit var sp: SP
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
lateinit var openHumansUploader: OpenHumansUploader
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
lateinit var resourceHelper: ResourceHelper
|
|
||||||
|
|
||||||
@kotlin.ExperimentalStdlibApi
|
|
||||||
override fun createWork(): Single<Result> = Single.defer {
|
|
||||||
|
|
||||||
// Here we inject every time we create work
|
|
||||||
// We could build our own WorkerFactory with dagger but this will create conflicts with other Workers
|
|
||||||
// (see https://medium.com/wonderquill/how-to-pass-custom-parameters-to-rxworker-worker-using-dagger-2-f4cfbc9892ba)
|
|
||||||
// This class will be replaced with new DB
|
|
||||||
|
|
||||||
(applicationContext as MainApp).androidInjector().inject(this)
|
|
||||||
|
|
||||||
val wifiManager = applicationContext.getSystemService(Context.WIFI_SERVICE) as? WifiManager
|
|
||||||
val wifiOnly = sp.getBoolean("key_oh_wifi_only", true)
|
|
||||||
val isConnectedToWifi = wifiManager?.isWifiEnabled ?: false && wifiManager?.connectionInfo?.networkId != -1
|
|
||||||
if (!wifiOnly || (wifiOnly && isConnectedToWifi)) {
|
|
||||||
setForegroundAsync(createForegroundInfo())
|
|
||||||
openHumansUploader.uploadDataSegmentally()
|
|
||||||
.andThen(Single.just(Result.success()))
|
|
||||||
.onErrorResumeNext { Single.just(Result.retry()) }
|
|
||||||
} else {
|
|
||||||
Single.just(Result.retry())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun createForegroundInfo(): ForegroundInfo {
|
|
||||||
val title = resourceHelper.gs(info.nightscout.androidaps.R.string.open_humans)
|
|
||||||
|
|
||||||
val notification: Notification = NotificationCompat.Builder(applicationContext, NOTIFICATION_CHANNEL)
|
|
||||||
.setContentTitle(title)
|
|
||||||
.setTicker(title)
|
|
||||||
.setContentText(resourceHelper.gs(info.nightscout.androidaps.R.string.your_phone_is_upload_data))
|
|
||||||
.setSmallIcon(info.nightscout.androidaps.R.drawable.notif_icon)
|
|
||||||
.setOngoing(true)
|
|
||||||
.setProgress(0, 0 , true)
|
|
||||||
.build()
|
|
||||||
return ForegroundInfo(UPLOAD_NOTIFICATION_ID, notification)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,191 +0,0 @@
|
||||||
package info.nightscout.androidaps.plugins.general.openhumans
|
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
|
||||||
import android.util.Base64
|
|
||||||
import io.reactivex.Completable
|
|
||||||
import io.reactivex.Single
|
|
||||||
import io.reactivex.disposables.Disposables
|
|
||||||
import okhttp3.*
|
|
||||||
import okio.BufferedSink
|
|
||||||
import org.json.JSONArray
|
|
||||||
import org.json.JSONObject
|
|
||||||
import java.io.IOException
|
|
||||||
import java.text.SimpleDateFormat
|
|
||||||
import java.util.*
|
|
||||||
|
|
||||||
class OpenHumansAPI(
|
|
||||||
private val baseUrl: String,
|
|
||||||
clientId: String,
|
|
||||||
clientSecret: String,
|
|
||||||
private val redirectUri: String
|
|
||||||
) {
|
|
||||||
|
|
||||||
private val authHeader = "Basic " + Base64.encodeToString("$clientId:$clientSecret".toByteArray(), Base64.NO_WRAP)
|
|
||||||
private val client = OkHttpClient()
|
|
||||||
|
|
||||||
fun exchangeAuthToken(code: String): Single<OAuthTokens> = sendTokenRequest(FormBody.Builder()
|
|
||||||
.add("grant_type", "authorization_code")
|
|
||||||
.add("redirect_uri", redirectUri)
|
|
||||||
.add("code", code)
|
|
||||||
.build())
|
|
||||||
|
|
||||||
fun refreshAccessToken(refreshToken: String): Single<OAuthTokens> = sendTokenRequest(FormBody.Builder()
|
|
||||||
.add("grant_type", "refresh_token")
|
|
||||||
.add("redirect_uri", redirectUri)
|
|
||||||
.add("refresh_token", refreshToken)
|
|
||||||
.build())
|
|
||||||
|
|
||||||
private fun sendTokenRequest(body: FormBody) = Request.Builder()
|
|
||||||
.url("$baseUrl/oauth2/token/")
|
|
||||||
.addHeader("Authorization", authHeader)
|
|
||||||
.post(body)
|
|
||||||
.build()
|
|
||||||
.toSingle()
|
|
||||||
.map { response ->
|
|
||||||
response.use { _ ->
|
|
||||||
val responseBody = response.body
|
|
||||||
val jsonObject = responseBody?.let { JSONObject(it.string()) }
|
|
||||||
if (!response.isSuccessful) throw OHHttpException(response.code, response.message, jsonObject?.getString("error"))
|
|
||||||
if (jsonObject == null) throw OHHttpException(response.code, response.message, "No body")
|
|
||||||
if (!jsonObject.has("expires_in")) throw OHMissingFieldException("expires_in")
|
|
||||||
OAuthTokens(
|
|
||||||
accessToken = jsonObject.getString("access_token")
|
|
||||||
?: throw OHMissingFieldException("access_token"),
|
|
||||||
refreshToken = jsonObject.getString("refresh_token")
|
|
||||||
?: throw OHMissingFieldException("refresh_token"),
|
|
||||||
expiresAt = response.sentRequestAtMillis + jsonObject.getInt("expires_in") * 1000L
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getProjectMemberId(accessToken: String): Single<String> = Request.Builder()
|
|
||||||
.url("$baseUrl/api/direct-sharing/project/exchange-member/?access_token=$accessToken")
|
|
||||||
.get()
|
|
||||||
.build()
|
|
||||||
.toSingle()
|
|
||||||
.map {
|
|
||||||
it.jsonBody.getString("project_member_id")
|
|
||||||
?: throw OHMissingFieldException("project_member_id")
|
|
||||||
}
|
|
||||||
|
|
||||||
fun prepareFileUpload(accessToken: String, fileName: String, metadata: FileMetadata): Single<PreparedUpload> = Request.Builder()
|
|
||||||
.url("$baseUrl/api/direct-sharing/project/files/upload/direct/?access_token=$accessToken")
|
|
||||||
.post(FormBody.Builder()
|
|
||||||
.add("filename", fileName)
|
|
||||||
.add("metadata", metadata.toJSON().toString())
|
|
||||||
.build())
|
|
||||||
.build()
|
|
||||||
.toSingle()
|
|
||||||
.map {
|
|
||||||
val json = it.jsonBody
|
|
||||||
PreparedUpload(
|
|
||||||
fileId = json.getString("id") ?: throw OHMissingFieldException("id"),
|
|
||||||
uploadURL = json.getString("url") ?: throw OHMissingFieldException("url")
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun uploadFile(url: String, content: ByteArray): Completable = Request.Builder()
|
|
||||||
.url(url)
|
|
||||||
.put(object : RequestBody() {
|
|
||||||
override fun contentType(): MediaType? = null
|
|
||||||
|
|
||||||
override fun contentLength() = content.size.toLong()
|
|
||||||
|
|
||||||
override fun writeTo(sink: BufferedSink) {
|
|
||||||
sink.write(content)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.build()
|
|
||||||
.toSingle()
|
|
||||||
.doOnSuccess { response ->
|
|
||||||
response.use { _ ->
|
|
||||||
if (!response.isSuccessful) throw OHHttpException(response.code, response.message, null)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.ignoreElement()
|
|
||||||
|
|
||||||
fun completeFileUpload(accessToken: String, fileId: String): Completable = Request.Builder()
|
|
||||||
.url("$baseUrl/api/direct-sharing/project/files/upload/complete/?access_token=$accessToken")
|
|
||||||
.post(FormBody.Builder()
|
|
||||||
.add("file_id", fileId)
|
|
||||||
.build())
|
|
||||||
.build()
|
|
||||||
.toSingle()
|
|
||||||
.doOnSuccess { it.jsonBody }
|
|
||||||
.ignoreElement()
|
|
||||||
|
|
||||||
private fun Request.toSingle() = Single.create<Response> {
|
|
||||||
val call = client.newCall(this)
|
|
||||||
call.enqueue(object : Callback {
|
|
||||||
override fun onFailure(call: Call, e: IOException) {
|
|
||||||
it.tryOnError(e)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onResponse(call: Call, response: Response) {
|
|
||||||
it.onSuccess(response)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
it.setDisposable(Disposables.fromRunnable { call.cancel() })
|
|
||||||
}
|
|
||||||
|
|
||||||
private val Response.jsonBody
|
|
||||||
get() = use { _ ->
|
|
||||||
val jsonObject = body?.let { JSONObject(it.string()) }
|
|
||||||
?: throw OHHttpException(code, message, null)
|
|
||||||
if (!isSuccessful) throw OHHttpException(code, message, jsonObject.getString("detail"))
|
|
||||||
jsonObject
|
|
||||||
}
|
|
||||||
|
|
||||||
data class OAuthTokens(
|
|
||||||
val accessToken: String,
|
|
||||||
val refreshToken: String,
|
|
||||||
val expiresAt: Long
|
|
||||||
)
|
|
||||||
|
|
||||||
data class FileMetadata(
|
|
||||||
val tags: List<String>,
|
|
||||||
val description: String,
|
|
||||||
val md5: String? = null,
|
|
||||||
val creationDate: Long? = null,
|
|
||||||
val startDate: Long? = null,
|
|
||||||
val endDate: Long? = null
|
|
||||||
) {
|
|
||||||
|
|
||||||
fun toJSON(): JSONObject {
|
|
||||||
val jsonObject = JSONObject()
|
|
||||||
jsonObject.put("tags", JSONArray().apply { tags.forEach { put(it) } })
|
|
||||||
jsonObject.put("description", description)
|
|
||||||
jsonObject.put("md5", md5)
|
|
||||||
creationDate?.let { jsonObject.put("creation_date", iso8601DateFormatter.format(Date(it))) }
|
|
||||||
startDate?.let { jsonObject.put("start_date", iso8601DateFormatter.format(Date(it))) }
|
|
||||||
endDate?.let { jsonObject.put("end_date", iso8601DateFormatter.format(Date(it))) }
|
|
||||||
return jsonObject
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
data class PreparedUpload(
|
|
||||||
val fileId: String,
|
|
||||||
val uploadURL: String
|
|
||||||
)
|
|
||||||
|
|
||||||
data class OHHttpException(
|
|
||||||
val code: Int,
|
|
||||||
val meaning: String,
|
|
||||||
val detail: String?
|
|
||||||
) : RuntimeException() {
|
|
||||||
|
|
||||||
override val message: String get() = toString()
|
|
||||||
}
|
|
||||||
|
|
||||||
data class OHMissingFieldException(
|
|
||||||
val name: String
|
|
||||||
) : RuntimeException() {
|
|
||||||
|
|
||||||
override val message: String get() = toString()
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
@SuppressLint("SimpleDateFormat")
|
|
||||||
private val iso8601DateFormatter = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX")
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,116 +0,0 @@
|
||||||
package info.nightscout.androidaps.plugins.general.openhumans
|
|
||||||
|
|
||||||
import android.content.Intent
|
|
||||||
import android.os.Bundle
|
|
||||||
import android.view.LayoutInflater
|
|
||||||
import android.view.View
|
|
||||||
import android.view.ViewGroup
|
|
||||||
import android.widget.Button
|
|
||||||
import android.widget.TextView
|
|
||||||
import androidx.work.WorkManager
|
|
||||||
import dagger.android.support.DaggerFragment
|
|
||||||
import info.nightscout.androidaps.R
|
|
||||||
import info.nightscout.androidaps.events.Event
|
|
||||||
import info.nightscout.androidaps.interfaces.DatabaseHelperInterface
|
|
||||||
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
|
||||||
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
|
|
||||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
|
||||||
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
|
||||||
import io.reactivex.BackpressureStrategy
|
|
||||||
import io.reactivex.Single
|
|
||||||
import io.reactivex.disposables.CompositeDisposable
|
|
||||||
import io.reactivex.rxkotlin.plusAssign
|
|
||||||
import java.util.concurrent.TimeUnit
|
|
||||||
import javax.inject.Inject
|
|
||||||
|
|
||||||
class OpenHumansFragment : DaggerFragment() {
|
|
||||||
|
|
||||||
private var viewsCreated = false
|
|
||||||
private var login: Button? = null
|
|
||||||
private var logout: Button? = null
|
|
||||||
private var memberId: TextView? = null
|
|
||||||
private var queueSize: TextView? = null
|
|
||||||
private var workerState: TextView? = null
|
|
||||||
private var queueSizeValue = 0L
|
|
||||||
private val compositeDisposable = CompositeDisposable()
|
|
||||||
|
|
||||||
@Inject lateinit var rxBus: RxBusWrapper
|
|
||||||
@Inject lateinit var openHumansUploader: OpenHumansUploader
|
|
||||||
@Inject lateinit var resourceHelper: ResourceHelper
|
|
||||||
@Inject lateinit var aapsSchedulers: AapsSchedulers
|
|
||||||
@Inject lateinit var databaseHelper: DatabaseHelperInterface
|
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
|
||||||
super.onCreate(savedInstanceState)
|
|
||||||
compositeDisposable += Single.fromCallable { databaseHelper.getOHQueueSize() }
|
|
||||||
.subscribeOn(aapsSchedulers.io)
|
|
||||||
.repeatWhen {
|
|
||||||
rxBus.toObservable(UpdateViewEvent::class.java)
|
|
||||||
.cast(Any::class.java)
|
|
||||||
.mergeWith(rxBus.toObservable(UpdateQueueEvent::class.java)
|
|
||||||
.throttleLatest(5, TimeUnit.SECONDS))
|
|
||||||
.toFlowable(BackpressureStrategy.LATEST)
|
|
||||||
}
|
|
||||||
.observeOn(aapsSchedulers.main)
|
|
||||||
.subscribe({
|
|
||||||
queueSizeValue = it
|
|
||||||
updateGUI()
|
|
||||||
}, {})
|
|
||||||
context?.applicationContext?.let { appContext ->
|
|
||||||
WorkManager.getInstance(appContext).getWorkInfosForUniqueWorkLiveData(OpenHumansUploader.WORK_NAME).observe(this, {
|
|
||||||
val workInfo = it.lastOrNull()
|
|
||||||
if (workInfo == null) {
|
|
||||||
workerState?.visibility = View.GONE
|
|
||||||
} else {
|
|
||||||
workerState?.visibility = View.VISIBLE
|
|
||||||
workerState?.text = getString(R.string.worker_state, workInfo.state.toString())
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onDestroy() {
|
|
||||||
compositeDisposable.clear()
|
|
||||||
super.onDestroy()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
|
|
||||||
val view = inflater.inflate(R.layout.fragment_open_humans, container, false)
|
|
||||||
login = view.findViewById(R.id.login)
|
|
||||||
logout = view.findViewById(R.id.logout)
|
|
||||||
memberId = view.findViewById(R.id.member_id)
|
|
||||||
queueSize = view.findViewById(R.id.queue_size)
|
|
||||||
workerState = view.findViewById(R.id.worker_state)
|
|
||||||
login!!.setOnClickListener { startActivity(Intent(context, OpenHumansLoginActivity::class.java)) }
|
|
||||||
logout!!.setOnClickListener {
|
|
||||||
activity?.let { activity -> OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.oh_logout_confirmation)) { openHumansUploader.logout() } }
|
|
||||||
}
|
|
||||||
viewsCreated = true
|
|
||||||
updateGUI()
|
|
||||||
return view
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onDestroyView() {
|
|
||||||
viewsCreated = false
|
|
||||||
login = null
|
|
||||||
logout = null
|
|
||||||
memberId = null
|
|
||||||
queueSize = null
|
|
||||||
super.onDestroyView()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun updateGUI() {
|
|
||||||
if (viewsCreated) {
|
|
||||||
queueSize!!.text = getString(R.string.queue_size, queueSizeValue)
|
|
||||||
val projectMemberId = openHumansUploader.projectMemberId
|
|
||||||
memberId!!.text = getString(R.string.project_member_id, projectMemberId
|
|
||||||
?: getString(R.string.not_logged_in))
|
|
||||||
login!!.visibility = if (projectMemberId == null) View.VISIBLE else View.GONE
|
|
||||||
logout!!.visibility = if (projectMemberId != null) View.VISIBLE else View.GONE
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
object UpdateViewEvent : Event()
|
|
||||||
|
|
||||||
object UpdateQueueEvent : Event()
|
|
||||||
}
|
|
|
@ -1,138 +0,0 @@
|
||||||
package info.nightscout.androidaps.plugins.general.openhumans
|
|
||||||
|
|
||||||
import android.app.Dialog
|
|
||||||
import android.content.Intent
|
|
||||||
import android.net.Uri
|
|
||||||
import android.os.Bundle
|
|
||||||
import android.widget.Button
|
|
||||||
import android.widget.CheckBox
|
|
||||||
import android.widget.Toast
|
|
||||||
import androidx.appcompat.app.AlertDialog
|
|
||||||
import androidx.browser.customtabs.CustomTabsIntent
|
|
||||||
import androidx.fragment.app.DialogFragment
|
|
||||||
import androidx.fragment.app.FragmentActivity
|
|
||||||
import dagger.android.support.DaggerDialogFragment
|
|
||||||
import info.nightscout.androidaps.R
|
|
||||||
import info.nightscout.androidaps.activities.NoSplashAppCompatActivity
|
|
||||||
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
|
||||||
import io.reactivex.disposables.Disposable
|
|
||||||
import javax.inject.Inject
|
|
||||||
|
|
||||||
class OpenHumansLoginActivity : NoSplashAppCompatActivity() {
|
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
|
||||||
super.onCreate(savedInstanceState)
|
|
||||||
setContentView(R.layout.activity_open_humans_login)
|
|
||||||
val button = findViewById<Button>(R.id.button)
|
|
||||||
val checkbox = findViewById<CheckBox>(R.id.checkbox)
|
|
||||||
|
|
||||||
button.setOnClickListener {
|
|
||||||
if (checkbox.isChecked) {
|
|
||||||
CustomTabsIntent.Builder().build().launchUrl(this, Uri.parse(OpenHumansUploader.AUTH_URL))
|
|
||||||
} else {
|
|
||||||
Toast.makeText(this, R.string.you_need_to_accept_the_of_use_first, Toast.LENGTH_SHORT).show()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onNewIntent(intent: Intent) {
|
|
||||||
super.onNewIntent(intent)
|
|
||||||
val code = intent.data?.getQueryParameter("code")
|
|
||||||
if (supportFragmentManager.fragments.size == 0 && code != null) {
|
|
||||||
ExchangeAuthTokenDialog(code).show(supportFragmentManager, "ExchangeAuthTokenDialog")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class ExchangeAuthTokenDialog : DaggerDialogFragment() {
|
|
||||||
|
|
||||||
@Inject lateinit var openHumansUploader: OpenHumansUploader
|
|
||||||
@Inject lateinit var aapsSchedulers: AapsSchedulers
|
|
||||||
|
|
||||||
private var disposable: Disposable? = null
|
|
||||||
|
|
||||||
init {
|
|
||||||
isCancelable = false
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
|
||||||
return AlertDialog.Builder(requireActivity())
|
|
||||||
.setTitle(R.string.completing_login)
|
|
||||||
.setMessage(R.string.please_wait)
|
|
||||||
.create()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
|
||||||
super.onCreate(savedInstanceState)
|
|
||||||
disposable = openHumansUploader.login(arguments?.getString("authToken")!!).subscribeOn(aapsSchedulers.io).subscribe({
|
|
||||||
dismiss()
|
|
||||||
SetupDoneDialog().show(parentFragmentManager, "SetupDoneDialog")
|
|
||||||
}, {
|
|
||||||
dismiss()
|
|
||||||
ErrorDialog(it.message).show(parentFragmentManager, "ErrorDialog")
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onDestroy() {
|
|
||||||
disposable?.dispose()
|
|
||||||
super.onDestroy()
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
|
|
||||||
operator fun invoke(authToken: String): ExchangeAuthTokenDialog {
|
|
||||||
val dialog = ExchangeAuthTokenDialog()
|
|
||||||
val args = Bundle()
|
|
||||||
args.putString("authToken", authToken)
|
|
||||||
dialog.arguments = args
|
|
||||||
return dialog
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class ErrorDialog : DialogFragment() {
|
|
||||||
|
|
||||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
|
||||||
val message = arguments?.getString("message")
|
|
||||||
val shownMessage = if (message == null) getString(R.string.there_was_an_error)
|
|
||||||
else "${getString(R.string.there_was_an_error)}\n\n$message"
|
|
||||||
return AlertDialog.Builder(requireActivity())
|
|
||||||
.setTitle(R.string.error)
|
|
||||||
.setMessage(shownMessage)
|
|
||||||
.setPositiveButton(R.string.close, null)
|
|
||||||
.create()
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
|
|
||||||
operator fun invoke(message: String?): ErrorDialog {
|
|
||||||
val dialog = ErrorDialog()
|
|
||||||
val args = Bundle()
|
|
||||||
args.putString("message", message)
|
|
||||||
dialog.arguments = args
|
|
||||||
return dialog
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class SetupDoneDialog : DialogFragment() {
|
|
||||||
|
|
||||||
init {
|
|
||||||
isCancelable = false
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
|
||||||
return AlertDialog.Builder(requireActivity())
|
|
||||||
.setTitle(R.string.successfully_logged_in)
|
|
||||||
.setMessage(R.string.setup_will_continue_in_background)
|
|
||||||
.setCancelable(false)
|
|
||||||
.setPositiveButton(R.string.close) { _, _ ->
|
|
||||||
requireActivity().run {
|
|
||||||
setResult(FragmentActivity.RESULT_OK)
|
|
||||||
requireActivity().finish()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.create()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,652 +0,0 @@
|
||||||
package info.nightscout.androidaps.plugins.general.openhumans
|
|
||||||
|
|
||||||
import android.app.NotificationChannel
|
|
||||||
import android.app.NotificationManager
|
|
||||||
import android.app.PendingIntent
|
|
||||||
import android.content.Context
|
|
||||||
import android.content.Intent
|
|
||||||
import android.os.Build
|
|
||||||
import android.os.PowerManager
|
|
||||||
import android.util.DisplayMetrics
|
|
||||||
import android.view.WindowManager
|
|
||||||
import androidx.core.app.NotificationCompat
|
|
||||||
import androidx.core.app.NotificationManagerCompat
|
|
||||||
import androidx.work.*
|
|
||||||
import dagger.android.HasAndroidInjector
|
|
||||||
import info.nightscout.androidaps.BuildConfig
|
|
||||||
import info.nightscout.androidaps.R
|
|
||||||
import info.nightscout.androidaps.database.AppRepository
|
|
||||||
import info.nightscout.androidaps.database.entities.GlucoseValue
|
|
||||||
import info.nightscout.androidaps.database.entities.TemporaryTarget
|
|
||||||
import info.nightscout.androidaps.database.entities.TherapyEvent
|
|
||||||
import info.nightscout.androidaps.db.*
|
|
||||||
import info.nightscout.androidaps.events.EventPreferenceChange
|
|
||||||
import info.nightscout.androidaps.interfaces.DatabaseHelperInterface
|
|
||||||
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.extensions.toConstant
|
|
||||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
|
||||||
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
|
||||||
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
|
||||||
import io.reactivex.Completable
|
|
||||||
import io.reactivex.Observable
|
|
||||||
import io.reactivex.Single
|
|
||||||
import io.reactivex.disposables.CompositeDisposable
|
|
||||||
import io.reactivex.disposables.Disposable
|
|
||||||
import io.reactivex.rxkotlin.plusAssign
|
|
||||||
import org.json.JSONArray
|
|
||||||
import org.json.JSONException
|
|
||||||
import org.json.JSONObject
|
|
||||||
import java.io.ByteArrayOutputStream
|
|
||||||
import java.security.MessageDigest
|
|
||||||
import java.text.SimpleDateFormat
|
|
||||||
import java.util.*
|
|
||||||
import java.util.concurrent.TimeUnit
|
|
||||||
import java.util.zip.ZipEntry
|
|
||||||
import java.util.zip.ZipOutputStream
|
|
||||||
import javax.inject.Inject
|
|
||||||
import javax.inject.Singleton
|
|
||||||
|
|
||||||
@Singleton
|
|
||||||
class OpenHumansUploader @Inject constructor(
|
|
||||||
injector: HasAndroidInjector,
|
|
||||||
resourceHelper: ResourceHelper,
|
|
||||||
aapsLogger: AAPSLogger,
|
|
||||||
private val aapsSchedulers: AapsSchedulers,
|
|
||||||
private val sp: SP,
|
|
||||||
private val rxBus: RxBusWrapper,
|
|
||||||
private val context: Context,
|
|
||||||
private val databaseHelper: DatabaseHelperInterface,
|
|
||||||
val repository: AppRepository
|
|
||||||
) : PluginBase(
|
|
||||||
PluginDescription()
|
|
||||||
.mainType(PluginType.GENERAL)
|
|
||||||
.pluginIcon(R.drawable.open_humans_white)
|
|
||||||
.pluginName(R.string.open_humans)
|
|
||||||
.shortName(R.string.open_humans_short)
|
|
||||||
.description(R.string.donate_your_data_to_science)
|
|
||||||
.fragmentClass(OpenHumansFragment::class.qualifiedName)
|
|
||||||
.preferencesId(R.xml.pref_openhumans),
|
|
||||||
aapsLogger, resourceHelper, injector) {
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
|
|
||||||
private const val OPEN_HUMANS_URL = "https://www.openhumans.org"
|
|
||||||
private const val CLIENT_ID = "oie6DvnaEOagTxSoD6BukkLPwDhVr6cMlN74Ihz1"
|
|
||||||
private const val CLIENT_SECRET = "jR0N8pkH1jOwtozHc7CsB1UPcJzFN95ldHcK4VGYIApecr8zGJox0v06xLwPLMASScngT12aIaIHXAVCJeKquEXAWG1XekZdbubSpccgNiQBmuVmIF8nc1xSKSNJltCf"
|
|
||||||
private const val REDIRECT_URL = "androidaps://setup-openhumans"
|
|
||||||
const val AUTH_URL = "https://www.openhumans.org/direct-sharing/projects/oauth2/authorize/?client_id=$CLIENT_ID&response_type=code"
|
|
||||||
const val WORK_NAME = "Open Humans"
|
|
||||||
const val NOTIFICATION_CHANNEL = "OpenHumans"
|
|
||||||
private const val COPY_NOTIFICATION_ID = 3122
|
|
||||||
private const val FAILURE_NOTIFICATION_ID = 3123
|
|
||||||
private const val SUCCESS_NOTIFICATION_ID = 3124
|
|
||||||
private const val SIGNED_OUT_NOTIFICATION_ID = 3125
|
|
||||||
const val UPLOAD_NOTIFICATION_ID = 3126
|
|
||||||
private const val UPLOAD_SEGMENT_SIZE = 10000L
|
|
||||||
}
|
|
||||||
|
|
||||||
private val openHumansAPI = OpenHumansAPI(OPEN_HUMANS_URL, CLIENT_ID, CLIENT_SECRET, REDIRECT_URL)
|
|
||||||
|
|
||||||
@Suppress("PrivatePropertyName")
|
|
||||||
private val FILE_NAME_DATE_FORMAT = SimpleDateFormat("yyyyMMdd'T'HHmmss", Locale.US).apply { timeZone = TimeZone.getTimeZone("UTC") }
|
|
||||||
|
|
||||||
private var isSetup
|
|
||||||
get() = sp.getBoolean("openhumans_is_setup", false)
|
|
||||||
set(value) = sp.putBoolean("openhumans_is_setup", value)
|
|
||||||
private var oAuthTokens: OpenHumansAPI.OAuthTokens?
|
|
||||||
get() {
|
|
||||||
return if (sp.contains("openhumans_access_token") && sp.contains("openhumans_refresh_token") && sp.contains("openhumans_expires_at")) {
|
|
||||||
OpenHumansAPI.OAuthTokens(
|
|
||||||
accessToken = sp.getStringOrNull("openhumans_access_token", null)!!,
|
|
||||||
refreshToken = sp.getStringOrNull("openhumans_refresh_token", null)!!,
|
|
||||||
expiresAt = sp.getLong("openhumans_expires_at", 0)
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
set(value) {
|
|
||||||
if (value != null) {
|
|
||||||
sp.putString("openhumans_access_token", value.accessToken)
|
|
||||||
sp.putString("openhumans_refresh_token", value.refreshToken)
|
|
||||||
sp.putLong("openhumans_expires_at", value.expiresAt)
|
|
||||||
} else {
|
|
||||||
sp.remove("openhumans_access_token")
|
|
||||||
sp.remove("openhumans_refresh_token")
|
|
||||||
sp.remove("openhumans_expires_at")
|
|
||||||
sp.remove("openhumans_expires_at")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var projectMemberId: String?
|
|
||||||
get() = sp.getStringOrNull("openhumans_project_member_id", null)
|
|
||||||
private set(value) {
|
|
||||||
if (value == null) sp.remove("openhumans_project_member_id")
|
|
||||||
else sp.putString("openhumans_project_member_id", value)
|
|
||||||
}
|
|
||||||
private var uploadCounter: Int
|
|
||||||
get() = sp.getInt("openhumans_counter", 1)
|
|
||||||
set(value) = sp.putInt("openhumans_counter", value)
|
|
||||||
private val appId: UUID
|
|
||||||
get() {
|
|
||||||
val id = sp.getStringOrNull("openhumans_appid", null)
|
|
||||||
return if (id == null) {
|
|
||||||
val generated = UUID.randomUUID()
|
|
||||||
sp.putString("openhumans_appid", generated.toString())
|
|
||||||
generated
|
|
||||||
} else {
|
|
||||||
UUID.fromString(id)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private var copyDisposable: Disposable? = null
|
|
||||||
|
|
||||||
private val wakeLock = (context.getSystemService(Context.POWER_SERVICE) as PowerManager)
|
|
||||||
.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "AndroidAPS::OpenHumans")
|
|
||||||
|
|
||||||
private val preferenceChangeDisposable = CompositeDisposable()
|
|
||||||
|
|
||||||
override fun onStart() {
|
|
||||||
super.onStart()
|
|
||||||
setupNotificationChannel()
|
|
||||||
if (isSetup) scheduleWorker(false)
|
|
||||||
preferenceChangeDisposable += rxBus.toObservable(EventPreferenceChange::class.java).subscribe {
|
|
||||||
onSharedPreferenceChanged(it)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onStop() {
|
|
||||||
copyDisposable?.dispose()
|
|
||||||
cancelWorker()
|
|
||||||
preferenceChangeDisposable.clear()
|
|
||||||
super.onStop()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun enqueueBGReading(glucoseValue: GlucoseValue?) = glucoseValue?.let {
|
|
||||||
insertQueueItem("BgReadings") {
|
|
||||||
put("date", glucoseValue.timestamp)
|
|
||||||
put("isValid", glucoseValue.isValid)
|
|
||||||
put("value", glucoseValue.value)
|
|
||||||
put("direction", glucoseValue.trendArrow)
|
|
||||||
put("raw", glucoseValue.raw)
|
|
||||||
put("source", glucoseValue.sourceSensor)
|
|
||||||
put("nsId", glucoseValue.interfaceIDs.nightscoutId)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// @JvmOverloads
|
|
||||||
// fun enqueueTreatment(treatment: Treatment?, deleted: Boolean = false) = treatment?.let {
|
|
||||||
// insertQueueItem("Treatments") {
|
|
||||||
// put("date", treatment.date)
|
|
||||||
// put("isValid", treatment.isValid)
|
|
||||||
// put("source", treatment.source)
|
|
||||||
// put("nsId", treatment._id)
|
|
||||||
// put("boluscalc", treatment.boluscalc)
|
|
||||||
// put("carbs", treatment.carbs)
|
|
||||||
// put("dia", treatment.dia)
|
|
||||||
// put("insulin", treatment.insulin)
|
|
||||||
// put("insulinInterfaceID", treatment.insulinInterfaceID)
|
|
||||||
// put("isSMB", treatment.isSMB)
|
|
||||||
// put("mealBolus", treatment.mealBolus)
|
|
||||||
// put("bolusCalcJson", treatment.getBoluscalc())
|
|
||||||
// put("isDeletion", deleted)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
@JvmOverloads
|
|
||||||
fun enqueueTherapyEvent(therapyEvent: TherapyEvent, deleted: Boolean = false) = insertQueueItem("TherapyEvents") {
|
|
||||||
put("date", therapyEvent.timestamp)
|
|
||||||
put("isValid", therapyEvent.isValid)
|
|
||||||
put("nsId", therapyEvent.interfaceIDs.nightscoutId)
|
|
||||||
put("eventType", therapyEvent.type.text)
|
|
||||||
put("glucose", therapyEvent.glucose)
|
|
||||||
put("units", therapyEvent.glucoseUnit.toConstant())
|
|
||||||
put("glucoseType", therapyEvent.glucoseType?.text)
|
|
||||||
put("duration", therapyEvent.duration)
|
|
||||||
put("isDeletion", deleted)
|
|
||||||
}
|
|
||||||
|
|
||||||
// @JvmOverloads
|
|
||||||
// fun enqueueExtendedBolus(extendedBolus: ExtendedBolus, deleted: Boolean = false) = insertQueueItem("ExtendedBoluses") {
|
|
||||||
// put("date", extendedBolus.date)
|
|
||||||
// put("isValid", extendedBolus.isValid)
|
|
||||||
// put("source", extendedBolus.source)
|
|
||||||
// put("nsId", extendedBolus._id)
|
|
||||||
// put("pumpId", extendedBolus.pumpId)
|
|
||||||
// put("insulin", extendedBolus.insulin)
|
|
||||||
// put("durationInMinutes", extendedBolus.durationInMinutes)
|
|
||||||
// put("isDeletion", deleted)
|
|
||||||
// }
|
|
||||||
|
|
||||||
// @JvmOverloads
|
|
||||||
// fun enqueueProfileSwitch(profileSwitch: ProfileSwitch, deleted: Boolean = false) = insertQueueItem("ProfileSwitches") {
|
|
||||||
// put("date", profileSwitch.date)
|
|
||||||
// put("isValid", profileSwitch.isValid)
|
|
||||||
// put("source", profileSwitch.source)
|
|
||||||
// put("nsId", profileSwitch._id)
|
|
||||||
// put("isCPP", profileSwitch.isCPP)
|
|
||||||
// put("timeshift", profileSwitch.timeshift)
|
|
||||||
// put("percentage", profileSwitch.percentage)
|
|
||||||
// put("profile", JSONObject(profileSwitch.profileJson))
|
|
||||||
// put("profilePlugin", profileSwitch.profilePlugin)
|
|
||||||
// put("durationInMinutes", profileSwitch.durationInMinutes)
|
|
||||||
// put("isDeletion", deleted)
|
|
||||||
// }
|
|
||||||
|
|
||||||
// fun enqueueTotalDailyDose(tdd: TDD) = insertQueueItem("TotalDailyDoses") {
|
|
||||||
// put("double", tdd.date)
|
|
||||||
// put("double", tdd.bolus)
|
|
||||||
// put("double", tdd.basal)
|
|
||||||
// put("double", tdd.total)
|
|
||||||
// }
|
|
||||||
|
|
||||||
// @JvmOverloads
|
|
||||||
// fun enqueueTemporaryBasal(temporaryBasal: TemporaryBasal?, deleted: Boolean = false) = temporaryBasal?.let {
|
|
||||||
// insertQueueItem("TemporaryBasals") {
|
|
||||||
// put("date", temporaryBasal.date)
|
|
||||||
// put("isValid", temporaryBasal.isValid)
|
|
||||||
// put("source", temporaryBasal.source)
|
|
||||||
// put("nsId", temporaryBasal._id)
|
|
||||||
// put("pumpId", temporaryBasal.pumpId)
|
|
||||||
// put("durationInMinutes", temporaryBasal.durationInMinutes)
|
|
||||||
// put("durationInMinutes", temporaryBasal.durationInMinutes)
|
|
||||||
// put("isAbsolute", temporaryBasal.isAbsolute)
|
|
||||||
// put("percentRate", temporaryBasal.percentRate)
|
|
||||||
// put("absoluteRate", temporaryBasal.absoluteRate)
|
|
||||||
// put("isDeletion", deleted)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
@JvmOverloads
|
|
||||||
fun enqueueTempTarget(tempTarget: TemporaryTarget?, deleted: Boolean = false) = tempTarget?.let {
|
|
||||||
insertQueueItem("TempTargets") {
|
|
||||||
put("date", tempTarget.timestamp)
|
|
||||||
put("isValid", tempTarget.isValid)
|
|
||||||
put("nsId", tempTarget.interfaceIDs_backing?.nightscoutId)
|
|
||||||
put("low", tempTarget.lowTarget)
|
|
||||||
put("high", tempTarget.highTarget)
|
|
||||||
put("reason", tempTarget.reason)
|
|
||||||
put("durationInMinutes", tempTarget.duration)
|
|
||||||
put("isDeletion", deleted)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun enqueueSMBData(profile: JSONObject?, glucoseStatus: JSONObject?, iobData: JSONArray?, mealData: JSONObject?, currentTemp: JSONObject?, autosensData: JSONObject?, smbAllowed: Boolean, smbAlwaysAllowed: Boolean, result: JSONObject?) = insertQueueItem("APSData") {
|
|
||||||
put("algorithm", "SMB")
|
|
||||||
put("profile", profile)
|
|
||||||
put("glucoseStatus", glucoseStatus)
|
|
||||||
put("iobData", iobData)
|
|
||||||
put("mealData", mealData)
|
|
||||||
put("currentTemp", currentTemp)
|
|
||||||
put("autosensData", autosensData)
|
|
||||||
put("smbAllowed", smbAllowed)
|
|
||||||
put("smbAlwaysAllowed", smbAlwaysAllowed)
|
|
||||||
put("result", result)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun enqueueAMAData(profile: JSONObject?, glucoseStatus: JSONObject?, iobData: JSONArray?, mealData: JSONObject?, currentTemp: JSONObject?, autosensData: JSONObject?, result: JSONObject?) = insertQueueItem("APSData") {
|
|
||||||
put("algorithm", "AMA")
|
|
||||||
put("profile", profile)
|
|
||||||
put("glucoseStatus", glucoseStatus)
|
|
||||||
put("iobData", iobData)
|
|
||||||
put("mealData", mealData)
|
|
||||||
put("currentTemp", currentTemp)
|
|
||||||
put("autosensData", autosensData)
|
|
||||||
put("result", result)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun insertQueueItem(file: String, structureVersion: Int = 1, generator: JSONObject.() -> Unit) {
|
|
||||||
if (oAuthTokens != null && this.isEnabled(PluginType.GENERAL)) {
|
|
||||||
try {
|
|
||||||
val jsonObject = JSONObject()
|
|
||||||
jsonObject.put("structureVersion", structureVersion)
|
|
||||||
jsonObject.put("queuedOn", System.currentTimeMillis())
|
|
||||||
generator(jsonObject)
|
|
||||||
val queueItem = OHQueueItem(
|
|
||||||
file = file,
|
|
||||||
content = jsonObject.toString()
|
|
||||||
)
|
|
||||||
databaseHelper.createOrUpdate(queueItem)
|
|
||||||
rxBus.send(OpenHumansFragment.UpdateQueueEvent)
|
|
||||||
} catch (e: JSONException) {
|
|
||||||
e.printStackTrace()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun login(authCode: String): Completable =
|
|
||||||
openHumansAPI.exchangeAuthToken(authCode)
|
|
||||||
.doOnSuccess {
|
|
||||||
oAuthTokens = it
|
|
||||||
}
|
|
||||||
.flatMap { openHumansAPI.getProjectMemberId(it.accessToken) }
|
|
||||||
.doOnSuccess {
|
|
||||||
projectMemberId = it
|
|
||||||
copyExistingDataToQueue()
|
|
||||||
rxBus.send(OpenHumansFragment.UpdateViewEvent)
|
|
||||||
}
|
|
||||||
.doOnError {
|
|
||||||
aapsLogger.error("Failed to login to Open Humans", it)
|
|
||||||
}
|
|
||||||
.ignoreElement()
|
|
||||||
|
|
||||||
fun logout() {
|
|
||||||
cancelWorker()
|
|
||||||
copyDisposable?.dispose()
|
|
||||||
isSetup = false
|
|
||||||
oAuthTokens = null
|
|
||||||
projectMemberId = null
|
|
||||||
databaseHelper.clearOpenHumansQueue()
|
|
||||||
rxBus.send(OpenHumansFragment.UpdateViewEvent)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun copyExistingDataToQueue() {
|
|
||||||
copyDisposable?.dispose()
|
|
||||||
var currentProgress = 0L
|
|
||||||
var maxProgress = 0L
|
|
||||||
val increaseCounter = {
|
|
||||||
currentProgress++
|
|
||||||
//Updating the notification for every item drastically slows down the operation
|
|
||||||
if (currentProgress % 1000L == 0L) showOngoingNotification(maxProgress, currentProgress)
|
|
||||||
}
|
|
||||||
copyDisposable = Completable.fromCallable { databaseHelper.clearOpenHumansQueue() }
|
|
||||||
// .andThen(Single.defer { Single.just(databaseHelper.getCountOfAllRows() + treatmentsPlugin.service.count()) })
|
|
||||||
// .doOnSuccess { maxProgress = it }
|
|
||||||
// .flatMapObservable { Observable.defer { Observable.fromIterable(treatmentsPlugin.service.getTreatmentData()) } }
|
|
||||||
// .map { enqueueTreatment(it); increaseCounter() }
|
|
||||||
// .ignoreElements()
|
|
||||||
.andThen(Observable.defer { Observable.fromIterable(repository.compatGetBgReadingsDataFromTime(0, true).blockingGet()) })
|
|
||||||
.map { enqueueBGReading(it); increaseCounter() }
|
|
||||||
.ignoreElements()
|
|
||||||
.andThen(Observable.defer { Observable.fromIterable(repository.compatGetTherapyEventDataFromTime(0, true).blockingGet()) })
|
|
||||||
.map { enqueueTherapyEvent(it); increaseCounter() }
|
|
||||||
.ignoreElements()
|
|
||||||
// .andThen(Observable.defer { Observable.fromIterable(databaseHelper.getAllExtendedBoluses()) })
|
|
||||||
// .map { enqueueExtendedBolus(it); increaseCounter() }
|
|
||||||
// .ignoreElements()
|
|
||||||
// .andThen(Observable.defer { Observable.fromIterable(databaseHelper.getAllProfileSwitches()) })
|
|
||||||
// .map { enqueueProfileSwitch(it); increaseCounter() }
|
|
||||||
// .ignoreElements()
|
|
||||||
// .andThen(Observable.defer { Observable.fromIterable(databaseHelper.getAllTDDs()) })
|
|
||||||
// .map { enqueueTotalDailyDose(it); increaseCounter() }
|
|
||||||
// .ignoreElements()
|
|
||||||
// .andThen(Observable.defer { Observable.fromIterable(databaseHelper.getAllTemporaryBasals()) })
|
|
||||||
// .map { enqueueTemporaryBasal(it); increaseCounter() }
|
|
||||||
// .ignoreElements()
|
|
||||||
.andThen(Observable.defer { Observable.fromIterable(repository.compatGetTemporaryTargetData().blockingGet()) })
|
|
||||||
.map { enqueueTempTarget(it); increaseCounter() }
|
|
||||||
.ignoreElements()
|
|
||||||
.doOnSubscribe {
|
|
||||||
wakeLock.acquire(TimeUnit.MINUTES.toMillis(30))
|
|
||||||
showOngoingNotification()
|
|
||||||
}
|
|
||||||
.doOnComplete {
|
|
||||||
isSetup = true
|
|
||||||
scheduleWorker(false)
|
|
||||||
showSetupFinishedNotification()
|
|
||||||
}
|
|
||||||
.doOnError {
|
|
||||||
logout()
|
|
||||||
showSetupFailedNotification()
|
|
||||||
}
|
|
||||||
.doFinally {
|
|
||||||
copyDisposable = null
|
|
||||||
NotificationManagerCompat.from(context).cancel(COPY_NOTIFICATION_ID)
|
|
||||||
wakeLock.release()
|
|
||||||
}
|
|
||||||
.onErrorComplete()
|
|
||||||
.subscribeOn(aapsSchedulers.io)
|
|
||||||
.subscribe()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun showOngoingNotification(maxProgress: Long? = null, currentProgress: Long? = null) {
|
|
||||||
val notification = NotificationCompat.Builder(context, NOTIFICATION_CHANNEL)
|
|
||||||
.setContentTitle(resourceHelper.gs(R.string.finishing_open_humans_setup))
|
|
||||||
.setContentText(resourceHelper.gs(R.string.this_may_take_a_while))
|
|
||||||
.setStyle(NotificationCompat.BigTextStyle())
|
|
||||||
.setProgress(maxProgress?.toInt() ?: 0, currentProgress?.toInt()
|
|
||||||
?: 0, maxProgress == null || currentProgress == null)
|
|
||||||
.setOngoing(true)
|
|
||||||
.setAutoCancel(false)
|
|
||||||
.setSmallIcon(R.drawable.notif_icon)
|
|
||||||
.build()
|
|
||||||
NotificationManagerCompat.from(context).notify(COPY_NOTIFICATION_ID, notification)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun showSetupFinishedNotification() {
|
|
||||||
val notification = NotificationCompat.Builder(context, NOTIFICATION_CHANNEL)
|
|
||||||
.setContentTitle(resourceHelper.gs(R.string.setup_finished))
|
|
||||||
.setContentText(resourceHelper.gs(R.string.your_phone_will_upload_data))
|
|
||||||
.setStyle(NotificationCompat.BigTextStyle())
|
|
||||||
.setSmallIcon(R.drawable.notif_icon)
|
|
||||||
.build()
|
|
||||||
val notificationManager = NotificationManagerCompat.from(context)
|
|
||||||
notificationManager.notify(SUCCESS_NOTIFICATION_ID, notification)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun showSetupFailedNotification() {
|
|
||||||
val notification = NotificationCompat.Builder(context, NOTIFICATION_CHANNEL)
|
|
||||||
.setContentTitle(resourceHelper.gs(R.string.setup_failed))
|
|
||||||
.setContentText(resourceHelper.gs(R.string.there_was_an_error))
|
|
||||||
.setStyle(NotificationCompat.BigTextStyle())
|
|
||||||
.setSmallIcon(R.drawable.notif_icon)
|
|
||||||
.build()
|
|
||||||
val notificationManager = NotificationManagerCompat.from(context)
|
|
||||||
notificationManager.notify(FAILURE_NOTIFICATION_ID, notification)
|
|
||||||
}
|
|
||||||
|
|
||||||
@kotlin.ExperimentalStdlibApi
|
|
||||||
fun uploadDataSegmentally(): Completable =
|
|
||||||
uploadData(UPLOAD_SEGMENT_SIZE)
|
|
||||||
.repeatUntil { databaseHelper.getOHQueueSize() == 0L }
|
|
||||||
.doOnSubscribe {
|
|
||||||
aapsLogger.info(LTag.OHUPLOADER, "Starting segmental upload")
|
|
||||||
}
|
|
||||||
.doOnComplete {
|
|
||||||
aapsLogger.info(LTag.OHUPLOADER, "Segmental upload successful")
|
|
||||||
}
|
|
||||||
.doOnError {
|
|
||||||
aapsLogger.error(LTag.OHUPLOADER, "Segmental upload exceptional", it)
|
|
||||||
}
|
|
||||||
|
|
||||||
@kotlin.ExperimentalStdlibApi
|
|
||||||
@Suppress("SameParameterValue")
|
|
||||||
private fun uploadData(maxEntries: Long): Completable = gatherData(maxEntries)
|
|
||||||
.flatMap { data -> refreshAccessTokensIfNeeded().map { accessToken -> accessToken to data } }
|
|
||||||
.flatMap { uploadFile(it.first, it.second).andThen(Single.just(it.second)) }
|
|
||||||
.flatMapCompletable {
|
|
||||||
if (it.highestQueueId != null) {
|
|
||||||
removeUploadedEntriesFromQueue(it.highestQueueId)
|
|
||||||
} else {
|
|
||||||
Completable.complete()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.doOnError {
|
|
||||||
if (it is OpenHumansAPI.OHHttpException && it.code == 401 && it.detail == "Invalid token.") {
|
|
||||||
handleSignOut()
|
|
||||||
}
|
|
||||||
aapsLogger.error("Error while uploading to Open Humans", it)
|
|
||||||
}
|
|
||||||
.doOnComplete {
|
|
||||||
aapsLogger.info(LTag.OHUPLOADER, "Upload successful")
|
|
||||||
rxBus.send(OpenHumansFragment.UpdateQueueEvent)
|
|
||||||
}
|
|
||||||
.doOnSubscribe {
|
|
||||||
aapsLogger.info(LTag.OHUPLOADER, "Starting upload")
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun uploadFile(accessToken: String, uploadData: UploadData) = Completable.defer {
|
|
||||||
openHumansAPI.prepareFileUpload(accessToken, uploadData.fileName, uploadData.metadata)
|
|
||||||
.flatMap { openHumansAPI.uploadFile(it.uploadURL, uploadData.content).andThen(Single.just(it.fileId)) }
|
|
||||||
.flatMapCompletable { openHumansAPI.completeFileUpload(accessToken, it) }
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun refreshAccessTokensIfNeeded() = Single.defer {
|
|
||||||
val oAuthTokens = this.oAuthTokens!!
|
|
||||||
if (oAuthTokens.expiresAt <= System.currentTimeMillis() - TimeUnit.HOURS.toMillis(1)) {
|
|
||||||
openHumansAPI.refreshAccessToken(oAuthTokens.refreshToken)
|
|
||||||
.doOnSuccess { this.oAuthTokens = it }
|
|
||||||
.map { it.accessToken }
|
|
||||||
} else {
|
|
||||||
Single.just(oAuthTokens.accessToken)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@kotlin.ExperimentalStdlibApi
|
|
||||||
private fun gatherData(maxEntries: Long) = Single.defer {
|
|
||||||
val items = databaseHelper.getAllOHQueueItems(maxEntries)
|
|
||||||
val baos = ByteArrayOutputStream()
|
|
||||||
val zos = ZipOutputStream(baos)
|
|
||||||
val tags = mutableListOf<String>()
|
|
||||||
|
|
||||||
items.groupBy { it.file }.forEach { entry ->
|
|
||||||
tags.add(entry.key)
|
|
||||||
val jsonArray = JSONArray()
|
|
||||||
entry.value.map { it.content }.forEach { jsonArray.put(JSONObject(it)) }
|
|
||||||
zos.writeFile("${entry.key}.json", jsonArray.toString().toByteArray())
|
|
||||||
}
|
|
||||||
|
|
||||||
val applicationInfo = JSONObject()
|
|
||||||
applicationInfo.put("versionName", BuildConfig.VERSION_NAME)
|
|
||||||
applicationInfo.put("versionCode", BuildConfig.VERSION_CODE)
|
|
||||||
val hasGitInfo = !BuildConfig.HEAD.endsWith("NoGitSystemAvailable", true)
|
|
||||||
val customRemote = !BuildConfig.REMOTE.equals("https://github.com/nightscout/AndroidAPS.git", true)
|
|
||||||
applicationInfo.put("hasGitInfo", hasGitInfo)
|
|
||||||
applicationInfo.put("customRemote", customRemote)
|
|
||||||
applicationInfo.put("applicationId", appId.toString())
|
|
||||||
zos.writeFile("ApplicationInfo.json", applicationInfo.toString().toByteArray())
|
|
||||||
tags.add("ApplicationInfo")
|
|
||||||
|
|
||||||
val preferences = JSONObject(sp.getAll().filterKeys { it.isAllowedKey() })
|
|
||||||
zos.writeFile("Preferences.json", preferences.toString().toByteArray())
|
|
||||||
tags.add("Preferences")
|
|
||||||
|
|
||||||
val deviceInfo = JSONObject()
|
|
||||||
deviceInfo.put("brand", Build.BRAND)
|
|
||||||
deviceInfo.put("device", Build.DEVICE)
|
|
||||||
deviceInfo.put("manufacturer", Build.MANUFACTURER)
|
|
||||||
deviceInfo.put("model", Build.MODEL)
|
|
||||||
deviceInfo.put("product", Build.PRODUCT)
|
|
||||||
zos.writeFile("DeviceInfo.json", deviceInfo.toString().toByteArray())
|
|
||||||
tags.add("DeviceInfo")
|
|
||||||
|
|
||||||
val displayMetrics = DisplayMetrics()
|
|
||||||
(context.getSystemService(Context.WINDOW_SERVICE) as WindowManager).defaultDisplay.getMetrics(displayMetrics)
|
|
||||||
val displayInfo = JSONObject()
|
|
||||||
displayInfo.put("height", displayMetrics.heightPixels)
|
|
||||||
displayInfo.put("width", displayMetrics.widthPixels)
|
|
||||||
displayInfo.put("density", displayMetrics.density)
|
|
||||||
displayInfo.put("scaledDensity", displayMetrics.scaledDensity)
|
|
||||||
displayInfo.put("xdpi", displayMetrics.xdpi)
|
|
||||||
displayInfo.put("ydpi", displayMetrics.ydpi)
|
|
||||||
zos.writeFile("DisplayInfo.json", displayInfo.toString().toByteArray())
|
|
||||||
tags.add("DisplayInfo")
|
|
||||||
|
|
||||||
val uploadNumber = this.uploadCounter++
|
|
||||||
val uploadDate = Date()
|
|
||||||
val uploadInfo = JSONObject()
|
|
||||||
uploadInfo.put("fileVersion", 1)
|
|
||||||
uploadInfo.put("counter", uploadNumber)
|
|
||||||
uploadInfo.put("timestamp", uploadDate.time)
|
|
||||||
uploadInfo.put("utcOffset", TimeZone.getDefault().getOffset(uploadDate.time))
|
|
||||||
zos.writeFile("UploadInfo.json", uploadInfo.toString().toByteArray())
|
|
||||||
tags.add("UploadInfo")
|
|
||||||
|
|
||||||
zos.close()
|
|
||||||
val bytes = baos.toByteArray()
|
|
||||||
|
|
||||||
Single.just(UploadData(
|
|
||||||
fileName = "upload-num$uploadNumber-ver1-date${FILE_NAME_DATE_FORMAT.format(uploadDate)}-appid${appId.toString().replace("-", "")}.zip",
|
|
||||||
metadata = OpenHumansAPI.FileMetadata(
|
|
||||||
tags = tags,
|
|
||||||
description = "AndroidAPS Database Upload",
|
|
||||||
md5 = MessageDigest.getInstance("MD5").digest(bytes).toHexString(),
|
|
||||||
creationDate = uploadDate.time
|
|
||||||
),
|
|
||||||
content = bytes,
|
|
||||||
highestQueueId = items.map { it.id }.maxOrNull()
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun ZipOutputStream.writeFile(name: String, bytes: ByteArray) {
|
|
||||||
putNextEntry(ZipEntry(name))
|
|
||||||
write(bytes)
|
|
||||||
closeEntry()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun removeUploadedEntriesFromQueue(highestId: Long) = Completable.fromCallable {
|
|
||||||
databaseHelper.removeAllOHQueueItemsWithIdSmallerThan(highestId)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun handleSignOut() {
|
|
||||||
val notification = NotificationCompat.Builder(context, NOTIFICATION_CHANNEL)
|
|
||||||
.setContentTitle(resourceHelper.gs(R.string.you_have_been_signed_out_of_open_humans))
|
|
||||||
.setContentText(resourceHelper.gs(R.string.click_here_to_sign_in_again_if_this_wasnt_on_purpose))
|
|
||||||
.setStyle(NotificationCompat.BigTextStyle())
|
|
||||||
.setSmallIcon(R.drawable.notif_icon)
|
|
||||||
.setAutoCancel(true)
|
|
||||||
.setContentIntent(PendingIntent.getActivity(
|
|
||||||
context,
|
|
||||||
0,
|
|
||||||
Intent(context, OpenHumansLoginActivity::class.java).apply {
|
|
||||||
flags = Intent.FLAG_ACTIVITY_CLEAR_TOP
|
|
||||||
},
|
|
||||||
0
|
|
||||||
))
|
|
||||||
.build()
|
|
||||||
NotificationManagerCompat.from(context).notify(SIGNED_OUT_NOTIFICATION_ID, notification)
|
|
||||||
logout()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun cancelWorker() {
|
|
||||||
WorkManager.getInstance(context).cancelUniqueWork(WORK_NAME)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun scheduleWorker(replace: Boolean) {
|
|
||||||
val constraints = Constraints.Builder()
|
|
||||||
.setRequiredNetworkType(NetworkType.CONNECTED)
|
|
||||||
.setRequiresCharging(sp.getBoolean("key_oh_charging_only", false))
|
|
||||||
.build()
|
|
||||||
val workRequest = PeriodicWorkRequestBuilder<OHUploadWorker>(1, TimeUnit.DAYS)
|
|
||||||
.setConstraints(constraints)
|
|
||||||
.setBackoffCriteria(BackoffPolicy.LINEAR, 20, TimeUnit.MINUTES)
|
|
||||||
.build()
|
|
||||||
WorkManager.getInstance(context).enqueueUniquePeriodicWork(WORK_NAME, if (replace) ExistingPeriodicWorkPolicy.REPLACE else ExistingPeriodicWorkPolicy.KEEP, workRequest)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun setupNotificationChannel() {
|
|
||||||
val notificationManagerCompat = NotificationManagerCompat.from(context)
|
|
||||||
notificationManagerCompat.createNotificationChannel(NotificationChannel(
|
|
||||||
NOTIFICATION_CHANNEL,
|
|
||||||
resourceHelper.gs(R.string.open_humans),
|
|
||||||
NotificationManager.IMPORTANCE_DEFAULT
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
private class UploadData(
|
|
||||||
val fileName: String,
|
|
||||||
val metadata: OpenHumansAPI.FileMetadata,
|
|
||||||
val content: ByteArray,
|
|
||||||
val highestQueueId: Long?
|
|
||||||
)
|
|
||||||
|
|
||||||
@Suppress("PrivatePropertyName")
|
|
||||||
private val HEX_DIGITS = "0123456789ABCDEF".toCharArray()
|
|
||||||
|
|
||||||
private fun ByteArray.toHexString(): String {
|
|
||||||
val stringBuilder = StringBuilder()
|
|
||||||
map { it.toInt() }.forEach {
|
|
||||||
stringBuilder.append(HEX_DIGITS[(it shr 4) and 0x0F])
|
|
||||||
stringBuilder.append(HEX_DIGITS[it and 0x0F])
|
|
||||||
}
|
|
||||||
return stringBuilder.toString()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun onSharedPreferenceChanged(event: EventPreferenceChange) {
|
|
||||||
if (event.changedKey == "key_oh_charging_only" && isSetup) scheduleWorker(true)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,46 +1,56 @@
|
||||||
package info.nightscout.androidaps.plugins.general.overview
|
package info.nightscout.androidaps.plugins.general.overview
|
||||||
|
|
||||||
|
import android.graphics.DashPathEffect
|
||||||
|
import android.graphics.Paint
|
||||||
import com.jjoe64.graphview.series.BarGraphSeries
|
import com.jjoe64.graphview.series.BarGraphSeries
|
||||||
import com.jjoe64.graphview.series.DataPoint
|
import com.jjoe64.graphview.series.DataPoint
|
||||||
import com.jjoe64.graphview.series.LineGraphSeries
|
import com.jjoe64.graphview.series.LineGraphSeries
|
||||||
|
import dagger.android.HasAndroidInjector
|
||||||
import info.nightscout.androidaps.R
|
import info.nightscout.androidaps.R
|
||||||
import info.nightscout.androidaps.data.IobTotal
|
import info.nightscout.androidaps.data.IobTotal
|
||||||
import info.nightscout.androidaps.database.entities.ExtendedBolus
|
import info.nightscout.androidaps.database.AppRepository
|
||||||
import info.nightscout.androidaps.database.entities.GlucoseValue
|
import info.nightscout.androidaps.database.ValueWrapper
|
||||||
import info.nightscout.androidaps.database.entities.TemporaryBasal
|
import info.nightscout.androidaps.database.entities.*
|
||||||
import info.nightscout.androidaps.database.entities.TemporaryTarget
|
import info.nightscout.androidaps.extensions.*
|
||||||
import info.nightscout.androidaps.extensions.convertedToPercent
|
import info.nightscout.androidaps.interfaces.*
|
||||||
import info.nightscout.androidaps.extensions.toStringFull
|
import info.nightscout.androidaps.logging.AAPSLogger
|
||||||
import info.nightscout.androidaps.extensions.toStringShort
|
import info.nightscout.androidaps.logging.LTag
|
||||||
import info.nightscout.androidaps.extensions.valueToUnits
|
import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin
|
||||||
import info.nightscout.androidaps.interfaces.ActivePlugin
|
import info.nightscout.androidaps.plugins.aps.openAPSSMB.SMBDefaults
|
||||||
import info.nightscout.androidaps.interfaces.Profile
|
import info.nightscout.androidaps.plugins.general.nsclient.data.NSDeviceStatus
|
||||||
import info.nightscout.androidaps.interfaces.ProfileFunction
|
import info.nightscout.androidaps.plugins.general.overview.graphExtensions.*
|
||||||
import info.nightscout.androidaps.plugins.general.overview.graphExtensions.DataPointWithLabelInterface
|
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensResult
|
||||||
import info.nightscout.androidaps.plugins.general.overview.graphExtensions.FixedLineGraphSeries
|
|
||||||
import info.nightscout.androidaps.plugins.general.overview.graphExtensions.PointsWithLabelGraphSeries
|
|
||||||
import info.nightscout.androidaps.plugins.general.overview.graphExtensions.Scale
|
|
||||||
import info.nightscout.androidaps.plugins.general.overview.graphExtensions.ScaledDataPoint
|
|
||||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.CobInfo
|
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.CobInfo
|
||||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.data.AutosensData
|
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.data.AutosensData
|
||||||
import info.nightscout.androidaps.utils.DateUtil
|
import info.nightscout.androidaps.utils.*
|
||||||
import info.nightscout.androidaps.utils.DefaultValueHelper
|
|
||||||
import info.nightscout.androidaps.utils.T
|
|
||||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||||
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
import kotlin.collections.ArrayList
|
import kotlin.collections.ArrayList
|
||||||
|
import kotlin.math.abs
|
||||||
|
import kotlin.math.ceil
|
||||||
|
import kotlin.math.max
|
||||||
|
import kotlin.math.min
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
class OverviewData @Inject constructor(
|
class OverviewData @Inject constructor(
|
||||||
|
private val injector: HasAndroidInjector,
|
||||||
|
private val aapsLogger: AAPSLogger,
|
||||||
private val resourceHelper: ResourceHelper,
|
private val resourceHelper: ResourceHelper,
|
||||||
private val dateUtil: DateUtil,
|
private val dateUtil: DateUtil,
|
||||||
private val sp: SP,
|
private val sp: SP,
|
||||||
private val activePlugin: ActivePlugin,
|
private val activePlugin: ActivePlugin,
|
||||||
private val defaultValueHelper: DefaultValueHelper,
|
private val defaultValueHelper: DefaultValueHelper,
|
||||||
private val profileFunction: ProfileFunction
|
private val profileFunction: ProfileFunction,
|
||||||
|
private val config: Config,
|
||||||
|
private val loopPlugin: LoopPlugin,
|
||||||
|
private val nsDeviceStatus: NSDeviceStatus,
|
||||||
|
private val repository: AppRepository,
|
||||||
|
private val overviewMenus: OverviewMenus,
|
||||||
|
private val iobCobCalculator: IobCobCalculator,
|
||||||
|
private val translator: Translator
|
||||||
) {
|
) {
|
||||||
|
|
||||||
enum class Property {
|
enum class Property {
|
||||||
|
@ -53,7 +63,8 @@ class OverviewData @Inject constructor(
|
||||||
BG,
|
BG,
|
||||||
IOB_COB,
|
IOB_COB,
|
||||||
SENSITIVITY,
|
SENSITIVITY,
|
||||||
GRAPH
|
GRAPH,
|
||||||
|
PUMPSTATUS
|
||||||
}
|
}
|
||||||
|
|
||||||
var rangeToDisplay = 6 // for graph
|
var rangeToDisplay = 6 // for graph
|
||||||
|
@ -61,6 +72,42 @@ class OverviewData @Inject constructor(
|
||||||
var fromTime: Long = 0
|
var fromTime: Long = 0
|
||||||
var endTime: Long = 0
|
var endTime: Long = 0
|
||||||
|
|
||||||
|
fun reset() {
|
||||||
|
pumpStatus = ""
|
||||||
|
calcProgress = ""
|
||||||
|
lastBg = null
|
||||||
|
temporaryBasal = null
|
||||||
|
extendedBolus = null
|
||||||
|
bolusIob = null
|
||||||
|
basalIob = null
|
||||||
|
cobInfo = null
|
||||||
|
lastCarbsTime = 0L
|
||||||
|
temporaryTarget = null
|
||||||
|
lastAutosensData = null
|
||||||
|
bgReadingsArray = ArrayList()
|
||||||
|
bucketedGraphSeries = PointsWithLabelGraphSeries()
|
||||||
|
bgReadingGraphSeries = PointsWithLabelGraphSeries()
|
||||||
|
predictionsGraphSeries = PointsWithLabelGraphSeries()
|
||||||
|
baseBasalGraphSeries = LineGraphSeries()
|
||||||
|
tempBasalGraphSeries = LineGraphSeries()
|
||||||
|
basalLineGraphSeries = LineGraphSeries()
|
||||||
|
absoluteBasalGraphSeries = LineGraphSeries()
|
||||||
|
activitySeries = FixedLineGraphSeries()
|
||||||
|
activityPredictionSeries = FixedLineGraphSeries()
|
||||||
|
iobSeries = FixedLineGraphSeries()
|
||||||
|
absIobSeries = FixedLineGraphSeries()
|
||||||
|
iobPredictions1Series = PointsWithLabelGraphSeries()
|
||||||
|
iobPredictions2Series = PointsWithLabelGraphSeries()
|
||||||
|
minusBgiSeries = FixedLineGraphSeries()
|
||||||
|
minusBgiHistSeries = FixedLineGraphSeries()
|
||||||
|
cobSeries = FixedLineGraphSeries()
|
||||||
|
cobMinFailOverSeries = PointsWithLabelGraphSeries()
|
||||||
|
deviationsSeries = BarGraphSeries()
|
||||||
|
ratioSeries = LineGraphSeries()
|
||||||
|
dsMaxSeries = LineGraphSeries()
|
||||||
|
dsMinSeries = LineGraphSeries()
|
||||||
|
}
|
||||||
|
|
||||||
fun initRange() {
|
fun initRange() {
|
||||||
rangeToDisplay = sp.getInt(R.string.key_rangetodisplay, 6)
|
rangeToDisplay = sp.getInt(R.string.key_rangetodisplay, 6)
|
||||||
|
|
||||||
|
@ -78,25 +125,10 @@ class OverviewData @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* PROFILE
|
* PUMP STATUS
|
||||||
*/
|
*/
|
||||||
var profile: Profile? = null
|
|
||||||
var profileName: String? = null
|
|
||||||
var profileNameWithRemainingTime: String? = null
|
|
||||||
|
|
||||||
val profileBackgroudColor: Int
|
var pumpStatus: String = ""
|
||||||
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
|
* CALC PROGRESS
|
||||||
|
@ -133,13 +165,14 @@ class OverviewData @Inject constructor(
|
||||||
|
|
||||||
val temporaryBasalText: String
|
val temporaryBasalText: String
|
||||||
get() =
|
get() =
|
||||||
profile?.let { profile ->
|
profileFunction.getProfile()?.let { profile ->
|
||||||
|
if (temporaryBasal?.isInProgress == false) temporaryBasal = null
|
||||||
temporaryBasal?.let { "T:" + it.toStringShort() }
|
temporaryBasal?.let { "T:" + it.toStringShort() }
|
||||||
?: resourceHelper.gs(R.string.pump_basebasalrate, profile.getBasal())
|
?: resourceHelper.gs(R.string.pump_basebasalrate, profile.getBasal())
|
||||||
} ?: resourceHelper.gs(R.string.notavailable)
|
} ?: resourceHelper.gs(R.string.notavailable)
|
||||||
|
|
||||||
val temporaryBasalDialogText: String
|
val temporaryBasalDialogText: String
|
||||||
get() = profile?.let { profile ->
|
get() = profileFunction.getProfile()?.let { profile ->
|
||||||
temporaryBasal?.let { temporaryBasal ->
|
temporaryBasal?.let { temporaryBasal ->
|
||||||
"${resourceHelper.gs(R.string.basebasalrate_label)}: ${resourceHelper.gs(R.string.pump_basebasalrate, profile.getBasal())}" +
|
"${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)
|
"\n" + resourceHelper.gs(R.string.tempbasal_label) + ": " + temporaryBasal.toStringFull(profile, dateUtil)
|
||||||
|
@ -149,7 +182,7 @@ class OverviewData @Inject constructor(
|
||||||
|
|
||||||
val temporaryBasalIcon: Int
|
val temporaryBasalIcon: Int
|
||||||
get() =
|
get() =
|
||||||
profile?.let { profile ->
|
profileFunction.getProfile()?.let { profile ->
|
||||||
temporaryBasal?.let { temporaryBasal ->
|
temporaryBasal?.let { temporaryBasal ->
|
||||||
val percentRate = temporaryBasal.convertedToPercent(dateUtil.now(), profile)
|
val percentRate = temporaryBasal.convertedToPercent(dateUtil.now(), profile)
|
||||||
when {
|
when {
|
||||||
|
@ -173,7 +206,10 @@ class OverviewData @Inject constructor(
|
||||||
val extendedBolusText: String
|
val extendedBolusText: String
|
||||||
get() =
|
get() =
|
||||||
extendedBolus?.let { extendedBolus ->
|
extendedBolus?.let { extendedBolus ->
|
||||||
if (activePlugin.activePump.isFakingTempsByExtendedBoluses) resourceHelper.gs(R.string.pump_basebasalrate, extendedBolus.rate)
|
if (!extendedBolus.isInProgress(dateUtil)) {
|
||||||
|
this@OverviewData.extendedBolus = null
|
||||||
|
""
|
||||||
|
} else if (!activePlugin.activePump.isFakingTempsByExtendedBoluses) resourceHelper.gs(R.string.pump_basebasalrate, extendedBolus.rate)
|
||||||
else ""
|
else ""
|
||||||
} ?: ""
|
} ?: ""
|
||||||
|
|
||||||
|
@ -211,7 +247,7 @@ class OverviewData @Inject constructor(
|
||||||
* TEMP TARGET
|
* TEMP TARGET
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var temporarytarget: TemporaryTarget? = null
|
var temporaryTarget: TemporaryTarget? = null
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* SENSITIVITY
|
* SENSITIVITY
|
||||||
|
@ -278,4 +314,520 @@ class OverviewData @Inject constructor(
|
||||||
var dsMaxSeries: LineGraphSeries<ScaledDataPoint> = LineGraphSeries()
|
var dsMaxSeries: LineGraphSeries<ScaledDataPoint> = LineGraphSeries()
|
||||||
var dsMinSeries: LineGraphSeries<ScaledDataPoint> = LineGraphSeries()
|
var dsMinSeries: LineGraphSeries<ScaledDataPoint> = LineGraphSeries()
|
||||||
|
|
||||||
|
@Synchronized
|
||||||
|
@Suppress("SameParameterValue", "UNUSED_PARAMETER")
|
||||||
|
fun prepareBgData(from: String) {
|
||||||
|
// val start = dateUtil.now()
|
||||||
|
maxBgValue = Double.MIN_VALUE
|
||||||
|
bgReadingsArray = repository.compatGetBgReadingsDataFromTime(fromTime, toTime, false).blockingGet()
|
||||||
|
val bgListArray: MutableList<DataPointWithLabelInterface> = java.util.ArrayList()
|
||||||
|
for (bg in bgReadingsArray) {
|
||||||
|
if (bg.timestamp < fromTime || bg.timestamp > toTime) continue
|
||||||
|
if (bg.value > maxBgValue) maxBgValue = bg.value
|
||||||
|
bgListArray.add(GlucoseValueDataPoint(bg, defaultValueHelper, profileFunction, resourceHelper))
|
||||||
|
}
|
||||||
|
bgReadingGraphSeries = PointsWithLabelGraphSeries(Array(bgListArray.size) { i -> bgListArray[i] })
|
||||||
|
maxBgValue = Profile.fromMgdlToUnits(maxBgValue, profileFunction.getUnits())
|
||||||
|
if (defaultValueHelper.determineHighLine() > maxBgValue) maxBgValue = defaultValueHelper.determineHighLine()
|
||||||
|
maxBgValue = addUpperChartMargin(maxBgValue)
|
||||||
|
// profiler.log(LTag.UI, "prepareBgData() $from", start)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("UNUSED_PARAMETER")
|
||||||
|
@Synchronized
|
||||||
|
fun preparePredictions(from: String) {
|
||||||
|
// val start = dateUtil.now()
|
||||||
|
val apsResult = if (config.APS) loopPlugin.lastRun?.constraintsProcessed else nsDeviceStatus.getAPSResult(injector)
|
||||||
|
val predictionsAvailable = if (config.APS) loopPlugin.lastRun?.request?.hasPredictions == true else config.NSCLIENT
|
||||||
|
val menuChartSettings = overviewMenus.setting
|
||||||
|
// align to hours
|
||||||
|
val calendar = Calendar.getInstance().also {
|
||||||
|
it.timeInMillis = System.currentTimeMillis()
|
||||||
|
it[Calendar.MILLISECOND] = 0
|
||||||
|
it[Calendar.SECOND] = 0
|
||||||
|
it[Calendar.MINUTE] = 0
|
||||||
|
it.add(Calendar.HOUR, 1)
|
||||||
|
}
|
||||||
|
if (predictionsAvailable && apsResult != null && menuChartSettings[0][OverviewMenus.CharType.PRE.ordinal]) {
|
||||||
|
var predictionHours = (ceil(apsResult.latestPredictionsTime - System.currentTimeMillis().toDouble()) / (60 * 60 * 1000)).toInt()
|
||||||
|
predictionHours = min(2, predictionHours)
|
||||||
|
predictionHours = max(0, predictionHours)
|
||||||
|
val hoursToFetch = rangeToDisplay - predictionHours
|
||||||
|
toTime = calendar.timeInMillis + 100000 // little bit more to avoid wrong rounding - GraphView specific
|
||||||
|
fromTime = toTime - T.hours(hoursToFetch.toLong()).msecs()
|
||||||
|
endTime = toTime + T.hours(predictionHours.toLong()).msecs()
|
||||||
|
} else {
|
||||||
|
toTime = calendar.timeInMillis + 100000 // little bit more to avoid wrong rounding - GraphView specific
|
||||||
|
fromTime = toTime - T.hours(rangeToDisplay.toLong()).msecs()
|
||||||
|
endTime = toTime
|
||||||
|
}
|
||||||
|
|
||||||
|
val bgListArray: MutableList<DataPointWithLabelInterface> = java.util.ArrayList()
|
||||||
|
val predictions: MutableList<GlucoseValueDataPoint>? = apsResult?.predictions
|
||||||
|
?.map { bg -> GlucoseValueDataPoint(bg, defaultValueHelper, profileFunction, resourceHelper) }
|
||||||
|
?.toMutableList()
|
||||||
|
if (predictions != null) {
|
||||||
|
predictions.sortWith { o1: GlucoseValueDataPoint, o2: GlucoseValueDataPoint -> o1.x.compareTo(o2.x) }
|
||||||
|
for (prediction in predictions) if (prediction.data.value >= 40) bgListArray.add(prediction)
|
||||||
|
}
|
||||||
|
predictionsGraphSeries = PointsWithLabelGraphSeries(Array(bgListArray.size) { i -> bgListArray[i] })
|
||||||
|
// profiler.log(LTag.UI, "preparePredictions() $from", start)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Synchronized
|
||||||
|
@Suppress("SameParameterValue", "UNUSED_PARAMETER")
|
||||||
|
fun prepareBucketedData(from: String) {
|
||||||
|
// val start = dateUtil.now()
|
||||||
|
val bucketedData = iobCobCalculator.ads.getBucketedDataTableCopy() ?: return
|
||||||
|
if (bucketedData.isEmpty()) {
|
||||||
|
aapsLogger.debug("No bucketed data.")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
val bucketedListArray: MutableList<DataPointWithLabelInterface> = java.util.ArrayList()
|
||||||
|
for (inMemoryGlucoseValue in bucketedData) {
|
||||||
|
if (inMemoryGlucoseValue.timestamp < fromTime || inMemoryGlucoseValue.timestamp > toTime) continue
|
||||||
|
bucketedListArray.add(InMemoryGlucoseValueDataPoint(inMemoryGlucoseValue, profileFunction, resourceHelper))
|
||||||
|
}
|
||||||
|
bucketedGraphSeries = PointsWithLabelGraphSeries(Array(bucketedListArray.size) { i -> bucketedListArray[i] })
|
||||||
|
// profiler.log(LTag.UI, "prepareBucketedData() $from", start)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("UNUSED_PARAMETER")
|
||||||
|
@Synchronized
|
||||||
|
fun prepareBasalData(from: String) {
|
||||||
|
// val start = dateUtil.now()
|
||||||
|
maxBasalValueFound = 0.0
|
||||||
|
val baseBasalArray: MutableList<ScaledDataPoint> = java.util.ArrayList()
|
||||||
|
val tempBasalArray: MutableList<ScaledDataPoint> = java.util.ArrayList()
|
||||||
|
val basalLineArray: MutableList<ScaledDataPoint> = java.util.ArrayList()
|
||||||
|
val absoluteBasalLineArray: MutableList<ScaledDataPoint> = java.util.ArrayList()
|
||||||
|
var lastLineBasal = 0.0
|
||||||
|
var lastAbsoluteLineBasal = -1.0
|
||||||
|
var lastBaseBasal = 0.0
|
||||||
|
var lastTempBasal = 0.0
|
||||||
|
var time = fromTime
|
||||||
|
while (time < toTime) {
|
||||||
|
val profile = profileFunction.getProfile(time)
|
||||||
|
if (profile == null) {
|
||||||
|
time += 60 * 1000L
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
val basalData = iobCobCalculator.getBasalData(profile, time)
|
||||||
|
val baseBasalValue = basalData.basal
|
||||||
|
var absoluteLineValue = baseBasalValue
|
||||||
|
var tempBasalValue = 0.0
|
||||||
|
var basal = 0.0
|
||||||
|
if (basalData.isTempBasalRunning) {
|
||||||
|
tempBasalValue = basalData.tempBasalAbsolute
|
||||||
|
absoluteLineValue = tempBasalValue
|
||||||
|
if (tempBasalValue != lastTempBasal) {
|
||||||
|
tempBasalArray.add(ScaledDataPoint(time, lastTempBasal, basalScale))
|
||||||
|
tempBasalArray.add(ScaledDataPoint(time, tempBasalValue.also { basal = it }, basalScale))
|
||||||
|
}
|
||||||
|
if (lastBaseBasal != 0.0) {
|
||||||
|
baseBasalArray.add(ScaledDataPoint(time, lastBaseBasal, basalScale))
|
||||||
|
baseBasalArray.add(ScaledDataPoint(time, 0.0, basalScale))
|
||||||
|
lastBaseBasal = 0.0
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (baseBasalValue != lastBaseBasal) {
|
||||||
|
baseBasalArray.add(ScaledDataPoint(time, lastBaseBasal, basalScale))
|
||||||
|
baseBasalArray.add(ScaledDataPoint(time, baseBasalValue.also { basal = it }, basalScale))
|
||||||
|
lastBaseBasal = baseBasalValue
|
||||||
|
}
|
||||||
|
if (lastTempBasal != 0.0) {
|
||||||
|
tempBasalArray.add(ScaledDataPoint(time, lastTempBasal, basalScale))
|
||||||
|
tempBasalArray.add(ScaledDataPoint(time, 0.0, basalScale))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (baseBasalValue != lastLineBasal) {
|
||||||
|
basalLineArray.add(ScaledDataPoint(time, lastLineBasal, basalScale))
|
||||||
|
basalLineArray.add(ScaledDataPoint(time, baseBasalValue, basalScale))
|
||||||
|
}
|
||||||
|
if (absoluteLineValue != lastAbsoluteLineBasal) {
|
||||||
|
absoluteBasalLineArray.add(ScaledDataPoint(time, lastAbsoluteLineBasal, basalScale))
|
||||||
|
absoluteBasalLineArray.add(ScaledDataPoint(time, basal, basalScale))
|
||||||
|
}
|
||||||
|
lastAbsoluteLineBasal = absoluteLineValue
|
||||||
|
lastLineBasal = baseBasalValue
|
||||||
|
lastTempBasal = tempBasalValue
|
||||||
|
maxBasalValueFound = max(maxBasalValueFound, max(tempBasalValue, baseBasalValue))
|
||||||
|
time += 60 * 1000L
|
||||||
|
}
|
||||||
|
|
||||||
|
// final points
|
||||||
|
basalLineArray.add(ScaledDataPoint(toTime, lastLineBasal, basalScale))
|
||||||
|
baseBasalArray.add(ScaledDataPoint(toTime, lastBaseBasal, basalScale))
|
||||||
|
tempBasalArray.add(ScaledDataPoint(toTime, lastTempBasal, basalScale))
|
||||||
|
absoluteBasalLineArray.add(ScaledDataPoint(toTime, lastAbsoluteLineBasal, basalScale))
|
||||||
|
|
||||||
|
// create series
|
||||||
|
baseBasalGraphSeries = LineGraphSeries(Array(baseBasalArray.size) { i -> baseBasalArray[i] }).also {
|
||||||
|
it.isDrawBackground = true
|
||||||
|
it.backgroundColor = resourceHelper.gc(R.color.basebasal)
|
||||||
|
it.thickness = 0
|
||||||
|
}
|
||||||
|
tempBasalGraphSeries = LineGraphSeries(Array(tempBasalArray.size) { i -> tempBasalArray[i] }).also {
|
||||||
|
it.isDrawBackground = true
|
||||||
|
it.backgroundColor = resourceHelper.gc(R.color.tempbasal)
|
||||||
|
it.thickness = 0
|
||||||
|
}
|
||||||
|
basalLineGraphSeries = LineGraphSeries(Array(basalLineArray.size) { i -> basalLineArray[i] }).also {
|
||||||
|
it.setCustomPaint(Paint().also { paint ->
|
||||||
|
paint.style = Paint.Style.STROKE
|
||||||
|
paint.strokeWidth = resourceHelper.getDisplayMetrics().scaledDensity * 2
|
||||||
|
paint.pathEffect = DashPathEffect(floatArrayOf(2f, 4f), 0f)
|
||||||
|
paint.color = resourceHelper.gc(R.color.basal)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
absoluteBasalGraphSeries = LineGraphSeries(Array(absoluteBasalLineArray.size) { i -> absoluteBasalLineArray[i] }).also {
|
||||||
|
it.setCustomPaint(Paint().also { absolutePaint ->
|
||||||
|
absolutePaint.style = Paint.Style.STROKE
|
||||||
|
absolutePaint.strokeWidth = resourceHelper.getDisplayMetrics().scaledDensity * 2
|
||||||
|
absolutePaint.color = resourceHelper.gc(R.color.basal)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
// profiler.log(LTag.UI, "prepareBasalData() $from", start)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("UNUSED_PARAMETER")
|
||||||
|
@Synchronized
|
||||||
|
fun prepareTemporaryTargetData(from: String) {
|
||||||
|
// val start = dateUtil.now()
|
||||||
|
val profile = profileFunction.getProfile() ?: 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.getBolusesDataFromTimeToTime(fromTime, endTime, true).blockingGet()
|
||||||
|
.map { BolusDataPoint(it, resourceHelper, activePlugin, defaultValueHelper) }
|
||||||
|
.filter { it.data.type == Bolus.Type.NORMAL || it.data.type == Bolus.Type.SMB }
|
||||||
|
.forEach {
|
||||||
|
it.y = getNearestBg(it.x.toLong())
|
||||||
|
filteredTreatments.add(it)
|
||||||
|
}
|
||||||
|
repository.getCarbsDataFromTimeToTimeExpanded(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 }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,7 @@ import dagger.android.HasAndroidInjector
|
||||||
import dagger.android.support.DaggerFragment
|
import dagger.android.support.DaggerFragment
|
||||||
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.ProfileSealed
|
||||||
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
|
||||||
|
@ -38,6 +39,7 @@ import info.nightscout.androidaps.events.EventPreferenceChange
|
||||||
import info.nightscout.androidaps.events.EventPumpStatusChanged
|
import info.nightscout.androidaps.events.EventPumpStatusChanged
|
||||||
import info.nightscout.androidaps.events.EventRefreshOverview
|
import info.nightscout.androidaps.events.EventRefreshOverview
|
||||||
import info.nightscout.androidaps.extensions.directionToIcon
|
import info.nightscout.androidaps.extensions.directionToIcon
|
||||||
|
import info.nightscout.androidaps.extensions.isInProgress
|
||||||
import info.nightscout.androidaps.extensions.toVisibility
|
import info.nightscout.androidaps.extensions.toVisibility
|
||||||
import info.nightscout.androidaps.extensions.valueToUnitsString
|
import info.nightscout.androidaps.extensions.valueToUnitsString
|
||||||
import info.nightscout.androidaps.interfaces.*
|
import info.nightscout.androidaps.interfaces.*
|
||||||
|
@ -57,10 +59,13 @@ import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatusProv
|
||||||
import info.nightscout.androidaps.plugins.pump.common.defs.PumpType
|
import info.nightscout.androidaps.plugins.pump.common.defs.PumpType
|
||||||
import info.nightscout.androidaps.plugins.source.DexcomPlugin
|
import info.nightscout.androidaps.plugins.source.DexcomPlugin
|
||||||
import info.nightscout.androidaps.plugins.source.XdripPlugin
|
import info.nightscout.androidaps.plugins.source.XdripPlugin
|
||||||
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin
|
|
||||||
import info.nightscout.androidaps.queue.CommandQueue
|
import info.nightscout.androidaps.queue.CommandQueue
|
||||||
import info.nightscout.androidaps.skins.SkinProvider
|
import info.nightscout.androidaps.skins.SkinProvider
|
||||||
import info.nightscout.androidaps.utils.*
|
import info.nightscout.androidaps.utils.DateUtil
|
||||||
|
import info.nightscout.androidaps.utils.DefaultValueHelper
|
||||||
|
import info.nightscout.androidaps.utils.FabricPrivacy
|
||||||
|
import info.nightscout.androidaps.utils.ToastUtils
|
||||||
|
import info.nightscout.androidaps.utils.TrendCalculator
|
||||||
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.protection.ProtectionCheck
|
import info.nightscout.androidaps.utils.protection.ProtectionCheck
|
||||||
|
@ -72,6 +77,7 @@ import info.nightscout.androidaps.utils.wizard.QuickWizard
|
||||||
import io.reactivex.disposables.CompositeDisposable
|
import io.reactivex.disposables.CompositeDisposable
|
||||||
import io.reactivex.rxkotlin.plusAssign
|
import io.reactivex.rxkotlin.plusAssign
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import kotlin.collections.ArrayList
|
import kotlin.collections.ArrayList
|
||||||
import kotlin.math.abs
|
import kotlin.math.abs
|
||||||
|
@ -92,7 +98,6 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
|
||||||
@Inject lateinit var nsDeviceStatus: NSDeviceStatus
|
@Inject lateinit var nsDeviceStatus: NSDeviceStatus
|
||||||
@Inject lateinit var loopPlugin: LoopPlugin
|
@Inject lateinit var loopPlugin: LoopPlugin
|
||||||
@Inject lateinit var activePlugin: ActivePlugin
|
@Inject lateinit var activePlugin: ActivePlugin
|
||||||
@Inject lateinit var treatmentsPlugin: TreatmentsPlugin
|
|
||||||
@Inject lateinit var iobCobCalculator: IobCobCalculator
|
@Inject lateinit var iobCobCalculator: IobCobCalculator
|
||||||
@Inject lateinit var dexcomPlugin: DexcomPlugin
|
@Inject lateinit var dexcomPlugin: DexcomPlugin
|
||||||
@Inject lateinit var dexcomMediator: DexcomPlugin.DexcomMediator
|
@Inject lateinit var dexcomMediator: DexcomPlugin.DexcomMediator
|
||||||
|
@ -108,7 +113,6 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
|
||||||
@Inject lateinit var trendCalculator: TrendCalculator
|
@Inject lateinit var trendCalculator: TrendCalculator
|
||||||
@Inject lateinit var config: Config
|
@Inject lateinit var config: Config
|
||||||
@Inject lateinit var dateUtil: DateUtil
|
@Inject lateinit var dateUtil: DateUtil
|
||||||
@Inject lateinit var databaseHelper: DatabaseHelperInterface
|
|
||||||
@Inject lateinit var uel: UserEntryLogger
|
@Inject lateinit var uel: UserEntryLogger
|
||||||
@Inject lateinit var repository: AppRepository
|
@Inject lateinit var repository: AppRepository
|
||||||
@Inject lateinit var glucoseStatusProvider: GlucoseStatusProvider
|
@Inject lateinit var glucoseStatusProvider: GlucoseStatusProvider
|
||||||
|
@ -121,7 +125,7 @@ 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 refreshLoop: Runnable? = null
|
private lateinit var refreshLoop: Runnable
|
||||||
private lateinit var handler: Handler
|
private lateinit var handler: Handler
|
||||||
|
|
||||||
private val secondaryGraphs = ArrayList<GraphView>()
|
private val secondaryGraphs = ArrayList<GraphView>()
|
||||||
|
@ -140,7 +144,10 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
|
||||||
_binding = it
|
_binding = it
|
||||||
//check screen width
|
//check screen width
|
||||||
dm = DisplayMetrics()
|
dm = DisplayMetrics()
|
||||||
activity?.windowManager?.defaultDisplay?.getMetrics(dm)
|
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.R)
|
||||||
|
activity?.display?.getRealMetrics(dm)
|
||||||
|
else
|
||||||
|
@Suppress("DEPRECATION") activity?.windowManager?.defaultDisplay?.getMetrics(dm)
|
||||||
}.root
|
}.root
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
@ -157,8 +164,6 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
|
||||||
skinProvider.activeSkin().preProcessLandscapeOverviewLayout(dm, view, landscape, resourceHelper.gb(R.bool.isTablet), smallHeight)
|
skinProvider.activeSkin().preProcessLandscapeOverviewLayout(dm, view, landscape, resourceHelper.gb(R.bool.isTablet), smallHeight)
|
||||||
binding.nsclientLayout.visibility = config.NSCLIENT.toVisibility()
|
binding.nsclientLayout.visibility = config.NSCLIENT.toVisibility()
|
||||||
|
|
||||||
binding.loopPumpStatusLayout.pumpStatus.setBackgroundColor(resourceHelper.gc(R.color.colorInitializingBorder))
|
|
||||||
|
|
||||||
binding.notifications.setHasFixedSize(false)
|
binding.notifications.setHasFixedSize(false)
|
||||||
binding.notifications.layoutManager = LinearLayoutManager(view.context)
|
binding.notifications.layoutManager = LinearLayoutManager(view.context)
|
||||||
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
|
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
|
||||||
|
@ -177,6 +182,8 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
|
||||||
overviewData.rangeToDisplay = if (overviewData.rangeToDisplay > 24) 6 else overviewData.rangeToDisplay
|
overviewData.rangeToDisplay = if (overviewData.rangeToDisplay > 24) 6 else overviewData.rangeToDisplay
|
||||||
sp.putInt(R.string.key_rangetodisplay, overviewData.rangeToDisplay)
|
sp.putInt(R.string.key_rangetodisplay, overviewData.rangeToDisplay)
|
||||||
overviewData.initRange()
|
overviewData.initRange()
|
||||||
|
overviewData.prepareBucketedData("EventBucketedDataCreated")
|
||||||
|
overviewData.prepareBgData("EventBucketedDataCreated")
|
||||||
updateGUI("rangeChange", OverviewData.Property.GRAPH)
|
updateGUI("rangeChange", OverviewData.Property.GRAPH)
|
||||||
rxBus.send(EventPreferenceChange(resourceHelper, R.string.key_rangetodisplay))
|
rxBus.send(EventPreferenceChange(resourceHelper, R.string.key_rangetodisplay))
|
||||||
sp.putBoolean(R.string.key_objectiveusescale, true)
|
sp.putBoolean(R.string.key_objectiveusescale, true)
|
||||||
|
@ -185,10 +192,10 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
|
||||||
prepareGraphsIfNeeded(overviewMenus.setting.size)
|
prepareGraphsIfNeeded(overviewMenus.setting.size)
|
||||||
overviewMenus.setupChartMenu(binding.graphsLayout.chartMenuButton)
|
overviewMenus.setupChartMenu(binding.graphsLayout.chartMenuButton)
|
||||||
|
|
||||||
binding.loopPumpStatusLayout.activeProfile.setOnClickListener(this)
|
binding.activeProfile.setOnClickListener(this)
|
||||||
binding.loopPumpStatusLayout.activeProfile.setOnLongClickListener(this)
|
binding.activeProfile.setOnLongClickListener(this)
|
||||||
binding.loopPumpStatusLayout.tempTarget.setOnClickListener(this)
|
binding.tempTarget.setOnClickListener(this)
|
||||||
binding.loopPumpStatusLayout.tempTarget.setOnLongClickListener(this)
|
binding.tempTarget.setOnLongClickListener(this)
|
||||||
binding.buttonsLayout.acceptTempButton.setOnClickListener(this)
|
binding.buttonsLayout.acceptTempButton.setOnClickListener(this)
|
||||||
binding.buttonsLayout.treatmentButton.setOnClickListener(this)
|
binding.buttonsLayout.treatmentButton.setOnClickListener(this)
|
||||||
binding.buttonsLayout.wizardButton.setOnClickListener(this)
|
binding.buttonsLayout.wizardButton.setOnClickListener(this)
|
||||||
|
@ -200,7 +207,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
|
||||||
binding.buttonsLayout.quickWizardButton.setOnLongClickListener(this)
|
binding.buttonsLayout.quickWizardButton.setOnLongClickListener(this)
|
||||||
binding.infoLayout.apsMode.setOnClickListener(this)
|
binding.infoLayout.apsMode.setOnClickListener(this)
|
||||||
binding.infoLayout.apsMode.setOnLongClickListener(this)
|
binding.infoLayout.apsMode.setOnLongClickListener(this)
|
||||||
binding.loopPumpStatusLayout.activeProfile.setOnLongClickListener(this)
|
binding.activeProfile.setOnLongClickListener(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Synchronized
|
@Synchronized
|
||||||
|
@ -241,10 +248,14 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
|
||||||
.toObservable(EventNewOpenLoopNotification::class.java)
|
.toObservable(EventNewOpenLoopNotification::class.java)
|
||||||
.observeOn(aapsSchedulers.io)
|
.observeOn(aapsSchedulers.io)
|
||||||
.subscribe({ scheduleUpdateGUI("EventNewOpenLoopNotification") }, fabricPrivacy::logException))
|
.subscribe({ scheduleUpdateGUI("EventNewOpenLoopNotification") }, fabricPrivacy::logException))
|
||||||
disposable.add(rxBus
|
disposable += rxBus
|
||||||
.toObservable(EventPumpStatusChanged::class.java)
|
.toObservable(EventPumpStatusChanged::class.java)
|
||||||
.observeOn(aapsSchedulers.main)
|
.observeOn(aapsSchedulers.main)
|
||||||
.subscribe({ updatePumpStatus(it) }, fabricPrivacy::logException))
|
.delay (30, TimeUnit.MILLISECONDS, aapsSchedulers.main)
|
||||||
|
.subscribe({
|
||||||
|
overviewData.pumpStatus = it.getStatus(resourceHelper)
|
||||||
|
updateGUI("EventPumpStatusChanged", OverviewData.Property.PUMPSTATUS)
|
||||||
|
}, fabricPrivacy::logException)
|
||||||
|
|
||||||
refreshLoop = Runnable {
|
refreshLoop = Runnable {
|
||||||
overviewPlugin.refreshLoop("refreshLoop")
|
overviewPlugin.refreshLoop("refreshLoop")
|
||||||
|
@ -374,7 +385,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.temp_target -> v.performClick()
|
R.id.temp_target -> v.performClick()
|
||||||
R.id.active_profile -> activity?.let { activity -> protectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, UIRunnable { ProfileSwitchDialog().show(childFragmentManager, "Overview") }) }
|
R.id.active_profile -> activity?.let { activity -> protectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, UIRunnable { ProfileSwitchDialog().show(childFragmentManager, "ProfileSwitchDialog") }) }
|
||||||
|
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
|
@ -402,18 +413,6 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updatePumpStatus(event: EventPumpStatusChanged) {
|
|
||||||
val status = event.getStatus(resourceHelper)
|
|
||||||
if (status != "") {
|
|
||||||
binding.loopPumpStatusLayout.pumpStatus.text = status
|
|
||||||
binding.loopPumpStatusLayout.pumpStatusLayout.visibility = View.VISIBLE
|
|
||||||
binding.loopPumpStatusLayout.loopLayout.visibility = View.GONE
|
|
||||||
} else {
|
|
||||||
binding.loopPumpStatusLayout.pumpStatusLayout.visibility = View.GONE
|
|
||||||
binding.loopPumpStatusLayout.loopLayout.visibility = View.VISIBLE
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressLint("SetTextI18n")
|
@SuppressLint("SetTextI18n")
|
||||||
private fun processButtonsVisibility() {
|
private fun processButtonsVisibility() {
|
||||||
val lastBG = iobCobCalculator.ads.lastBg()
|
val lastBG = iobCobCalculator.ads.lastBg()
|
||||||
|
@ -585,9 +584,9 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
|
||||||
task = null
|
task = null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
handler.removeCallbacks(task)
|
task?.let { handler.removeCallbacks(it) }
|
||||||
task = UpdateRunnable()
|
task = UpdateRunnable()
|
||||||
handler.postDelayed(task, 500)
|
task?.let { handler.postDelayed(it, 500) }
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("UNUSED_PARAMETER")
|
@Suppress("UNUSED_PARAMETER")
|
||||||
|
@ -595,15 +594,12 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
|
||||||
fun updateGUI(from: String, what: OverviewData.Property) {
|
fun updateGUI(from: String, what: OverviewData.Property) {
|
||||||
// if (what != OverviewData.Property.CALC_PROGRESS)
|
// if (what != OverviewData.Property.CALC_PROGRESS)
|
||||||
// aapsLogger.debug(LTag.UI, "UpdateGui $from $what")
|
// aapsLogger.debug(LTag.UI, "UpdateGui $from $what")
|
||||||
if (overviewData.profile == null) {
|
if (profileFunction.getProfile() == null) {
|
||||||
binding.loopPumpStatusLayout.pumpStatus.setText(R.string.noprofileset)
|
binding.activeProfile.setText(R.string.noprofileset)
|
||||||
binding.loopPumpStatusLayout.pumpStatusLayout.visibility = View.VISIBLE
|
binding.activeProfile.setBackgroundColor(resourceHelper.gc(R.color.errorAlertBackground))
|
||||||
binding.loopPumpStatusLayout.loopLayout.visibility = View.GONE
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
binding.notifications.let { notificationStore.updateNotifications(it) }
|
binding.notifications.let { notificationStore.updateNotifications(it) }
|
||||||
binding.loopPumpStatusLayout.pumpStatusLayout.visibility = View.GONE
|
|
||||||
binding.loopPumpStatusLayout.loopLayout.visibility = View.VISIBLE
|
|
||||||
|
|
||||||
val units = profileFunction.getUnits()
|
val units = profileFunction.getUnits()
|
||||||
val pump = activePlugin.activePump
|
val pump = activePlugin.activePump
|
||||||
|
@ -623,7 +619,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
|
||||||
binding.infoLayout.avgDelta.text = Profile.toSignedUnitsString(glucoseStatus.shortAvgDelta, glucoseStatus.shortAvgDelta * Constants.MGDL_TO_MMOLL, units)
|
binding.infoLayout.avgDelta.text = Profile.toSignedUnitsString(glucoseStatus.shortAvgDelta, glucoseStatus.shortAvgDelta * Constants.MGDL_TO_MMOLL, units)
|
||||||
binding.infoLayout.longAvgDelta.text = Profile.toSignedUnitsString(glucoseStatus.longAvgDelta, glucoseStatus.longAvgDelta * Constants.MGDL_TO_MMOLL, units)
|
binding.infoLayout.longAvgDelta.text = Profile.toSignedUnitsString(glucoseStatus.longAvgDelta, glucoseStatus.longAvgDelta * Constants.MGDL_TO_MMOLL, units)
|
||||||
} else {
|
} else {
|
||||||
binding.infoLayout.deltaLarge.text = "Δ " + resourceHelper.gs(R.string.notavailable)
|
binding.infoLayout.deltaLarge.text = ""
|
||||||
binding.infoLayout.delta.text = "Δ " + resourceHelper.gs(R.string.notavailable)
|
binding.infoLayout.delta.text = "Δ " + resourceHelper.gs(R.string.notavailable)
|
||||||
binding.infoLayout.avgDelta.text = ""
|
binding.infoLayout.avgDelta.text = ""
|
||||||
binding.infoLayout.longAvgDelta.text = ""
|
binding.infoLayout.longAvgDelta.text = ""
|
||||||
|
@ -638,10 +634,25 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
|
||||||
}
|
}
|
||||||
|
|
||||||
OverviewData.Property.PROFILE -> {
|
OverviewData.Property.PROFILE -> {
|
||||||
binding.loopPumpStatusLayout.activeProfile.text = overviewData.profileNameWithRemainingTime
|
val profileBackgroundColor =
|
||||||
?: ""
|
profileFunction.getProfile()?.let {
|
||||||
binding.loopPumpStatusLayout.activeProfile.setBackgroundColor(overviewData.profileBackgroudColor)
|
val profile = (it as ProfileSealed.EPS).value
|
||||||
binding.loopPumpStatusLayout.activeProfile.setTextColor(overviewData.profileTextColor)
|
if (profile.originalPercentage != 100 || profile.originalTimeshift != 0L || profile.originalDuration != 0L)
|
||||||
|
resourceHelper.gc(R.color.ribbonWarning)
|
||||||
|
else resourceHelper.gc(R.color.ribbonDefault)
|
||||||
|
} ?: resourceHelper.gc(R.color.ribbonTextDefault)
|
||||||
|
|
||||||
|
val profileTextColor =
|
||||||
|
profileFunction.getProfile()?.let {
|
||||||
|
val profile = (it as ProfileSealed.EPS).value
|
||||||
|
if (profile.originalPercentage != 100 || profile.originalTimeshift != 0L || profile.originalDuration != 0L)
|
||||||
|
resourceHelper.gc(R.color.ribbonTextWarning)
|
||||||
|
else resourceHelper.gc(R.color.ribbonTextDefault)
|
||||||
|
} ?: resourceHelper.gc(R.color.ribbonTextDefault)
|
||||||
|
|
||||||
|
binding.activeProfile.text = profileFunction.getProfileNameWithRemainingTime()
|
||||||
|
binding.activeProfile.setBackgroundColor(profileBackgroundColor)
|
||||||
|
binding.activeProfile.setTextColor(profileTextColor)
|
||||||
}
|
}
|
||||||
|
|
||||||
OverviewData.Property.TEMPORARY_BASAL -> {
|
OverviewData.Property.TEMPORARY_BASAL -> {
|
||||||
|
@ -655,7 +666,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
|
||||||
|
|
||||||
OverviewData.Property.EXTENDED_BOLUS -> {
|
OverviewData.Property.EXTENDED_BOLUS -> {
|
||||||
binding.infoLayout.extendedBolus.text = overviewData.extendedBolusText
|
binding.infoLayout.extendedBolus.text = overviewData.extendedBolusText
|
||||||
binding.infoLayout.extendedBolus.setOnClickListener {
|
binding.infoLayout.extendedLayout.setOnClickListener {
|
||||||
activity?.let { OKDialog.show(it, resourceHelper.gs(R.string.extended_bolus), overviewData.extendedBolusDialogText) }
|
activity?.let { OKDialog.show(it, resourceHelper.gs(R.string.extended_bolus), overviewData.extendedBolusDialogText) }
|
||||||
}
|
}
|
||||||
binding.infoLayout.extendedLayout.visibility = (overviewData.extendedBolus != null && !pump.isFakingTempsByExtendedBoluses).toVisibility()
|
binding.infoLayout.extendedLayout.visibility = (overviewData.extendedBolus != null && !pump.isFakingTempsByExtendedBoluses).toVisibility()
|
||||||
|
@ -677,14 +688,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
|
||||||
activity?.let { OKDialog.show(it, resourceHelper.gs(R.string.iob), overviewData.iobDialogText) }
|
activity?.let { OKDialog.show(it, resourceHelper.gs(R.string.iob), overviewData.iobDialogText) }
|
||||||
}
|
}
|
||||||
// cob
|
// cob
|
||||||
var cobText: String = resourceHelper.gs(R.string.value_unavailable_short)
|
var cobText = overviewData.cobInfo?.displayText(resourceHelper, dateUtil, buildHelper.isDev()) ?: 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 constraintsProcessed = loopPlugin.lastRun?.constraintsProcessed
|
||||||
val lastRun = loopPlugin.lastRun
|
val lastRun = loopPlugin.lastRun
|
||||||
|
@ -692,7 +696,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
|
||||||
if (constraintsProcessed.carbsReq > 0) {
|
if (constraintsProcessed.carbsReq > 0) {
|
||||||
//only display carbsreq when carbs have not been entered recently
|
//only display carbsreq when carbs have not been entered recently
|
||||||
if (overviewData.lastCarbsTime < lastRun.lastAPSRun) {
|
if (overviewData.lastCarbsTime < lastRun.lastAPSRun) {
|
||||||
cobText = cobText + " | " + constraintsProcessed.carbsReq + " " + resourceHelper.gs(R.string.required)
|
cobText += " | " + constraintsProcessed.carbsReq + " " + resourceHelper.gs(R.string.required)
|
||||||
}
|
}
|
||||||
if (carbAnimation?.isRunning == false)
|
if (carbAnimation?.isRunning == false)
|
||||||
carbAnimation?.start()
|
carbAnimation?.start()
|
||||||
|
@ -701,36 +705,38 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
|
||||||
carbAnimation?.selectDrawable(0)
|
carbAnimation?.selectDrawable(0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
binding.infoLayout.cob.text = cobText
|
||||||
}
|
}
|
||||||
|
|
||||||
OverviewData.Property.TEMPORARY_TARGET -> {
|
OverviewData.Property.TEMPORARY_TARGET -> {
|
||||||
// temp target
|
// temp target
|
||||||
val tempTarget = overviewData.temporarytarget
|
if (overviewData.temporaryTarget?.isInProgress(dateUtil) == false) overviewData.temporaryTarget = null
|
||||||
|
val tempTarget = overviewData.temporaryTarget
|
||||||
if (tempTarget != null) {
|
if (tempTarget != null) {
|
||||||
binding.loopPumpStatusLayout.tempTarget.setTextColor(resourceHelper.gc(R.color.ribbonTextWarning))
|
binding.tempTarget.setTextColor(resourceHelper.gc(R.color.ribbonTextWarning))
|
||||||
binding.loopPumpStatusLayout.tempTarget.setBackgroundColor(resourceHelper.gc(R.color.ribbonWarning))
|
binding.tempTarget.setBackgroundColor(resourceHelper.gc(R.color.ribbonWarning))
|
||||||
binding.loopPumpStatusLayout.tempTarget.text = Profile.toTargetRangeString(tempTarget.lowTarget, tempTarget.highTarget, GlucoseUnit.MGDL, units) + " " + dateUtil.untilString(tempTarget.end, resourceHelper)
|
binding.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
|
||||||
overviewData.profile?.let { profile ->
|
profileFunction.getProfile()?.let { profile ->
|
||||||
val targetUsed = loopPlugin.lastRun?.constraintsProcessed?.targetBG ?: 0.0
|
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")
|
||||||
binding.loopPumpStatusLayout.tempTarget.text = Profile.toTargetRangeString(targetUsed, targetUsed, GlucoseUnit.MGDL, units)
|
binding.tempTarget.text = Profile.toTargetRangeString(targetUsed, targetUsed, GlucoseUnit.MGDL, units)
|
||||||
binding.loopPumpStatusLayout.tempTarget.setTextColor(resourceHelper.gc(R.color.ribbonTextWarning))
|
binding.tempTarget.setTextColor(resourceHelper.gc(R.color.ribbonTextWarning))
|
||||||
binding.loopPumpStatusLayout.tempTarget.setBackgroundColor(resourceHelper.gc(R.color.tempTargetBackground))
|
binding.tempTarget.setBackgroundColor(resourceHelper.gc(R.color.tempTargetBackground))
|
||||||
} else {
|
} else {
|
||||||
binding.loopPumpStatusLayout.tempTarget.setTextColor(resourceHelper.gc(R.color.ribbonTextDefault))
|
binding.tempTarget.setTextColor(resourceHelper.gc(R.color.ribbonTextDefault))
|
||||||
binding.loopPumpStatusLayout.tempTarget.setBackgroundColor(resourceHelper.gc(R.color.ribbonDefault))
|
binding.tempTarget.setBackgroundColor(resourceHelper.gc(R.color.ribbonDefault))
|
||||||
binding.loopPumpStatusLayout.tempTarget.text = Profile.toTargetRangeString(profile.getTargetLowMgdl(), profile.getTargetHighMgdl(), GlucoseUnit.MGDL, units)
|
binding.tempTarget.text = Profile.toTargetRangeString(profile.getTargetLowMgdl(), profile.getTargetHighMgdl(), GlucoseUnit.MGDL, units)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
OverviewData.Property.GRAPH -> {
|
OverviewData.Property.GRAPH -> {
|
||||||
val graphData = GraphData(injector, binding.graphsLayout.bgGraph)
|
val graphData = GraphData(injector, binding.graphsLayout.bgGraph, overviewData)
|
||||||
val menuChartSettings = overviewMenus.setting
|
val menuChartSettings = overviewMenus.setting
|
||||||
graphData.addInRangeArea(overviewData.fromTime, overviewData.endTime, defaultValueHelper.determineLowLine(), defaultValueHelper.determineHighLine())
|
graphData.addInRangeArea(overviewData.fromTime, overviewData.endTime, defaultValueHelper.determineLowLine(), defaultValueHelper.determineHighLine())
|
||||||
graphData.addBgReadings(menuChartSettings[0][OverviewMenus.CharType.PRE.ordinal])
|
graphData.addBgReadings(menuChartSettings[0][OverviewMenus.CharType.PRE.ordinal])
|
||||||
|
@ -738,7 +744,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
|
||||||
graphData.addTreatments()
|
graphData.addTreatments()
|
||||||
if (menuChartSettings[0][OverviewMenus.CharType.ACT.ordinal])
|
if (menuChartSettings[0][OverviewMenus.CharType.ACT.ordinal])
|
||||||
graphData.addActivity(0.8)
|
graphData.addActivity(0.8)
|
||||||
if (pump.pumpDescription.isTempBasalCapable && menuChartSettings[0][OverviewMenus.CharType.BAS.ordinal])
|
if ((pump.pumpDescription.isTempBasalCapable || config.NSCLIENT) && menuChartSettings[0][OverviewMenus.CharType.BAS.ordinal])
|
||||||
graphData.addBasals()
|
graphData.addBasals()
|
||||||
graphData.addTargetLine()
|
graphData.addTargetLine()
|
||||||
graphData.addNowLine(dateUtil.now())
|
graphData.addNowLine(dateUtil.now())
|
||||||
|
@ -755,7 +761,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
|
||||||
|
|
||||||
val now = System.currentTimeMillis()
|
val now = System.currentTimeMillis()
|
||||||
for (g in 0 until min(secondaryGraphs.size, menuChartSettings.size + 1)) {
|
for (g in 0 until min(secondaryGraphs.size, menuChartSettings.size + 1)) {
|
||||||
val secondGraphData = GraphData(injector, secondaryGraphs[g])
|
val secondGraphData = GraphData(injector, secondaryGraphs[g], overviewData)
|
||||||
var useABSForScale = false
|
var useABSForScale = false
|
||||||
var useIobForScale = false
|
var useIobForScale = false
|
||||||
var useCobForScale = false
|
var useCobForScale = false
|
||||||
|
@ -780,7 +786,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
|
||||||
if (menuChartSettings[g + 1][OverviewMenus.CharType.DEV.ordinal]) secondGraphData.addDeviations(useDevForScale, 1.0)
|
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.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.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)
|
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(overviewData.fromTime, overviewData.endTime)
|
secondGraphData.formatAxis(overviewData.fromTime, overviewData.endTime)
|
||||||
|
@ -818,6 +824,12 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
|
||||||
String.format(Locale.ENGLISH, "%.0f%%", autosensData.autosensResult.ratio * 100)
|
String.format(Locale.ENGLISH, "%.0f%%", autosensData.autosensResult.ratio * 100)
|
||||||
} ?: ""
|
} ?: ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
OverviewData.Property.PUMPSTATUS -> {
|
||||||
|
val status = overviewData.pumpStatus
|
||||||
|
binding.pumpStatus.text = status
|
||||||
|
binding.pumpStatusLayout.visibility = (status != "").toVisibility()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -113,6 +113,9 @@ class OverviewMenus @Inject constructor(
|
||||||
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
|
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
|
||||||
|
|
|
@ -1,50 +1,36 @@
|
||||||
package info.nightscout.androidaps.plugins.general.overview
|
package info.nightscout.androidaps.plugins.general.overview
|
||||||
|
|
||||||
import android.graphics.DashPathEffect
|
|
||||||
import android.graphics.Paint
|
|
||||||
import androidx.preference.PreferenceFragmentCompat
|
import androidx.preference.PreferenceFragmentCompat
|
||||||
import androidx.preference.SwitchPreference
|
import androidx.preference.SwitchPreference
|
||||||
import com.jjoe64.graphview.series.BarGraphSeries
|
|
||||||
import com.jjoe64.graphview.series.DataPoint
|
|
||||||
import com.jjoe64.graphview.series.LineGraphSeries
|
|
||||||
import dagger.android.HasAndroidInjector
|
import dagger.android.HasAndroidInjector
|
||||||
import info.nightscout.androidaps.R
|
import info.nightscout.androidaps.R
|
||||||
import info.nightscout.androidaps.data.IobTotal
|
|
||||||
import info.nightscout.androidaps.database.AppRepository
|
import info.nightscout.androidaps.database.AppRepository
|
||||||
import info.nightscout.androidaps.database.ValueWrapper
|
import info.nightscout.androidaps.database.ValueWrapper
|
||||||
import info.nightscout.androidaps.database.entities.Bolus
|
|
||||||
import info.nightscout.androidaps.events.*
|
import info.nightscout.androidaps.events.*
|
||||||
import info.nightscout.androidaps.extensions.*
|
import info.nightscout.androidaps.extensions.*
|
||||||
import info.nightscout.androidaps.interfaces.*
|
import info.nightscout.androidaps.interfaces.*
|
||||||
import info.nightscout.androidaps.logging.AAPSLogger
|
import info.nightscout.androidaps.logging.AAPSLogger
|
||||||
import info.nightscout.androidaps.logging.LTag
|
import info.nightscout.androidaps.logging.LTag
|
||||||
import info.nightscout.androidaps.plugins.aps.events.EventLoopInvoked
|
import info.nightscout.androidaps.plugins.aps.events.EventLoopInvoked
|
||||||
import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin
|
|
||||||
import info.nightscout.androidaps.plugins.aps.openAPSSMB.SMBDefaults
|
|
||||||
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
||||||
import info.nightscout.androidaps.plugins.general.nsclient.data.NSDeviceStatus
|
|
||||||
import info.nightscout.androidaps.plugins.general.overview.events.EventDismissNotification
|
import info.nightscout.androidaps.plugins.general.overview.events.EventDismissNotification
|
||||||
import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification
|
import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification
|
||||||
import info.nightscout.androidaps.plugins.general.overview.events.EventUpdateOverview
|
import info.nightscout.androidaps.plugins.general.overview.events.EventUpdateOverview
|
||||||
import info.nightscout.androidaps.plugins.general.overview.graphExtensions.*
|
import info.nightscout.androidaps.plugins.general.overview.graphExtensions.Scale
|
||||||
|
import info.nightscout.androidaps.plugins.general.overview.graphExtensions.ScaledDataPoint
|
||||||
import info.nightscout.androidaps.plugins.general.overview.notifications.NotificationStore
|
import info.nightscout.androidaps.plugins.general.overview.notifications.NotificationStore
|
||||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensResult
|
|
||||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventBucketedDataCreated
|
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventBucketedDataCreated
|
||||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventIobCalculationProgress
|
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventIobCalculationProgress
|
||||||
import info.nightscout.androidaps.utils.*
|
import info.nightscout.androidaps.utils.DateUtil
|
||||||
|
import info.nightscout.androidaps.utils.FabricPrivacy
|
||||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||||
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
||||||
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
||||||
import io.reactivex.disposables.CompositeDisposable
|
import io.reactivex.disposables.CompositeDisposable
|
||||||
import io.reactivex.rxkotlin.plusAssign
|
import io.reactivex.rxkotlin.plusAssign
|
||||||
import org.json.JSONObject
|
import org.json.JSONObject
|
||||||
import java.util.*
|
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
import kotlin.math.abs
|
|
||||||
import kotlin.math.ceil
|
|
||||||
import kotlin.math.max
|
|
||||||
import kotlin.math.min
|
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
class OverviewPlugin @Inject constructor(
|
class OverviewPlugin @Inject constructor(
|
||||||
|
@ -58,15 +44,9 @@ class OverviewPlugin @Inject constructor(
|
||||||
resourceHelper: ResourceHelper,
|
resourceHelper: ResourceHelper,
|
||||||
private val config: Config,
|
private val config: Config,
|
||||||
private val dateUtil: DateUtil,
|
private val dateUtil: DateUtil,
|
||||||
private val translator: Translator,
|
|
||||||
// private val profiler: Profiler,
|
|
||||||
private val profileFunction: ProfileFunction,
|
private val profileFunction: ProfileFunction,
|
||||||
private val iobCobCalculator: IobCobCalculator,
|
private val iobCobCalculator: IobCobCalculator,
|
||||||
private val repository: AppRepository,
|
private val repository: AppRepository,
|
||||||
private val defaultValueHelper: DefaultValueHelper,
|
|
||||||
private val loopPlugin: LoopPlugin,
|
|
||||||
private val activePlugin: ActivePlugin,
|
|
||||||
private val nsDeviceStatus: NSDeviceStatus,
|
|
||||||
private val overviewData: OverviewData,
|
private val overviewData: OverviewData,
|
||||||
private val overviewMenus: OverviewMenus
|
private val overviewMenus: OverviewMenus
|
||||||
) : PluginBase(PluginDescription()
|
) : PluginBase(PluginDescription()
|
||||||
|
@ -110,7 +90,7 @@ class OverviewPlugin @Inject constructor(
|
||||||
}, fabricPrivacy::logException)
|
}, fabricPrivacy::logException)
|
||||||
disposable += rxBus
|
disposable += rxBus
|
||||||
.toObservable(EventIobCalculationProgress::class.java)
|
.toObservable(EventIobCalculationProgress::class.java)
|
||||||
.observeOn(aapsSchedulers.main)
|
.observeOn(aapsSchedulers.io)
|
||||||
.subscribe({ overviewData.calcProgress = it.progress; overviewBus.send(EventUpdateOverview("EventIobCalculationProgress", OverviewData.Property.CALC_PROGRESS)) }, fabricPrivacy::logException)
|
.subscribe({ overviewData.calcProgress = it.progress; overviewBus.send(EventUpdateOverview("EventIobCalculationProgress", OverviewData.Property.CALC_PROGRESS)) }, fabricPrivacy::logException)
|
||||||
disposable += rxBus
|
disposable += rxBus
|
||||||
.toObservable(EventTempBasalChange::class.java)
|
.toObservable(EventTempBasalChange::class.java)
|
||||||
|
@ -133,36 +113,44 @@ class OverviewPlugin @Inject constructor(
|
||||||
.observeOn(aapsSchedulers.io)
|
.observeOn(aapsSchedulers.io)
|
||||||
.subscribe({
|
.subscribe({
|
||||||
loadIobCobResults("EventTreatmentChange")
|
loadIobCobResults("EventTreatmentChange")
|
||||||
prepareTreatmentsData("EventTreatmentChange")
|
overviewData.prepareTreatmentsData("EventTreatmentChange")
|
||||||
overviewBus.send(EventUpdateOverview("EventTreatmentChange", OverviewData.Property.GRAPH))
|
overviewBus.send(EventUpdateOverview("EventTreatmentChange", OverviewData.Property.GRAPH))
|
||||||
}, fabricPrivacy::logException)
|
}, fabricPrivacy::logException)
|
||||||
disposable += rxBus
|
disposable += rxBus
|
||||||
.toObservable(EventTherapyEventChange::class.java)
|
.toObservable(EventTherapyEventChange::class.java)
|
||||||
.observeOn(aapsSchedulers.io)
|
.observeOn(aapsSchedulers.io)
|
||||||
.subscribe({
|
.subscribe({
|
||||||
prepareTreatmentsData("EventTherapyEventChange")
|
overviewData.prepareTreatmentsData("EventTherapyEventChange")
|
||||||
overviewBus.send(EventUpdateOverview("EventTherapyEventChange", OverviewData.Property.GRAPH))
|
overviewBus.send(EventUpdateOverview("EventTherapyEventChange", OverviewData.Property.GRAPH))
|
||||||
}, fabricPrivacy::logException)
|
}, fabricPrivacy::logException)
|
||||||
disposable += rxBus
|
disposable += rxBus
|
||||||
.toObservable(EventBucketedDataCreated::class.java)
|
.toObservable(EventBucketedDataCreated::class.java)
|
||||||
.observeOn(aapsSchedulers.io)
|
.observeOn(aapsSchedulers.io)
|
||||||
.subscribe({
|
.subscribe({
|
||||||
prepareBucketedData("EventBucketedDataCreated")
|
overviewData.prepareBucketedData("EventBucketedDataCreated")
|
||||||
prepareBgData("EventBucketedDataCreated")
|
overviewData.prepareBgData("EventBucketedDataCreated")
|
||||||
overviewBus.send(EventUpdateOverview("EventBucketedDataCreated", OverviewData.Property.GRAPH))
|
overviewBus.send(EventUpdateOverview("EventBucketedDataCreated", OverviewData.Property.GRAPH))
|
||||||
}, fabricPrivacy::logException)
|
}, fabricPrivacy::logException)
|
||||||
disposable += rxBus
|
disposable += rxBus
|
||||||
.toObservable(EventLoopInvoked::class.java)
|
.toObservable(EventLoopInvoked::class.java)
|
||||||
.observeOn(aapsSchedulers.io)
|
.observeOn(aapsSchedulers.io)
|
||||||
.subscribe({ preparePredictions("EventLoopInvoked") }, fabricPrivacy::logException)
|
.subscribe({ overviewData.preparePredictions("EventLoopInvoked") }, fabricPrivacy::logException)
|
||||||
disposable.add(rxBus
|
disposable += rxBus
|
||||||
.toObservable(EventProfileSwitchChanged::class.java)
|
.toObservable(EventNewBasalProfile::class.java)
|
||||||
.observeOn(aapsSchedulers.io)
|
.observeOn(aapsSchedulers.io)
|
||||||
.subscribe({ loadProfile("EventProfileSwitchChanged") }, fabricPrivacy::logException))
|
.subscribe({ loadProfile("EventNewBasalProfile") }, fabricPrivacy::logException)
|
||||||
disposable.add(rxBus
|
disposable += rxBus
|
||||||
.toObservable(EventAutosensCalculationFinished::class.java)
|
.toObservable(EventAutosensCalculationFinished::class.java)
|
||||||
.observeOn(aapsSchedulers.io)
|
.observeOn(aapsSchedulers.io)
|
||||||
.subscribe({ refreshLoop("EventAutosensCalculationFinished") }, fabricPrivacy::logException))
|
.subscribe({
|
||||||
|
if (it.cause !is EventCustomCalculationFinished) refreshLoop("EventAutosensCalculationFinished")
|
||||||
|
}, fabricPrivacy::logException)
|
||||||
|
disposable += rxBus
|
||||||
|
.toObservable(EventPumpStatusChanged::class.java)
|
||||||
|
.observeOn(aapsSchedulers.io)
|
||||||
|
.subscribe({
|
||||||
|
overviewData.pumpStatus = it.getStatus(resourceHelper)
|
||||||
|
}, fabricPrivacy::logException)
|
||||||
|
|
||||||
Thread { loadAll("onResume") }.start()
|
Thread { loadAll("onResume") }.start()
|
||||||
}
|
}
|
||||||
|
@ -188,6 +176,7 @@ class OverviewPlugin @Inject constructor(
|
||||||
|
|
||||||
override fun configuration(): JSONObject =
|
override fun configuration(): JSONObject =
|
||||||
JSONObject()
|
JSONObject()
|
||||||
|
.putInt(R.string.key_units, sp, resourceHelper)
|
||||||
.putString(R.string.key_quickwizard, sp, resourceHelper)
|
.putString(R.string.key_quickwizard, sp, resourceHelper)
|
||||||
.putInt(R.string.key_eatingsoon_duration, sp, resourceHelper)
|
.putInt(R.string.key_eatingsoon_duration, sp, resourceHelper)
|
||||||
.putDouble(R.string.key_eatingsoon_target, sp, resourceHelper)
|
.putDouble(R.string.key_eatingsoon_target, sp, resourceHelper)
|
||||||
|
@ -214,6 +203,7 @@ class OverviewPlugin @Inject constructor(
|
||||||
|
|
||||||
override fun applyConfiguration(configuration: JSONObject) {
|
override fun applyConfiguration(configuration: JSONObject) {
|
||||||
configuration
|
configuration
|
||||||
|
.storeInt(R.string.key_units, sp, resourceHelper)
|
||||||
.storeString(R.string.key_quickwizard, sp, resourceHelper)
|
.storeString(R.string.key_quickwizard, sp, resourceHelper)
|
||||||
.storeInt(R.string.key_eatingsoon_duration, sp, resourceHelper)
|
.storeInt(R.string.key_eatingsoon_duration, sp, resourceHelper)
|
||||||
.storeDouble(R.string.key_eatingsoon_target, sp, resourceHelper)
|
.storeDouble(R.string.key_eatingsoon_target, sp, resourceHelper)
|
||||||
|
@ -239,25 +229,27 @@ class OverviewPlugin @Inject constructor(
|
||||||
.storeDouble(R.string.key_statuslights_bat_critical, sp, resourceHelper)
|
.storeDouble(R.string.key_statuslights_bat_critical, sp, resourceHelper)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Volatile var runningRefresh = false
|
@Volatile
|
||||||
|
var runningRefresh = false
|
||||||
override fun refreshLoop(from: String) {
|
override fun refreshLoop(from: String) {
|
||||||
if (runningRefresh) return
|
if (runningRefresh) return
|
||||||
runningRefresh = true
|
runningRefresh = true
|
||||||
loadIobCobResults(from)
|
loadIobCobResults(from)
|
||||||
|
overviewBus.send(EventUpdateOverview(from, OverviewData.Property.PROFILE))
|
||||||
overviewBus.send(EventUpdateOverview(from, OverviewData.Property.BG))
|
overviewBus.send(EventUpdateOverview(from, OverviewData.Property.BG))
|
||||||
overviewBus.send(EventUpdateOverview(from, OverviewData.Property.TIME))
|
overviewBus.send(EventUpdateOverview(from, OverviewData.Property.TIME))
|
||||||
overviewBus.send(EventUpdateOverview(from, OverviewData.Property.TEMPORARY_BASAL))
|
overviewBus.send(EventUpdateOverview(from, OverviewData.Property.TEMPORARY_BASAL))
|
||||||
overviewBus.send(EventUpdateOverview(from, OverviewData.Property.EXTENDED_BOLUS))
|
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.TEMPORARY_TARGET))
|
||||||
overviewBus.send(EventUpdateOverview(from, OverviewData.Property.SENSITIVITY))
|
overviewBus.send(EventUpdateOverview(from, OverviewData.Property.SENSITIVITY))
|
||||||
loadAsData(from)
|
loadAsData(from)
|
||||||
preparePredictions(from)
|
overviewData.preparePredictions(from)
|
||||||
prepareBasalData(from)
|
overviewData.prepareBasalData(from)
|
||||||
prepareTemporaryTargetData(from)
|
overviewData.prepareTemporaryTargetData(from)
|
||||||
prepareTreatmentsData(from)
|
overviewData.prepareTreatmentsData(from)
|
||||||
prepareIobAutosensData(from)
|
overviewData.prepareIobAutosensData(from)
|
||||||
overviewBus.send(EventUpdateOverview(from, OverviewData.Property.GRAPH))
|
overviewBus.send(EventUpdateOverview(from, OverviewData.Property.GRAPH))
|
||||||
|
overviewBus.send(EventUpdateOverview(from, OverviewData.Property.IOB_COB))
|
||||||
aapsLogger.debug(LTag.UI, "refreshLoop finished")
|
aapsLogger.debug(LTag.UI, "refreshLoop finished")
|
||||||
runningRefresh = false
|
runningRefresh = false
|
||||||
}
|
}
|
||||||
|
@ -271,9 +263,9 @@ class OverviewPlugin @Inject constructor(
|
||||||
loadTemporaryTarget(from)
|
loadTemporaryTarget(from)
|
||||||
loadIobCobResults(from)
|
loadIobCobResults(from)
|
||||||
loadAsData(from)
|
loadAsData(from)
|
||||||
prepareBasalData(from)
|
overviewData.prepareBasalData(from)
|
||||||
prepareTemporaryTargetData(from)
|
overviewData.prepareTemporaryTargetData(from)
|
||||||
prepareTreatmentsData(from)
|
overviewData.prepareTreatmentsData(from)
|
||||||
// prepareIobAutosensData(from)
|
// prepareIobAutosensData(from)
|
||||||
// preparePredictions(from)
|
// preparePredictions(from)
|
||||||
overviewBus.send(EventUpdateOverview(from, OverviewData.Property.GRAPH))
|
overviewBus.send(EventUpdateOverview(from, OverviewData.Property.GRAPH))
|
||||||
|
@ -281,9 +273,6 @@ class OverviewPlugin @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun loadProfile(from: String) {
|
private fun loadProfile(from: String) {
|
||||||
overviewData.profile = profileFunction.getProfile()
|
|
||||||
overviewData.profileName = profileFunction.getProfileName()
|
|
||||||
overviewData.profileNameWithRemainingTime = profileFunction.getProfileNameWithRemainingTime()
|
|
||||||
overviewBus.send(EventUpdateOverview(from, OverviewData.Property.PROFILE))
|
overviewBus.send(EventUpdateOverview(from, OverviewData.Property.PROFILE))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -299,8 +288,8 @@ class OverviewPlugin @Inject constructor(
|
||||||
|
|
||||||
private fun loadTemporaryTarget(from: String) {
|
private fun loadTemporaryTarget(from: String) {
|
||||||
val tempTarget = repository.getTemporaryTargetActiveAt(dateUtil.now()).blockingGet()
|
val tempTarget = repository.getTemporaryTargetActiveAt(dateUtil.now()).blockingGet()
|
||||||
if (tempTarget is ValueWrapper.Existing) overviewData.temporarytarget = tempTarget.value
|
if (tempTarget is ValueWrapper.Existing) overviewData.temporaryTarget = tempTarget.value
|
||||||
else overviewData.temporarytarget = null
|
else overviewData.temporaryTarget = null
|
||||||
overviewBus.send(EventUpdateOverview(from, OverviewData.Property.TEMPORARY_TARGET))
|
overviewBus.send(EventUpdateOverview(from, OverviewData.Property.TEMPORARY_TARGET))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -319,521 +308,11 @@ class OverviewPlugin @Inject constructor(
|
||||||
private fun loadIobCobResults(from: String) {
|
private fun loadIobCobResults(from: String) {
|
||||||
overviewData.bolusIob = iobCobCalculator.calculateIobFromBolus().round()
|
overviewData.bolusIob = iobCobCalculator.calculateIobFromBolus().round()
|
||||||
overviewData.basalIob = iobCobCalculator.calculateIobFromTempBasalsIncludingConvertedExtended().round()
|
overviewData.basalIob = iobCobCalculator.calculateIobFromTempBasalsIncludingConvertedExtended().round()
|
||||||
overviewData.cobInfo = iobCobCalculator.getCobInfo(false, "Overview COB")
|
overviewData.cobInfo = iobCobCalculator.getCobInfo(true, "Overview COB")
|
||||||
val lastCarbs = repository.getLastCarbsRecordWrapped().blockingGet()
|
val lastCarbs = repository.getLastCarbsRecordWrapped().blockingGet()
|
||||||
overviewData.lastCarbsTime = if (lastCarbs is ValueWrapper.Existing) lastCarbs.value.timestamp else 0L
|
overviewData.lastCarbsTime = if (lastCarbs is ValueWrapper.Existing) lastCarbs.value.timestamp else 0L
|
||||||
|
|
||||||
overviewBus.send(EventUpdateOverview(from, OverviewData.Property.IOB_COB))
|
overviewBus.send(EventUpdateOverview(from, OverviewData.Property.IOB_COB))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Synchronized
|
|
||||||
@Suppress("SameParameterValue", "UNUSED_PARAMETER")
|
|
||||||
private fun prepareBgData(from: String) {
|
|
||||||
// val start = dateUtil.now()
|
|
||||||
var maxBgValue = Double.MIN_VALUE
|
|
||||||
overviewData.bgReadingsArray = repository.compatGetBgReadingsDataFromTime(overviewData.fromTime, overviewData.toTime, false).blockingGet()
|
|
||||||
val bgListArray: MutableList<DataPointWithLabelInterface> = ArrayList()
|
|
||||||
for (bg in overviewData.bgReadingsArray) {
|
|
||||||
if (bg.timestamp < overviewData.fromTime || bg.timestamp > overviewData.toTime) continue
|
|
||||||
if (bg.value > maxBgValue) maxBgValue = bg.value
|
|
||||||
bgListArray.add(GlucoseValueDataPoint(bg, defaultValueHelper, profileFunction, resourceHelper))
|
|
||||||
}
|
|
||||||
overviewData.bgReadingGraphSeries = PointsWithLabelGraphSeries(Array(bgListArray.size) { i -> bgListArray[i] })
|
|
||||||
overviewData.maxBgValue = Profile.fromMgdlToUnits(maxBgValue, profileFunction.getUnits())
|
|
||||||
if (defaultValueHelper.determineHighLine() > maxBgValue) overviewData.maxBgValue = defaultValueHelper.determineHighLine()
|
|
||||||
overviewData.maxBgValue = addUpperChartMargin(overviewData.maxBgValue)
|
|
||||||
// profiler.log(LTag.UI, "prepareBgData() $from", start)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Suppress("UNUSED_PARAMETER")
|
|
||||||
@Synchronized
|
|
||||||
private fun preparePredictions(from: String) {
|
|
||||||
// val start = dateUtil.now()
|
|
||||||
val apsResult = if (config.APS) loopPlugin.lastRun?.constraintsProcessed else nsDeviceStatus.getAPSResult(injector)
|
|
||||||
val predictionsAvailable = if (config.APS) loopPlugin.lastRun?.request?.hasPredictions == true else config.NSCLIENT
|
|
||||||
val menuChartSettings = overviewMenus.setting
|
|
||||||
// align to hours
|
|
||||||
val calendar = Calendar.getInstance().also {
|
|
||||||
it.timeInMillis = System.currentTimeMillis()
|
|
||||||
it[Calendar.MILLISECOND] = 0
|
|
||||||
it[Calendar.SECOND] = 0
|
|
||||||
it[Calendar.MINUTE] = 0
|
|
||||||
it.add(Calendar.HOUR, 1)
|
|
||||||
}
|
|
||||||
if (predictionsAvailable && apsResult != null && menuChartSettings[0][OverviewMenus.CharType.PRE.ordinal]) {
|
|
||||||
var predictionHours = (ceil(apsResult.latestPredictionsTime - System.currentTimeMillis().toDouble()) / (60 * 60 * 1000)).toInt()
|
|
||||||
predictionHours = min(2, predictionHours)
|
|
||||||
predictionHours = max(0, predictionHours)
|
|
||||||
val hoursToFetch = overviewData.rangeToDisplay - predictionHours
|
|
||||||
overviewData.toTime = calendar.timeInMillis + 100000 // little bit more to avoid wrong rounding - GraphView specific
|
|
||||||
overviewData.fromTime = overviewData.toTime - T.hours(hoursToFetch.toLong()).msecs()
|
|
||||||
overviewData.endTime = overviewData.toTime + T.hours(predictionHours.toLong()).msecs()
|
|
||||||
} else {
|
|
||||||
overviewData.toTime = calendar.timeInMillis + 100000 // little bit more to avoid wrong rounding - GraphView specific
|
|
||||||
overviewData.fromTime = overviewData.toTime - T.hours(overviewData.rangeToDisplay.toLong()).msecs()
|
|
||||||
overviewData.endTime = overviewData.toTime
|
|
||||||
}
|
|
||||||
|
|
||||||
val bgListArray: MutableList<DataPointWithLabelInterface> = ArrayList()
|
|
||||||
val predictions: MutableList<GlucoseValueDataPoint>? = apsResult?.predictions
|
|
||||||
?.map { bg -> GlucoseValueDataPoint(bg, defaultValueHelper, profileFunction, resourceHelper) }
|
|
||||||
?.toMutableList()
|
|
||||||
if (predictions != null) {
|
|
||||||
predictions.sortWith { o1: GlucoseValueDataPoint, o2: GlucoseValueDataPoint -> o1.x.compareTo(o2.x) }
|
|
||||||
for (prediction in predictions) if (prediction.data.value >= 40) bgListArray.add(prediction)
|
|
||||||
}
|
|
||||||
overviewData.predictionsGraphSeries = PointsWithLabelGraphSeries(Array(bgListArray.size) { i -> bgListArray[i] })
|
|
||||||
// profiler.log(LTag.UI, "preparePredictions() $from", start)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Synchronized
|
|
||||||
@Suppress("SameParameterValue", "UNUSED_PARAMETER")
|
|
||||||
private fun prepareBucketedData(from: String) {
|
|
||||||
// val start = dateUtil.now()
|
|
||||||
val bucketedData = iobCobCalculator.ads.getBucketedDataTableCopy() ?: return
|
|
||||||
if (bucketedData.isEmpty()) {
|
|
||||||
aapsLogger.debug("No bucketed data.")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
val bucketedListArray: MutableList<DataPointWithLabelInterface> = ArrayList()
|
|
||||||
for (inMemoryGlucoseValue in bucketedData) {
|
|
||||||
if (inMemoryGlucoseValue.timestamp < overviewData.fromTime || inMemoryGlucoseValue.timestamp > overviewData.toTime) continue
|
|
||||||
bucketedListArray.add(InMemoryGlucoseValueDataPoint(inMemoryGlucoseValue, profileFunction, resourceHelper))
|
|
||||||
}
|
|
||||||
overviewData.bucketedGraphSeries = PointsWithLabelGraphSeries(Array(bucketedListArray.size) { i -> bucketedListArray[i] })
|
|
||||||
// profiler.log(LTag.UI, "prepareBucketedData() $from", start)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Suppress("UNUSED_PARAMETER")
|
|
||||||
@Synchronized
|
|
||||||
private fun prepareBasalData(from: String) {
|
|
||||||
// val start = dateUtil.now()
|
|
||||||
overviewData.maxBasalValueFound = 0.0
|
|
||||||
val baseBasalArray: MutableList<ScaledDataPoint> = ArrayList()
|
|
||||||
val tempBasalArray: MutableList<ScaledDataPoint> = ArrayList()
|
|
||||||
val basalLineArray: MutableList<ScaledDataPoint> = ArrayList()
|
|
||||||
val absoluteBasalLineArray: MutableList<ScaledDataPoint> = ArrayList()
|
|
||||||
var lastLineBasal = 0.0
|
|
||||||
var lastAbsoluteLineBasal = -1.0
|
|
||||||
var lastBaseBasal = 0.0
|
|
||||||
var lastTempBasal = 0.0
|
|
||||||
var time = overviewData.fromTime
|
|
||||||
while (time < overviewData.toTime) {
|
|
||||||
val profile = profileFunction.getProfile(time)
|
|
||||||
if (profile == null) {
|
|
||||||
time += 60 * 1000L
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
val basalData = iobCobCalculator.getBasalData(profile, time)
|
|
||||||
val baseBasalValue = basalData.basal
|
|
||||||
var absoluteLineValue = baseBasalValue
|
|
||||||
var tempBasalValue = 0.0
|
|
||||||
var basal = 0.0
|
|
||||||
if (basalData.isTempBasalRunning) {
|
|
||||||
tempBasalValue = basalData.tempBasalAbsolute
|
|
||||||
absoluteLineValue = tempBasalValue
|
|
||||||
if (tempBasalValue != lastTempBasal) {
|
|
||||||
tempBasalArray.add(ScaledDataPoint(time, lastTempBasal, overviewData.basalScale))
|
|
||||||
tempBasalArray.add(ScaledDataPoint(time, tempBasalValue.also { basal = it }, overviewData.basalScale))
|
|
||||||
}
|
|
||||||
if (lastBaseBasal != 0.0) {
|
|
||||||
baseBasalArray.add(ScaledDataPoint(time, lastBaseBasal, overviewData.basalScale))
|
|
||||||
baseBasalArray.add(ScaledDataPoint(time, 0.0, overviewData.basalScale))
|
|
||||||
lastBaseBasal = 0.0
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (baseBasalValue != lastBaseBasal) {
|
|
||||||
baseBasalArray.add(ScaledDataPoint(time, lastBaseBasal, overviewData.basalScale))
|
|
||||||
baseBasalArray.add(ScaledDataPoint(time, baseBasalValue.also { basal = it }, overviewData.basalScale))
|
|
||||||
lastBaseBasal = baseBasalValue
|
|
||||||
}
|
|
||||||
if (lastTempBasal != 0.0) {
|
|
||||||
tempBasalArray.add(ScaledDataPoint(time, lastTempBasal, overviewData.basalScale))
|
|
||||||
tempBasalArray.add(ScaledDataPoint(time, 0.0, overviewData.basalScale))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (baseBasalValue != lastLineBasal) {
|
|
||||||
basalLineArray.add(ScaledDataPoint(time, lastLineBasal, overviewData.basalScale))
|
|
||||||
basalLineArray.add(ScaledDataPoint(time, baseBasalValue, overviewData.basalScale))
|
|
||||||
}
|
|
||||||
if (absoluteLineValue != lastAbsoluteLineBasal) {
|
|
||||||
absoluteBasalLineArray.add(ScaledDataPoint(time, lastAbsoluteLineBasal, overviewData.basalScale))
|
|
||||||
absoluteBasalLineArray.add(ScaledDataPoint(time, basal, overviewData.basalScale))
|
|
||||||
}
|
|
||||||
lastAbsoluteLineBasal = absoluteLineValue
|
|
||||||
lastLineBasal = baseBasalValue
|
|
||||||
lastTempBasal = tempBasalValue
|
|
||||||
overviewData.maxBasalValueFound = max(overviewData.maxBasalValueFound, max(tempBasalValue, baseBasalValue))
|
|
||||||
time += 60 * 1000L
|
|
||||||
}
|
|
||||||
|
|
||||||
// final points
|
|
||||||
basalLineArray.add(ScaledDataPoint(overviewData.toTime, lastLineBasal, overviewData.basalScale))
|
|
||||||
baseBasalArray.add(ScaledDataPoint(overviewData.toTime, lastBaseBasal, overviewData.basalScale))
|
|
||||||
tempBasalArray.add(ScaledDataPoint(overviewData.toTime, lastTempBasal, overviewData.basalScale))
|
|
||||||
absoluteBasalLineArray.add(ScaledDataPoint(overviewData.toTime, lastAbsoluteLineBasal, overviewData.basalScale))
|
|
||||||
|
|
||||||
// create series
|
|
||||||
overviewData.baseBasalGraphSeries = LineGraphSeries(Array(baseBasalArray.size) { i -> baseBasalArray[i] }).also {
|
|
||||||
it.isDrawBackground = true
|
|
||||||
it.backgroundColor = resourceHelper.gc(R.color.basebasal)
|
|
||||||
it.thickness = 0
|
|
||||||
}
|
|
||||||
overviewData.tempBasalGraphSeries = LineGraphSeries(Array(tempBasalArray.size) { i -> tempBasalArray[i] }).also {
|
|
||||||
it.isDrawBackground = true
|
|
||||||
it.backgroundColor = resourceHelper.gc(R.color.tempbasal)
|
|
||||||
it.thickness = 0
|
|
||||||
}
|
|
||||||
overviewData.basalLineGraphSeries = LineGraphSeries(Array(basalLineArray.size) { i -> basalLineArray[i] }).also {
|
|
||||||
it.setCustomPaint(Paint().also { paint ->
|
|
||||||
paint.style = Paint.Style.STROKE
|
|
||||||
paint.strokeWidth = resourceHelper.getDisplayMetrics().scaledDensity * 2
|
|
||||||
paint.pathEffect = DashPathEffect(floatArrayOf(2f, 4f), 0f)
|
|
||||||
paint.color = resourceHelper.gc(R.color.basal)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
overviewData.absoluteBasalGraphSeries = LineGraphSeries(Array(absoluteBasalLineArray.size) { i -> absoluteBasalLineArray[i] }).also {
|
|
||||||
it.setCustomPaint(Paint().also { absolutePaint ->
|
|
||||||
absolutePaint.style = Paint.Style.STROKE
|
|
||||||
absolutePaint.strokeWidth = resourceHelper.getDisplayMetrics().scaledDensity * 2
|
|
||||||
absolutePaint.color = resourceHelper.gc(R.color.basal)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
// profiler.log(LTag.UI, "prepareBasalData() $from", start)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Suppress("UNUSED_PARAMETER")
|
|
||||||
@Synchronized
|
|
||||||
private fun prepareTemporaryTargetData(from: String) {
|
|
||||||
// val start = dateUtil.now()
|
|
||||||
val profile = overviewData.profile ?: return
|
|
||||||
val units = profileFunction.getUnits()
|
|
||||||
var toTime = overviewData.toTime
|
|
||||||
val targetsSeriesArray: MutableList<DataPoint> = ArrayList()
|
|
||||||
var lastTarget = -1.0
|
|
||||||
loopPlugin.lastRun?.constraintsProcessed?.let { toTime = max(it.latestPredictionsTime, toTime) }
|
|
||||||
var time = overviewData.fromTime
|
|
||||||
while (time < toTime) {
|
|
||||||
val tt = repository.getTemporaryTargetActiveAt(time).blockingGet()
|
|
||||||
val value: Double = if (tt is ValueWrapper.Existing) {
|
|
||||||
Profile.fromMgdlToUnits(tt.value.target(), units)
|
|
||||||
} else {
|
|
||||||
Profile.fromMgdlToUnits((profile.getTargetLowMgdl(time) + profile.getTargetHighMgdl(time)) / 2, units)
|
|
||||||
}
|
|
||||||
if (lastTarget != value) {
|
|
||||||
if (lastTarget != -1.0) targetsSeriesArray.add(DataPoint(time.toDouble(), lastTarget))
|
|
||||||
targetsSeriesArray.add(DataPoint(time.toDouble(), value))
|
|
||||||
}
|
|
||||||
lastTarget = value
|
|
||||||
time += 5 * 60 * 1000L
|
|
||||||
}
|
|
||||||
// final point
|
|
||||||
targetsSeriesArray.add(DataPoint(toTime.toDouble(), lastTarget))
|
|
||||||
// create series
|
|
||||||
overviewData.temporaryTargetSeries = LineGraphSeries(Array(targetsSeriesArray.size) { i -> targetsSeriesArray[i] }).also {
|
|
||||||
it.isDrawBackground = false
|
|
||||||
it.color = resourceHelper.gc(R.color.tempTargetBackground)
|
|
||||||
it.thickness = 2
|
|
||||||
}
|
|
||||||
// profiler.log(LTag.UI, "prepareTemporaryTargetData() $from", start)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Suppress("UNUSED_PARAMETER")
|
|
||||||
@Synchronized
|
|
||||||
private fun prepareTreatmentsData(from: String) {
|
|
||||||
// val start = dateUtil.now()
|
|
||||||
overviewData.maxTreatmentsValue = 0.0
|
|
||||||
val filteredTreatments: MutableList<DataPointWithLabelInterface> = ArrayList()
|
|
||||||
repository.getBolusesIncludingInvalidFromTimeToTime(overviewData.fromTime, overviewData.endTime, true).blockingGet()
|
|
||||||
.map { BolusDataPoint(it, resourceHelper, activePlugin, defaultValueHelper) }
|
|
||||||
.filter { it.data.type != Bolus.Type.SMB || it.data.isValid }
|
|
||||||
.forEach {
|
|
||||||
it.y = getNearestBg(it.x.toLong())
|
|
||||||
filteredTreatments.add(it)
|
|
||||||
}
|
|
||||||
repository.getCarbsIncludingInvalidFromTimeToTimeExpanded(overviewData.fromTime, overviewData.endTime, true).blockingGet()
|
|
||||||
.map { CarbsDataPoint(it, resourceHelper) }
|
|
||||||
.forEach {
|
|
||||||
it.y = getNearestBg(it.x.toLong())
|
|
||||||
filteredTreatments.add(it)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ProfileSwitch
|
|
||||||
repository.getEffectiveProfileSwitchDataFromTimeToTime(overviewData.fromTime, overviewData.endTime, true).blockingGet()
|
|
||||||
.map { EffectiveProfileSwitchDataPoint(it) }
|
|
||||||
.forEach(filteredTreatments::add)
|
|
||||||
|
|
||||||
// Extended bolus
|
|
||||||
if (!activePlugin.activePump.isFakingTempsByExtendedBoluses) {
|
|
||||||
repository.getExtendedBolusDataFromTimeToTime(overviewData.fromTime, overviewData.endTime, true).blockingGet()
|
|
||||||
.map { ExtendedBolusDataPoint(it) }
|
|
||||||
.filter { it.duration != 0L }
|
|
||||||
.forEach {
|
|
||||||
it.y = getNearestBg(it.x.toLong())
|
|
||||||
filteredTreatments.add(it)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Careportal
|
|
||||||
repository.compatGetTherapyEventDataFromToTime(overviewData.fromTime - T.hours(6).msecs(), overviewData.endTime).blockingGet()
|
|
||||||
.map { TherapyEventDataPoint(it, resourceHelper, profileFunction, translator) }
|
|
||||||
.filterTimeframe(overviewData.fromTime, overviewData.endTime)
|
|
||||||
.forEach {
|
|
||||||
if (it.y == 0.0) it.y = getNearestBg(it.x.toLong())
|
|
||||||
filteredTreatments.add(it)
|
|
||||||
}
|
|
||||||
|
|
||||||
// increase maxY if a treatment forces it's own height that's higher than a BG value
|
|
||||||
filteredTreatments.map { it.y }
|
|
||||||
.maxOrNull()
|
|
||||||
?.let(::addUpperChartMargin)
|
|
||||||
?.let { overviewData.maxTreatmentsValue = maxOf(overviewData.maxTreatmentsValue, it) }
|
|
||||||
|
|
||||||
overviewData.treatmentsSeries = PointsWithLabelGraphSeries(filteredTreatments.toTypedArray())
|
|
||||||
// profiler.log(LTag.UI, "prepareTreatmentsData() $from", start)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Suppress("UNUSED_PARAMETER")
|
|
||||||
@Synchronized
|
|
||||||
private fun prepareIobAutosensData(from: String) {
|
|
||||||
// val start = dateUtil.now()
|
|
||||||
val iobArray: MutableList<ScaledDataPoint> = ArrayList()
|
|
||||||
val absIobArray: MutableList<ScaledDataPoint> = ArrayList()
|
|
||||||
overviewData.maxIobValueFound = Double.MIN_VALUE
|
|
||||||
var lastIob = 0.0
|
|
||||||
var absLastIob = 0.0
|
|
||||||
var time = overviewData.fromTime
|
|
||||||
|
|
||||||
val minFailOverActiveList: MutableList<DataPointWithLabelInterface> = ArrayList()
|
|
||||||
val cobArray: MutableList<ScaledDataPoint> = ArrayList()
|
|
||||||
overviewData.maxCobValueFound = Double.MIN_VALUE
|
|
||||||
var lastCob = 0
|
|
||||||
|
|
||||||
val actArrayHist: MutableList<ScaledDataPoint> = ArrayList()
|
|
||||||
val actArrayPrediction: MutableList<ScaledDataPoint> = ArrayList()
|
|
||||||
val now = dateUtil.now().toDouble()
|
|
||||||
overviewData.maxIAValue = 0.0
|
|
||||||
|
|
||||||
val bgiArrayHist: MutableList<ScaledDataPoint> = ArrayList()
|
|
||||||
val bgiArrayPrediction: MutableList<ScaledDataPoint> = ArrayList()
|
|
||||||
overviewData.maxBGIValue = Double.MIN_VALUE
|
|
||||||
|
|
||||||
val devArray: MutableList<DeviationDataPoint> = ArrayList()
|
|
||||||
overviewData.maxDevValueFound = Double.MIN_VALUE
|
|
||||||
|
|
||||||
val ratioArray: MutableList<ScaledDataPoint> = ArrayList()
|
|
||||||
overviewData.maxRatioValueFound = 5.0 //even if sens data equals 0 for all the period, minimum scale is between 95% and 105%
|
|
||||||
overviewData.minRatioValueFound = -5.0
|
|
||||||
|
|
||||||
val dsMaxArray: MutableList<ScaledDataPoint> = ArrayList()
|
|
||||||
val dsMinArray: MutableList<ScaledDataPoint> = ArrayList()
|
|
||||||
overviewData.maxFromMaxValueFound = Double.MIN_VALUE
|
|
||||||
overviewData.maxFromMinValueFound = Double.MIN_VALUE
|
|
||||||
|
|
||||||
val adsData = iobCobCalculator.ads.clone()
|
|
||||||
|
|
||||||
while (time <= overviewData.toTime) {
|
|
||||||
val profile = profileFunction.getProfile(time)
|
|
||||||
if (profile == null) {
|
|
||||||
time += 5 * 60 * 1000L
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
// IOB
|
|
||||||
val iob = iobCobCalculator.calculateFromTreatmentsAndTemps(time, profile)
|
|
||||||
val baseBasalIob = iobCobCalculator.calculateAbsoluteIobFromBaseBasals(time)
|
|
||||||
val absIob = IobTotal.combine(iob, baseBasalIob)
|
|
||||||
val autosensData = adsData.getAutosensDataAtTime(time)
|
|
||||||
if (abs(lastIob - iob.iob) > 0.02) {
|
|
||||||
if (abs(lastIob - iob.iob) > 0.2) iobArray.add(ScaledDataPoint(time, lastIob, overviewData.iobScale))
|
|
||||||
iobArray.add(ScaledDataPoint(time, iob.iob, overviewData.iobScale))
|
|
||||||
overviewData.maxIobValueFound = maxOf(overviewData.maxIobValueFound, abs(iob.iob))
|
|
||||||
lastIob = iob.iob
|
|
||||||
}
|
|
||||||
if (abs(absLastIob - absIob.iob) > 0.02) {
|
|
||||||
if (abs(absLastIob - absIob.iob) > 0.2) absIobArray.add(ScaledDataPoint(time, absLastIob, overviewData.iobScale))
|
|
||||||
absIobArray.add(ScaledDataPoint(time, absIob.iob, overviewData.iobScale))
|
|
||||||
overviewData.maxIobValueFound = maxOf(overviewData.maxIobValueFound, abs(absIob.iob))
|
|
||||||
absLastIob = absIob.iob
|
|
||||||
}
|
|
||||||
|
|
||||||
// COB
|
|
||||||
if (autosensData != null) {
|
|
||||||
val cob = autosensData.cob.toInt()
|
|
||||||
if (cob != lastCob) {
|
|
||||||
if (autosensData.carbsFromBolus > 0) cobArray.add(ScaledDataPoint(time, lastCob.toDouble(), overviewData.cobScale))
|
|
||||||
cobArray.add(ScaledDataPoint(time, cob.toDouble(), overviewData.cobScale))
|
|
||||||
overviewData.maxCobValueFound = max(overviewData.maxCobValueFound, cob.toDouble())
|
|
||||||
lastCob = cob
|
|
||||||
}
|
|
||||||
if (autosensData.failoverToMinAbsorbtionRate) {
|
|
||||||
autosensData.setScale(overviewData.cobScale)
|
|
||||||
autosensData.setChartTime(time)
|
|
||||||
minFailOverActiveList.add(autosensData)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ACTIVITY
|
|
||||||
if (time <= now) actArrayHist.add(ScaledDataPoint(time, iob.activity, overviewData.actScale))
|
|
||||||
else actArrayPrediction.add(ScaledDataPoint(time, iob.activity, overviewData.actScale))
|
|
||||||
overviewData.maxIAValue = max(overviewData.maxIAValue, abs(iob.activity))
|
|
||||||
|
|
||||||
// BGI
|
|
||||||
val devBgiScale = overviewMenus.isEnabledIn(OverviewMenus.CharType.DEV) == overviewMenus.isEnabledIn(OverviewMenus.CharType.BGI)
|
|
||||||
val deviation = if (devBgiScale) autosensData?.deviation ?: 0.0 else 0.0
|
|
||||||
val bgi: Double = iob.activity * profile.getIsfMgdl(time) * 5.0
|
|
||||||
if (time <= now) bgiArrayHist.add(ScaledDataPoint(time, bgi, overviewData.bgiScale))
|
|
||||||
else bgiArrayPrediction.add(ScaledDataPoint(time, bgi, overviewData.bgiScale))
|
|
||||||
overviewData.maxBGIValue = max(overviewData.maxBGIValue, max(abs(bgi), deviation))
|
|
||||||
|
|
||||||
// DEVIATIONS
|
|
||||||
if (autosensData != null) {
|
|
||||||
var color = resourceHelper.gc(R.color.deviationblack) // "="
|
|
||||||
if (autosensData.type == "" || autosensData.type == "non-meal") {
|
|
||||||
if (autosensData.pastSensitivity == "C") color = resourceHelper.gc(R.color.deviationgrey)
|
|
||||||
if (autosensData.pastSensitivity == "+") color = resourceHelper.gc(R.color.deviationgreen)
|
|
||||||
if (autosensData.pastSensitivity == "-") color = resourceHelper.gc(R.color.deviationred)
|
|
||||||
} else if (autosensData.type == "uam") {
|
|
||||||
color = resourceHelper.gc(R.color.uam)
|
|
||||||
} else if (autosensData.type == "csf") {
|
|
||||||
color = resourceHelper.gc(R.color.deviationgrey)
|
|
||||||
}
|
|
||||||
devArray.add(DeviationDataPoint(time.toDouble(), autosensData.deviation, color, overviewData.devScale))
|
|
||||||
overviewData.maxDevValueFound = maxOf(overviewData.maxDevValueFound, abs(autosensData.deviation), abs(bgi))
|
|
||||||
}
|
|
||||||
|
|
||||||
// RATIO
|
|
||||||
if (autosensData != null) {
|
|
||||||
ratioArray.add(ScaledDataPoint(time, 100.0 * (autosensData.autosensResult.ratio - 1), overviewData.ratioScale))
|
|
||||||
overviewData.maxRatioValueFound = max(overviewData.maxRatioValueFound, 100.0 * (autosensData.autosensResult.ratio - 1))
|
|
||||||
overviewData.minRatioValueFound = min(overviewData.minRatioValueFound, 100.0 * (autosensData.autosensResult.ratio - 1))
|
|
||||||
}
|
|
||||||
|
|
||||||
// DEV SLOPE
|
|
||||||
if (autosensData != null) {
|
|
||||||
dsMaxArray.add(ScaledDataPoint(time, autosensData.slopeFromMaxDeviation, overviewData.dsMaxScale))
|
|
||||||
dsMinArray.add(ScaledDataPoint(time, autosensData.slopeFromMinDeviation, overviewData.dsMinScale))
|
|
||||||
overviewData.maxFromMaxValueFound = max(overviewData.maxFromMaxValueFound, abs(autosensData.slopeFromMaxDeviation))
|
|
||||||
overviewData.maxFromMinValueFound = max(overviewData.maxFromMinValueFound, abs(autosensData.slopeFromMinDeviation))
|
|
||||||
}
|
|
||||||
|
|
||||||
time += 5 * 60 * 1000L
|
|
||||||
}
|
|
||||||
// IOB
|
|
||||||
overviewData.iobSeries = FixedLineGraphSeries(Array(iobArray.size) { i -> iobArray[i] }).also {
|
|
||||||
it.isDrawBackground = true
|
|
||||||
it.backgroundColor = -0x7f000001 and resourceHelper.gc(R.color.iob) //50%
|
|
||||||
it.color = resourceHelper.gc(R.color.iob)
|
|
||||||
it.thickness = 3
|
|
||||||
}
|
|
||||||
overviewData.absIobSeries = FixedLineGraphSeries(Array(absIobArray.size) { i -> absIobArray[i] }).also {
|
|
||||||
it.isDrawBackground = true
|
|
||||||
it.backgroundColor = -0x7f000001 and resourceHelper.gc(R.color.iob) //50%
|
|
||||||
it.color = resourceHelper.gc(R.color.iob)
|
|
||||||
it.thickness = 3
|
|
||||||
}
|
|
||||||
|
|
||||||
if (overviewMenus.setting[0][OverviewMenus.CharType.PRE.ordinal]) {
|
|
||||||
val autosensData = adsData.getLastAutosensData("GraphData", aapsLogger, dateUtil)
|
|
||||||
val lastAutosensResult = autosensData?.autosensResult ?: AutosensResult()
|
|
||||||
val isTempTarget = repository.getTemporaryTargetActiveAt(dateUtil.now()).blockingGet() is ValueWrapper.Existing
|
|
||||||
val iobPrediction: MutableList<DataPointWithLabelInterface> = ArrayList()
|
|
||||||
val iobPredictionArray = iobCobCalculator.calculateIobArrayForSMB(lastAutosensResult, SMBDefaults.exercise_mode, SMBDefaults.half_basal_exercise_target, isTempTarget)
|
|
||||||
for (i in iobPredictionArray) {
|
|
||||||
iobPrediction.add(i.setColor(resourceHelper.gc(R.color.iobPredAS)))
|
|
||||||
overviewData.maxIobValueFound = max(overviewData.maxIobValueFound, abs(i.iob))
|
|
||||||
}
|
|
||||||
overviewData.iobPredictions1Series = PointsWithLabelGraphSeries(Array(iobPrediction.size) { i -> iobPrediction[i] })
|
|
||||||
val iobPrediction2: MutableList<DataPointWithLabelInterface> = ArrayList()
|
|
||||||
val iobPredictionArray2 = iobCobCalculator.calculateIobArrayForSMB(AutosensResult(), SMBDefaults.exercise_mode, SMBDefaults.half_basal_exercise_target, isTempTarget)
|
|
||||||
for (i in iobPredictionArray2) {
|
|
||||||
iobPrediction2.add(i.setColor(resourceHelper.gc(R.color.iobPred)))
|
|
||||||
overviewData.maxIobValueFound = max(overviewData.maxIobValueFound, abs(i.iob))
|
|
||||||
}
|
|
||||||
overviewData.iobPredictions2Series = PointsWithLabelGraphSeries(Array(iobPrediction2.size) { i -> iobPrediction2[i] })
|
|
||||||
aapsLogger.debug(LTag.AUTOSENS, "IOB prediction for AS=" + DecimalFormatter.to2Decimal(lastAutosensResult.ratio) + ": " + iobCobCalculator.iobArrayToString(iobPredictionArray))
|
|
||||||
aapsLogger.debug(LTag.AUTOSENS, "IOB prediction for AS=" + DecimalFormatter.to2Decimal(1.0) + ": " + iobCobCalculator.iobArrayToString(iobPredictionArray2))
|
|
||||||
} else {
|
|
||||||
overviewData.iobPredictions1Series = PointsWithLabelGraphSeries()
|
|
||||||
overviewData.iobPredictions2Series = PointsWithLabelGraphSeries()
|
|
||||||
}
|
|
||||||
|
|
||||||
// COB
|
|
||||||
overviewData.cobSeries = FixedLineGraphSeries(Array(cobArray.size) { i -> cobArray[i] }).also {
|
|
||||||
it.isDrawBackground = true
|
|
||||||
it.backgroundColor = -0x7f000001 and resourceHelper.gc(R.color.cob) //50%
|
|
||||||
it.color = resourceHelper.gc(R.color.cob)
|
|
||||||
it.thickness = 3
|
|
||||||
}
|
|
||||||
overviewData.cobMinFailOverSeries = PointsWithLabelGraphSeries(Array(minFailOverActiveList.size) { i -> minFailOverActiveList[i] })
|
|
||||||
|
|
||||||
// ACTIVITY
|
|
||||||
overviewData.activitySeries = FixedLineGraphSeries(Array(actArrayHist.size) { i -> actArrayHist[i] }).also {
|
|
||||||
it.isDrawBackground = false
|
|
||||||
it.color = resourceHelper.gc(R.color.activity)
|
|
||||||
it.thickness = 3
|
|
||||||
}
|
|
||||||
overviewData.activityPredictionSeries = FixedLineGraphSeries(Array(actArrayPrediction.size) { i -> actArrayPrediction[i] }).also {
|
|
||||||
it.setCustomPaint(Paint().also { paint ->
|
|
||||||
paint.style = Paint.Style.STROKE
|
|
||||||
paint.strokeWidth = 3f
|
|
||||||
paint.pathEffect = DashPathEffect(floatArrayOf(4f, 4f), 0f)
|
|
||||||
paint.color = resourceHelper.gc(R.color.activity)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// BGI
|
|
||||||
overviewData.minusBgiSeries = FixedLineGraphSeries(Array(bgiArrayHist.size) { i -> bgiArrayHist[i] }).also {
|
|
||||||
it.isDrawBackground = false
|
|
||||||
it.color = resourceHelper.gc(R.color.bgi)
|
|
||||||
it.thickness = 3
|
|
||||||
}
|
|
||||||
overviewData.minusBgiHistSeries = FixedLineGraphSeries(Array(bgiArrayPrediction.size) { i -> bgiArrayPrediction[i] }).also {
|
|
||||||
it.setCustomPaint(Paint().also { paint ->
|
|
||||||
paint.style = Paint.Style.STROKE
|
|
||||||
paint.strokeWidth = 3f
|
|
||||||
paint.pathEffect = DashPathEffect(floatArrayOf(4f, 4f), 0f)
|
|
||||||
paint.color = resourceHelper.gc(R.color.bgi)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// DEVIATIONS
|
|
||||||
overviewData.deviationsSeries = BarGraphSeries(Array(devArray.size) { i -> devArray[i] }).also {
|
|
||||||
it.setValueDependentColor { data: DeviationDataPoint -> data.color }
|
|
||||||
}
|
|
||||||
|
|
||||||
// RATIO
|
|
||||||
overviewData.ratioSeries = LineGraphSeries(Array(ratioArray.size) { i -> ratioArray[i] }).also {
|
|
||||||
it.color = resourceHelper.gc(R.color.ratio)
|
|
||||||
it.thickness = 3
|
|
||||||
}
|
|
||||||
|
|
||||||
// DEV SLOPE
|
|
||||||
overviewData.dsMaxSeries = LineGraphSeries(Array(dsMaxArray.size) { i -> dsMaxArray[i] }).also {
|
|
||||||
it.color = resourceHelper.gc(R.color.devslopepos)
|
|
||||||
it.thickness = 3
|
|
||||||
}
|
|
||||||
overviewData.dsMinSeries = LineGraphSeries(Array(dsMinArray.size) { i -> dsMinArray[i] }).also {
|
|
||||||
it.color = resourceHelper.gc(R.color.devslopeneg)
|
|
||||||
it.thickness = 3
|
|
||||||
}
|
|
||||||
|
|
||||||
// profiler.log(LTag.UI, "prepareIobAutosensData() $from", start)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun addUpperChartMargin(maxBgValue: Double) =
|
|
||||||
if (profileFunction.getUnits() == GlucoseUnit.MGDL) Round.roundTo(maxBgValue, 40.0) + 80 else Round.roundTo(maxBgValue, 2.0) + 4
|
|
||||||
|
|
||||||
private fun getNearestBg(date: Long): Double {
|
|
||||||
overviewData.bgReadingsArray.let { bgReadingsArray ->
|
|
||||||
for (reading in bgReadingsArray) {
|
|
||||||
if (reading.timestamp > date) continue
|
|
||||||
return Profile.fromMgdlToUnits(reading.value, profileFunction.getUnits())
|
|
||||||
}
|
|
||||||
return if (bgReadingsArray.isNotEmpty()) Profile.fromMgdlToUnits(bgReadingsArray[0].value, profileFunction.getUnits())
|
|
||||||
else Profile.fromMgdlToUnits(100.0, profileFunction.getUnits())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun <E : DataPointWithLabelInterface> List<E>.filterTimeframe(fromTime: Long, endTime: Long): List<E> =
|
|
||||||
filter { it.x + it.duration >= fromTime && it.x <= endTime }
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -74,7 +74,7 @@ class StatusLightHandler @Inject constructor(
|
||||||
private fun handleAge(view: TextView?, type: TherapyEvent.Type, @StringRes warnSettings: Int, defaultWarnThreshold: Double, @StringRes urgentSettings: Int, defaultUrgentThreshold: Double) {
|
private fun handleAge(view: TextView?, type: TherapyEvent.Type, @StringRes warnSettings: Int, defaultWarnThreshold: Double, @StringRes urgentSettings: Int, defaultUrgentThreshold: Double) {
|
||||||
val warn = sp.getDouble(warnSettings, defaultWarnThreshold)
|
val warn = sp.getDouble(warnSettings, defaultWarnThreshold)
|
||||||
val urgent = sp.getDouble(urgentSettings, defaultUrgentThreshold)
|
val urgent = sp.getDouble(urgentSettings, defaultUrgentThreshold)
|
||||||
val therapyEvent = repository.getLastTherapyRecord(type).blockingGet()
|
val therapyEvent = repository.getLastTherapyRecordUpToNow(type).blockingGet()
|
||||||
if (therapyEvent is ValueWrapper.Existing) {
|
if (therapyEvent is ValueWrapper.Existing) {
|
||||||
warnColors.setColorByAge(view, therapyEvent.value, warn, urgent)
|
warnColors.setColorByAge(view, therapyEvent.value, warn, urgent)
|
||||||
view?.text = therapyEvent.value.age(resourceHelper.shortTextMode(), resourceHelper, dateUtil)
|
view?.text = therapyEvent.value.age(resourceHelper.shortTextMode(), resourceHelper, dateUtil)
|
||||||
|
|
|
@ -64,12 +64,12 @@ class QuickWizardListActivity : NoSplashAppCompatActivity() {
|
||||||
val manager = fragmentManager
|
val manager = fragmentManager
|
||||||
val editQuickWizardDialog = EditQuickWizardDialog()
|
val editQuickWizardDialog = EditQuickWizardDialog()
|
||||||
val bundle = Bundle()
|
val bundle = Bundle()
|
||||||
bundle.putInt("position", adapterPosition)
|
bundle.putInt("position", bindingAdapterPosition)
|
||||||
editQuickWizardDialog.arguments = bundle
|
editQuickWizardDialog.arguments = bundle
|
||||||
editQuickWizardDialog.show(manager, "EditQuickWizardDialog")
|
editQuickWizardDialog.show(manager, "EditQuickWizardDialog")
|
||||||
}
|
}
|
||||||
removeButton.setOnClickListener {
|
removeButton.setOnClickListener {
|
||||||
quickWizard.remove(adapterPosition)
|
quickWizard.remove(bindingAdapterPosition)
|
||||||
rxBus.send(EventQuickWizardChange())
|
rxBus.send(EventQuickWizardChange())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,16 +26,16 @@ import kotlin.math.max
|
||||||
|
|
||||||
class GraphData(
|
class GraphData(
|
||||||
injector: HasAndroidInjector,
|
injector: HasAndroidInjector,
|
||||||
private val graph: GraphView
|
private val graph: GraphView,
|
||||||
|
private val overviewData: OverviewData
|
||||||
) {
|
) {
|
||||||
|
|
||||||
@Inject lateinit var aapsLogger: AAPSLogger
|
@Inject lateinit var aapsLogger: AAPSLogger
|
||||||
@Inject lateinit var profileFunction: ProfileFunction
|
@Inject lateinit var profileFunction: ProfileFunction
|
||||||
@Inject lateinit var resourceHelper: ResourceHelper
|
@Inject lateinit var resourceHelper: ResourceHelper
|
||||||
@Inject lateinit var defaultValueHelper: DefaultValueHelper
|
@Inject lateinit var defaultValueHelper: DefaultValueHelper
|
||||||
@Inject lateinit var overviewData: OverviewData
|
|
||||||
|
|
||||||
var maxY = Double.MIN_VALUE
|
private var maxY = Double.MIN_VALUE
|
||||||
private var minY = Double.MAX_VALUE
|
private var minY = Double.MAX_VALUE
|
||||||
private val units: GlucoseUnit
|
private val units: GlucoseUnit
|
||||||
private val series: MutableList<Series<*>> = ArrayList()
|
private val series: MutableList<Series<*>> = ArrayList()
|
||||||
|
@ -76,7 +76,7 @@ class GraphData(
|
||||||
addSeries(overviewData.tempBasalGraphSeries)
|
addSeries(overviewData.tempBasalGraphSeries)
|
||||||
addSeries(overviewData.basalLineGraphSeries)
|
addSeries(overviewData.basalLineGraphSeries)
|
||||||
addSeries(overviewData.absoluteBasalGraphSeries)
|
addSeries(overviewData.absoluteBasalGraphSeries)
|
||||||
overviewData.basalScale.setMultiplier(maxY * scale / overviewData.maxBasalValueFound)
|
overviewData.basalScale.multiplier = maxY * scale / overviewData.maxBasalValueFound
|
||||||
}
|
}
|
||||||
|
|
||||||
fun addTargetLine() {
|
fun addTargetLine() {
|
||||||
|
@ -91,7 +91,7 @@ class GraphData(
|
||||||
fun addActivity(scale: Double) {
|
fun addActivity(scale: Double) {
|
||||||
addSeries(overviewData.activitySeries)
|
addSeries(overviewData.activitySeries)
|
||||||
addSeries(overviewData.activityPredictionSeries)
|
addSeries(overviewData.activityPredictionSeries)
|
||||||
overviewData.actScale.setMultiplier(maxY * scale / overviewData.maxIAValue)
|
overviewData.actScale.multiplier = maxY * scale / overviewData.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
|
||||||
|
@ -100,7 +100,7 @@ class GraphData(
|
||||||
maxY = overviewData.maxBGIValue
|
maxY = overviewData.maxBGIValue
|
||||||
minY = -overviewData.maxBGIValue
|
minY = -overviewData.maxBGIValue
|
||||||
}
|
}
|
||||||
overviewData.bgiScale.setMultiplier(maxY * scale / overviewData.maxBGIValue)
|
overviewData.bgiScale.multiplier = maxY * scale / overviewData.maxBGIValue
|
||||||
addSeries(overviewData.minusBgiSeries)
|
addSeries(overviewData.minusBgiSeries)
|
||||||
addSeries(overviewData.minusBgiHistSeries)
|
addSeries(overviewData.minusBgiHistSeries)
|
||||||
}
|
}
|
||||||
|
@ -111,7 +111,7 @@ class GraphData(
|
||||||
maxY = overviewData.maxIobValueFound
|
maxY = overviewData.maxIobValueFound
|
||||||
minY = -overviewData.maxIobValueFound
|
minY = -overviewData.maxIobValueFound
|
||||||
}
|
}
|
||||||
overviewData.iobScale.setMultiplier(maxY * scale / overviewData.maxIobValueFound)
|
overviewData.iobScale.multiplier = maxY * scale / overviewData.maxIobValueFound
|
||||||
addSeries(overviewData.iobSeries)
|
addSeries(overviewData.iobSeries)
|
||||||
addSeries(overviewData.iobPredictions1Series)
|
addSeries(overviewData.iobPredictions1Series)
|
||||||
addSeries(overviewData.iobPredictions2Series)
|
addSeries(overviewData.iobPredictions2Series)
|
||||||
|
@ -123,7 +123,7 @@ class GraphData(
|
||||||
maxY = overviewData.maxIobValueFound
|
maxY = overviewData.maxIobValueFound
|
||||||
minY = -overviewData.maxIobValueFound
|
minY = -overviewData.maxIobValueFound
|
||||||
}
|
}
|
||||||
overviewData.iobScale.setMultiplier(maxY * scale / overviewData.maxIobValueFound)
|
overviewData.iobScale.multiplier = maxY * scale / overviewData.maxIobValueFound
|
||||||
addSeries(overviewData.absIobSeries)
|
addSeries(overviewData.absIobSeries)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -133,7 +133,7 @@ class GraphData(
|
||||||
maxY = overviewData.maxCobValueFound
|
maxY = overviewData.maxCobValueFound
|
||||||
minY = 0.0
|
minY = 0.0
|
||||||
}
|
}
|
||||||
overviewData.cobScale.setMultiplier(maxY * scale / overviewData.maxCobValueFound)
|
overviewData.cobScale.multiplier = maxY * scale / overviewData.maxCobValueFound
|
||||||
addSeries(overviewData.cobSeries)
|
addSeries(overviewData.cobSeries)
|
||||||
addSeries(overviewData.cobMinFailOverSeries)
|
addSeries(overviewData.cobMinFailOverSeries)
|
||||||
}
|
}
|
||||||
|
@ -144,7 +144,7 @@ class GraphData(
|
||||||
maxY = overviewData.maxDevValueFound
|
maxY = overviewData.maxDevValueFound
|
||||||
minY = -maxY
|
minY = -maxY
|
||||||
}
|
}
|
||||||
overviewData.devScale.setMultiplier(maxY * scale / overviewData.maxDevValueFound)
|
overviewData.devScale.multiplier = maxY * scale / overviewData.maxDevValueFound
|
||||||
addSeries(overviewData.deviationsSeries)
|
addSeries(overviewData.deviationsSeries)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -153,20 +153,32 @@ class GraphData(
|
||||||
if (useForScale) {
|
if (useForScale) {
|
||||||
maxY = 100.0 + max(overviewData.maxRatioValueFound, abs(overviewData.minRatioValueFound))
|
maxY = 100.0 + max(overviewData.maxRatioValueFound, abs(overviewData.minRatioValueFound))
|
||||||
minY = 100.0 - max(overviewData.maxRatioValueFound, abs(overviewData.minRatioValueFound))
|
minY = 100.0 - max(overviewData.maxRatioValueFound, abs(overviewData.minRatioValueFound))
|
||||||
overviewData.ratioScale.setMultiplier(1.0)
|
overviewData.ratioScale.multiplier = 1.0
|
||||||
} else
|
overviewData.ratioScale.shift = 100.0
|
||||||
overviewData.ratioScale.setMultiplier(maxY * scale / max(overviewData.maxRatioValueFound, abs(overviewData.minRatioValueFound)))
|
} else {
|
||||||
|
overviewData.ratioScale.multiplier = maxY * scale / max(overviewData.maxRatioValueFound, abs(overviewData.minRatioValueFound))
|
||||||
|
overviewData.ratioScale.shift = 0.0
|
||||||
|
}
|
||||||
addSeries(overviewData.ratioSeries)
|
addSeries(overviewData.ratioSeries)
|
||||||
}
|
}
|
||||||
|
|
||||||
// scale in % of vertical size (like 0.3)
|
// scale in % of vertical size (like 0.3)
|
||||||
fun addDeviationSlope(useForScale: Boolean, scale: Double) {
|
fun addDeviationSlope(useForScale: Boolean, scale: Double, isRatioScale: Boolean = false) {
|
||||||
if (useForScale) {
|
if (useForScale) {
|
||||||
maxY = max(overviewData.maxFromMaxValueFound, overviewData.maxFromMinValueFound)
|
maxY = max(overviewData.maxFromMaxValueFound, overviewData.maxFromMinValueFound)
|
||||||
minY = -maxY
|
minY = -maxY
|
||||||
}
|
}
|
||||||
overviewData.dsMaxScale.setMultiplier(maxY * scale / overviewData.maxFromMaxValueFound)
|
var graphMaxY = maxY
|
||||||
overviewData.dsMinScale.setMultiplier(maxY * scale / overviewData.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.dsMaxSeries)
|
||||||
addSeries(overviewData.dsMinSeries)
|
addSeries(overviewData.dsMinSeries)
|
||||||
}
|
}
|
||||||
|
@ -201,7 +213,7 @@ class GraphData(
|
||||||
graph.gridLabelRenderer.numHorizontalLabels = 7 // only 7 because of the space
|
graph.gridLabelRenderer.numHorizontalLabels = 7 // only 7 because of the space
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun addSeries(s: Series<*>) = series.add(s)
|
private fun addSeries(s: Series<*>) = series.add(s)
|
||||||
|
|
||||||
fun performUpdate() {
|
fun performUpdate() {
|
||||||
// clear old data
|
// clear old data
|
||||||
|
|
|
@ -3,10 +3,8 @@ package info.nightscout.androidaps.plugins.general.overview.graphExtensions
|
||||||
import android.graphics.Color
|
import android.graphics.Color
|
||||||
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.interfaces.Profile
|
|
||||||
import info.nightscout.androidaps.database.entities.TherapyEvent
|
import info.nightscout.androidaps.database.entities.TherapyEvent
|
||||||
import info.nightscout.androidaps.interfaces.GlucoseUnit
|
import info.nightscout.androidaps.interfaces.Profile
|
||||||
import info.nightscout.androidaps.interfaces.Interval
|
|
||||||
import info.nightscout.androidaps.interfaces.ProfileFunction
|
import info.nightscout.androidaps.interfaces.ProfileFunction
|
||||||
import info.nightscout.androidaps.utils.Translator
|
import info.nightscout.androidaps.utils.Translator
|
||||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||||
|
@ -17,7 +15,7 @@ class TherapyEventDataPoint @Inject constructor(
|
||||||
private val resourceHelper: ResourceHelper,
|
private val resourceHelper: ResourceHelper,
|
||||||
private val profileFunction: ProfileFunction,
|
private val profileFunction: ProfileFunction,
|
||||||
private val translator: Translator
|
private val translator: Translator
|
||||||
) : DataPointWithLabelInterface, Interval {
|
) : DataPointWithLabelInterface {
|
||||||
|
|
||||||
private var yValue = 0.0
|
private var yValue = 0.0
|
||||||
|
|
||||||
|
@ -49,10 +47,10 @@ class TherapyEventDataPoint @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getLabel(): String? =
|
override fun getLabel(): String? =
|
||||||
if (data.note != null) data.note
|
if (data.note.isNullOrBlank().not()) data.note
|
||||||
else translator.translate(data.type)
|
else translator.translate(data.type)
|
||||||
|
|
||||||
override fun getDuration(): Long = end() - start()
|
override fun getDuration(): Long = data.duration
|
||||||
override fun getShape(): PointsWithLabelGraphSeries.Shape =
|
override fun getShape(): PointsWithLabelGraphSeries.Shape =
|
||||||
when {
|
when {
|
||||||
data.type == TherapyEvent.Type.NS_MBG -> PointsWithLabelGraphSeries.Shape.MBG
|
data.type == TherapyEvent.Type.NS_MBG -> PointsWithLabelGraphSeries.Shape.MBG
|
||||||
|
@ -74,22 +72,4 @@ class TherapyEventDataPoint @Inject constructor(
|
||||||
TherapyEvent.Type.APS_OFFLINE -> Color.GRAY and -0x7f000001
|
TherapyEvent.Type.APS_OFFLINE -> Color.GRAY and -0x7f000001
|
||||||
else -> Color.GRAY
|
else -> Color.GRAY
|
||||||
}
|
}
|
||||||
|
|
||||||
// Interval interface
|
|
||||||
private var cutEnd: Long? = null
|
|
||||||
|
|
||||||
override fun durationInMsec(): Long = data.duration
|
|
||||||
override fun start(): Long = data.timestamp
|
|
||||||
override fun originalEnd(): Long = data.timestamp + durationInMsec()
|
|
||||||
override fun end(): Long = cutEnd ?: originalEnd()
|
|
||||||
override fun cutEndTo(end: Long) {
|
|
||||||
cutEnd = end
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun match(time: Long): Boolean = start() <= time && end() >= time
|
|
||||||
override fun before(time: Long): Boolean = end() < time
|
|
||||||
override fun after(time: Long): Boolean = start() > time
|
|
||||||
override val isInProgress: Boolean get() = match(System.currentTimeMillis())
|
|
||||||
override val isEndingEvent: Boolean get() = durationInMsec() == 0L
|
|
||||||
override val isValid: Boolean get() = data.type == TherapyEvent.Type.APS_OFFLINE
|
|
||||||
}
|
}
|
|
@ -128,7 +128,7 @@ class NotificationStore @Inject constructor(
|
||||||
private fun deleteIntent(id: Int): PendingIntent {
|
private fun deleteIntent(id: Int): PendingIntent {
|
||||||
val intent = Intent(context, DismissNotificationService::class.java)
|
val intent = Intent(context, DismissNotificationService::class.java)
|
||||||
intent.putExtra("alertID", id)
|
intent.putExtra("alertID", id)
|
||||||
return PendingIntent.getService(context, id, intent, PendingIntent.FLAG_UPDATE_CURRENT)
|
return PendingIntent.getService(context, id, intent, PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun createNotificationChannel() {
|
fun createNotificationChannel() {
|
||||||
|
|
|
@ -171,7 +171,7 @@ class PersistentNotificationPlugin @Inject constructor(
|
||||||
val msgReadPendingIntent = PendingIntent.getBroadcast(context,
|
val msgReadPendingIntent = PendingIntent.getBroadcast(context,
|
||||||
notificationHolder.notificationID,
|
notificationHolder.notificationID,
|
||||||
msgReadIntent,
|
msgReadIntent,
|
||||||
PendingIntent.FLAG_UPDATE_CURRENT)
|
PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT)
|
||||||
val msgReplyIntent = Intent()
|
val msgReplyIntent = Intent()
|
||||||
.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES)
|
.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES)
|
||||||
.setAction(REPLY_ACTION)
|
.setAction(REPLY_ACTION)
|
||||||
|
@ -181,7 +181,7 @@ class PersistentNotificationPlugin @Inject constructor(
|
||||||
context,
|
context,
|
||||||
notificationHolder.notificationID,
|
notificationHolder.notificationID,
|
||||||
msgReplyIntent,
|
msgReplyIntent,
|
||||||
PendingIntent.FLAG_UPDATE_CURRENT)
|
PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT)
|
||||||
// Build a RemoteInput for receiving voice input from devices
|
// Build a RemoteInput for receiving voice input from devices
|
||||||
val remoteInput = RemoteInput.Builder(EXTRA_VOICE_REPLY).build()
|
val remoteInput = RemoteInput.Builder(EXTRA_VOICE_REPLY).build()
|
||||||
// Create the UnreadConversation
|
// Create the UnreadConversation
|
||||||
|
|
|
@ -1,13 +1,16 @@
|
||||||
package info.nightscout.androidaps.plugins.general.smsCommunicator
|
package info.nightscout.androidaps.plugins.general.smsCommunicator
|
||||||
|
|
||||||
|
import android.os.SystemClock
|
||||||
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
|
||||||
|
import info.nightscout.androidaps.interfaces.CommandQueueProvider
|
||||||
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.utils.DateUtil
|
|
||||||
import info.nightscout.androidaps.plugins.general.smsCommunicator.otp.OneTimePassword
|
import info.nightscout.androidaps.plugins.general.smsCommunicator.otp.OneTimePassword
|
||||||
import info.nightscout.androidaps.plugins.general.smsCommunicator.otp.OneTimePasswordValidationResult
|
import info.nightscout.androidaps.plugins.general.smsCommunicator.otp.OneTimePasswordValidationResult
|
||||||
|
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 javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
@ -23,6 +26,7 @@ class AuthRequest internal constructor(
|
||||||
@Inject lateinit var resourceHelper: ResourceHelper
|
@Inject lateinit var resourceHelper: ResourceHelper
|
||||||
@Inject lateinit var otp: OneTimePassword
|
@Inject lateinit var otp: OneTimePassword
|
||||||
@Inject lateinit var dateUtil: DateUtil
|
@Inject lateinit var dateUtil: DateUtil
|
||||||
|
@Inject lateinit var commandQueue: CommandQueueProvider
|
||||||
|
|
||||||
private var date = 0L
|
private var date = 0L
|
||||||
private var processed = false
|
private var processed = false
|
||||||
|
@ -49,6 +53,19 @@ class AuthRequest internal constructor(
|
||||||
}
|
}
|
||||||
if (dateUtil.now() - date < Constants.SMS_CONFIRM_TIMEOUT) {
|
if (dateUtil.now() - date < Constants.SMS_CONFIRM_TIMEOUT) {
|
||||||
processed = true
|
processed = true
|
||||||
|
if (action.pumpCommand) {
|
||||||
|
val start = dateUtil.now()
|
||||||
|
//wait for empty queue
|
||||||
|
while (start + T.mins(3).msecs() > dateUtil.now()) {
|
||||||
|
if (commandQueue.size() == 0) break
|
||||||
|
SystemClock.sleep(100)
|
||||||
|
}
|
||||||
|
if (commandQueue.size() != 0) {
|
||||||
|
aapsLogger.debug(LTag.SMS, "Command timed out: " + requester.text)
|
||||||
|
smsCommunicatorPlugin.sendSMS(Sms(requester.phoneNumber, resourceHelper.gs(R.string.sms_timeout_while_wating)))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
aapsLogger.debug(LTag.SMS, "Processing confirmed SMS: " + requester.text)
|
aapsLogger.debug(LTag.SMS, "Processing confirmed SMS: " + requester.text)
|
||||||
action.run()
|
action.run()
|
||||||
return
|
return
|
||||||
|
|
|
@ -1,37 +1,37 @@
|
||||||
package info.nightscout.androidaps.plugins.general.smsCommunicator
|
package info.nightscout.androidaps.plugins.general.smsCommunicator
|
||||||
|
|
||||||
abstract class SmsAction : Runnable {
|
abstract class SmsAction(val pumpCommand: Boolean) : Runnable {
|
||||||
|
|
||||||
var aDouble: Double? = null
|
var aDouble: Double? = null
|
||||||
var anInteger: Int? = null
|
var anInteger: Int? = null
|
||||||
var secondInteger: Int? = null
|
var secondInteger: Int? = null
|
||||||
var secondLong: Long? = null
|
var secondLong: Long? = null
|
||||||
var aString: String? = null
|
var aString: String? = null
|
||||||
|
|
||||||
internal constructor()
|
internal constructor(pumpCommand: Boolean, aDouble: Double) : this(pumpCommand) {
|
||||||
internal constructor(aDouble: Double) {
|
|
||||||
this.aDouble = aDouble
|
this.aDouble = aDouble
|
||||||
}
|
}
|
||||||
|
|
||||||
internal constructor(aDouble: Double, secondInteger: Int) {
|
internal constructor(pumpCommand: Boolean, aDouble: Double, secondInteger: Int) : this(pumpCommand) {
|
||||||
this.aDouble = aDouble
|
this.aDouble = aDouble
|
||||||
this.secondInteger = secondInteger
|
this.secondInteger = secondInteger
|
||||||
}
|
}
|
||||||
|
|
||||||
internal constructor(aString: String, secondInteger: Int) {
|
internal constructor(pumpCommand: Boolean, aString: String, secondInteger: Int) : this(pumpCommand) {
|
||||||
this.aString = aString
|
this.aString = aString
|
||||||
this.secondInteger = secondInteger
|
this.secondInteger = secondInteger
|
||||||
}
|
}
|
||||||
|
|
||||||
internal constructor(anInteger: Int) {
|
internal constructor(pumpCommand: Boolean, anInteger: Int) : this(pumpCommand) {
|
||||||
this.anInteger = anInteger
|
this.anInteger = anInteger
|
||||||
}
|
}
|
||||||
|
|
||||||
internal constructor(anInteger: Int, secondInteger: Int) {
|
internal constructor(pumpCommand: Boolean, anInteger: Int, secondInteger: Int) : this(pumpCommand) {
|
||||||
this.anInteger = anInteger
|
this.anInteger = anInteger
|
||||||
this.secondInteger = secondInteger
|
this.secondInteger = secondInteger
|
||||||
}
|
}
|
||||||
|
|
||||||
internal constructor(anInteger: Int, secondLong: Long) {
|
internal constructor(pumpCommand: Boolean, anInteger: Int, secondLong: Long) : this(pumpCommand) {
|
||||||
this.anInteger = anInteger
|
this.anInteger = anInteger
|
||||||
this.secondLong = secondLong
|
this.secondLong = secondLong
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,25 +11,27 @@ 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.annotations.OpenForTesting
|
||||||
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 +43,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
|
||||||
|
@ -59,11 +60,13 @@ import javax.inject.Singleton
|
||||||
import kotlin.math.max
|
import kotlin.math.max
|
||||||
import kotlin.math.min
|
import kotlin.math.min
|
||||||
|
|
||||||
|
@OpenForTesting
|
||||||
@Singleton
|
@Singleton
|
||||||
class SmsCommunicatorPlugin @Inject constructor(
|
class SmsCommunicatorPlugin @Inject constructor(
|
||||||
injector: HasAndroidInjector,
|
injector: HasAndroidInjector,
|
||||||
aapsLogger: AAPSLogger,
|
aapsLogger: AAPSLogger,
|
||||||
resourceHelper: ResourceHelper,
|
resourceHelper: ResourceHelper,
|
||||||
|
private val smsManager: SmsManager,
|
||||||
private val aapsSchedulers: AapsSchedulers,
|
private val aapsSchedulers: AapsSchedulers,
|
||||||
private val sp: SP,
|
private val sp: SP,
|
||||||
private val constraintChecker: ConstraintChecker,
|
private val constraintChecker: ConstraintChecker,
|
||||||
|
@ -72,7 +75,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,
|
||||||
|
@ -94,8 +97,8 @@ class SmsCommunicatorPlugin @Inject constructor(
|
||||||
|
|
||||||
private val disposable = CompositeDisposable()
|
private val disposable = CompositeDisposable()
|
||||||
var allowedNumbers: MutableList<String> = ArrayList()
|
var allowedNumbers: MutableList<String> = ArrayList()
|
||||||
var messageToConfirm: AuthRequest? = null
|
@Volatile var messageToConfirm: AuthRequest? = null
|
||||||
var lastRemoteBolusTime: Long = 0
|
@Volatile var lastRemoteBolusTime: Long = 0
|
||||||
var messages = ArrayList<Sms>()
|
var messages = ArrayList<Sms>()
|
||||||
|
|
||||||
val commands = mapOf(
|
val commands = mapOf(
|
||||||
|
@ -181,7 +184,6 @@ 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"))
|
||||||
|
@ -224,7 +226,6 @@ 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.")
|
||||||
|
@ -278,6 +279,7 @@ class SmsCommunicatorPlugin @Inject constructor(
|
||||||
else sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.wrongformat)))
|
else sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.wrongformat)))
|
||||||
"BOLUS" ->
|
"BOLUS" ->
|
||||||
if (!remoteCommandsAllowed) sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.smscommunicator_remotecommandnotallowed)))
|
if (!remoteCommandsAllowed) sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.smscommunicator_remotecommandnotallowed)))
|
||||||
|
else if (commandQueue.bolusInQueue()) sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.smscommunicator_another_bolus_in_queue)))
|
||||||
else if (divided.size == 2 && dateUtil.now() - lastRemoteBolusTime < minDistance) sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.smscommunicator_remotebolusnotallowed)))
|
else if (divided.size == 2 && dateUtil.now() - lastRemoteBolusTime < minDistance) sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.smscommunicator_remotebolusnotallowed)))
|
||||||
else if (divided.size == 2 && pump.isSuspended()) sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.pumpsuspended)))
|
else if (divided.size == 2 && pump.isSuspended()) sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.pumpsuspended)))
|
||||||
else if (divided.size == 2 || divided.size == 3) processBOLUS(divided, receivedSms)
|
else if (divided.size == 2 || divided.size == 3) processBOLUS(divided, receivedSms)
|
||||||
|
@ -303,9 +305,13 @@ class SmsCommunicatorPlugin @Inject constructor(
|
||||||
else sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.wrongformat)))
|
else sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.wrongformat)))
|
||||||
else ->
|
else ->
|
||||||
if (messageToConfirm?.requester?.phoneNumber == receivedSms.phoneNumber) {
|
if (messageToConfirm?.requester?.phoneNumber == receivedSms.phoneNumber) {
|
||||||
messageToConfirm?.action(divided[0])
|
val execute = messageToConfirm
|
||||||
messageToConfirm = null
|
messageToConfirm = null
|
||||||
} else sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.smscommunicator_unknowncommand)))
|
execute?.action(divided[0])
|
||||||
|
} else {
|
||||||
|
messageToConfirm = null
|
||||||
|
sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.smscommunicator_unknowncommand)))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
rxBus.send(EventSmsCommunicatorUpdateGui())
|
rxBus.send(EventSmsCommunicatorUpdateGui())
|
||||||
|
@ -336,18 +342,17 @@ 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].uppercase(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(pumpCommand = false) {
|
||||||
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"))
|
||||||
|
@ -364,14 +369,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(pumpCommand = false) {
|
||||||
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"))
|
||||||
}
|
}
|
||||||
|
@ -382,8 +387,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,10 +400,15 @@ class SmsCommunicatorPlugin @Inject constructor(
|
||||||
val passCode = generatePassCode()
|
val passCode = generatePassCode()
|
||||||
val reply = String.format(resourceHelper.gs(R.string.smscommunicator_loopresumereplywithcode), passCode)
|
val reply = String.format(resourceHelper.gs(R.string.smscommunicator_loopresumereplywithcode), passCode)
|
||||||
receivedSms.processed = true
|
receivedSms.processed = true
|
||||||
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction() {
|
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction(pumpCommand = true) {
|
||||||
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() {
|
||||||
|
@ -409,7 +419,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)))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -428,14 +437,19 @@ class SmsCommunicatorPlugin @Inject constructor(
|
||||||
val passCode = generatePassCode()
|
val passCode = generatePassCode()
|
||||||
val reply = String.format(resourceHelper.gs(R.string.smscommunicator_suspendreplywithcode), duration, passCode)
|
val reply = String.format(resourceHelper.gs(R.string.smscommunicator_suspendreplywithcode), duration, passCode)
|
||||||
receivedSms.processed = true
|
receivedSms.processed = true
|
||||||
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction(duration) {
|
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction(pumpCommand = true, duration) {
|
||||||
override fun run() {
|
override fun run() {
|
||||||
uel.log(Action.SUSPEND, Sources.SMS)
|
uel.log(Action.SUSPEND, Sources.SMS)
|
||||||
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)
|
||||||
|
@ -456,7 +470,6 @@ 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].uppercase(Locale.getDefault()) == "RESTART") {
|
if (divided[1].uppercase(Locale.getDefault()) == "RESTART") {
|
||||||
rxBus.send(EventNSClientRestart())
|
rxBus.send(EventNSClientRestart())
|
||||||
|
@ -466,7 +479,6 @@ 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 -> {
|
||||||
|
@ -504,7 +516,7 @@ class SmsCommunicatorPlugin @Inject constructor(
|
||||||
val passCode = generatePassCode()
|
val passCode = generatePassCode()
|
||||||
val reply = String.format(resourceHelper.gs(R.string.smscommunicator_pumpconnectwithcode), passCode)
|
val reply = String.format(resourceHelper.gs(R.string.smscommunicator_pumpconnectwithcode), passCode)
|
||||||
receivedSms.processed = true
|
receivedSms.processed = true
|
||||||
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction() {
|
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction(pumpCommand = true) {
|
||||||
override fun run() {
|
override fun run() {
|
||||||
uel.log(Action.RECONNECT, Sources.SMS)
|
uel.log(Action.RECONNECT, Sources.SMS)
|
||||||
commandQueue.cancelTempBasal(true, object : Callback() {
|
commandQueue.cancelTempBasal(true, object : Callback() {
|
||||||
|
@ -512,10 +524,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)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -533,11 +549,11 @@ class SmsCommunicatorPlugin @Inject constructor(
|
||||||
val passCode = generatePassCode()
|
val passCode = generatePassCode()
|
||||||
val reply = String.format(resourceHelper.gs(R.string.smscommunicator_pumpdisconnectwithcode), duration, passCode)
|
val reply = String.format(resourceHelper.gs(R.string.smscommunicator_pumpdisconnectwithcode), duration, passCode)
|
||||||
receivedSms.processed = true
|
receivedSms.processed = true
|
||||||
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction() {
|
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction(pumpCommand = true) {
|
||||||
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)))
|
||||||
}
|
}
|
||||||
|
@ -549,7 +565,6 @@ 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
|
||||||
|
@ -588,7 +603,7 @@ class SmsCommunicatorPlugin @Inject constructor(
|
||||||
val reply = String.format(resourceHelper.gs(R.string.smscommunicator_profilereplywithcode), list[pIndex - 1], percentage, passCode)
|
val reply = String.format(resourceHelper.gs(R.string.smscommunicator_profilereplywithcode), list[pIndex - 1], percentage, passCode)
|
||||||
receivedSms.processed = true
|
receivedSms.processed = true
|
||||||
val finalPercentage = percentage
|
val finalPercentage = percentage
|
||||||
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction(list[pIndex - 1] as String, finalPercentage) {
|
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction(pumpCommand = true, list[pIndex - 1] as String, finalPercentage) {
|
||||||
override fun run() {
|
override fun run() {
|
||||||
profileFunction.createProfileSwitch(store, list[pIndex - 1] as String, 0, finalPercentage, 0, dateUtil.now())
|
profileFunction.createProfileSwitch(store, list[pIndex - 1] as String, 0, finalPercentage, 0, dateUtil.now())
|
||||||
val replyText = resourceHelper.gs(R.string.profileswitchcreated)
|
val replyText = resourceHelper.gs(R.string.profileswitchcreated)
|
||||||
|
@ -603,13 +618,12 @@ 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].uppercase(Locale.getDefault()) == "CANCEL" || divided[1].uppercase(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
|
||||||
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction() {
|
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction(pumpCommand = true) {
|
||||||
override fun run() {
|
override fun run() {
|
||||||
commandQueue.cancelTempBasal(true, object : Callback() {
|
commandQueue.cancelTempBasal(true, object : Callback() {
|
||||||
override fun run() {
|
override fun run() {
|
||||||
|
@ -644,7 +658,7 @@ class SmsCommunicatorPlugin @Inject constructor(
|
||||||
val passCode = generatePassCode()
|
val passCode = generatePassCode()
|
||||||
val reply = String.format(resourceHelper.gs(R.string.smscommunicator_basalpctreplywithcode), tempBasalPct, duration, passCode)
|
val reply = String.format(resourceHelper.gs(R.string.smscommunicator_basalpctreplywithcode), tempBasalPct, duration, passCode)
|
||||||
receivedSms.processed = true
|
receivedSms.processed = true
|
||||||
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction(tempBasalPct, duration) {
|
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction(pumpCommand = true, tempBasalPct, duration) {
|
||||||
override fun run() {
|
override fun run() {
|
||||||
commandQueue.tempBasalPercent(anInteger(), secondInteger(), true, profile, PumpSync.TemporaryBasalType.NORMAL, object : Callback() {
|
commandQueue.tempBasalPercent(anInteger(), secondInteger(), true, profile, PumpSync.TemporaryBasalType.NORMAL, object : Callback() {
|
||||||
override fun run() {
|
override fun run() {
|
||||||
|
@ -688,7 +702,7 @@ class SmsCommunicatorPlugin @Inject constructor(
|
||||||
val passCode = generatePassCode()
|
val passCode = generatePassCode()
|
||||||
val reply = String.format(resourceHelper.gs(R.string.smscommunicator_basalreplywithcode), tempBasal, duration, passCode)
|
val reply = String.format(resourceHelper.gs(R.string.smscommunicator_basalreplywithcode), tempBasal, duration, passCode)
|
||||||
receivedSms.processed = true
|
receivedSms.processed = true
|
||||||
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction(tempBasal, duration) {
|
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction(pumpCommand = true, tempBasal, duration) {
|
||||||
override fun run() {
|
override fun run() {
|
||||||
commandQueue.tempBasalAbsolute(aDouble(), secondInteger(), true, profile, PumpSync.TemporaryBasalType.NORMAL, object : Callback() {
|
commandQueue.tempBasalAbsolute(aDouble(), secondInteger(), true, profile, PumpSync.TemporaryBasalType.NORMAL, object : Callback() {
|
||||||
override fun run() {
|
override fun run() {
|
||||||
|
@ -720,13 +734,12 @@ 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].uppercase(Locale.getDefault()) == "CANCEL" || divided[1].uppercase(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
|
||||||
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction() {
|
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction(pumpCommand = true) {
|
||||||
override fun run() {
|
override fun run() {
|
||||||
commandQueue.cancelExtended(object : Callback() {
|
commandQueue.cancelExtended(object : Callback() {
|
||||||
override fun run() {
|
override fun run() {
|
||||||
|
@ -756,7 +769,7 @@ class SmsCommunicatorPlugin @Inject constructor(
|
||||||
val passCode = generatePassCode()
|
val passCode = generatePassCode()
|
||||||
val reply = String.format(resourceHelper.gs(R.string.smscommunicator_extendedreplywithcode), extended, duration, passCode)
|
val reply = String.format(resourceHelper.gs(R.string.smscommunicator_extendedreplywithcode), extended, duration, passCode)
|
||||||
receivedSms.processed = true
|
receivedSms.processed = true
|
||||||
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction(extended, duration) {
|
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction(pumpCommand = true, extended, duration) {
|
||||||
override fun run() {
|
override fun run() {
|
||||||
commandQueue.extendedBolus(aDouble(), secondInteger(), object : Callback() {
|
commandQueue.extendedBolus(aDouble(), secondInteger(), object : Callback() {
|
||||||
override fun run() {
|
override fun run() {
|
||||||
|
@ -802,7 +815,7 @@ class SmsCommunicatorPlugin @Inject constructor(
|
||||||
else
|
else
|
||||||
String.format(resourceHelper.gs(R.string.smscommunicator_bolusreplywithcode), bolus, passCode)
|
String.format(resourceHelper.gs(R.string.smscommunicator_bolusreplywithcode), bolus, passCode)
|
||||||
receivedSms.processed = true
|
receivedSms.processed = true
|
||||||
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction(bolus) {
|
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction(pumpCommand = true, bolus) {
|
||||||
override fun run() {
|
override fun run() {
|
||||||
val detailedBolusInfo = DetailedBolusInfo()
|
val detailedBolusInfo = DetailedBolusInfo()
|
||||||
detailedBolusInfo.insulin = aDouble()
|
detailedBolusInfo.insulin = aDouble()
|
||||||
|
@ -832,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,
|
||||||
|
@ -887,7 +900,6 @@ 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()
|
||||||
|
@ -904,7 +916,7 @@ class SmsCommunicatorPlugin @Inject constructor(
|
||||||
val passCode = generatePassCode()
|
val passCode = generatePassCode()
|
||||||
val reply = String.format(resourceHelper.gs(R.string.smscommunicator_carbsreplywithcode), grams, dateUtil.timeString(time), passCode)
|
val reply = String.format(resourceHelper.gs(R.string.smscommunicator_carbsreplywithcode), grams, dateUtil.timeString(time), passCode)
|
||||||
receivedSms.processed = true
|
receivedSms.processed = true
|
||||||
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction(grams, time) {
|
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction(pumpCommand = true, grams, time) {
|
||||||
override fun run() {
|
override fun run() {
|
||||||
val detailedBolusInfo = DetailedBolusInfo()
|
val detailedBolusInfo = DetailedBolusInfo()
|
||||||
detailedBolusInfo.carbs = anInteger().toDouble()
|
detailedBolusInfo.carbs = anInteger().toDouble()
|
||||||
|
@ -931,7 +943,6 @@ 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)
|
||||||
|
@ -941,7 +952,7 @@ class SmsCommunicatorPlugin @Inject constructor(
|
||||||
val passCode = generatePassCode()
|
val passCode = generatePassCode()
|
||||||
val reply = String.format(resourceHelper.gs(R.string.smscommunicator_temptargetwithcode), divided[1].uppercase(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(pumpCommand = false) {
|
||||||
override fun run() {
|
override fun run() {
|
||||||
val units = profileFunction.getUnits()
|
val units = profileFunction.getUnits()
|
||||||
var keyDuration = 0
|
var keyDuration = 0
|
||||||
|
@ -979,7 +990,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,
|
||||||
|
@ -1003,7 +1014,7 @@ class SmsCommunicatorPlugin @Inject constructor(
|
||||||
val passCode = generatePassCode()
|
val passCode = generatePassCode()
|
||||||
val reply = String.format(resourceHelper.gs(R.string.smscommunicator_temptargetcancel), passCode)
|
val reply = String.format(resourceHelper.gs(R.string.smscommunicator_temptargetcancel), passCode)
|
||||||
receivedSms.processed = true
|
receivedSms.processed = true
|
||||||
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction() {
|
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction(pumpCommand = false) {
|
||||||
override fun run() {
|
override fun run() {
|
||||||
disposable += repository.runTransactionForResult(CancelCurrentTemporaryTargetIfAnyTransaction(dateUtil.now()))
|
disposable += repository.runTransactionForResult(CancelCurrentTemporaryTargetIfAnyTransaction(dateUtil.now()))
|
||||||
.subscribe({ result ->
|
.subscribe({ result ->
|
||||||
|
@ -1028,7 +1039,7 @@ class SmsCommunicatorPlugin @Inject constructor(
|
||||||
val passCode = generatePassCode()
|
val passCode = generatePassCode()
|
||||||
val reply = String.format(resourceHelper.gs(R.string.smscommunicator_stopsmswithcode), passCode)
|
val reply = String.format(resourceHelper.gs(R.string.smscommunicator_stopsmswithcode), passCode)
|
||||||
receivedSms.processed = true
|
receivedSms.processed = true
|
||||||
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction() {
|
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction(pumpCommand = false) {
|
||||||
override fun run() {
|
override fun run() {
|
||||||
sp.putBoolean(R.string.key_smscommunicator_remotecommandsallowed, false)
|
sp.putBoolean(R.string.key_smscommunicator_remotecommandsallowed, false)
|
||||||
val replyText = String.format(resourceHelper.gs(R.string.smscommunicator_stoppedsms))
|
val replyText = String.format(resourceHelper.gs(R.string.smscommunicator_stoppedsms))
|
||||||
|
@ -1046,7 +1057,7 @@ class SmsCommunicatorPlugin @Inject constructor(
|
||||||
val passCode = generatePassCode()
|
val passCode = generatePassCode()
|
||||||
val reply = String.format(resourceHelper.gs(R.string.smscommunicator_calibrationreplywithcode), cal, passCode)
|
val reply = String.format(resourceHelper.gs(R.string.smscommunicator_calibrationreplywithcode), cal, passCode)
|
||||||
receivedSms.processed = true
|
receivedSms.processed = true
|
||||||
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction(cal) {
|
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction(pumpCommand = false, cal) {
|
||||||
override fun run() {
|
override fun run() {
|
||||||
val result = xdripCalibrations.sendIntent(aDouble!!)
|
val result = xdripCalibrations.sendIntent(aDouble!!)
|
||||||
val replyText =
|
val replyText =
|
||||||
|
@ -1080,7 +1091,6 @@ class SmsCommunicatorPlugin @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
fun sendSMS(sms: Sms): Boolean {
|
fun sendSMS(sms: Sms): Boolean {
|
||||||
val smsManager = SmsManager.getDefault()
|
|
||||||
sms.text = stripAccents(sms.text)
|
sms.text = stripAccents(sms.text)
|
||||||
try {
|
try {
|
||||||
aapsLogger.debug(LTag.SMS, "Sending SMS to " + sms.phoneNumber + ": " + sms.text)
|
aapsLogger.debug(LTag.SMS, "Sending SMS to " + sms.phoneNumber + ": " + sms.text)
|
||||||
|
|
|
@ -88,7 +88,7 @@ class SmsCommunicatorOtpActivity : NoSplashAppCompatActivity() {
|
||||||
Runnable {
|
Runnable {
|
||||||
val clipboard = getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
|
val clipboard = getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
|
||||||
val clip = ClipData.newPlainText("OTP Secret", otp.provisioningSecret())
|
val clip = ClipData.newPlainText("OTP Secret", otp.provisioningSecret())
|
||||||
clipboard.primaryClip = clip
|
clipboard.setPrimaryClip(clip)
|
||||||
ToastUtils.Long.infoToast(this, resourceHelper.gs(R.string.smscommunicator_otp_export_successful))
|
ToastUtils.Long.infoToast(this, resourceHelper.gs(R.string.smscommunicator_otp_export_successful))
|
||||||
uel.log(Action.OTP_EXPORT, Sources.SMS)
|
uel.log(Action.OTP_EXPORT, Sources.SMS)
|
||||||
})
|
})
|
||||||
|
|
|
@ -5,6 +5,7 @@ import com.eatthepath.otp.HmacOneTimePasswordGenerator
|
||||||
import com.google.common.io.BaseEncoding
|
import com.google.common.io.BaseEncoding
|
||||||
import info.nightscout.androidaps.Constants
|
import info.nightscout.androidaps.Constants
|
||||||
import info.nightscout.androidaps.R
|
import info.nightscout.androidaps.R
|
||||||
|
import info.nightscout.androidaps.annotations.OpenForTesting
|
||||||
import info.nightscout.androidaps.utils.DateUtil
|
import info.nightscout.androidaps.utils.DateUtil
|
||||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||||
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
||||||
|
@ -15,6 +16,7 @@ import javax.crypto.spec.SecretKeySpec
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
|
|
||||||
|
@OpenForTesting
|
||||||
@Singleton
|
@Singleton
|
||||||
class OneTimePassword @Inject constructor(
|
class OneTimePassword @Inject constructor(
|
||||||
private val sp: SP,
|
private val sp: SP,
|
||||||
|
|
|
@ -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,
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue