Merge branch 'dev' into signature_verifier
This commit is contained in:
commit
b448bbe670
|
@ -2,19 +2,19 @@ language: android
|
|||
jdk: oraclejdk8
|
||||
env:
|
||||
matrix:
|
||||
- ANDROID_TARGET=android-23 ANDROID_ABI=x86 org.gradle.jvmargs=-XX:-OmitStackTraceInFastThrow
|
||||
- ANDROID_TARGET=android-28 ANDROID_ABI=x86 org.gradle.jvmargs=-XX:-OmitStackTraceInFastThrow
|
||||
android:
|
||||
components:
|
||||
- platform-tools
|
||||
- tools
|
||||
- build-tools-27.0.2
|
||||
- android-23
|
||||
- build-tools-28.0.3
|
||||
- android-28
|
||||
- extra-google-m2repository
|
||||
- extra-android-m2repository
|
||||
- extra-google-google_play_services
|
||||
|
||||
before_install:
|
||||
- yes | sdkmanager "platforms;android-27"
|
||||
#- yes | sdkmanager "platforms;android-28"
|
||||
|
||||
script:
|
||||
# Unit Test
|
||||
|
|
|
@ -11,4 +11,4 @@
|
|||
dev: [![codecov](https://codecov.io/gh/MilosKozak/AndroidAPS/branch/dev/graph/badge.svg)](https://codecov.io/gh/MilosKozak/AndroidAPS)
|
||||
|
||||
|
||||
[![Donate via PayPal](https://www.paypalobjects.com/en_US/i/btn/btn_donateCC_LG.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=Y4LHGJJESAVB8)
|
||||
[![Donate via PayPal](https://www.paypalobjects.com/en_US/i/btn/btn_donateCC_LG.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=Y4LHGJJESAVB8)
|
121
app/build.gradle
121
app/build.gradle
|
@ -6,23 +6,30 @@ buildscript {
|
|||
|
||||
dependencies {
|
||||
classpath 'io.fabric.tools:gradle:1.+'
|
||||
classpath 'com.dicedmelon.gradle:jacoco-android:0.1.3'
|
||||
classpath 'com.dicedmelon.gradle:jacoco-android:0.1.4'
|
||||
classpath 'de.undercouch:gradle-download-task:3.4.3'
|
||||
}
|
||||
}
|
||||
apply plugin: "com.android.application"
|
||||
apply plugin: 'kotlin-android-extensions'
|
||||
apply plugin: 'com.android.application'
|
||||
apply plugin: 'kotlin-android'
|
||||
apply plugin: 'kotlin-android-extensions'
|
||||
apply plugin: 'com.google.gms.google-services'
|
||||
apply plugin: "io.fabric"
|
||||
apply plugin: "jacoco-android"
|
||||
apply plugin: 'io.fabric'
|
||||
apply plugin: 'jacoco-android'
|
||||
apply plugin: 'com.jakewharton.butterknife'
|
||||
apply plugin: 'de.undercouch.download'
|
||||
|
||||
|
||||
jacoco {
|
||||
toolVersion = "0.8.3"
|
||||
}
|
||||
|
||||
ext {
|
||||
supportLibraryVersion = "27.1.1"
|
||||
supportLibraryVersion = "28.0.0"
|
||||
ormLiteVersion = "4.46"
|
||||
powermockVersion = "1.7.3"
|
||||
dexmakerVersion = "1.2"
|
||||
butterknifeVersion = "8.8.1"
|
||||
butterknifeVersion = "10.1.0"
|
||||
}
|
||||
|
||||
|
||||
|
@ -79,7 +86,7 @@ def allCommited = { ->
|
|||
try {
|
||||
def stdout = new ByteArrayOutputStream()
|
||||
exec {
|
||||
commandLine 'git', 'status'
|
||||
commandLine 'git', 'status', '-s'
|
||||
standardOutput = stdout
|
||||
}
|
||||
String commitObject = stdout.toString().trim()
|
||||
|
@ -87,7 +94,8 @@ def allCommited = { ->
|
|||
} catch (ignored) {
|
||||
return false; // NoGitSystemAvailable
|
||||
}
|
||||
return stringBuilder.toString().contains("nothing to commit")
|
||||
return stringBuilder.toString().isEmpty()
|
||||
|
||||
}
|
||||
|
||||
tasks.matching { it instanceof Test }.all {
|
||||
|
@ -96,19 +104,19 @@ tasks.matching { it instanceof Test }.all {
|
|||
}
|
||||
|
||||
android {
|
||||
compileSdkVersion 27
|
||||
compileSdkVersion 28
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion 21
|
||||
targetSdkVersion 25
|
||||
minSdkVersion 23
|
||||
targetSdkVersion 28
|
||||
multiDexEnabled true
|
||||
versionCode 1500
|
||||
version "2.3.1-dev"
|
||||
version "2.4-dev"
|
||||
buildConfigField "String", "VERSION", '"' + version + '"'
|
||||
buildConfigField "String", "BUILDVERSION", '"' + generateGitBuild() + '-' + generateDate() + '"'
|
||||
buildConfigField "String", "REMOTE", '"' + generateGitRemote() + '"'
|
||||
buildConfigField "String", "HEAD", '"' + generateGitBuild() + '"'
|
||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
// if you change minSdkVersion to less than 11, you need to change executeTask for wear
|
||||
|
||||
ndk {
|
||||
|
@ -187,8 +195,15 @@ android {
|
|||
}
|
||||
|
||||
testOptions {
|
||||
unitTests.returnDefaultValues = true
|
||||
unitTests.includeAndroidResources = true
|
||||
unitTests {
|
||||
returnDefaultValues = true
|
||||
includeAndroidResources = true
|
||||
|
||||
all {
|
||||
maxParallelForks = 10
|
||||
forkEvery = 20
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
useLibrary "org.apache.http.legacy"
|
||||
|
@ -200,34 +215,34 @@ allprojects {
|
|||
flatDir {
|
||||
dirs 'libs'
|
||||
}
|
||||
maven { url 'https://jitpack.io' }
|
||||
}
|
||||
}
|
||||
|
||||
configurations {
|
||||
libs
|
||||
}
|
||||
|
||||
dependencies {
|
||||
wearApp project(':wear')
|
||||
|
||||
implementation fileTree(include: ['*.jar'], dir: 'libs')
|
||||
implementation 'com.google.android.gms:play-services-wearable:16.0.1'
|
||||
implementation 'com.google.firebase:firebase-core:16.0.8'
|
||||
implementation 'com.google.android.gms:play-services-wearable:17.0.0'
|
||||
implementation 'com.google.firebase:firebase-core:17.0.1'
|
||||
implementation("com.crashlytics.sdk.android:crashlytics:2.9.9@aar") {
|
||||
transitive = true;
|
||||
}
|
||||
libs "MilosKozak:danars-support-lib:master@zip"
|
||||
|
||||
implementation "com.android.support:appcompat-v7:${supportLibraryVersion}"
|
||||
implementation "com.android.support:support-v13:${supportLibraryVersion}"
|
||||
implementation "com.android.support:support-v4:${supportLibraryVersion}"
|
||||
implementation "com.android.support:cardview-v7:${supportLibraryVersion}"
|
||||
implementation "com.android.support:recyclerview-v7:${supportLibraryVersion}"
|
||||
implementation "com.android.support:gridlayout-v7:${supportLibraryVersion}"
|
||||
implementation "com.android.support:design:${supportLibraryVersion}"
|
||||
implementation "com.android.support:percent:${supportLibraryVersion}"
|
||||
implementation 'androidx.appcompat:appcompat:1.0.2'
|
||||
implementation 'androidx.legacy:legacy-support-v13:1.0.0'
|
||||
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
|
||||
implementation 'androidx.cardview:cardview:1.0.0'
|
||||
implementation 'androidx.recyclerview:recyclerview:1.0.0'
|
||||
implementation 'androidx.gridlayout:gridlayout:1.0.0'
|
||||
implementation 'com.google.android.material:material:1.0.0'
|
||||
implementation 'androidx.percentlayout:percentlayout:1.0.0'
|
||||
implementation "com.wdullaer:materialdatetimepicker:2.3.0"
|
||||
|
||||
// Otto bus will be replaced by rx
|
||||
implementation "com.squareup:otto:1.3.7"
|
||||
implementation "io.reactivex.rxjava2:rxandroid:2.1.1"
|
||||
|
||||
implementation "com.j256.ormlite:ormlite-core:${ormLiteVersion}"
|
||||
implementation "com.j256.ormlite:ormlite-android:${ormLiteVersion}"
|
||||
implementation("com.github.tony19:logback-android-classic:1.1.1-6") {
|
||||
|
@ -238,7 +253,7 @@ dependencies {
|
|||
// Graphview cannot be upgraded
|
||||
implementation "com.jjoe64:graphview:4.0.1"
|
||||
implementation "com.joanzapata.iconify:android-iconify-fontawesome:2.1.1"
|
||||
implementation 'com.android.support.constraint:constraint-layout:1.1.3'
|
||||
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
|
||||
implementation(name: "android-edittext-validator-v1.3.4-mod", ext: "aar")
|
||||
implementation 'com.madgag.spongycastle:core:1.58.0.0'
|
||||
|
||||
|
@ -249,7 +264,7 @@ dependencies {
|
|||
// excluding org.json which is provided by Android
|
||||
exclude group: "org.json", module: "json"
|
||||
}
|
||||
implementation "com.google.code.gson:gson:2.8.2"
|
||||
implementation "com.google.code.gson:gson:2.8.5"
|
||||
implementation "com.google.guava:guava:24.1-jre"
|
||||
|
||||
implementation "net.danlew:android.joda:2.9.9.1"
|
||||
|
@ -260,6 +275,8 @@ dependencies {
|
|||
implementation "com.jakewharton:butterknife:${butterknifeVersion}"
|
||||
annotationProcessor "com.jakewharton:butterknife-compiler:${butterknifeVersion}"
|
||||
|
||||
implementation 'com.github.DavidProdinger:weekdays-selector:1.0.4'
|
||||
|
||||
testImplementation "junit:junit:4.12"
|
||||
testImplementation "org.json:json:20140107"
|
||||
testImplementation "org.mockito:mockito-core:2.8.47"
|
||||
|
@ -268,26 +285,48 @@ dependencies {
|
|||
testImplementation "org.powermock:powermock-module-junit4-rule:${powermockVersion}"
|
||||
testImplementation "org.powermock:powermock-module-junit4:${powermockVersion}"
|
||||
testImplementation "joda-time:joda-time:2.9.9"
|
||||
testImplementation "com.google.truth:truth:0.39"
|
||||
testImplementation 'org.robolectric:robolectric:3.8'
|
||||
testImplementation("com.google.truth:truth:0.39") {
|
||||
exclude group: "com.google.guava", module: "guava"
|
||||
}
|
||||
testImplementation("org.robolectric:robolectric:4.2.1") {
|
||||
exclude group: "com.google.guava", module: "guava"
|
||||
}
|
||||
testImplementation "org.skyscreamer:jsonassert:1.5.0"
|
||||
testImplementation "org.hamcrest:hamcrest-all:1.3"
|
||||
testImplementation("uk.org.lidalia:slf4j-test:1.2.0") {
|
||||
exclude group: "com.google.guava", module: "guava"
|
||||
}
|
||||
|
||||
androidTestImplementation "org.mockito:mockito-core:2.8.47"
|
||||
androidTestImplementation "com.google.dexmaker:dexmaker:${dexmakerVersion}"
|
||||
androidTestImplementation "com.google.dexmaker:dexmaker-mockito:${dexmakerVersion}"
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
||||
implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
|
||||
|
||||
|
||||
// new for tidepool
|
||||
implementation 'com.squareup.okhttp3:okhttp:3.10.0'
|
||||
implementation 'com.squareup.okhttp3:logging-interceptor:3.10.0'
|
||||
implementation "com.squareup.retrofit2:retrofit:2.4.0"
|
||||
implementation "com.squareup.retrofit2:adapter-rxjava2:2.4.0"
|
||||
implementation "com.squareup.retrofit2:converter-gson:2.4.0"
|
||||
|
||||
}
|
||||
|
||||
task unzip(type: Copy) {
|
||||
def zipPath = configurations.libs.find { it.name.startsWith("danars") }
|
||||
def zipFile = file(zipPath)
|
||||
def outputDir = file("${buildDir}/unpacked/dist")
|
||||
|
||||
from zipTree(zipFile)
|
||||
task downloadZipFile(type: Download) {
|
||||
src 'https://github.com/MilosKozak/danars-support-lib/archive/master.zip'
|
||||
dest new File(buildDir, 'danars.zip')
|
||||
}
|
||||
|
||||
task downloadAndUnzipFile(dependsOn: downloadZipFile, type: Copy) {
|
||||
from zipTree(downloadZipFile.dest)
|
||||
def outputDir = file("${buildDir}/unpacked/dist")
|
||||
into outputDir
|
||||
}
|
||||
|
||||
task copyLibs(dependsOn: unzip, type: Copy) {
|
||||
|
||||
task copyLibs(dependsOn: downloadAndUnzipFile, type: Copy) {
|
||||
def src = file("${buildDir}/unpacked/dist/danars-support-lib-master")
|
||||
def target = file("src/main/jniLibs/")
|
||||
|
||||
|
|
|
@ -17,10 +17,12 @@
|
|||
<uses-permission android:name="android.permission.VIBRATE" />
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="com.google.android.permission.PROVIDE_BACKGROUND" />
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
|
||||
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
|
||||
<uses-permission android:name="sugar.free.sightremote.HISTORY_BROADCASTS" />
|
||||
<uses-permission android:name="com.dexcom.cgm.EXTERNAL_PERMISSION" />
|
||||
|
||||
<uses-permission-sdk-23 android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
|
||||
|
||||
|
@ -34,13 +36,15 @@
|
|||
android:label="@string/app_name"
|
||||
android:roundIcon="${appIconRound}"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/AppTheme.NoActionBar">
|
||||
android:theme="@style/AppTheme.NoActionBar"
|
||||
android:fullBackupContent="true">
|
||||
<meta-data
|
||||
android:name="com.google.android.gms.car.application"
|
||||
android:resource="@xml/automotive_app_desc" />
|
||||
|
||||
<activity android:name=".MainActivity">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
|
@ -85,10 +89,8 @@
|
|||
<action android:name="com.eveningoutpost.dexdrip.NS_EMULATOR"/>
|
||||
<!-- Receiver from glimp -->
|
||||
<action android:name="it.ct.glicemia.ACTION_GLUCOSE_MEASURED"/>
|
||||
<!-- Receiver from DexcomG5 -->
|
||||
<action android:name="com.dexcom.cgm.DATA"/>
|
||||
<action android:name="com.dexcom.cgm.AndroidAPSEVGCallback.BROADCAST"/>
|
||||
<action android:name="com.dexcom.cgm.g5.AndroidAPSEVGCallback.BROADCAST"/>
|
||||
<!-- Receiver from Dexcom -->
|
||||
<action android:name="com.dexcom.cgm.EXTERNAL_BROADCAST"/>
|
||||
<!-- Receiver from Poctech -->
|
||||
<action android:name="com.china.poctech.data"/>
|
||||
<!-- Receiver from Tomato -->
|
||||
|
@ -147,7 +149,7 @@
|
|||
</receiver>
|
||||
|
||||
<provider
|
||||
android:name="android.support.v4.content.FileProvider"
|
||||
android:name="androidx.core.content.FileProvider"
|
||||
android:authorities="${applicationId}.fileprovider"
|
||||
android:exported="false"
|
||||
android:grantUriPermissions="true">
|
||||
|
@ -160,6 +162,9 @@
|
|||
<service
|
||||
android:name=".services.DataService"
|
||||
android:exported="false" />
|
||||
<service
|
||||
android:name=".services.LocationService"
|
||||
android:exported="false" />
|
||||
<service
|
||||
android:name=".plugins.pump.danaR.services.DanaRExecutionService"
|
||||
android:enabled="true"
|
||||
|
@ -281,6 +286,27 @@
|
|||
android:name=".plugins.pump.insight.activities.InsightPairingInformationActivity"
|
||||
android:label="@string/pairing_information"
|
||||
android:theme="@style/AppTheme" />
|
||||
<activity android:name=".activities.RequestDexcomPermissionActivity" />
|
||||
|
||||
<!-- Medtronic service and activities -->
|
||||
<service
|
||||
android:name=".plugins.pump.medtronic.service.RileyLinkMedtronicService"
|
||||
android:enabled="true"
|
||||
android:exported="true" />
|
||||
<activity android:name=".plugins.pump.common.dialog.RileyLinkBLEScanActivity">
|
||||
<intent-filter>
|
||||
<action android:name="info.nightscout.androidaps.plugins.PumpCommon.dialog.RileyLinkBLEScanActivity" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".plugins.pump.common.hw.rileylink.dialog.RileyLinkStatusActivity"
|
||||
android:label="@string/title_activity_rileylink_settings"
|
||||
android:theme="@style/Theme.AppCompat.NoTitle" />
|
||||
<activity android:name=".plugins.pump.medtronic.dialog.MedtronicHistoryActivity" />
|
||||
|
||||
<uses-library android:name="org.apache.http.legacy" android:required="false"/>
|
||||
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
|
|
|
@ -31,7 +31,7 @@ public class Constants {
|
|||
public static final long remoteBolusMinDistance = 15 * 60 * 1000L;
|
||||
|
||||
// Circadian Percentage Profile
|
||||
public static final int CPP_MIN_PERCENTAGE = 50;
|
||||
public static final int CPP_MIN_PERCENTAGE = 30;
|
||||
public static final int CPP_MAX_PERCENTAGE = 200;
|
||||
public static final int CPP_MIN_TIMESHIFT = -6;
|
||||
public static final int CPP_MAX_TIMESHIFT = 23;
|
||||
|
|
|
@ -7,16 +7,16 @@ import android.graphics.Rect;
|
|||
import android.os.Bundle;
|
||||
import android.os.PersistableBundle;
|
||||
import android.os.PowerManager;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.design.widget.NavigationView;
|
||||
import android.support.design.widget.TabLayout;
|
||||
import android.support.v4.app.ActivityCompat;
|
||||
import android.support.v4.view.ViewPager;
|
||||
import android.support.v4.widget.DrawerLayout;
|
||||
import android.support.v7.app.ActionBarDrawerToggle;
|
||||
import android.support.v7.app.AlertDialog;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.support.v7.widget.Toolbar;
|
||||
import androidx.annotation.Nullable;
|
||||
import com.google.android.material.navigation.NavigationView;
|
||||
import com.google.android.material.tabs.TabLayout;
|
||||
import androidx.core.app.ActivityCompat;
|
||||
import androidx.viewpager.widget.ViewPager;
|
||||
import androidx.drawerlayout.widget.DrawerLayout;
|
||||
import androidx.appcompat.app.ActionBarDrawerToggle;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
import android.text.SpannableString;
|
||||
import android.text.method.LinkMovementMethod;
|
||||
import android.text.util.Linkify;
|
||||
|
|
|
@ -1,12 +1,18 @@
|
|||
package info.nightscout.androidaps;
|
||||
|
||||
import android.app.Application;
|
||||
import android.bluetooth.BluetoothAdapter;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.res.Resources;
|
||||
import android.os.SystemClock;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.annotation.PluralsRes;
|
||||
import android.support.v4.content.LocalBroadcastManager;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.PluralsRes;
|
||||
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
|
||||
|
||||
import com.crashlytics.android.Crashlytics;
|
||||
import com.google.firebase.analytics.FirebaseAnalytics;
|
||||
|
@ -39,6 +45,7 @@ import info.nightscout.androidaps.plugins.constraints.objectives.ObjectivesPlugi
|
|||
import info.nightscout.androidaps.plugins.constraints.safety.SafetyPlugin;
|
||||
import info.nightscout.androidaps.plugins.constraints.storage.StorageConstraintPlugin;
|
||||
import info.nightscout.androidaps.plugins.general.actions.ActionsFragment;
|
||||
import info.nightscout.androidaps.plugins.general.automation.AutomationPlugin;
|
||||
import info.nightscout.androidaps.plugins.general.careportal.CareportalPlugin;
|
||||
import info.nightscout.androidaps.plugins.general.food.FoodPlugin;
|
||||
import info.nightscout.androidaps.plugins.general.maintenance.LoggerUtils;
|
||||
|
@ -51,6 +58,7 @@ import info.nightscout.androidaps.plugins.general.overview.OverviewPlugin;
|
|||
import info.nightscout.androidaps.plugins.general.persistentNotification.PersistentNotificationPlugin;
|
||||
import info.nightscout.androidaps.plugins.general.signatureVerifier.SignatureVerifier;
|
||||
import info.nightscout.androidaps.plugins.general.smsCommunicator.SmsCommunicatorPlugin;
|
||||
import info.nightscout.androidaps.plugins.general.tidepool.TidepoolPlugin;
|
||||
import info.nightscout.androidaps.plugins.general.versionChecker.VersionCheckerPlugin;
|
||||
import info.nightscout.androidaps.plugins.general.wear.WearPlugin;
|
||||
import info.nightscout.androidaps.plugins.general.xdripStatusline.StatuslinePlugin;
|
||||
|
@ -62,19 +70,21 @@ import info.nightscout.androidaps.plugins.profile.local.LocalProfilePlugin;
|
|||
import info.nightscout.androidaps.plugins.profile.ns.NSProfilePlugin;
|
||||
import info.nightscout.androidaps.plugins.profile.simple.SimpleProfilePlugin;
|
||||
import info.nightscout.androidaps.plugins.pump.combo.ComboPlugin;
|
||||
import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.RileyLinkConst;
|
||||
import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.RileyLinkUtil;
|
||||
import info.nightscout.androidaps.plugins.pump.danaR.DanaRPlugin;
|
||||
import info.nightscout.androidaps.plugins.pump.danaRKorean.DanaRKoreanPlugin;
|
||||
import info.nightscout.androidaps.plugins.pump.danaRS.DanaRSPlugin;
|
||||
import info.nightscout.androidaps.plugins.pump.danaRv2.DanaRv2Plugin;
|
||||
import info.nightscout.androidaps.plugins.pump.insight.LocalInsightPlugin;
|
||||
import info.nightscout.androidaps.plugins.pump.mdi.MDIPlugin;
|
||||
import info.nightscout.androidaps.plugins.pump.medtronic.MedtronicPumpPlugin;
|
||||
import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpPlugin;
|
||||
import info.nightscout.androidaps.plugins.sensitivity.SensitivityAAPSPlugin;
|
||||
import info.nightscout.androidaps.plugins.sensitivity.SensitivityOref0Plugin;
|
||||
import info.nightscout.androidaps.plugins.sensitivity.SensitivityOref1Plugin;
|
||||
import info.nightscout.androidaps.plugins.sensitivity.SensitivityWeightedAveragePlugin;
|
||||
import info.nightscout.androidaps.plugins.source.SourceDexcomG5Plugin;
|
||||
import info.nightscout.androidaps.plugins.source.SourceDexcomG6Plugin;
|
||||
import info.nightscout.androidaps.plugins.source.SourceDexcomPlugin;
|
||||
import info.nightscout.androidaps.plugins.source.SourceEversensePlugin;
|
||||
import info.nightscout.androidaps.plugins.source.SourceGlimpPlugin;
|
||||
import info.nightscout.androidaps.plugins.source.SourceMM640gPlugin;
|
||||
|
@ -86,6 +96,7 @@ import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin;
|
|||
import info.nightscout.androidaps.receivers.DataReceiver;
|
||||
import info.nightscout.androidaps.receivers.KeepAliveReceiver;
|
||||
import info.nightscout.androidaps.receivers.NSAlarmReceiver;
|
||||
import info.nightscout.androidaps.receivers.TimeDateOrTZChangeReceiver;
|
||||
import info.nightscout.androidaps.services.Intents;
|
||||
import info.nightscout.androidaps.utils.FabricPrivacy;
|
||||
import io.fabric.sdk.android.Fabric;
|
||||
|
@ -113,6 +124,8 @@ public class MainApp extends Application {
|
|||
private static AckAlarmReceiver ackAlarmReciever = new AckAlarmReceiver();
|
||||
private static DBAccessReceiver dbAccessReciever = new DBAccessReceiver();
|
||||
private LocalBroadcastManager lbm;
|
||||
BroadcastReceiver btReceiver;
|
||||
TimeDateOrTZChangeReceiver timeDateOrTZChangeReceiver;
|
||||
|
||||
public static boolean devBranch;
|
||||
public static boolean engineeringMode;
|
||||
|
@ -146,7 +159,7 @@ public class MainApp extends Application {
|
|||
File engineeringModeSemaphore = new File(extFilesDir, "engineering_mode");
|
||||
|
||||
engineeringMode = engineeringModeSemaphore.exists() && engineeringModeSemaphore.isFile();
|
||||
devBranch = BuildConfig.VERSION.contains("dev");
|
||||
devBranch = BuildConfig.VERSION.contains("-") || BuildConfig.VERSION.matches(".*[a-zA-Z]+.*");
|
||||
|
||||
sBus = L.isEnabled(L.EVENTS) && devBranch ? new LoggingBus(ThreadEnforcer.ANY) : new Bus(ThreadEnforcer.ANY);
|
||||
|
||||
|
@ -154,6 +167,7 @@ public class MainApp extends Application {
|
|||
|
||||
//trigger here to see the new version on app start after an update
|
||||
triggerCheckVersion();
|
||||
//setBTReceiver();
|
||||
|
||||
if (pluginsList == null) {
|
||||
pluginsList = new ArrayList<>();
|
||||
|
@ -175,6 +189,7 @@ public class MainApp extends Application {
|
|||
if (Config.PUMPDRIVERS) pluginsList.add(LocalInsightPlugin.getPlugin());
|
||||
pluginsList.add(CareportalPlugin.getPlugin());
|
||||
if (Config.PUMPDRIVERS) pluginsList.add(ComboPlugin.getPlugin());
|
||||
if (Config.PUMPDRIVERS && engineeringMode) pluginsList.add(MedtronicPumpPlugin.getPlugin());
|
||||
if (Config.MDI) pluginsList.add(MDIPlugin.getPlugin());
|
||||
pluginsList.add(VirtualPumpPlugin.getPlugin());
|
||||
if (Config.APS) pluginsList.add(LoopPlugin.getPlugin());
|
||||
|
@ -194,8 +209,7 @@ public class MainApp extends Application {
|
|||
pluginsList.add(SourceNSClientPlugin.getPlugin());
|
||||
pluginsList.add(SourceMM640gPlugin.getPlugin());
|
||||
pluginsList.add(SourceGlimpPlugin.getPlugin());
|
||||
pluginsList.add(SourceDexcomG5Plugin.getPlugin());
|
||||
pluginsList.add(SourceDexcomG6Plugin.getPlugin());
|
||||
pluginsList.add(SourceDexcomPlugin.INSTANCE);
|
||||
pluginsList.add(SourcePoctechPlugin.getPlugin());
|
||||
pluginsList.add(SourceTomatoPlugin.getPlugin());
|
||||
pluginsList.add(SourceEversensePlugin.getPlugin());
|
||||
|
@ -206,7 +220,11 @@ public class MainApp extends Application {
|
|||
pluginsList.add(StatuslinePlugin.initPlugin(this));
|
||||
pluginsList.add(PersistentNotificationPlugin.getPlugin());
|
||||
pluginsList.add(NSClientPlugin.getPlugin());
|
||||
if (engineeringMode)
|
||||
pluginsList.add(TidepoolPlugin.INSTANCE);
|
||||
pluginsList.add(MaintenancePlugin.initPlugin(this));
|
||||
if (engineeringMode)
|
||||
pluginsList.add(AutomationPlugin.INSTANCE);
|
||||
|
||||
pluginsList.add(ConfigBuilderPlugin.getPlugin());
|
||||
|
||||
|
@ -254,6 +272,10 @@ public class MainApp extends Application {
|
|||
|
||||
//register dbaccess
|
||||
lbm.registerReceiver(dbAccessReciever, new IntentFilter(Intents.ACTION_DATABASE));
|
||||
|
||||
this.timeDateOrTZChangeReceiver = new TimeDateOrTZChangeReceiver();
|
||||
this.timeDateOrTZChangeReceiver.registerBroadcasts(this);
|
||||
|
||||
}
|
||||
|
||||
private void startKeepAliveService() {
|
||||
|
@ -439,5 +461,19 @@ public class MainApp extends Application {
|
|||
sDatabaseHelper.close();
|
||||
sDatabaseHelper = null;
|
||||
}
|
||||
|
||||
if (btReceiver != null) {
|
||||
unregisterReceiver(btReceiver);
|
||||
}
|
||||
|
||||
if (timeDateOrTZChangeReceiver!=null) {
|
||||
unregisterReceiver(timeDateOrTZChangeReceiver);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static int dpToPx(int dp) {
|
||||
float scale = sResources.getDisplayMetrics().density;
|
||||
return (int) (dp * scale + 0.5f);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,9 +2,9 @@ package info.nightscout.androidaps.activities;
|
|||
|
||||
import android.os.Bundle;
|
||||
import android.os.SystemClock;
|
||||
import android.support.v4.content.res.ResourcesCompat;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.support.v7.widget.PopupMenu;
|
||||
import androidx.core.content.res.ResourcesCompat;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.appcompat.widget.PopupMenu;
|
||||
import android.text.SpannableString;
|
||||
import android.text.style.ForegroundColorSpan;
|
||||
import android.view.Menu;
|
||||
|
@ -52,7 +52,7 @@ public class HistoryBrowseActivity extends AppCompatActivity {
|
|||
ImageButton chartButton;
|
||||
|
||||
boolean showBasal = true;
|
||||
boolean showIob, showCob, showDev, showRat, showDevslope;
|
||||
boolean showIob, showCob, showDev, showRat, showActPrim, showActSec, showDevslope;
|
||||
|
||||
|
||||
@BindView(R.id.historybrowse_date)
|
||||
|
@ -285,6 +285,10 @@ public class HistoryBrowseActivity extends AppCompatActivity {
|
|||
// set manual x bounds to have nice steps
|
||||
graphData.formatAxis(fromTime, toTime);
|
||||
|
||||
if(showActPrim) {
|
||||
graphData.addActivity(fromTime, toTime, false,1d);
|
||||
}
|
||||
|
||||
// Treatments
|
||||
graphData.addTreatments(fromTime, toTime);
|
||||
|
||||
|
@ -305,6 +309,7 @@ public class HistoryBrowseActivity extends AppCompatActivity {
|
|||
boolean useCobForScale = false;
|
||||
boolean useDevForScale = false;
|
||||
boolean useRatioForScale = false;
|
||||
boolean useIAForScale = false;
|
||||
boolean useDSForScale = false;
|
||||
|
||||
if (showIob) {
|
||||
|
@ -315,6 +320,8 @@ public class HistoryBrowseActivity extends AppCompatActivity {
|
|||
useDevForScale = true;
|
||||
} else if (showRat) {
|
||||
useRatioForScale = true;
|
||||
} else if (showActSec) {
|
||||
useIAForScale = true;
|
||||
} else if (showDevslope) {
|
||||
useDSForScale = true;
|
||||
}
|
||||
|
@ -327,6 +334,8 @@ public class HistoryBrowseActivity extends AppCompatActivity {
|
|||
secondGraphData.addDeviations(fromTime, toTime, useDevForScale, 1d);
|
||||
if (showRat)
|
||||
secondGraphData.addRatio(fromTime, toTime, useRatioForScale, 1d);
|
||||
if (showActSec)
|
||||
secondGraphData.addActivity(fromTime, toTime, useIAForScale, useIAForScale? 2d: 1d);
|
||||
if (showDevslope)
|
||||
secondGraphData.addDeviationSlope(fromTime, toTime, useDSForScale, 1d);
|
||||
|
||||
|
@ -337,14 +346,14 @@ public class HistoryBrowseActivity extends AppCompatActivity {
|
|||
|
||||
// do GUI update
|
||||
runOnUiThread(() -> {
|
||||
if (showIob || showCob || showDev || showRat || showDevslope) {
|
||||
if (showIob || showCob || showDev || showRat || showActSec || showDevslope) {
|
||||
iobGraph.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
iobGraph.setVisibility(View.GONE);
|
||||
}
|
||||
// finally enforce drawing of graphs
|
||||
graphData.performUpdate();
|
||||
if (showIob || showCob || showDev || showRat || showDevslope)
|
||||
if (showIob || showCob || showDev || showRat || showActSec || showDevslope)
|
||||
secondGraphData.performUpdate();
|
||||
});
|
||||
}).start();
|
||||
|
@ -353,22 +362,37 @@ public class HistoryBrowseActivity extends AppCompatActivity {
|
|||
private void setupChartMenu() {
|
||||
chartButton = (ImageButton) findViewById(R.id.overview_chartMenuButton);
|
||||
chartButton.setOnClickListener(v -> {
|
||||
MenuItem item;
|
||||
MenuItem item,dividerItem;
|
||||
CharSequence title;
|
||||
int titleMaxChars = 0;
|
||||
SpannableString s;
|
||||
PopupMenu popup = new PopupMenu(v.getContext(), v);
|
||||
|
||||
|
||||
item = popup.getMenu().add(Menu.NONE, OverviewFragment.CHARTTYPE.BAS.ordinal(), Menu.NONE, MainApp.gs(R.string.overview_show_basals));
|
||||
title = item.getTitle();
|
||||
if (titleMaxChars < title.length()) titleMaxChars = title.length();
|
||||
s = new SpannableString(title);
|
||||
s.setSpan(new ForegroundColorSpan(ResourcesCompat.getColor(getResources(), R.color.basal, null)), 0, s.length(), 0);
|
||||
item.setTitle(s);
|
||||
item.setCheckable(true);
|
||||
item.setChecked(showBasal);
|
||||
|
||||
item = popup.getMenu().add(Menu.NONE, OverviewFragment.CHARTTYPE.ACTPRIM.ordinal(), Menu.NONE, MainApp.gs(R.string.overview_show_activity));
|
||||
title = item.getTitle();
|
||||
if (titleMaxChars < title.length()) titleMaxChars = title.length();
|
||||
s = new SpannableString(title);
|
||||
s.setSpan(new ForegroundColorSpan(ResourcesCompat.getColor(getResources(), R.color.activity, null)), 0, s.length(), 0);
|
||||
item.setTitle(s);
|
||||
item.setCheckable(true);
|
||||
item.setChecked(showActPrim);
|
||||
|
||||
dividerItem = popup.getMenu().add("");
|
||||
dividerItem.setEnabled(false);
|
||||
|
||||
item = popup.getMenu().add(Menu.NONE, OverviewFragment.CHARTTYPE.IOB.ordinal(), Menu.NONE, MainApp.gs(R.string.overview_show_iob));
|
||||
title = item.getTitle();
|
||||
if (titleMaxChars < title.length()) titleMaxChars = title.length();
|
||||
s = new SpannableString(title);
|
||||
s.setSpan(new ForegroundColorSpan(ResourcesCompat.getColor(getResources(), R.color.iob, null)), 0, s.length(), 0);
|
||||
item.setTitle(s);
|
||||
|
@ -377,6 +401,7 @@ public class HistoryBrowseActivity extends AppCompatActivity {
|
|||
|
||||
item = popup.getMenu().add(Menu.NONE, OverviewFragment.CHARTTYPE.COB.ordinal(), Menu.NONE, MainApp.gs(R.string.overview_show_cob));
|
||||
title = item.getTitle();
|
||||
if (titleMaxChars < title.length()) titleMaxChars = title.length();
|
||||
s = new SpannableString(title);
|
||||
s.setSpan(new ForegroundColorSpan(ResourcesCompat.getColor(getResources(), R.color.cob, null)), 0, s.length(), 0);
|
||||
item.setTitle(s);
|
||||
|
@ -385,6 +410,7 @@ public class HistoryBrowseActivity extends AppCompatActivity {
|
|||
|
||||
item = popup.getMenu().add(Menu.NONE, OverviewFragment.CHARTTYPE.DEV.ordinal(), Menu.NONE, MainApp.gs(R.string.overview_show_deviations));
|
||||
title = item.getTitle();
|
||||
if (titleMaxChars < title.length()) titleMaxChars = title.length();
|
||||
s = new SpannableString(title);
|
||||
s.setSpan(new ForegroundColorSpan(ResourcesCompat.getColor(getResources(), R.color.deviations, null)), 0, s.length(), 0);
|
||||
item.setTitle(s);
|
||||
|
@ -393,15 +419,27 @@ public class HistoryBrowseActivity extends AppCompatActivity {
|
|||
|
||||
item = popup.getMenu().add(Menu.NONE, OverviewFragment.CHARTTYPE.SEN.ordinal(), Menu.NONE, MainApp.gs(R.string.overview_show_sensitivity));
|
||||
title = item.getTitle();
|
||||
if (titleMaxChars < title.length()) titleMaxChars = title.length();
|
||||
s = new SpannableString(title);
|
||||
s.setSpan(new ForegroundColorSpan(ResourcesCompat.getColor(getResources(), R.color.ratio, null)), 0, s.length(), 0);
|
||||
item.setTitle(s);
|
||||
item.setCheckable(true);
|
||||
item.setChecked(showRat);
|
||||
|
||||
item = popup.getMenu().add(Menu.NONE, OverviewFragment.CHARTTYPE.ACTSEC.ordinal(), Menu.NONE, MainApp.gs(R.string.overview_show_activity));
|
||||
title = item.getTitle();
|
||||
if (titleMaxChars < title.length()) titleMaxChars = title.length();
|
||||
s = new SpannableString(title);
|
||||
s.setSpan(new ForegroundColorSpan(ResourcesCompat.getColor(getResources(), R.color.activity, null)), 0, s.length(), 0);
|
||||
item.setTitle(s);
|
||||
item.setCheckable(true);
|
||||
item.setChecked(showActSec);
|
||||
|
||||
|
||||
if (MainApp.devBranch) {
|
||||
item = popup.getMenu().add(Menu.NONE, OverviewFragment.CHARTTYPE.DEVSLOPE.ordinal(), Menu.NONE, "Deviation slope");
|
||||
title = item.getTitle();
|
||||
if (titleMaxChars < title.length()) titleMaxChars = title.length();
|
||||
s = new SpannableString(title);
|
||||
s.setSpan(new ForegroundColorSpan(ResourcesCompat.getColor(getResources(), R.color.devslopepos, null)), 0, s.length(), 0);
|
||||
item.setTitle(s);
|
||||
|
@ -409,6 +447,10 @@ public class HistoryBrowseActivity extends AppCompatActivity {
|
|||
item.setChecked(showDevslope);
|
||||
}
|
||||
|
||||
// Fairly good guestimate for required divider text size...
|
||||
title = new String(new char[titleMaxChars+10]).replace("\0", "_");
|
||||
dividerItem.setTitle(title);
|
||||
|
||||
popup.setOnMenuItemClickListener(item1 -> {
|
||||
if (item1.getItemId() == OverviewFragment.CHARTTYPE.BAS.ordinal()) {
|
||||
showBasal = !item1.isChecked();
|
||||
|
@ -420,6 +462,10 @@ public class HistoryBrowseActivity extends AppCompatActivity {
|
|||
showDev = !item1.isChecked();
|
||||
} else if (item1.getItemId() == OverviewFragment.CHARTTYPE.SEN.ordinal()) {
|
||||
showRat = !item1.isChecked();
|
||||
} else if (item1.getItemId() == OverviewFragment.CHARTTYPE.ACTPRIM.ordinal()) {
|
||||
showActPrim = !item1.isChecked();
|
||||
} else if (item1.getItemId() == OverviewFragment.CHARTTYPE.ACTSEC.ordinal()) {
|
||||
showActSec = !item1.isChecked();
|
||||
} else if (item1.getItemId() == OverviewFragment.CHARTTYPE.DEVSLOPE.ordinal()) {
|
||||
showDevslope = !item1.isChecked();
|
||||
}
|
||||
|
|
|
@ -15,12 +15,15 @@ import android.text.TextUtils;
|
|||
import info.nightscout.androidaps.Config;
|
||||
import info.nightscout.androidaps.MainApp;
|
||||
import info.nightscout.androidaps.R;
|
||||
import info.nightscout.androidaps.plugins.bus.RxBus;
|
||||
import info.nightscout.androidaps.events.EventPreferenceChange;
|
||||
import info.nightscout.androidaps.events.EventRefreshGui;
|
||||
import info.nightscout.androidaps.interfaces.PluginBase;
|
||||
import info.nightscout.androidaps.interfaces.PluginType;
|
||||
import info.nightscout.androidaps.plugins.general.careportal.CareportalPlugin;
|
||||
import info.nightscout.androidaps.plugins.constraints.safety.SafetyPlugin;
|
||||
import info.nightscout.androidaps.plugins.general.tidepool.TidepoolPlugin;
|
||||
import info.nightscout.androidaps.plugins.general.tidepool.comm.TidepoolUploader;
|
||||
import info.nightscout.androidaps.plugins.insulin.InsulinOrefFreePeakPlugin;
|
||||
import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin;
|
||||
import info.nightscout.androidaps.plugins.general.nsclient.NSClientPlugin;
|
||||
|
@ -33,18 +36,20 @@ import info.nightscout.androidaps.plugins.pump.danaRKorean.DanaRKoreanPlugin;
|
|||
import info.nightscout.androidaps.plugins.pump.danaRS.DanaRSPlugin;
|
||||
import info.nightscout.androidaps.plugins.pump.danaRv2.DanaRv2Plugin;
|
||||
import info.nightscout.androidaps.plugins.pump.insight.LocalInsightPlugin;
|
||||
import info.nightscout.androidaps.plugins.pump.medtronic.MedtronicPumpPlugin;
|
||||
import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpPlugin;
|
||||
import info.nightscout.androidaps.plugins.sensitivity.SensitivityAAPSPlugin;
|
||||
import info.nightscout.androidaps.plugins.sensitivity.SensitivityOref0Plugin;
|
||||
import info.nightscout.androidaps.plugins.sensitivity.SensitivityOref1Plugin;
|
||||
import info.nightscout.androidaps.plugins.sensitivity.SensitivityWeightedAveragePlugin;
|
||||
import info.nightscout.androidaps.plugins.general.smsCommunicator.SmsCommunicatorPlugin;
|
||||
import info.nightscout.androidaps.plugins.source.SourceDexcomG5Plugin;
|
||||
import info.nightscout.androidaps.plugins.general.wear.WearPlugin;
|
||||
import info.nightscout.androidaps.plugins.general.xdripStatusline.StatuslinePlugin;
|
||||
import info.nightscout.androidaps.plugins.source.SourceDexcomPlugin;
|
||||
import info.nightscout.androidaps.utils.LocaleHelper;
|
||||
import info.nightscout.androidaps.utils.OKDialog;
|
||||
import info.nightscout.androidaps.utils.SP;
|
||||
import info.nightscout.androidaps.plugins.general.automation.AutomationPlugin;
|
||||
|
||||
public class PreferencesActivity extends PreferenceActivity implements SharedPreferences.OnSharedPreferenceChangeListener {
|
||||
MyPreferenceFragment myPreferenceFragment;
|
||||
|
@ -63,6 +68,7 @@ public class PreferencesActivity extends PreferenceActivity implements SharedPre
|
|||
@Override
|
||||
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
|
||||
MainApp.bus().post(new EventPreferenceChange(key));
|
||||
RxBus.INSTANCE.send(new EventPreferenceChange(key));
|
||||
if (key.equals("language")) {
|
||||
String lang = sharedPreferences.getString("language", "en");
|
||||
LocaleHelper.setLocale(getApplicationContext(), lang);
|
||||
|
@ -93,7 +99,7 @@ public class PreferencesActivity extends PreferenceActivity implements SharedPre
|
|||
} else if (editTextPref.getText() != null) {
|
||||
((EditTextPreference) pref).setDialogMessage(editTextPref.getDialogMessage());
|
||||
pref.setSummary(editTextPref.getText());
|
||||
} else if (pref.getKey().contains("smscommunicator_allowednumbers") && TextUtils.isEmpty(editTextPref.getText().trim())) {
|
||||
} else if (pref.getKey().contains("smscommunicator_allowednumbers") && (editTextPref.getText() == null || TextUtils.isEmpty(editTextPref.getText().trim()))) {
|
||||
pref.setSummary(MainApp.gs(R.string.smscommunicator_allowednumbers_summary));
|
||||
}
|
||||
}
|
||||
|
@ -144,7 +150,7 @@ public class PreferencesActivity extends PreferenceActivity implements SharedPre
|
|||
|
||||
addPreferencesFromResource(R.xml.pref_overview);
|
||||
|
||||
addPreferencesFromResourceIfEnabled(SourceDexcomG5Plugin.getPlugin(), PluginType.BGSOURCE);
|
||||
addPreferencesFromResourceIfEnabled(SourceDexcomPlugin.INSTANCE, PluginType.BGSOURCE);
|
||||
addPreferencesFromResourceIfEnabled(CareportalPlugin.getPlugin(), PluginType.GENERAL);
|
||||
addPreferencesFromResourceIfEnabled(SafetyPlugin.getPlugin(), PluginType.CONSTRAINTS);
|
||||
if (Config.APS) {
|
||||
|
@ -166,6 +172,7 @@ public class PreferencesActivity extends PreferenceActivity implements SharedPre
|
|||
addPreferencesFromResourceIfEnabled(DanaRSPlugin.getPlugin(), PluginType.PUMP);
|
||||
addPreferencesFromResourceIfEnabled(LocalInsightPlugin.getPlugin(), PluginType.PUMP);
|
||||
addPreferencesFromResourceIfEnabled(ComboPlugin.getPlugin(), PluginType.PUMP);
|
||||
addPreferencesFromResourceIfEnabled(MedtronicPumpPlugin.getPlugin(), PluginType.PUMP);
|
||||
|
||||
if (DanaRPlugin.getPlugin().isEnabled(PluginType.PROFILE)
|
||||
|| DanaRKoreanPlugin.getPlugin().isEnabled(PluginType.PROFILE)
|
||||
|
@ -182,7 +189,9 @@ public class PreferencesActivity extends PreferenceActivity implements SharedPre
|
|||
addPreferencesFromResourceIfEnabled(InsulinOrefFreePeakPlugin.getPlugin(), PluginType.INSULIN);
|
||||
|
||||
addPreferencesFromResourceIfEnabled(NSClientPlugin.getPlugin(), PluginType.GENERAL);
|
||||
addPreferencesFromResourceIfEnabled(TidepoolPlugin.INSTANCE, PluginType.GENERAL);
|
||||
addPreferencesFromResourceIfEnabled(SmsCommunicatorPlugin.getPlugin(), PluginType.GENERAL);
|
||||
addPreferencesFromResourceIfEnabled(AutomationPlugin.INSTANCE, PluginType.GENERAL);
|
||||
|
||||
addPreferencesFromResource(R.xml.pref_others);
|
||||
addPreferencesFromResource(R.xml.pref_datachoices);
|
||||
|
@ -192,7 +201,7 @@ public class PreferencesActivity extends PreferenceActivity implements SharedPre
|
|||
}
|
||||
|
||||
if (Config.NSCLIENT) {
|
||||
PreferenceScreen scrnAdvancedSettings = (PreferenceScreen)findPreference(getString(R.string.key_advancedsettings));
|
||||
PreferenceScreen scrnAdvancedSettings = (PreferenceScreen) findPreference(getString(R.string.key_advancedsettings));
|
||||
if (scrnAdvancedSettings != null) {
|
||||
scrnAdvancedSettings.removePreference(getPreference(getString(R.string.key_statuslights_res_warning)));
|
||||
scrnAdvancedSettings.removePreference(getPreference(getString(R.string.key_statuslights_res_critical)));
|
||||
|
@ -203,6 +212,13 @@ public class PreferencesActivity extends PreferenceActivity implements SharedPre
|
|||
}
|
||||
|
||||
initSummary(getPreferenceScreen());
|
||||
|
||||
final Preference tidepoolTestLogin = findPreference(MainApp.gs(R.string.key_tidepool_test_login));
|
||||
if (tidepoolTestLogin != null)
|
||||
tidepoolTestLogin.setOnPreferenceClickListener(preference -> {
|
||||
TidepoolUploader.INSTANCE.testLogin(getActivity());
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
package info.nightscout.androidaps.activities
|
||||
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import info.nightscout.androidaps.plugins.source.SourceDexcomPlugin
|
||||
|
||||
class RequestDexcomPermissionActivity : AppCompatActivity() {
|
||||
|
||||
private val requestCode = "AndroidAPS <3".map { it.toInt() }.sum()
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
requestPermissions(arrayOf(SourceDexcomPlugin.PERMISSION), requestCode)
|
||||
} else {
|
||||
finish()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
|
||||
finish()
|
||||
}
|
||||
|
||||
}
|
|
@ -2,9 +2,9 @@ package info.nightscout.androidaps.activities;
|
|||
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@ import android.app.Activity;
|
|||
import android.graphics.Color;
|
||||
import android.graphics.Rect;
|
||||
import android.os.Bundle;
|
||||
import android.support.v7.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import android.text.TextUtils;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.MotionEvent;
|
||||
|
|
|
@ -1,11 +1,9 @@
|
|||
package info.nightscout.androidaps.data;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
import info.nightscout.androidaps.Constants;
|
||||
import info.nightscout.androidaps.MainApp;
|
||||
import info.nightscout.androidaps.interfaces.Constraint;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package info.nightscout.androidaps.data;
|
||||
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.util.LongSparseArray;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.collection.LongSparseArray;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
|
|
@ -1,10 +1,8 @@
|
|||
package info.nightscout.androidaps.data;
|
||||
|
||||
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.util.LongSparseArray;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import info.nightscout.androidaps.db.TemporaryBasal;
|
||||
import info.nightscout.androidaps.interfaces.Interval;
|
||||
|
||||
/**
|
||||
|
@ -21,7 +19,7 @@ public class NonOverlappingIntervals<T extends Interval> extends Intervals<T> {
|
|||
rawData = other.rawData.clone();
|
||||
}
|
||||
|
||||
protected synchronized void merge() {
|
||||
public synchronized void merge() {
|
||||
for (int index = 0; index < rawData.size() - 1; index++) {
|
||||
Interval i = rawData.valueAt(index);
|
||||
long startOfNewer = rawData.valueAt(index + 1).start();
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package info.nightscout.androidaps.data;
|
||||
|
||||
|
||||
import android.support.annotation.Nullable;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import info.nightscout.androidaps.interfaces.Interval;
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package info.nightscout.androidaps.data;
|
||||
|
||||
import android.support.v4.util.LongSparseArray;
|
||||
import androidx.collection.LongSparseArray;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
|
@ -400,6 +400,19 @@ public class Profile {
|
|||
return getValuesList(isf_v, null, new DecimalFormat("0.0"), getUnits() + MainApp.gs(R.string.profile_per_unit));
|
||||
}
|
||||
|
||||
public ProfileValue[] getIsfs() {
|
||||
if (isf_v == null)
|
||||
isf_v = convertToSparseArray(ic);
|
||||
ProfileValue[] ret = new ProfileValue[isf_v.size()];
|
||||
|
||||
for (Integer index = 0; index < isf_v.size(); index++) {
|
||||
Integer tas = (int) isf_v.keyAt(index);
|
||||
double value = isf_v.valueAt(index);
|
||||
ret[index] = new ProfileValue(tas, value);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public double getIc() {
|
||||
return getIcTimeFromMidnight(secondsFromMidnight());
|
||||
}
|
||||
|
@ -420,6 +433,19 @@ public class Profile {
|
|||
return getValuesList(ic_v, null, new DecimalFormat("0.0"), MainApp.gs(R.string.profile_carbs_per_unit));
|
||||
}
|
||||
|
||||
public ProfileValue[] getIcs() {
|
||||
if (ic_v == null)
|
||||
ic_v = convertToSparseArray(ic);
|
||||
ProfileValue[] ret = new ProfileValue[ic_v.size()];
|
||||
|
||||
for (Integer index = 0; index < ic_v.size(); index++) {
|
||||
Integer tas = (int) ic_v.keyAt(index);
|
||||
double value = ic_v.valueAt(index);
|
||||
ret[index] = new ProfileValue(tas, value);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public double getBasal() {
|
||||
return getBasalTimeFromMidnight(secondsFromMidnight());
|
||||
}
|
||||
|
@ -441,8 +467,8 @@ public class Profile {
|
|||
return getValuesList(basal_v, null, new DecimalFormat("0.00"), MainApp.gs(R.string.profile_ins_units_per_hout));
|
||||
}
|
||||
|
||||
public class BasalValue {
|
||||
public BasalValue(int timeAsSeconds, double value) {
|
||||
public class ProfileValue {
|
||||
public ProfileValue(int timeAsSeconds, double value) {
|
||||
this.timeAsSeconds = timeAsSeconds;
|
||||
this.value = value;
|
||||
}
|
||||
|
@ -451,15 +477,15 @@ public class Profile {
|
|||
public double value;
|
||||
}
|
||||
|
||||
public synchronized BasalValue[] getBasalValues() {
|
||||
public synchronized ProfileValue[] getBasalValues() {
|
||||
if (basal_v == null)
|
||||
basal_v = convertToSparseArray(basal);
|
||||
BasalValue[] ret = new BasalValue[basal_v.size()];
|
||||
ProfileValue[] ret = new ProfileValue[basal_v.size()];
|
||||
|
||||
for (Integer index = 0; index < basal_v.size(); index++) {
|
||||
Integer tas = (int) basal_v.keyAt(index);
|
||||
double value = basal_v.valueAt(index);
|
||||
ret[index] = new BasalValue(tas, value);
|
||||
ret[index] = new ProfileValue(tas, value);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
@ -500,6 +526,49 @@ public class Profile {
|
|||
return getValueToTime(targetHigh_v, timeAsSeconds);
|
||||
}
|
||||
|
||||
public class TargetValue {
|
||||
public TargetValue(int timeAsSeconds, double low, double high) {
|
||||
this.timeAsSeconds = timeAsSeconds;
|
||||
this.low = low;
|
||||
this.high = high;
|
||||
}
|
||||
|
||||
public int timeAsSeconds;
|
||||
public double low;
|
||||
public double high;
|
||||
}
|
||||
|
||||
public TargetValue[] getTargets() {
|
||||
if (targetLow_v == null)
|
||||
targetLow_v = convertToSparseArray(targetLow);
|
||||
if (targetHigh_v == null)
|
||||
targetHigh_v = convertToSparseArray(targetHigh);
|
||||
TargetValue[] ret = new TargetValue[targetLow_v.size()];
|
||||
|
||||
for (Integer index = 0; index < targetLow_v.size(); index++) {
|
||||
Integer tas = (int) targetLow_v.keyAt(index);
|
||||
double low = targetLow_v.valueAt(index);
|
||||
double high = targetHigh_v.valueAt(index);
|
||||
ret[index] = new TargetValue(tas, low, high);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public ProfileValue[] getSingleTargets() {
|
||||
if (targetLow_v == null)
|
||||
targetLow_v = convertToSparseArray(targetLow);
|
||||
if (targetHigh_v == null)
|
||||
targetHigh_v = convertToSparseArray(targetHigh);
|
||||
ProfileValue[] ret = new ProfileValue[targetLow_v.size()];
|
||||
|
||||
for (Integer index = 0; index < targetLow_v.size(); index++) {
|
||||
Integer tas = (int) targetLow_v.keyAt(index);
|
||||
double target = (targetLow_v.valueAt(index) + targetHigh_v.valueAt(index)) / 2;
|
||||
ret[index] = new ProfileValue(tas, target);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public String getTargetList() {
|
||||
if (targetLow_v == null)
|
||||
targetLow_v = convertToSparseArray(targetLow);
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package info.nightscout.androidaps.data;
|
||||
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.util.LongSparseArray;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.collection.LongSparseArray;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package info.nightscout.androidaps.data;
|
||||
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.util.ArrayMap;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.collection.ArrayMap;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
|
|
@ -45,6 +45,11 @@ public class PumpEnactResult {
|
|||
return this;
|
||||
}
|
||||
|
||||
public PumpEnactResult comment(int comment) {
|
||||
this.comment = MainApp.gs(comment);
|
||||
return this;
|
||||
}
|
||||
|
||||
public PumpEnactResult duration(int duration) {
|
||||
this.duration = duration;
|
||||
return this;
|
||||
|
|
|
@ -50,7 +50,7 @@ public class QuickWizardEntry {
|
|||
useTemptarget: 0
|
||||
}
|
||||
*/
|
||||
public QuickWizardEntry() {
|
||||
QuickWizardEntry() {
|
||||
String emptyData = "{\"buttonText\":\"\",\"carbs\":0,\"validFrom\":0,\"validTo\":86340}";
|
||||
try {
|
||||
storage = new JSONObject(emptyData);
|
||||
|
@ -60,18 +60,17 @@ public class QuickWizardEntry {
|
|||
position = -1;
|
||||
}
|
||||
|
||||
public QuickWizardEntry(JSONObject entry, int position) {
|
||||
QuickWizardEntry(JSONObject entry, int position) {
|
||||
storage = entry;
|
||||
this.position = position;
|
||||
}
|
||||
|
||||
public Boolean isActive() {
|
||||
Boolean isActive() {
|
||||
return Profile.secondsFromMidnight() >= validFrom() && Profile.secondsFromMidnight() <= validTo();
|
||||
}
|
||||
|
||||
public BolusWizard doCalc(Profile profile, TempTarget tempTarget, BgReading lastBG, boolean _synchronized) {
|
||||
BolusWizard wizard = new BolusWizard();
|
||||
|
||||
public BolusWizard doCalc(Profile profile, String profileName, BgReading lastBG, boolean _synchronized) {
|
||||
final TempTarget tempTarget = TreatmentsPlugin.getPlugin().getTempTargetFromHistory();
|
||||
//BG
|
||||
double bg = 0;
|
||||
if (lastBG != null && useBG() == YES) {
|
||||
|
@ -86,11 +85,6 @@ public class QuickWizardEntry {
|
|||
cob = cobInfo.displayCob;
|
||||
}
|
||||
|
||||
// Temp target
|
||||
if (useTempTarget() == NO) {
|
||||
tempTarget = null;
|
||||
}
|
||||
|
||||
// Bolus IOB
|
||||
boolean bolusIOB = false;
|
||||
if (useBolusIOB() == YES) {
|
||||
|
@ -130,8 +124,7 @@ public class QuickWizardEntry {
|
|||
trend = true;
|
||||
}
|
||||
|
||||
wizard.doCalc(profile, tempTarget, carbs(), cob, bg, 0d, bolusIOB, basalIOB, superBolus, trend);
|
||||
return wizard;
|
||||
return new BolusWizard(profile, profileName, tempTarget, carbs(), cob, bg, 0d, 100, true, useCOB() == YES, bolusIOB, basalIOB, superBolus, useTempTarget() == YES, trend, "QuickWizard");
|
||||
}
|
||||
|
||||
public String buttonText() {
|
||||
|
|
|
@ -3,7 +3,7 @@ package info.nightscout.androidaps.db;
|
|||
import android.content.Context;
|
||||
import android.database.DatabaseUtils;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.support.annotation.Nullable;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.j256.ormlite.android.apptools.OrmLiteSqliteOpenHelper;
|
||||
import com.j256.ormlite.dao.CloseableIterator;
|
||||
|
@ -21,6 +21,8 @@ import org.slf4j.LoggerFactory;
|
|||
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
|
@ -29,6 +31,7 @@ import java.util.concurrent.TimeUnit;
|
|||
|
||||
import info.nightscout.androidaps.Constants;
|
||||
import info.nightscout.androidaps.MainApp;
|
||||
import info.nightscout.androidaps.plugins.bus.RxBus;
|
||||
import info.nightscout.androidaps.data.OverlappingIntervals;
|
||||
import info.nightscout.androidaps.data.Profile;
|
||||
import info.nightscout.androidaps.data.ProfileStore;
|
||||
|
@ -410,6 +413,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
|
|||
if (L.isEnabled(L.DATABASE))
|
||||
log.debug("Firing EventNewBg");
|
||||
MainApp.bus().post(new EventNewBG(bgReading));
|
||||
RxBus.INSTANCE.send(new EventNewBG(bgReading));
|
||||
scheduledBgPost = null;
|
||||
}
|
||||
}
|
||||
|
@ -434,7 +438,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
|
|||
return null;
|
||||
|
||||
for (int i = 0; i < bgList.size(); i++)
|
||||
if (bgList.get(i).value > 39)
|
||||
if (bgList.get(i).value >= 39)
|
||||
return bgList.get(i);
|
||||
return null;
|
||||
}
|
||||
|
@ -534,6 +538,24 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
|
|||
return tddList;
|
||||
}
|
||||
|
||||
public List<TDD> getTDDsForLastXDays(int days) {
|
||||
List<TDD> tddList;
|
||||
GregorianCalendar gc = new GregorianCalendar();
|
||||
gc.add(Calendar.DAY_OF_YEAR, (-1) * days);
|
||||
|
||||
try {
|
||||
QueryBuilder<TDD, String> queryBuilder = getDaoTDD().queryBuilder();
|
||||
queryBuilder.orderBy("date", false);
|
||||
Where<TDD, String> where = queryBuilder.where();
|
||||
where.ge("date", gc.getTimeInMillis());
|
||||
PreparedQuery<TDD> preparedQuery = queryBuilder.prepare();
|
||||
tddList = getDaoTDD().query(preparedQuery);
|
||||
} catch (SQLException e) {
|
||||
log.error("Unhandled exception", e);
|
||||
tddList = new ArrayList<>();
|
||||
}
|
||||
return tddList;
|
||||
}
|
||||
|
||||
// ------------- DbRequests handling -------------------
|
||||
|
||||
|
@ -596,7 +618,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
|
|||
}
|
||||
}
|
||||
|
||||
// -------------------- TREATMENT HANDLING -------------------
|
||||
// -------------------- TEMPTARGET HANDLING -------------------
|
||||
|
||||
public static void updateEarliestDataChange(long newDate) {
|
||||
if (earliestDataChange == null) {
|
||||
|
@ -627,6 +649,23 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
|
|||
return new ArrayList<TempTarget>();
|
||||
}
|
||||
|
||||
public List<TempTarget> getTemptargetsDataFromTime(long from, long to, boolean ascending) {
|
||||
try {
|
||||
Dao<TempTarget, Long> daoTempTargets = getDaoTempTargets();
|
||||
List<TempTarget> tempTargets;
|
||||
QueryBuilder<TempTarget, Long> queryBuilder = daoTempTargets.queryBuilder();
|
||||
queryBuilder.orderBy("date", ascending);
|
||||
Where where = queryBuilder.where();
|
||||
where.between("date", from, to);
|
||||
PreparedQuery<TempTarget> preparedQuery = queryBuilder.prepare();
|
||||
tempTargets = daoTempTargets.query(preparedQuery);
|
||||
return tempTargets;
|
||||
} catch (SQLException e) {
|
||||
log.error("Unhandled exception", e);
|
||||
}
|
||||
return new ArrayList<TempTarget>();
|
||||
}
|
||||
|
||||
public boolean createOrUpdate(TempTarget tempTarget) {
|
||||
try {
|
||||
TempTarget old;
|
||||
|
@ -852,6 +891,31 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
|
|||
log.debug("TEMPBASAL: Already exists from: " + Source.getString(tempBasal.source) + " " + tempBasal.toString());
|
||||
return false;
|
||||
}
|
||||
|
||||
// search by date (in case its standard record that has become pump record)
|
||||
QueryBuilder<TemporaryBasal, Long> queryBuilder2 = getDaoTemporaryBasal().queryBuilder();
|
||||
Where where2 = queryBuilder2.where();
|
||||
where2.eq("date", tempBasal.date);
|
||||
PreparedQuery<TemporaryBasal> preparedQuery2 = queryBuilder2.prepare();
|
||||
List<TemporaryBasal> trList2 = getDaoTemporaryBasal().query(preparedQuery2);
|
||||
|
||||
if (trList2.size() > 0) {
|
||||
old = trList2.get(0);
|
||||
|
||||
old.copyFromPump(tempBasal);
|
||||
old.source = Source.PUMP;
|
||||
|
||||
if (L.isEnabled(L.DATABASE))
|
||||
log.debug("TEMPBASAL: Updated record with Pump Data : " + Source.getString(tempBasal.source) + " " + tempBasal.toString());
|
||||
|
||||
getDaoTemporaryBasal().update(old);
|
||||
|
||||
updateEarliestDataChange(tempBasal.date);
|
||||
scheduleTemporaryBasalChange();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
getDaoTemporaryBasal().create(tempBasal);
|
||||
if (L.isEnabled(L.DATABASE))
|
||||
log.debug("TEMPBASAL: New record from: " + Source.getString(tempBasal.source) + " " + tempBasal.toString());
|
||||
|
@ -950,6 +1014,22 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
|
|||
return new ArrayList<TemporaryBasal>();
|
||||
}
|
||||
|
||||
public List<TemporaryBasal> getTemporaryBasalsDataFromTime(long from, long to, boolean ascending) {
|
||||
try {
|
||||
List<TemporaryBasal> tempbasals;
|
||||
QueryBuilder<TemporaryBasal, Long> queryBuilder = getDaoTemporaryBasal().queryBuilder();
|
||||
queryBuilder.orderBy("date", ascending);
|
||||
Where where = queryBuilder.where();
|
||||
where.between("date", from, to);
|
||||
PreparedQuery<TemporaryBasal> preparedQuery = queryBuilder.prepare();
|
||||
tempbasals = getDaoTemporaryBasal().query(preparedQuery);
|
||||
return tempbasals;
|
||||
} catch (SQLException e) {
|
||||
log.error("Unhandled exception", e);
|
||||
}
|
||||
return new ArrayList<TemporaryBasal>();
|
||||
}
|
||||
|
||||
private static void scheduleTemporaryBasalChange() {
|
||||
class PostRunnable implements Runnable {
|
||||
public void run() {
|
||||
|
@ -1076,6 +1156,29 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
|
|||
return null;
|
||||
}
|
||||
|
||||
|
||||
public TemporaryBasal findTempBasalByPumpId(Long pumpId) {
|
||||
try {
|
||||
QueryBuilder<TemporaryBasal, Long> queryBuilder = null;
|
||||
queryBuilder = getDaoTemporaryBasal().queryBuilder();
|
||||
queryBuilder.orderBy("date", false);
|
||||
Where where = queryBuilder.where();
|
||||
where.eq("pumpId", pumpId);
|
||||
PreparedQuery<TemporaryBasal> preparedQuery = queryBuilder.prepare();
|
||||
List<TemporaryBasal> list = getDaoTemporaryBasal().query(preparedQuery);
|
||||
|
||||
if (list.size() > 0)
|
||||
return list.get(0);
|
||||
else
|
||||
return null;
|
||||
|
||||
} catch (SQLException e) {
|
||||
log.error("Unhandled exception", e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
// ------------ ExtendedBolus handling ---------------
|
||||
|
||||
public boolean createOrUpdate(ExtendedBolus extendedBolus) {
|
||||
|
@ -1354,6 +1457,23 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
|
|||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
public List<CareportalEvent> getCareportalEvents(long start, long end, boolean ascending) {
|
||||
try {
|
||||
List<CareportalEvent> careportalEvents;
|
||||
QueryBuilder<CareportalEvent, Long> queryBuilder = getDaoCareportalEvents().queryBuilder();
|
||||
queryBuilder.orderBy("date", ascending);
|
||||
Where where = queryBuilder.where();
|
||||
where.between("date", start, end);
|
||||
PreparedQuery<CareportalEvent> preparedQuery = queryBuilder.prepare();
|
||||
careportalEvents = getDaoCareportalEvents().query(preparedQuery);
|
||||
preprocessOpenAPSOfflineEvents(careportalEvents);
|
||||
return careportalEvents;
|
||||
} catch (SQLException e) {
|
||||
log.error("Unhandled exception", e);
|
||||
}
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
public void preprocessOpenAPSOfflineEvents(List<CareportalEvent> list) {
|
||||
OverlappingIntervals offlineEvents = new OverlappingIntervals();
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
|
@ -1507,6 +1627,24 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
|
|||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
public List<ProfileSwitch> getProfileSwitchEventsFromTime(long from, long to, boolean ascending) {
|
||||
try {
|
||||
Dao<ProfileSwitch, Long> daoProfileSwitch = getDaoProfileSwitch();
|
||||
List<ProfileSwitch> profileSwitches;
|
||||
QueryBuilder<ProfileSwitch, Long> queryBuilder = daoProfileSwitch.queryBuilder();
|
||||
queryBuilder.orderBy("date", ascending);
|
||||
queryBuilder.limit(100L);
|
||||
Where where = queryBuilder.where();
|
||||
where.between("date", from, to);
|
||||
PreparedQuery<ProfileSwitch> preparedQuery = queryBuilder.prepare();
|
||||
profileSwitches = daoProfileSwitch.query(preparedQuery);
|
||||
return profileSwitches;
|
||||
} catch (SQLException e) {
|
||||
log.error("Unhandled exception", e);
|
||||
}
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
public boolean createOrUpdate(ProfileSwitch profileSwitch) {
|
||||
try {
|
||||
ProfileSwitch old;
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
package info.nightscout.androidaps.db;
|
||||
|
||||
public interface DbObjectBase {
|
||||
|
||||
long getDate();
|
||||
|
||||
long getPumpId();
|
||||
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
package info.nightscout.androidaps.db;
|
||||
|
||||
import android.graphics.Color;
|
||||
import android.support.annotation.Nullable;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.j256.ormlite.field.DatabaseField;
|
||||
import com.j256.ormlite.table.DatabaseTable;
|
||||
|
|
|
@ -6,9 +6,8 @@ import com.j256.ormlite.table.DatabaseTable;
|
|||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import info.nightscout.androidaps.logging.L;
|
||||
import info.nightscout.androidaps.plugins.pump.common.utils.DateTimeUtil;
|
||||
|
||||
/**
|
||||
* Created by mike on 20.09.2017.
|
||||
|
@ -45,4 +44,16 @@ public class TDD {
|
|||
this.basal = basal;
|
||||
this.total = total;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "TDD [" +
|
||||
"date=" + date +
|
||||
"date(str)=" + DateTimeUtil.toStringFromTimeInMillis(date) +
|
||||
", bolus=" + bolus +
|
||||
", basal=" + basal +
|
||||
", total=" + total +
|
||||
']';
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,6 +9,9 @@ import org.slf4j.LoggerFactory;
|
|||
import java.util.Objects;
|
||||
|
||||
import info.nightscout.androidaps.Constants;
|
||||
import info.nightscout.androidaps.MainApp;
|
||||
import info.nightscout.androidaps.R;
|
||||
import info.nightscout.androidaps.data.Profile;
|
||||
import info.nightscout.androidaps.interfaces.Interval;
|
||||
import info.nightscout.androidaps.logging.L;
|
||||
import info.nightscout.androidaps.utils.DateUtil;
|
||||
|
@ -191,4 +194,11 @@ public class TempTarget implements Interval {
|
|||
'}';
|
||||
}
|
||||
|
||||
public String friendlyDescription(String units) {
|
||||
return Profile.toTargetRangeString(low, high, Constants.MGDL, units) +
|
||||
units +
|
||||
"@" + MainApp.gs(R.string.mins, durationInMinutes) +
|
||||
(reason != null && !reason.equals("") ? "(" + reason + ")" : "");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -27,7 +27,7 @@ import info.nightscout.androidaps.utils.SP;
|
|||
*/
|
||||
|
||||
@DatabaseTable(tableName = DatabaseHelper.DATABASE_TEMPORARYBASALS)
|
||||
public class TemporaryBasal implements Interval {
|
||||
public class TemporaryBasal implements Interval, DbObjectBase {
|
||||
private static Logger log = LoggerFactory.getLogger(L.DATABASE);
|
||||
|
||||
@DatabaseField(id = true)
|
||||
|
@ -156,6 +156,14 @@ public class TemporaryBasal implements Interval {
|
|||
netExtendedRate = t.netExtendedRate;
|
||||
}
|
||||
|
||||
public void copyFromPump(TemporaryBasal t) {
|
||||
durationInMinutes = t.durationInMinutes;
|
||||
isAbsolute = t.isAbsolute;
|
||||
percentRate = t.percentRate;
|
||||
absoluteRate = t.absoluteRate;
|
||||
pumpId = t.pumpId;
|
||||
}
|
||||
|
||||
// -------- Interval interface ---------
|
||||
|
||||
Long cuttedEnd = null;
|
||||
|
@ -416,4 +424,13 @@ public class TemporaryBasal implements Interval {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getDate() {
|
||||
return this.date;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getPumpId() {
|
||||
return this.pumpId;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
package info.nightscout.androidaps.events;
|
||||
|
||||
public class EventCustomActionsChanged extends Event {
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
package info.nightscout.androidaps.events;
|
||||
|
||||
import android.location.Location;
|
||||
|
||||
public class EventLocationChange extends Event {
|
||||
public Location location;
|
||||
|
||||
public EventLocationChange(Location location) {
|
||||
this.location = location;
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
package info.nightscout.androidaps.events;
|
||||
|
||||
import android.support.annotation.Nullable;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import info.nightscout.androidaps.db.BgReading;
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package info.nightscout.androidaps.events;
|
||||
|
||||
import android.support.annotation.Nullable;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import info.nightscout.androidaps.plugins.treatments.Treatment;
|
||||
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
package info.nightscout.androidaps.interfaces;
|
||||
|
||||
import android.os.SystemClock;
|
||||
import android.support.v4.app.FragmentActivity;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.fragment.app.FragmentActivity;
|
||||
|
||||
import info.nightscout.androidaps.R;
|
||||
import info.nightscout.androidaps.utils.SP;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
@ -42,6 +45,28 @@ public abstract class PluginBase {
|
|||
pluginSwitcher.invoke();
|
||||
}
|
||||
|
||||
protected void confirmPumpPluginActivation(ConfigBuilderFragment.PluginViewHolder.PluginSwitcher pluginSwitcher, FragmentActivity activity) {
|
||||
boolean allowHardwarePump = SP.getBoolean("allow_hardware_pump", false);
|
||||
if (allowHardwarePump || activity == null) {
|
||||
pluginSwitcher.invoke();
|
||||
} else {
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
|
||||
builder.setMessage(R.string.allow_hardware_pump_text)
|
||||
.setPositiveButton(R.string.yes, (dialog, id) -> {
|
||||
pluginSwitcher.invoke();
|
||||
SP.putBoolean("allow_hardware_pump", true);
|
||||
if (L.isEnabled(L.PUMP))
|
||||
log.debug("First time HW pump allowed!");
|
||||
})
|
||||
.setNegativeButton(R.string.cancel, (dialog, id) -> {
|
||||
pluginSwitcher.cancel();
|
||||
if (L.isEnabled(L.PUMP))
|
||||
log.debug("User does not allow switching to HW pump!");
|
||||
});
|
||||
builder.create().show();
|
||||
}
|
||||
}
|
||||
|
||||
// public PluginType getType() {
|
||||
// return mainType;
|
||||
// }
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package info.nightscout.androidaps.interfaces;
|
||||
|
||||
import android.support.annotation.Nullable;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import info.nightscout.androidaps.data.ProfileStore;
|
||||
|
||||
|
|
|
@ -7,8 +7,10 @@ import java.util.List;
|
|||
import info.nightscout.androidaps.data.DetailedBolusInfo;
|
||||
import info.nightscout.androidaps.data.Profile;
|
||||
import info.nightscout.androidaps.data.PumpEnactResult;
|
||||
import info.nightscout.androidaps.plugins.common.ManufacturerType;
|
||||
import info.nightscout.androidaps.plugins.general.actions.defs.CustomAction;
|
||||
import info.nightscout.androidaps.plugins.general.actions.defs.CustomActionType;
|
||||
import info.nightscout.androidaps.plugins.pump.common.defs.PumpType;
|
||||
|
||||
/**
|
||||
* Created by mike on 04.06.2016.
|
||||
|
@ -53,7 +55,9 @@ public interface PumpInterface {
|
|||
|
||||
// Status to be passed to NS
|
||||
JSONObject getJSONStatus(Profile profile, String profileName);
|
||||
String deviceID();
|
||||
ManufacturerType manufacturer();
|
||||
PumpType model();
|
||||
String serialNumber();
|
||||
|
||||
// Pump capabilities
|
||||
PumpDescription getPumpDescription();
|
||||
|
@ -71,4 +75,10 @@ public interface PumpInterface {
|
|||
|
||||
void executeCustomAction(CustomActionType customActionType);
|
||||
|
||||
/**
|
||||
* This method will be called when time or Timezone changes, and pump driver can then do a specific action (for
|
||||
* example update clock on pump).
|
||||
*/
|
||||
void timeDateOrTimeZoneChanged();
|
||||
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ import java.util.List;
|
|||
import info.nightscout.androidaps.data.DetailedBolusInfo;
|
||||
import info.nightscout.androidaps.data.IobTotal;
|
||||
import info.nightscout.androidaps.data.MealData;
|
||||
import info.nightscout.androidaps.data.NonOverlappingIntervals;
|
||||
import info.nightscout.androidaps.data.Profile;
|
||||
import info.nightscout.androidaps.db.ExtendedBolus;
|
||||
import info.nightscout.androidaps.db.ProfileSwitch;
|
||||
|
@ -31,6 +32,7 @@ public interface TreatmentsInterface {
|
|||
|
||||
List<Treatment> getTreatmentsFromHistory();
|
||||
List<Treatment> getTreatments5MinBackFromHistory(long time);
|
||||
List<Treatment> getTreatmentsFromHistoryAfterTimestamp(long timestamp);
|
||||
long getLastBolusTime();
|
||||
|
||||
// real basals (not faked by extended bolus)
|
||||
|
@ -42,7 +44,7 @@ public interface TreatmentsInterface {
|
|||
// basal that can be faked by extended boluses
|
||||
boolean isTempBasalInProgress();
|
||||
TemporaryBasal getTempBasalFromHistory(long time);
|
||||
Intervals<TemporaryBasal> getTemporaryBasalsFromHistory();
|
||||
NonOverlappingIntervals<TemporaryBasal> getTemporaryBasalsFromHistory();
|
||||
|
||||
boolean isInHistoryExtendedBoluslInProgress();
|
||||
ExtendedBolus getExtendedBolusFromHistory(long time);
|
||||
|
@ -63,4 +65,4 @@ public interface TreatmentsInterface {
|
|||
|
||||
long oldestDataAvailable();
|
||||
|
||||
}
|
||||
}
|
|
@ -77,6 +77,7 @@ public class L {
|
|||
|
||||
public static final String CORE = "CORE";
|
||||
public static final String AUTOSENS = "AUTOSENS";
|
||||
public static final String AUTOMATION = "AUTOMATION";
|
||||
public static final String EVENTS = "EVENTS";
|
||||
public static final String GLUCOSE = "GLUCOSE";
|
||||
public static final String BGSOURCE = "BGSOURCE";
|
||||
|
@ -87,6 +88,7 @@ public class L {
|
|||
public static final String DATAFOOD = "DATAFOOD";
|
||||
public static final String DATATREATMENTS = "DATATREATMENTS";
|
||||
public static final String NSCLIENT = "NSCLIENT";
|
||||
public static final String TIDEPOOL = "TIDEPOOL";
|
||||
public static final String CONSTRAINTS = "CONSTRAINTS";
|
||||
public static final String PUMP = "PUMP";
|
||||
public static final String PUMPQUEUE = "PUMPQUEUE";
|
||||
|
@ -96,11 +98,13 @@ public class L {
|
|||
public static final String PROFILE = "PROFILE";
|
||||
public static final String CONFIGBUILDER = "CONFIGBUILDER";
|
||||
public static final String UI = "UI";
|
||||
public static final String LOCATION = "LOCATION";
|
||||
public static final String SMS = "SMS";
|
||||
|
||||
private static void initialize() {
|
||||
logElements = new ArrayList<>();
|
||||
logElements.add(new LogElement(APS, true));
|
||||
logElements.add(new LogElement(AUTOMATION, true));
|
||||
logElements.add(new LogElement(AUTOSENS, false));
|
||||
logElements.add(new LogElement(BGSOURCE, true));
|
||||
logElements.add(new LogElement(GLUCOSE, false));
|
||||
|
@ -112,8 +116,10 @@ public class L {
|
|||
logElements.add(new LogElement(DATASERVICE, true));
|
||||
logElements.add(new LogElement(DATATREATMENTS, true));
|
||||
logElements.add(new LogElement(EVENTS, false, true));
|
||||
logElements.add(new LogElement(LOCATION, true));
|
||||
logElements.add(new LogElement(NOTIFICATION, true));
|
||||
logElements.add(new LogElement(NSCLIENT, true));
|
||||
logElements.add(new LogElement(TIDEPOOL, true));
|
||||
logElements.add(new LogElement(OVERVIEW, true));
|
||||
logElements.add(new LogElement(PROFILE, true));
|
||||
logElements.add(new LogElement(PUMP, true));
|
||||
|
|
|
@ -10,8 +10,8 @@ import android.content.Context;
|
|||
import android.content.Intent;
|
||||
import android.os.Build;
|
||||
import android.os.SystemClock;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.v4.app.NotificationCompat;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.core.app.NotificationCompat;
|
||||
|
||||
import com.squareup.otto.Subscribe;
|
||||
|
||||
|
@ -644,14 +644,27 @@ public class LoopPlugin extends PluginBase {
|
|||
TreatmentsInterface activeTreatments = TreatmentsPlugin.getPlugin();
|
||||
|
||||
LoopPlugin.getPlugin().disconnectTo(System.currentTimeMillis() + durationInMinutes * 60 * 1000L);
|
||||
ConfigBuilderPlugin.getPlugin().getCommandQueue().tempBasalPercent(0, durationInMinutes, true, profile, new Callback() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (!result.success) {
|
||||
ToastUtils.showToastInUiThread(MainApp.instance().getApplicationContext(), MainApp.gs(R.string.tempbasaldeliveryerror));
|
||||
|
||||
if (pump.getPumpDescription().tempBasalStyle == PumpDescription.ABSOLUTE) {
|
||||
ConfigBuilderPlugin.getPlugin().getCommandQueue().tempBasalAbsolute(0, durationInMinutes, true, profile, new Callback() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (!result.success) {
|
||||
ToastUtils.showToastInUiThread(MainApp.instance().getApplicationContext(), MainApp.gs(R.string.tempbasaldeliveryerror));
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
} else {
|
||||
ConfigBuilderPlugin.getPlugin().getCommandQueue().tempBasalPercent(0, durationInMinutes, true, profile, new Callback() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (!result.success) {
|
||||
ToastUtils.showToastInUiThread(MainApp.instance().getApplicationContext(), MainApp.gs(R.string.tempbasaldeliveryerror));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (pump.getPumpDescription().isExtendedBolusCapable && activeTreatments.isInHistoryExtendedBoluslInProgress()) {
|
||||
ConfigBuilderPlugin.getPlugin().getCommandQueue().cancelExtended(new Callback() {
|
||||
@Override
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
package info.nightscout.androidaps.plugins.bus
|
||||
|
||||
import info.nightscout.androidaps.events.Event
|
||||
import io.reactivex.Observable
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import io.reactivex.subjects.PublishSubject
|
||||
|
||||
// Use object so we have a singleton instance
|
||||
object RxBus {
|
||||
|
||||
private val publisher = PublishSubject.create<Event>()
|
||||
|
||||
fun send(event: Event) {
|
||||
publisher.onNext(event)
|
||||
}
|
||||
|
||||
// Listen should return an Observable and not the publisher
|
||||
// Using ofType we filter only events that match that class type
|
||||
fun <T> toObservable(eventType: Class<T>): Observable<T> =
|
||||
publisher
|
||||
.subscribeOn(Schedulers.io())
|
||||
.ofType(eventType)
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
package info.nightscout.androidaps.plugins.common;
|
||||
|
||||
public enum ManufacturerType {
|
||||
|
||||
AndroidAPS("AndroidAPS"),
|
||||
Medtronic("Medtronic"),
|
||||
Sooil("SOOIL"),
|
||||
|
||||
Tandem("Tandem"),
|
||||
Insulet("Insulet"),
|
||||
Animas("Animas"), Cellnovo("Cellnovo"), Roche("Roche");
|
||||
|
||||
|
||||
|
||||
private String description;
|
||||
|
||||
ManufacturerType(String description) {
|
||||
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
package info.nightscout.androidaps.plugins.common;
|
||||
|
||||
import android.support.v4.app.Fragment;
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import butterknife.Unbinder;
|
||||
import info.nightscout.androidaps.MainApp;
|
||||
|
|
|
@ -3,8 +3,8 @@ package info.nightscout.androidaps.plugins.configBuilder;
|
|||
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.StringRes;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.StringRes;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package info.nightscout.androidaps.plugins.configBuilder;
|
||||
|
||||
import android.support.annotation.Nullable;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
@ -232,26 +232,32 @@ public class ConfigBuilderPlugin extends PluginBase {
|
|||
return commandQueue;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public BgSourceInterface getActiveBgSource() {
|
||||
return activeBgSource;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public ProfileInterface getActiveProfileInterface() {
|
||||
return activeProfile;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public InsulinInterface getActiveInsulin() {
|
||||
return activeInsulin;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public APSInterface getActiveAPS() {
|
||||
return activeAPS;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public PumpInterface getActivePump() {
|
||||
return activePump;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public SensitivityInterface getActiveSensitivity() {
|
||||
return activeSensitivity;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package info.nightscout.androidaps.plugins.configBuilder;
|
||||
|
||||
import android.support.annotation.Nullable;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
|
|
@ -2,7 +2,7 @@ package info.nightscout.androidaps.plugins.configBuilder;
|
|||
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.Nullable;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.google.firebase.analytics.FirebaseAnalytics;
|
||||
import com.squareup.otto.Subscribe;
|
||||
|
|
|
@ -4,11 +4,11 @@ import android.app.Activity;
|
|||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.v7.widget.CardView;
|
||||
import android.support.v7.widget.LinearLayoutManager;
|
||||
import android.support.v7.widget.LinearSmoothScroller;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.cardview.widget.CardView;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.LinearSmoothScroller;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import android.text.Html;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package info.nightscout.androidaps.plugins.constraints.objectives.objectives;
|
||||
|
||||
import android.support.annotation.StringRes;
|
||||
import androidx.annotation.StringRes;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
|
|
|
@ -13,10 +13,10 @@ import info.nightscout.androidaps.interfaces.PluginDescription;
|
|||
import info.nightscout.androidaps.interfaces.PluginType;
|
||||
import info.nightscout.androidaps.interfaces.PumpDescription;
|
||||
import info.nightscout.androidaps.interfaces.PumpInterface;
|
||||
import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin;
|
||||
import info.nightscout.androidaps.plugins.aps.openAPSAMA.OpenAPSAMAPlugin;
|
||||
import info.nightscout.androidaps.plugins.aps.openAPSMA.OpenAPSMAPlugin;
|
||||
import info.nightscout.androidaps.plugins.aps.openAPSSMB.OpenAPSSMBPlugin;
|
||||
import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin;
|
||||
import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification;
|
||||
import info.nightscout.androidaps.plugins.general.overview.notifications.Notification;
|
||||
import info.nightscout.androidaps.plugins.sensitivity.SensitivityOref1Plugin;
|
||||
|
@ -196,7 +196,7 @@ public class SafetyPlugin extends PluginBase implements ConstraintsInterface {
|
|||
|
||||
PumpInterface pump = ConfigBuilderPlugin.getPlugin().getActivePump();
|
||||
if (pump != null) {
|
||||
double rounded = Round.roundTo(insulin.value(), pump.getPumpDescription().pumpType.determineCorrectBolusSize(insulin.value()));
|
||||
double rounded = pump.getPumpDescription().pumpType.determineCorrectBolusSize(insulin.value());
|
||||
insulin.setIfDifferent(rounded, MainApp.gs(R.string.pumplimit), this);
|
||||
}
|
||||
return insulin;
|
||||
|
@ -213,7 +213,7 @@ public class SafetyPlugin extends PluginBase implements ConstraintsInterface {
|
|||
|
||||
PumpInterface pump = ConfigBuilderPlugin.getPlugin().getActivePump();
|
||||
if (pump != null) {
|
||||
double rounded = Round.roundTo(insulin.value(), pump.getPumpDescription().pumpType.determineCorrectExtendedBolusSize(insulin.value()));
|
||||
double rounded = pump.getPumpDescription().pumpType.determineCorrectExtendedBolusSize(insulin.value());
|
||||
insulin.setIfDifferent(rounded, MainApp.gs(R.string.pumplimit), this);
|
||||
}
|
||||
return insulin;
|
||||
|
|
|
@ -5,8 +5,8 @@ import android.app.Activity;
|
|||
import android.content.Intent;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.support.v4.app.FragmentManager;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
@ -26,6 +26,7 @@ import info.nightscout.androidaps.activities.HistoryBrowseActivity;
|
|||
import info.nightscout.androidaps.activities.TDDStatsActivity;
|
||||
import info.nightscout.androidaps.db.ExtendedBolus;
|
||||
import info.nightscout.androidaps.db.TemporaryBasal;
|
||||
import info.nightscout.androidaps.events.EventCustomActionsChanged;
|
||||
import info.nightscout.androidaps.events.EventExtendedBolusChange;
|
||||
import info.nightscout.androidaps.events.EventInitializationChanged;
|
||||
import info.nightscout.androidaps.events.EventRefreshOverview;
|
||||
|
@ -133,6 +134,11 @@ public class ActionsFragment extends SubscriberFragment implements View.OnClickL
|
|||
updateGUI();
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onStatusEvent(final EventCustomActionsChanged ev) {
|
||||
updateGUI();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateGUI() {
|
||||
Activity activity = getActivity();
|
||||
|
@ -247,6 +253,9 @@ public class ActionsFragment extends SubscriberFragment implements View.OnClickL
|
|||
|
||||
for (CustomAction customAction : customActions) {
|
||||
|
||||
if (!customAction.isEnabled())
|
||||
continue;
|
||||
|
||||
SingleClickButton btn = new SingleClickButton(getContext(), null, android.R.attr.buttonStyle);
|
||||
btn.setText(MainApp.gs(customAction.getName()));
|
||||
|
||||
|
@ -264,10 +273,8 @@ public class ActionsFragment extends SubscriberFragment implements View.OnClickL
|
|||
|
||||
this.pumpCustomActions.put(MainApp.gs(customAction.getName()), customAction);
|
||||
this.pumpCustomButtons.add(btn);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -283,7 +290,6 @@ public class ActionsFragment extends SubscriberFragment implements View.OnClickL
|
|||
}
|
||||
|
||||
pumpCustomButtons.clear();
|
||||
pumpCustomActions.clear();
|
||||
}
|
||||
|
||||
|
||||
|
@ -335,4 +341,4 @@ public class ActionsFragment extends SubscriberFragment implements View.OnClickL
|
|||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -12,31 +12,36 @@ public class CustomAction {
|
|||
private String iconName;
|
||||
private CustomActionType customActionType;
|
||||
private int iconResourceId;
|
||||
private boolean enabled = true;
|
||||
|
||||
|
||||
public CustomAction(int nameResourceId, CustomActionType actionType) {
|
||||
this.name = nameResourceId;
|
||||
this.customActionType = actionType;
|
||||
this.iconResourceId = R.drawable.icon_actions_profileswitch;
|
||||
this(nameResourceId, actionType, R.drawable.icon_actions_profileswitch, true);
|
||||
}
|
||||
|
||||
|
||||
public CustomAction(int nameResourceId, CustomActionType actionType, int iconResourceId) {
|
||||
this(nameResourceId, actionType, iconResourceId, true);
|
||||
}
|
||||
|
||||
public CustomAction(int nameResourceId, CustomActionType actionType, boolean enabled) {
|
||||
this(nameResourceId, actionType, R.drawable.icon_actions_profileswitch, enabled);
|
||||
}
|
||||
|
||||
public CustomAction(int nameResourceId, CustomActionType actionType, int iconResourceId, boolean enabled) {
|
||||
this.name = nameResourceId;
|
||||
this.customActionType = actionType;
|
||||
this.iconResourceId = iconResourceId;
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
|
||||
public int getName() {
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public CustomActionType getCustomActionType() {
|
||||
|
||||
return customActionType;
|
||||
}
|
||||
|
||||
|
@ -44,4 +49,15 @@ public class CustomAction {
|
|||
public int getIconResourceId() {
|
||||
return iconResourceId;
|
||||
}
|
||||
|
||||
|
||||
public boolean isEnabled() {
|
||||
return enabled;
|
||||
}
|
||||
|
||||
|
||||
public void setEnabled(boolean enabled) {
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -3,8 +3,8 @@ package info.nightscout.androidaps.plugins.general.actions.dialogs;
|
|||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.DialogFragment;
|
||||
import android.support.v7.app.AlertDialog;
|
||||
import androidx.fragment.app.DialogFragment;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import android.text.Editable;
|
||||
import android.text.Html;
|
||||
import android.text.TextWatcher;
|
||||
|
@ -103,7 +103,7 @@ public class FillDialog extends DialogFragment implements OnClickListener {
|
|||
Double maxInsulin = MainApp.getConstraintChecker().getMaxBolusAllowed().value();
|
||||
double bolusstep = ConfigBuilderPlugin.getPlugin().getActivePump().getPumpDescription().bolusStep;
|
||||
editInsulin = view.findViewById(R.id.fill_insulinamount);
|
||||
editInsulin.setParams(0d, 0d, maxInsulin, bolusstep, DecimalFormatter.pumpSupportedBolusFormat(), false, textWatcher);
|
||||
editInsulin.setParams(0d, 0d, maxInsulin, bolusstep, DecimalFormatter.pumpSupportedBolusFormat(), false, view.findViewById(R.id.ok), textWatcher);
|
||||
|
||||
|
||||
Button preset1Button = view.findViewById(R.id.fill_preset_button1);
|
||||
|
@ -184,7 +184,7 @@ public class FillDialog extends DialogFragment implements OnClickListener {
|
|||
confirmMessage.add("");
|
||||
confirmMessage.add(MainApp.gs(R.string.bolus) + ": " + "<font color='" + MainApp.gc(R.color.colorCarbsButton) + "'>" + DecimalFormatter.toPumpSupportedBolus(insulinAfterConstraints) + "U" + "</font>");
|
||||
if (Math.abs(insulinAfterConstraints - insulin) > 0.01d)
|
||||
confirmMessage.add("<font color='" + MainApp.gc(R.color.low) + "'>" + MainApp.gs(R.string.bolusconstraintapplied) + "</font>");
|
||||
confirmMessage.add(MainApp.gs(R.string.bolusconstraintappliedwarning, MainApp.gc(R.color.warning), insulin, insulinAfterConstraints));
|
||||
}
|
||||
|
||||
if (pumpSiteChangeCheckbox.isChecked())
|
||||
|
|
|
@ -4,8 +4,8 @@ import android.content.Context;
|
|||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.DialogFragment;
|
||||
import android.support.v7.app.AlertDialog;
|
||||
import androidx.fragment.app.DialogFragment;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
@ -42,12 +42,12 @@ public class NewExtendedBolusDialog extends DialogFragment implements View.OnCli
|
|||
|
||||
Double maxInsulin = MainApp.getConstraintChecker().getMaxExtendedBolusAllowed().value();
|
||||
editInsulin = (NumberPicker) view.findViewById(R.id.overview_newextendedbolus_insulin);
|
||||
editInsulin.setParams(0d, 0d, maxInsulin, 0.1d, new DecimalFormat("0.00"), false);
|
||||
editInsulin.setParams(0d, 0d, maxInsulin, 0.1d, new DecimalFormat("0.00"), false, view.findViewById(R.id.ok));
|
||||
|
||||
double extendedDurationStep = ConfigBuilderPlugin.getPlugin().getActivePump().getPumpDescription().extendedBolusDurationStep;
|
||||
double extendedMaxDuration = ConfigBuilderPlugin.getPlugin().getActivePump().getPumpDescription().extendedBolusMaxDuration;
|
||||
editDuration = (NumberPicker) view.findViewById(R.id.overview_newextendedbolus_duration);
|
||||
editDuration.setParams(extendedDurationStep, extendedDurationStep, extendedMaxDuration, extendedDurationStep, new DecimalFormat("0"), false);
|
||||
editDuration.setParams(extendedDurationStep, extendedDurationStep, extendedMaxDuration, extendedDurationStep, new DecimalFormat("0"), false, view.findViewById(R.id.ok));
|
||||
|
||||
view.findViewById(R.id.ok).setOnClickListener(this);
|
||||
view.findViewById(R.id.cancel).setOnClickListener(this);
|
||||
|
|
|
@ -3,8 +3,8 @@ package info.nightscout.androidaps.plugins.general.actions.dialogs;
|
|||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.DialogFragment;
|
||||
import android.support.v7.app.AlertDialog;
|
||||
import androidx.fragment.app.DialogFragment;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
@ -66,17 +66,17 @@ public class NewTempBasalDialog extends DialogFragment implements View.OnClickLi
|
|||
basalPercent = (NumberPicker) view.findViewById(R.id.overview_newtempbasal_basalpercentinput);
|
||||
double maxTempPercent = pumpDescription.maxTempPercent;
|
||||
double tempPercentStep = pumpDescription.tempPercentStep;
|
||||
basalPercent.setParams(100d, 0d, maxTempPercent, tempPercentStep, new DecimalFormat("0"), true);
|
||||
basalPercent.setParams(100d, 0d, maxTempPercent, tempPercentStep, new DecimalFormat("0"), true, view.findViewById(R.id.ok));
|
||||
|
||||
Profile profile = ProfileFunctions.getInstance().getProfile();
|
||||
Double currentBasal = profile != null ? profile.getBasal() : 0d;
|
||||
basalAbsolute = (NumberPicker) view.findViewById(R.id.overview_newtempbasal_basalabsoluteinput);
|
||||
basalAbsolute.setParams(currentBasal, 0d, pumpDescription.maxTempAbsolute, pumpDescription.tempAbsoluteStep, new DecimalFormat("0.00"), true);
|
||||
basalAbsolute.setParams(currentBasal, 0d, pumpDescription.maxTempAbsolute, pumpDescription.tempAbsoluteStep, new DecimalFormat("0.00"), true, view.findViewById(R.id.ok));
|
||||
|
||||
double tempDurationStep = pumpDescription.tempDurationStep;
|
||||
double tempMaxDuration = pumpDescription.tempMaxDuration;
|
||||
duration = (NumberPicker) view.findViewById(R.id.overview_newtempbasal_duration);
|
||||
duration.setParams(tempDurationStep, tempDurationStep, tempMaxDuration, tempDurationStep, new DecimalFormat("0"), false);
|
||||
duration.setParams(tempDurationStep, tempDurationStep, tempMaxDuration, tempDurationStep, new DecimalFormat("0"), false, view.findViewById(R.id.ok));
|
||||
|
||||
if ((pumpDescription.tempBasalStyle & PumpDescription.PERCENT) == PumpDescription.PERCENT && (pumpDescription.tempBasalStyle & PumpDescription.ABSOLUTE) == PumpDescription.ABSOLUTE) {
|
||||
// Both allowed
|
||||
|
|
|
@ -0,0 +1,90 @@
|
|||
package info.nightscout.androidaps.plugins.general.automation;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import info.nightscout.androidaps.plugins.general.automation.actions.Action;
|
||||
import info.nightscout.androidaps.plugins.general.automation.triggers.Trigger;
|
||||
import info.nightscout.androidaps.plugins.general.automation.triggers.TriggerConnector;
|
||||
|
||||
public class AutomationEvent {
|
||||
|
||||
private Trigger trigger = new TriggerConnector();
|
||||
private List<Action> actions = new ArrayList<>();
|
||||
private String title;
|
||||
|
||||
public void setTitle(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
public void setTrigger(Trigger trigger) {
|
||||
this.trigger = trigger;
|
||||
}
|
||||
|
||||
public Trigger getTrigger() {
|
||||
return trigger;
|
||||
}
|
||||
|
||||
public List<Action> getActions() {
|
||||
return actions;
|
||||
}
|
||||
|
||||
public TriggerConnector getPreconditions() {
|
||||
TriggerConnector trigger = new TriggerConnector(TriggerConnector.Type.AND);
|
||||
for (Action action : actions) {
|
||||
if (action.precondition != null)
|
||||
trigger.add(action.precondition);
|
||||
}
|
||||
return trigger;
|
||||
}
|
||||
|
||||
public void addAction(Action action) {
|
||||
actions.add(action);
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
public String toJSON() {
|
||||
JSONObject o = new JSONObject();
|
||||
try {
|
||||
// title
|
||||
o.put("title", title);
|
||||
// trigger
|
||||
o.put("trigger", trigger.toJSON());
|
||||
// actions
|
||||
JSONArray array = new JSONArray();
|
||||
for (Action a : actions) {
|
||||
array.put(a.toJSON());
|
||||
}
|
||||
o.put("actions", array);
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return o.toString();
|
||||
}
|
||||
|
||||
public AutomationEvent fromJSON(String data) {
|
||||
try {
|
||||
JSONObject d = new JSONObject(data);
|
||||
// title
|
||||
title = d.optString("title", "");
|
||||
// trigger
|
||||
trigger = Trigger.instantiate(d.getString("trigger"));
|
||||
// actions
|
||||
JSONArray array = d.getJSONArray("actions");
|
||||
actions.clear();
|
||||
for (int i = 0; i < array.length(); i++) {
|
||||
actions.add(Action.instantiate(new JSONObject(array.getString(i))));
|
||||
}
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
package info.nightscout.androidaps.plugins.general.automation
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.plugins.bus.RxBus
|
||||
import info.nightscout.androidaps.plugins.general.automation.dialogs.EditEventDialog
|
||||
import info.nightscout.androidaps.plugins.general.automation.events.EventAutomationDataChanged
|
||||
import info.nightscout.androidaps.plugins.general.automation.events.EventAutomationUpdateGui
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.disposables.CompositeDisposable
|
||||
import io.reactivex.disposables.Disposable
|
||||
import kotlinx.android.synthetic.main.automation_fragment.*
|
||||
|
||||
class AutomationFragment : Fragment() {
|
||||
|
||||
private var disposable: CompositeDisposable = CompositeDisposable()
|
||||
private var eventListAdapter: EventListAdapter? = null
|
||||
|
||||
operator fun CompositeDisposable.plusAssign(disposable: Disposable) {
|
||||
add(disposable)
|
||||
}
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
return inflater.inflate(R.layout.automation_fragment, container, false)
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
eventListAdapter = EventListAdapter(AutomationPlugin.automationEvents, fragmentManager)
|
||||
automation_eventListView.layoutManager = LinearLayoutManager(context)
|
||||
automation_eventListView.adapter = eventListAdapter
|
||||
|
||||
automation_fabAddEvent.setOnClickListener {
|
||||
val dialog = EditEventDialog()
|
||||
val args = Bundle()
|
||||
args.putString("event", AutomationEvent().toJSON())
|
||||
args.putInt("position", -1) // New event
|
||||
dialog.arguments = args
|
||||
fragmentManager?.let { dialog.show(it, "EditEventDialog") }
|
||||
}
|
||||
|
||||
disposable += RxBus
|
||||
.toObservable(EventAutomationUpdateGui::class.java)
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe({
|
||||
eventListAdapter?.notifyDataSetChanged()
|
||||
val sb = StringBuilder()
|
||||
for (l in AutomationPlugin.executionLog) {
|
||||
sb.append(l)
|
||||
sb.append("\n")
|
||||
}
|
||||
automation_logView.text = sb.toString()
|
||||
}, {})
|
||||
disposable += RxBus
|
||||
.toObservable(EventAutomationDataChanged::class.java)
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe({
|
||||
eventListAdapter?.notifyDataSetChanged()
|
||||
}, {})
|
||||
}
|
||||
|
||||
override fun onStop() {
|
||||
super.onStop()
|
||||
disposable.clear()
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,213 @@
|
|||
package info.nightscout.androidaps.plugins.general.automation
|
||||
|
||||
import android.content.Intent
|
||||
import android.os.Handler
|
||||
import info.nightscout.androidaps.MainApp
|
||||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.events.EventChargingState
|
||||
import info.nightscout.androidaps.events.EventLocationChange
|
||||
import info.nightscout.androidaps.events.EventNetworkChange
|
||||
import info.nightscout.androidaps.events.EventPreferenceChange
|
||||
import info.nightscout.androidaps.interfaces.PluginBase
|
||||
import info.nightscout.androidaps.interfaces.PluginDescription
|
||||
import info.nightscout.androidaps.interfaces.PluginType
|
||||
import info.nightscout.androidaps.logging.L
|
||||
import info.nightscout.androidaps.plugins.bus.RxBus
|
||||
import info.nightscout.androidaps.plugins.general.automation.actions.*
|
||||
import info.nightscout.androidaps.plugins.general.automation.events.EventAutomationDataChanged
|
||||
import info.nightscout.androidaps.plugins.general.automation.events.EventAutomationUpdateGui
|
||||
import info.nightscout.androidaps.plugins.general.automation.triggers.*
|
||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventAutosensCalculationFinished
|
||||
import info.nightscout.androidaps.queue.Callback
|
||||
import info.nightscout.androidaps.services.LocationService
|
||||
import info.nightscout.androidaps.utils.DateUtil
|
||||
import info.nightscout.androidaps.utils.SP
|
||||
import info.nightscout.androidaps.utils.T
|
||||
import io.reactivex.disposables.CompositeDisposable
|
||||
import io.reactivex.disposables.Disposable
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import org.json.JSONArray
|
||||
import org.json.JSONException
|
||||
import org.json.JSONObject
|
||||
import org.slf4j.LoggerFactory
|
||||
import java.util.*
|
||||
|
||||
object AutomationPlugin : PluginBase(PluginDescription()
|
||||
.mainType(PluginType.GENERAL)
|
||||
.fragmentClass(AutomationFragment::class.qualifiedName)
|
||||
.pluginName(R.string.automation)
|
||||
.shortName(R.string.automation_short)
|
||||
.preferencesId(R.xml.pref_automation)
|
||||
.description(R.string.automation_description)) {
|
||||
|
||||
private val log = LoggerFactory.getLogger(L.AUTOMATION)
|
||||
private var disposable: CompositeDisposable = CompositeDisposable()
|
||||
|
||||
private const val key_AUTOMATION_EVENTS = "AUTOMATION_EVENTS"
|
||||
|
||||
val automationEvents = ArrayList<AutomationEvent>()
|
||||
var executionLog: MutableList<String> = ArrayList()
|
||||
|
||||
private val loopHandler = Handler()
|
||||
private lateinit var refreshLoop: Runnable
|
||||
|
||||
init {
|
||||
refreshLoop = Runnable {
|
||||
processActions()
|
||||
loopHandler.postDelayed(refreshLoop, T.mins(1).msecs())
|
||||
}
|
||||
}
|
||||
|
||||
operator fun CompositeDisposable.plusAssign(disposable: Disposable) {
|
||||
add(disposable)
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
val context = MainApp.instance().applicationContext
|
||||
context.startService(Intent(context, LocationService::class.java))
|
||||
|
||||
super.onStart()
|
||||
loadFromSP()
|
||||
loopHandler.postDelayed(refreshLoop, T.mins(1).msecs())
|
||||
|
||||
disposable += RxBus
|
||||
.toObservable(EventPreferenceChange::class.java)
|
||||
.observeOn(Schedulers.io())
|
||||
.subscribe({ e ->
|
||||
if (e.isChanged(R.string.key_location)) {
|
||||
val ctx = MainApp.instance().applicationContext
|
||||
ctx.stopService(Intent(ctx, LocationService::class.java))
|
||||
ctx.startService(Intent(ctx, LocationService::class.java))
|
||||
}
|
||||
}, {})
|
||||
disposable += RxBus
|
||||
.toObservable(EventAutomationDataChanged::class.java)
|
||||
.observeOn(Schedulers.io())
|
||||
.subscribe({ storeToSP() }, {})
|
||||
disposable += RxBus
|
||||
.toObservable(EventLocationChange::class.java)
|
||||
.observeOn(Schedulers.io())
|
||||
.subscribe({ e ->
|
||||
e?.let {
|
||||
log.debug("Grabbed location: $it.location.latitude $it.location.longitude Provider: $it.location.provider")
|
||||
processActions()
|
||||
}
|
||||
}, {})
|
||||
disposable += RxBus
|
||||
.toObservable(EventChargingState::class.java)
|
||||
.observeOn(Schedulers.io())
|
||||
.subscribe({ processActions() }, {})
|
||||
disposable += RxBus
|
||||
.toObservable(EventNetworkChange::class.java)
|
||||
.observeOn(Schedulers.io())
|
||||
.subscribe({ processActions() }, {})
|
||||
disposable += RxBus
|
||||
.toObservable(EventAutosensCalculationFinished::class.java)
|
||||
.observeOn(Schedulers.io())
|
||||
.subscribe({ processActions() }, {})
|
||||
}
|
||||
|
||||
override fun onStop() {
|
||||
disposable.clear()
|
||||
loopHandler.removeCallbacks(refreshLoop)
|
||||
val context = MainApp.instance().applicationContext
|
||||
context.stopService(Intent(context, LocationService::class.java))
|
||||
}
|
||||
|
||||
private fun storeToSP() {
|
||||
val array = JSONArray()
|
||||
try {
|
||||
for (event in automationEvents) {
|
||||
array.put(JSONObject(event.toJSON()))
|
||||
}
|
||||
} catch (e: JSONException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
|
||||
SP.putString(key_AUTOMATION_EVENTS, array.toString())
|
||||
}
|
||||
|
||||
private fun loadFromSP() {
|
||||
automationEvents.clear()
|
||||
val data = SP.getString(key_AUTOMATION_EVENTS, "")
|
||||
if (data != "") {
|
||||
try {
|
||||
val array = JSONArray(data)
|
||||
for (i in 0 until array.length()) {
|
||||
val o = array.getJSONObject(i)
|
||||
val event = AutomationEvent().fromJSON(o.toString())
|
||||
automationEvents.add(event)
|
||||
}
|
||||
} catch (e: JSONException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
private fun processActions() {
|
||||
if (!isEnabled(PluginType.GENERAL))
|
||||
return
|
||||
|
||||
if (L.isEnabled(L.AUTOMATION))
|
||||
log.debug("processActions")
|
||||
for (event in automationEvents) {
|
||||
if (event.trigger.shouldRun() && event.preconditions.shouldRun()) {
|
||||
val actions = event.actions
|
||||
for (action in actions) {
|
||||
action.doAction(object : Callback() {
|
||||
override fun run() {
|
||||
val sb = StringBuilder()
|
||||
sb.append(DateUtil.timeString(DateUtil.now()))
|
||||
sb.append(" ")
|
||||
sb.append(if (result.success) "☺" else "X")
|
||||
sb.append(" ")
|
||||
sb.append(event.title)
|
||||
sb.append(": ")
|
||||
sb.append(action.shortDescription())
|
||||
sb.append(": ")
|
||||
sb.append(result.comment)
|
||||
executionLog.add(sb.toString())
|
||||
if (L.isEnabled(L.AUTOMATION))
|
||||
log.debug("Executed: $sb")
|
||||
RxBus.send(EventAutomationUpdateGui())
|
||||
}
|
||||
})
|
||||
}
|
||||
event.trigger.executed(DateUtil.now())
|
||||
}
|
||||
}
|
||||
storeToSP() // save last run time
|
||||
}
|
||||
|
||||
fun getActionDummyObjects(): List<Action> {
|
||||
return listOf(
|
||||
//ActionLoopDisable(),
|
||||
//ActionLoopEnable(),
|
||||
//ActionLoopResume(),
|
||||
//ActionLoopSuspend(),
|
||||
ActionStartTempTarget(),
|
||||
ActionStopTempTarget(),
|
||||
ActionNotification(),
|
||||
ActionProfileSwitchPercent()
|
||||
)
|
||||
}
|
||||
|
||||
fun getTriggerDummyObjects(): List<Trigger> {
|
||||
return listOf(
|
||||
TriggerTime(),
|
||||
TriggerRecurringTime(),
|
||||
TriggerBg(),
|
||||
TriggerDelta(),
|
||||
TriggerIob(),
|
||||
TriggerCOB(),
|
||||
TriggerProfilePercent(),
|
||||
TriggerTempTarget(),
|
||||
TriggerWifiSsid(),
|
||||
TriggerLocation(),
|
||||
TriggerAutosensValue(),
|
||||
TriggerBolusAgo()
|
||||
)
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,120 @@
|
|||
package info.nightscout.androidaps.plugins.general.automation;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.RelativeLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.DrawableRes;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
|
||||
import info.nightscout.androidaps.MainApp;
|
||||
import info.nightscout.androidaps.R;
|
||||
import info.nightscout.androidaps.plugins.general.automation.actions.Action;
|
||||
import info.nightscout.androidaps.plugins.general.automation.dialogs.EditEventDialog;
|
||||
import info.nightscout.androidaps.plugins.general.automation.triggers.TriggerConnector;
|
||||
|
||||
class EventListAdapter extends RecyclerView.Adapter<EventListAdapter.ViewHolder> {
|
||||
private final List<AutomationEvent> mEventList;
|
||||
private final FragmentManager mFragmentManager;
|
||||
|
||||
EventListAdapter(List<AutomationEvent> events, FragmentManager fragmentManager) {
|
||||
this.mEventList = events;
|
||||
this.mFragmentManager = fragmentManager;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.automation_event_item, parent, false);
|
||||
return new ViewHolder(v, parent.getContext());
|
||||
}
|
||||
|
||||
private void addImage(@DrawableRes int res, Context context, LinearLayout layout) {
|
||||
ImageView iv = new ImageView(context);
|
||||
iv.setImageResource(res);
|
||||
iv.setLayoutParams(new LinearLayout.LayoutParams(MainApp.dpToPx(24), MainApp.dpToPx(24)));
|
||||
layout.addView(iv);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
|
||||
final AutomationEvent event = mEventList.get(position);
|
||||
holder.eventTitle.setText(event.getTitle());
|
||||
holder.iconLayout.removeAllViews();
|
||||
|
||||
// trigger icons
|
||||
HashSet<Integer> triggerIcons = new HashSet<>();
|
||||
TriggerConnector.fillIconSet((TriggerConnector) event.getTrigger(), triggerIcons);
|
||||
for (int res : triggerIcons) {
|
||||
addImage(res, holder.context, holder.iconLayout);
|
||||
}
|
||||
|
||||
// arrow icon
|
||||
ImageView iv = new ImageView(holder.context);
|
||||
iv.setImageResource(R.drawable.ic_arrow_forward_white_24dp);
|
||||
iv.setLayoutParams(new LinearLayout.LayoutParams(MainApp.dpToPx(24), MainApp.dpToPx(24)));
|
||||
iv.setPadding(MainApp.dpToPx(4), 0, MainApp.dpToPx(4), 0);
|
||||
holder.iconLayout.addView(iv);
|
||||
|
||||
// action icons
|
||||
HashSet<Integer> actionIcons = new HashSet<>();
|
||||
for (Action action : event.getActions()) {
|
||||
if (action.icon().isPresent())
|
||||
actionIcons.add(action.icon().get());
|
||||
}
|
||||
for (int res : actionIcons) {
|
||||
addImage(res, holder.context, holder.iconLayout);
|
||||
}
|
||||
|
||||
// remove event
|
||||
holder.iconTrash.setOnClickListener(v -> {
|
||||
mEventList.remove(event);
|
||||
notifyDataSetChanged();
|
||||
});
|
||||
|
||||
// edit event
|
||||
holder.rootLayout.setOnClickListener(v -> {
|
||||
//EditEventDialog dialog = EditEventDialog.Companion.newInstance(event, false);
|
||||
EditEventDialog dialog = new EditEventDialog();
|
||||
Bundle args = new Bundle();
|
||||
args.putString("event", event.toJSON());
|
||||
args.putInt("position", position);
|
||||
dialog.setArguments(args);
|
||||
if (mFragmentManager != null)
|
||||
dialog.show(mFragmentManager, "EditEventDialog");
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return mEventList.size();
|
||||
}
|
||||
|
||||
static class ViewHolder extends RecyclerView.ViewHolder {
|
||||
final RelativeLayout rootLayout;
|
||||
final LinearLayout iconLayout;
|
||||
final TextView eventTitle;
|
||||
final Context context;
|
||||
final ImageView iconTrash;
|
||||
|
||||
ViewHolder(View view, Context context) {
|
||||
super(view);
|
||||
this.context = context;
|
||||
eventTitle = view.findViewById(R.id.viewEventTitle);
|
||||
rootLayout = view.findViewById(R.id.rootLayout);
|
||||
iconLayout = view.findViewById(R.id.iconLayout);
|
||||
iconTrash = view.findViewById(R.id.iconTrash);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,104 @@
|
|||
package info.nightscout.androidaps.plugins.general.automation.actions;
|
||||
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import com.google.common.base.Optional;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import info.nightscout.androidaps.plugins.general.automation.triggers.Trigger;
|
||||
import info.nightscout.androidaps.queue.Callback;
|
||||
|
||||
/*
|
||||
Action ideas:
|
||||
|
||||
* cancel temp target
|
||||
* change preference setting
|
||||
* enable/disable plugin
|
||||
* create notification
|
||||
* create ugly alarm
|
||||
* create profile switch
|
||||
* set/cancel tbr
|
||||
* set/cancel extended bolus
|
||||
* run bolus wizard
|
||||
|
||||
Trigger ideas:
|
||||
|
||||
* location (close to)
|
||||
* connected to specific wifi
|
||||
* internet available/not available
|
||||
* nsclient connected/disconnected
|
||||
* iob
|
||||
* cob
|
||||
* autosens value
|
||||
* delta, short delta, long delta
|
||||
* last bolus ago
|
||||
* is tbr running
|
||||
* bolus wizard result
|
||||
* loop is enabled, disabled, suspended, running
|
||||
|
||||
*/
|
||||
|
||||
|
||||
public abstract class Action {
|
||||
|
||||
public Trigger precondition = null;
|
||||
|
||||
public abstract int friendlyName();
|
||||
|
||||
public abstract String shortDescription();
|
||||
|
||||
public abstract void doAction(Callback callback);
|
||||
|
||||
public void generateDialog(LinearLayout root) {
|
||||
}
|
||||
|
||||
public boolean hasDialog() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public String toJSON() {
|
||||
JSONObject o = new JSONObject();
|
||||
try {
|
||||
o.put("type", this.getClass().getName());
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return o.toString();
|
||||
}
|
||||
|
||||
public abstract Optional<Integer> icon();
|
||||
|
||||
public Action fromJSON(String data) {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static Action instantiate(JSONObject object) {
|
||||
try {
|
||||
String type = object.getString("type");
|
||||
JSONObject data = object.optJSONObject("data");
|
||||
Class clazz = Class.forName(type);
|
||||
return ((Action) clazz.newInstance()).fromJSON(data != null ? data.toString() : "");
|
||||
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void apply(Action a) {
|
||||
try {
|
||||
JSONObject object = new JSONObject(a.toJSON());
|
||||
String type = object.getString("type");
|
||||
JSONObject data = object.getJSONObject("data");
|
||||
if (type.equals(getClass().getName())) {
|
||||
fromJSON(data.toString());
|
||||
}
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
package info.nightscout.androidaps.plugins.general.automation.actions;
|
||||
|
||||
import com.google.common.base.Optional;
|
||||
|
||||
import info.nightscout.androidaps.MainApp;
|
||||
import info.nightscout.androidaps.R;
|
||||
import info.nightscout.androidaps.data.PumpEnactResult;
|
||||
import info.nightscout.androidaps.events.EventRefreshOverview;
|
||||
import info.nightscout.androidaps.interfaces.PluginType;
|
||||
import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin;
|
||||
import info.nightscout.androidaps.plugins.bus.RxBus;
|
||||
import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin;
|
||||
import info.nightscout.androidaps.queue.Callback;
|
||||
|
||||
public class ActionLoopDisable extends Action {
|
||||
@Override
|
||||
public int friendlyName() {
|
||||
return R.string.disableloop;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String shortDescription() {
|
||||
return MainApp.gs(R.string.disableloop);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doAction(Callback callback) {
|
||||
if (LoopPlugin.getPlugin().isEnabled(PluginType.LOOP)) {
|
||||
LoopPlugin.getPlugin().setPluginEnabled(PluginType.LOOP, false);
|
||||
ConfigBuilderPlugin.getPlugin().storeSettings("ActionLoopDisable");
|
||||
ConfigBuilderPlugin.getPlugin().getCommandQueue().cancelTempBasal(true, new Callback() {
|
||||
@Override
|
||||
public void run() {
|
||||
RxBus.INSTANCE.send(new EventRefreshOverview("ActionLoopDisable"));
|
||||
if (callback != null)
|
||||
callback.result(result).run();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
if (callback != null)
|
||||
callback.result(new PumpEnactResult().success(true).comment(R.string.alreadydisabled)).run();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Integer> icon() {
|
||||
return Optional.of(R.drawable.ic_stop_24dp);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
package info.nightscout.androidaps.plugins.general.automation.actions;
|
||||
|
||||
import com.google.common.base.Optional;
|
||||
|
||||
import info.nightscout.androidaps.MainApp;
|
||||
import info.nightscout.androidaps.R;
|
||||
import info.nightscout.androidaps.data.PumpEnactResult;
|
||||
import info.nightscout.androidaps.events.EventRefreshOverview;
|
||||
import info.nightscout.androidaps.interfaces.PluginType;
|
||||
import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin;
|
||||
import info.nightscout.androidaps.plugins.bus.RxBus;
|
||||
import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin;
|
||||
import info.nightscout.androidaps.queue.Callback;
|
||||
|
||||
public class ActionLoopEnable extends Action {
|
||||
@Override
|
||||
public int friendlyName() {
|
||||
return R.string.enableloop;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String shortDescription() {
|
||||
return MainApp.gs(R.string.enableloop);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doAction(Callback callback) {
|
||||
if (!LoopPlugin.getPlugin().isEnabled(PluginType.LOOP)) {
|
||||
LoopPlugin.getPlugin().setPluginEnabled(PluginType.LOOP, true);
|
||||
ConfigBuilderPlugin.getPlugin().storeSettings("ActionLoopEnable");
|
||||
RxBus.INSTANCE.send(new EventRefreshOverview("ActionLoopEnable"));
|
||||
if (callback != null)
|
||||
callback.result(new PumpEnactResult().success(true).comment(R.string.ok)).run();
|
||||
} else {
|
||||
if (callback != null)
|
||||
callback.result(new PumpEnactResult().success(true).comment(R.string.alreadyenabled)).run();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Integer> icon() {
|
||||
return Optional.of(R.drawable.ic_play_circle_outline_24dp);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
package info.nightscout.androidaps.plugins.general.automation.actions;
|
||||
|
||||
import com.google.common.base.Optional;
|
||||
|
||||
import info.nightscout.androidaps.MainApp;
|
||||
import info.nightscout.androidaps.R;
|
||||
import info.nightscout.androidaps.data.PumpEnactResult;
|
||||
import info.nightscout.androidaps.events.EventRefreshOverview;
|
||||
import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin;
|
||||
import info.nightscout.androidaps.plugins.bus.RxBus;
|
||||
import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin;
|
||||
import info.nightscout.androidaps.plugins.general.nsclient.NSUpload;
|
||||
import info.nightscout.androidaps.queue.Callback;
|
||||
|
||||
public class ActionLoopResume extends Action {
|
||||
@Override
|
||||
public int friendlyName() {
|
||||
return R.string.resumeloop;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String shortDescription() {
|
||||
return MainApp.gs(R.string.resumeloop);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doAction(Callback callback) {
|
||||
if (LoopPlugin.getPlugin().isSuspended()) {
|
||||
LoopPlugin.getPlugin().suspendTo(0);
|
||||
ConfigBuilderPlugin.getPlugin().storeSettings("ActionLoopResume");
|
||||
NSUpload.uploadOpenAPSOffline(0);
|
||||
RxBus.INSTANCE.send(new EventRefreshOverview("ActionLoopResume"));
|
||||
if (callback != null)
|
||||
callback.result(new PumpEnactResult().success(true).comment(R.string.ok)).run();
|
||||
} else {
|
||||
if (callback != null)
|
||||
callback.result(new PumpEnactResult().success(true).comment(R.string.notsuspended)).run();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Integer> icon() {
|
||||
return Optional.of(R.drawable.ic_replay_24dp);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,91 @@
|
|||
package info.nightscout.androidaps.plugins.general.automation.actions;
|
||||
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import com.google.common.base.Optional;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import info.nightscout.androidaps.MainApp;
|
||||
import info.nightscout.androidaps.R;
|
||||
import info.nightscout.androidaps.data.PumpEnactResult;
|
||||
import info.nightscout.androidaps.events.EventRefreshOverview;
|
||||
import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin;
|
||||
import info.nightscout.androidaps.plugins.bus.RxBus;
|
||||
import info.nightscout.androidaps.plugins.general.automation.elements.InputDuration;
|
||||
import info.nightscout.androidaps.plugins.general.automation.elements.LabelWithElement;
|
||||
import info.nightscout.androidaps.plugins.general.automation.elements.LayoutBuilder;
|
||||
import info.nightscout.androidaps.queue.Callback;
|
||||
import info.nightscout.androidaps.utils.JsonHelper;
|
||||
|
||||
public class ActionLoopSuspend extends Action {
|
||||
public InputDuration minutes = new InputDuration(0, InputDuration.TimeUnit.MINUTES);
|
||||
|
||||
@Override
|
||||
public int friendlyName() {
|
||||
return R.string.suspendloop;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String shortDescription() {
|
||||
return MainApp.gs(R.string.suspendloopforXmin, minutes.getMinutes());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doAction(Callback callback) {
|
||||
if (!LoopPlugin.getPlugin().isSuspended()) {
|
||||
LoopPlugin.getPlugin().suspendLoop(minutes.getMinutes());
|
||||
RxBus.INSTANCE.send(new EventRefreshOverview("ActionLoopSuspend"));
|
||||
if (callback != null)
|
||||
callback.result(new PumpEnactResult().success(true).comment(R.string.ok)).run();
|
||||
} else {
|
||||
if (callback != null)
|
||||
callback.result(new PumpEnactResult().success(true).comment(R.string.alreadysuspended)).run();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Integer> icon() {
|
||||
return Optional.of(R.drawable.ic_pause_circle_outline_24dp);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toJSON() {
|
||||
JSONObject o = new JSONObject();
|
||||
JSONObject data = new JSONObject();
|
||||
try {
|
||||
data.put("minutes", minutes.getMinutes());
|
||||
o.put("type", this.getClass().getName());
|
||||
o.put("data", data);
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return o.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Action fromJSON(String data) {
|
||||
try {
|
||||
JSONObject o = new JSONObject(data);
|
||||
minutes.setMinutes(JsonHelper.safeGetInt(o, "minutes"));
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasDialog() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generateDialog(LinearLayout root) {
|
||||
|
||||
new LayoutBuilder()
|
||||
.add(new LabelWithElement(MainApp.gs(R.string.careportal_newnstreatment_duration_min_label), "", minutes))
|
||||
.build(root);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,91 @@
|
|||
package info.nightscout.androidaps.plugins.general.automation.actions;
|
||||
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import com.google.common.base.Optional;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import info.nightscout.androidaps.MainApp;
|
||||
import info.nightscout.androidaps.R;
|
||||
import info.nightscout.androidaps.data.PumpEnactResult;
|
||||
import info.nightscout.androidaps.events.EventRefreshOverview;
|
||||
import info.nightscout.androidaps.plugins.bus.RxBus;
|
||||
import info.nightscout.androidaps.plugins.general.automation.elements.InputString;
|
||||
import info.nightscout.androidaps.plugins.general.automation.elements.LabelWithElement;
|
||||
import info.nightscout.androidaps.plugins.general.automation.elements.LayoutBuilder;
|
||||
import info.nightscout.androidaps.plugins.general.nsclient.NSUpload;
|
||||
import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification;
|
||||
import info.nightscout.androidaps.plugins.general.overview.notifications.Notification;
|
||||
import info.nightscout.androidaps.queue.Callback;
|
||||
import info.nightscout.androidaps.utils.JsonHelper;
|
||||
|
||||
public class ActionNotification extends Action {
|
||||
public InputString text = new InputString();
|
||||
|
||||
@Override
|
||||
public int friendlyName() {
|
||||
return R.string.notification;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String shortDescription() {
|
||||
return MainApp.gs(R.string.notification_message, text.getValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doAction(Callback callback) {
|
||||
Notification notification = new Notification(Notification.USERMESSAGE, text.getValue(), Notification.URGENT);
|
||||
RxBus.INSTANCE.send(new EventNewNotification(notification));
|
||||
NSUpload.uploadError(text.getValue());
|
||||
RxBus.INSTANCE.send(new EventRefreshOverview("ActionNotification"));
|
||||
if (callback != null)
|
||||
callback.result(new PumpEnactResult().success(true).comment(R.string.ok)).run();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Integer> icon() {
|
||||
return Optional.of(R.drawable.ic_notifications);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toJSON() {
|
||||
JSONObject o = new JSONObject();
|
||||
JSONObject data = new JSONObject();
|
||||
try {
|
||||
data.put("text", text.getValue());
|
||||
o.put("type", this.getClass().getName());
|
||||
o.put("data", data);
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return o.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Action fromJSON(String data) {
|
||||
try {
|
||||
JSONObject o = new JSONObject(data);
|
||||
text.setValue(JsonHelper.safeGetString(o, "text"));
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasDialog() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generateDialog(LinearLayout root) {
|
||||
|
||||
new LayoutBuilder()
|
||||
.add(new LabelWithElement(MainApp.gs(R.string.message_short), "", text))
|
||||
.build(root);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,95 @@
|
|||
package info.nightscout.androidaps.plugins.general.automation.actions;
|
||||
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import com.google.common.base.Optional;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import info.nightscout.androidaps.MainApp;
|
||||
import info.nightscout.androidaps.R;
|
||||
import info.nightscout.androidaps.data.PumpEnactResult;
|
||||
import info.nightscout.androidaps.plugins.configBuilder.ProfileFunctions;
|
||||
import info.nightscout.androidaps.plugins.general.automation.elements.Comparator;
|
||||
import info.nightscout.androidaps.plugins.general.automation.elements.InputDuration;
|
||||
import info.nightscout.androidaps.plugins.general.automation.elements.InputPercent;
|
||||
import info.nightscout.androidaps.plugins.general.automation.elements.LabelWithElement;
|
||||
import info.nightscout.androidaps.plugins.general.automation.elements.LayoutBuilder;
|
||||
import info.nightscout.androidaps.plugins.general.automation.triggers.TriggerProfilePercent;
|
||||
import info.nightscout.androidaps.queue.Callback;
|
||||
import info.nightscout.androidaps.utils.JsonHelper;
|
||||
|
||||
public class ActionProfileSwitchPercent extends Action {
|
||||
InputPercent pct = new InputPercent();
|
||||
InputDuration duration = new InputDuration(0, InputDuration.TimeUnit.MINUTES);
|
||||
|
||||
public ActionProfileSwitchPercent() {
|
||||
precondition = new TriggerProfilePercent().comparator(Comparator.Compare.IS_EQUAL).setValue(100);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int friendlyName() {
|
||||
return R.string.profilepercentage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String shortDescription() {
|
||||
if (duration.getMinutes() == 0)
|
||||
return MainApp.gs(R.string.startprofileforever, (int) pct.getValue());
|
||||
else
|
||||
return MainApp.gs(R.string.startprofile, (int) pct.getValue(), duration.getMinutes());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doAction(Callback callback) {
|
||||
ProfileFunctions.doProfileSwitch((int) duration.getValue(), (int) pct.getValue(), 0);
|
||||
if (callback != null)
|
||||
callback.result(new PumpEnactResult().success(true).comment(R.string.ok)).run();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generateDialog(LinearLayout root) {
|
||||
new LayoutBuilder()
|
||||
.add(new LabelWithElement(MainApp.gs(R.string.percent_u), "", pct))
|
||||
.add(new LabelWithElement(MainApp.gs(R.string.careportal_newnstreatment_duration_min_label), "", duration))
|
||||
.build(root);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasDialog() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toJSON() {
|
||||
JSONObject o = new JSONObject();
|
||||
try {
|
||||
o.put("type", ActionProfileSwitchPercent.class.getName());
|
||||
JSONObject data = new JSONObject();
|
||||
data.put("percentage", pct.getValue());
|
||||
data.put("durationInMinutes", duration.getMinutes());
|
||||
o.put("data", data);
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return o.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Action fromJSON(String data) {
|
||||
try {
|
||||
JSONObject d = new JSONObject(data);
|
||||
pct.setValue(JsonHelper.safeGetInt(d, "percentage"));
|
||||
duration.setMinutes(JsonHelper.safeGetInt(d, "durationInMinutes"));
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Integer> icon() {
|
||||
return Optional.of(R.drawable.icon_actions_profileswitch);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,119 @@
|
|||
package info.nightscout.androidaps.plugins.general.automation.actions;
|
||||
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import com.google.common.base.Optional;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import info.nightscout.androidaps.Constants;
|
||||
import info.nightscout.androidaps.MainApp;
|
||||
import info.nightscout.androidaps.R;
|
||||
import info.nightscout.androidaps.data.Profile;
|
||||
import info.nightscout.androidaps.data.PumpEnactResult;
|
||||
import info.nightscout.androidaps.db.Source;
|
||||
import info.nightscout.androidaps.db.TempTarget;
|
||||
import info.nightscout.androidaps.plugins.general.automation.elements.ComparatorExists;
|
||||
import info.nightscout.androidaps.plugins.general.automation.elements.InputBg;
|
||||
import info.nightscout.androidaps.plugins.general.automation.elements.InputDuration;
|
||||
import info.nightscout.androidaps.plugins.general.automation.elements.LabelWithElement;
|
||||
import info.nightscout.androidaps.plugins.general.automation.elements.LayoutBuilder;
|
||||
import info.nightscout.androidaps.plugins.general.automation.triggers.TriggerTempTarget;
|
||||
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin;
|
||||
import info.nightscout.androidaps.queue.Callback;
|
||||
import info.nightscout.androidaps.utils.DateUtil;
|
||||
import info.nightscout.androidaps.utils.JsonHelper;
|
||||
|
||||
public class ActionStartTempTarget extends Action {
|
||||
String reason = "";
|
||||
InputBg value = new InputBg();
|
||||
InputDuration duration = new InputDuration(0, InputDuration.TimeUnit.MINUTES);
|
||||
private TempTarget tempTarget;
|
||||
|
||||
public ActionStartTempTarget() {
|
||||
precondition = new TriggerTempTarget().comparator(ComparatorExists.Compare.NOT_EXISTS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int friendlyName() {
|
||||
return R.string.starttemptarget;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String shortDescription() {
|
||||
tempTarget = new TempTarget()
|
||||
.date(DateUtil.now())
|
||||
.duration(duration.getMinutes())
|
||||
.reason(reason)
|
||||
.source(Source.USER)
|
||||
.low(Profile.toMgdl(value.getValue(), value.getUnits()))
|
||||
.high(Profile.toMgdl(value.getValue(), value.getUnits()));
|
||||
return MainApp.gs(R.string.starttemptarget) + ": " + (tempTarget == null ? "null" : tempTarget.friendlyDescription(value.getUnits()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doAction(Callback callback) {
|
||||
tempTarget = new TempTarget()
|
||||
.date(DateUtil.now())
|
||||
.duration(duration.getMinutes())
|
||||
.reason(reason)
|
||||
.source(Source.USER)
|
||||
.low(Profile.toMgdl(value.getValue(), value.getUnits()))
|
||||
.high(Profile.toMgdl(value.getValue(), value.getUnits()));
|
||||
TreatmentsPlugin.getPlugin().addToHistoryTempTarget(tempTarget);
|
||||
if (callback != null)
|
||||
callback.result(new PumpEnactResult().success(true).comment(R.string.ok)).run();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generateDialog(LinearLayout root) {
|
||||
int unitResId = value.getUnits().equals(Constants.MGDL) ? R.string.mgdl : R.string.mmol;
|
||||
|
||||
new LayoutBuilder()
|
||||
.add(new LabelWithElement(MainApp.gs(R.string.careportal_temporarytarget), MainApp.gs(unitResId), value))
|
||||
.add(new LabelWithElement(MainApp.gs(R.string.careportal_newnstreatment_duration_min_label), "", duration))
|
||||
.build(root);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasDialog() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toJSON() {
|
||||
JSONObject o = new JSONObject();
|
||||
try {
|
||||
o.put("type", ActionStartTempTarget.class.getName());
|
||||
JSONObject data = new JSONObject();
|
||||
data.put("reason", reason);
|
||||
data.put("value", value.getValue());
|
||||
data.put("units", value.getUnits());
|
||||
data.put("durationInMinutes", duration.getMinutes());
|
||||
o.put("data", data);
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return o.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Action fromJSON(String data) {
|
||||
try {
|
||||
JSONObject d = new JSONObject(data);
|
||||
reason = JsonHelper.safeGetString(d, "reason");
|
||||
value.setUnits(JsonHelper.safeGetString(d, "units"));
|
||||
value.setValue(JsonHelper.safeGetDouble(d, "value"));
|
||||
duration.setMinutes(JsonHelper.safeGetInt(d, "durationInMinutes"));
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Integer> icon() {
|
||||
return Optional.of(R.drawable.icon_cp_cgm_target);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
package info.nightscout.androidaps.plugins.general.automation.actions;
|
||||
|
||||
import com.google.common.base.Optional;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import info.nightscout.androidaps.MainApp;
|
||||
import info.nightscout.androidaps.R;
|
||||
import info.nightscout.androidaps.data.PumpEnactResult;
|
||||
import info.nightscout.androidaps.db.Source;
|
||||
import info.nightscout.androidaps.db.TempTarget;
|
||||
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin;
|
||||
import info.nightscout.androidaps.queue.Callback;
|
||||
import info.nightscout.androidaps.utils.DateUtil;
|
||||
import info.nightscout.androidaps.utils.JsonHelper;
|
||||
|
||||
public class ActionStopTempTarget extends Action {
|
||||
String reason = "";
|
||||
private TempTarget tempTarget;
|
||||
|
||||
public ActionStopTempTarget() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int friendlyName() {
|
||||
return R.string.stoptemptarget;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String shortDescription() {
|
||||
return MainApp.gs(R.string.stoptemptarget);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doAction(Callback callback) {
|
||||
tempTarget = new TempTarget().date(DateUtil.now()).duration(0).reason(reason).source(Source.USER).low(0).high(0);
|
||||
TreatmentsPlugin.getPlugin().addToHistoryTempTarget(tempTarget);
|
||||
if (callback != null)
|
||||
callback.result(new PumpEnactResult().success(true).comment(R.string.ok)).run();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasDialog() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toJSON() {
|
||||
JSONObject o = new JSONObject();
|
||||
try {
|
||||
o.put("type", ActionStopTempTarget.class.getName());
|
||||
JSONObject data = new JSONObject();
|
||||
data.put("reason", reason);
|
||||
o.put("data", data);
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return o.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Action fromJSON(String data) {
|
||||
try {
|
||||
JSONObject d = new JSONObject(data);
|
||||
reason = JsonHelper.safeGetString(d, "reason");
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Integer> icon() {
|
||||
return Optional.of(R.drawable.ic_stop_24dp);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
package info.nightscout.androidaps.plugins.general.automation.dialogs
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.ImageView
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.TextView
|
||||
import androidx.fragment.app.FragmentManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.plugins.bus.RxBus
|
||||
import info.nightscout.androidaps.plugins.general.automation.actions.Action
|
||||
import info.nightscout.androidaps.plugins.general.automation.events.EventAutomationUpdateGui
|
||||
|
||||
class ActionListAdapter(private val fragmentManager: FragmentManager, private val actionList: MutableList<Action>) : RecyclerView.Adapter<ActionListAdapter.ViewHolder>() {
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
||||
val v = LayoutInflater.from(parent.context).inflate(R.layout.automation_action_item, parent, false)
|
||||
return ViewHolder(v)
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||
val action = actionList[position]
|
||||
holder.bind(action, fragmentManager, this, position, actionList)
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int {
|
||||
return actionList.size
|
||||
}
|
||||
|
||||
class ViewHolder(val view: View) : RecyclerView.ViewHolder(view) {
|
||||
|
||||
fun bind(action: Action, fragmentManager: FragmentManager, recyclerView: RecyclerView.Adapter<ViewHolder>, position : Int, actionList: MutableList<Action>) {
|
||||
view.findViewById<LinearLayout>(R.id.automation_layoutText).setOnClickListener {
|
||||
if (action.hasDialog()) {
|
||||
val args = Bundle()
|
||||
args.putInt("actionPosition", position)
|
||||
args.putString("action", action.toJSON())
|
||||
val dialog = EditActionDialog()
|
||||
dialog.arguments = args
|
||||
dialog.show(fragmentManager, "EditActionDialog")
|
||||
}
|
||||
}
|
||||
view.findViewById<ImageView>(R.id.automation_iconTrash).setOnClickListener {
|
||||
actionList.remove(action)
|
||||
recyclerView.notifyDataSetChanged()
|
||||
RxBus.send(EventAutomationUpdateGui())
|
||||
}
|
||||
view.findViewById<TextView>(R.id.automation_viewActionTitle).text = action.shortDescription()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
package info.nightscout.androidaps.plugins.general.automation.dialogs
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.RadioButton
|
||||
import androidx.fragment.app.DialogFragment
|
||||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.plugins.bus.RxBus
|
||||
import info.nightscout.androidaps.plugins.general.automation.AutomationPlugin
|
||||
import info.nightscout.androidaps.plugins.general.automation.actions.Action
|
||||
import info.nightscout.androidaps.plugins.general.automation.events.EventAutomationAddAction
|
||||
import info.nightscout.androidaps.plugins.general.automation.events.EventAutomationUpdateGui
|
||||
import kotlinx.android.synthetic.main.automation_dialog_choose_action.*
|
||||
import kotlinx.android.synthetic.main.okcancel.*
|
||||
|
||||
class ChooseActionDialog : DialogFragment() {
|
||||
|
||||
var checkedIndex = -1
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
|
||||
savedInstanceState: Bundle?): View? {
|
||||
// restore checked radio button
|
||||
savedInstanceState?.let { bundle ->
|
||||
checkedIndex = bundle.getInt("checkedIndex")
|
||||
}
|
||||
|
||||
dialog.setCanceledOnTouchOutside(false)
|
||||
return inflater.inflate(R.layout.automation_dialog_choose_action, container, false)
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
for (a in AutomationPlugin.getActionDummyObjects()) {
|
||||
val radioButton = RadioButton(context)
|
||||
radioButton.setText(a.friendlyName())
|
||||
radioButton.tag = a.javaClass
|
||||
automation_radioGroup.addView(radioButton)
|
||||
}
|
||||
|
||||
if (checkedIndex != -1)
|
||||
(automation_radioGroup.getChildAt(checkedIndex) as RadioButton).isChecked = true
|
||||
|
||||
// OK button
|
||||
ok.setOnClickListener {
|
||||
dismiss()
|
||||
instantiateAction()?.let {
|
||||
RxBus.send(EventAutomationAddAction(it))
|
||||
RxBus.send(EventAutomationUpdateGui())
|
||||
}
|
||||
}
|
||||
|
||||
// Cancel button
|
||||
cancel.setOnClickListener { dismiss() }
|
||||
}
|
||||
|
||||
override fun onSaveInstanceState(bundle: Bundle) {
|
||||
bundle.putInt("checkedIndex", determineCheckedIndex())
|
||||
}
|
||||
|
||||
private fun instantiateAction(): Action? {
|
||||
return getActionClass()?.let {
|
||||
it.newInstance() as Action
|
||||
}
|
||||
}
|
||||
|
||||
private fun getActionClass(): Class<*>? {
|
||||
val radioButtonID = automation_radioGroup.checkedRadioButtonId
|
||||
val radioButton = automation_radioGroup.findViewById<RadioButton>(radioButtonID)
|
||||
return radioButton?.let {
|
||||
it.tag as Class<*>
|
||||
}
|
||||
}
|
||||
|
||||
private fun determineCheckedIndex(): Int {
|
||||
for (i in 0 until automation_radioGroup.childCount) {
|
||||
if ((automation_radioGroup.getChildAt(i) as RadioButton).isChecked)
|
||||
return i
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,89 @@
|
|||
package info.nightscout.androidaps.plugins.general.automation.dialogs
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.RadioButton
|
||||
import androidx.fragment.app.DialogFragment
|
||||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.plugins.general.automation.AutomationPlugin
|
||||
import info.nightscout.androidaps.plugins.general.automation.triggers.Trigger
|
||||
import kotlinx.android.synthetic.main.automation_dialog_choose_trigger.*
|
||||
import kotlinx.android.synthetic.main.okcancel.*
|
||||
|
||||
class ChooseTriggerDialog : DialogFragment() {
|
||||
|
||||
private var checkedIndex = -1
|
||||
|
||||
private var clickListener: OnClickListener? = null
|
||||
|
||||
interface OnClickListener {
|
||||
fun onClick(newTriggerObject: Trigger?)
|
||||
}
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
|
||||
savedInstanceState: Bundle?): View? {
|
||||
// restore checked radio button
|
||||
savedInstanceState?.let { bundle ->
|
||||
checkedIndex = bundle.getInt("checkedIndex")
|
||||
}
|
||||
|
||||
dialog.setCanceledOnTouchOutside(false)
|
||||
return inflater.inflate(R.layout.automation_dialog_choose_trigger, container, false)
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
for (t in AutomationPlugin.getTriggerDummyObjects()) {
|
||||
val radioButton = RadioButton(context)
|
||||
radioButton.setText(t.friendlyName())
|
||||
radioButton.tag = t.javaClass
|
||||
automation_chooseTriggerRadioGroup.addView(radioButton)
|
||||
}
|
||||
|
||||
if (checkedIndex != -1)
|
||||
(automation_chooseTriggerRadioGroup.getChildAt(checkedIndex) as RadioButton).isChecked = true
|
||||
|
||||
// OK button
|
||||
ok.setOnClickListener {
|
||||
dismiss()
|
||||
clickListener?.onClick(instantiateTrigger())
|
||||
}
|
||||
|
||||
// Cancel button
|
||||
cancel.setOnClickListener { dismiss() }
|
||||
}
|
||||
|
||||
fun setOnClickListener(clickListener: OnClickListener) {
|
||||
this.clickListener = clickListener
|
||||
}
|
||||
|
||||
override fun onSaveInstanceState(bundle: Bundle) {
|
||||
bundle.putInt("checkedIndex", determineCheckedIndex())
|
||||
}
|
||||
|
||||
private fun instantiateTrigger(): Trigger? {
|
||||
return getTriggerClass()?.let {
|
||||
it.newInstance() as Trigger
|
||||
}
|
||||
}
|
||||
|
||||
private fun getTriggerClass(): Class<*>? {
|
||||
val radioButtonID = automation_chooseTriggerRadioGroup.checkedRadioButtonId
|
||||
val radioButton = automation_chooseTriggerRadioGroup.findViewById<RadioButton>(radioButtonID)
|
||||
return radioButton?.let {
|
||||
it.tag as Class<*>
|
||||
}
|
||||
}
|
||||
|
||||
private fun determineCheckedIndex(): Int {
|
||||
for (i in 0 until automation_chooseTriggerRadioGroup.childCount) {
|
||||
if ((automation_chooseTriggerRadioGroup.getChildAt(i) as RadioButton).isChecked)
|
||||
return i
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
package info.nightscout.androidaps.plugins.general.automation.dialogs
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.Button
|
||||
import androidx.fragment.app.DialogFragment
|
||||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.plugins.bus.RxBus
|
||||
import info.nightscout.androidaps.plugins.general.automation.actions.Action
|
||||
import info.nightscout.androidaps.plugins.general.automation.events.EventAutomationUpdateAction
|
||||
import kotlinx.android.synthetic.main.automation_dialog_action.*
|
||||
import kotlinx.android.synthetic.main.okcancel.*
|
||||
import org.json.JSONObject
|
||||
|
||||
class EditActionDialog : DialogFragment() {
|
||||
|
||||
private var action: Action? = null
|
||||
private var actionPosition: Int = -1
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
|
||||
savedInstanceState: Bundle?): View? {
|
||||
// load data from bundle
|
||||
(savedInstanceState ?: arguments)?.let { bundle ->
|
||||
actionPosition = bundle.getInt("actionPosition", -1)
|
||||
bundle.getString("action")?.let { action = Action.instantiate(JSONObject(it)) }
|
||||
}
|
||||
|
||||
dialog.setCanceledOnTouchOutside(false)
|
||||
return inflater.inflate(R.layout.automation_dialog_action, container, false)
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
action?.let {
|
||||
automation_actionTitle.setText(it.friendlyName())
|
||||
automation_editActionLayout.removeAllViews()
|
||||
it.generateDialog(automation_editActionLayout)
|
||||
}
|
||||
|
||||
// OK button
|
||||
ok.setOnClickListener {
|
||||
dismiss()
|
||||
action?.let {
|
||||
RxBus.send(EventAutomationUpdateAction(it, actionPosition))
|
||||
}
|
||||
}
|
||||
|
||||
// Cancel button
|
||||
cancel.setOnClickListener { dismiss() }
|
||||
}
|
||||
|
||||
override fun onSaveInstanceState(bundle: Bundle) {
|
||||
super.onSaveInstanceState(bundle)
|
||||
action?.let {
|
||||
bundle.putInt("actionPosition", actionPosition)
|
||||
bundle.putString("action", it.toJSON())
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,154 @@
|
|||
package info.nightscout.androidaps.plugins.general.automation.dialogs
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.fragment.app.DialogFragment
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.plugins.bus.RxBus
|
||||
import info.nightscout.androidaps.plugins.general.automation.AutomationEvent
|
||||
import info.nightscout.androidaps.plugins.general.automation.AutomationPlugin
|
||||
import info.nightscout.androidaps.plugins.general.automation.events.*
|
||||
import info.nightscout.androidaps.plugins.general.automation.triggers.TriggerConnector
|
||||
import info.nightscout.androidaps.utils.ToastUtils
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.disposables.CompositeDisposable
|
||||
import kotlinx.android.synthetic.main.automation_dialog_event.*
|
||||
import kotlinx.android.synthetic.main.okcancel.*
|
||||
|
||||
class EditEventDialog : DialogFragment() {
|
||||
|
||||
private var actionListAdapter: ActionListAdapter? = null
|
||||
private var event: AutomationEvent = AutomationEvent()
|
||||
private var position: Int = -1
|
||||
|
||||
private var disposable: CompositeDisposable = CompositeDisposable()
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
|
||||
savedInstanceState: Bundle?): View? {
|
||||
// load data from bundle
|
||||
(savedInstanceState ?: arguments)?.let { bundle ->
|
||||
position = bundle.getInt("position", -1)
|
||||
bundle.getString("event")?.let { event = AutomationEvent().fromJSON(it) }
|
||||
}
|
||||
|
||||
dialog.setCanceledOnTouchOutside(false)
|
||||
return inflater.inflate(R.layout.automation_dialog_event, container, false)
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
automation_inputEventTitle.setText(event.title)
|
||||
automation_triggerDescription.text = event.trigger.friendlyDescription()
|
||||
|
||||
automation_editTrigger.setOnClickListener {
|
||||
val args = Bundle()
|
||||
args.putString("trigger", event.trigger.toJSON())
|
||||
val dialog = EditTriggerDialog()
|
||||
dialog.arguments = args
|
||||
fragmentManager?.let { dialog.show(it, "EditTriggerDialog") }
|
||||
}
|
||||
|
||||
// setup action list view
|
||||
fragmentManager?.let { actionListAdapter = ActionListAdapter(it, event.actions) }
|
||||
automation_actionListView.layoutManager = LinearLayoutManager(context)
|
||||
automation_actionListView.adapter = actionListAdapter
|
||||
|
||||
automation_addAction.setOnClickListener { fragmentManager?.let { ChooseActionDialog().show(it, "ChooseActionDialog") } }
|
||||
|
||||
// OK button
|
||||
ok.setOnClickListener {
|
||||
// check for title
|
||||
val title = automation_inputEventTitle.text.toString()
|
||||
if (title.isEmpty()) {
|
||||
ToastUtils.showToastInUiThread(context, R.string.automation_missing_task_name)
|
||||
return@setOnClickListener
|
||||
}
|
||||
event.title = title
|
||||
// check for at least one trigger
|
||||
val con = event.trigger as TriggerConnector
|
||||
if (con.size() == 0) {
|
||||
ToastUtils.showToastInUiThread(context, R.string.automation_missing_trigger)
|
||||
return@setOnClickListener
|
||||
}
|
||||
// check for at least one action
|
||||
if (event.actions.isEmpty()) {
|
||||
ToastUtils.showToastInUiThread(context, R.string.automation_missing_action)
|
||||
return@setOnClickListener
|
||||
}
|
||||
// store
|
||||
if (position == -1)
|
||||
AutomationPlugin.automationEvents.add(event)
|
||||
else
|
||||
AutomationPlugin.automationEvents[position] = event
|
||||
|
||||
dismiss()
|
||||
RxBus.send(EventAutomationDataChanged())
|
||||
}
|
||||
|
||||
// Cancel button
|
||||
cancel.setOnClickListener { dismiss() }
|
||||
|
||||
showPreconditions()
|
||||
|
||||
disposable.add(RxBus
|
||||
.toObservable(EventAutomationUpdateGui::class.java)
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe({
|
||||
actionListAdapter?.notifyDataSetChanged()
|
||||
showPreconditions()
|
||||
}, {})
|
||||
)
|
||||
disposable.add(RxBus
|
||||
.toObservable(EventAutomationAddAction::class.java)
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe({
|
||||
event.addAction(it.action)
|
||||
actionListAdapter?.notifyDataSetChanged()
|
||||
}, {})
|
||||
)
|
||||
disposable.add(RxBus
|
||||
.toObservable(EventAutomationUpdateTrigger::class.java)
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe({
|
||||
event.trigger = it.trigger
|
||||
automation_triggerDescription.text = event.trigger.friendlyDescription()
|
||||
}, {})
|
||||
)
|
||||
disposable.add(RxBus
|
||||
.toObservable(EventAutomationUpdateAction::class.java)
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe({
|
||||
event.actions[it.position] = it.action
|
||||
actionListAdapter?.notifyDataSetChanged()
|
||||
}, {})
|
||||
)
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
super.onDestroyView()
|
||||
disposable.clear()
|
||||
}
|
||||
|
||||
override fun onSaveInstanceState(bundle: Bundle) {
|
||||
super.onSaveInstanceState(bundle)
|
||||
bundle.putString("event", event.toJSON())
|
||||
bundle.putInt("position", position)
|
||||
}
|
||||
|
||||
private fun showPreconditions() {
|
||||
val forcedTriggers = event.preconditions
|
||||
if (forcedTriggers.size() > 0) {
|
||||
automation_forcedTriggerDescription.visibility = View.VISIBLE
|
||||
automation_forcedTriggerDescriptionLabel.visibility = View.VISIBLE
|
||||
automation_forcedTriggerDescription.text = forcedTriggers.friendlyDescription()
|
||||
} else {
|
||||
automation_forcedTriggerDescription.visibility = View.GONE
|
||||
automation_forcedTriggerDescriptionLabel.visibility = View.GONE
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
package info.nightscout.androidaps.plugins.general.automation.dialogs
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.fragment.app.DialogFragment
|
||||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.plugins.bus.RxBus
|
||||
import info.nightscout.androidaps.plugins.general.automation.events.EventAutomationUpdateTrigger
|
||||
import info.nightscout.androidaps.plugins.general.automation.triggers.Trigger
|
||||
import kotlinx.android.synthetic.main.automation_dialog_edit_trigger.*
|
||||
import kotlinx.android.synthetic.main.okcancel.*
|
||||
|
||||
class EditTriggerDialog : DialogFragment() {
|
||||
|
||||
private var trigger: Trigger? = null
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
|
||||
savedInstanceState: Bundle?): View? {
|
||||
// load data from bundle
|
||||
(savedInstanceState ?: arguments)?.let { bundle ->
|
||||
bundle.getString("trigger")?.let { trigger = Trigger.instantiate(it) }
|
||||
}
|
||||
|
||||
dialog.setCanceledOnTouchOutside(false)
|
||||
return inflater.inflate(R.layout.automation_dialog_edit_trigger, container, false)
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
// display root trigger
|
||||
trigger?.let { it.generateDialog(automation_layoutTrigger, fragmentManager) }
|
||||
|
||||
// OK button
|
||||
ok.setOnClickListener {
|
||||
dismiss()
|
||||
RxBus.send(EventAutomationUpdateTrigger(trigger!!))
|
||||
}
|
||||
|
||||
// Cancel button
|
||||
cancel.setOnClickListener { dismiss() }
|
||||
}
|
||||
|
||||
override fun onSaveInstanceState(bundle: Bundle) {
|
||||
super.onSaveInstanceState(bundle)
|
||||
trigger?.let { bundle.putString("trigger", it.toJSON()) }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,186 @@
|
|||
package info.nightscout.androidaps.plugins.general.automation.dialogs;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.Button;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.Spinner;
|
||||
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
|
||||
import info.nightscout.androidaps.MainApp;
|
||||
import info.nightscout.androidaps.R;
|
||||
import info.nightscout.androidaps.plugins.general.automation.triggers.Trigger;
|
||||
import info.nightscout.androidaps.plugins.general.automation.triggers.TriggerConnector;
|
||||
|
||||
public class TriggerListAdapter {
|
||||
private final LinearLayout mRootLayout;
|
||||
private final FragmentManager mFragmentManager;
|
||||
private final Context mContext;
|
||||
private final TriggerConnector mRootConnector;
|
||||
|
||||
public TriggerListAdapter(FragmentManager fragmentManager, Context context, LinearLayout rootLayout, TriggerConnector rootTrigger) {
|
||||
mRootLayout = rootLayout;
|
||||
mFragmentManager = fragmentManager;
|
||||
mContext = context;
|
||||
mRootConnector = rootTrigger;
|
||||
build(fragmentManager);
|
||||
}
|
||||
|
||||
public Context getContext() {
|
||||
return mContext;
|
||||
}
|
||||
|
||||
private FragmentManager getFM() {
|
||||
return mFragmentManager;
|
||||
}
|
||||
|
||||
private void destroy() {
|
||||
mRootLayout.removeAllViews();
|
||||
}
|
||||
|
||||
private void build(FragmentManager fragmentManager) {
|
||||
for (int i = 0; i < mRootConnector.size(); ++i) {
|
||||
final Trigger trigger = mRootConnector.get(i);
|
||||
|
||||
// spinner
|
||||
if (i > 0) {
|
||||
createSpinner(trigger);
|
||||
}
|
||||
|
||||
// trigger layout
|
||||
trigger.generateDialog(mRootLayout, fragmentManager);
|
||||
|
||||
// buttons
|
||||
createButtons(fragmentManager, trigger);
|
||||
}
|
||||
|
||||
if (mRootConnector.size() == 0) {
|
||||
Button buttonAdd = new Button(mContext);
|
||||
buttonAdd.setText(MainApp.gs(R.string.addnew));
|
||||
buttonAdd.setOnClickListener(v -> {
|
||||
ChooseTriggerDialog dialog = new ChooseTriggerDialog();
|
||||
dialog.setOnClickListener(newTriggerObject -> {
|
||||
mRootConnector.add(newTriggerObject);
|
||||
rebuild(fragmentManager);
|
||||
});
|
||||
dialog.show(fragmentManager, "ChooseTriggerDialog");
|
||||
});
|
||||
mRootLayout.addView(buttonAdd);
|
||||
}
|
||||
}
|
||||
|
||||
private Spinner createSpinner() {
|
||||
Spinner spinner = new Spinner(mContext);
|
||||
ArrayAdapter<String> spinnerArrayAdapter = new ArrayAdapter<>(mContext, android.R.layout.simple_spinner_item, TriggerConnector.Type.labels());
|
||||
spinnerArrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
|
||||
spinner.setAdapter(spinnerArrayAdapter);
|
||||
return spinner;
|
||||
}
|
||||
|
||||
private void createSpinner(Trigger trigger) {
|
||||
final TriggerConnector connector = trigger.getConnector();
|
||||
final int initialPosition = connector.getConnectorType().ordinal();
|
||||
Spinner spinner = createSpinner();
|
||||
spinner.setSelection(initialPosition);
|
||||
spinner.setBackgroundColor(MainApp.gc(R.color.black_overlay));
|
||||
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
|
||||
LinearLayout.LayoutParams.MATCH_PARENT,
|
||||
LinearLayout.LayoutParams.WRAP_CONTENT
|
||||
);
|
||||
params.setMargins(0, MainApp.dpToPx(8), 0, MainApp.dpToPx(8));
|
||||
spinner.setLayoutParams(params);
|
||||
spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
|
||||
@Override
|
||||
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
|
||||
if (position != initialPosition) {
|
||||
// connector type changed
|
||||
changeConnector(getFM(), trigger, connector, TriggerConnector.Type.values()[position]);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNothingSelected(AdapterView<?> parent) {
|
||||
}
|
||||
});
|
||||
mRootLayout.addView(spinner);
|
||||
}
|
||||
|
||||
private void createButtons(FragmentManager fragmentManager, Trigger trigger) {
|
||||
// do not create buttons for TriggerConnector
|
||||
if (trigger instanceof TriggerConnector) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Button Layout
|
||||
LinearLayout buttonLayout = new LinearLayout(mContext);
|
||||
buttonLayout.setOrientation(LinearLayout.HORIZONTAL);
|
||||
buttonLayout.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
|
||||
mRootLayout.addView(buttonLayout);
|
||||
|
||||
// Button [-]
|
||||
Button buttonRemove = new Button(mContext);
|
||||
buttonRemove.setText(MainApp.gs(R.string.delete_short));
|
||||
buttonRemove.setOnClickListener(v -> {
|
||||
final TriggerConnector connector = trigger.getConnector();
|
||||
connector.remove(trigger);
|
||||
connector.simplify().rebuildView(getFM());
|
||||
});
|
||||
buttonLayout.addView(buttonRemove);
|
||||
|
||||
// Button [+]
|
||||
Button buttonAdd = new Button(mContext);
|
||||
buttonAdd.setText(MainApp.gs(R.string.add_short));
|
||||
buttonAdd.setOnClickListener(v -> {
|
||||
ChooseTriggerDialog dialog = new ChooseTriggerDialog();
|
||||
dialog.show(fragmentManager, "ChooseTriggerDialog");
|
||||
dialog.setOnClickListener(newTriggerObject -> {
|
||||
TriggerConnector connector = trigger.getConnector();
|
||||
connector.add(connector.pos(trigger) + 1, newTriggerObject);
|
||||
connector.simplify().rebuildView(getFM());
|
||||
});
|
||||
});
|
||||
buttonLayout.addView(buttonAdd);
|
||||
|
||||
// Button [*]
|
||||
Button buttonCopy = new Button(mContext);
|
||||
buttonCopy.setText(MainApp.gs(R.string.copy_short));
|
||||
buttonCopy.setOnClickListener(v -> {
|
||||
TriggerConnector connector = trigger.getConnector();
|
||||
connector.add(connector.pos(trigger) + 1, trigger.duplicate());
|
||||
connector.simplify().rebuildView(getFM());
|
||||
});
|
||||
buttonLayout.addView(buttonCopy);
|
||||
}
|
||||
|
||||
public void rebuild(FragmentManager fragmentManager) {
|
||||
destroy();
|
||||
build(fragmentManager);
|
||||
}
|
||||
|
||||
public static void changeConnector(final FragmentManager fragmentManager, final Trigger trigger, final TriggerConnector connector, final TriggerConnector.Type newConnectorType) {
|
||||
if (connector.size() > 2) {
|
||||
// split connector
|
||||
int pos = connector.pos(trigger) - 1;
|
||||
|
||||
TriggerConnector newConnector = new TriggerConnector(newConnectorType);
|
||||
|
||||
// move trigger from pos and pos+1 into new connector
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
Trigger t = connector.get(pos);
|
||||
newConnector.add(t);
|
||||
connector.remove(t);
|
||||
}
|
||||
|
||||
connector.add(pos, newConnector);
|
||||
} else {
|
||||
connector.changeConnectorType(newConnectorType);
|
||||
}
|
||||
|
||||
connector.simplify().rebuildView(fragmentManager);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,123 @@
|
|||
package info.nightscout.androidaps.plugins.general.automation.elements;
|
||||
|
||||
import android.view.View;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.Spinner;
|
||||
|
||||
import androidx.annotation.StringRes;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import info.nightscout.androidaps.MainApp;
|
||||
import info.nightscout.androidaps.R;
|
||||
|
||||
public class Comparator extends Element {
|
||||
public enum Compare {
|
||||
IS_LESSER,
|
||||
IS_EQUAL_OR_LESSER,
|
||||
IS_EQUAL,
|
||||
IS_EQUAL_OR_GREATER,
|
||||
IS_GREATER,
|
||||
IS_NOT_AVAILABLE;
|
||||
|
||||
public @StringRes
|
||||
int getStringRes() {
|
||||
switch (this) {
|
||||
case IS_LESSER:
|
||||
return R.string.islesser;
|
||||
case IS_EQUAL_OR_LESSER:
|
||||
return R.string.isequalorlesser;
|
||||
case IS_EQUAL:
|
||||
return R.string.isequal;
|
||||
case IS_EQUAL_OR_GREATER:
|
||||
return R.string.isequalorgreater;
|
||||
case IS_GREATER:
|
||||
return R.string.isgreater;
|
||||
case IS_NOT_AVAILABLE:
|
||||
return R.string.isnotavailable;
|
||||
default:
|
||||
return R.string.unknown;
|
||||
}
|
||||
}
|
||||
|
||||
public <T extends Comparable> boolean check(T obj1, T obj2) {
|
||||
if (obj1 == null || obj2 == null)
|
||||
return this.equals(IS_NOT_AVAILABLE);
|
||||
|
||||
int comparison = obj1.compareTo(obj2);
|
||||
switch (this) {
|
||||
case IS_LESSER:
|
||||
return comparison < 0;
|
||||
case IS_EQUAL_OR_LESSER:
|
||||
return comparison <= 0;
|
||||
case IS_EQUAL:
|
||||
return comparison == 0;
|
||||
case IS_EQUAL_OR_GREATER:
|
||||
return comparison >= 0;
|
||||
case IS_GREATER:
|
||||
return comparison > 0;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static List<String> labels() {
|
||||
List<String> list = new ArrayList<>();
|
||||
for (Compare c : Compare.values()) {
|
||||
list.add(MainApp.gs(c.getStringRes()));
|
||||
}
|
||||
return list;
|
||||
}
|
||||
}
|
||||
|
||||
private Compare compare = Compare.IS_EQUAL;
|
||||
|
||||
public Comparator() {
|
||||
super();
|
||||
}
|
||||
|
||||
public Comparator(Comparator another) {
|
||||
super();
|
||||
compare = another.getValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addToLayout(LinearLayout root) {
|
||||
Spinner spinner = new Spinner(root.getContext());
|
||||
ArrayAdapter<String> spinnerArrayAdapter = new ArrayAdapter<>(root.getContext(), android.R.layout.simple_spinner_item, Compare.labels());
|
||||
spinnerArrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
|
||||
spinner.setAdapter(spinnerArrayAdapter);
|
||||
LinearLayout.LayoutParams spinnerParams = new LinearLayout.LayoutParams(
|
||||
LinearLayout.LayoutParams.MATCH_PARENT,
|
||||
LinearLayout.LayoutParams.WRAP_CONTENT
|
||||
);
|
||||
spinnerParams.setMargins(0, MainApp.dpToPx(4), 0, MainApp.dpToPx(4));
|
||||
spinner.setLayoutParams(spinnerParams);
|
||||
spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
|
||||
@Override
|
||||
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
|
||||
compare = Compare.values()[position];
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNothingSelected(AdapterView<?> parent) {
|
||||
}
|
||||
});
|
||||
spinner.setSelection(compare.ordinal());
|
||||
root.addView(spinner);
|
||||
|
||||
}
|
||||
|
||||
public Compare getValue() {
|
||||
return compare;
|
||||
}
|
||||
|
||||
public Comparator setValue(Compare compare) {
|
||||
this.compare = compare;
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,90 @@
|
|||
package info.nightscout.androidaps.plugins.general.automation.elements;
|
||||
|
||||
import android.view.View;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.Spinner;
|
||||
|
||||
import androidx.annotation.StringRes;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import info.nightscout.androidaps.MainApp;
|
||||
import info.nightscout.androidaps.R;
|
||||
|
||||
public class ComparatorExists extends Element {
|
||||
public enum Compare {
|
||||
EXISTS,
|
||||
NOT_EXISTS;
|
||||
|
||||
public @StringRes
|
||||
int getStringRes() {
|
||||
switch (this) {
|
||||
case EXISTS:
|
||||
return R.string.exists;
|
||||
case NOT_EXISTS:
|
||||
return R.string.notexists;
|
||||
default:
|
||||
return R.string.unknown;
|
||||
}
|
||||
}
|
||||
|
||||
public static List<String> labels() {
|
||||
List<String> list = new ArrayList<>();
|
||||
for (Compare c : Compare.values()) {
|
||||
list.add(MainApp.gs(c.getStringRes()));
|
||||
}
|
||||
return list;
|
||||
}
|
||||
}
|
||||
|
||||
private Compare compare = Compare.EXISTS;
|
||||
|
||||
public ComparatorExists() {
|
||||
super();
|
||||
}
|
||||
|
||||
public ComparatorExists(ComparatorExists another) {
|
||||
super();
|
||||
compare = another.getValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addToLayout(LinearLayout root) {
|
||||
Spinner spinner = new Spinner(root.getContext());
|
||||
ArrayAdapter<String> spinnerArrayAdapter = new ArrayAdapter<>(root.getContext(), android.R.layout.simple_spinner_item, Compare.labels());
|
||||
spinnerArrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
|
||||
spinner.setAdapter(spinnerArrayAdapter);
|
||||
LinearLayout.LayoutParams spinnerParams = new LinearLayout.LayoutParams(
|
||||
LinearLayout.LayoutParams.MATCH_PARENT,
|
||||
LinearLayout.LayoutParams.WRAP_CONTENT
|
||||
);
|
||||
spinnerParams.setMargins(0, MainApp.dpToPx(4), 0, MainApp.dpToPx(4));
|
||||
spinner.setLayoutParams(spinnerParams);
|
||||
spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
|
||||
@Override
|
||||
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
|
||||
compare = Compare.values()[position];
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNothingSelected(AdapterView<?> parent) {
|
||||
}
|
||||
});
|
||||
spinner.setSelection(compare.ordinal());
|
||||
root.addView(spinner);
|
||||
|
||||
}
|
||||
|
||||
public Compare getValue() {
|
||||
return compare;
|
||||
}
|
||||
|
||||
public ComparatorExists setValue(Compare compare) {
|
||||
this.compare = compare;
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
package info.nightscout.androidaps.plugins.general.automation.elements;
|
||||
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
public abstract class Element {
|
||||
public abstract void addToLayout(LinearLayout root);
|
||||
}
|
|
@ -0,0 +1,99 @@
|
|||
package info.nightscout.androidaps.plugins.general.automation.elements;
|
||||
|
||||
import android.text.Editable;
|
||||
import android.text.TextWatcher;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import java.text.DecimalFormat;
|
||||
|
||||
import info.nightscout.androidaps.Constants;
|
||||
import info.nightscout.androidaps.plugins.configBuilder.ProfileFunctions;
|
||||
import info.nightscout.androidaps.utils.NumberPicker;
|
||||
|
||||
public class InputBg extends Element {
|
||||
|
||||
final TextWatcher textWatcher = new TextWatcher() {
|
||||
@Override
|
||||
public void afterTextChanged(Editable s) {
|
||||
if (units.equals(Constants.MMOL)) {
|
||||
value = Math.max(value, 4d);
|
||||
value = Math.min(value, 15d);
|
||||
} else {
|
||||
value = Math.max(value, 72d);
|
||||
value = Math.min(value, 270d);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTextChanged(CharSequence s, int start, int before, int count) {
|
||||
}
|
||||
};
|
||||
|
||||
private String units = Constants.MGDL;
|
||||
private double value;
|
||||
double minValue;
|
||||
private double maxValue;
|
||||
private double step;
|
||||
private DecimalFormat decimalFormat;
|
||||
|
||||
public InputBg() {
|
||||
super();
|
||||
setUnits(ProfileFunctions.getInstance().getProfileUnits());
|
||||
}
|
||||
|
||||
public InputBg(InputBg another) {
|
||||
super();
|
||||
value = another.getValue();
|
||||
setUnits(another.getUnits());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void addToLayout(LinearLayout root) {
|
||||
NumberPicker numberPicker = new NumberPicker(root.getContext(), null);
|
||||
numberPicker.setParams(value, minValue, maxValue, step, decimalFormat, true, null, textWatcher);
|
||||
numberPicker.setOnValueChangedListener(value -> this.value = value);
|
||||
root.addView(numberPicker);
|
||||
}
|
||||
|
||||
public String getUnits() {
|
||||
return units;
|
||||
}
|
||||
|
||||
public InputBg setUnits(String units) {
|
||||
// set default initial value
|
||||
if (units.equals(Constants.MMOL)) {
|
||||
// mmol
|
||||
minValue = 2;
|
||||
maxValue = 30;
|
||||
step = 0.1;
|
||||
decimalFormat = new DecimalFormat("0.0");
|
||||
} else {
|
||||
// mg/dL
|
||||
minValue = 40;
|
||||
maxValue = 540;
|
||||
step = 1;
|
||||
decimalFormat = new DecimalFormat("0");
|
||||
}
|
||||
|
||||
// make sure that value is in range
|
||||
textWatcher.afterTextChanged(null);
|
||||
|
||||
this.units = units;
|
||||
return this;
|
||||
}
|
||||
|
||||
public InputBg setValue(double value) {
|
||||
this.value = value;
|
||||
return this;
|
||||
}
|
||||
|
||||
public double getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
package info.nightscout.androidaps.plugins.general.automation.elements;
|
||||
|
||||
import android.widget.Button;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
public class InputButton extends Element {
|
||||
|
||||
String text;
|
||||
Runnable runnable;
|
||||
|
||||
public InputButton(String text, Runnable runnable) {
|
||||
this.text = text;
|
||||
this.runnable = runnable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addToLayout(LinearLayout root) {
|
||||
Button button = new Button(root.getContext());
|
||||
|
||||
button.setText(text);
|
||||
button.setOnClickListener(view -> {
|
||||
if (runnable != null)
|
||||
runnable.run();
|
||||
});
|
||||
|
||||
root.addView(button);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,151 @@
|
|||
package info.nightscout.androidaps.plugins.general.automation.elements;
|
||||
|
||||
import android.text.Editable;
|
||||
import android.text.TextWatcher;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.Spinner;
|
||||
|
||||
import androidx.annotation.StringRes;
|
||||
|
||||
import java.text.DecimalFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import info.nightscout.androidaps.MainApp;
|
||||
import info.nightscout.androidaps.R;
|
||||
import info.nightscout.androidaps.utils.NumberPicker;
|
||||
|
||||
public class InputDelta extends Element {
|
||||
private Comparator.Compare compare = Comparator.Compare.IS_EQUAL;
|
||||
final TextWatcher textWatcher = new TextWatcher() {
|
||||
@Override
|
||||
public void afterTextChanged(Editable s) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTextChanged(CharSequence s, int start, int before, int count) {
|
||||
}
|
||||
};
|
||||
|
||||
public enum DeltaType {
|
||||
DELTA,
|
||||
SHORT_AVERAGE,
|
||||
LONG_AVERAGE;
|
||||
|
||||
public @StringRes
|
||||
int getStringRes() {
|
||||
switch (this) {
|
||||
case DELTA:
|
||||
return R.string.delta;
|
||||
case SHORT_AVERAGE:
|
||||
return R.string.short_avgdelta;
|
||||
case LONG_AVERAGE:
|
||||
return R.string.long_avgdelta;
|
||||
default:
|
||||
return R.string.unknown;
|
||||
}
|
||||
}
|
||||
|
||||
public static List<String> labels() {
|
||||
List<String> list = new ArrayList<>();
|
||||
for (DeltaType d : DeltaType.values()) {
|
||||
list.add(MainApp.gs(d.getStringRes()));
|
||||
}
|
||||
return list;
|
||||
}
|
||||
}
|
||||
|
||||
private double value;
|
||||
double minValue;
|
||||
double maxValue;
|
||||
private double step;
|
||||
private DecimalFormat decimalFormat;
|
||||
private DeltaType deltaType;
|
||||
|
||||
NumberPicker numberPicker;
|
||||
|
||||
public InputDelta() {
|
||||
super();
|
||||
}
|
||||
|
||||
public InputDelta(double value, double minValue, double maxValue, double step, DecimalFormat decimalFormat, DeltaType deltaType) {
|
||||
super();
|
||||
this.value = value;
|
||||
this.minValue = minValue;
|
||||
this.maxValue = maxValue;
|
||||
this.step = step;
|
||||
this.decimalFormat = decimalFormat;
|
||||
this.deltaType = deltaType;
|
||||
}
|
||||
|
||||
public InputDelta(InputDelta another) {
|
||||
super();
|
||||
value = another.getValue();
|
||||
minValue = another.minValue;
|
||||
maxValue = another.maxValue;
|
||||
step = another.step;
|
||||
decimalFormat = another.decimalFormat;
|
||||
deltaType = another.deltaType;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void addToLayout(LinearLayout root) {
|
||||
Spinner spinner = new Spinner(root.getContext());
|
||||
ArrayAdapter<String> spinnerArrayAdapter = new ArrayAdapter<>(root.getContext(), android.R.layout.simple_spinner_item, DeltaType.labels());
|
||||
spinnerArrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
|
||||
spinner.setAdapter(spinnerArrayAdapter);
|
||||
LinearLayout.LayoutParams spinnerParams = new LinearLayout.LayoutParams(
|
||||
LinearLayout.LayoutParams.WRAP_CONTENT,
|
||||
LinearLayout.LayoutParams.WRAP_CONTENT
|
||||
);
|
||||
spinnerParams.setMargins(0, MainApp.dpToPx(4), 0, MainApp.dpToPx(4));
|
||||
spinner.setLayoutParams(spinnerParams);
|
||||
spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
|
||||
@Override
|
||||
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
|
||||
deltaType = DeltaType.values()[position];
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNothingSelected(AdapterView<?> parent) {
|
||||
}
|
||||
});
|
||||
spinner.setSelection(this.deltaType.ordinal());
|
||||
// root.addView(spinner);
|
||||
numberPicker = new NumberPicker(root.getContext(), null);
|
||||
numberPicker.setParams(value, minValue, maxValue, step, decimalFormat, true, null, textWatcher);
|
||||
numberPicker.setOnValueChangedListener(value -> this.value = value);
|
||||
LinearLayout l = new LinearLayout(root.getContext());
|
||||
l.setOrientation(LinearLayout.VERTICAL);
|
||||
l.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
|
||||
l.addView(spinner);
|
||||
l.addView(numberPicker);
|
||||
root.addView(l);
|
||||
}
|
||||
|
||||
public InputDelta setValue(double value, DeltaType type) {
|
||||
this.value = value;
|
||||
this.deltaType = type;
|
||||
if (numberPicker != null)
|
||||
numberPicker.setValue(value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public double getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public DeltaType getDeltaType() {
|
||||
return deltaType;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
package info.nightscout.androidaps.plugins.general.automation.elements;
|
||||
|
||||
import android.text.Editable;
|
||||
import android.text.TextWatcher;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import java.text.DecimalFormat;
|
||||
|
||||
import info.nightscout.androidaps.utils.NumberPicker;
|
||||
|
||||
public class InputDouble extends Element {
|
||||
|
||||
final TextWatcher textWatcher = new TextWatcher() {
|
||||
@Override
|
||||
public void afterTextChanged(Editable s) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTextChanged(CharSequence s, int start, int before, int count) {
|
||||
}
|
||||
};
|
||||
|
||||
private double value;
|
||||
double minValue;
|
||||
double maxValue;
|
||||
private double step;
|
||||
private DecimalFormat decimalFormat;
|
||||
|
||||
NumberPicker numberPicker;
|
||||
|
||||
public InputDouble() {
|
||||
super();
|
||||
}
|
||||
|
||||
public InputDouble(double value, double minValue, double maxValue, double step, DecimalFormat decimalFormat) {
|
||||
super();
|
||||
this.value = value;
|
||||
this.minValue = minValue;
|
||||
this.maxValue = maxValue;
|
||||
this.step = step;
|
||||
this.decimalFormat = decimalFormat;
|
||||
}
|
||||
|
||||
public InputDouble(InputDouble another) {
|
||||
super();
|
||||
value = another.getValue();
|
||||
minValue = another.minValue;
|
||||
maxValue = another.maxValue;
|
||||
step = another.step;
|
||||
decimalFormat = another.decimalFormat;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void addToLayout(LinearLayout root) {
|
||||
numberPicker = new NumberPicker(root.getContext(), null);
|
||||
numberPicker.setParams(value, minValue, maxValue, step, decimalFormat, true, null, textWatcher);
|
||||
numberPicker.setOnValueChangedListener(value -> this.value = value);
|
||||
root.addView(numberPicker);
|
||||
}
|
||||
|
||||
public InputDouble setValue(double value) {
|
||||
this.value = value;
|
||||
if (numberPicker != null)
|
||||
numberPicker.setValue(value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public double getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
package info.nightscout.androidaps.plugins.general.automation.elements;
|
||||
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import java.text.DecimalFormat;
|
||||
|
||||
import info.nightscout.androidaps.utils.NumberPicker;
|
||||
|
||||
public class InputDuration extends Element {
|
||||
public enum TimeUnit {
|
||||
MINUTES,
|
||||
HOURS
|
||||
}
|
||||
|
||||
private TimeUnit unit;
|
||||
private int value;
|
||||
|
||||
public InputDuration(int value, TimeUnit unit) {
|
||||
this.unit = unit;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addToLayout(LinearLayout root) {
|
||||
NumberPicker numberPicker = new NumberPicker(root.getContext(), null);
|
||||
if (unit.equals(TimeUnit.MINUTES)) {
|
||||
// Minutes
|
||||
numberPicker.setParams(0d, 0d, 24 * 60d, 10d, new DecimalFormat("0"), false, null);
|
||||
} else {
|
||||
// Hours
|
||||
numberPicker.setParams(0d, 0d, 24d, 1d, new DecimalFormat("0"), false, null);
|
||||
}
|
||||
numberPicker.setValue((double) value);
|
||||
numberPicker.setOnValueChangedListener(value -> this.value = (int) value);
|
||||
root.addView(numberPicker);
|
||||
}
|
||||
|
||||
TimeUnit getUnit() {
|
||||
return unit;
|
||||
}
|
||||
|
||||
public double getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public void setMinutes(int value) {
|
||||
if (unit.equals(TimeUnit.MINUTES)) {
|
||||
this.value = value;
|
||||
} else {
|
||||
this.value = value / 60;
|
||||
}
|
||||
}
|
||||
|
||||
public int getMinutes() {
|
||||
if (unit.equals(TimeUnit.MINUTES)) {
|
||||
return value;
|
||||
} else {
|
||||
return value * 60;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
package info.nightscout.androidaps.plugins.general.automation.elements;
|
||||
|
||||
import android.text.Editable;
|
||||
import android.text.TextWatcher;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import java.text.DecimalFormat;
|
||||
|
||||
import info.nightscout.androidaps.utils.NumberPicker;
|
||||
|
||||
public class InputInsulin extends Element {
|
||||
|
||||
final TextWatcher textWatcher = new TextWatcher() {
|
||||
@Override
|
||||
public void afterTextChanged(Editable s) {
|
||||
value = Math.max(value, -20d);
|
||||
value = Math.min(value, 20d);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTextChanged(CharSequence s, int start, int before, int count) {
|
||||
}
|
||||
};
|
||||
|
||||
private double value;
|
||||
|
||||
public InputInsulin() {
|
||||
super();
|
||||
}
|
||||
|
||||
public InputInsulin(InputInsulin another) {
|
||||
super();
|
||||
value = another.getValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addToLayout(LinearLayout root) {
|
||||
NumberPicker numberPicker = new NumberPicker(root.getContext(), null);
|
||||
numberPicker.setParams(0d, -20d, 20d, 0.1, new DecimalFormat("0.0"), true, null, textWatcher);
|
||||
numberPicker.setValue(value);
|
||||
numberPicker.setOnValueChangedListener(value -> this.value = value);
|
||||
root.addView(numberPicker);
|
||||
}
|
||||
|
||||
public double getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public InputInsulin setValue(double value) {
|
||||
this.value = value;
|
||||
return this;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
package info.nightscout.androidaps.plugins.general.automation.elements;
|
||||
|
||||
import android.text.Editable;
|
||||
import android.text.TextWatcher;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import java.text.DecimalFormat;
|
||||
|
||||
import info.nightscout.androidaps.utils.NumberPicker;
|
||||
|
||||
public class InputPercent extends Element {
|
||||
|
||||
final TextWatcher textWatcher = new TextWatcher() {
|
||||
@Override
|
||||
public void afterTextChanged(Editable s) {
|
||||
value = Math.max(value, 70d);
|
||||
value = Math.min(value, 130d);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTextChanged(CharSequence s, int start, int before, int count) {
|
||||
}
|
||||
};
|
||||
|
||||
private double value;
|
||||
|
||||
public InputPercent() {
|
||||
super();
|
||||
value = 100d;
|
||||
}
|
||||
|
||||
public InputPercent(InputPercent another) {
|
||||
super();
|
||||
value = another.getValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addToLayout(LinearLayout root) {
|
||||
NumberPicker numberPicker = new NumberPicker(root.getContext(), null);
|
||||
numberPicker.setParams(100d, 70d, 130d, 5d, new DecimalFormat("0"), true, null, textWatcher);
|
||||
numberPicker.setValue(value);
|
||||
numberPicker.setOnValueChangedListener(value -> this.value = value);
|
||||
root.addView(numberPicker);
|
||||
}
|
||||
|
||||
public double getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public InputPercent setValue(double value) {
|
||||
this.value = value;
|
||||
return this;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
package info.nightscout.androidaps.plugins.general.automation.elements;
|
||||
|
||||
import android.text.Editable;
|
||||
import android.text.TextWatcher;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.EditText;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
public class InputString extends Element {
|
||||
|
||||
TextWatcher textWatcher = new TextWatcher() {
|
||||
@Override
|
||||
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTextChanged(CharSequence s, int start, int before, int count) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterTextChanged(Editable s) {
|
||||
value = s.toString();
|
||||
}
|
||||
};
|
||||
|
||||
private String value = "";
|
||||
|
||||
public InputString() {
|
||||
super();
|
||||
}
|
||||
|
||||
public InputString(InputString another) {
|
||||
super();
|
||||
value = another.getValue();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void addToLayout(LinearLayout root) {
|
||||
EditText editText = new EditText(root.getContext());
|
||||
editText.setText(value);
|
||||
editText.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
|
||||
editText.addTextChangedListener(textWatcher);
|
||||
root.addView(editText);
|
||||
}
|
||||
|
||||
public InputString setValue(String value) {
|
||||
this.value = value;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
package info.nightscout.androidaps.plugins.general.automation.elements;
|
||||
|
||||
import android.graphics.Typeface;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import info.nightscout.androidaps.MainApp;
|
||||
|
||||
public class LabelWithElement extends Element {
|
||||
final Element element;
|
||||
final String textPre;
|
||||
final String textPost;
|
||||
|
||||
public LabelWithElement(String textPre, String textPost, Element element) {
|
||||
this.element = element;
|
||||
this.textPre = textPre;
|
||||
this.textPost = textPost;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addToLayout(LinearLayout root) {
|
||||
// container layout
|
||||
LinearLayout layout = new LinearLayout(root.getContext());
|
||||
layout.setOrientation(LinearLayout.HORIZONTAL);
|
||||
layout.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT));
|
||||
|
||||
// text view pre element
|
||||
int px = MainApp.dpToPx(10);
|
||||
TextView textViewPre = new TextView(root.getContext());
|
||||
textViewPre.setText(textPre);
|
||||
textViewPre.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT));
|
||||
//textViewPre.setWidth(MainApp.dpToPx(120));
|
||||
textViewPre.setPadding(px, px, px, px);
|
||||
textViewPre.setTypeface(textViewPre.getTypeface(), Typeface.BOLD);
|
||||
layout.addView(textViewPre);
|
||||
|
||||
// add element to layout
|
||||
element.addToLayout(layout);
|
||||
|
||||
// text view post element
|
||||
if (textPost != null) {
|
||||
px = MainApp.dpToPx(5);
|
||||
TextView textViewPost = new TextView(root.getContext());
|
||||
textViewPost.setText(textPost);
|
||||
textViewPost.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT));
|
||||
//textViewPost.setWidth(MainApp.dpToPx(45));
|
||||
textViewPost.setPadding(px, px, px, px);
|
||||
textViewPost.setTypeface(textViewPost.getTypeface(), Typeface.BOLD);
|
||||
layout.addView(textViewPost);
|
||||
}
|
||||
|
||||
// add layout to root layout
|
||||
root.addView(layout);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
package info.nightscout.androidaps.plugins.general.automation.elements;
|
||||
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class LayoutBuilder {
|
||||
ArrayList<Element> mElements = new ArrayList<>();
|
||||
|
||||
public LayoutBuilder add(Element element) {
|
||||
mElements.add(element);
|
||||
return this;
|
||||
}
|
||||
|
||||
public LayoutBuilder add(Element element, boolean condition) {
|
||||
if (condition) mElements.add(element);
|
||||
return this;
|
||||
}
|
||||
|
||||
public void build(LinearLayout layout) {
|
||||
for (Element e : mElements) {
|
||||
e.addToLayout(layout);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
package info.nightscout.androidaps.plugins.general.automation.elements;
|
||||
|
||||
import android.graphics.Typeface;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import info.nightscout.androidaps.MainApp;
|
||||
import info.nightscout.androidaps.R;
|
||||
|
||||
public class StaticLabel extends Element {
|
||||
String label;
|
||||
|
||||
public StaticLabel(String label) {
|
||||
super();
|
||||
this.label = label;
|
||||
}
|
||||
|
||||
public StaticLabel(int resourceId) {
|
||||
super();
|
||||
this.label = MainApp.gs(resourceId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addToLayout(LinearLayout root) {
|
||||
// text view pre element
|
||||
int px = MainApp.dpToPx(10);
|
||||
TextView textView = new TextView(root.getContext());
|
||||
textView.setText(label);
|
||||
// textViewPre.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
|
||||
textView.setPadding(px, px, px, px);
|
||||
textView.setTypeface(textView.getTypeface(), Typeface.BOLD);
|
||||
textView.setBackgroundColor(MainApp.gc(R.color.mdtp_line_dark));
|
||||
// add element to layout
|
||||
root.addView(textView);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
package info.nightscout.androidaps.plugins.general.automation.events
|
||||
|
||||
import info.nightscout.androidaps.events.Event
|
||||
import info.nightscout.androidaps.plugins.general.automation.actions.Action
|
||||
|
||||
class EventAutomationAddAction(val action: Action) : Event()
|
|
@ -0,0 +1,5 @@
|
|||
package info.nightscout.androidaps.plugins.general.automation.events
|
||||
|
||||
import info.nightscout.androidaps.events.Event
|
||||
|
||||
class EventAutomationDataChanged : Event()
|
|
@ -0,0 +1,7 @@
|
|||
package info.nightscout.androidaps.plugins.general.automation.events
|
||||
|
||||
import info.nightscout.androidaps.events.Event
|
||||
import info.nightscout.androidaps.plugins.general.automation.actions.Action
|
||||
|
||||
class EventAutomationUpdateAction(val action: Action, val position : Int) : Event() {
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
package info.nightscout.androidaps.plugins.general.automation.events
|
||||
|
||||
import info.nightscout.androidaps.events.Event
|
||||
|
||||
class EventAutomationUpdateGui : Event()
|
|
@ -0,0 +1,6 @@
|
|||
package info.nightscout.androidaps.plugins.general.automation.events
|
||||
|
||||
import info.nightscout.androidaps.events.Event
|
||||
import info.nightscout.androidaps.plugins.general.automation.triggers.Trigger
|
||||
|
||||
class EventAutomationUpdateTrigger(val trigger: Trigger) : Event()
|
|
@ -0,0 +1,94 @@
|
|||
package info.nightscout.androidaps.plugins.general.automation.triggers;
|
||||
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.ContextWrapper;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
|
||||
import com.google.common.base.Optional;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public abstract class Trigger {
|
||||
|
||||
TriggerConnector connector = null;
|
||||
long lastRun;
|
||||
|
||||
Trigger() {
|
||||
}
|
||||
|
||||
public TriggerConnector getConnector() {
|
||||
return connector;
|
||||
}
|
||||
|
||||
public abstract boolean shouldRun();
|
||||
|
||||
|
||||
public abstract String toJSON();
|
||||
|
||||
/*package*/
|
||||
abstract Trigger fromJSON(String data);
|
||||
|
||||
public abstract int friendlyName();
|
||||
|
||||
public abstract String friendlyDescription();
|
||||
|
||||
public abstract Optional<Integer> icon();
|
||||
|
||||
public void executed(long time) {
|
||||
lastRun = time;
|
||||
}
|
||||
|
||||
public long getLastRun() {
|
||||
return lastRun;
|
||||
}
|
||||
|
||||
public abstract Trigger duplicate();
|
||||
|
||||
public static Trigger instantiate(String json) {
|
||||
try {
|
||||
return instantiate(new JSONObject(json));
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static Trigger instantiate(JSONObject object) {
|
||||
try {
|
||||
String type = object.getString("type");
|
||||
JSONObject data = object.getJSONObject("data");
|
||||
Class clazz = Class.forName(type);
|
||||
return ((Trigger) clazz.newInstance()).fromJSON(data.toString());
|
||||
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void generateDialog(LinearLayout root, FragmentManager fragmentManager) {
|
||||
TextView title = new TextView(root.getContext());
|
||||
title.setText(friendlyName());
|
||||
root.addView(title);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
Activity scanForActivity(Context cont) {
|
||||
if (cont == null)
|
||||
return null;
|
||||
else if (cont instanceof Activity)
|
||||
return (Activity) cont;
|
||||
else if (cont instanceof ContextWrapper)
|
||||
return scanForActivity(((ContextWrapper) cont).getBaseContext());
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,153 @@
|
|||
package info.nightscout.androidaps.plugins.general.automation.triggers;
|
||||
|
||||
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
|
||||
import com.google.common.base.Optional;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.text.DecimalFormat;
|
||||
|
||||
import info.nightscout.androidaps.MainApp;
|
||||
import info.nightscout.androidaps.R;
|
||||
import info.nightscout.androidaps.logging.L;
|
||||
import info.nightscout.androidaps.plugins.general.automation.elements.Comparator;
|
||||
import info.nightscout.androidaps.plugins.general.automation.elements.InputDouble;
|
||||
import info.nightscout.androidaps.plugins.general.automation.elements.LabelWithElement;
|
||||
import info.nightscout.androidaps.plugins.general.automation.elements.LayoutBuilder;
|
||||
import info.nightscout.androidaps.plugins.general.automation.elements.StaticLabel;
|
||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensData;
|
||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin;
|
||||
import info.nightscout.androidaps.utils.DateUtil;
|
||||
import info.nightscout.androidaps.utils.JsonHelper;
|
||||
import info.nightscout.androidaps.utils.SP;
|
||||
import info.nightscout.androidaps.utils.T;
|
||||
|
||||
public class TriggerAutosensValue extends Trigger {
|
||||
private static Logger log = LoggerFactory.getLogger(L.AUTOMATION);
|
||||
private final int minValue = (int) (SP.getDouble("openapsama_autosens_min", 0.7d) * 100);
|
||||
private final int maxValue = (int) (SP.getDouble("openapsama_autosens_max", 1.2d) * 100);
|
||||
private final double step = 1;
|
||||
private DecimalFormat decimalFormat = new DecimalFormat("1");
|
||||
private InputDouble value = new InputDouble(100, (double) minValue, (double) maxValue, step, decimalFormat);
|
||||
private Comparator comparator = new Comparator();
|
||||
|
||||
public TriggerAutosensValue() {
|
||||
super();
|
||||
}
|
||||
|
||||
private TriggerAutosensValue(TriggerAutosensValue triggerAutosensValue) {
|
||||
super();
|
||||
value = new InputDouble(triggerAutosensValue.value);
|
||||
lastRun = triggerAutosensValue.lastRun;
|
||||
comparator = new Comparator(triggerAutosensValue.comparator);
|
||||
}
|
||||
|
||||
public double getValue() {
|
||||
return value.getValue();
|
||||
}
|
||||
|
||||
public Comparator getComparator() {
|
||||
return comparator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized boolean shouldRun() {
|
||||
AutosensData autosensData = IobCobCalculatorPlugin.getPlugin().getLastAutosensData("Automation trigger");
|
||||
if (autosensData == null)
|
||||
if (comparator.getValue() == Comparator.Compare.IS_NOT_AVAILABLE)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
|
||||
if (lastRun > DateUtil.now() - T.mins(5).msecs())
|
||||
return false;
|
||||
|
||||
boolean doRun = comparator.getValue().check((autosensData.autosensResult.ratio), getValue() / 100d);
|
||||
if (doRun) {
|
||||
if (L.isEnabled(L.AUTOMATION))
|
||||
log.debug("Ready for execution: " + friendlyDescription());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized String toJSON() {
|
||||
JSONObject o = new JSONObject();
|
||||
try {
|
||||
o.put("type", TriggerAutosensValue.class.getName());
|
||||
JSONObject data = new JSONObject();
|
||||
data.put("value", getValue());
|
||||
data.put("lastRun", lastRun);
|
||||
data.put("comparator", comparator.getValue().toString());
|
||||
o.put("data", data);
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return o.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
Trigger fromJSON(String data) {
|
||||
try {
|
||||
JSONObject d = new JSONObject(data);
|
||||
value.setValue(JsonHelper.safeGetDouble(d, "value"));
|
||||
lastRun = JsonHelper.safeGetLong(d, "lastRun");
|
||||
comparator.setValue(Comparator.Compare.valueOf(JsonHelper.safeGetString(d, "comparator")));
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int friendlyName() {
|
||||
return R.string.autosenslabel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String friendlyDescription() {
|
||||
return MainApp.gs(R.string.autosenscompared, MainApp.gs(comparator.getValue().getStringRes()), getValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Integer> icon() {
|
||||
return Optional.of(R.drawable.as);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Trigger duplicate() {
|
||||
return new TriggerAutosensValue(this);
|
||||
}
|
||||
|
||||
TriggerAutosensValue setValue(int requestedValue) {
|
||||
this.value.setValue(requestedValue);
|
||||
return this;
|
||||
}
|
||||
|
||||
TriggerAutosensValue lastRun(long lastRun) {
|
||||
this.lastRun = lastRun;
|
||||
return this;
|
||||
}
|
||||
|
||||
TriggerAutosensValue comparator(Comparator.Compare compare) {
|
||||
this.comparator = new Comparator().setValue(compare);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generateDialog(LinearLayout root, FragmentManager fragmentManager) {
|
||||
new LayoutBuilder()
|
||||
.add(new StaticLabel(R.string.autosenslabel))
|
||||
.add(comparator)
|
||||
.add(new LabelWithElement(MainApp.gs(R.string.autosenslabel) + ": ", "", value))
|
||||
.build(root);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,169 @@
|
|||
package info.nightscout.androidaps.plugins.general.automation.triggers;
|
||||
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
|
||||
import com.google.common.base.Optional;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import info.nightscout.androidaps.Constants;
|
||||
import info.nightscout.androidaps.MainApp;
|
||||
import info.nightscout.androidaps.R;
|
||||
import info.nightscout.androidaps.data.Profile;
|
||||
import info.nightscout.androidaps.logging.L;
|
||||
import info.nightscout.androidaps.plugins.general.automation.elements.Comparator;
|
||||
import info.nightscout.androidaps.plugins.general.automation.elements.InputBg;
|
||||
import info.nightscout.androidaps.plugins.general.automation.elements.LabelWithElement;
|
||||
import info.nightscout.androidaps.plugins.general.automation.elements.LayoutBuilder;
|
||||
import info.nightscout.androidaps.plugins.general.automation.elements.StaticLabel;
|
||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus;
|
||||
import info.nightscout.androidaps.utils.DateUtil;
|
||||
import info.nightscout.androidaps.utils.JsonHelper;
|
||||
import info.nightscout.androidaps.utils.T;
|
||||
|
||||
public class TriggerBg extends Trigger {
|
||||
private static Logger log = LoggerFactory.getLogger(L.AUTOMATION);
|
||||
|
||||
private InputBg bg = new InputBg();
|
||||
private Comparator comparator = new Comparator();
|
||||
|
||||
public TriggerBg() {
|
||||
super();
|
||||
}
|
||||
|
||||
private TriggerBg(TriggerBg triggerBg) {
|
||||
super();
|
||||
bg = new InputBg(triggerBg.bg);
|
||||
comparator = new Comparator(triggerBg.comparator);
|
||||
lastRun = triggerBg.lastRun;
|
||||
}
|
||||
|
||||
public double getValue() {
|
||||
return bg.getValue();
|
||||
}
|
||||
|
||||
public Comparator getComparator() {
|
||||
return comparator;
|
||||
}
|
||||
|
||||
public String getUnits() {
|
||||
return bg.getUnits();
|
||||
}
|
||||
|
||||
public long getLastRun() {
|
||||
return lastRun;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized boolean shouldRun() {
|
||||
GlucoseStatus glucoseStatus = GlucoseStatus.getGlucoseStatusData();
|
||||
|
||||
if (lastRun > DateUtil.now() - T.mins(5).msecs())
|
||||
return false;
|
||||
|
||||
if (glucoseStatus == null && comparator.getValue().equals(Comparator.Compare.IS_NOT_AVAILABLE)) {
|
||||
if (L.isEnabled(L.AUTOMATION))
|
||||
log.debug("Ready for execution: " + friendlyDescription());
|
||||
return true;
|
||||
}
|
||||
if (glucoseStatus == null)
|
||||
return false;
|
||||
|
||||
boolean doRun = comparator.getValue().check(glucoseStatus.glucose, Profile.toMgdl(bg.getValue(), bg.getUnits()));
|
||||
if (doRun) {
|
||||
if (L.isEnabled(L.AUTOMATION))
|
||||
log.debug("Ready for execution: " + friendlyDescription());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized String toJSON() {
|
||||
JSONObject o = new JSONObject();
|
||||
try {
|
||||
o.put("type", TriggerBg.class.getName());
|
||||
JSONObject data = new JSONObject();
|
||||
data.put("bg", bg.getValue());
|
||||
data.put("lastRun", lastRun);
|
||||
data.put("comparator", comparator.getValue().toString());
|
||||
data.put("units", bg.getUnits());
|
||||
o.put("data", data);
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return o.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
Trigger fromJSON(String data) {
|
||||
try {
|
||||
JSONObject d = new JSONObject(data);
|
||||
bg.setUnits(JsonHelper.safeGetString(d, "units"));
|
||||
bg.setValue(JsonHelper.safeGetDouble(d, "bg"));
|
||||
lastRun = JsonHelper.safeGetLong(d, "lastRun");
|
||||
comparator.setValue(Comparator.Compare.valueOf(JsonHelper.safeGetString(d, "comparator")));
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int friendlyName() {
|
||||
return R.string.glucose;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String friendlyDescription() {
|
||||
if (comparator.getValue().equals(Comparator.Compare.IS_NOT_AVAILABLE))
|
||||
return MainApp.gs(R.string.glucoseisnotavailable);
|
||||
else {
|
||||
return MainApp.gs(bg.getUnits().equals(Constants.MGDL) ? R.string.glucosecomparedmgdl : R.string.glucosecomparedmmol, MainApp.gs(comparator.getValue().getStringRes()), bg.getValue(), bg.getUnits());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Integer> icon() {
|
||||
return Optional.of(R.drawable.icon_cp_bgcheck);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Trigger duplicate() {
|
||||
return new TriggerBg(this);
|
||||
}
|
||||
|
||||
TriggerBg setValue(double value) {
|
||||
bg.setValue(value);
|
||||
return this;
|
||||
}
|
||||
|
||||
TriggerBg lastRun(long lastRun) {
|
||||
this.lastRun = lastRun;
|
||||
return this;
|
||||
}
|
||||
|
||||
TriggerBg comparator(Comparator.Compare compare) {
|
||||
this.comparator = new Comparator().setValue(compare);
|
||||
return this;
|
||||
}
|
||||
|
||||
TriggerBg setUnits(String units) {
|
||||
bg.setUnits(units);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generateDialog(LinearLayout root, FragmentManager fragmentManager) {
|
||||
new LayoutBuilder()
|
||||
.add(new StaticLabel(R.string.glucose))
|
||||
.add(comparator)
|
||||
.add(new LabelWithElement(MainApp.gs(R.string.glucose_u, bg.getUnits()), "", bg))
|
||||
.build(root);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,154 @@
|
|||
package info.nightscout.androidaps.plugins.general.automation.triggers;
|
||||
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
|
||||
import com.google.common.base.Optional;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.text.DecimalFormat;
|
||||
|
||||
import info.nightscout.androidaps.MainApp;
|
||||
import info.nightscout.androidaps.R;
|
||||
import info.nightscout.androidaps.logging.L;
|
||||
import info.nightscout.androidaps.plugins.general.automation.elements.Comparator;
|
||||
import info.nightscout.androidaps.plugins.general.automation.elements.InputDuration;
|
||||
import info.nightscout.androidaps.plugins.general.automation.elements.LabelWithElement;
|
||||
import info.nightscout.androidaps.plugins.general.automation.elements.LayoutBuilder;
|
||||
import info.nightscout.androidaps.plugins.general.automation.elements.StaticLabel;
|
||||
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin;
|
||||
import info.nightscout.androidaps.utils.DateUtil;
|
||||
import info.nightscout.androidaps.utils.JsonHelper;
|
||||
import info.nightscout.androidaps.utils.T;
|
||||
|
||||
public class TriggerBolusAgo extends Trigger {
|
||||
private static Logger log = LoggerFactory.getLogger(L.AUTOMATION);
|
||||
private final double step = 1;
|
||||
private DecimalFormat decimalFormat = new DecimalFormat("1");
|
||||
public InputDuration minutesAgo = new InputDuration(0, InputDuration.TimeUnit.MINUTES);
|
||||
private Comparator comparator = new Comparator();
|
||||
|
||||
public TriggerBolusAgo() {
|
||||
super();
|
||||
}
|
||||
|
||||
private TriggerBolusAgo(TriggerBolusAgo triggerBolusAgo) {
|
||||
super();
|
||||
minutesAgo = new InputDuration(triggerBolusAgo.minutesAgo.getMinutes(), InputDuration.TimeUnit.MINUTES);
|
||||
lastRun = triggerBolusAgo.lastRun;
|
||||
comparator = new Comparator(triggerBolusAgo.comparator);
|
||||
}
|
||||
|
||||
public double getValue() {
|
||||
return minutesAgo.getValue();
|
||||
}
|
||||
|
||||
public Comparator getComparator() {
|
||||
return comparator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized boolean shouldRun() {
|
||||
|
||||
if (lastRun > DateUtil.now() - T.mins(5).msecs())
|
||||
return false;
|
||||
|
||||
long lastBolusTime = TreatmentsPlugin.getPlugin().getLastBolusTime(false);
|
||||
|
||||
if (lastBolusTime == 0)
|
||||
if (comparator.getValue() == Comparator.Compare.IS_NOT_AVAILABLE)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
|
||||
double minutesAgo = (double) (DateUtil.now() - lastBolusTime) / (60 * 1000);
|
||||
if (L.isEnabled(L.AUTOMATION))
|
||||
log.debug("LastBolus min ago: " + minutesAgo);
|
||||
|
||||
boolean doRun = comparator.getValue().check((minutesAgo), getValue());
|
||||
if (doRun) {
|
||||
if (L.isEnabled(L.AUTOMATION))
|
||||
log.debug("Ready for execution: " + friendlyDescription());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized String toJSON() {
|
||||
JSONObject o = new JSONObject();
|
||||
try {
|
||||
o.put("type", TriggerBolusAgo.class.getName());
|
||||
JSONObject data = new JSONObject();
|
||||
data.put("minutesAgo", getValue());
|
||||
data.put("lastRun", lastRun);
|
||||
data.put("comparator", comparator.getValue().toString());
|
||||
o.put("data", data);
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return o.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
Trigger fromJSON(String data) {
|
||||
try {
|
||||
JSONObject d = new JSONObject(data);
|
||||
minutesAgo.setMinutes(JsonHelper.safeGetInt(d, "minutesAgo"));
|
||||
lastRun = JsonHelper.safeGetLong(d, "lastRun");
|
||||
comparator.setValue(Comparator.Compare.valueOf(JsonHelper.safeGetString(d, "comparator")));
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int friendlyName() {
|
||||
return R.string.lastboluslabel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String friendlyDescription() {
|
||||
return MainApp.gs(R.string.lastboluscompared, MainApp.gs(comparator.getValue().getStringRes()), (int) getValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Integer> icon() {
|
||||
return Optional.of(R.drawable.icon_bolus);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Trigger duplicate() {
|
||||
return new TriggerBolusAgo(this);
|
||||
}
|
||||
|
||||
TriggerBolusAgo setValue(int requestedValue) {
|
||||
this.minutesAgo.setMinutes(requestedValue);
|
||||
return this;
|
||||
}
|
||||
|
||||
TriggerBolusAgo lastRun(long lastRun) {
|
||||
this.lastRun = lastRun;
|
||||
return this;
|
||||
}
|
||||
|
||||
TriggerBolusAgo comparator(Comparator.Compare compare) {
|
||||
this.comparator = new Comparator().setValue(compare);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generateDialog(LinearLayout root, FragmentManager fragmentManager) {
|
||||
new LayoutBuilder()
|
||||
.add(new StaticLabel(R.string.lastboluslabel))
|
||||
.add(comparator)
|
||||
.add(new LabelWithElement(MainApp.gs(R.string.lastboluslabel) + ": ", "", minutesAgo))
|
||||
.build(root);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,153 @@
|
|||
package info.nightscout.androidaps.plugins.general.automation.triggers;
|
||||
|
||||
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
|
||||
import com.google.common.base.Optional;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.text.DecimalFormat;
|
||||
|
||||
import info.nightscout.androidaps.MainApp;
|
||||
import info.nightscout.androidaps.R;
|
||||
import info.nightscout.androidaps.logging.L;
|
||||
import info.nightscout.androidaps.plugins.general.automation.elements.Comparator;
|
||||
import info.nightscout.androidaps.plugins.general.automation.elements.InputDouble;
|
||||
import info.nightscout.androidaps.plugins.general.automation.elements.LabelWithElement;
|
||||
import info.nightscout.androidaps.plugins.general.automation.elements.LayoutBuilder;
|
||||
import info.nightscout.androidaps.plugins.general.automation.elements.StaticLabel;
|
||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.CobInfo;
|
||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin;
|
||||
import info.nightscout.androidaps.utils.DateUtil;
|
||||
import info.nightscout.androidaps.utils.JsonHelper;
|
||||
import info.nightscout.androidaps.utils.SP;
|
||||
import info.nightscout.androidaps.utils.T;
|
||||
|
||||
public class TriggerCOB extends Trigger {
|
||||
private static Logger log = LoggerFactory.getLogger(L.AUTOMATION);
|
||||
private final int minValue = 0;
|
||||
private final int maxValue = (int) (SP.getInt(R.string.key_treatmentssafety_maxcarbs, 48));
|
||||
private final double step = 1;
|
||||
private DecimalFormat decimalFormat = new DecimalFormat("1");
|
||||
private InputDouble value = new InputDouble(0, (double) minValue, (double) maxValue, step, decimalFormat);
|
||||
private Comparator comparator = new Comparator();
|
||||
|
||||
public TriggerCOB() {
|
||||
super();
|
||||
}
|
||||
|
||||
private TriggerCOB(TriggerCOB triggerCOB) {
|
||||
super();
|
||||
value = new InputDouble(triggerCOB.value);
|
||||
lastRun = triggerCOB.lastRun;
|
||||
comparator = new Comparator(triggerCOB.comparator);
|
||||
}
|
||||
|
||||
public double getValue() {
|
||||
return value.getValue();
|
||||
}
|
||||
|
||||
public Comparator getComparator() {
|
||||
return comparator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized boolean shouldRun() {
|
||||
CobInfo cobInfo = IobCobCalculatorPlugin.getPlugin().getCobInfo(false, "AutomationTriggerCOB");
|
||||
if (cobInfo == null)
|
||||
if (comparator.getValue() == Comparator.Compare.IS_NOT_AVAILABLE)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
|
||||
if (lastRun > DateUtil.now() - T.mins(5).msecs())
|
||||
return false;
|
||||
|
||||
boolean doRun = comparator.getValue().check((cobInfo.displayCob), getValue());
|
||||
if (doRun) {
|
||||
if (L.isEnabled(L.AUTOMATION))
|
||||
log.debug("Ready for execution: " + friendlyDescription());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized String toJSON() {
|
||||
JSONObject o = new JSONObject();
|
||||
try {
|
||||
o.put("type", TriggerCOB.class.getName());
|
||||
JSONObject data = new JSONObject();
|
||||
data.put("carbs", getValue());
|
||||
data.put("lastRun", lastRun);
|
||||
data.put("comparator", comparator.getValue().toString());
|
||||
o.put("data", data);
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return o.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
Trigger fromJSON(String data) {
|
||||
try {
|
||||
JSONObject d = new JSONObject(data);
|
||||
value.setValue(JsonHelper.safeGetDouble(d, "carbs"));
|
||||
lastRun = JsonHelper.safeGetLong(d, "lastRun");
|
||||
comparator.setValue(Comparator.Compare.valueOf(JsonHelper.safeGetString(d, "comparator")));
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int friendlyName() {
|
||||
return R.string.triggercoblabel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String friendlyDescription() {
|
||||
return MainApp.gs(R.string.cobcompared, MainApp.gs(comparator.getValue().getStringRes()), getValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Integer> icon() {
|
||||
return Optional.of(R.drawable.icon_cp_bolus_carbs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Trigger duplicate() {
|
||||
return new TriggerCOB(this);
|
||||
}
|
||||
|
||||
TriggerCOB setValue(int requestedValue) {
|
||||
this.value.setValue(requestedValue);
|
||||
return this;
|
||||
}
|
||||
|
||||
TriggerCOB lastRun(long lastRun) {
|
||||
this.lastRun = lastRun;
|
||||
return this;
|
||||
}
|
||||
|
||||
TriggerCOB comparator(Comparator.Compare compare) {
|
||||
this.comparator = new Comparator().setValue(compare);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generateDialog(LinearLayout root, FragmentManager fragmentManager) {
|
||||
new LayoutBuilder()
|
||||
.add(new StaticLabel(R.string.triggercoblabel))
|
||||
.add(comparator)
|
||||
.add(new LabelWithElement(MainApp.gs(R.string.triggercoblabel) + ": ", "", value))
|
||||
.build(root);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,277 @@
|
|||
package info.nightscout.androidaps.plugins.general.automation.triggers;
|
||||
|
||||
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import androidx.annotation.StringRes;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
|
||||
import com.google.common.base.Optional;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
|
||||
import info.nightscout.androidaps.MainApp;
|
||||
import info.nightscout.androidaps.R;
|
||||
import info.nightscout.androidaps.logging.L;
|
||||
import info.nightscout.androidaps.plugins.general.automation.dialogs.TriggerListAdapter;
|
||||
import info.nightscout.androidaps.utils.JsonHelper;
|
||||
|
||||
public class TriggerConnector extends Trigger {
|
||||
private static Logger log = LoggerFactory.getLogger(L.AUTOMATION);
|
||||
|
||||
public enum Type {
|
||||
AND,
|
||||
OR,
|
||||
XOR;
|
||||
|
||||
public boolean apply(boolean a, boolean b) {
|
||||
switch (this) {
|
||||
case AND:
|
||||
return a && b;
|
||||
case OR:
|
||||
return a || b;
|
||||
case XOR:
|
||||
return a ^ b;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public @StringRes
|
||||
int getStringRes() {
|
||||
switch (this) {
|
||||
case OR:
|
||||
return R.string.or;
|
||||
case XOR:
|
||||
return R.string.xor;
|
||||
|
||||
default:
|
||||
case AND:
|
||||
return R.string.and;
|
||||
}
|
||||
}
|
||||
|
||||
public static List<String> labels() {
|
||||
List<String> list = new ArrayList<>();
|
||||
for (Type t : values()) {
|
||||
list.add(MainApp.gs(t.getStringRes()));
|
||||
}
|
||||
return list;
|
||||
}
|
||||
}
|
||||
|
||||
public static void fillIconSet(TriggerConnector connector, HashSet<Integer> set) {
|
||||
for (Trigger t : connector.list) {
|
||||
if (t instanceof TriggerConnector) {
|
||||
fillIconSet((TriggerConnector) t, set);
|
||||
} else {
|
||||
Optional<Integer> icon = t.icon();
|
||||
if (icon.isPresent()) {
|
||||
set.add(icon.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected List<Trigger> list = new ArrayList<>();
|
||||
private Type connectorType;
|
||||
|
||||
public TriggerConnector() {
|
||||
connectorType = Type.AND;
|
||||
}
|
||||
|
||||
public TriggerConnector(Type connectorType) {
|
||||
this.connectorType = connectorType;
|
||||
}
|
||||
|
||||
public void changeConnectorType(Type type) {
|
||||
this.connectorType = type;
|
||||
}
|
||||
|
||||
public Type getConnectorType() {
|
||||
return connectorType;
|
||||
}
|
||||
|
||||
public synchronized void add(Trigger t) {
|
||||
list.add(t);
|
||||
t.connector = this;
|
||||
}
|
||||
|
||||
public synchronized void add(int pos, Trigger t) {
|
||||
list.add(pos, t);
|
||||
t.connector = this;
|
||||
}
|
||||
|
||||
public synchronized boolean remove(Trigger t) {
|
||||
return list.remove(t);
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return list.size();
|
||||
}
|
||||
|
||||
public Trigger get(int i) {
|
||||
return list.get(i);
|
||||
}
|
||||
|
||||
public int pos(Trigger trigger) {
|
||||
for (int i = 0; i < list.size(); ++i) {
|
||||
if (list.get(i) == trigger) return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized boolean shouldRun() {
|
||||
boolean result = true;
|
||||
|
||||
// check first trigger
|
||||
if (list.size() > 0)
|
||||
result = list.get(0).shouldRun();
|
||||
|
||||
// check all others
|
||||
for (int i = 1; i < list.size(); ++i) {
|
||||
result = connectorType.apply(result, list.get(i).shouldRun());
|
||||
}
|
||||
if (result)
|
||||
if (L.isEnabled(L.AUTOMATION))
|
||||
log.debug("Ready for execution: " + friendlyDescription().replace("\n", " "));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized String toJSON() {
|
||||
JSONObject o = new JSONObject();
|
||||
try {
|
||||
o.put("type", TriggerConnector.class.getName());
|
||||
JSONObject data = new JSONObject();
|
||||
data.put("connectorType", connectorType.toString());
|
||||
JSONArray array = new JSONArray();
|
||||
for (Trigger t : list) {
|
||||
array.put(t.toJSON());
|
||||
}
|
||||
data.put("triggerList", array);
|
||||
o.put("data", data);
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return o.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
Trigger fromJSON(String data) {
|
||||
try {
|
||||
JSONObject d = new JSONObject(data);
|
||||
connectorType = Type.valueOf(JsonHelper.safeGetString(d, "connectorType"));
|
||||
JSONArray array = d.getJSONArray("triggerList");
|
||||
list.clear();
|
||||
for (int i = 0; i < array.length(); i++) {
|
||||
Trigger newItem = instantiate(new JSONObject(array.getString(i)));
|
||||
add(newItem);
|
||||
}
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int friendlyName() {
|
||||
return connectorType.getStringRes();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String friendlyDescription() {
|
||||
int counter = 0;
|
||||
StringBuilder result = new StringBuilder();
|
||||
for (Trigger t : list) {
|
||||
if (counter++ > 0) result.append("\n").append(MainApp.gs(friendlyName())).append("\n");
|
||||
result.append(t.friendlyDescription());
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Integer> icon() {
|
||||
return Optional.absent();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void executed(long time) {
|
||||
for (int i = 0; i < list.size(); ++i) {
|
||||
list.get(i).executed(time);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Trigger duplicate() {
|
||||
return null;
|
||||
}
|
||||
|
||||
private TriggerListAdapter adapter;
|
||||
|
||||
public void rebuildView(FragmentManager fragmentManager) {
|
||||
if (adapter != null)
|
||||
adapter.rebuild(fragmentManager);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generateDialog(LinearLayout root, FragmentManager fragmentManager) {
|
||||
final int padding = MainApp.dpToPx(5);
|
||||
|
||||
root.setPadding(padding, padding, padding, padding);
|
||||
root.setBackgroundResource(R.drawable.border_automation_unit);
|
||||
|
||||
LinearLayout triggerListLayout = new LinearLayout(root.getContext());
|
||||
triggerListLayout.setOrientation(LinearLayout.VERTICAL);
|
||||
triggerListLayout.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
|
||||
root.addView(triggerListLayout);
|
||||
|
||||
adapter = new TriggerListAdapter(fragmentManager, root.getContext(), triggerListLayout, this);
|
||||
}
|
||||
|
||||
public TriggerConnector simplify() {
|
||||
// simplify children
|
||||
for (int i = 0; i < size(); ++i) {
|
||||
if (get(i) instanceof TriggerConnector) {
|
||||
TriggerConnector t = (TriggerConnector) get(i);
|
||||
t.simplify();
|
||||
}
|
||||
}
|
||||
|
||||
// drop connector with only 1 element
|
||||
if (size() == 1 && get(0) instanceof TriggerConnector) {
|
||||
TriggerConnector c = (TriggerConnector) get(0);
|
||||
remove(c);
|
||||
changeConnectorType(c.getConnectorType());
|
||||
for (Trigger t : c.list) {
|
||||
add(t);
|
||||
}
|
||||
c.list.clear();
|
||||
return simplify();
|
||||
}
|
||||
|
||||
// merge connectors
|
||||
if (connector != null && (connector.getConnectorType().equals(connectorType) || size() == 1)) {
|
||||
final int pos = connector.pos(this);
|
||||
connector.remove(this);
|
||||
// move triggers of child connector into parent connector
|
||||
for (int i = size() - 1; i >= 0; --i) {
|
||||
connector.add(pos, get(i));
|
||||
}
|
||||
list.clear();
|
||||
return connector.simplify();
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,208 @@
|
|||
package info.nightscout.androidaps.plugins.general.automation.triggers;
|
||||
|
||||
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
|
||||
import com.google.common.base.Optional;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.text.DecimalFormat;
|
||||
|
||||
import info.nightscout.androidaps.Constants;
|
||||
import info.nightscout.androidaps.MainApp;
|
||||
import info.nightscout.androidaps.R;
|
||||
import info.nightscout.androidaps.data.Profile;
|
||||
import info.nightscout.androidaps.logging.L;
|
||||
import info.nightscout.androidaps.plugins.configBuilder.ProfileFunctions;
|
||||
import info.nightscout.androidaps.plugins.general.automation.elements.Comparator;
|
||||
import info.nightscout.androidaps.plugins.general.automation.elements.InputDelta;
|
||||
import info.nightscout.androidaps.plugins.general.automation.elements.InputDelta.DeltaType;
|
||||
import info.nightscout.androidaps.plugins.general.automation.elements.LabelWithElement;
|
||||
import info.nightscout.androidaps.plugins.general.automation.elements.LayoutBuilder;
|
||||
import info.nightscout.androidaps.plugins.general.automation.elements.StaticLabel;
|
||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus;
|
||||
import info.nightscout.androidaps.utils.DateUtil;
|
||||
import info.nightscout.androidaps.utils.JsonHelper;
|
||||
import info.nightscout.androidaps.utils.T;
|
||||
|
||||
public class TriggerDelta extends Trigger {
|
||||
private static Logger log = LoggerFactory.getLogger(L.AUTOMATION);
|
||||
private double minValue = 0d;
|
||||
private double maxValue = 1d;
|
||||
private double step = 1;
|
||||
private DecimalFormat decimalFormat = new DecimalFormat("1");
|
||||
private String units;
|
||||
private DeltaType deltaType;
|
||||
|
||||
private InputDelta value = new InputDelta( (double) minValue,(double) minValue, (double) maxValue, step, decimalFormat, deltaType);
|
||||
private Comparator comparator = new Comparator();
|
||||
|
||||
public TriggerDelta() {
|
||||
super();
|
||||
this.units = ProfileFunctions.getInstance().getProfileUnits();
|
||||
initializer();
|
||||
}
|
||||
|
||||
private TriggerDelta(TriggerDelta triggerDelta) {
|
||||
super();
|
||||
this.units = ProfileFunctions.getInstance().getProfileUnits();
|
||||
initializer();
|
||||
value = triggerDelta.value;
|
||||
lastRun = triggerDelta.lastRun;
|
||||
}
|
||||
|
||||
public double getValue() {
|
||||
deltaType = value.getDeltaType();
|
||||
return value.getValue();
|
||||
}
|
||||
|
||||
public DeltaType getType() {
|
||||
return deltaType;
|
||||
}
|
||||
|
||||
public String getUnits() {
|
||||
return this.units;
|
||||
}
|
||||
|
||||
public Comparator getComparator() {
|
||||
return comparator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized boolean shouldRun() {
|
||||
GlucoseStatus glucoseStatus = GlucoseStatus.getGlucoseStatusData();
|
||||
if (glucoseStatus == null)
|
||||
if (comparator.getValue() == Comparator.Compare.IS_NOT_AVAILABLE)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
|
||||
// Setting type of delta
|
||||
double delta;
|
||||
|
||||
if (deltaType == DeltaType.SHORT_AVERAGE)
|
||||
delta = glucoseStatus.short_avgdelta;
|
||||
else if (deltaType == DeltaType.LONG_AVERAGE)
|
||||
delta = glucoseStatus.long_avgdelta;
|
||||
else
|
||||
delta = glucoseStatus.delta;
|
||||
|
||||
if (lastRun > DateUtil.now() - T.mins(5).msecs())
|
||||
return false;
|
||||
|
||||
boolean doRun = comparator.getValue().check(delta, Profile.toMgdl(value.getValue(), this.units));
|
||||
if (doRun) {
|
||||
if (L.isEnabled(L.AUTOMATION))
|
||||
log.debug("Ready for execution: delta is " + delta + " " + friendlyDescription());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized String toJSON() {
|
||||
JSONObject o = new JSONObject();
|
||||
try {
|
||||
o.put("type", TriggerDelta.class.getName());
|
||||
JSONObject data = new JSONObject();
|
||||
data.put("value", getValue());
|
||||
data.put("units", units);
|
||||
data.put("lastRun", lastRun);
|
||||
data.put("deltaType", getType());
|
||||
data.put("comparator", comparator.getValue().toString());
|
||||
o.put("data", data);
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return o.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
Trigger fromJSON(String data) {
|
||||
try {
|
||||
JSONObject d = new JSONObject(data);
|
||||
units = JsonHelper.safeGetString(d, "units");
|
||||
deltaType = DeltaType.valueOf(JsonHelper.safeGetString(d, "deltaType", ""));
|
||||
value.setValue(JsonHelper.safeGetDouble(d, "value"), deltaType);
|
||||
lastRun = JsonHelper.safeGetLong(d, "lastRun");
|
||||
comparator.setValue(Comparator.Compare.valueOf(JsonHelper.safeGetString(d, "comparator")));
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int friendlyName() {
|
||||
return R.string.deltalabel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String friendlyDescription() {
|
||||
return MainApp.gs(R.string.deltacompared, MainApp.gs(comparator.getValue().getStringRes()), getValue(), MainApp.gs(deltaType.getStringRes()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Integer> icon() {
|
||||
return Optional.of(R.drawable.icon_auto_delta);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Trigger duplicate() {
|
||||
return new TriggerDelta(this);
|
||||
}
|
||||
|
||||
TriggerDelta setValue(double requestedValue, DeltaType requestedType) {
|
||||
this.value.setValue(requestedValue, requestedType);
|
||||
this.deltaType = requestedType;
|
||||
return this;
|
||||
}
|
||||
|
||||
TriggerDelta setUnits(String units) {
|
||||
this.units = units;
|
||||
return this;
|
||||
}
|
||||
|
||||
void initializer(){
|
||||
if (this.units.equals(Constants.MMOL)) {
|
||||
this.maxValue = 4d;
|
||||
this.minValue = -4d;
|
||||
this.step = 0.1d;
|
||||
this.decimalFormat = new DecimalFormat("0.1");
|
||||
this.deltaType = DeltaType.DELTA;
|
||||
} else {
|
||||
this.maxValue = 72d;
|
||||
this.minValue = -72d;
|
||||
this.step = 1d;
|
||||
this.deltaType = DeltaType.DELTA;
|
||||
}
|
||||
value = new InputDelta( (double) minValue,(double) minValue, (double) maxValue, step, decimalFormat, deltaType);
|
||||
}
|
||||
|
||||
|
||||
TriggerDelta lastRun(long lastRun) {
|
||||
this.lastRun = lastRun;
|
||||
return this;
|
||||
}
|
||||
|
||||
TriggerDelta comparator(Comparator.Compare compare) {
|
||||
this.comparator = new Comparator().setValue(compare);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generateDialog(LinearLayout root, FragmentManager fragmentManager) {
|
||||
new LayoutBuilder()
|
||||
.add(new StaticLabel(R.string.deltalabel))
|
||||
.add(comparator)
|
||||
.add(new LabelWithElement(MainApp.gs(R.string.deltalabel) + ": ", "", value))
|
||||
.build(root);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,146 @@
|
|||
package info.nightscout.androidaps.plugins.general.automation.triggers;
|
||||
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
|
||||
import com.google.common.base.Optional;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import info.nightscout.androidaps.MainApp;
|
||||
import info.nightscout.androidaps.R;
|
||||
import info.nightscout.androidaps.data.IobTotal;
|
||||
import info.nightscout.androidaps.data.Profile;
|
||||
import info.nightscout.androidaps.logging.L;
|
||||
import info.nightscout.androidaps.plugins.configBuilder.ProfileFunctions;
|
||||
import info.nightscout.androidaps.plugins.general.automation.elements.Comparator;
|
||||
import info.nightscout.androidaps.plugins.general.automation.elements.InputInsulin;
|
||||
import info.nightscout.androidaps.plugins.general.automation.elements.LabelWithElement;
|
||||
import info.nightscout.androidaps.plugins.general.automation.elements.LayoutBuilder;
|
||||
import info.nightscout.androidaps.plugins.general.automation.elements.StaticLabel;
|
||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin;
|
||||
import info.nightscout.androidaps.utils.DateUtil;
|
||||
import info.nightscout.androidaps.utils.JsonHelper;
|
||||
import info.nightscout.androidaps.utils.T;
|
||||
|
||||
public class TriggerIob extends Trigger {
|
||||
private static Logger log = LoggerFactory.getLogger(L.AUTOMATION);
|
||||
|
||||
private InputInsulin insulin = new InputInsulin();
|
||||
private Comparator comparator = new Comparator();
|
||||
|
||||
public TriggerIob() {
|
||||
super();
|
||||
}
|
||||
|
||||
private TriggerIob(TriggerIob triggerIob) {
|
||||
super();
|
||||
insulin = new InputInsulin(triggerIob.insulin);
|
||||
comparator = new Comparator(triggerIob.comparator);
|
||||
lastRun = triggerIob.lastRun;
|
||||
}
|
||||
|
||||
public double getValue() {
|
||||
return insulin.getValue();
|
||||
}
|
||||
|
||||
public Comparator getComparator() {
|
||||
return comparator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized boolean shouldRun() {
|
||||
Profile profile = ProfileFunctions.getInstance().getProfile();
|
||||
if (profile == null)
|
||||
return false;
|
||||
IobTotal iob = IobCobCalculatorPlugin.getPlugin().calculateFromTreatmentsAndTempsSynchronized(DateUtil.now(), profile);
|
||||
|
||||
if (lastRun > DateUtil.now() - T.mins(5).msecs())
|
||||
return false;
|
||||
|
||||
boolean doRun = comparator.getValue().check(iob.iob, getValue());
|
||||
if (doRun) {
|
||||
if (L.isEnabled(L.AUTOMATION))
|
||||
log.debug("Ready for execution: " + friendlyDescription());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized String toJSON() {
|
||||
JSONObject o = new JSONObject();
|
||||
try {
|
||||
o.put("type", TriggerIob.class.getName());
|
||||
JSONObject data = new JSONObject();
|
||||
data.put("insulin", getValue());
|
||||
data.put("lastRun", lastRun);
|
||||
data.put("comparator", comparator.getValue().toString());
|
||||
o.put("data", data);
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return o.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
Trigger fromJSON(String data) {
|
||||
try {
|
||||
JSONObject d = new JSONObject(data);
|
||||
insulin.setValue(JsonHelper.safeGetDouble(d, "insulin"));
|
||||
lastRun = JsonHelper.safeGetLong(d, "lastRun");
|
||||
comparator.setValue(Comparator.Compare.valueOf(JsonHelper.safeGetString(d, "comparator")));
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int friendlyName() {
|
||||
return R.string.iob;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String friendlyDescription() {
|
||||
return MainApp.gs(R.string.iobcompared, MainApp.gs(comparator.getValue().getStringRes()), getValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Integer> icon() {
|
||||
return Optional.of(R.drawable.ic_keyboard_capslock);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Trigger duplicate() {
|
||||
return new TriggerIob(this);
|
||||
}
|
||||
|
||||
TriggerIob setValue(double threshold) {
|
||||
insulin.setValue(threshold);
|
||||
return this;
|
||||
}
|
||||
|
||||
TriggerIob lastRun(long lastRun) {
|
||||
this.lastRun = lastRun;
|
||||
return this;
|
||||
}
|
||||
|
||||
TriggerIob comparator(Comparator.Compare compare) {
|
||||
this.comparator = new Comparator().setValue(compare);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generateDialog(LinearLayout root, FragmentManager fragmentManager) {
|
||||
new LayoutBuilder()
|
||||
.add(new StaticLabel(R.string.iob))
|
||||
.add(comparator)
|
||||
.add(new LabelWithElement(MainApp.gs(R.string.iob_u), "", insulin))
|
||||
.build(root);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,167 @@
|
|||
package info.nightscout.androidaps.plugins.general.automation.triggers;
|
||||
|
||||
import android.location.Location;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
|
||||
import com.google.common.base.Optional;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.text.DecimalFormat;
|
||||
|
||||
import info.nightscout.androidaps.MainApp;
|
||||
import info.nightscout.androidaps.R;
|
||||
import info.nightscout.androidaps.logging.L;
|
||||
import info.nightscout.androidaps.plugins.general.automation.elements.InputButton;
|
||||
import info.nightscout.androidaps.plugins.general.automation.elements.InputDouble;
|
||||
import info.nightscout.androidaps.plugins.general.automation.elements.InputString;
|
||||
import info.nightscout.androidaps.plugins.general.automation.elements.LabelWithElement;
|
||||
import info.nightscout.androidaps.plugins.general.automation.elements.LayoutBuilder;
|
||||
import info.nightscout.androidaps.plugins.general.automation.elements.StaticLabel;
|
||||
import info.nightscout.androidaps.services.LocationService;
|
||||
import info.nightscout.androidaps.utils.DateUtil;
|
||||
import info.nightscout.androidaps.utils.JsonHelper;
|
||||
import info.nightscout.androidaps.utils.T;
|
||||
|
||||
public class TriggerLocation extends Trigger {
|
||||
private static Logger log = LoggerFactory.getLogger(L.AUTOMATION);
|
||||
|
||||
InputDouble latitude = new InputDouble(0d, -90d, +90d, 0.000001d, new DecimalFormat("0.000000"));
|
||||
InputDouble longitude = new InputDouble(0d, -180d, +180d, 0.000001d, new DecimalFormat("0.000000"));
|
||||
InputDouble distance = new InputDouble(200d, 0, 100000, 10d, new DecimalFormat("0"));
|
||||
InputString name = new InputString();
|
||||
|
||||
private Runnable buttonAction = () -> {
|
||||
Location location = LocationService.getLastLocation();
|
||||
if (location != null) {
|
||||
latitude.setValue(location.getLatitude());
|
||||
longitude.setValue(location.getLongitude());
|
||||
log.debug(String.format("Grabbed location: %f %f", latitude.getValue(), longitude.getValue()));
|
||||
}
|
||||
};
|
||||
|
||||
public TriggerLocation() {
|
||||
super();
|
||||
}
|
||||
|
||||
private TriggerLocation(TriggerLocation triggerLocation) {
|
||||
super();
|
||||
latitude = new InputDouble(triggerLocation.latitude.getValue(), -90d, +90d, 0.00001d, new DecimalFormat("0.00000"));
|
||||
longitude = new InputDouble(triggerLocation.longitude.getValue(), -180d, +180d, 0.00001d, new DecimalFormat("0.00000"));
|
||||
distance = new InputDouble(200d, 0, 100000, 10d, new DecimalFormat("0"));
|
||||
lastRun = triggerLocation.lastRun;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized boolean shouldRun() {
|
||||
Location location = LocationService.getLastLocation();
|
||||
if (location == null)
|
||||
return false;
|
||||
|
||||
if (lastRun > DateUtil.now() - T.mins(5).msecs())
|
||||
return false;
|
||||
|
||||
Location a = new Location("Trigger");
|
||||
a.setLatitude(latitude.getValue());
|
||||
a.setLongitude(longitude.getValue());
|
||||
double calculatedDistance = location.distanceTo(a);
|
||||
|
||||
if (calculatedDistance < distance.getValue()) {
|
||||
if (L.isEnabled(L.AUTOMATION))
|
||||
log.debug("Ready for execution: " + friendlyDescription());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized String toJSON() {
|
||||
JSONObject o = new JSONObject();
|
||||
try {
|
||||
o.put("type", TriggerLocation.class.getName());
|
||||
JSONObject data = new JSONObject();
|
||||
data.put("latitude", latitude.getValue());
|
||||
data.put("longitude", longitude.getValue());
|
||||
data.put("distance", distance.getValue());
|
||||
data.put("name", name.getValue());
|
||||
data.put("lastRun", lastRun);
|
||||
o.put("data", data);
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return o.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
Trigger fromJSON(String data) {
|
||||
try {
|
||||
JSONObject d = new JSONObject(data);
|
||||
latitude.setValue(JsonHelper.safeGetDouble(d, "latitude"));
|
||||
longitude.setValue(JsonHelper.safeGetDouble(d, "longitude"));
|
||||
distance.setValue(JsonHelper.safeGetDouble(d, "distance"));
|
||||
name.setValue(JsonHelper.safeGetString(d, "name"));
|
||||
lastRun = JsonHelper.safeGetLong(d, "lastRun");
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int friendlyName() {
|
||||
return R.string.location;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String friendlyDescription() {
|
||||
return MainApp.gs(R.string.locationis, name.getValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Integer> icon() {
|
||||
return Optional.of(R.drawable.ic_location_on);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Trigger duplicate() {
|
||||
return new TriggerLocation(this);
|
||||
}
|
||||
|
||||
|
||||
TriggerLocation setLatitude(double value) {
|
||||
latitude.setValue(value);
|
||||
return this;
|
||||
}
|
||||
|
||||
TriggerLocation setLongitude(double value) {
|
||||
longitude.setValue(value);
|
||||
return this;
|
||||
}
|
||||
|
||||
TriggerLocation setdistance(double value) {
|
||||
distance.setValue(value);
|
||||
return this;
|
||||
}
|
||||
|
||||
TriggerLocation lastRun(long lastRun) {
|
||||
this.lastRun = lastRun;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generateDialog(LinearLayout root, FragmentManager fragmentManager) {
|
||||
new LayoutBuilder()
|
||||
.add(new StaticLabel(R.string.location))
|
||||
.add(new LabelWithElement(MainApp.gs(R.string.name_short), "", name))
|
||||
.add(new LabelWithElement(MainApp.gs(R.string.latitude_short), "", latitude))
|
||||
.add(new LabelWithElement(MainApp.gs(R.string.longitude_short), "", longitude))
|
||||
.add(new LabelWithElement(MainApp.gs(R.string.distance_short), "", distance))
|
||||
.add(new InputButton(MainApp.gs(R.string.currentlocation), buttonAction), LocationService.getLastLocation() != null)
|
||||
.build(root);
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue