commit
3ff6145962
161 changed files with 6494 additions and 4418 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -2,6 +2,7 @@
|
||||||
.gradle
|
.gradle
|
||||||
/local.properties
|
/local.properties
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
app/jacoco.exec
|
||||||
/build
|
/build
|
||||||
/captures
|
/captures
|
||||||
*.apk
|
*.apk
|
||||||
|
|
|
@ -117,7 +117,7 @@ android {
|
||||||
targetSdkVersion 28
|
targetSdkVersion 28
|
||||||
multiDexEnabled true
|
multiDexEnabled true
|
||||||
versionCode 1500
|
versionCode 1500
|
||||||
version "2.8.2.1-dev"
|
version "2.8.2.1-dev-a"
|
||||||
buildConfigField "String", "VERSION", '"' + version + '"'
|
buildConfigField "String", "VERSION", '"' + version + '"'
|
||||||
buildConfigField "String", "BUILDVERSION", '"' + generateGitBuild() + '-' + generateDate() + '"'
|
buildConfigField "String", "BUILDVERSION", '"' + generateGitBuild() + '-' + generateDate() + '"'
|
||||||
buildConfigField "String", "REMOTE", '"' + generateGitRemote() + '"'
|
buildConfigField "String", "REMOTE", '"' + generateGitRemote() + '"'
|
||||||
|
@ -241,9 +241,6 @@ dependencies {
|
||||||
|
|
||||||
implementation fileTree(include: ['*.jar'], dir: 'libs')
|
implementation fileTree(include: ['*.jar'], dir: 'libs')
|
||||||
|
|
||||||
// https://github.com/DavidProdinger/Weekdays-Selector (used outdated 'com.amulyakhare:com.amulyakhare.textdrawable:1.0.1')
|
|
||||||
implementation(name: 'weekdaysselector-1.1.1', ext: 'aar')
|
|
||||||
|
|
||||||
testImplementation "junit:junit:$junit_version"
|
testImplementation "junit:junit:$junit_version"
|
||||||
testImplementation 'org.json:json:20201115'
|
testImplementation 'org.json:json:20201115'
|
||||||
testImplementation "org.mockito:mockito-core:${mockitoVersion}"
|
testImplementation "org.mockito:mockito-core:${mockitoVersion}"
|
||||||
|
@ -258,7 +255,7 @@ dependencies {
|
||||||
testImplementation "org.skyscreamer:jsonassert:1.5.0"
|
testImplementation "org.skyscreamer:jsonassert:1.5.0"
|
||||||
testImplementation "org.hamcrest:hamcrest-all:1.3"
|
testImplementation "org.hamcrest:hamcrest-all:1.3"
|
||||||
|
|
||||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0-alpha03'
|
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0-alpha04'
|
||||||
androidTestImplementation "androidx.test.ext:junit:$androidx_junit"
|
androidTestImplementation "androidx.test.ext:junit:$androidx_junit"
|
||||||
androidTestImplementation "androidx.test:rules:$androidx_rules"
|
androidTestImplementation "androidx.test:rules:$androidx_rules"
|
||||||
|
|
||||||
|
|
Binary file not shown.
|
@ -13,12 +13,13 @@ abstract class WizardModule {
|
||||||
@ContributesAndroidInjector abstract fun swBreakInjector(): SWBreak
|
@ContributesAndroidInjector abstract fun swBreakInjector(): SWBreak
|
||||||
@ContributesAndroidInjector abstract fun swButtonInjector(): SWButton
|
@ContributesAndroidInjector abstract fun swButtonInjector(): SWButton
|
||||||
@ContributesAndroidInjector abstract fun swEditNumberWithUnitsInjector(): SWEditNumberWithUnits
|
@ContributesAndroidInjector abstract fun swEditNumberWithUnitsInjector(): SWEditNumberWithUnits
|
||||||
|
@ContributesAndroidInjector abstract fun swEditNumberInjector(): SWEditNumber
|
||||||
@ContributesAndroidInjector abstract fun swEditStringInjector(): SWEditString
|
@ContributesAndroidInjector abstract fun swEditStringInjector(): SWEditString
|
||||||
@ContributesAndroidInjector abstract fun swEditEncryptedPasswordInjector(): SWEditEncryptedPassword
|
@ContributesAndroidInjector abstract fun swEditEncryptedPasswordInjector(): SWEditEncryptedPassword
|
||||||
@ContributesAndroidInjector abstract fun swEditUrlInjector(): SWEditUrl
|
@ContributesAndroidInjector abstract fun swEditUrlInjector(): SWEditUrl
|
||||||
@ContributesAndroidInjector abstract fun swFragmentInjector(): SWFragment
|
@ContributesAndroidInjector abstract fun swFragmentInjector(): SWFragment
|
||||||
@ContributesAndroidInjector abstract fun swHtmlLinkInjector(): SWHtmlLink
|
@ContributesAndroidInjector abstract fun swHtmlLinkInjector(): SWHtmlLink
|
||||||
@ContributesAndroidInjector abstract fun swInfotextInjector(): SWInfotext
|
@ContributesAndroidInjector abstract fun swInfotextInjector(): SWInfoText
|
||||||
@ContributesAndroidInjector abstract fun swItemInjector(): SWItem
|
@ContributesAndroidInjector abstract fun swItemInjector(): SWItem
|
||||||
@ContributesAndroidInjector abstract fun swPluginInjector(): SWPlugin
|
@ContributesAndroidInjector abstract fun swPluginInjector(): SWPlugin
|
||||||
@ContributesAndroidInjector abstract fun swRadioButtonInjector(): SWRadioButton
|
@ContributesAndroidInjector abstract fun swRadioButtonInjector(): SWRadioButton
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package info.nightscout.androidaps.dialogs
|
package info.nightscout.androidaps.dialogs
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
@ -92,12 +91,7 @@ class ExtendedBolusDialog : DialogFragmentWithDate() {
|
||||||
commandQueue.extendedBolus(insulinAfterConstraint, durationInMinutes, object : Callback() {
|
commandQueue.extendedBolus(insulinAfterConstraint, durationInMinutes, object : Callback() {
|
||||||
override fun run() {
|
override fun run() {
|
||||||
if (!result.success) {
|
if (!result.success) {
|
||||||
val i = Intent(ctx, ErrorHelperActivity::class.java)
|
ErrorHelperActivity.runAlarm(ctx, result.comment, resourceHelper.gs(R.string.treatmentdeliveryerror), info.nightscout.androidaps.dana.R.raw.boluserror)
|
||||||
i.putExtra("soundid", R.raw.boluserror)
|
|
||||||
i.putExtra("status", result.comment)
|
|
||||||
i.putExtra("title", resourceHelper.gs(R.string.treatmentdeliveryerror))
|
|
||||||
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
|
||||||
ctx.startActivity(i)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package info.nightscout.androidaps.dialogs
|
package info.nightscout.androidaps.dialogs
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
@ -161,12 +160,7 @@ class FillDialog : DialogFragmentWithDate() {
|
||||||
commandQueue.bolus(detailedBolusInfo, object : Callback() {
|
commandQueue.bolus(detailedBolusInfo, object : Callback() {
|
||||||
override fun run() {
|
override fun run() {
|
||||||
if (!result.success) {
|
if (!result.success) {
|
||||||
val i = Intent(ctx, ErrorHelperActivity::class.java)
|
ErrorHelperActivity.runAlarm(ctx, result.comment, resourceHelper.gs(R.string.treatmentdeliveryerror), info.nightscout.androidaps.dana.R.raw.boluserror)
|
||||||
i.putExtra("soundid", R.raw.boluserror)
|
|
||||||
i.putExtra("status", result.comment)
|
|
||||||
i.putExtra("title", resourceHelper.gs(R.string.treatmentdeliveryerror))
|
|
||||||
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
|
||||||
ctx.startActivity(i)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package info.nightscout.androidaps.dialogs
|
package info.nightscout.androidaps.dialogs
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.text.Editable
|
import android.text.Editable
|
||||||
import android.text.TextWatcher
|
import android.text.TextWatcher
|
||||||
|
@ -206,12 +205,7 @@ class InsulinDialog : DialogFragmentWithDate() {
|
||||||
commandQueue.bolus(detailedBolusInfo, object : Callback() {
|
commandQueue.bolus(detailedBolusInfo, object : Callback() {
|
||||||
override fun run() {
|
override fun run() {
|
||||||
if (!result.success) {
|
if (!result.success) {
|
||||||
val i = Intent(ctx, ErrorHelperActivity::class.java)
|
ErrorHelperActivity.runAlarm(ctx, result.comment, resourceHelper.gs(R.string.treatmentdeliveryerror), info.nightscout.androidaps.dana.R.raw.boluserror)
|
||||||
i.putExtra("soundid", R.raw.boluserror)
|
|
||||||
i.putExtra("status", result.comment)
|
|
||||||
i.putExtra("title", resourceHelper.gs(R.string.treatmentdeliveryerror))
|
|
||||||
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
|
||||||
ctx.startActivity(i)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package info.nightscout.androidaps.dialogs
|
package info.nightscout.androidaps.dialogs
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.os.Handler
|
import android.os.Handler
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
|
@ -14,7 +13,8 @@ import dagger.android.support.DaggerDialogFragment
|
||||||
import info.nightscout.androidaps.R
|
import info.nightscout.androidaps.R
|
||||||
import info.nightscout.androidaps.activities.ErrorHelperActivity
|
import info.nightscout.androidaps.activities.ErrorHelperActivity
|
||||||
import info.nightscout.androidaps.databinding.DialogLoopBinding
|
import info.nightscout.androidaps.databinding.DialogLoopBinding
|
||||||
import info.nightscout.androidaps.events.*
|
import info.nightscout.androidaps.events.EventPreferenceChange
|
||||||
|
import info.nightscout.androidaps.events.EventRefreshOverview
|
||||||
import info.nightscout.androidaps.interfaces.*
|
import info.nightscout.androidaps.interfaces.*
|
||||||
import info.nightscout.androidaps.logging.AAPSLogger
|
import info.nightscout.androidaps.logging.AAPSLogger
|
||||||
import info.nightscout.androidaps.logging.UserEntryLogger
|
import info.nightscout.androidaps.logging.UserEntryLogger
|
||||||
|
@ -53,6 +53,7 @@ class LoopDialog : DaggerDialogFragment() {
|
||||||
private var _binding: DialogLoopBinding? = null
|
private var _binding: DialogLoopBinding? = null
|
||||||
private var loopHandler = Handler()
|
private var loopHandler = Handler()
|
||||||
private var refreshDialog: Runnable? = null
|
private var refreshDialog: Runnable? = null
|
||||||
|
|
||||||
// This property is only valid between onCreateView and
|
// This property is only valid between onCreateView and
|
||||||
// onDestroyView.
|
// onDestroyView.
|
||||||
private val binding get() = _binding!!
|
private val binding get() = _binding!!
|
||||||
|
@ -293,12 +294,7 @@ class LoopDialog : DaggerDialogFragment() {
|
||||||
commandQueue.cancelTempBasal(true, object : Callback() {
|
commandQueue.cancelTempBasal(true, object : Callback() {
|
||||||
override fun run() {
|
override fun run() {
|
||||||
if (!result.success) {
|
if (!result.success) {
|
||||||
val i = Intent(ctx, ErrorHelperActivity::class.java)
|
ErrorHelperActivity.runAlarm(ctx, result.comment, resourceHelper.gs(R.string.tempbasaldeliveryerror), info.nightscout.androidaps.dana.R.raw.boluserror)
|
||||||
i.putExtra("soundid", R.raw.boluserror)
|
|
||||||
i.putExtra("status", result.comment)
|
|
||||||
i.putExtra("title", resourceHelper.gs(R.string.tempbasaldeliveryerror))
|
|
||||||
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
|
||||||
ctx.startActivity(i)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package info.nightscout.androidaps.dialogs
|
package info.nightscout.androidaps.dialogs
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
@ -121,12 +120,7 @@ class TempBasalDialog : DialogFragmentWithDate() {
|
||||||
val callback: Callback = object : Callback() {
|
val callback: Callback = object : Callback() {
|
||||||
override fun run() {
|
override fun run() {
|
||||||
if (!result.success) {
|
if (!result.success) {
|
||||||
val i = Intent(ctx, ErrorHelperActivity::class.java)
|
ErrorHelperActivity.runAlarm(ctx, result.comment, resourceHelper.gs(R.string.tempbasaldeliveryerror), info.nightscout.androidaps.dana.R.raw.boluserror)
|
||||||
i.putExtra("soundid", R.raw.boluserror)
|
|
||||||
i.putExtra("status", result.comment)
|
|
||||||
i.putExtra("title", resourceHelper.gs(R.string.tempbasaldeliveryerror))
|
|
||||||
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
|
||||||
ctx.startActivity(i)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package info.nightscout.androidaps.dialogs
|
package info.nightscout.androidaps.dialogs
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.text.Editable
|
import android.text.Editable
|
||||||
import android.text.TextWatcher
|
import android.text.TextWatcher
|
||||||
|
@ -142,12 +141,7 @@ class TreatmentDialog : DialogFragmentWithDate() {
|
||||||
commandQueue.bolus(detailedBolusInfo, object : Callback() {
|
commandQueue.bolus(detailedBolusInfo, object : Callback() {
|
||||||
override fun run() {
|
override fun run() {
|
||||||
if (!result.success) {
|
if (!result.success) {
|
||||||
val i = Intent(ctx, ErrorHelperActivity::class.java)
|
ErrorHelperActivity.runAlarm(ctx, result.comment, resourceHelper.gs(R.string.treatmentdeliveryerror), info.nightscout.androidaps.dana.R.raw.boluserror)
|
||||||
i.putExtra("soundid", R.raw.boluserror)
|
|
||||||
i.putExtra("status", result.comment)
|
|
||||||
i.putExtra("title", resourceHelper.gs(R.string.treatmentdeliveryerror))
|
|
||||||
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
|
||||||
ctx.startActivity(i)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,63 +0,0 @@
|
||||||
package info.nightscout.androidaps.plugins.aps.logger;
|
|
||||||
|
|
||||||
import org.mozilla.javascript.ScriptableObject;
|
|
||||||
|
|
||||||
import javax.inject.Inject;
|
|
||||||
|
|
||||||
import info.nightscout.androidaps.db.StaticInjector;
|
|
||||||
import info.nightscout.androidaps.logging.AAPSLogger;
|
|
||||||
import info.nightscout.androidaps.logging.LTag;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Created by adrian on 15/10/17.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
public class LoggerCallback extends ScriptableObject {
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
AAPSLogger aapsLogger;
|
|
||||||
|
|
||||||
private static StringBuffer errorBuffer = new StringBuffer();
|
|
||||||
private static StringBuffer logBuffer = new StringBuffer();
|
|
||||||
|
|
||||||
|
|
||||||
public LoggerCallback() {
|
|
||||||
//empty constructor needed for Rhino
|
|
||||||
errorBuffer = new StringBuffer();
|
|
||||||
logBuffer = new StringBuffer();
|
|
||||||
StaticInjector.Companion.getInstance().androidInjector().inject(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getClassName() {
|
|
||||||
return "LoggerCallback";
|
|
||||||
}
|
|
||||||
|
|
||||||
public void jsConstructor() {
|
|
||||||
//empty constructor on JS site; could work as setter
|
|
||||||
}
|
|
||||||
|
|
||||||
public void jsFunction_log(Object obj1) {
|
|
||||||
aapsLogger.debug(LTag.APS, obj1.toString().trim());
|
|
||||||
logBuffer.append(obj1.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
public void jsFunction_error(Object obj1) {
|
|
||||||
aapsLogger.error(LTag.APS, obj1.toString().trim());
|
|
||||||
errorBuffer.append(obj1.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static String getScriptDebug() {
|
|
||||||
String ret = "";
|
|
||||||
if (errorBuffer.length() > 0) {
|
|
||||||
ret += "e:\n" + errorBuffer.toString();
|
|
||||||
}
|
|
||||||
if (ret.length() > 0 && logBuffer.length() > 0) ret += '\n';
|
|
||||||
if (logBuffer.length() > 0) {
|
|
||||||
ret += "d:\n" + logBuffer.toString();
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,61 @@
|
||||||
|
package info.nightscout.androidaps.plugins.aps.logger
|
||||||
|
|
||||||
|
import info.nightscout.androidaps.db.StaticInjector
|
||||||
|
import info.nightscout.androidaps.logging.AAPSLogger
|
||||||
|
import info.nightscout.androidaps.logging.LTag
|
||||||
|
import org.mozilla.javascript.ScriptableObject
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
@Suppress("unused", "FunctionName")
|
||||||
|
class LoggerCallback : ScriptableObject() {
|
||||||
|
|
||||||
|
@Inject lateinit var aapsLogger: AAPSLogger
|
||||||
|
|
||||||
|
override fun getClassName(): String = "LoggerCallback"
|
||||||
|
|
||||||
|
fun jsConstructor() {
|
||||||
|
//empty constructor on JS site; could work as setter
|
||||||
|
}
|
||||||
|
|
||||||
|
fun jsFunction_log(obj1: Any) {
|
||||||
|
aapsLogger.debug(LTag.APS, obj1.toString().trim { it <= ' ' })
|
||||||
|
logBuffer.append(obj1.toString())
|
||||||
|
}
|
||||||
|
|
||||||
|
fun jsFunction_error(obj1: Any) {
|
||||||
|
aapsLogger.error(LTag.APS, obj1.toString().trim { it <= ' ' })
|
||||||
|
errorBuffer.append(obj1.toString())
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
private var errorBuffer = StringBuffer()
|
||||||
|
private var logBuffer = StringBuffer()
|
||||||
|
val scriptDebug: String
|
||||||
|
get() {
|
||||||
|
var ret = ""
|
||||||
|
if (errorBuffer.isNotEmpty()) {
|
||||||
|
ret += """
|
||||||
|
e:
|
||||||
|
$errorBuffer
|
||||||
|
""".trimIndent()
|
||||||
|
}
|
||||||
|
if (ret.isNotEmpty() && logBuffer.isNotEmpty()) ret += '\n'
|
||||||
|
if (logBuffer.isNotEmpty()) {
|
||||||
|
ret += """
|
||||||
|
d:
|
||||||
|
$logBuffer
|
||||||
|
""".trimIndent()
|
||||||
|
}
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
//empty constructor needed for Rhino
|
||||||
|
errorBuffer = StringBuffer()
|
||||||
|
logBuffer = StringBuffer()
|
||||||
|
@Suppress("DEPRECATION")
|
||||||
|
StaticInjector.Companion.getInstance().androidInjector().inject(this)
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,880 +0,0 @@
|
||||||
package info.nightscout.androidaps.plugins.aps.loop;
|
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
|
||||||
import android.app.NotificationChannel;
|
|
||||||
import android.app.NotificationManager;
|
|
||||||
import android.app.PendingIntent;
|
|
||||||
import android.app.TaskStackBuilder;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.os.SystemClock;
|
|
||||||
|
|
||||||
import androidx.core.app.NotificationCompat;
|
|
||||||
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
import org.json.JSONException;
|
|
||||||
import org.json.JSONObject;
|
|
||||||
|
|
||||||
import javax.inject.Inject;
|
|
||||||
import javax.inject.Singleton;
|
|
||||||
|
|
||||||
import dagger.Lazy;
|
|
||||||
import dagger.android.HasAndroidInjector;
|
|
||||||
import info.nightscout.androidaps.BuildConfig;
|
|
||||||
import info.nightscout.androidaps.Config;
|
|
||||||
import info.nightscout.androidaps.Constants;
|
|
||||||
import info.nightscout.androidaps.MainActivity;
|
|
||||||
import info.nightscout.androidaps.MainApp;
|
|
||||||
import info.nightscout.androidaps.R;
|
|
||||||
import info.nightscout.androidaps.activities.ErrorHelperActivity;
|
|
||||||
import info.nightscout.androidaps.data.DetailedBolusInfo;
|
|
||||||
import info.nightscout.androidaps.data.Profile;
|
|
||||||
import info.nightscout.androidaps.data.PumpEnactResult;
|
|
||||||
import info.nightscout.androidaps.database.entities.GlucoseValue;
|
|
||||||
import info.nightscout.androidaps.db.CareportalEvent;
|
|
||||||
import info.nightscout.androidaps.db.Source;
|
|
||||||
import info.nightscout.androidaps.db.TemporaryBasal;
|
|
||||||
import info.nightscout.androidaps.events.EventAcceptOpenLoopChange;
|
|
||||||
import info.nightscout.androidaps.events.EventNewBG;
|
|
||||||
import info.nightscout.androidaps.events.EventTempTargetChange;
|
|
||||||
import info.nightscout.androidaps.interfaces.APSInterface;
|
|
||||||
import info.nightscout.androidaps.interfaces.ActivePluginProvider;
|
|
||||||
import info.nightscout.androidaps.interfaces.CommandQueueProvider;
|
|
||||||
import info.nightscout.androidaps.interfaces.Constraint;
|
|
||||||
import info.nightscout.androidaps.interfaces.LoopInterface;
|
|
||||||
import info.nightscout.androidaps.interfaces.PluginBase;
|
|
||||||
import info.nightscout.androidaps.interfaces.PluginDescription;
|
|
||||||
import info.nightscout.androidaps.interfaces.PluginType;
|
|
||||||
import info.nightscout.androidaps.interfaces.ProfileFunction;
|
|
||||||
import info.nightscout.androidaps.interfaces.PumpDescription;
|
|
||||||
import info.nightscout.androidaps.interfaces.PumpInterface;
|
|
||||||
import info.nightscout.androidaps.logging.AAPSLogger;
|
|
||||||
import info.nightscout.androidaps.logging.LTag;
|
|
||||||
import info.nightscout.androidaps.plugins.aps.loop.events.EventLoopSetLastRunGui;
|
|
||||||
import info.nightscout.androidaps.plugins.aps.loop.events.EventLoopUpdateGui;
|
|
||||||
import info.nightscout.androidaps.plugins.aps.loop.events.EventNewOpenLoopNotification;
|
|
||||||
import info.nightscout.androidaps.plugins.bus.RxBusWrapper;
|
|
||||||
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker;
|
|
||||||
import info.nightscout.androidaps.plugins.general.nsclient.NSUpload;
|
|
||||||
import info.nightscout.androidaps.plugins.general.overview.events.EventDismissNotification;
|
|
||||||
import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification;
|
|
||||||
import info.nightscout.androidaps.plugins.general.overview.notifications.Notification;
|
|
||||||
import info.nightscout.androidaps.plugins.general.wear.ActionStringHandler;
|
|
||||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin;
|
|
||||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventAutosensCalculationFinished;
|
|
||||||
import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpPlugin;
|
|
||||||
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin;
|
|
||||||
import info.nightscout.androidaps.queue.Callback;
|
|
||||||
import info.nightscout.androidaps.queue.commands.Command;
|
|
||||||
import info.nightscout.androidaps.receivers.ReceiverStatusStore;
|
|
||||||
import info.nightscout.androidaps.utils.DateUtil;
|
|
||||||
import info.nightscout.androidaps.utils.FabricPrivacy;
|
|
||||||
import info.nightscout.androidaps.utils.HardLimits;
|
|
||||||
import info.nightscout.androidaps.utils.T;
|
|
||||||
import info.nightscout.androidaps.utils.resources.ResourceHelper;
|
|
||||||
import info.nightscout.androidaps.utils.rx.AapsSchedulers;
|
|
||||||
import info.nightscout.androidaps.utils.sharedPreferences.SP;
|
|
||||||
import io.reactivex.disposables.CompositeDisposable;
|
|
||||||
|
|
||||||
@Singleton
|
|
||||||
public class LoopPlugin extends PluginBase implements LoopInterface {
|
|
||||||
private final HasAndroidInjector injector;
|
|
||||||
private final SP sp;
|
|
||||||
private final RxBusWrapper rxBus;
|
|
||||||
private final AapsSchedulers aapsSchedulers;
|
|
||||||
private final ConstraintChecker constraintChecker;
|
|
||||||
private final ResourceHelper resourceHelper;
|
|
||||||
private final ProfileFunction profileFunction;
|
|
||||||
private final Context context;
|
|
||||||
private final CommandQueueProvider commandQueue;
|
|
||||||
private final ActivePluginProvider activePlugin;
|
|
||||||
private final TreatmentsPlugin treatmentsPlugin;
|
|
||||||
private final VirtualPumpPlugin virtualPumpPlugin;
|
|
||||||
private final Lazy<ActionStringHandler> actionStringHandler;
|
|
||||||
private final IobCobCalculatorPlugin iobCobCalculatorPlugin;
|
|
||||||
private final ReceiverStatusStore receiverStatusStore;
|
|
||||||
private final FabricPrivacy fabricPrivacy;
|
|
||||||
private final NSUpload nsUpload;
|
|
||||||
private final HardLimits hardLimits;
|
|
||||||
|
|
||||||
private final CompositeDisposable disposable = new CompositeDisposable();
|
|
||||||
|
|
||||||
private static final String CHANNEL_ID = "AndroidAPS-Openloop";
|
|
||||||
|
|
||||||
private long lastBgTriggeredRun = 0;
|
|
||||||
|
|
||||||
private long loopSuspendedTill; // end of manual loop suspend
|
|
||||||
private boolean isSuperBolus;
|
|
||||||
private boolean isDisconnected;
|
|
||||||
|
|
||||||
private long carbsSuggestionsSuspendedUntil = 0;
|
|
||||||
private int prevCarbsreq = 0;
|
|
||||||
|
|
||||||
@Nullable private LastRun lastRun = null;
|
|
||||||
|
|
||||||
@Nullable @Override public LastRun getLastRun() {
|
|
||||||
return lastRun;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public void setLastRun(@Nullable LastRun lastRun) {
|
|
||||||
this.lastRun = lastRun;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
public LoopPlugin(
|
|
||||||
HasAndroidInjector injector,
|
|
||||||
AAPSLogger aapsLogger,
|
|
||||||
AapsSchedulers aapsSchedulers,
|
|
||||||
RxBusWrapper rxBus,
|
|
||||||
SP sp,
|
|
||||||
Config config,
|
|
||||||
ConstraintChecker constraintChecker,
|
|
||||||
ResourceHelper resourceHelper,
|
|
||||||
ProfileFunction profileFunction,
|
|
||||||
Context context,
|
|
||||||
CommandQueueProvider commandQueue,
|
|
||||||
ActivePluginProvider activePlugin,
|
|
||||||
TreatmentsPlugin treatmentsPlugin,
|
|
||||||
VirtualPumpPlugin virtualPumpPlugin,
|
|
||||||
Lazy<ActionStringHandler> actionStringHandler, // TODO Adrian use RxBus instead of Lazy
|
|
||||||
IobCobCalculatorPlugin iobCobCalculatorPlugin,
|
|
||||||
ReceiverStatusStore receiverStatusStore,
|
|
||||||
FabricPrivacy fabricPrivacy,
|
|
||||||
NSUpload nsUpload,
|
|
||||||
HardLimits hardLimits
|
|
||||||
) {
|
|
||||||
super(new PluginDescription()
|
|
||||||
.mainType(PluginType.LOOP)
|
|
||||||
.fragmentClass(LoopFragment.class.getName())
|
|
||||||
.pluginIcon(R.drawable.ic_loop_closed_white)
|
|
||||||
.pluginName(R.string.loop)
|
|
||||||
.shortName(R.string.loop_shortname)
|
|
||||||
.preferencesId(R.xml.pref_loop)
|
|
||||||
.enableByDefault(config.getAPS())
|
|
||||||
.description(R.string.description_loop),
|
|
||||||
aapsLogger, resourceHelper, injector
|
|
||||||
);
|
|
||||||
this.injector = injector;
|
|
||||||
this.aapsSchedulers = aapsSchedulers;
|
|
||||||
this.sp = sp;
|
|
||||||
this.rxBus = rxBus;
|
|
||||||
this.constraintChecker = constraintChecker;
|
|
||||||
this.resourceHelper = resourceHelper;
|
|
||||||
this.profileFunction = profileFunction;
|
|
||||||
this.context = context;
|
|
||||||
this.activePlugin = activePlugin;
|
|
||||||
this.commandQueue = commandQueue;
|
|
||||||
this.treatmentsPlugin = treatmentsPlugin;
|
|
||||||
this.virtualPumpPlugin = virtualPumpPlugin;
|
|
||||||
this.actionStringHandler = actionStringHandler;
|
|
||||||
this.iobCobCalculatorPlugin = iobCobCalculatorPlugin;
|
|
||||||
this.receiverStatusStore = receiverStatusStore;
|
|
||||||
this.fabricPrivacy = fabricPrivacy;
|
|
||||||
this.nsUpload = nsUpload;
|
|
||||||
this.hardLimits = hardLimits;
|
|
||||||
|
|
||||||
loopSuspendedTill = sp.getLong("loopSuspendedTill", 0L);
|
|
||||||
isSuperBolus = sp.getBoolean("isSuperBolus", false);
|
|
||||||
isDisconnected = sp.getBoolean("isDisconnected", false);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onStart() {
|
|
||||||
createNotificationChannel();
|
|
||||||
super.onStart();
|
|
||||||
disposable.add(rxBus
|
|
||||||
.toObservable(EventTempTargetChange.class)
|
|
||||||
.observeOn(aapsSchedulers.getIo())
|
|
||||||
.subscribe(event -> invoke("EventTempTargetChange", true), fabricPrivacy::logException)
|
|
||||||
);
|
|
||||||
/*
|
|
||||||
This method is triggered once autosens calculation has completed, so the LoopPlugin
|
|
||||||
has current data to work with. However, autosens calculation can be triggered by multiple
|
|
||||||
sources and currently only a new BG should trigger a loop run. Hence we return early if
|
|
||||||
the event causing the calculation is not EventNewBg.
|
|
||||||
<p>
|
|
||||||
*/
|
|
||||||
disposable.add(rxBus
|
|
||||||
.toObservable(EventAutosensCalculationFinished.class)
|
|
||||||
.observeOn(aapsSchedulers.getIo())
|
|
||||||
.subscribe(event -> {
|
|
||||||
// Autosens calculation not triggered by a new BG
|
|
||||||
if (!(event.getCause() instanceof EventNewBG)) return;
|
|
||||||
|
|
||||||
GlucoseValue glucoseValue = iobCobCalculatorPlugin.actualBg();
|
|
||||||
// BG outdated
|
|
||||||
if (glucoseValue == null) return;
|
|
||||||
// already looped with that value
|
|
||||||
if (glucoseValue.getTimestamp() <= lastBgTriggeredRun) return;
|
|
||||||
|
|
||||||
lastBgTriggeredRun = glucoseValue.getTimestamp();
|
|
||||||
invoke("AutosenseCalculation for " + glucoseValue, true);
|
|
||||||
}, fabricPrivacy::logException)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void createNotificationChannel() {
|
|
||||||
NotificationManager mNotificationManager =
|
|
||||||
(NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
|
|
||||||
@SuppressLint("WrongConstant") NotificationChannel channel = new NotificationChannel(CHANNEL_ID,
|
|
||||||
CHANNEL_ID,
|
|
||||||
NotificationManager.IMPORTANCE_HIGH);
|
|
||||||
mNotificationManager.createNotificationChannel(channel);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onStop() {
|
|
||||||
disposable.clear();
|
|
||||||
super.onStop();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean specialEnableCondition() {
|
|
||||||
try {
|
|
||||||
PumpInterface pump = activePlugin.getActivePump();
|
|
||||||
return pump.getPumpDescription().isTempBasalCapable;
|
|
||||||
} catch (Exception ignored) {
|
|
||||||
// may fail during initialization
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void suspendTo(long endTime) {
|
|
||||||
loopSuspendedTill = endTime;
|
|
||||||
isSuperBolus = false;
|
|
||||||
isDisconnected = false;
|
|
||||||
sp.putLong("loopSuspendedTill", loopSuspendedTill);
|
|
||||||
sp.putBoolean("isSuperBolus", isSuperBolus);
|
|
||||||
sp.putBoolean("isDisconnected", isDisconnected);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void superBolusTo(long endTime) {
|
|
||||||
loopSuspendedTill = endTime;
|
|
||||||
isSuperBolus = true;
|
|
||||||
isDisconnected = false;
|
|
||||||
sp.putLong("loopSuspendedTill", loopSuspendedTill);
|
|
||||||
sp.putBoolean("isSuperBolus", isSuperBolus);
|
|
||||||
sp.putBoolean("isDisconnected", isDisconnected);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void disconnectTo(long endTime) {
|
|
||||||
loopSuspendedTill = endTime;
|
|
||||||
isSuperBolus = false;
|
|
||||||
isDisconnected = true;
|
|
||||||
sp.putLong("loopSuspendedTill", loopSuspendedTill);
|
|
||||||
sp.putBoolean("isSuperBolus", isSuperBolus);
|
|
||||||
sp.putBoolean("isDisconnected", isDisconnected);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int minutesToEndOfSuspend() {
|
|
||||||
if (loopSuspendedTill == 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
long now = System.currentTimeMillis();
|
|
||||||
long msecDiff = loopSuspendedTill - now;
|
|
||||||
|
|
||||||
if (loopSuspendedTill <= now) { // time exceeded
|
|
||||||
suspendTo(0L);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (int) (msecDiff / 60d / 1000d);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isSuspended() {
|
|
||||||
if (loopSuspendedTill == 0)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
long now = System.currentTimeMillis();
|
|
||||||
|
|
||||||
if (loopSuspendedTill <= now) { // time exceeded
|
|
||||||
suspendTo(0L);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isLGS() {
|
|
||||||
Constraint<Boolean> closedLoopEnabled = constraintChecker.isClosedLoopAllowed();
|
|
||||||
Double MaxIOBallowed = constraintChecker.getMaxIOBAllowed().value();
|
|
||||||
String APSmode = sp.getString(R.string.key_aps_mode, "open");
|
|
||||||
PumpInterface pump = activePlugin.getActivePump();
|
|
||||||
boolean isLGS = false;
|
|
||||||
|
|
||||||
if (!isSuspended() && !pump.isSuspended())
|
|
||||||
if (closedLoopEnabled.value())
|
|
||||||
if ((MaxIOBallowed.equals(hardLimits.getMAXIOB_LGS())) || (APSmode.equals("lgs")))
|
|
||||||
isLGS = true;
|
|
||||||
|
|
||||||
return isLGS;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isSuperBolus() {
|
|
||||||
if (loopSuspendedTill == 0)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
long now = System.currentTimeMillis();
|
|
||||||
|
|
||||||
if (loopSuspendedTill <= now) { // time exceeded
|
|
||||||
suspendTo(0L);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return isSuperBolus;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isDisconnected() {
|
|
||||||
if (loopSuspendedTill == 0)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
long now = System.currentTimeMillis();
|
|
||||||
|
|
||||||
if (loopSuspendedTill <= now) { // time exceeded
|
|
||||||
suspendTo(0L);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return isDisconnected;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean treatmentTimethreshold(int duartionMinutes) {
|
|
||||||
long threshold = System.currentTimeMillis() + (duartionMinutes * 60 * 1000);
|
|
||||||
boolean bool = false;
|
|
||||||
if (treatmentsPlugin.getLastBolusTime() > threshold || treatmentsPlugin.getLastCarbTime() > threshold)
|
|
||||||
bool = true;
|
|
||||||
|
|
||||||
return bool;
|
|
||||||
}
|
|
||||||
|
|
||||||
public synchronized void invoke(String initiator, boolean allowNotification) {
|
|
||||||
invoke(initiator, allowNotification, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public synchronized void invoke(String initiator, boolean allowNotification, boolean tempBasalFallback) {
|
|
||||||
try {
|
|
||||||
getAapsLogger().debug(LTag.APS, "invoke from " + initiator);
|
|
||||||
Constraint<Boolean> loopEnabled = constraintChecker.isLoopInvocationAllowed();
|
|
||||||
|
|
||||||
if (!loopEnabled.value()) {
|
|
||||||
String message = resourceHelper.gs(R.string.loopdisabled) + "\n" + loopEnabled.getReasons(getAapsLogger());
|
|
||||||
getAapsLogger().debug(LTag.APS, message);
|
|
||||||
rxBus.send(new EventLoopSetLastRunGui(message));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
final PumpInterface pump = activePlugin.getActivePump();
|
|
||||||
APSResult result = null;
|
|
||||||
|
|
||||||
if (!isEnabled(PluginType.LOOP))
|
|
||||||
return;
|
|
||||||
|
|
||||||
Profile profile = profileFunction.getProfile();
|
|
||||||
|
|
||||||
if (profile == null || !profileFunction.isProfileValid("Loop")) {
|
|
||||||
getAapsLogger().debug(LTag.APS, resourceHelper.gs(R.string.noprofileselected));
|
|
||||||
rxBus.send(new EventLoopSetLastRunGui(resourceHelper.gs(R.string.noprofileselected)));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if pump info is loaded
|
|
||||||
if (pump.getBaseBasalRate() < 0.01d) return;
|
|
||||||
|
|
||||||
APSInterface usedAPS = activePlugin.getActiveAPS();
|
|
||||||
if (((PluginBase) usedAPS).isEnabled(PluginType.APS)) {
|
|
||||||
usedAPS.invoke(initiator, tempBasalFallback);
|
|
||||||
result = usedAPS.getLastAPSResult();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if we have any result
|
|
||||||
if (result == null) {
|
|
||||||
rxBus.send(new EventLoopSetLastRunGui(resourceHelper.gs(R.string.noapsselected)));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Prepare for pumps using % basals
|
|
||||||
if (pump.getPumpDescription().tempBasalStyle == PumpDescription.PERCENT && allowPercentage()) {
|
|
||||||
result.setUsePercent(true);
|
|
||||||
}
|
|
||||||
result.setPercent((int) (result.getRate() / profile.getBasal() * 100));
|
|
||||||
|
|
||||||
// check rate for constraints
|
|
||||||
final APSResult resultAfterConstraints = result.newAndClone(injector);
|
|
||||||
resultAfterConstraints.setRateConstraint(new Constraint<>(resultAfterConstraints.getRate()));
|
|
||||||
resultAfterConstraints.setRate(constraintChecker.applyBasalConstraints(resultAfterConstraints.getRateConstraint(), profile).value());
|
|
||||||
|
|
||||||
resultAfterConstraints.setPercentConstraint(new Constraint<>(resultAfterConstraints.getPercent()));
|
|
||||||
resultAfterConstraints.setPercent(constraintChecker.applyBasalPercentConstraints(resultAfterConstraints.getPercentConstraint(), profile).value());
|
|
||||||
|
|
||||||
resultAfterConstraints.setSmbConstraint(new Constraint<>(resultAfterConstraints.getSmb()));
|
|
||||||
resultAfterConstraints.setSmb(constraintChecker.applyBolusConstraints(resultAfterConstraints.getSmbConstraint()).value());
|
|
||||||
|
|
||||||
// safety check for multiple SMBs
|
|
||||||
long lastBolusTime = treatmentsPlugin.getLastBolusTime();
|
|
||||||
if (lastBolusTime != 0 && lastBolusTime + T.mins(3).msecs() > System.currentTimeMillis()) {
|
|
||||||
getAapsLogger().debug(LTag.APS, "SMB requested but still in 3 min interval");
|
|
||||||
resultAfterConstraints.setSmb(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (lastRun != null && lastRun.getConstraintsProcessed() != null) {
|
|
||||||
prevCarbsreq = lastRun.getConstraintsProcessed().getCarbsReq();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (lastRun == null) lastRun = new LastRun();
|
|
||||||
lastRun.setRequest(result);
|
|
||||||
lastRun.setConstraintsProcessed(resultAfterConstraints);
|
|
||||||
lastRun.setLastAPSRun(DateUtil.now());
|
|
||||||
lastRun.setSource(((PluginBase) usedAPS).getName());
|
|
||||||
lastRun.setTbrSetByPump(null);
|
|
||||||
lastRun.setSmbSetByPump(null);
|
|
||||||
lastRun.setLastTBREnact(0);
|
|
||||||
lastRun.setLastTBRRequest(0);
|
|
||||||
lastRun.setLastSMBEnact(0);
|
|
||||||
lastRun.setLastSMBRequest(0);
|
|
||||||
|
|
||||||
nsUpload.uploadDeviceStatus(this, iobCobCalculatorPlugin, profileFunction, activePlugin.getActivePump(), receiverStatusStore, BuildConfig.VERSION_NAME + "-" + BuildConfig.BUILDVERSION);
|
|
||||||
|
|
||||||
if (isSuspended()) {
|
|
||||||
getAapsLogger().debug(LTag.APS, resourceHelper.gs(R.string.loopsuspended));
|
|
||||||
rxBus.send(new EventLoopSetLastRunGui(resourceHelper.gs(R.string.loopsuspended)));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pump.isSuspended()) {
|
|
||||||
getAapsLogger().debug(LTag.APS, resourceHelper.gs(R.string.pumpsuspended));
|
|
||||||
rxBus.send(new EventLoopSetLastRunGui(resourceHelper.gs(R.string.pumpsuspended)));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Constraint<Boolean> closedLoopEnabled = constraintChecker.isClosedLoopAllowed();
|
|
||||||
|
|
||||||
if (closedLoopEnabled.value()) {
|
|
||||||
if (allowNotification) {
|
|
||||||
if (resultAfterConstraints.isCarbsRequired()
|
|
||||||
&& resultAfterConstraints.getCarbsReq() >= sp.getInt(R.string.key_smb_enable_carbs_suggestions_threshold, 0)
|
|
||||||
&& carbsSuggestionsSuspendedUntil < System.currentTimeMillis() && !treatmentTimethreshold(-15)) {
|
|
||||||
|
|
||||||
if (sp.getBoolean(R.string.key_enable_carbs_required_alert_local, true) && !sp.getBoolean(R.string.key_raise_notifications_as_android_notifications, true)) {
|
|
||||||
Notification carbreqlocal = new Notification(Notification.CARBS_REQUIRED, resultAfterConstraints.getCarbsRequiredText(), Notification.NORMAL);
|
|
||||||
rxBus.send(new EventNewNotification(carbreqlocal));
|
|
||||||
}
|
|
||||||
if (sp.getBoolean(R.string.key_ns_create_announcements_from_carbs_req, false)) {
|
|
||||||
nsUpload.uploadError(resultAfterConstraints.getCarbsRequiredText());
|
|
||||||
}
|
|
||||||
if (sp.getBoolean(R.string.key_enable_carbs_required_alert_local, true) && sp.getBoolean(R.string.key_raise_notifications_as_android_notifications, true)) {
|
|
||||||
Intent intentAction5m = new Intent(context, CarbSuggestionReceiver.class);
|
|
||||||
intentAction5m.putExtra("ignoreDuration", 5);
|
|
||||||
PendingIntent pendingIntent5m = PendingIntent.getBroadcast(context, 1, intentAction5m, PendingIntent.FLAG_UPDATE_CURRENT);
|
|
||||||
NotificationCompat.Action actionIgnore5m = new
|
|
||||||
NotificationCompat.Action(R.drawable.ic_notif_aaps, resourceHelper.gs(R.string.ignore5m, "Ignore 5m"), pendingIntent5m);
|
|
||||||
|
|
||||||
Intent intentAction15m = new Intent(context, CarbSuggestionReceiver.class);
|
|
||||||
intentAction15m.putExtra("ignoreDuration", 15);
|
|
||||||
PendingIntent pendingIntent15m = PendingIntent.getBroadcast(context, 1, intentAction15m, PendingIntent.FLAG_UPDATE_CURRENT);
|
|
||||||
NotificationCompat.Action actionIgnore15m = new
|
|
||||||
NotificationCompat.Action(R.drawable.ic_notif_aaps, resourceHelper.gs(R.string.ignore15m, "Ignore 15m"), pendingIntent15m);
|
|
||||||
|
|
||||||
Intent intentAction30m = new Intent(context, CarbSuggestionReceiver.class);
|
|
||||||
intentAction30m.putExtra("ignoreDuration", 30);
|
|
||||||
PendingIntent pendingIntent30m = PendingIntent.getBroadcast(context, 1, intentAction30m, PendingIntent.FLAG_UPDATE_CURRENT);
|
|
||||||
NotificationCompat.Action actionIgnore30m = new
|
|
||||||
NotificationCompat.Action(R.drawable.ic_notif_aaps, resourceHelper.gs(R.string.ignore30m, "Ignore 30m"), pendingIntent30m);
|
|
||||||
|
|
||||||
NotificationCompat.Builder builder = new NotificationCompat.Builder(context, CHANNEL_ID);
|
|
||||||
builder.setSmallIcon(R.drawable.notif_icon)
|
|
||||||
.setContentTitle(resourceHelper.gs(R.string.carbssuggestion))
|
|
||||||
.setContentText(resultAfterConstraints.getCarbsRequiredText())
|
|
||||||
.setAutoCancel(true)
|
|
||||||
.setPriority(Notification.IMPORTANCE_HIGH)
|
|
||||||
.setCategory(Notification.CATEGORY_ALARM)
|
|
||||||
.addAction(actionIgnore5m)
|
|
||||||
.addAction(actionIgnore15m)
|
|
||||||
.addAction(actionIgnore30m)
|
|
||||||
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
|
|
||||||
.setVibrate(new long[]{1000, 1000, 1000, 1000, 1000});
|
|
||||||
|
|
||||||
NotificationManager mNotificationManager =
|
|
||||||
(NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
|
|
||||||
|
|
||||||
// mId allows you to update the notification later on.
|
|
||||||
mNotificationManager.notify(Constants.notificationID, builder.build());
|
|
||||||
rxBus.send(new EventNewOpenLoopNotification());
|
|
||||||
|
|
||||||
//only send to wear if Native notifications are turned off
|
|
||||||
if (!sp.getBoolean(R.string.key_raise_notifications_as_android_notifications, true)) {
|
|
||||||
// Send to Wear
|
|
||||||
actionStringHandler.get().handleInitiate("changeRequest");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
//If carbs were required previously, but are no longer needed, dismiss notifications
|
|
||||||
if (prevCarbsreq > 0) {
|
|
||||||
dismissSuggestion();
|
|
||||||
rxBus.send(new EventDismissNotification(Notification.CARBS_REQUIRED));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (resultAfterConstraints.isChangeRequested()
|
|
||||||
&& !commandQueue.bolusInQueue()
|
|
||||||
&& !commandQueue.isRunning(Command.CommandType.BOLUS)) {
|
|
||||||
final PumpEnactResult waiting = new PumpEnactResult(getInjector());
|
|
||||||
waiting.queued = true;
|
|
||||||
if (resultAfterConstraints.getTempBasalRequested())
|
|
||||||
lastRun.setTbrSetByPump(waiting);
|
|
||||||
if (resultAfterConstraints.getBolusRequested())
|
|
||||||
lastRun.setSmbSetByPump(waiting);
|
|
||||||
rxBus.send(new EventLoopUpdateGui());
|
|
||||||
fabricPrivacy.logCustom("APSRequest");
|
|
||||||
applyTBRRequest(resultAfterConstraints, profile, new Callback() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
if (result.enacted || result.success) {
|
|
||||||
lastRun.setTbrSetByPump(result);
|
|
||||||
lastRun.setLastTBRRequest(lastRun.getLastAPSRun());
|
|
||||||
lastRun.setLastTBREnact(DateUtil.now());
|
|
||||||
rxBus.send(new EventLoopUpdateGui());
|
|
||||||
applySMBRequest(resultAfterConstraints, new Callback() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
// Callback is only called if a bolus was actually requested
|
|
||||||
if (result.enacted || result.success) {
|
|
||||||
lastRun.setSmbSetByPump(result);
|
|
||||||
lastRun.setLastSMBRequest(lastRun.getLastAPSRun());
|
|
||||||
lastRun.setLastSMBEnact(DateUtil.now());
|
|
||||||
} else {
|
|
||||||
new Thread(() -> {
|
|
||||||
SystemClock.sleep(1000);
|
|
||||||
invoke("tempBasalFallback", allowNotification, true);
|
|
||||||
}).start();
|
|
||||||
}
|
|
||||||
rxBus.send(new EventLoopUpdateGui());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
lastRun.setTbrSetByPump(result);
|
|
||||||
lastRun.setLastTBRRequest(lastRun.getLastAPSRun());
|
|
||||||
}
|
|
||||||
rxBus.send(new EventLoopUpdateGui());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
lastRun.setTbrSetByPump(null);
|
|
||||||
lastRun.setSmbSetByPump(null);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (resultAfterConstraints.isChangeRequested() && allowNotification) {
|
|
||||||
NotificationCompat.Builder builder =
|
|
||||||
new NotificationCompat.Builder(context, CHANNEL_ID);
|
|
||||||
builder.setSmallIcon(R.drawable.notif_icon)
|
|
||||||
.setContentTitle(resourceHelper.gs(R.string.openloop_newsuggestion))
|
|
||||||
.setContentText(resultAfterConstraints.toString())
|
|
||||||
.setAutoCancel(true)
|
|
||||||
.setPriority(Notification.IMPORTANCE_HIGH)
|
|
||||||
.setCategory(Notification.CATEGORY_ALARM)
|
|
||||||
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC);
|
|
||||||
if (sp.getBoolean("wearcontrol", false)) {
|
|
||||||
builder.setLocalOnly(true);
|
|
||||||
}
|
|
||||||
presentSuggestion(builder);
|
|
||||||
} else if (allowNotification) {
|
|
||||||
dismissSuggestion();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
rxBus.send(new EventLoopUpdateGui());
|
|
||||||
} finally {
|
|
||||||
getAapsLogger().debug(LTag.APS, "invoke end");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void disableCarbSuggestions(int durationMinutes) {
|
|
||||||
carbsSuggestionsSuspendedUntil = System.currentTimeMillis() + (durationMinutes * 60 * 1000);
|
|
||||||
dismissSuggestion();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void presentSuggestion(NotificationCompat.Builder builder) {
|
|
||||||
// Creates an explicit intent for an Activity in your app
|
|
||||||
Intent resultIntent = new Intent(context, MainActivity.class);
|
|
||||||
|
|
||||||
// The stack builder object will contain an artificial back stack for the
|
|
||||||
// started Activity.
|
|
||||||
// This ensures that navigating backward from the Activity leads out of
|
|
||||||
// your application to the Home screen.
|
|
||||||
TaskStackBuilder stackBuilder = TaskStackBuilder.create(context);
|
|
||||||
stackBuilder.addParentStack(MainActivity.class);
|
|
||||||
// Adds the Intent that starts the Activity to the top of the stack
|
|
||||||
stackBuilder.addNextIntent(resultIntent);
|
|
||||||
PendingIntent resultPendingIntent =
|
|
||||||
stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
|
|
||||||
builder.setContentIntent(resultPendingIntent);
|
|
||||||
builder.setVibrate(new long[]{1000, 1000, 1000, 1000, 1000});
|
|
||||||
NotificationManager mNotificationManager =
|
|
||||||
(NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
|
|
||||||
// mId allows you to update the notification later on.
|
|
||||||
mNotificationManager.notify(Constants.notificationID, builder.build());
|
|
||||||
rxBus.send(new EventNewOpenLoopNotification());
|
|
||||||
|
|
||||||
// Send to Wear
|
|
||||||
actionStringHandler.get().handleInitiate("changeRequest");
|
|
||||||
}
|
|
||||||
|
|
||||||
private void dismissSuggestion() {
|
|
||||||
// dismiss notifications
|
|
||||||
NotificationManager notificationManager =
|
|
||||||
(NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
|
|
||||||
notificationManager.cancel(Constants.notificationID);
|
|
||||||
actionStringHandler.get().handleInitiate("cancelChangeRequest");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void acceptChangeRequest() {
|
|
||||||
Profile profile = profileFunction.getProfile();
|
|
||||||
final LoopPlugin lp = this;
|
|
||||||
applyTBRRequest(lastRun.getConstraintsProcessed(), profile, new Callback() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
if (result.enacted) {
|
|
||||||
lastRun.setTbrSetByPump(result);
|
|
||||||
lastRun.setLastTBRRequest(lastRun.getLastAPSRun());
|
|
||||||
lastRun.setLastTBREnact(DateUtil.now());
|
|
||||||
lastRun.setLastOpenModeAccept(DateUtil.now());
|
|
||||||
nsUpload.uploadDeviceStatus(lp, iobCobCalculatorPlugin, profileFunction, activePlugin.getActivePump(), receiverStatusStore, BuildConfig.VERSION_NAME + "-" + BuildConfig.BUILDVERSION);
|
|
||||||
sp.incInt(R.string.key_ObjectivesmanualEnacts);
|
|
||||||
}
|
|
||||||
rxBus.send(new EventAcceptOpenLoopChange());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
fabricPrivacy.logCustom("AcceptTemp");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* expect absolute request and allow both absolute and percent response based on pump capabilities
|
|
||||||
* TODO: update pump drivers to support APS request in %
|
|
||||||
*/
|
|
||||||
|
|
||||||
private void applyTBRRequest(APSResult request, Profile profile, Callback callback) {
|
|
||||||
|
|
||||||
if (!request.getTempBasalRequested()) {
|
|
||||||
if (callback != null) {
|
|
||||||
callback.result(new PumpEnactResult(getInjector()).enacted(false).success(true).comment(resourceHelper.gs(R.string.nochangerequested))).run();
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
PumpInterface pump = activePlugin.getActivePump();
|
|
||||||
|
|
||||||
if (!pump.isInitialized()) {
|
|
||||||
getAapsLogger().debug(LTag.APS, "applyAPSRequest: " + resourceHelper.gs(R.string.pumpNotInitialized));
|
|
||||||
if (callback != null) {
|
|
||||||
callback.result(new PumpEnactResult(getInjector()).comment(resourceHelper.gs(R.string.pumpNotInitialized)).enacted(false).success(false)).run();
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pump.isSuspended()) {
|
|
||||||
getAapsLogger().debug(LTag.APS, "applyAPSRequest: " + resourceHelper.gs(R.string.pumpsuspended));
|
|
||||||
if (callback != null) {
|
|
||||||
callback.result(new PumpEnactResult(getInjector()).comment(resourceHelper.gs(R.string.pumpsuspended)).enacted(false).success(false)).run();
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
getAapsLogger().debug(LTag.APS, "applyAPSRequest: " + request.toString());
|
|
||||||
|
|
||||||
long now = System.currentTimeMillis();
|
|
||||||
TemporaryBasal activeTemp = treatmentsPlugin.getTempBasalFromHistory(now);
|
|
||||||
if (request.getUsePercent() && allowPercentage()) {
|
|
||||||
if (request.getPercent() == 100 && request.getDuration() == 0) {
|
|
||||||
if (activeTemp != null) {
|
|
||||||
getAapsLogger().debug(LTag.APS, "applyAPSRequest: cancelTempBasal()");
|
|
||||||
commandQueue.cancelTempBasal(false, callback);
|
|
||||||
} else {
|
|
||||||
getAapsLogger().debug(LTag.APS, "applyAPSRequest: Basal set correctly");
|
|
||||||
if (callback != null) {
|
|
||||||
callback.result(new PumpEnactResult(getInjector()).percent(request.getPercent()).duration(0)
|
|
||||||
.enacted(false).success(true).comment(resourceHelper.gs(R.string.basal_set_correctly))).run();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (activeTemp != null
|
|
||||||
&& activeTemp.getPlannedRemainingMinutes() > 5
|
|
||||||
&& request.getDuration() - activeTemp.getPlannedRemainingMinutes() < 30
|
|
||||||
&& request.getPercent() == activeTemp.percentRate) {
|
|
||||||
getAapsLogger().debug(LTag.APS, "applyAPSRequest: Temp basal set correctly");
|
|
||||||
if (callback != null) {
|
|
||||||
callback.result(new PumpEnactResult(getInjector()).percent(request.getPercent())
|
|
||||||
.enacted(false).success(true).duration(activeTemp.getPlannedRemainingMinutes())
|
|
||||||
.comment(resourceHelper.gs(R.string.let_temp_basal_run))).run();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
getAapsLogger().debug(LTag.APS, "applyAPSRequest: tempBasalPercent()");
|
|
||||||
commandQueue.tempBasalPercent(request.getPercent(), request.getDuration(), false, profile, callback);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if ((request.getRate() == 0 && request.getDuration() == 0) || Math.abs(request.getRate() - pump.getBaseBasalRate()) < pump.getPumpDescription().basalStep) {
|
|
||||||
if (activeTemp != null) {
|
|
||||||
getAapsLogger().debug(LTag.APS, "applyAPSRequest: cancelTempBasal()");
|
|
||||||
commandQueue.cancelTempBasal(false, callback);
|
|
||||||
} else {
|
|
||||||
getAapsLogger().debug(LTag.APS, "applyAPSRequest: Basal set correctly");
|
|
||||||
if (callback != null) {
|
|
||||||
callback.result(new PumpEnactResult(getInjector()).absolute(request.getRate()).duration(0)
|
|
||||||
.enacted(false).success(true).comment(resourceHelper.gs(R.string.basal_set_correctly))).run();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (activeTemp != null
|
|
||||||
&& activeTemp.getPlannedRemainingMinutes() > 5
|
|
||||||
&& request.getDuration() - activeTemp.getPlannedRemainingMinutes() < 30
|
|
||||||
&& Math.abs(request.getRate() - activeTemp.tempBasalConvertedToAbsolute(now, profile)) < pump.getPumpDescription().basalStep) {
|
|
||||||
getAapsLogger().debug(LTag.APS, "applyAPSRequest: Temp basal set correctly");
|
|
||||||
if (callback != null) {
|
|
||||||
callback.result(new PumpEnactResult(getInjector()).absolute(activeTemp.tempBasalConvertedToAbsolute(now, profile))
|
|
||||||
.enacted(false).success(true).duration(activeTemp.getPlannedRemainingMinutes())
|
|
||||||
.comment(resourceHelper.gs(R.string.let_temp_basal_run))).run();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
getAapsLogger().debug(LTag.APS, "applyAPSRequest: setTempBasalAbsolute()");
|
|
||||||
commandQueue.tempBasalAbsolute(request.getRate(), request.getDuration(), false, profile, callback);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void applySMBRequest(APSResult request, Callback callback) {
|
|
||||||
if (!request.getBolusRequested()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
PumpInterface pump = activePlugin.getActivePump();
|
|
||||||
|
|
||||||
long lastBolusTime = treatmentsPlugin.getLastBolusTime();
|
|
||||||
if (lastBolusTime != 0 && lastBolusTime + 3 * 60 * 1000 > System.currentTimeMillis()) {
|
|
||||||
getAapsLogger().debug(LTag.APS, "SMB requested but still in 3 min interval");
|
|
||||||
if (callback != null) {
|
|
||||||
callback.result(new PumpEnactResult(getInjector())
|
|
||||||
.comment(resourceHelper.gs(R.string.smb_frequency_exceeded))
|
|
||||||
.enacted(false).success(false)).run();
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!pump.isInitialized()) {
|
|
||||||
getAapsLogger().debug(LTag.APS, "applySMBRequest: " + resourceHelper.gs(R.string.pumpNotInitialized));
|
|
||||||
if (callback != null) {
|
|
||||||
callback.result(new PumpEnactResult(getInjector()).comment(resourceHelper.gs(R.string.pumpNotInitialized)).enacted(false).success(false)).run();
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pump.isSuspended()) {
|
|
||||||
getAapsLogger().debug(LTag.APS, "applySMBRequest: " + resourceHelper.gs(R.string.pumpsuspended));
|
|
||||||
if (callback != null) {
|
|
||||||
callback.result(new PumpEnactResult(getInjector()).comment(resourceHelper.gs(R.string.pumpsuspended)).enacted(false).success(false)).run();
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
getAapsLogger().debug(LTag.APS, "applySMBRequest: " + request.toString());
|
|
||||||
|
|
||||||
// deliver SMB
|
|
||||||
DetailedBolusInfo detailedBolusInfo = new DetailedBolusInfo();
|
|
||||||
detailedBolusInfo.lastKnownBolusTime = treatmentsPlugin.getLastBolusTime();
|
|
||||||
detailedBolusInfo.eventType = CareportalEvent.CORRECTIONBOLUS;
|
|
||||||
detailedBolusInfo.insulin = request.getSmb();
|
|
||||||
detailedBolusInfo.isSMB = true;
|
|
||||||
detailedBolusInfo.source = Source.USER;
|
|
||||||
detailedBolusInfo.deliverAt = request.getDeliverAt();
|
|
||||||
getAapsLogger().debug(LTag.APS, "applyAPSRequest: bolus()");
|
|
||||||
commandQueue.bolus(detailedBolusInfo, callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean allowPercentage() {
|
|
||||||
return virtualPumpPlugin.isEnabled(PluginType.PUMP);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void disconnectPump(int durationInMinutes, Profile profile) {
|
|
||||||
PumpInterface pump = activePlugin.getActivePump();
|
|
||||||
|
|
||||||
disconnectTo(System.currentTimeMillis() + durationInMinutes * 60 * 1000L);
|
|
||||||
|
|
||||||
if (pump.getPumpDescription().tempBasalStyle == PumpDescription.ABSOLUTE) {
|
|
||||||
commandQueue.tempBasalAbsolute(0, durationInMinutes, true, profile, new Callback() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
if (!result.success) {
|
|
||||||
Intent i = new Intent(context, ErrorHelperActivity.class);
|
|
||||||
i.putExtra("soundid", R.raw.boluserror);
|
|
||||||
i.putExtra("status", result.comment);
|
|
||||||
i.putExtra("title", resourceHelper.gs(R.string.tempbasaldeliveryerror));
|
|
||||||
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
|
||||||
context.startActivity(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
commandQueue.tempBasalPercent(0, durationInMinutes, true, profile, new Callback() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
if (!result.success) {
|
|
||||||
Intent i = new Intent(context, ErrorHelperActivity.class);
|
|
||||||
i.putExtra("soundid", R.raw.boluserror);
|
|
||||||
i.putExtra("status", result.comment);
|
|
||||||
i.putExtra("title", resourceHelper.gs(R.string.tempbasaldeliveryerror));
|
|
||||||
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
|
||||||
context.startActivity(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pump.getPumpDescription().isExtendedBolusCapable && treatmentsPlugin.isInHistoryExtendedBoluslInProgress()) {
|
|
||||||
commandQueue.cancelExtended(new Callback() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
if (!result.success) {
|
|
||||||
Intent i = new Intent(context, ErrorHelperActivity.class);
|
|
||||||
i.putExtra("soundid", R.raw.boluserror);
|
|
||||||
i.putExtra("status", result.comment);
|
|
||||||
i.putExtra("title", resourceHelper.gs(R.string.extendedbolusdeliveryerror));
|
|
||||||
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
|
||||||
context.startActivity(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
createOfflineEvent(durationInMinutes);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void suspendLoop(int durationInMinutes) {
|
|
||||||
suspendTo(System.currentTimeMillis() + durationInMinutes * 60 * 1000);
|
|
||||||
commandQueue.cancelTempBasal(true, new Callback() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
if (!result.success) {
|
|
||||||
Intent i = new Intent(context, ErrorHelperActivity.class);
|
|
||||||
i.putExtra("soundid", R.raw.boluserror);
|
|
||||||
i.putExtra("status", result.comment);
|
|
||||||
i.putExtra("title", resourceHelper.gs(R.string.tempbasaldeliveryerror));
|
|
||||||
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
|
||||||
context.startActivity(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
createOfflineEvent(durationInMinutes);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void createOfflineEvent(int durationInMinutes) {
|
|
||||||
JSONObject data = new JSONObject();
|
|
||||||
try {
|
|
||||||
data.put("eventType", CareportalEvent.OPENAPSOFFLINE);
|
|
||||||
data.put("duration", durationInMinutes);
|
|
||||||
} catch (JSONException e) {
|
|
||||||
getAapsLogger().error("Unhandled exception", e);
|
|
||||||
}
|
|
||||||
CareportalEvent event = new CareportalEvent(getInjector());
|
|
||||||
event.date = DateUtil.now();
|
|
||||||
event.source = Source.USER;
|
|
||||||
event.eventType = CareportalEvent.OPENAPSOFFLINE;
|
|
||||||
event.json = data.toString();
|
|
||||||
MainApp.getDbHelper().createOrUpdate(event);
|
|
||||||
nsUpload.uploadOpenAPSOffline(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -0,0 +1,674 @@
|
||||||
|
package info.nightscout.androidaps.plugins.aps.loop
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import android.app.NotificationChannel
|
||||||
|
import android.app.NotificationManager
|
||||||
|
import android.app.PendingIntent
|
||||||
|
import android.app.TaskStackBuilder
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.os.SystemClock
|
||||||
|
import androidx.core.app.NotificationCompat
|
||||||
|
import dagger.android.HasAndroidInjector
|
||||||
|
import info.nightscout.androidaps.*
|
||||||
|
import info.nightscout.androidaps.activities.ErrorHelperActivity
|
||||||
|
import info.nightscout.androidaps.data.DetailedBolusInfo
|
||||||
|
import info.nightscout.androidaps.data.Profile
|
||||||
|
import info.nightscout.androidaps.data.PumpEnactResult
|
||||||
|
import info.nightscout.androidaps.db.CareportalEvent
|
||||||
|
import info.nightscout.androidaps.db.Source
|
||||||
|
import info.nightscout.androidaps.events.EventAcceptOpenLoopChange
|
||||||
|
import info.nightscout.androidaps.events.EventNewBG
|
||||||
|
import info.nightscout.androidaps.events.EventTempTargetChange
|
||||||
|
import info.nightscout.androidaps.interfaces.*
|
||||||
|
import info.nightscout.androidaps.interfaces.LoopInterface.LastRun
|
||||||
|
import info.nightscout.androidaps.logging.AAPSLogger
|
||||||
|
import info.nightscout.androidaps.logging.LTag
|
||||||
|
import info.nightscout.androidaps.plugins.aps.loop.events.EventLoopSetLastRunGui
|
||||||
|
import info.nightscout.androidaps.plugins.aps.loop.events.EventLoopUpdateGui
|
||||||
|
import info.nightscout.androidaps.plugins.aps.loop.events.EventNewOpenLoopNotification
|
||||||
|
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
||||||
|
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
|
||||||
|
import info.nightscout.androidaps.plugins.general.nsclient.NSUpload
|
||||||
|
import info.nightscout.androidaps.plugins.general.overview.events.EventDismissNotification
|
||||||
|
import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification
|
||||||
|
import info.nightscout.androidaps.plugins.general.overview.notifications.Notification
|
||||||
|
import info.nightscout.androidaps.plugins.general.wear.events.EventWearDoAction
|
||||||
|
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin
|
||||||
|
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventAutosensCalculationFinished
|
||||||
|
import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpPlugin
|
||||||
|
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin
|
||||||
|
import info.nightscout.androidaps.queue.Callback
|
||||||
|
import info.nightscout.androidaps.queue.commands.Command
|
||||||
|
import info.nightscout.androidaps.receivers.ReceiverStatusStore
|
||||||
|
import info.nightscout.androidaps.utils.DateUtil
|
||||||
|
import info.nightscout.androidaps.utils.FabricPrivacy
|
||||||
|
import info.nightscout.androidaps.utils.HardLimits
|
||||||
|
import info.nightscout.androidaps.utils.T
|
||||||
|
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||||
|
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
||||||
|
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
||||||
|
import io.reactivex.disposables.CompositeDisposable
|
||||||
|
import org.json.JSONException
|
||||||
|
import org.json.JSONObject
|
||||||
|
import javax.inject.Inject
|
||||||
|
import javax.inject.Singleton
|
||||||
|
import kotlin.math.abs
|
||||||
|
|
||||||
|
@Singleton
|
||||||
|
open class LoopPlugin @Inject constructor(
|
||||||
|
injector: HasAndroidInjector,
|
||||||
|
aapsLogger: AAPSLogger?,
|
||||||
|
private val aapsSchedulers: AapsSchedulers,
|
||||||
|
private val rxBus: RxBusWrapper,
|
||||||
|
private val sp: SP,
|
||||||
|
config: Config,
|
||||||
|
private val constraintChecker: ConstraintChecker,
|
||||||
|
resourceHelper: ResourceHelper,
|
||||||
|
private val profileFunction: ProfileFunction,
|
||||||
|
private val context: Context,
|
||||||
|
private val commandQueue: CommandQueueProvider,
|
||||||
|
private val activePlugin: ActivePluginProvider,
|
||||||
|
private val treatmentsPlugin: TreatmentsPlugin,
|
||||||
|
private val virtualPumpPlugin: VirtualPumpPlugin,
|
||||||
|
private val iobCobCalculatorPlugin: IobCobCalculatorPlugin,
|
||||||
|
private val receiverStatusStore: ReceiverStatusStore,
|
||||||
|
private val fabricPrivacy: FabricPrivacy,
|
||||||
|
private val nsUpload: NSUpload,
|
||||||
|
private val hardLimits: HardLimits
|
||||||
|
) : PluginBase(PluginDescription()
|
||||||
|
.mainType(PluginType.LOOP)
|
||||||
|
.fragmentClass(LoopFragment::class.java.name)
|
||||||
|
.pluginIcon(R.drawable.ic_loop_closed_white)
|
||||||
|
.pluginName(R.string.loop)
|
||||||
|
.shortName(R.string.loop_shortname)
|
||||||
|
.preferencesId(R.xml.pref_loop)
|
||||||
|
.enableByDefault(config.APS)
|
||||||
|
.description(R.string.description_loop),
|
||||||
|
aapsLogger!!, resourceHelper, injector
|
||||||
|
), LoopInterface {
|
||||||
|
|
||||||
|
private val disposable = CompositeDisposable()
|
||||||
|
private var lastBgTriggeredRun: Long = 0
|
||||||
|
private var carbsSuggestionsSuspendedUntil: Long = 0
|
||||||
|
private var prevCarbsreq = 0
|
||||||
|
override var lastRun: LastRun? = null
|
||||||
|
override fun onStart() {
|
||||||
|
createNotificationChannel()
|
||||||
|
super.onStart()
|
||||||
|
disposable.add(rxBus
|
||||||
|
.toObservable(EventTempTargetChange::class.java)
|
||||||
|
.observeOn(aapsSchedulers.io)
|
||||||
|
.subscribe({ invoke("EventTempTargetChange", true) }, fabricPrivacy::logException)
|
||||||
|
)
|
||||||
|
/*
|
||||||
|
This method is triggered once autosens calculation has completed, so the LoopPlugin
|
||||||
|
has current data to work with. However, autosens calculation can be triggered by multiple
|
||||||
|
sources and currently only a new BG should trigger a loop run. Hence we return early if
|
||||||
|
the event causing the calculation is not EventNewBg.
|
||||||
|
<p>
|
||||||
|
*/
|
||||||
|
disposable.add(rxBus
|
||||||
|
.toObservable(EventAutosensCalculationFinished::class.java)
|
||||||
|
.observeOn(aapsSchedulers.io)
|
||||||
|
.subscribe({ event: EventAutosensCalculationFinished ->
|
||||||
|
// Autosens calculation not triggered by a new BG
|
||||||
|
if (event.cause !is EventNewBG) return@subscribe
|
||||||
|
val glucoseValue = iobCobCalculatorPlugin.actualBg() ?: return@subscribe
|
||||||
|
// BG outdated
|
||||||
|
// already looped with that value
|
||||||
|
if (glucoseValue.timestamp <= lastBgTriggeredRun) return@subscribe
|
||||||
|
lastBgTriggeredRun = glucoseValue.timestamp
|
||||||
|
invoke("AutosenseCalculation for $glucoseValue", true)
|
||||||
|
}, fabricPrivacy::logException)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createNotificationChannel() {
|
||||||
|
val mNotificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
||||||
|
@SuppressLint("WrongConstant") val channel = NotificationChannel(CHANNEL_ID,
|
||||||
|
CHANNEL_ID,
|
||||||
|
NotificationManager.IMPORTANCE_HIGH)
|
||||||
|
mNotificationManager.createNotificationChannel(channel)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onStop() {
|
||||||
|
disposable.clear()
|
||||||
|
super.onStop()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun specialEnableCondition(): Boolean {
|
||||||
|
return try {
|
||||||
|
val pump = activePlugin.activePump
|
||||||
|
pump.pumpDescription.isTempBasalCapable
|
||||||
|
} catch (ignored: Exception) {
|
||||||
|
// may fail during initialization
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun suspendTo(endTime: Long) {
|
||||||
|
sp.putLong("loopSuspendedTill", endTime)
|
||||||
|
sp.putBoolean("isSuperBolus", false)
|
||||||
|
sp.putBoolean("isDisconnected", false)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun superBolusTo(endTime: Long) {
|
||||||
|
sp.putLong("loopSuspendedTill", endTime)
|
||||||
|
sp.putBoolean("isSuperBolus", true)
|
||||||
|
sp.putBoolean("isDisconnected", false)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun disconnectTo(endTime: Long) {
|
||||||
|
sp.putLong("loopSuspendedTill", endTime)
|
||||||
|
sp.putBoolean("isSuperBolus", false)
|
||||||
|
sp.putBoolean("isDisconnected", true)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun minutesToEndOfSuspend(): Int {
|
||||||
|
val loopSuspendedTill = sp.getLong("loopSuspendedTill", 0L)
|
||||||
|
if (loopSuspendedTill == 0L) return 0
|
||||||
|
val now = System.currentTimeMillis()
|
||||||
|
val millisDiff = loopSuspendedTill - now
|
||||||
|
if (loopSuspendedTill <= now) { // time exceeded
|
||||||
|
suspendTo(0L)
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return (millisDiff / 60.0 / 1000.0).toInt()
|
||||||
|
}
|
||||||
|
|
||||||
|
// time exceeded
|
||||||
|
val isSuspended: Boolean
|
||||||
|
get() {
|
||||||
|
val loopSuspendedTill = sp.getLong("loopSuspendedTill", 0L)
|
||||||
|
if (loopSuspendedTill == 0L) return false
|
||||||
|
val now = System.currentTimeMillis()
|
||||||
|
if (loopSuspendedTill <= now) { // time exceeded
|
||||||
|
suspendTo(0L)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
val isLGS: Boolean
|
||||||
|
get() {
|
||||||
|
val closedLoopEnabled = constraintChecker.isClosedLoopAllowed()
|
||||||
|
val maxIobAllowed = constraintChecker.getMaxIOBAllowed().value()
|
||||||
|
val apsMode = sp.getString(R.string.key_aps_mode, "open")
|
||||||
|
val pump = activePlugin.activePump
|
||||||
|
var isLGS = false
|
||||||
|
if (!isSuspended && !pump.isSuspended) if (closedLoopEnabled.value()) if (maxIobAllowed == hardLimits.MAXIOB_LGS || apsMode == "lgs") isLGS = true
|
||||||
|
return isLGS
|
||||||
|
}
|
||||||
|
|
||||||
|
// time exceeded
|
||||||
|
val isSuperBolus: Boolean
|
||||||
|
get() {
|
||||||
|
val loopSuspendedTill = sp.getLong("loopSuspendedTill", 0L)
|
||||||
|
if (loopSuspendedTill == 0L) return false
|
||||||
|
val now = System.currentTimeMillis()
|
||||||
|
if (loopSuspendedTill <= now) { // time exceeded
|
||||||
|
suspendTo(0L)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return sp.getBoolean("isSuperBolus", false)
|
||||||
|
}
|
||||||
|
|
||||||
|
// time exceeded
|
||||||
|
val isDisconnected: Boolean
|
||||||
|
get() {
|
||||||
|
val loopSuspendedTill = sp.getLong("loopSuspendedTill", 0L)
|
||||||
|
if (loopSuspendedTill == 0L) return false
|
||||||
|
val now = System.currentTimeMillis()
|
||||||
|
if (loopSuspendedTill <= now) { // time exceeded
|
||||||
|
suspendTo(0L)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return sp.getBoolean("isDisconnected", false)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("SameParameterValue")
|
||||||
|
private fun treatmentTimeThreshold(durationMinutes: Int): Boolean {
|
||||||
|
val threshold = System.currentTimeMillis() + durationMinutes * 60 * 1000
|
||||||
|
var bool = false
|
||||||
|
if (treatmentsPlugin.lastBolusTime > threshold || treatmentsPlugin.lastCarbTime > threshold) bool = true
|
||||||
|
return bool
|
||||||
|
}
|
||||||
|
|
||||||
|
@Synchronized operator fun invoke(initiator: String, allowNotification: Boolean) {
|
||||||
|
invoke(initiator, allowNotification, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Synchronized
|
||||||
|
operator fun invoke(initiator: String, allowNotification: Boolean, tempBasalFallback: Boolean) {
|
||||||
|
try {
|
||||||
|
aapsLogger.debug(LTag.APS, "invoke from $initiator")
|
||||||
|
val loopEnabled = constraintChecker.isLoopInvocationAllowed()
|
||||||
|
if (!loopEnabled.value()) {
|
||||||
|
val message = """
|
||||||
|
${resourceHelper.gs(R.string.loopdisabled)}
|
||||||
|
${loopEnabled.getReasons(aapsLogger)}
|
||||||
|
""".trimIndent()
|
||||||
|
aapsLogger.debug(LTag.APS, message)
|
||||||
|
rxBus.send(EventLoopSetLastRunGui(message))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
val pump = activePlugin.activePump
|
||||||
|
var apsResult: APSResult? = null
|
||||||
|
if (!isEnabled(PluginType.LOOP)) return
|
||||||
|
val profile = profileFunction.getProfile()
|
||||||
|
if (profile == null || !profileFunction.isProfileValid("Loop")) {
|
||||||
|
aapsLogger.debug(LTag.APS, resourceHelper.gs(R.string.noprofileselected))
|
||||||
|
rxBus.send(EventLoopSetLastRunGui(resourceHelper.gs(R.string.noprofileselected)))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if pump info is loaded
|
||||||
|
if (pump.baseBasalRate < 0.01) return
|
||||||
|
val usedAPS = activePlugin.activeAPS
|
||||||
|
if ((usedAPS as PluginBase).isEnabled(PluginType.APS)) {
|
||||||
|
usedAPS.invoke(initiator, tempBasalFallback)
|
||||||
|
apsResult = usedAPS.lastAPSResult
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if we have any result
|
||||||
|
if (apsResult == null) {
|
||||||
|
rxBus.send(EventLoopSetLastRunGui(resourceHelper.gs(R.string.noapsselected)))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prepare for pumps using % basals
|
||||||
|
if (pump.pumpDescription.tempBasalStyle == PumpDescription.PERCENT && allowPercentage()) {
|
||||||
|
apsResult.usePercent = true
|
||||||
|
}
|
||||||
|
apsResult.percent = (apsResult.rate / profile.basal * 100).toInt()
|
||||||
|
|
||||||
|
// check rate for constraints
|
||||||
|
val resultAfterConstraints = apsResult.newAndClone(injector)
|
||||||
|
resultAfterConstraints.rateConstraint = Constraint(resultAfterConstraints.rate)
|
||||||
|
resultAfterConstraints.rate = constraintChecker.applyBasalConstraints(resultAfterConstraints.rateConstraint!!, profile).value()
|
||||||
|
resultAfterConstraints.percentConstraint = Constraint(resultAfterConstraints.percent)
|
||||||
|
resultAfterConstraints.percent = constraintChecker.applyBasalPercentConstraints(resultAfterConstraints.percentConstraint!!, profile).value()
|
||||||
|
resultAfterConstraints.smbConstraint = Constraint(resultAfterConstraints.smb)
|
||||||
|
resultAfterConstraints.smb = constraintChecker.applyBolusConstraints(resultAfterConstraints.smbConstraint!!).value()
|
||||||
|
|
||||||
|
// safety check for multiple SMBs
|
||||||
|
val lastBolusTime = treatmentsPlugin.lastBolusTime
|
||||||
|
if (lastBolusTime != 0L && lastBolusTime + T.mins(3).msecs() > System.currentTimeMillis()) {
|
||||||
|
aapsLogger.debug(LTag.APS, "SMB requested but still in 3 min interval")
|
||||||
|
resultAfterConstraints.smb = 0.0
|
||||||
|
}
|
||||||
|
if (lastRun != null && lastRun!!.constraintsProcessed != null) {
|
||||||
|
prevCarbsreq = lastRun!!.constraintsProcessed!!.carbsReq
|
||||||
|
}
|
||||||
|
if (lastRun == null) lastRun = LastRun()
|
||||||
|
lastRun!!.request = apsResult
|
||||||
|
lastRun!!.constraintsProcessed = resultAfterConstraints
|
||||||
|
lastRun!!.lastAPSRun = DateUtil.now()
|
||||||
|
lastRun!!.source = (usedAPS as PluginBase).name
|
||||||
|
lastRun!!.tbrSetByPump = null
|
||||||
|
lastRun!!.smbSetByPump = null
|
||||||
|
lastRun!!.lastTBREnact = 0
|
||||||
|
lastRun!!.lastTBRRequest = 0
|
||||||
|
lastRun!!.lastSMBEnact = 0
|
||||||
|
lastRun!!.lastSMBRequest = 0
|
||||||
|
nsUpload.uploadDeviceStatus(this, iobCobCalculatorPlugin, profileFunction, activePlugin.activePump, receiverStatusStore, BuildConfig.VERSION_NAME + "-" + BuildConfig.BUILDVERSION)
|
||||||
|
if (isSuspended) {
|
||||||
|
aapsLogger.debug(LTag.APS, resourceHelper.gs(R.string.loopsuspended))
|
||||||
|
rxBus.send(EventLoopSetLastRunGui(resourceHelper.gs(R.string.loopsuspended)))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (pump.isSuspended) {
|
||||||
|
aapsLogger.debug(LTag.APS, resourceHelper.gs(R.string.pumpsuspended))
|
||||||
|
rxBus.send(EventLoopSetLastRunGui(resourceHelper.gs(R.string.pumpsuspended)))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
val closedLoopEnabled = constraintChecker.isClosedLoopAllowed()
|
||||||
|
if (closedLoopEnabled.value()) {
|
||||||
|
if (allowNotification) {
|
||||||
|
if (resultAfterConstraints.isCarbsRequired
|
||||||
|
&& resultAfterConstraints.carbsReq >= sp.getInt(R.string.key_smb_enable_carbs_suggestions_threshold, 0) && carbsSuggestionsSuspendedUntil < System.currentTimeMillis() && !treatmentTimeThreshold(-15)) {
|
||||||
|
if (sp.getBoolean(R.string.key_enable_carbs_required_alert_local, true) && !sp.getBoolean(R.string.key_raise_notifications_as_android_notifications, true)) {
|
||||||
|
val carbReqLocal = Notification(Notification.CARBS_REQUIRED, resultAfterConstraints.carbsRequiredText, Notification.NORMAL)
|
||||||
|
rxBus.send(EventNewNotification(carbReqLocal))
|
||||||
|
}
|
||||||
|
if (sp.getBoolean(R.string.key_ns_create_announcements_from_carbs_req, false)) {
|
||||||
|
nsUpload.uploadError(resultAfterConstraints.carbsRequiredText)
|
||||||
|
}
|
||||||
|
if (sp.getBoolean(R.string.key_enable_carbs_required_alert_local, true) && sp.getBoolean(R.string.key_raise_notifications_as_android_notifications, true)) {
|
||||||
|
val intentAction5m = Intent(context, CarbSuggestionReceiver::class.java)
|
||||||
|
intentAction5m.putExtra("ignoreDuration", 5)
|
||||||
|
val pendingIntent5m = PendingIntent.getBroadcast(context, 1, intentAction5m, PendingIntent.FLAG_UPDATE_CURRENT)
|
||||||
|
val actionIgnore5m = NotificationCompat.Action(R.drawable.ic_notif_aaps, resourceHelper.gs(R.string.ignore5m, "Ignore 5m"), pendingIntent5m)
|
||||||
|
val intentAction15m = Intent(context, CarbSuggestionReceiver::class.java)
|
||||||
|
intentAction15m.putExtra("ignoreDuration", 15)
|
||||||
|
val pendingIntent15m = PendingIntent.getBroadcast(context, 1, intentAction15m, PendingIntent.FLAG_UPDATE_CURRENT)
|
||||||
|
val actionIgnore15m = NotificationCompat.Action(R.drawable.ic_notif_aaps, resourceHelper.gs(R.string.ignore15m, "Ignore 15m"), pendingIntent15m)
|
||||||
|
val intentAction30m = Intent(context, CarbSuggestionReceiver::class.java)
|
||||||
|
intentAction30m.putExtra("ignoreDuration", 30)
|
||||||
|
val pendingIntent30m = PendingIntent.getBroadcast(context, 1, intentAction30m, PendingIntent.FLAG_UPDATE_CURRENT)
|
||||||
|
val actionIgnore30m = NotificationCompat.Action(R.drawable.ic_notif_aaps, resourceHelper.gs(R.string.ignore30m, "Ignore 30m"), pendingIntent30m)
|
||||||
|
val builder = NotificationCompat.Builder(context, CHANNEL_ID)
|
||||||
|
builder.setSmallIcon(R.drawable.notif_icon)
|
||||||
|
.setContentTitle(resourceHelper.gs(R.string.carbssuggestion))
|
||||||
|
.setContentText(resultAfterConstraints.carbsRequiredText)
|
||||||
|
.setAutoCancel(true)
|
||||||
|
.setPriority(Notification.IMPORTANCE_HIGH)
|
||||||
|
.setCategory(Notification.CATEGORY_ALARM)
|
||||||
|
.addAction(actionIgnore5m)
|
||||||
|
.addAction(actionIgnore15m)
|
||||||
|
.addAction(actionIgnore30m)
|
||||||
|
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
|
||||||
|
.setVibrate(longArrayOf(1000, 1000, 1000, 1000, 1000))
|
||||||
|
val mNotificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
||||||
|
|
||||||
|
// mId allows you to update the notification later on.
|
||||||
|
mNotificationManager.notify(Constants.notificationID, builder.build())
|
||||||
|
rxBus.send(EventNewOpenLoopNotification())
|
||||||
|
|
||||||
|
//only send to wear if Native notifications are turned off
|
||||||
|
if (!sp.getBoolean(R.string.key_raise_notifications_as_android_notifications, true)) {
|
||||||
|
// Send to Wear
|
||||||
|
rxBus.send(EventWearDoAction("changeRequest"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
//If carbs were required previously, but are no longer needed, dismiss notifications
|
||||||
|
if (prevCarbsreq > 0) {
|
||||||
|
dismissSuggestion()
|
||||||
|
rxBus.send(EventDismissNotification(Notification.CARBS_REQUIRED))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (resultAfterConstraints.isChangeRequested
|
||||||
|
&& !commandQueue.bolusInQueue()
|
||||||
|
&& !commandQueue.isRunning(Command.CommandType.BOLUS)) {
|
||||||
|
val waiting = PumpEnactResult(injector)
|
||||||
|
waiting.queued = true
|
||||||
|
if (resultAfterConstraints.tempBasalRequested) lastRun!!.tbrSetByPump = waiting
|
||||||
|
if (resultAfterConstraints.bolusRequested) lastRun!!.smbSetByPump = waiting
|
||||||
|
rxBus.send(EventLoopUpdateGui())
|
||||||
|
fabricPrivacy.logCustom("APSRequest")
|
||||||
|
applyTBRRequest(resultAfterConstraints, profile, object : Callback() {
|
||||||
|
override fun run() {
|
||||||
|
if (result.enacted || result.success) {
|
||||||
|
lastRun!!.tbrSetByPump = result
|
||||||
|
lastRun!!.lastTBRRequest = lastRun!!.lastAPSRun
|
||||||
|
lastRun!!.lastTBREnact = DateUtil.now()
|
||||||
|
rxBus.send(EventLoopUpdateGui())
|
||||||
|
applySMBRequest(resultAfterConstraints, object : Callback() {
|
||||||
|
override fun run() {
|
||||||
|
// Callback is only called if a bolus was actually requested
|
||||||
|
if (result.enacted || result.success) {
|
||||||
|
lastRun!!.smbSetByPump = result
|
||||||
|
lastRun!!.lastSMBRequest = lastRun!!.lastAPSRun
|
||||||
|
lastRun!!.lastSMBEnact = DateUtil.now()
|
||||||
|
} else {
|
||||||
|
Thread {
|
||||||
|
SystemClock.sleep(1000)
|
||||||
|
invoke("tempBasalFallback", allowNotification, true)
|
||||||
|
}.start()
|
||||||
|
}
|
||||||
|
rxBus.send(EventLoopUpdateGui())
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
lastRun!!.tbrSetByPump = result
|
||||||
|
lastRun!!.lastTBRRequest = lastRun!!.lastAPSRun
|
||||||
|
}
|
||||||
|
rxBus.send(EventLoopUpdateGui())
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
lastRun!!.tbrSetByPump = null
|
||||||
|
lastRun!!.smbSetByPump = null
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (resultAfterConstraints.isChangeRequested && allowNotification) {
|
||||||
|
val builder = NotificationCompat.Builder(context, CHANNEL_ID)
|
||||||
|
builder.setSmallIcon(R.drawable.notif_icon)
|
||||||
|
.setContentTitle(resourceHelper.gs(R.string.openloop_newsuggestion))
|
||||||
|
.setContentText(resultAfterConstraints.toString())
|
||||||
|
.setAutoCancel(true)
|
||||||
|
.setPriority(Notification.IMPORTANCE_HIGH)
|
||||||
|
.setCategory(Notification.CATEGORY_ALARM)
|
||||||
|
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
|
||||||
|
if (sp.getBoolean(R.string.key_wear_control, false)) {
|
||||||
|
builder.setLocalOnly(true)
|
||||||
|
}
|
||||||
|
presentSuggestion(builder)
|
||||||
|
} else if (allowNotification) {
|
||||||
|
dismissSuggestion()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rxBus.send(EventLoopUpdateGui())
|
||||||
|
} finally {
|
||||||
|
aapsLogger.debug(LTag.APS, "invoke end")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun disableCarbSuggestions(durationMinutes: Int) {
|
||||||
|
carbsSuggestionsSuspendedUntil = System.currentTimeMillis() + durationMinutes * 60 * 1000
|
||||||
|
dismissSuggestion()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun presentSuggestion(builder: NotificationCompat.Builder) {
|
||||||
|
// Creates an explicit intent for an Activity in your app
|
||||||
|
val resultIntent = Intent(context, MainActivity::class.java)
|
||||||
|
|
||||||
|
// The stack builder object will contain an artificial back stack for the
|
||||||
|
// started Activity.
|
||||||
|
// This ensures that navigating backward from the Activity leads out of
|
||||||
|
// your application to the Home screen.
|
||||||
|
val stackBuilder = TaskStackBuilder.create(context)
|
||||||
|
stackBuilder.addParentStack(MainActivity::class.java)
|
||||||
|
// Adds the Intent that starts the Activity to the top of the stack
|
||||||
|
stackBuilder.addNextIntent(resultIntent)
|
||||||
|
val resultPendingIntent = stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT)
|
||||||
|
builder.setContentIntent(resultPendingIntent)
|
||||||
|
builder.setVibrate(longArrayOf(1000, 1000, 1000, 1000, 1000))
|
||||||
|
val mNotificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
||||||
|
// mId allows you to update the notification later on.
|
||||||
|
mNotificationManager.notify(Constants.notificationID, builder.build())
|
||||||
|
rxBus.send(EventNewOpenLoopNotification())
|
||||||
|
|
||||||
|
// Send to Wear
|
||||||
|
rxBus.send(EventWearDoAction("changeRequest"))
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun dismissSuggestion() {
|
||||||
|
// dismiss notifications
|
||||||
|
val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
||||||
|
notificationManager.cancel(Constants.notificationID)
|
||||||
|
rxBus.send(EventWearDoAction("cancelChangeRequest"))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun acceptChangeRequest() {
|
||||||
|
val profile = profileFunction.getProfile()
|
||||||
|
val lp = this
|
||||||
|
applyTBRRequest(lastRun!!.constraintsProcessed, profile, object : Callback() {
|
||||||
|
override fun run() {
|
||||||
|
if (result.enacted) {
|
||||||
|
lastRun!!.tbrSetByPump = result
|
||||||
|
lastRun!!.lastTBRRequest = lastRun!!.lastAPSRun
|
||||||
|
lastRun!!.lastTBREnact = DateUtil.now()
|
||||||
|
lastRun!!.lastOpenModeAccept = DateUtil.now()
|
||||||
|
nsUpload.uploadDeviceStatus(lp, iobCobCalculatorPlugin, profileFunction, activePlugin.activePump, receiverStatusStore, BuildConfig.VERSION_NAME + "-" + BuildConfig.BUILDVERSION)
|
||||||
|
sp.incInt(R.string.key_ObjectivesmanualEnacts)
|
||||||
|
}
|
||||||
|
rxBus.send(EventAcceptOpenLoopChange())
|
||||||
|
}
|
||||||
|
})
|
||||||
|
fabricPrivacy.logCustom("AcceptTemp")
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* expect absolute request and allow both absolute and percent response based on pump capabilities
|
||||||
|
* TODO: update pump drivers to support APS request in %
|
||||||
|
*/
|
||||||
|
private fun applyTBRRequest(request: APSResult?, profile: Profile?, callback: Callback?) {
|
||||||
|
if (!request!!.tempBasalRequested) {
|
||||||
|
callback?.result(PumpEnactResult(injector).enacted(false).success(true).comment(resourceHelper.gs(R.string.nochangerequested)))?.run()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
val pump = activePlugin.activePump
|
||||||
|
if (!pump.isInitialized) {
|
||||||
|
aapsLogger.debug(LTag.APS, "applyAPSRequest: " + resourceHelper.gs(R.string.pumpNotInitialized))
|
||||||
|
callback?.result(PumpEnactResult(injector).comment(resourceHelper.gs(R.string.pumpNotInitialized)).enacted(false).success(false))?.run()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (pump.isSuspended) {
|
||||||
|
aapsLogger.debug(LTag.APS, "applyAPSRequest: " + resourceHelper.gs(R.string.pumpsuspended))
|
||||||
|
callback?.result(PumpEnactResult(injector).comment(resourceHelper.gs(R.string.pumpsuspended)).enacted(false).success(false))?.run()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
aapsLogger.debug(LTag.APS, "applyAPSRequest: $request")
|
||||||
|
val now = System.currentTimeMillis()
|
||||||
|
val activeTemp = treatmentsPlugin.getTempBasalFromHistory(now)
|
||||||
|
if (request.usePercent && allowPercentage()) {
|
||||||
|
if (request.percent == 100 && request.duration == 0) {
|
||||||
|
if (activeTemp != null) {
|
||||||
|
aapsLogger.debug(LTag.APS, "applyAPSRequest: cancelTempBasal()")
|
||||||
|
commandQueue.cancelTempBasal(false, callback)
|
||||||
|
} else {
|
||||||
|
aapsLogger.debug(LTag.APS, "applyAPSRequest: Basal set correctly")
|
||||||
|
callback?.result(PumpEnactResult(injector).percent(request.percent).duration(0)
|
||||||
|
.enacted(false).success(true).comment(resourceHelper.gs(R.string.basal_set_correctly)))?.run()
|
||||||
|
}
|
||||||
|
} else if (activeTemp != null && activeTemp.plannedRemainingMinutes > 5 && request.duration - activeTemp.plannedRemainingMinutes < 30 && request.percent == activeTemp.percentRate) {
|
||||||
|
aapsLogger.debug(LTag.APS, "applyAPSRequest: Temp basal set correctly")
|
||||||
|
callback?.result(PumpEnactResult(injector).percent(request.percent)
|
||||||
|
.enacted(false).success(true).duration(activeTemp.plannedRemainingMinutes)
|
||||||
|
.comment(resourceHelper.gs(R.string.let_temp_basal_run)))?.run()
|
||||||
|
} else {
|
||||||
|
aapsLogger.debug(LTag.APS, "applyAPSRequest: tempBasalPercent()")
|
||||||
|
commandQueue.tempBasalPercent(request.percent, request.duration, false, profile!!, callback)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (request.rate == 0.0 && request.duration == 0 || abs(request.rate - pump.baseBasalRate) < pump.pumpDescription.basalStep) {
|
||||||
|
if (activeTemp != null) {
|
||||||
|
aapsLogger.debug(LTag.APS, "applyAPSRequest: cancelTempBasal()")
|
||||||
|
commandQueue.cancelTempBasal(false, callback)
|
||||||
|
} else {
|
||||||
|
aapsLogger.debug(LTag.APS, "applyAPSRequest: Basal set correctly")
|
||||||
|
callback?.result(PumpEnactResult(injector).absolute(request.rate).duration(0)
|
||||||
|
.enacted(false).success(true).comment(resourceHelper.gs(R.string.basal_set_correctly)))?.run()
|
||||||
|
}
|
||||||
|
} else if (activeTemp != null && activeTemp.plannedRemainingMinutes > 5 && request.duration - activeTemp.plannedRemainingMinutes < 30 && abs(request.rate - activeTemp.tempBasalConvertedToAbsolute(now, profile)) < pump.pumpDescription.basalStep) {
|
||||||
|
aapsLogger.debug(LTag.APS, "applyAPSRequest: Temp basal set correctly")
|
||||||
|
callback?.result(PumpEnactResult(injector).absolute(activeTemp.tempBasalConvertedToAbsolute(now, profile))
|
||||||
|
.enacted(false).success(true).duration(activeTemp.plannedRemainingMinutes)
|
||||||
|
.comment(resourceHelper.gs(R.string.let_temp_basal_run)))?.run()
|
||||||
|
} else {
|
||||||
|
aapsLogger.debug(LTag.APS, "applyAPSRequest: setTempBasalAbsolute()")
|
||||||
|
commandQueue.tempBasalAbsolute(request.rate, request.duration, false, profile!!, callback)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun applySMBRequest(request: APSResult, callback: Callback?) {
|
||||||
|
if (!request.bolusRequested) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
val pump = activePlugin.activePump
|
||||||
|
val lastBolusTime = treatmentsPlugin.lastBolusTime
|
||||||
|
if (lastBolusTime != 0L && lastBolusTime + 3 * 60 * 1000 > System.currentTimeMillis()) {
|
||||||
|
aapsLogger.debug(LTag.APS, "SMB requested but still in 3 min interval")
|
||||||
|
callback?.result(PumpEnactResult(injector)
|
||||||
|
.comment(resourceHelper.gs(R.string.smb_frequency_exceeded))
|
||||||
|
.enacted(false).success(false))?.run()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (!pump.isInitialized) {
|
||||||
|
aapsLogger.debug(LTag.APS, "applySMBRequest: " + resourceHelper.gs(R.string.pumpNotInitialized))
|
||||||
|
callback?.result(PumpEnactResult(injector).comment(resourceHelper.gs(R.string.pumpNotInitialized)).enacted(false).success(false))?.run()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (pump.isSuspended) {
|
||||||
|
aapsLogger.debug(LTag.APS, "applySMBRequest: " + resourceHelper.gs(R.string.pumpsuspended))
|
||||||
|
callback?.result(PumpEnactResult(injector).comment(resourceHelper.gs(R.string.pumpsuspended)).enacted(false).success(false))?.run()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
aapsLogger.debug(LTag.APS, "applySMBRequest: $request")
|
||||||
|
|
||||||
|
// deliver SMB
|
||||||
|
val detailedBolusInfo = DetailedBolusInfo()
|
||||||
|
detailedBolusInfo.lastKnownBolusTime = treatmentsPlugin.lastBolusTime
|
||||||
|
detailedBolusInfo.eventType = CareportalEvent.CORRECTIONBOLUS
|
||||||
|
detailedBolusInfo.insulin = request.smb
|
||||||
|
detailedBolusInfo.isSMB = true
|
||||||
|
detailedBolusInfo.source = Source.USER
|
||||||
|
detailedBolusInfo.deliverAt = request.deliverAt
|
||||||
|
aapsLogger.debug(LTag.APS, "applyAPSRequest: bolus()")
|
||||||
|
commandQueue.bolus(detailedBolusInfo, callback)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun allowPercentage(): Boolean {
|
||||||
|
return virtualPumpPlugin.isEnabled(PluginType.PUMP)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun disconnectPump(durationInMinutes: Int, profile: Profile?) {
|
||||||
|
val pump = activePlugin.activePump
|
||||||
|
disconnectTo(System.currentTimeMillis() + durationInMinutes * 60 * 1000L)
|
||||||
|
if (pump.pumpDescription.tempBasalStyle == PumpDescription.ABSOLUTE) {
|
||||||
|
commandQueue.tempBasalAbsolute(0.0, durationInMinutes, true, profile!!, object : Callback() {
|
||||||
|
override fun run() {
|
||||||
|
if (!result.success) {
|
||||||
|
ErrorHelperActivity.runAlarm(context, result.comment, resourceHelper.gs(R.string.tempbasaldeliveryerror), info.nightscout.androidaps.dana.R.raw.boluserror)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
commandQueue.tempBasalPercent(0, durationInMinutes, true, profile!!, object : Callback() {
|
||||||
|
override fun run() {
|
||||||
|
if (!result.success) {
|
||||||
|
ErrorHelperActivity.runAlarm(context, result.comment, resourceHelper.gs(R.string.tempbasaldeliveryerror), info.nightscout.androidaps.dana.R.raw.boluserror)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if (pump.pumpDescription.isExtendedBolusCapable && treatmentsPlugin.isInHistoryExtendedBoluslInProgress) {
|
||||||
|
commandQueue.cancelExtended(object : Callback() {
|
||||||
|
override fun run() {
|
||||||
|
if (!result.success) {
|
||||||
|
ErrorHelperActivity.runAlarm(context, result.comment, resourceHelper.gs(R.string.extendedbolusdeliveryerror), info.nightscout.androidaps.dana.R.raw.boluserror)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
createOfflineEvent(durationInMinutes)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun suspendLoop(durationInMinutes: Int) {
|
||||||
|
suspendTo(System.currentTimeMillis() + durationInMinutes * 60 * 1000)
|
||||||
|
commandQueue.cancelTempBasal(true, object : Callback() {
|
||||||
|
override fun run() {
|
||||||
|
if (!result.success) {
|
||||||
|
ErrorHelperActivity.runAlarm(context, result.comment, resourceHelper.gs(R.string.tempbasaldeliveryerror), info.nightscout.androidaps.dana.R.raw.boluserror)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
createOfflineEvent(durationInMinutes)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun createOfflineEvent(durationInMinutes: Int) {
|
||||||
|
val data = JSONObject()
|
||||||
|
try {
|
||||||
|
data.put("eventType", CareportalEvent.OPENAPSOFFLINE)
|
||||||
|
data.put("duration", durationInMinutes)
|
||||||
|
} catch (e: JSONException) {
|
||||||
|
aapsLogger.error("Unhandled exception", e)
|
||||||
|
}
|
||||||
|
val event = CareportalEvent(injector)
|
||||||
|
event.date = DateUtil.now()
|
||||||
|
event.source = Source.USER
|
||||||
|
event.eventType = CareportalEvent.OPENAPSOFFLINE
|
||||||
|
event.json = data.toString()
|
||||||
|
MainApp.getDbHelper().createOrUpdate(event)
|
||||||
|
nsUpload.uploadOpenAPSOffline(event)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
private const val CHANNEL_ID = "AndroidAPS-OpenLoop"
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,41 +0,0 @@
|
||||||
package info.nightscout.androidaps.plugins.aps.loop;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.res.AssetManager;
|
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
|
|
||||||
public class ScriptReader {
|
|
||||||
|
|
||||||
private final Context mContext;
|
|
||||||
|
|
||||||
public ScriptReader(Context context) {
|
|
||||||
mContext = context;
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] readFile(String fileName) throws IOException {
|
|
||||||
|
|
||||||
AssetManager assetManager = mContext.getAssets();
|
|
||||||
InputStream is = assetManager.open(fileName);
|
|
||||||
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
|
||||||
|
|
||||||
int nRead;
|
|
||||||
byte[] data = new byte[16384];
|
|
||||||
|
|
||||||
while ((nRead = is.read(data, 0, data.length)) != -1) {
|
|
||||||
buffer.write(data, 0, nRead);
|
|
||||||
}
|
|
||||||
|
|
||||||
buffer.flush();
|
|
||||||
|
|
||||||
byte[] bytes = buffer.toByteArray();
|
|
||||||
is.close();
|
|
||||||
buffer.close();
|
|
||||||
|
|
||||||
|
|
||||||
return bytes;
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
package info.nightscout.androidaps.plugins.aps.loop
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import java.io.ByteArrayOutputStream
|
||||||
|
import java.io.IOException
|
||||||
|
|
||||||
|
class ScriptReader(private val context: Context) {
|
||||||
|
|
||||||
|
@Throws(IOException::class)
|
||||||
|
fun readFile(fileName: String): ByteArray {
|
||||||
|
val assetManager = context.assets
|
||||||
|
val `is` = assetManager.open(fileName)
|
||||||
|
val buffer = ByteArrayOutputStream()
|
||||||
|
var nRead: Int
|
||||||
|
val data = ByteArray(16384)
|
||||||
|
while (`is`.read(data, 0, data.size).also { nRead = it } != -1) {
|
||||||
|
buffer.write(data, 0, nRead)
|
||||||
|
}
|
||||||
|
buffer.flush()
|
||||||
|
val bytes = buffer.toByteArray()
|
||||||
|
`is`.close()
|
||||||
|
buffer.close()
|
||||||
|
return bytes
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,300 +0,0 @@
|
||||||
package info.nightscout.androidaps.plugins.aps.openAPSAMA;
|
|
||||||
|
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
|
|
||||||
import org.json.JSONArray;
|
|
||||||
import org.json.JSONException;
|
|
||||||
import org.json.JSONObject;
|
|
||||||
import org.mozilla.javascript.Context;
|
|
||||||
import org.mozilla.javascript.Function;
|
|
||||||
import org.mozilla.javascript.NativeJSON;
|
|
||||||
import org.mozilla.javascript.NativeObject;
|
|
||||||
import org.mozilla.javascript.RhinoException;
|
|
||||||
import org.mozilla.javascript.Scriptable;
|
|
||||||
import org.mozilla.javascript.ScriptableObject;
|
|
||||||
import org.mozilla.javascript.Undefined;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.lang.reflect.InvocationTargetException;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
|
|
||||||
import javax.inject.Inject;
|
|
||||||
|
|
||||||
import info.nightscout.androidaps.plugins.general.openhumans.OpenHumansUploader;
|
|
||||||
import dagger.android.HasAndroidInjector;
|
|
||||||
import info.nightscout.androidaps.Constants;
|
|
||||||
import info.nightscout.androidaps.R;
|
|
||||||
import info.nightscout.androidaps.data.IobTotal;
|
|
||||||
import info.nightscout.androidaps.data.MealData;
|
|
||||||
import info.nightscout.androidaps.data.Profile;
|
|
||||||
import info.nightscout.androidaps.db.TemporaryBasal;
|
|
||||||
import info.nightscout.androidaps.logging.AAPSLogger;
|
|
||||||
import info.nightscout.androidaps.logging.LTag;
|
|
||||||
import info.nightscout.androidaps.plugins.aps.loop.ScriptReader;
|
|
||||||
import info.nightscout.androidaps.plugins.aps.logger.LoggerCallback;
|
|
||||||
import info.nightscout.androidaps.plugins.aps.openAPSSMB.SMBDefaults;
|
|
||||||
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker;
|
|
||||||
import info.nightscout.androidaps.interfaces.ProfileFunction;
|
|
||||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus;
|
|
||||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin;
|
|
||||||
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin;
|
|
||||||
import info.nightscout.androidaps.utils.sharedPreferences.SP;
|
|
||||||
|
|
||||||
public class DetermineBasalAdapterAMAJS {
|
|
||||||
private final HasAndroidInjector injector;
|
|
||||||
@Inject AAPSLogger aapsLogger;
|
|
||||||
@Inject ConstraintChecker constraintChecker;
|
|
||||||
@Inject SP sp;
|
|
||||||
@Inject ProfileFunction profileFunction;
|
|
||||||
@Inject TreatmentsPlugin treatmentsPlugin;
|
|
||||||
@Inject OpenHumansUploader openHumansUploader;
|
|
||||||
|
|
||||||
private final ScriptReader mScriptReader;
|
|
||||||
|
|
||||||
private JSONObject mProfile;
|
|
||||||
private JSONObject mGlucoseStatus;
|
|
||||||
private JSONArray mIobData;
|
|
||||||
private JSONObject mMealData;
|
|
||||||
private JSONObject mCurrentTemp;
|
|
||||||
private JSONObject mAutosensData = null;
|
|
||||||
|
|
||||||
private String storedCurrentTemp = null;
|
|
||||||
private String storedIobData = null;
|
|
||||||
private String storedGlucoseStatus = null;
|
|
||||||
private String storedProfile = null;
|
|
||||||
private String storedMeal_data = null;
|
|
||||||
private String storedAutosens_data = null;
|
|
||||||
|
|
||||||
private String scriptDebug = "";
|
|
||||||
|
|
||||||
DetermineBasalAdapterAMAJS(ScriptReader scriptReader, HasAndroidInjector injector) {
|
|
||||||
injector.androidInjector().inject(this);
|
|
||||||
mScriptReader = scriptReader;
|
|
||||||
this.injector = injector;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
public DetermineBasalResultAMA invoke() {
|
|
||||||
|
|
||||||
aapsLogger.debug(LTag.APS, ">>> Invoking detemine_basal <<<");
|
|
||||||
aapsLogger.debug(LTag.APS, "Glucose status: " + (storedGlucoseStatus = mGlucoseStatus.toString()));
|
|
||||||
aapsLogger.debug(LTag.APS, "IOB data: " + (storedIobData = mIobData.toString()));
|
|
||||||
aapsLogger.debug(LTag.APS, "Current temp: " + (storedCurrentTemp = mCurrentTemp.toString()));
|
|
||||||
aapsLogger.debug(LTag.APS, "Profile: " + (storedProfile = mProfile.toString()));
|
|
||||||
aapsLogger.debug(LTag.APS, "Meal data: " + (storedMeal_data = mMealData.toString()));
|
|
||||||
if (mAutosensData != null)
|
|
||||||
aapsLogger.debug(LTag.APS, "Autosens data: " + (storedAutosens_data = mAutosensData.toString()));
|
|
||||||
else
|
|
||||||
aapsLogger.debug(LTag.APS, "Autosens data: " + (storedAutosens_data = "undefined"));
|
|
||||||
|
|
||||||
|
|
||||||
DetermineBasalResultAMA determineBasalResultAMA = null;
|
|
||||||
|
|
||||||
Context rhino = Context.enter();
|
|
||||||
Scriptable scope = rhino.initStandardObjects();
|
|
||||||
// Turn off optimization to make Rhino Android compatible
|
|
||||||
rhino.setOptimizationLevel(-1);
|
|
||||||
|
|
||||||
try {
|
|
||||||
|
|
||||||
//register logger callback for console.log and console.error
|
|
||||||
ScriptableObject.defineClass(scope, LoggerCallback.class);
|
|
||||||
Scriptable myLogger = rhino.newObject(scope, "LoggerCallback", null);
|
|
||||||
scope.put("console2", scope, myLogger);
|
|
||||||
rhino.evaluateString(scope, readFile("OpenAPSAMA/loggerhelper.js"), "JavaScript", 0, null);
|
|
||||||
|
|
||||||
//set module parent
|
|
||||||
rhino.evaluateString(scope, "var module = {\"parent\":Boolean(1)};", "JavaScript", 0, null);
|
|
||||||
rhino.evaluateString(scope, "var round_basal = function round_basal(basal, profile) { return basal; };", "JavaScript", 0, null);
|
|
||||||
rhino.evaluateString(scope, "require = function() {return round_basal;};", "JavaScript", 0, null);
|
|
||||||
|
|
||||||
//generate functions "determine_basal" and "setTempBasal"
|
|
||||||
rhino.evaluateString(scope, readFile("OpenAPSAMA/determine-basal.js"), "JavaScript", 0, null);
|
|
||||||
rhino.evaluateString(scope, readFile("OpenAPSAMA/basal-set-temp.js"), "setTempBasal.js", 0, null);
|
|
||||||
Object determineBasalObj = scope.get("determine_basal", scope);
|
|
||||||
Object setTempBasalFunctionsObj = scope.get("tempBasalFunctions", scope);
|
|
||||||
|
|
||||||
//call determine-basal
|
|
||||||
if (determineBasalObj instanceof Function && setTempBasalFunctionsObj instanceof NativeObject) {
|
|
||||||
Function determineBasalJS = (Function) determineBasalObj;
|
|
||||||
|
|
||||||
//prepare parameters
|
|
||||||
Object[] params = new Object[]{
|
|
||||||
makeParam(mGlucoseStatus, rhino, scope),
|
|
||||||
makeParam(mCurrentTemp, rhino, scope),
|
|
||||||
makeParamArray(mIobData, rhino, scope),
|
|
||||||
makeParam(mProfile, rhino, scope),
|
|
||||||
makeParam(mAutosensData, rhino, scope),
|
|
||||||
makeParam(mMealData, rhino, scope),
|
|
||||||
setTempBasalFunctionsObj};
|
|
||||||
|
|
||||||
NativeObject jsResult = (NativeObject) determineBasalJS.call(rhino, scope, scope, params);
|
|
||||||
scriptDebug = LoggerCallback.getScriptDebug();
|
|
||||||
|
|
||||||
// Parse the jsResult object to a JSON-String
|
|
||||||
String result = NativeJSON.stringify(rhino, scope, jsResult, null, null).toString();
|
|
||||||
aapsLogger.debug(LTag.APS, "Result: " + result);
|
|
||||||
try {
|
|
||||||
JSONObject resultJson = new JSONObject(result);
|
|
||||||
openHumansUploader.enqueueAMAData(mProfile, mGlucoseStatus, mIobData, mMealData, mCurrentTemp, mAutosensData, resultJson);
|
|
||||||
determineBasalResultAMA = new DetermineBasalResultAMA(injector, jsResult, resultJson);
|
|
||||||
} catch (JSONException e) {
|
|
||||||
aapsLogger.error(LTag.APS, "Unhandled exception", e);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
aapsLogger.error(LTag.APS, "Problem loading JS Functions");
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
aapsLogger.error(LTag.APS, "IOException");
|
|
||||||
} catch (RhinoException e) {
|
|
||||||
aapsLogger.error(LTag.APS, "RhinoException: (" + e.lineNumber() + "," + e.columnNumber() + ") " + e.toString());
|
|
||||||
} catch (IllegalAccessException | InstantiationException | InvocationTargetException e) {
|
|
||||||
aapsLogger.error(LTag.APS, e.toString());
|
|
||||||
} finally {
|
|
||||||
Context.exit();
|
|
||||||
}
|
|
||||||
|
|
||||||
storedGlucoseStatus = mGlucoseStatus.toString();
|
|
||||||
storedIobData = mIobData.toString();
|
|
||||||
storedCurrentTemp = mCurrentTemp.toString();
|
|
||||||
storedProfile = mProfile.toString();
|
|
||||||
storedMeal_data = mMealData.toString();
|
|
||||||
|
|
||||||
return determineBasalResultAMA;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
String getGlucoseStatusParam() {
|
|
||||||
return storedGlucoseStatus;
|
|
||||||
}
|
|
||||||
|
|
||||||
String getCurrentTempParam() {
|
|
||||||
return storedCurrentTemp;
|
|
||||||
}
|
|
||||||
|
|
||||||
String getIobDataParam() {
|
|
||||||
return storedIobData;
|
|
||||||
}
|
|
||||||
|
|
||||||
String getProfileParam() {
|
|
||||||
return storedProfile;
|
|
||||||
}
|
|
||||||
|
|
||||||
String getMealDataParam() {
|
|
||||||
return storedMeal_data;
|
|
||||||
}
|
|
||||||
|
|
||||||
String getAutosensDataParam() {
|
|
||||||
return storedAutosens_data;
|
|
||||||
}
|
|
||||||
|
|
||||||
String getScriptDebug() {
|
|
||||||
return scriptDebug;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setData(Profile profile,
|
|
||||||
double maxIob,
|
|
||||||
double maxBasal,
|
|
||||||
double minBg,
|
|
||||||
double maxBg,
|
|
||||||
double targetBg,
|
|
||||||
double basalrate,
|
|
||||||
IobTotal[] iobArray,
|
|
||||||
GlucoseStatus glucoseStatus,
|
|
||||||
MealData mealData,
|
|
||||||
double autosensDataRatio,
|
|
||||||
boolean tempTargetSet) throws JSONException {
|
|
||||||
|
|
||||||
mProfile = new JSONObject();
|
|
||||||
mProfile.put("max_iob", maxIob);
|
|
||||||
mProfile.put("dia", Math.min(profile.getDia(), 3d));
|
|
||||||
mProfile.put("type", "current");
|
|
||||||
mProfile.put("max_daily_basal", profile.getMaxDailyBasal());
|
|
||||||
mProfile.put("max_basal", maxBasal);
|
|
||||||
mProfile.put("min_bg", minBg);
|
|
||||||
mProfile.put("max_bg", maxBg);
|
|
||||||
mProfile.put("target_bg", targetBg);
|
|
||||||
mProfile.put("carb_ratio", profile.getIc());
|
|
||||||
mProfile.put("sens", profile.getIsfMgdl());
|
|
||||||
mProfile.put("max_daily_safety_multiplier", sp.getInt(R.string.key_openapsama_max_daily_safety_multiplier, 3));
|
|
||||||
mProfile.put("current_basal_safety_multiplier", sp.getDouble(R.string.key_openapsama_current_basal_safety_multiplier, 4d));
|
|
||||||
mProfile.put("skip_neutral_temps", true);
|
|
||||||
mProfile.put("current_basal", basalrate);
|
|
||||||
mProfile.put("temptargetSet", tempTargetSet);
|
|
||||||
mProfile.put("autosens_adjust_targets", sp.getBoolean(R.string.key_openapsama_autosens_adjusttargets, true));
|
|
||||||
//align with max-absorption model in AMA sensitivity
|
|
||||||
if (mealData.usedMinCarbsImpact > 0) {
|
|
||||||
mProfile.put("min_5m_carbimpact", mealData.usedMinCarbsImpact);
|
|
||||||
} else {
|
|
||||||
mProfile.put("min_5m_carbimpact", sp.getDouble(R.string.key_openapsama_min_5m_carbimpact, SMBDefaults.min_5m_carbimpact));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (profileFunction.getUnits().equals(Constants.MMOL)) {
|
|
||||||
mProfile.put("out_units", "mmol/L");
|
|
||||||
}
|
|
||||||
|
|
||||||
long now = System.currentTimeMillis();
|
|
||||||
TemporaryBasal tb = treatmentsPlugin.getTempBasalFromHistory(now);
|
|
||||||
|
|
||||||
mCurrentTemp = new JSONObject();
|
|
||||||
mCurrentTemp.put("temp", "absolute");
|
|
||||||
mCurrentTemp.put("duration", tb != null ? tb.getPlannedRemainingMinutes() : 0);
|
|
||||||
mCurrentTemp.put("rate", tb != null ? tb.tempBasalConvertedToAbsolute(now, profile) : 0d);
|
|
||||||
|
|
||||||
// as we have non default temps longer than 30 mintues
|
|
||||||
TemporaryBasal tempBasal = treatmentsPlugin.getTempBasalFromHistory(System.currentTimeMillis());
|
|
||||||
if (tempBasal != null) {
|
|
||||||
mCurrentTemp.put("minutesrunning", tempBasal.getRealDuration());
|
|
||||||
}
|
|
||||||
|
|
||||||
mIobData = IobCobCalculatorPlugin.convertToJSONArray(iobArray);
|
|
||||||
|
|
||||||
mGlucoseStatus = new JSONObject();
|
|
||||||
mGlucoseStatus.put("glucose", glucoseStatus.glucose);
|
|
||||||
|
|
||||||
if (sp.getBoolean(R.string.key_always_use_shortavg, false)) {
|
|
||||||
mGlucoseStatus.put("delta", glucoseStatus.short_avgdelta);
|
|
||||||
} else {
|
|
||||||
mGlucoseStatus.put("delta", glucoseStatus.delta);
|
|
||||||
}
|
|
||||||
mGlucoseStatus.put("short_avgdelta", glucoseStatus.short_avgdelta);
|
|
||||||
mGlucoseStatus.put("long_avgdelta", glucoseStatus.long_avgdelta);
|
|
||||||
|
|
||||||
mMealData = new JSONObject();
|
|
||||||
mMealData.put("carbs", mealData.carbs);
|
|
||||||
mMealData.put("boluses", mealData.boluses);
|
|
||||||
mMealData.put("mealCOB", mealData.mealCOB);
|
|
||||||
|
|
||||||
if (constraintChecker.isAutosensModeEnabled().value()) {
|
|
||||||
mAutosensData = new JSONObject();
|
|
||||||
mAutosensData.put("ratio", autosensDataRatio);
|
|
||||||
} else {
|
|
||||||
mAutosensData = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private Object makeParam(JSONObject jsonObject, Context rhino, Scriptable scope) {
|
|
||||||
|
|
||||||
if (jsonObject == null) return Undefined.instance;
|
|
||||||
|
|
||||||
Object param = NativeJSON.parse(rhino, scope, jsonObject.toString(), (context, scriptable, scriptable1, objects) -> objects[1]);
|
|
||||||
return param;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Object makeParamArray(JSONArray jsonArray, Context rhino, Scriptable scope) {
|
|
||||||
//Object param = NativeJSON.parse(rhino, scope, "{myarray: " + jsonArray.toString() + " }", new Callable() {
|
|
||||||
Object param = NativeJSON.parse(rhino, scope, jsonArray.toString(), (context, scriptable, scriptable1, objects) -> objects[1]);
|
|
||||||
return param;
|
|
||||||
}
|
|
||||||
|
|
||||||
private String readFile(String filename) throws IOException {
|
|
||||||
byte[] bytes = mScriptReader.readFile(filename);
|
|
||||||
String string = new String(bytes, StandardCharsets.UTF_8);
|
|
||||||
if (string.startsWith("#!/usr/bin/env node")) {
|
|
||||||
string = string.substring(20);
|
|
||||||
}
|
|
||||||
return string;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -0,0 +1,238 @@
|
||||||
|
package info.nightscout.androidaps.plugins.aps.openAPSAMA
|
||||||
|
|
||||||
|
import dagger.android.HasAndroidInjector
|
||||||
|
import info.nightscout.androidaps.Constants
|
||||||
|
import info.nightscout.androidaps.R
|
||||||
|
import info.nightscout.androidaps.data.IobTotal
|
||||||
|
import info.nightscout.androidaps.data.MealData
|
||||||
|
import info.nightscout.androidaps.data.Profile
|
||||||
|
import info.nightscout.androidaps.interfaces.ProfileFunction
|
||||||
|
import info.nightscout.androidaps.logging.AAPSLogger
|
||||||
|
import info.nightscout.androidaps.logging.LTag
|
||||||
|
import info.nightscout.androidaps.plugins.aps.logger.LoggerCallback
|
||||||
|
import info.nightscout.androidaps.plugins.aps.loop.ScriptReader
|
||||||
|
import info.nightscout.androidaps.plugins.aps.openAPSSMB.SMBDefaults
|
||||||
|
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
|
||||||
|
import info.nightscout.androidaps.plugins.general.openhumans.OpenHumansUploader
|
||||||
|
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus
|
||||||
|
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin
|
||||||
|
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin
|
||||||
|
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
||||||
|
import org.json.JSONArray
|
||||||
|
import org.json.JSONException
|
||||||
|
import org.json.JSONObject
|
||||||
|
import org.mozilla.javascript.*
|
||||||
|
import org.mozilla.javascript.Function
|
||||||
|
import java.io.IOException
|
||||||
|
import java.lang.reflect.InvocationTargetException
|
||||||
|
import java.nio.charset.StandardCharsets
|
||||||
|
import javax.inject.Inject
|
||||||
|
import kotlin.math.min
|
||||||
|
|
||||||
|
class DetermineBasalAdapterAMAJS internal constructor(scriptReader: ScriptReader, injector: HasAndroidInjector) {
|
||||||
|
|
||||||
|
private val injector: HasAndroidInjector
|
||||||
|
|
||||||
|
@Inject lateinit var aapsLogger: AAPSLogger
|
||||||
|
@Inject lateinit var constraintChecker: ConstraintChecker
|
||||||
|
@Inject lateinit var sp: SP
|
||||||
|
@Inject lateinit var profileFunction: ProfileFunction
|
||||||
|
@Inject lateinit var treatmentsPlugin: TreatmentsPlugin
|
||||||
|
@Inject lateinit var openHumansUploader: OpenHumansUploader
|
||||||
|
|
||||||
|
private val mScriptReader: ScriptReader
|
||||||
|
private var profile = JSONObject()
|
||||||
|
private var glucoseStatus = JSONObject()
|
||||||
|
private var iobData: JSONArray? = null
|
||||||
|
private var mealData = JSONObject()
|
||||||
|
private var currentTemp = JSONObject()
|
||||||
|
private var autosensData = JSONObject()
|
||||||
|
|
||||||
|
var currentTempParam: String? = null
|
||||||
|
private set
|
||||||
|
var iobDataParam: String? = null
|
||||||
|
private set
|
||||||
|
var glucoseStatusParam: String? = null
|
||||||
|
private set
|
||||||
|
var profileParam: String? = null
|
||||||
|
private set
|
||||||
|
var mealDataParam: String? = null
|
||||||
|
private set
|
||||||
|
var scriptDebug = ""
|
||||||
|
private set
|
||||||
|
|
||||||
|
operator fun invoke(): DetermineBasalResultAMA? {
|
||||||
|
aapsLogger.debug(LTag.APS, ">>> Invoking determine_basal <<<")
|
||||||
|
aapsLogger.debug(LTag.APS, "Glucose status: " + glucoseStatus.toString().also { glucoseStatusParam = it })
|
||||||
|
aapsLogger.debug(LTag.APS, "IOB data: " + iobData.toString().also { iobDataParam = it })
|
||||||
|
aapsLogger.debug(LTag.APS, "Current temp: " + currentTemp.toString().also { currentTempParam = it })
|
||||||
|
aapsLogger.debug(LTag.APS, "Profile: " + profile.toString().also { profileParam = it })
|
||||||
|
aapsLogger.debug(LTag.APS, "Meal data: " + mealData.toString().also { mealDataParam = it })
|
||||||
|
aapsLogger.debug(LTag.APS, "Autosens data: $autosensData")
|
||||||
|
var determineBasalResultAMA: DetermineBasalResultAMA? = null
|
||||||
|
val rhino = Context.enter()
|
||||||
|
val scope: Scriptable = rhino.initStandardObjects()
|
||||||
|
// Turn off optimization to make Rhino Android compatible
|
||||||
|
rhino.optimizationLevel = -1
|
||||||
|
try {
|
||||||
|
|
||||||
|
//register logger callback for console.log and console.error
|
||||||
|
ScriptableObject.defineClass(scope, LoggerCallback::class.java)
|
||||||
|
val myLogger = rhino.newObject(scope, "LoggerCallback", null)
|
||||||
|
scope.put("console2", scope, myLogger)
|
||||||
|
rhino.evaluateString(scope, readFile("OpenAPSAMA/loggerhelper.js"), "JavaScript", 0, null)
|
||||||
|
|
||||||
|
//set module parent
|
||||||
|
rhino.evaluateString(scope, "var module = {\"parent\":Boolean(1)};", "JavaScript", 0, null)
|
||||||
|
rhino.evaluateString(scope, "var round_basal = function round_basal(basal, profile) { return basal; };", "JavaScript", 0, null)
|
||||||
|
rhino.evaluateString(scope, "require = function() {return round_basal;};", "JavaScript", 0, null)
|
||||||
|
|
||||||
|
//generate functions "determine_basal" and "setTempBasal"
|
||||||
|
rhino.evaluateString(scope, readFile("OpenAPSAMA/determine-basal.js"), "JavaScript", 0, null)
|
||||||
|
rhino.evaluateString(scope, readFile("OpenAPSAMA/basal-set-temp.js"), "setTempBasal.js", 0, null)
|
||||||
|
val determineBasalObj = scope["determine_basal", scope]
|
||||||
|
val setTempBasalFunctionsObj = scope["tempBasalFunctions", scope]
|
||||||
|
|
||||||
|
//call determine-basal
|
||||||
|
if (determineBasalObj is Function && setTempBasalFunctionsObj is NativeObject) {
|
||||||
|
|
||||||
|
//prepare parameters
|
||||||
|
val params = arrayOf(
|
||||||
|
makeParam(glucoseStatus, rhino, scope),
|
||||||
|
makeParam(currentTemp, rhino, scope),
|
||||||
|
makeParamArray(iobData, rhino, scope),
|
||||||
|
makeParam(profile, rhino, scope),
|
||||||
|
makeParam(autosensData, rhino, scope),
|
||||||
|
makeParam(mealData, rhino, scope),
|
||||||
|
setTempBasalFunctionsObj)
|
||||||
|
val jsResult = determineBasalObj.call(rhino, scope, scope, params) as NativeObject
|
||||||
|
scriptDebug = LoggerCallback.scriptDebug
|
||||||
|
|
||||||
|
// Parse the jsResult object to a JSON-String
|
||||||
|
val result = NativeJSON.stringify(rhino, scope, jsResult, null, null).toString()
|
||||||
|
aapsLogger.debug(LTag.APS, "Result: $result")
|
||||||
|
try {
|
||||||
|
val resultJson = JSONObject(result)
|
||||||
|
openHumansUploader.enqueueAMAData(profile, glucoseStatus, iobData, mealData, currentTemp, autosensData, resultJson)
|
||||||
|
determineBasalResultAMA = DetermineBasalResultAMA(injector, jsResult, resultJson)
|
||||||
|
} catch (e: JSONException) {
|
||||||
|
aapsLogger.error(LTag.APS, "Unhandled exception", e)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
aapsLogger.error(LTag.APS, "Problem loading JS Functions")
|
||||||
|
}
|
||||||
|
} catch (e: IOException) {
|
||||||
|
aapsLogger.error(LTag.APS, "IOException")
|
||||||
|
} catch (e: RhinoException) {
|
||||||
|
aapsLogger.error(LTag.APS, "RhinoException: (" + e.lineNumber() + "," + e.columnNumber() + ") " + e.toString())
|
||||||
|
} catch (e: IllegalAccessException) {
|
||||||
|
aapsLogger.error(LTag.APS, e.toString())
|
||||||
|
} catch (e: InstantiationException) {
|
||||||
|
aapsLogger.error(LTag.APS, e.toString())
|
||||||
|
} catch (e: InvocationTargetException) {
|
||||||
|
aapsLogger.error(LTag.APS, e.toString())
|
||||||
|
} finally {
|
||||||
|
Context.exit()
|
||||||
|
}
|
||||||
|
glucoseStatusParam = glucoseStatus.toString()
|
||||||
|
iobDataParam = iobData.toString()
|
||||||
|
currentTempParam = currentTemp.toString()
|
||||||
|
profileParam = profile.toString()
|
||||||
|
mealDataParam = mealData.toString()
|
||||||
|
return determineBasalResultAMA
|
||||||
|
}
|
||||||
|
|
||||||
|
@Throws(JSONException::class) fun setData(profile: Profile,
|
||||||
|
maxIob: Double,
|
||||||
|
maxBasal: Double,
|
||||||
|
minBg: Double,
|
||||||
|
maxBg: Double,
|
||||||
|
targetBg: Double,
|
||||||
|
basalRate: Double,
|
||||||
|
iobArray: Array<IobTotal?>?,
|
||||||
|
glucoseStatus: GlucoseStatus,
|
||||||
|
mealData: MealData,
|
||||||
|
autosensDataRatio: Double,
|
||||||
|
tempTargetSet: Boolean) {
|
||||||
|
this.profile = JSONObject()
|
||||||
|
this.profile.put("max_iob", maxIob)
|
||||||
|
this.profile.put("dia", min(profile.dia, 3.0))
|
||||||
|
this.profile.put("type", "current")
|
||||||
|
this.profile.put("max_daily_basal", profile.maxDailyBasal)
|
||||||
|
this.profile.put("max_basal", maxBasal)
|
||||||
|
this.profile.put("min_bg", minBg)
|
||||||
|
this.profile.put("max_bg", maxBg)
|
||||||
|
this.profile.put("target_bg", targetBg)
|
||||||
|
this.profile.put("carb_ratio", profile.ic)
|
||||||
|
this.profile.put("sens", profile.isfMgdl)
|
||||||
|
this.profile.put("max_daily_safety_multiplier", sp.getInt(R.string.key_openapsama_max_daily_safety_multiplier, 3))
|
||||||
|
this.profile.put("current_basal_safety_multiplier", sp.getDouble(R.string.key_openapsama_current_basal_safety_multiplier, 4.0))
|
||||||
|
this.profile.put("skip_neutral_temps", true)
|
||||||
|
this.profile.put("current_basal", basalRate)
|
||||||
|
this.profile.put("temptargetSet", tempTargetSet)
|
||||||
|
this.profile.put("autosens_adjust_targets", sp.getBoolean(R.string.key_openapsama_autosens_adjusttargets, true))
|
||||||
|
//align with max-absorption model in AMA sensitivity
|
||||||
|
if (mealData.usedMinCarbsImpact > 0) {
|
||||||
|
this.profile.put("min_5m_carbimpact", mealData.usedMinCarbsImpact)
|
||||||
|
} else {
|
||||||
|
this.profile.put("min_5m_carbimpact", sp.getDouble(R.string.key_openapsama_min_5m_carbimpact, SMBDefaults.min_5m_carbimpact))
|
||||||
|
}
|
||||||
|
if (profileFunction.getUnits() == Constants.MMOL) {
|
||||||
|
this.profile.put("out_units", "mmol/L")
|
||||||
|
}
|
||||||
|
val now = System.currentTimeMillis()
|
||||||
|
val tb = treatmentsPlugin.getTempBasalFromHistory(now)
|
||||||
|
currentTemp = JSONObject()
|
||||||
|
currentTemp.put("temp", "absolute")
|
||||||
|
currentTemp.put("duration", tb?.plannedRemainingMinutes ?: 0)
|
||||||
|
currentTemp.put("rate", tb?.tempBasalConvertedToAbsolute(now, profile) ?: 0.0)
|
||||||
|
|
||||||
|
// as we have non default temps longer than 30 minutes
|
||||||
|
val tempBasal = treatmentsPlugin.getTempBasalFromHistory(System.currentTimeMillis())
|
||||||
|
if (tempBasal != null) {
|
||||||
|
currentTemp.put("minutesrunning", tempBasal.realDuration)
|
||||||
|
}
|
||||||
|
iobData = IobCobCalculatorPlugin.convertToJSONArray(iobArray)
|
||||||
|
this.glucoseStatus = JSONObject()
|
||||||
|
this.glucoseStatus.put("glucose", glucoseStatus.glucose)
|
||||||
|
if (sp.getBoolean(R.string.key_always_use_shortavg, false)) {
|
||||||
|
this.glucoseStatus.put("delta", glucoseStatus.short_avgdelta)
|
||||||
|
} else {
|
||||||
|
this.glucoseStatus.put("delta", glucoseStatus.delta)
|
||||||
|
}
|
||||||
|
this.glucoseStatus.put("short_avgdelta", glucoseStatus.short_avgdelta)
|
||||||
|
this.glucoseStatus.put("long_avgdelta", glucoseStatus.long_avgdelta)
|
||||||
|
this.mealData = JSONObject()
|
||||||
|
this.mealData.put("carbs", mealData.carbs)
|
||||||
|
this.mealData.put("boluses", mealData.boluses)
|
||||||
|
this.mealData.put("mealCOB", mealData.mealCOB)
|
||||||
|
if (constraintChecker.isAutosensModeEnabled().value()) {
|
||||||
|
autosensData.put("ratio", autosensDataRatio)
|
||||||
|
} else {
|
||||||
|
autosensData.put("ratio", 1.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun makeParam(jsonObject: JSONObject?, rhino: Context, scope: Scriptable): Any {
|
||||||
|
return if (jsonObject == null) Undefined.instance else NativeJSON.parse(rhino, scope, jsonObject.toString()) { _: Context?, _: Scriptable?, _: Scriptable?, objects: Array<Any?> -> objects[1] }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun makeParamArray(jsonArray: JSONArray?, rhino: Context, scope: Scriptable): Any {
|
||||||
|
return NativeJSON.parse(rhino, scope, jsonArray.toString()) { _: Context?, _: Scriptable?, _: Scriptable?, objects: Array<Any?> -> objects[1] }
|
||||||
|
}
|
||||||
|
|
||||||
|
@Throws(IOException::class) private fun readFile(filename: String): String {
|
||||||
|
val bytes = mScriptReader.readFile(filename)
|
||||||
|
var string = String(bytes, StandardCharsets.UTF_8)
|
||||||
|
if (string.startsWith("#!/usr/bin/env node")) {
|
||||||
|
string = string.substring(20)
|
||||||
|
}
|
||||||
|
return string
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
injector.androidInjector().inject(this)
|
||||||
|
mScriptReader = scriptReader
|
||||||
|
this.injector = injector
|
||||||
|
}
|
||||||
|
}
|
|
@ -114,7 +114,7 @@ class OpenAPSAMAFragment : DaggerFragment() {
|
||||||
if (openAPSAMAPlugin.lastAPSRun != 0L) {
|
if (openAPSAMAPlugin.lastAPSRun != 0L) {
|
||||||
binding.lastrun.text = dateUtil.dateAndTimeString(openAPSAMAPlugin.lastAPSRun)
|
binding.lastrun.text = dateUtil.dateAndTimeString(openAPSAMAPlugin.lastAPSRun)
|
||||||
}
|
}
|
||||||
openAPSAMAPlugin.lastAutosensResult?.let {
|
openAPSAMAPlugin.lastAutosensResult.let {
|
||||||
binding.autosensdata.text = JSONFormatter.format(it.json())
|
binding.autosensdata.text = JSONFormatter.format(it.json())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,263 +0,0 @@
|
||||||
package info.nightscout.androidaps.plugins.aps.openAPSAMA;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
|
|
||||||
import org.json.JSONException;
|
|
||||||
|
|
||||||
import javax.inject.Inject;
|
|
||||||
import javax.inject.Singleton;
|
|
||||||
|
|
||||||
import dagger.android.HasAndroidInjector;
|
|
||||||
import info.nightscout.androidaps.R;
|
|
||||||
import info.nightscout.androidaps.data.IobTotal;
|
|
||||||
import info.nightscout.androidaps.data.MealData;
|
|
||||||
import info.nightscout.androidaps.data.Profile;
|
|
||||||
import info.nightscout.androidaps.db.TempTarget;
|
|
||||||
import info.nightscout.androidaps.interfaces.APSInterface;
|
|
||||||
import info.nightscout.androidaps.interfaces.ActivePluginProvider;
|
|
||||||
import info.nightscout.androidaps.interfaces.PluginBase;
|
|
||||||
import info.nightscout.androidaps.interfaces.PluginDescription;
|
|
||||||
import info.nightscout.androidaps.interfaces.PluginType;
|
|
||||||
import info.nightscout.androidaps.interfaces.ProfileFunction;
|
|
||||||
import info.nightscout.androidaps.interfaces.PumpInterface;
|
|
||||||
import info.nightscout.androidaps.logging.AAPSLogger;
|
|
||||||
import info.nightscout.androidaps.logging.LTag;
|
|
||||||
import info.nightscout.androidaps.plugins.aps.events.EventOpenAPSUpdateGui;
|
|
||||||
import info.nightscout.androidaps.plugins.aps.events.EventOpenAPSUpdateResultGui;
|
|
||||||
import info.nightscout.androidaps.plugins.aps.loop.APSResult;
|
|
||||||
import info.nightscout.androidaps.plugins.aps.loop.ScriptReader;
|
|
||||||
import info.nightscout.androidaps.plugins.bus.RxBusWrapper;
|
|
||||||
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker;
|
|
||||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensResult;
|
|
||||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus;
|
|
||||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin;
|
|
||||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.data.AutosensData;
|
|
||||||
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin;
|
|
||||||
import info.nightscout.androidaps.utils.DateUtil;
|
|
||||||
import info.nightscout.androidaps.utils.FabricPrivacy;
|
|
||||||
import info.nightscout.androidaps.utils.HardLimits;
|
|
||||||
import info.nightscout.androidaps.utils.Profiler;
|
|
||||||
import info.nightscout.androidaps.utils.Round;
|
|
||||||
import info.nightscout.androidaps.utils.resources.ResourceHelper;
|
|
||||||
|
|
||||||
@Singleton
|
|
||||||
public class OpenAPSAMAPlugin extends PluginBase implements APSInterface {
|
|
||||||
private final AAPSLogger aapsLogger;
|
|
||||||
private final RxBusWrapper rxBus;
|
|
||||||
private final ConstraintChecker constraintChecker;
|
|
||||||
private final ResourceHelper resourceHelper;
|
|
||||||
private final ProfileFunction profileFunction;
|
|
||||||
private final Context context;
|
|
||||||
private final ActivePluginProvider activePlugin;
|
|
||||||
private final TreatmentsPlugin treatmentsPlugin;
|
|
||||||
private final IobCobCalculatorPlugin iobCobCalculatorPlugin;
|
|
||||||
private final HardLimits hardLimits;
|
|
||||||
private final Profiler profiler;
|
|
||||||
private final FabricPrivacy fabricPrivacy;
|
|
||||||
|
|
||||||
// last values
|
|
||||||
DetermineBasalAdapterAMAJS lastDetermineBasalAdapterAMAJS = null;
|
|
||||||
long lastAPSRun = 0;
|
|
||||||
DetermineBasalResultAMA lastAPSResult = null;
|
|
||||||
AutosensResult lastAutosensResult = null;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
public OpenAPSAMAPlugin(
|
|
||||||
HasAndroidInjector injector,
|
|
||||||
AAPSLogger aapsLogger,
|
|
||||||
RxBusWrapper rxBus,
|
|
||||||
ConstraintChecker constraintChecker,
|
|
||||||
ResourceHelper resourceHelper,
|
|
||||||
ProfileFunction profileFunction,
|
|
||||||
Context context,
|
|
||||||
ActivePluginProvider activePlugin,
|
|
||||||
TreatmentsPlugin treatmentsPlugin,
|
|
||||||
IobCobCalculatorPlugin iobCobCalculatorPlugin,
|
|
||||||
HardLimits hardLimits,
|
|
||||||
Profiler profiler,
|
|
||||||
FabricPrivacy fabricPrivacy
|
|
||||||
) {
|
|
||||||
super(new PluginDescription()
|
|
||||||
.mainType(PluginType.APS)
|
|
||||||
.fragmentClass(OpenAPSAMAFragment.class.getName())
|
|
||||||
.pluginIcon(R.drawable.ic_generic_icon)
|
|
||||||
.pluginName(R.string.openapsama)
|
|
||||||
.shortName(R.string.oaps_shortname)
|
|
||||||
.preferencesId(R.xml.pref_openapsama)
|
|
||||||
.description(R.string.description_ama),
|
|
||||||
aapsLogger, resourceHelper, injector
|
|
||||||
);
|
|
||||||
this.aapsLogger = aapsLogger;
|
|
||||||
this.rxBus = rxBus;
|
|
||||||
this.constraintChecker = constraintChecker;
|
|
||||||
this.resourceHelper = resourceHelper;
|
|
||||||
this.profileFunction = profileFunction;
|
|
||||||
this.context = context;
|
|
||||||
this.activePlugin = activePlugin;
|
|
||||||
this.treatmentsPlugin = treatmentsPlugin;
|
|
||||||
this.iobCobCalculatorPlugin = iobCobCalculatorPlugin;
|
|
||||||
this.hardLimits = hardLimits;
|
|
||||||
this.profiler = profiler;
|
|
||||||
this.fabricPrivacy = fabricPrivacy;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean specialEnableCondition() {
|
|
||||||
try {
|
|
||||||
PumpInterface pump = activePlugin.getActivePump();
|
|
||||||
return pump.getPumpDescription().isTempBasalCapable;
|
|
||||||
} catch (Exception ignored) {
|
|
||||||
// may fail during initialization
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean specialShowInListCondition() {
|
|
||||||
PumpInterface pump = activePlugin.getActivePump();
|
|
||||||
return pump.getPumpDescription().isTempBasalCapable;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public APSResult getLastAPSResult() {
|
|
||||||
return lastAPSResult;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public long getLastAPSRun() {
|
|
||||||
return lastAPSRun;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void invoke(String initiator, boolean tempBasalFallback) {
|
|
||||||
aapsLogger.debug(LTag.APS, "invoke from " + initiator + " tempBasalFallback: " + tempBasalFallback);
|
|
||||||
lastAPSResult = null;
|
|
||||||
DetermineBasalAdapterAMAJS determineBasalAdapterAMAJS;
|
|
||||||
determineBasalAdapterAMAJS = new DetermineBasalAdapterAMAJS(new ScriptReader(context), getInjector());
|
|
||||||
|
|
||||||
GlucoseStatus glucoseStatus = new GlucoseStatus(getInjector()).getGlucoseStatusData();
|
|
||||||
Profile profile = profileFunction.getProfile();
|
|
||||||
PumpInterface pump = activePlugin.getActivePump();
|
|
||||||
|
|
||||||
if (profile == null) {
|
|
||||||
rxBus.send(new EventOpenAPSUpdateResultGui(resourceHelper.gs(R.string.noprofileselected)));
|
|
||||||
aapsLogger.debug(LTag.APS, resourceHelper.gs(R.string.noprofileselected));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isEnabled(PluginType.APS)) {
|
|
||||||
rxBus.send(new EventOpenAPSUpdateResultGui(resourceHelper.gs(R.string.openapsma_disabled)));
|
|
||||||
aapsLogger.debug(LTag.APS, resourceHelper.gs(R.string.openapsma_disabled));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (glucoseStatus == null) {
|
|
||||||
rxBus.send(new EventOpenAPSUpdateResultGui(resourceHelper.gs(R.string.openapsma_noglucosedata)));
|
|
||||||
aapsLogger.debug(LTag.APS, resourceHelper.gs(R.string.openapsma_noglucosedata));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
double maxBasal = constraintChecker.getMaxBasalAllowed(profile).value();
|
|
||||||
double minBg = profile.getTargetLowMgdl();
|
|
||||||
double maxBg = profile.getTargetHighMgdl();
|
|
||||||
double targetBg = profile.getTargetMgdl();
|
|
||||||
|
|
||||||
minBg = Round.roundTo(minBg, 0.1d);
|
|
||||||
maxBg = Round.roundTo(maxBg, 0.1d);
|
|
||||||
|
|
||||||
long start = System.currentTimeMillis();
|
|
||||||
long startPart = System.currentTimeMillis();
|
|
||||||
IobTotal[] iobArray = iobCobCalculatorPlugin.calculateIobArrayInDia(profile);
|
|
||||||
profiler.log(LTag.APS, "calculateIobArrayInDia()", startPart);
|
|
||||||
|
|
||||||
startPart = System.currentTimeMillis();
|
|
||||||
MealData mealData = iobCobCalculatorPlugin.getMealData();
|
|
||||||
profiler.log(LTag.APS, "getMealData()", startPart);
|
|
||||||
|
|
||||||
double maxIob = constraintChecker.getMaxIOBAllowed().value();
|
|
||||||
|
|
||||||
minBg = hardLimits.verifyHardLimits(minBg, "minBg", hardLimits.getVERY_HARD_LIMIT_MIN_BG()[0], hardLimits.getVERY_HARD_LIMIT_MIN_BG()[1]);
|
|
||||||
maxBg = hardLimits.verifyHardLimits(maxBg, "maxBg", hardLimits.getVERY_HARD_LIMIT_MAX_BG()[0], hardLimits.getVERY_HARD_LIMIT_MAX_BG()[1]);
|
|
||||||
targetBg = hardLimits.verifyHardLimits(targetBg, "targetBg", hardLimits.getVERY_HARD_LIMIT_TARGET_BG()[0], hardLimits.getVERY_HARD_LIMIT_TARGET_BG()[1]);
|
|
||||||
|
|
||||||
boolean isTempTarget = false;
|
|
||||||
TempTarget tempTarget = treatmentsPlugin.getTempTargetFromHistory(System.currentTimeMillis());
|
|
||||||
if (tempTarget != null) {
|
|
||||||
isTempTarget = true;
|
|
||||||
minBg = hardLimits.verifyHardLimits(tempTarget.low, "minBg", hardLimits.getVERY_HARD_LIMIT_TEMP_MIN_BG()[0], hardLimits.getVERY_HARD_LIMIT_TEMP_MIN_BG()[1]);
|
|
||||||
maxBg = hardLimits.verifyHardLimits(tempTarget.high, "maxBg", hardLimits.getVERY_HARD_LIMIT_TEMP_MAX_BG()[0], hardLimits.getVERY_HARD_LIMIT_TEMP_MAX_BG()[1]);
|
|
||||||
targetBg = hardLimits.verifyHardLimits(tempTarget.target(), "targetBg", hardLimits.getVERY_HARD_LIMIT_TEMP_TARGET_BG()[0], hardLimits.getVERY_HARD_LIMIT_TEMP_TARGET_BG()[1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (!hardLimits.checkOnlyHardLimits(profile.getDia(), "dia", hardLimits.minDia(), hardLimits.maxDia()))
|
|
||||||
return;
|
|
||||||
if (!hardLimits.checkOnlyHardLimits(profile.getIcTimeFromMidnight(Profile.secondsFromMidnight()), "carbratio", hardLimits.minIC(), hardLimits.maxIC()))
|
|
||||||
return;
|
|
||||||
if (!hardLimits.checkOnlyHardLimits(profile.getIsfMgdl(), "sens", hardLimits.getMINISF(), hardLimits.getMAXISF()))
|
|
||||||
return;
|
|
||||||
if (!hardLimits.checkOnlyHardLimits(profile.getMaxDailyBasal(), "max_daily_basal", 0.02, hardLimits.maxBasal()))
|
|
||||||
return;
|
|
||||||
if (!hardLimits.checkOnlyHardLimits(pump.getBaseBasalRate(), "current_basal", 0.01, hardLimits.maxBasal()))
|
|
||||||
return;
|
|
||||||
|
|
||||||
startPart = System.currentTimeMillis();
|
|
||||||
if (constraintChecker.isAutosensModeEnabled().value()) {
|
|
||||||
AutosensData autosensData = iobCobCalculatorPlugin.getLastAutosensDataSynchronized("OpenAPSPlugin");
|
|
||||||
if (autosensData == null) {
|
|
||||||
rxBus.send(new EventOpenAPSUpdateResultGui(resourceHelper.gs(R.string.openaps_noasdata)));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
lastAutosensResult = autosensData.autosensResult;
|
|
||||||
} else {
|
|
||||||
lastAutosensResult = new AutosensResult();
|
|
||||||
lastAutosensResult.sensResult = "autosens disabled";
|
|
||||||
}
|
|
||||||
profiler.log(LTag.APS, "detectSensitivityandCarbAbsorption()", startPart);
|
|
||||||
profiler.log(LTag.APS, "AMA data gathering", start);
|
|
||||||
|
|
||||||
start = System.currentTimeMillis();
|
|
||||||
|
|
||||||
try {
|
|
||||||
determineBasalAdapterAMAJS.setData(profile, maxIob, maxBasal, minBg, maxBg, targetBg, activePlugin.getActivePump().getBaseBasalRate(), iobArray, glucoseStatus, mealData,
|
|
||||||
lastAutosensResult.ratio, //autosensDataRatio
|
|
||||||
isTempTarget
|
|
||||||
);
|
|
||||||
} catch (JSONException e) {
|
|
||||||
fabricPrivacy.logException(e);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
DetermineBasalResultAMA determineBasalResultAMA = determineBasalAdapterAMAJS.invoke();
|
|
||||||
profiler.log(LTag.APS, "AMA calculation", start);
|
|
||||||
// Fix bug determine basal
|
|
||||||
if (determineBasalResultAMA == null) {
|
|
||||||
aapsLogger.error(LTag.APS, "SMB calculation returned null");
|
|
||||||
lastDetermineBasalAdapterAMAJS = null;
|
|
||||||
lastAPSResult = null;
|
|
||||||
lastAPSRun = 0;
|
|
||||||
} else {
|
|
||||||
if (determineBasalResultAMA.getRate() == 0d && determineBasalResultAMA.getDuration() == 0 && !treatmentsPlugin.isTempBasalInProgress())
|
|
||||||
determineBasalResultAMA.setTempBasalRequested(false);
|
|
||||||
|
|
||||||
determineBasalResultAMA.setIob(iobArray[0]);
|
|
||||||
|
|
||||||
long now = System.currentTimeMillis();
|
|
||||||
|
|
||||||
try {
|
|
||||||
determineBasalResultAMA.getJson().put("timestamp", DateUtil.toISOString(now));
|
|
||||||
} catch (JSONException e) {
|
|
||||||
aapsLogger.error(LTag.APS, "Unhandled exception", e);
|
|
||||||
}
|
|
||||||
|
|
||||||
lastDetermineBasalAdapterAMAJS = determineBasalAdapterAMAJS;
|
|
||||||
lastAPSResult = determineBasalResultAMA;
|
|
||||||
lastAPSRun = now;
|
|
||||||
}
|
|
||||||
rxBus.send(new EventOpenAPSUpdateGui());
|
|
||||||
|
|
||||||
//deviceStatus.suggested = determineBasalResultAMA.json;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -0,0 +1,172 @@
|
||||||
|
package info.nightscout.androidaps.plugins.aps.openAPSAMA
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import dagger.android.HasAndroidInjector
|
||||||
|
import info.nightscout.androidaps.R
|
||||||
|
import info.nightscout.androidaps.data.Profile
|
||||||
|
import info.nightscout.androidaps.interfaces.*
|
||||||
|
import info.nightscout.androidaps.logging.AAPSLogger
|
||||||
|
import info.nightscout.androidaps.logging.LTag
|
||||||
|
import info.nightscout.androidaps.plugins.aps.events.EventOpenAPSUpdateGui
|
||||||
|
import info.nightscout.androidaps.plugins.aps.events.EventOpenAPSUpdateResultGui
|
||||||
|
import info.nightscout.androidaps.plugins.aps.loop.ScriptReader
|
||||||
|
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
||||||
|
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
|
||||||
|
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensResult
|
||||||
|
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus
|
||||||
|
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin
|
||||||
|
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin
|
||||||
|
import info.nightscout.androidaps.utils.DateUtil
|
||||||
|
import info.nightscout.androidaps.utils.FabricPrivacy
|
||||||
|
import info.nightscout.androidaps.utils.HardLimits
|
||||||
|
import info.nightscout.androidaps.utils.Profiler
|
||||||
|
import info.nightscout.androidaps.utils.Round
|
||||||
|
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||||
|
import org.json.JSONException
|
||||||
|
import javax.inject.Inject
|
||||||
|
import javax.inject.Singleton
|
||||||
|
|
||||||
|
@Singleton
|
||||||
|
open class OpenAPSAMAPlugin @Inject constructor(
|
||||||
|
injector: HasAndroidInjector,
|
||||||
|
aapsLogger: AAPSLogger,
|
||||||
|
private val rxBus: RxBusWrapper,
|
||||||
|
private val constraintChecker: ConstraintChecker,
|
||||||
|
resourceHelper: ResourceHelper,
|
||||||
|
private val profileFunction: ProfileFunction,
|
||||||
|
private val context: Context,
|
||||||
|
private val activePlugin: ActivePluginProvider,
|
||||||
|
private val treatmentsPlugin: TreatmentsPlugin,
|
||||||
|
private val iobCobCalculatorPlugin: IobCobCalculatorPlugin,
|
||||||
|
private val hardLimits: HardLimits,
|
||||||
|
private val profiler: Profiler,
|
||||||
|
private val fabricPrivacy: FabricPrivacy
|
||||||
|
) : PluginBase(PluginDescription()
|
||||||
|
.mainType(PluginType.APS)
|
||||||
|
.fragmentClass(OpenAPSAMAFragment::class.java.name)
|
||||||
|
.pluginIcon(R.drawable.ic_generic_icon)
|
||||||
|
.pluginName(R.string.openapsama)
|
||||||
|
.shortName(R.string.oaps_shortname)
|
||||||
|
.preferencesId(R.xml.pref_openapsama)
|
||||||
|
.description(R.string.description_ama),
|
||||||
|
aapsLogger, resourceHelper, injector
|
||||||
|
), APSInterface {
|
||||||
|
|
||||||
|
// last values
|
||||||
|
override var lastAPSRun: Long = 0
|
||||||
|
override var lastAPSResult: DetermineBasalResultAMA? = null
|
||||||
|
var lastDetermineBasalAdapterAMAJS: DetermineBasalAdapterAMAJS? = null
|
||||||
|
var lastAutosensResult: AutosensResult = AutosensResult()
|
||||||
|
|
||||||
|
override fun specialEnableCondition(): Boolean {
|
||||||
|
return try {
|
||||||
|
val pump = activePlugin.activePump
|
||||||
|
pump.pumpDescription.isTempBasalCapable
|
||||||
|
} catch (ignored: Exception) {
|
||||||
|
// may fail during initialization
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun specialShowInListCondition(): Boolean {
|
||||||
|
val pump = activePlugin.activePump
|
||||||
|
return pump.pumpDescription.isTempBasalCapable
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun invoke(initiator: String, tempBasalFallback: Boolean) {
|
||||||
|
aapsLogger.debug(LTag.APS, "invoke from $initiator tempBasalFallback: $tempBasalFallback")
|
||||||
|
lastAPSResult = null
|
||||||
|
val determineBasalAdapterAMAJS = DetermineBasalAdapterAMAJS(ScriptReader(context), injector)
|
||||||
|
val glucoseStatus = GlucoseStatus(injector).glucoseStatusData
|
||||||
|
val profile = profileFunction.getProfile()
|
||||||
|
val pump = activePlugin.activePump
|
||||||
|
if (profile == null) {
|
||||||
|
rxBus.send(EventOpenAPSUpdateResultGui(resourceHelper.gs(R.string.noprofileselected)))
|
||||||
|
aapsLogger.debug(LTag.APS, resourceHelper.gs(R.string.noprofileselected))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (!isEnabled(PluginType.APS)) {
|
||||||
|
rxBus.send(EventOpenAPSUpdateResultGui(resourceHelper.gs(R.string.openapsma_disabled)))
|
||||||
|
aapsLogger.debug(LTag.APS, resourceHelper.gs(R.string.openapsma_disabled))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (glucoseStatus == null) {
|
||||||
|
rxBus.send(EventOpenAPSUpdateResultGui(resourceHelper.gs(R.string.openapsma_noglucosedata)))
|
||||||
|
aapsLogger.debug(LTag.APS, resourceHelper.gs(R.string.openapsma_noglucosedata))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
val inputConstraints = Constraint(0.0) // fake. only for collecting all results
|
||||||
|
val maxBasal = constraintChecker.getMaxBasalAllowed(profile).also {
|
||||||
|
inputConstraints.copyReasons(it)
|
||||||
|
}.value()
|
||||||
|
var start = System.currentTimeMillis()
|
||||||
|
var startPart = System.currentTimeMillis()
|
||||||
|
val iobArray = iobCobCalculatorPlugin.calculateIobArrayInDia(profile)
|
||||||
|
profiler.log(LTag.APS, "calculateIobArrayInDia()", startPart)
|
||||||
|
startPart = System.currentTimeMillis()
|
||||||
|
val mealData = iobCobCalculatorPlugin.mealData
|
||||||
|
profiler.log(LTag.APS, "getMealData()", startPart)
|
||||||
|
val maxIob = constraintChecker.getMaxIOBAllowed().also { maxIOBAllowedConstraint ->
|
||||||
|
inputConstraints.copyReasons(maxIOBAllowedConstraint)
|
||||||
|
}.value()
|
||||||
|
var minBg = hardLimits.verifyHardLimits(Round.roundTo(profile.targetLowMgdl, 0.1), "minBg", hardLimits.VERY_HARD_LIMIT_MIN_BG[0].toDouble(), hardLimits.VERY_HARD_LIMIT_MIN_BG[1].toDouble())
|
||||||
|
var maxBg = hardLimits.verifyHardLimits(Round.roundTo(profile.targetHighMgdl, 0.1), "maxBg", hardLimits.VERY_HARD_LIMIT_MAX_BG[0].toDouble(), hardLimits.VERY_HARD_LIMIT_MAX_BG[1].toDouble())
|
||||||
|
var targetBg = hardLimits.verifyHardLimits(profile.targetMgdl, "targetBg", hardLimits.VERY_HARD_LIMIT_TARGET_BG[0].toDouble(), hardLimits.VERY_HARD_LIMIT_TARGET_BG[1].toDouble())
|
||||||
|
var isTempTarget = false
|
||||||
|
treatmentsPlugin.getTempTargetFromHistory(System.currentTimeMillis())?.let { tempTarget ->
|
||||||
|
isTempTarget = true
|
||||||
|
minBg = hardLimits.verifyHardLimits(tempTarget.low, "minBg", hardLimits.VERY_HARD_LIMIT_TEMP_MIN_BG[0].toDouble(), hardLimits.VERY_HARD_LIMIT_TEMP_MIN_BG[1].toDouble())
|
||||||
|
maxBg = hardLimits.verifyHardLimits(tempTarget.high, "maxBg", hardLimits.VERY_HARD_LIMIT_TEMP_MAX_BG[0].toDouble(), hardLimits.VERY_HARD_LIMIT_TEMP_MAX_BG[1].toDouble())
|
||||||
|
targetBg = hardLimits.verifyHardLimits(tempTarget.target(), "targetBg", hardLimits.VERY_HARD_LIMIT_TEMP_TARGET_BG[0].toDouble(), hardLimits.VERY_HARD_LIMIT_TEMP_TARGET_BG[1].toDouble())
|
||||||
|
}
|
||||||
|
if (!hardLimits.checkOnlyHardLimits(profile.dia, "dia", hardLimits.minDia(), hardLimits.maxDia())) return
|
||||||
|
if (!hardLimits.checkOnlyHardLimits(profile.getIcTimeFromMidnight(Profile.secondsFromMidnight()), "carbratio", hardLimits.minIC(), hardLimits.maxIC())) return
|
||||||
|
if (!hardLimits.checkOnlyHardLimits(profile.isfMgdl, "sens", hardLimits.MINISF, hardLimits.MAXISF)) return
|
||||||
|
if (!hardLimits.checkOnlyHardLimits(profile.maxDailyBasal, "max_daily_basal", 0.02, hardLimits.maxBasal())) return
|
||||||
|
if (!hardLimits.checkOnlyHardLimits(pump.baseBasalRate, "current_basal", 0.01, hardLimits.maxBasal())) return
|
||||||
|
startPart = System.currentTimeMillis()
|
||||||
|
if (constraintChecker.isAutosensModeEnabled().value()) {
|
||||||
|
val autosensData = iobCobCalculatorPlugin.getLastAutosensDataSynchronized("OpenAPSPlugin")
|
||||||
|
if (autosensData == null) {
|
||||||
|
rxBus.send(EventOpenAPSUpdateResultGui(resourceHelper.gs(R.string.openaps_noasdata)))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
lastAutosensResult = autosensData.autosensResult
|
||||||
|
} else {
|
||||||
|
lastAutosensResult.sensResult = "autosens disabled"
|
||||||
|
}
|
||||||
|
profiler.log(LTag.APS, "detectSensitivityAndCarbAbsorption()", startPart)
|
||||||
|
profiler.log(LTag.APS, "AMA data gathering", start)
|
||||||
|
start = System.currentTimeMillis()
|
||||||
|
try {
|
||||||
|
determineBasalAdapterAMAJS.setData(profile, maxIob, maxBasal, minBg, maxBg, targetBg, activePlugin.activePump.baseBasalRate, iobArray, glucoseStatus, mealData,
|
||||||
|
lastAutosensResult.ratio,
|
||||||
|
isTempTarget
|
||||||
|
)
|
||||||
|
} catch (e: JSONException) {
|
||||||
|
fabricPrivacy.logException(e)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
val determineBasalResultAMA = determineBasalAdapterAMAJS.invoke()
|
||||||
|
profiler.log(LTag.APS, "AMA calculation", start)
|
||||||
|
// Fix bug determine basal
|
||||||
|
if (determineBasalResultAMA == null) {
|
||||||
|
aapsLogger.error(LTag.APS, "SMB calculation returned null")
|
||||||
|
lastDetermineBasalAdapterAMAJS = null
|
||||||
|
lastAPSResult = null
|
||||||
|
lastAPSRun = 0
|
||||||
|
} else {
|
||||||
|
if (determineBasalResultAMA.rate == 0.0 && determineBasalResultAMA.duration == 0 && !treatmentsPlugin.isTempBasalInProgress) determineBasalResultAMA.tempBasalRequested = false
|
||||||
|
determineBasalResultAMA.iob = iobArray[0]
|
||||||
|
val now = System.currentTimeMillis()
|
||||||
|
determineBasalResultAMA.json?.put("timestamp", DateUtil.toISOString(now))
|
||||||
|
determineBasalResultAMA.inputConstraints = inputConstraints
|
||||||
|
lastDetermineBasalAdapterAMAJS = determineBasalAdapterAMAJS
|
||||||
|
lastAPSResult = determineBasalResultAMA
|
||||||
|
lastAPSRun = now
|
||||||
|
}
|
||||||
|
rxBus.send(EventOpenAPSUpdateGui())
|
||||||
|
|
||||||
|
//deviceStatus.suggested = determineBasalResultAMA.json;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,373 +0,0 @@
|
||||||
package info.nightscout.androidaps.plugins.aps.openAPSSMB;
|
|
||||||
|
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
|
|
||||||
import org.json.JSONArray;
|
|
||||||
import org.json.JSONException;
|
|
||||||
import org.json.JSONObject;
|
|
||||||
import org.mozilla.javascript.Context;
|
|
||||||
import org.mozilla.javascript.Function;
|
|
||||||
import org.mozilla.javascript.NativeJSON;
|
|
||||||
import org.mozilla.javascript.NativeObject;
|
|
||||||
import org.mozilla.javascript.RhinoException;
|
|
||||||
import org.mozilla.javascript.Scriptable;
|
|
||||||
import org.mozilla.javascript.ScriptableObject;
|
|
||||||
import org.mozilla.javascript.Undefined;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.lang.reflect.InvocationTargetException;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
|
|
||||||
import javax.inject.Inject;
|
|
||||||
|
|
||||||
import dagger.android.HasAndroidInjector;
|
|
||||||
import info.nightscout.androidaps.Constants;
|
|
||||||
import info.nightscout.androidaps.R;
|
|
||||||
import info.nightscout.androidaps.data.IobTotal;
|
|
||||||
import info.nightscout.androidaps.data.MealData;
|
|
||||||
import info.nightscout.androidaps.data.Profile;
|
|
||||||
import info.nightscout.androidaps.db.TemporaryBasal;
|
|
||||||
import info.nightscout.androidaps.interfaces.ActivePluginProvider;
|
|
||||||
import info.nightscout.androidaps.interfaces.ProfileFunction;
|
|
||||||
import info.nightscout.androidaps.interfaces.PumpInterface;
|
|
||||||
import info.nightscout.androidaps.logging.AAPSLogger;
|
|
||||||
import info.nightscout.androidaps.logging.LTag;
|
|
||||||
import info.nightscout.androidaps.plugins.aps.logger.LoggerCallback;
|
|
||||||
import info.nightscout.androidaps.plugins.aps.loop.ScriptReader;
|
|
||||||
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker;
|
|
||||||
import info.nightscout.androidaps.plugins.general.openhumans.OpenHumansUploader;
|
|
||||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus;
|
|
||||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin;
|
|
||||||
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin;
|
|
||||||
import info.nightscout.androidaps.utils.SafeParse;
|
|
||||||
import info.nightscout.androidaps.utils.resources.ResourceHelper;
|
|
||||||
import info.nightscout.androidaps.utils.sharedPreferences.SP;
|
|
||||||
|
|
||||||
|
|
||||||
public class DetermineBasalAdapterSMBJS {
|
|
||||||
private final HasAndroidInjector injector;
|
|
||||||
@Inject AAPSLogger aapsLogger;
|
|
||||||
@Inject ConstraintChecker constraintChecker;
|
|
||||||
@Inject SP sp;
|
|
||||||
@Inject ResourceHelper resourceHelper;
|
|
||||||
@Inject ProfileFunction profileFunction;
|
|
||||||
@Inject TreatmentsPlugin treatmentsPlugin;
|
|
||||||
@Inject ActivePluginProvider activePluginProvider;
|
|
||||||
@Inject OpenHumansUploader openHumansUploader;
|
|
||||||
|
|
||||||
|
|
||||||
private final ScriptReader mScriptReader;
|
|
||||||
private JSONObject mProfile;
|
|
||||||
private JSONObject mGlucoseStatus;
|
|
||||||
private JSONArray mIobData;
|
|
||||||
private JSONObject mMealData;
|
|
||||||
private JSONObject mCurrentTemp;
|
|
||||||
private JSONObject mAutosensData = null;
|
|
||||||
private boolean mMicrobolusAllowed;
|
|
||||||
private boolean mSMBAlwaysAllowed;
|
|
||||||
private long mCurrentTime;
|
|
||||||
private boolean mIsSaveCgmSource;
|
|
||||||
|
|
||||||
private String storedCurrentTemp = null;
|
|
||||||
private String storedIobData = null;
|
|
||||||
|
|
||||||
private String storedGlucoseStatus = null;
|
|
||||||
private String storedProfile = null;
|
|
||||||
private String storedMeal_data = null;
|
|
||||||
|
|
||||||
private String scriptDebug = "";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Main code
|
|
||||||
*/
|
|
||||||
|
|
||||||
DetermineBasalAdapterSMBJS(ScriptReader scriptReader, HasAndroidInjector injector) {
|
|
||||||
mScriptReader = scriptReader;
|
|
||||||
this.injector = injector;
|
|
||||||
injector.androidInjector().inject(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
public DetermineBasalResultSMB invoke() {
|
|
||||||
|
|
||||||
|
|
||||||
aapsLogger.debug(LTag.APS, ">>> Invoking detemine_basal <<<");
|
|
||||||
aapsLogger.debug(LTag.APS, "Glucose status: " + (storedGlucoseStatus = mGlucoseStatus.toString()));
|
|
||||||
aapsLogger.debug(LTag.APS, "IOB data: " + (storedIobData = mIobData.toString()));
|
|
||||||
aapsLogger.debug(LTag.APS, "Current temp: " + (storedCurrentTemp = mCurrentTemp.toString()));
|
|
||||||
aapsLogger.debug(LTag.APS, "Profile: " + (storedProfile = mProfile.toString()));
|
|
||||||
aapsLogger.debug(LTag.APS, "Meal data: " + (storedMeal_data = mMealData.toString()));
|
|
||||||
if (mAutosensData != null)
|
|
||||||
aapsLogger.debug(LTag.APS, "Autosens data: " + mAutosensData.toString());
|
|
||||||
else
|
|
||||||
aapsLogger.debug(LTag.APS, "Autosens data: " + "undefined");
|
|
||||||
aapsLogger.debug(LTag.APS, "Reservoir data: " + "undefined");
|
|
||||||
aapsLogger.debug(LTag.APS, "MicroBolusAllowed: " + mMicrobolusAllowed);
|
|
||||||
aapsLogger.debug(LTag.APS, "SMBAlwaysAllowed: " + mSMBAlwaysAllowed);
|
|
||||||
aapsLogger.debug(LTag.APS, "CurrentTime: " + mCurrentTime);
|
|
||||||
aapsLogger.debug(LTag.APS, "isSaveCgmSource: " + mIsSaveCgmSource);
|
|
||||||
|
|
||||||
|
|
||||||
DetermineBasalResultSMB determineBasalResultSMB = null;
|
|
||||||
|
|
||||||
Context rhino = Context.enter();
|
|
||||||
Scriptable scope = rhino.initStandardObjects();
|
|
||||||
// Turn off optimization to make Rhino Android compatible
|
|
||||||
rhino.setOptimizationLevel(-1);
|
|
||||||
|
|
||||||
try {
|
|
||||||
|
|
||||||
//register logger callback for console.log and console.error
|
|
||||||
ScriptableObject.defineClass(scope, LoggerCallback.class);
|
|
||||||
Scriptable myLogger = rhino.newObject(scope, "LoggerCallback", null);
|
|
||||||
scope.put("console2", scope, myLogger);
|
|
||||||
rhino.evaluateString(scope, readFile("OpenAPSAMA/loggerhelper.js"), "JavaScript", 0, null);
|
|
||||||
|
|
||||||
//set module parent
|
|
||||||
rhino.evaluateString(scope, "var module = {\"parent\":Boolean(1)};", "JavaScript", 0, null);
|
|
||||||
rhino.evaluateString(scope, "var round_basal = function round_basal(basal, profile) { return basal; };", "JavaScript", 0, null);
|
|
||||||
rhino.evaluateString(scope, "require = function() {return round_basal;};", "JavaScript", 0, null);
|
|
||||||
|
|
||||||
//generate functions "determine_basal" and "setTempBasal"
|
|
||||||
rhino.evaluateString(scope, readFile("OpenAPSSMB/determine-basal.js"), "JavaScript", 0, null);
|
|
||||||
rhino.evaluateString(scope, readFile("OpenAPSSMB/basal-set-temp.js"), "setTempBasal.js", 0, null);
|
|
||||||
Object determineBasalObj = scope.get("determine_basal", scope);
|
|
||||||
Object setTempBasalFunctionsObj = scope.get("tempBasalFunctions", scope);
|
|
||||||
|
|
||||||
//call determine-basal
|
|
||||||
if (determineBasalObj instanceof Function && setTempBasalFunctionsObj instanceof NativeObject) {
|
|
||||||
Function determineBasalJS = (Function) determineBasalObj;
|
|
||||||
|
|
||||||
//prepare parameters
|
|
||||||
Object[] params = new Object[]{
|
|
||||||
makeParam(mGlucoseStatus, rhino, scope),
|
|
||||||
makeParam(mCurrentTemp, rhino, scope),
|
|
||||||
makeParamArray(mIobData, rhino, scope),
|
|
||||||
makeParam(mProfile, rhino, scope),
|
|
||||||
makeParam(mAutosensData, rhino, scope),
|
|
||||||
makeParam(mMealData, rhino, scope),
|
|
||||||
setTempBasalFunctionsObj,
|
|
||||||
Boolean.valueOf(mMicrobolusAllowed),
|
|
||||||
makeParam(null, rhino, scope), // reservoir data as undefined
|
|
||||||
Long.valueOf(mCurrentTime),
|
|
||||||
Boolean.valueOf(mIsSaveCgmSource)
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
NativeObject jsResult = (NativeObject) determineBasalJS.call(rhino, scope, scope, params);
|
|
||||||
scriptDebug = LoggerCallback.getScriptDebug();
|
|
||||||
|
|
||||||
// Parse the jsResult object to a JSON-String
|
|
||||||
String result = NativeJSON.stringify(rhino, scope, jsResult, null, null).toString();
|
|
||||||
aapsLogger.debug(LTag.APS, "Result: " + result);
|
|
||||||
try {
|
|
||||||
JSONObject resultJson = new JSONObject(result);
|
|
||||||
openHumansUploader.enqueueSMBData(mProfile, mGlucoseStatus, mIobData, mMealData, mCurrentTemp, mAutosensData, mMicrobolusAllowed, mSMBAlwaysAllowed, resultJson);
|
|
||||||
determineBasalResultSMB = new DetermineBasalResultSMB(injector, resultJson);
|
|
||||||
} catch (JSONException e) {
|
|
||||||
aapsLogger.error(LTag.APS, "Unhandled exception", e);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
aapsLogger.error(LTag.APS, "Problem loading JS Functions");
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
aapsLogger.error(LTag.APS, "IOException");
|
|
||||||
} catch (RhinoException e) {
|
|
||||||
aapsLogger.error(LTag.APS, "RhinoException: (" + e.lineNumber() + "," + e.columnNumber() + ") " + e.toString());
|
|
||||||
} catch (IllegalAccessException | InstantiationException | InvocationTargetException e) {
|
|
||||||
aapsLogger.error(LTag.APS, e.toString());
|
|
||||||
} finally {
|
|
||||||
Context.exit();
|
|
||||||
}
|
|
||||||
|
|
||||||
storedGlucoseStatus = mGlucoseStatus.toString();
|
|
||||||
storedIobData = mIobData.toString();
|
|
||||||
storedCurrentTemp = mCurrentTemp.toString();
|
|
||||||
storedProfile = mProfile.toString();
|
|
||||||
storedMeal_data = mMealData.toString();
|
|
||||||
|
|
||||||
return determineBasalResultSMB;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
String getGlucoseStatusParam() {
|
|
||||||
return storedGlucoseStatus;
|
|
||||||
}
|
|
||||||
|
|
||||||
String getCurrentTempParam() {
|
|
||||||
return storedCurrentTemp;
|
|
||||||
}
|
|
||||||
|
|
||||||
String getIobDataParam() {
|
|
||||||
return storedIobData;
|
|
||||||
}
|
|
||||||
|
|
||||||
String getProfileParam() {
|
|
||||||
return storedProfile;
|
|
||||||
}
|
|
||||||
|
|
||||||
String getMealDataParam() {
|
|
||||||
return storedMeal_data;
|
|
||||||
}
|
|
||||||
|
|
||||||
String getScriptDebug() {
|
|
||||||
return scriptDebug;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setData(Profile profile,
|
|
||||||
double maxIob,
|
|
||||||
double maxBasal,
|
|
||||||
double minBg,
|
|
||||||
double maxBg,
|
|
||||||
double targetBg,
|
|
||||||
double basalrate,
|
|
||||||
IobTotal[] iobArray,
|
|
||||||
GlucoseStatus glucoseStatus,
|
|
||||||
MealData mealData,
|
|
||||||
double autosensDataRatio,
|
|
||||||
boolean tempTargetSet,
|
|
||||||
boolean microBolusAllowed,
|
|
||||||
boolean uamAllowed,
|
|
||||||
boolean advancedFiltering,
|
|
||||||
boolean isSaveCgmSource
|
|
||||||
) throws JSONException {
|
|
||||||
|
|
||||||
PumpInterface pump = activePluginProvider.getActivePump();
|
|
||||||
Double pumpbolusstep = pump.getPumpDescription().bolusStep;
|
|
||||||
mProfile = new JSONObject();
|
|
||||||
|
|
||||||
mProfile.put("max_iob", maxIob);
|
|
||||||
//mProfile.put("dia", profile.getDia());
|
|
||||||
mProfile.put("type", "current");
|
|
||||||
mProfile.put("max_daily_basal", profile.getMaxDailyBasal());
|
|
||||||
mProfile.put("max_basal", maxBasal);
|
|
||||||
mProfile.put("min_bg", minBg);
|
|
||||||
mProfile.put("max_bg", maxBg);
|
|
||||||
mProfile.put("target_bg", targetBg);
|
|
||||||
mProfile.put("carb_ratio", profile.getIc());
|
|
||||||
mProfile.put("sens", profile.getIsfMgdl());
|
|
||||||
mProfile.put("max_daily_safety_multiplier", sp.getInt(R.string.key_openapsama_max_daily_safety_multiplier, 3));
|
|
||||||
mProfile.put("current_basal_safety_multiplier", sp.getDouble(R.string.key_openapsama_current_basal_safety_multiplier, 4d));
|
|
||||||
|
|
||||||
//mProfile.put("high_temptarget_raises_sensitivity", SP.getBoolean(R.string.key_high_temptarget_raises_sensitivity, SMBDefaults.high_temptarget_raises_sensitivity));
|
|
||||||
mProfile.put("high_temptarget_raises_sensitivity", false);
|
|
||||||
//mProfile.put("low_temptarget_lowers_sensitivity", SP.getBoolean(R.string.key_low_temptarget_lowers_sensitivity, SMBDefaults.low_temptarget_lowers_sensitivity));
|
|
||||||
mProfile.put("low_temptarget_lowers_sensitivity", false);
|
|
||||||
|
|
||||||
|
|
||||||
mProfile.put("sensitivity_raises_target", sp.getBoolean(R.string.key_sensitivity_raises_target, SMBDefaults.sensitivity_raises_target));
|
|
||||||
mProfile.put("resistance_lowers_target", sp.getBoolean(R.string.key_resistance_lowers_target, SMBDefaults.resistance_lowers_target));
|
|
||||||
mProfile.put("adv_target_adjustments", SMBDefaults.adv_target_adjustments);
|
|
||||||
mProfile.put("exercise_mode", SMBDefaults.exercise_mode);
|
|
||||||
mProfile.put("half_basal_exercise_target", SMBDefaults.half_basal_exercise_target);
|
|
||||||
mProfile.put("maxCOB", SMBDefaults.maxCOB);
|
|
||||||
mProfile.put("skip_neutral_temps", pump.setNeutralTempAtFullHour());
|
|
||||||
// min_5m_carbimpact is not used within SMB determinebasal
|
|
||||||
//if (mealData.usedMinCarbsImpact > 0) {
|
|
||||||
// mProfile.put("min_5m_carbimpact", mealData.usedMinCarbsImpact);
|
|
||||||
//} else {
|
|
||||||
// mProfile.put("min_5m_carbimpact", SP.getDouble(R.string.key_openapsama_min_5m_carbimpact, SMBDefaults.min_5m_carbimpact));
|
|
||||||
//}
|
|
||||||
mProfile.put("remainingCarbsCap", SMBDefaults.remainingCarbsCap);
|
|
||||||
mProfile.put("enableUAM", uamAllowed);
|
|
||||||
mProfile.put("A52_risk_enable", SMBDefaults.A52_risk_enable);
|
|
||||||
|
|
||||||
boolean smbEnabled = sp.getBoolean(R.string.key_use_smb, false);
|
|
||||||
mProfile.put("SMBInterval", sp.getInt(R.string.key_smbinterval, SMBDefaults.SMBInterval));
|
|
||||||
mProfile.put("enableSMB_with_COB", smbEnabled && sp.getBoolean(R.string.key_enableSMB_with_COB, false));
|
|
||||||
mProfile.put("enableSMB_with_temptarget", smbEnabled && sp.getBoolean(R.string.key_enableSMB_with_temptarget, false));
|
|
||||||
mProfile.put("allowSMB_with_high_temptarget", smbEnabled && sp.getBoolean(R.string.key_allowSMB_with_high_temptarget, false));
|
|
||||||
mProfile.put("enableSMB_always", smbEnabled && sp.getBoolean(R.string.key_enableSMB_always, false) && advancedFiltering);
|
|
||||||
mProfile.put("enableSMB_after_carbs", smbEnabled && sp.getBoolean(R.string.key_enableSMB_after_carbs, false) && advancedFiltering);
|
|
||||||
mProfile.put("maxSMBBasalMinutes", sp.getInt(R.string.key_smbmaxminutes, SMBDefaults.maxSMBBasalMinutes));
|
|
||||||
mProfile.put("maxUAMSMBBasalMinutes", sp.getInt(R.string.key_uamsmbmaxminutes, SMBDefaults.maxUAMSMBBasalMinutes));
|
|
||||||
//set the min SMB amount to be the amount set by the pump.
|
|
||||||
mProfile.put("bolus_increment", pumpbolusstep);
|
|
||||||
mProfile.put("carbsReqThreshold", sp.getInt(R.string.key_carbsReqThreshold, SMBDefaults.carbsReqThreshold));
|
|
||||||
|
|
||||||
mProfile.put("current_basal", basalrate);
|
|
||||||
mProfile.put("temptargetSet", tempTargetSet);
|
|
||||||
mProfile.put("autosens_max", SafeParse.stringToDouble(sp.getString(R.string.key_openapsama_autosens_max, "1.2")));
|
|
||||||
|
|
||||||
if (profileFunction.getUnits().equals(Constants.MMOL)) {
|
|
||||||
mProfile.put("out_units", "mmol/L");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
long now = System.currentTimeMillis();
|
|
||||||
TemporaryBasal tb = treatmentsPlugin.getTempBasalFromHistory(now);
|
|
||||||
|
|
||||||
mCurrentTemp = new JSONObject();
|
|
||||||
mCurrentTemp.put("temp", "absolute");
|
|
||||||
mCurrentTemp.put("duration", tb != null ? tb.getPlannedRemainingMinutes() : 0);
|
|
||||||
mCurrentTemp.put("rate", tb != null ? tb.tempBasalConvertedToAbsolute(now, profile) : 0d);
|
|
||||||
|
|
||||||
// as we have non default temps longer than 30 mintues
|
|
||||||
TemporaryBasal tempBasal = treatmentsPlugin.getTempBasalFromHistory(System.currentTimeMillis());
|
|
||||||
if (tempBasal != null) {
|
|
||||||
mCurrentTemp.put("minutesrunning", tempBasal.getRealDuration());
|
|
||||||
}
|
|
||||||
|
|
||||||
mIobData = IobCobCalculatorPlugin.convertToJSONArray(iobArray);
|
|
||||||
|
|
||||||
mGlucoseStatus = new JSONObject();
|
|
||||||
mGlucoseStatus.put("glucose", glucoseStatus.glucose);
|
|
||||||
mGlucoseStatus.put("noise", glucoseStatus.noise);
|
|
||||||
|
|
||||||
if (sp.getBoolean(R.string.key_always_use_shortavg, false)) {
|
|
||||||
mGlucoseStatus.put("delta", glucoseStatus.short_avgdelta);
|
|
||||||
} else {
|
|
||||||
mGlucoseStatus.put("delta", glucoseStatus.delta);
|
|
||||||
}
|
|
||||||
mGlucoseStatus.put("short_avgdelta", glucoseStatus.short_avgdelta);
|
|
||||||
mGlucoseStatus.put("long_avgdelta", glucoseStatus.long_avgdelta);
|
|
||||||
mGlucoseStatus.put("date", glucoseStatus.date);
|
|
||||||
|
|
||||||
mMealData = new JSONObject();
|
|
||||||
mMealData.put("carbs", mealData.carbs);
|
|
||||||
mMealData.put("boluses", mealData.boluses);
|
|
||||||
mMealData.put("mealCOB", mealData.mealCOB);
|
|
||||||
mMealData.put("slopeFromMaxDeviation", mealData.slopeFromMaxDeviation);
|
|
||||||
mMealData.put("slopeFromMinDeviation", mealData.slopeFromMinDeviation);
|
|
||||||
mMealData.put("lastBolusTime", mealData.lastBolusTime);
|
|
||||||
mMealData.put("lastCarbTime", mealData.lastCarbTime);
|
|
||||||
|
|
||||||
|
|
||||||
if (constraintChecker.isAutosensModeEnabled().value()) {
|
|
||||||
mAutosensData = new JSONObject();
|
|
||||||
mAutosensData.put("ratio", autosensDataRatio);
|
|
||||||
} else {
|
|
||||||
mAutosensData = new JSONObject();
|
|
||||||
mAutosensData.put("ratio", 1.0);
|
|
||||||
}
|
|
||||||
mMicrobolusAllowed = microBolusAllowed;
|
|
||||||
mSMBAlwaysAllowed = advancedFiltering;
|
|
||||||
|
|
||||||
mCurrentTime = now;
|
|
||||||
|
|
||||||
mIsSaveCgmSource = isSaveCgmSource;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Object makeParam(JSONObject jsonObject, Context rhino, Scriptable scope) {
|
|
||||||
|
|
||||||
if (jsonObject == null) return Undefined.instance;
|
|
||||||
|
|
||||||
return NativeJSON.parse(rhino, scope, jsonObject.toString(), (context, scriptable, scriptable1, objects) -> objects[1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
private Object makeParamArray(JSONArray jsonArray, Context rhino, Scriptable scope) {
|
|
||||||
//Object param = NativeJSON.parse(rhino, scope, "{myarray: " + jsonArray.toString() + " }", new Callable() {
|
|
||||||
return NativeJSON.parse(rhino, scope, jsonArray.toString(), (context, scriptable, scriptable1, objects) -> objects[1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
private String readFile(String filename) throws IOException {
|
|
||||||
byte[] bytes = mScriptReader.readFile(filename);
|
|
||||||
String string = new String(bytes, StandardCharsets.UTF_8);
|
|
||||||
if (string.startsWith("#!/usr/bin/env node")) {
|
|
||||||
string = string.substring(20);
|
|
||||||
}
|
|
||||||
return string;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -0,0 +1,290 @@
|
||||||
|
package info.nightscout.androidaps.plugins.aps.openAPSSMB
|
||||||
|
|
||||||
|
import dagger.android.HasAndroidInjector
|
||||||
|
import info.nightscout.androidaps.Constants
|
||||||
|
import info.nightscout.androidaps.R
|
||||||
|
import info.nightscout.androidaps.data.IobTotal
|
||||||
|
import info.nightscout.androidaps.data.MealData
|
||||||
|
import info.nightscout.androidaps.data.Profile
|
||||||
|
import info.nightscout.androidaps.interfaces.ActivePluginProvider
|
||||||
|
import info.nightscout.androidaps.interfaces.ProfileFunction
|
||||||
|
import info.nightscout.androidaps.logging.AAPSLogger
|
||||||
|
import info.nightscout.androidaps.logging.LTag
|
||||||
|
import info.nightscout.androidaps.plugins.aps.logger.LoggerCallback
|
||||||
|
import info.nightscout.androidaps.plugins.aps.loop.ScriptReader
|
||||||
|
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
|
||||||
|
import info.nightscout.androidaps.plugins.general.openhumans.OpenHumansUploader
|
||||||
|
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus
|
||||||
|
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin
|
||||||
|
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin
|
||||||
|
import info.nightscout.androidaps.utils.SafeParse
|
||||||
|
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||||
|
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
||||||
|
import org.json.JSONArray
|
||||||
|
import org.json.JSONException
|
||||||
|
import org.json.JSONObject
|
||||||
|
import org.mozilla.javascript.*
|
||||||
|
import org.mozilla.javascript.Function
|
||||||
|
import java.io.IOException
|
||||||
|
import java.lang.reflect.InvocationTargetException
|
||||||
|
import java.nio.charset.StandardCharsets
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class DetermineBasalAdapterSMBJS internal constructor(private val scriptReader: ScriptReader, private val injector: HasAndroidInjector) {
|
||||||
|
|
||||||
|
@Inject lateinit var aapsLogger: AAPSLogger
|
||||||
|
@Inject lateinit var constraintChecker: ConstraintChecker
|
||||||
|
@Inject lateinit var sp: SP
|
||||||
|
@Inject lateinit var resourceHelper: ResourceHelper
|
||||||
|
@Inject lateinit var profileFunction: ProfileFunction
|
||||||
|
@Inject lateinit var treatmentsPlugin: TreatmentsPlugin
|
||||||
|
@Inject lateinit var activePluginProvider: ActivePluginProvider
|
||||||
|
@Inject lateinit var openHumansUploader: OpenHumansUploader
|
||||||
|
|
||||||
|
private var profile = JSONObject()
|
||||||
|
private var mGlucoseStatus = JSONObject()
|
||||||
|
private var iobData: JSONArray? = null
|
||||||
|
private var mealData = JSONObject()
|
||||||
|
private var currentTemp = JSONObject()
|
||||||
|
private var autosensData = JSONObject()
|
||||||
|
private var microBolusAllowed = false
|
||||||
|
private var smbAlwaysAllowed = false
|
||||||
|
private var currentTime: Long = 0
|
||||||
|
private var saveCgmSource = false
|
||||||
|
var currentTempParam: String? = null
|
||||||
|
private set
|
||||||
|
var iobDataParam: String? = null
|
||||||
|
private set
|
||||||
|
var glucoseStatusParam: String? = null
|
||||||
|
private set
|
||||||
|
var profileParam: String? = null
|
||||||
|
private set
|
||||||
|
var mealDataParam: String? = null
|
||||||
|
private set
|
||||||
|
var scriptDebug = ""
|
||||||
|
private set
|
||||||
|
|
||||||
|
@Suppress("SpellCheckingInspection")
|
||||||
|
operator fun invoke(): DetermineBasalResultSMB? {
|
||||||
|
aapsLogger.debug(LTag.APS, ">>> Invoking determine_basal <<<")
|
||||||
|
aapsLogger.debug(LTag.APS, "Glucose status: " + mGlucoseStatus.toString().also { glucoseStatusParam = it })
|
||||||
|
aapsLogger.debug(LTag.APS, "IOB data: " + iobData.toString().also { iobDataParam = it })
|
||||||
|
aapsLogger.debug(LTag.APS, "Current temp: " + currentTemp.toString().also { currentTempParam = it })
|
||||||
|
aapsLogger.debug(LTag.APS, "Profile: " + profile.toString().also { profileParam = it })
|
||||||
|
aapsLogger.debug(LTag.APS, "Meal data: " + mealData.toString().also { mealDataParam = it })
|
||||||
|
aapsLogger.debug(LTag.APS, "Autosens data: $autosensData")
|
||||||
|
aapsLogger.debug(LTag.APS, "Reservoir data: " + "undefined")
|
||||||
|
aapsLogger.debug(LTag.APS, "MicroBolusAllowed: $microBolusAllowed")
|
||||||
|
aapsLogger.debug(LTag.APS, "SMBAlwaysAllowed: $smbAlwaysAllowed")
|
||||||
|
aapsLogger.debug(LTag.APS, "CurrentTime: $currentTime")
|
||||||
|
aapsLogger.debug(LTag.APS, "isSaveCgmSource: $saveCgmSource")
|
||||||
|
var determineBasalResultSMB: DetermineBasalResultSMB? = null
|
||||||
|
val rhino = Context.enter()
|
||||||
|
val scope: Scriptable = rhino.initStandardObjects()
|
||||||
|
// Turn off optimization to make Rhino Android compatible
|
||||||
|
rhino.optimizationLevel = -1
|
||||||
|
try {
|
||||||
|
|
||||||
|
//register logger callback for console.log and console.error
|
||||||
|
ScriptableObject.defineClass(scope, LoggerCallback::class.java)
|
||||||
|
val myLogger = rhino.newObject(scope, "LoggerCallback", null)
|
||||||
|
scope.put("console2", scope, myLogger)
|
||||||
|
rhino.evaluateString(scope, readFile("OpenAPSAMA/loggerhelper.js"), "JavaScript", 0, null)
|
||||||
|
|
||||||
|
//set module parent
|
||||||
|
rhino.evaluateString(scope, "var module = {\"parent\":Boolean(1)};", "JavaScript", 0, null)
|
||||||
|
rhino.evaluateString(scope, "var round_basal = function round_basal(basal, profile) { return basal; };", "JavaScript", 0, null)
|
||||||
|
rhino.evaluateString(scope, "require = function() {return round_basal;};", "JavaScript", 0, null)
|
||||||
|
|
||||||
|
//generate functions "determine_basal" and "setTempBasal"
|
||||||
|
rhino.evaluateString(scope, readFile("OpenAPSSMB/determine-basal.js"), "JavaScript", 0, null)
|
||||||
|
rhino.evaluateString(scope, readFile("OpenAPSSMB/basal-set-temp.js"), "setTempBasal.js", 0, null)
|
||||||
|
val determineBasalObj = scope["determine_basal", scope]
|
||||||
|
val setTempBasalFunctionsObj = scope["tempBasalFunctions", scope]
|
||||||
|
|
||||||
|
//call determine-basal
|
||||||
|
if (determineBasalObj is Function && setTempBasalFunctionsObj is NativeObject) {
|
||||||
|
|
||||||
|
//prepare parameters
|
||||||
|
val params = arrayOf(
|
||||||
|
makeParam(mGlucoseStatus, rhino, scope),
|
||||||
|
makeParam(currentTemp, rhino, scope),
|
||||||
|
makeParamArray(iobData, rhino, scope),
|
||||||
|
makeParam(profile, rhino, scope),
|
||||||
|
makeParam(autosensData, rhino, scope),
|
||||||
|
makeParam(mealData, rhino, scope),
|
||||||
|
setTempBasalFunctionsObj,
|
||||||
|
java.lang.Boolean.valueOf(microBolusAllowed),
|
||||||
|
makeParam(null, rhino, scope), // reservoir data as undefined
|
||||||
|
java.lang.Long.valueOf(currentTime),
|
||||||
|
java.lang.Boolean.valueOf(saveCgmSource)
|
||||||
|
)
|
||||||
|
val jsResult = determineBasalObj.call(rhino, scope, scope, params) as NativeObject
|
||||||
|
scriptDebug = LoggerCallback.scriptDebug
|
||||||
|
|
||||||
|
// Parse the jsResult object to a JSON-String
|
||||||
|
val result = NativeJSON.stringify(rhino, scope, jsResult, null, null).toString()
|
||||||
|
aapsLogger.debug(LTag.APS, "Result: $result")
|
||||||
|
try {
|
||||||
|
val resultJson = JSONObject(result)
|
||||||
|
openHumansUploader.enqueueSMBData(profile, mGlucoseStatus, iobData, mealData, currentTemp, autosensData, microBolusAllowed, smbAlwaysAllowed, resultJson)
|
||||||
|
determineBasalResultSMB = DetermineBasalResultSMB(injector, resultJson)
|
||||||
|
} catch (e: JSONException) {
|
||||||
|
aapsLogger.error(LTag.APS, "Unhandled exception", e)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
aapsLogger.error(LTag.APS, "Problem loading JS Functions")
|
||||||
|
}
|
||||||
|
} catch (e: IOException) {
|
||||||
|
aapsLogger.error(LTag.APS, "IOException")
|
||||||
|
} catch (e: RhinoException) {
|
||||||
|
aapsLogger.error(LTag.APS, "RhinoException: (" + e.lineNumber() + "," + e.columnNumber() + ") " + e.toString())
|
||||||
|
} catch (e: IllegalAccessException) {
|
||||||
|
aapsLogger.error(LTag.APS, e.toString())
|
||||||
|
} catch (e: InstantiationException) {
|
||||||
|
aapsLogger.error(LTag.APS, e.toString())
|
||||||
|
} catch (e: InvocationTargetException) {
|
||||||
|
aapsLogger.error(LTag.APS, e.toString())
|
||||||
|
} finally {
|
||||||
|
Context.exit()
|
||||||
|
}
|
||||||
|
glucoseStatusParam = mGlucoseStatus.toString()
|
||||||
|
iobDataParam = iobData.toString()
|
||||||
|
currentTempParam = currentTemp.toString()
|
||||||
|
profileParam = profile.toString()
|
||||||
|
mealDataParam = mealData.toString()
|
||||||
|
return determineBasalResultSMB
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("SpellCheckingInspection") fun setData(profile: Profile,
|
||||||
|
maxIob: Double,
|
||||||
|
maxBasal: Double,
|
||||||
|
minBg: Double,
|
||||||
|
maxBg: Double,
|
||||||
|
targetBg: Double,
|
||||||
|
basalRate: Double,
|
||||||
|
iobArray: Array<IobTotal>,
|
||||||
|
glucoseStatus: GlucoseStatus,
|
||||||
|
mealData: MealData,
|
||||||
|
autosensDataRatio: Double,
|
||||||
|
tempTargetSet: Boolean,
|
||||||
|
microBolusAllowed: Boolean,
|
||||||
|
uamAllowed: Boolean,
|
||||||
|
advancedFiltering: Boolean,
|
||||||
|
isSaveCgmSource: Boolean
|
||||||
|
) {
|
||||||
|
val pump = activePluginProvider.activePump
|
||||||
|
val pumpBolusStep = pump.pumpDescription.bolusStep
|
||||||
|
this.profile.put("max_iob", maxIob)
|
||||||
|
//mProfile.put("dia", profile.getDia());
|
||||||
|
this.profile.put("type", "current")
|
||||||
|
this.profile.put("max_daily_basal", profile.maxDailyBasal)
|
||||||
|
this.profile.put("max_basal", maxBasal)
|
||||||
|
this.profile.put("min_bg", minBg)
|
||||||
|
this.profile.put("max_bg", maxBg)
|
||||||
|
this.profile.put("target_bg", targetBg)
|
||||||
|
this.profile.put("carb_ratio", profile.ic)
|
||||||
|
this.profile.put("sens", profile.isfMgdl)
|
||||||
|
this.profile.put("max_daily_safety_multiplier", sp.getInt(R.string.key_openapsama_max_daily_safety_multiplier, 3))
|
||||||
|
this.profile.put("current_basal_safety_multiplier", sp.getDouble(R.string.key_openapsama_current_basal_safety_multiplier, 4.0))
|
||||||
|
|
||||||
|
//mProfile.put("high_temptarget_raises_sensitivity", SP.getBoolean(R.string.key_high_temptarget_raises_sensitivity, SMBDefaults.high_temptarget_raises_sensitivity));
|
||||||
|
this.profile.put("high_temptarget_raises_sensitivity", false)
|
||||||
|
//mProfile.put("low_temptarget_lowers_sensitivity", SP.getBoolean(R.string.key_low_temptarget_lowers_sensitivity, SMBDefaults.low_temptarget_lowers_sensitivity));
|
||||||
|
this.profile.put("low_temptarget_lowers_sensitivity", false)
|
||||||
|
this.profile.put("sensitivity_raises_target", sp.getBoolean(R.string.key_sensitivity_raises_target, SMBDefaults.sensitivity_raises_target))
|
||||||
|
this.profile.put("resistance_lowers_target", sp.getBoolean(R.string.key_resistance_lowers_target, SMBDefaults.resistance_lowers_target))
|
||||||
|
this.profile.put("adv_target_adjustments", SMBDefaults.adv_target_adjustments)
|
||||||
|
this.profile.put("exercise_mode", SMBDefaults.exercise_mode)
|
||||||
|
this.profile.put("half_basal_exercise_target", SMBDefaults.half_basal_exercise_target)
|
||||||
|
this.profile.put("maxCOB", SMBDefaults.maxCOB)
|
||||||
|
this.profile.put("skip_neutral_temps", pump.setNeutralTempAtFullHour())
|
||||||
|
// min_5m_carbimpact is not used within SMB determinebasal
|
||||||
|
//if (mealData.usedMinCarbsImpact > 0) {
|
||||||
|
// mProfile.put("min_5m_carbimpact", mealData.usedMinCarbsImpact);
|
||||||
|
//} else {
|
||||||
|
// mProfile.put("min_5m_carbimpact", SP.getDouble(R.string.key_openapsama_min_5m_carbimpact, SMBDefaults.min_5m_carbimpact));
|
||||||
|
//}
|
||||||
|
this.profile.put("remainingCarbsCap", SMBDefaults.remainingCarbsCap)
|
||||||
|
this.profile.put("enableUAM", uamAllowed)
|
||||||
|
this.profile.put("A52_risk_enable", SMBDefaults.A52_risk_enable)
|
||||||
|
val smbEnabled = sp.getBoolean(R.string.key_use_smb, false)
|
||||||
|
this.profile.put("SMBInterval", sp.getInt(R.string.key_smbinterval, SMBDefaults.SMBInterval))
|
||||||
|
this.profile.put("enableSMB_with_COB", smbEnabled && sp.getBoolean(R.string.key_enableSMB_with_COB, false))
|
||||||
|
this.profile.put("enableSMB_with_temptarget", smbEnabled && sp.getBoolean(R.string.key_enableSMB_with_temptarget, false))
|
||||||
|
this.profile.put("allowSMB_with_high_temptarget", smbEnabled && sp.getBoolean(R.string.key_allowSMB_with_high_temptarget, false))
|
||||||
|
this.profile.put("enableSMB_always", smbEnabled && sp.getBoolean(R.string.key_enableSMB_always, false) && advancedFiltering)
|
||||||
|
this.profile.put("enableSMB_after_carbs", smbEnabled && sp.getBoolean(R.string.key_enableSMB_after_carbs, false) && advancedFiltering)
|
||||||
|
this.profile.put("maxSMBBasalMinutes", sp.getInt(R.string.key_smbmaxminutes, SMBDefaults.maxSMBBasalMinutes))
|
||||||
|
this.profile.put("maxUAMSMBBasalMinutes", sp.getInt(R.string.key_uamsmbmaxminutes, SMBDefaults.maxUAMSMBBasalMinutes))
|
||||||
|
//set the min SMB amount to be the amount set by the pump.
|
||||||
|
this.profile.put("bolus_increment", pumpBolusStep)
|
||||||
|
this.profile.put("carbsReqThreshold", sp.getInt(R.string.key_carbsReqThreshold, SMBDefaults.carbsReqThreshold))
|
||||||
|
this.profile.put("current_basal", basalRate)
|
||||||
|
this.profile.put("temptargetSet", tempTargetSet)
|
||||||
|
this.profile.put("autosens_max", SafeParse.stringToDouble(sp.getString(R.string.key_openapsama_autosens_max, "1.2")))
|
||||||
|
if (profileFunction.getUnits() == Constants.MMOL) {
|
||||||
|
this.profile.put("out_units", "mmol/L")
|
||||||
|
}
|
||||||
|
val now = System.currentTimeMillis()
|
||||||
|
val tb = treatmentsPlugin.getTempBasalFromHistory(now)
|
||||||
|
currentTemp.put("temp", "absolute")
|
||||||
|
currentTemp.put("duration", tb?.plannedRemainingMinutes ?: 0)
|
||||||
|
currentTemp.put("rate", tb?.tempBasalConvertedToAbsolute(now, profile) ?: 0.0)
|
||||||
|
|
||||||
|
// as we have non default temps longer than 30 mintues
|
||||||
|
val tempBasal = treatmentsPlugin.getTempBasalFromHistory(System.currentTimeMillis())
|
||||||
|
if (tempBasal != null) {
|
||||||
|
currentTemp.put("minutesrunning", tempBasal.realDuration)
|
||||||
|
}
|
||||||
|
iobData = IobCobCalculatorPlugin.convertToJSONArray(iobArray)
|
||||||
|
mGlucoseStatus.put("glucose", glucoseStatus.glucose)
|
||||||
|
mGlucoseStatus.put("noise", glucoseStatus.noise)
|
||||||
|
if (sp.getBoolean(R.string.key_always_use_shortavg, false)) {
|
||||||
|
mGlucoseStatus.put("delta", glucoseStatus.short_avgdelta)
|
||||||
|
} else {
|
||||||
|
mGlucoseStatus.put("delta", glucoseStatus.delta)
|
||||||
|
}
|
||||||
|
mGlucoseStatus.put("short_avgdelta", glucoseStatus.short_avgdelta)
|
||||||
|
mGlucoseStatus.put("long_avgdelta", glucoseStatus.long_avgdelta)
|
||||||
|
mGlucoseStatus.put("date", glucoseStatus.date)
|
||||||
|
this.mealData.put("carbs", mealData.carbs)
|
||||||
|
this.mealData.put("boluses", mealData.boluses)
|
||||||
|
this.mealData.put("mealCOB", mealData.mealCOB)
|
||||||
|
this.mealData.put("slopeFromMaxDeviation", mealData.slopeFromMaxDeviation)
|
||||||
|
this.mealData.put("slopeFromMinDeviation", mealData.slopeFromMinDeviation)
|
||||||
|
this.mealData.put("lastBolusTime", mealData.lastBolusTime)
|
||||||
|
this.mealData.put("lastCarbTime", mealData.lastCarbTime)
|
||||||
|
if (constraintChecker.isAutosensModeEnabled().value()) {
|
||||||
|
autosensData.put("ratio", autosensDataRatio)
|
||||||
|
} else {
|
||||||
|
autosensData.put("ratio", 1.0)
|
||||||
|
}
|
||||||
|
this.microBolusAllowed = microBolusAllowed
|
||||||
|
smbAlwaysAllowed = advancedFiltering
|
||||||
|
currentTime = now
|
||||||
|
saveCgmSource = isSaveCgmSource
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun makeParam(jsonObject: JSONObject?, rhino: Context, scope: Scriptable): Any {
|
||||||
|
return if (jsonObject == null) Undefined.instance
|
||||||
|
else NativeJSON.parse(rhino, scope, jsonObject.toString()) { _: Context?, _: Scriptable?, _: Scriptable?, objects: Array<Any?> -> objects[1] }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun makeParamArray(jsonArray: JSONArray?, rhino: Context, scope: Scriptable): Any {
|
||||||
|
return NativeJSON.parse(rhino, scope, jsonArray.toString()) { _: Context?, _: Scriptable?, _: Scriptable?, objects: Array<Any?> -> objects[1] }
|
||||||
|
}
|
||||||
|
|
||||||
|
@Throws(IOException::class) private fun readFile(filename: String): String {
|
||||||
|
val bytes = scriptReader.readFile(filename)
|
||||||
|
var string = String(bytes, StandardCharsets.UTF_8)
|
||||||
|
if (string.startsWith("#!/usr/bin/env node")) {
|
||||||
|
string = string.substring(20)
|
||||||
|
}
|
||||||
|
return string
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
injector.androidInjector().inject(this)
|
||||||
|
}
|
||||||
|
}
|
|
@ -117,7 +117,7 @@ class OpenAPSSMBFragment : DaggerFragment() {
|
||||||
if (openAPSSMBPlugin.lastAPSRun != 0L) {
|
if (openAPSSMBPlugin.lastAPSRun != 0L) {
|
||||||
binding.lastrun.text = dateUtil.dateAndTimeString(openAPSSMBPlugin.lastAPSRun)
|
binding.lastrun.text = dateUtil.dateAndTimeString(openAPSSMBPlugin.lastAPSRun)
|
||||||
}
|
}
|
||||||
openAPSSMBPlugin.lastAutosensResult?.let {
|
openAPSSMBPlugin.lastAutosensResult.let {
|
||||||
binding.autosensdata.text = JSONFormatter.format(it.json())
|
binding.autosensdata.text = JSONFormatter.format(it.json())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,323 +0,0 @@
|
||||||
package info.nightscout.androidaps.plugins.aps.openAPSSMB;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
|
|
||||||
import androidx.preference.PreferenceFragmentCompat;
|
|
||||||
import androidx.preference.SwitchPreference;
|
|
||||||
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
import org.json.JSONException;
|
|
||||||
|
|
||||||
import javax.inject.Inject;
|
|
||||||
import javax.inject.Singleton;
|
|
||||||
|
|
||||||
import dagger.android.HasAndroidInjector;
|
|
||||||
import info.nightscout.androidaps.R;
|
|
||||||
import info.nightscout.androidaps.data.IobTotal;
|
|
||||||
import info.nightscout.androidaps.data.MealData;
|
|
||||||
import info.nightscout.androidaps.data.Profile;
|
|
||||||
import info.nightscout.androidaps.db.TempTarget;
|
|
||||||
import info.nightscout.androidaps.interfaces.APSInterface;
|
|
||||||
import info.nightscout.androidaps.interfaces.ActivePluginProvider;
|
|
||||||
import info.nightscout.androidaps.interfaces.Constraint;
|
|
||||||
import info.nightscout.androidaps.interfaces.ConstraintsInterface;
|
|
||||||
import info.nightscout.androidaps.interfaces.PluginBase;
|
|
||||||
import info.nightscout.androidaps.interfaces.PluginDescription;
|
|
||||||
import info.nightscout.androidaps.interfaces.PluginType;
|
|
||||||
import info.nightscout.androidaps.interfaces.ProfileFunction;
|
|
||||||
import info.nightscout.androidaps.interfaces.PumpInterface;
|
|
||||||
import info.nightscout.androidaps.logging.AAPSLogger;
|
|
||||||
import info.nightscout.androidaps.logging.LTag;
|
|
||||||
import info.nightscout.androidaps.plugins.aps.events.EventOpenAPSUpdateGui;
|
|
||||||
import info.nightscout.androidaps.plugins.aps.events.EventOpenAPSUpdateResultGui;
|
|
||||||
import info.nightscout.androidaps.plugins.aps.loop.APSResult;
|
|
||||||
import info.nightscout.androidaps.plugins.aps.loop.ScriptReader;
|
|
||||||
import info.nightscout.androidaps.plugins.bus.RxBusWrapper;
|
|
||||||
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker;
|
|
||||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensResult;
|
|
||||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus;
|
|
||||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin;
|
|
||||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.data.AutosensData;
|
|
||||||
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin;
|
|
||||||
import info.nightscout.androidaps.utils.DateUtil;
|
|
||||||
import info.nightscout.androidaps.utils.FabricPrivacy;
|
|
||||||
import info.nightscout.androidaps.utils.HardLimits;
|
|
||||||
import info.nightscout.androidaps.utils.Profiler;
|
|
||||||
import info.nightscout.androidaps.utils.Round;
|
|
||||||
import info.nightscout.androidaps.utils.resources.ResourceHelper;
|
|
||||||
import info.nightscout.androidaps.utils.sharedPreferences.SP;
|
|
||||||
|
|
||||||
@Singleton
|
|
||||||
public class OpenAPSSMBPlugin extends PluginBase implements APSInterface, ConstraintsInterface {
|
|
||||||
private final ConstraintChecker constraintChecker;
|
|
||||||
private final ResourceHelper resourceHelper;
|
|
||||||
private final ProfileFunction profileFunction;
|
|
||||||
private final Context context;
|
|
||||||
private final RxBusWrapper rxBus;
|
|
||||||
private final ActivePluginProvider activePlugin;
|
|
||||||
private final TreatmentsPlugin treatmentsPlugin;
|
|
||||||
private final IobCobCalculatorPlugin iobCobCalculatorPlugin;
|
|
||||||
private final HardLimits hardLimits;
|
|
||||||
private final Profiler profiler;
|
|
||||||
private final FabricPrivacy fabricPrivacy;
|
|
||||||
private final SP sp;
|
|
||||||
|
|
||||||
// last values
|
|
||||||
DetermineBasalAdapterSMBJS lastDetermineBasalAdapterSMBJS = null;
|
|
||||||
long lastAPSRun = 0;
|
|
||||||
DetermineBasalResultSMB lastAPSResult = null;
|
|
||||||
AutosensResult lastAutosensResult = null;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
public OpenAPSSMBPlugin(
|
|
||||||
HasAndroidInjector injector,
|
|
||||||
AAPSLogger aapsLogger,
|
|
||||||
RxBusWrapper rxBus,
|
|
||||||
ConstraintChecker constraintChecker,
|
|
||||||
ResourceHelper resourceHelper,
|
|
||||||
ProfileFunction profileFunction,
|
|
||||||
Context context,
|
|
||||||
ActivePluginProvider activePlugin,
|
|
||||||
TreatmentsPlugin treatmentsPlugin,
|
|
||||||
IobCobCalculatorPlugin iobCobCalculatorPlugin,
|
|
||||||
HardLimits hardLimits,
|
|
||||||
Profiler profiler,
|
|
||||||
FabricPrivacy fabricPrivacy,
|
|
||||||
SP sp
|
|
||||||
) {
|
|
||||||
super(new PluginDescription()
|
|
||||||
.mainType(PluginType.APS)
|
|
||||||
.fragmentClass(OpenAPSSMBFragment.class.getName())
|
|
||||||
.pluginIcon(R.drawable.ic_generic_icon)
|
|
||||||
.pluginName(R.string.openapssmb)
|
|
||||||
.shortName(R.string.smb_shortname)
|
|
||||||
.preferencesId(R.xml.pref_openapssmb)
|
|
||||||
.description(R.string.description_smb)
|
|
||||||
.setDefault(),
|
|
||||||
aapsLogger, resourceHelper, injector
|
|
||||||
);
|
|
||||||
this.constraintChecker = constraintChecker;
|
|
||||||
this.resourceHelper = resourceHelper;
|
|
||||||
this.profileFunction = profileFunction;
|
|
||||||
this.rxBus = rxBus;
|
|
||||||
this.context = context;
|
|
||||||
this.activePlugin = activePlugin;
|
|
||||||
this.treatmentsPlugin = treatmentsPlugin;
|
|
||||||
this.iobCobCalculatorPlugin = iobCobCalculatorPlugin;
|
|
||||||
this.hardLimits = hardLimits;
|
|
||||||
this.profiler = profiler;
|
|
||||||
this.fabricPrivacy = fabricPrivacy;
|
|
||||||
this.sp = sp;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean specialEnableCondition() {
|
|
||||||
try {
|
|
||||||
PumpInterface pump = activePlugin.getActivePump();
|
|
||||||
return pump.getPumpDescription().isTempBasalCapable;
|
|
||||||
} catch (Exception ignored) {
|
|
||||||
// may fail during initialization
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean specialShowInListCondition() {
|
|
||||||
PumpInterface pump = activePlugin.getActivePump();
|
|
||||||
return pump.getPumpDescription().isTempBasalCapable;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void preprocessPreferences(@NotNull PreferenceFragmentCompat preferenceFragment) {
|
|
||||||
super.preprocessPreferences(preferenceFragment);
|
|
||||||
boolean smbAlwaysEnabled = sp.getBoolean(R.string.key_enableSMB_always, false);
|
|
||||||
|
|
||||||
SwitchPreference withCOB = preferenceFragment.findPreference(resourceHelper.gs(R.string.key_enableSMB_with_COB));
|
|
||||||
if (withCOB != null) {
|
|
||||||
withCOB.setVisible(!smbAlwaysEnabled);
|
|
||||||
}
|
|
||||||
SwitchPreference withTempTarget = preferenceFragment.findPreference(resourceHelper.gs(R.string.key_enableSMB_with_temptarget));
|
|
||||||
if (withTempTarget != null) {
|
|
||||||
withTempTarget.setVisible(!smbAlwaysEnabled);
|
|
||||||
}
|
|
||||||
SwitchPreference afterCarbs = preferenceFragment.findPreference(resourceHelper.gs(R.string.key_enableSMB_after_carbs));
|
|
||||||
if (afterCarbs != null) {
|
|
||||||
afterCarbs.setVisible(!smbAlwaysEnabled);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public APSResult getLastAPSResult() {
|
|
||||||
return lastAPSResult;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public long getLastAPSRun() {
|
|
||||||
return lastAPSRun;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void invoke(String initiator, boolean tempBasalFallback) {
|
|
||||||
getAapsLogger().debug(LTag.APS, "invoke from " + initiator + " tempBasalFallback: " + tempBasalFallback);
|
|
||||||
lastAPSResult = null;
|
|
||||||
DetermineBasalAdapterSMBJS determineBasalAdapterSMBJS;
|
|
||||||
determineBasalAdapterSMBJS = new DetermineBasalAdapterSMBJS(new ScriptReader(context), getInjector());
|
|
||||||
|
|
||||||
GlucoseStatus glucoseStatus = new GlucoseStatus(getInjector()).getGlucoseStatusData();
|
|
||||||
Profile profile = profileFunction.getProfile();
|
|
||||||
PumpInterface pump = activePlugin.getActivePump();
|
|
||||||
|
|
||||||
if (profile == null) {
|
|
||||||
rxBus.send(new EventOpenAPSUpdateResultGui(resourceHelper.gs(R.string.noprofileselected)));
|
|
||||||
getAapsLogger().debug(LTag.APS, resourceHelper.gs(R.string.noprofileselected));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isEnabled(PluginType.APS)) {
|
|
||||||
rxBus.send(new EventOpenAPSUpdateResultGui(resourceHelper.gs(R.string.openapsma_disabled)));
|
|
||||||
getAapsLogger().debug(LTag.APS, resourceHelper.gs(R.string.openapsma_disabled));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (glucoseStatus == null) {
|
|
||||||
rxBus.send(new EventOpenAPSUpdateResultGui(resourceHelper.gs(R.string.openapsma_noglucosedata)));
|
|
||||||
getAapsLogger().debug(LTag.APS, resourceHelper.gs(R.string.openapsma_noglucosedata));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Constraint<Double> inputConstraints = new Constraint<>(0d); // fake. only for collecting all results
|
|
||||||
|
|
||||||
Constraint<Double> maxBasalConstraint = constraintChecker.getMaxBasalAllowed(profile);
|
|
||||||
inputConstraints.copyReasons(maxBasalConstraint);
|
|
||||||
double maxBasal = maxBasalConstraint.value();
|
|
||||||
double minBg = profile.getTargetLowMgdl();
|
|
||||||
double maxBg = profile.getTargetHighMgdl();
|
|
||||||
double targetBg = profile.getTargetMgdl();
|
|
||||||
|
|
||||||
minBg = Round.roundTo(minBg, 0.1d);
|
|
||||||
maxBg = Round.roundTo(maxBg, 0.1d);
|
|
||||||
|
|
||||||
long start = System.currentTimeMillis();
|
|
||||||
long startPart = System.currentTimeMillis();
|
|
||||||
|
|
||||||
MealData mealData = iobCobCalculatorPlugin.getMealData();
|
|
||||||
profiler.log(LTag.APS, "getMealData()", startPart);
|
|
||||||
|
|
||||||
Constraint<Double> maxIOBAllowedConstraint = constraintChecker.getMaxIOBAllowed();
|
|
||||||
inputConstraints.copyReasons(maxIOBAllowedConstraint);
|
|
||||||
double maxIob = maxIOBAllowedConstraint.value();
|
|
||||||
|
|
||||||
minBg = hardLimits.verifyHardLimits(minBg, "minBg", hardLimits.getVERY_HARD_LIMIT_MIN_BG()[0], hardLimits.getVERY_HARD_LIMIT_MIN_BG()[1]);
|
|
||||||
maxBg = hardLimits.verifyHardLimits(maxBg, "maxBg", hardLimits.getVERY_HARD_LIMIT_MAX_BG()[0], hardLimits.getVERY_HARD_LIMIT_MAX_BG()[1]);
|
|
||||||
targetBg = hardLimits.verifyHardLimits(targetBg, "targetBg", hardLimits.getVERY_HARD_LIMIT_TARGET_BG()[0], hardLimits.getVERY_HARD_LIMIT_TARGET_BG()[1]);
|
|
||||||
|
|
||||||
boolean isTempTarget = false;
|
|
||||||
TempTarget tempTarget = treatmentsPlugin.getTempTargetFromHistory(System.currentTimeMillis());
|
|
||||||
if (tempTarget != null) {
|
|
||||||
isTempTarget = true;
|
|
||||||
minBg = hardLimits.verifyHardLimits(tempTarget.low, "minBg", hardLimits.getVERY_HARD_LIMIT_TEMP_MIN_BG()[0], hardLimits.getVERY_HARD_LIMIT_TEMP_MIN_BG()[1]);
|
|
||||||
maxBg = hardLimits.verifyHardLimits(tempTarget.high, "maxBg", hardLimits.getVERY_HARD_LIMIT_TEMP_MAX_BG()[0], hardLimits.getVERY_HARD_LIMIT_TEMP_MAX_BG()[1]);
|
|
||||||
targetBg = hardLimits.verifyHardLimits(tempTarget.target(), "targetBg", hardLimits.getVERY_HARD_LIMIT_TEMP_TARGET_BG()[0], hardLimits.getVERY_HARD_LIMIT_TEMP_TARGET_BG()[1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (!hardLimits.checkOnlyHardLimits(profile.getDia(), "dia", hardLimits.minDia(), hardLimits.maxDia()))
|
|
||||||
return;
|
|
||||||
if (!hardLimits.checkOnlyHardLimits(profile.getIcTimeFromMidnight(Profile.secondsFromMidnight()), "carbratio", hardLimits.minIC(), hardLimits.maxIC()))
|
|
||||||
return;
|
|
||||||
if (!hardLimits.checkOnlyHardLimits(profile.getIsfMgdl(), "sens", hardLimits.getMINISF(), hardLimits.getMAXISF()))
|
|
||||||
return;
|
|
||||||
if (!hardLimits.checkOnlyHardLimits(profile.getMaxDailyBasal(), "max_daily_basal", 0.02, hardLimits.maxBasal()))
|
|
||||||
return;
|
|
||||||
if (!hardLimits.checkOnlyHardLimits(pump.getBaseBasalRate(), "current_basal", 0.01, hardLimits.maxBasal()))
|
|
||||||
return;
|
|
||||||
|
|
||||||
startPart = System.currentTimeMillis();
|
|
||||||
if (constraintChecker.isAutosensModeEnabled().value()) {
|
|
||||||
AutosensData autosensData = iobCobCalculatorPlugin.getLastAutosensDataSynchronized("OpenAPSPlugin");
|
|
||||||
if (autosensData == null) {
|
|
||||||
rxBus.send(new EventOpenAPSUpdateResultGui(resourceHelper.gs(R.string.openaps_noasdata)));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
lastAutosensResult = autosensData.autosensResult;
|
|
||||||
} else {
|
|
||||||
lastAutosensResult = new AutosensResult();
|
|
||||||
lastAutosensResult.sensResult = "autosens disabled";
|
|
||||||
}
|
|
||||||
|
|
||||||
IobTotal[] iobArray = iobCobCalculatorPlugin.calculateIobArrayForSMB(lastAutosensResult, SMBDefaults.exercise_mode, SMBDefaults.half_basal_exercise_target, isTempTarget);
|
|
||||||
profiler.log(LTag.APS, "calculateIobArrayInDia()", startPart);
|
|
||||||
|
|
||||||
startPart = System.currentTimeMillis();
|
|
||||||
Constraint<Boolean> smbAllowed = new Constraint<>(!tempBasalFallback);
|
|
||||||
constraintChecker.isSMBModeEnabled(smbAllowed);
|
|
||||||
inputConstraints.copyReasons(smbAllowed);
|
|
||||||
|
|
||||||
Constraint<Boolean> advancedFiltering = new Constraint<>(!tempBasalFallback);
|
|
||||||
constraintChecker.isAdvancedFilteringEnabled(advancedFiltering);
|
|
||||||
inputConstraints.copyReasons(advancedFiltering);
|
|
||||||
|
|
||||||
Constraint<Boolean> uam = new Constraint<>(true);
|
|
||||||
constraintChecker.isUAMEnabled(uam);
|
|
||||||
inputConstraints.copyReasons(uam);
|
|
||||||
|
|
||||||
profiler.log(LTag.APS, "detectSensitivityandCarbAbsorption()", startPart);
|
|
||||||
profiler.log(LTag.APS, "SMB data gathering", start);
|
|
||||||
|
|
||||||
start = System.currentTimeMillis();
|
|
||||||
try {
|
|
||||||
determineBasalAdapterSMBJS.setData(profile, maxIob, maxBasal, minBg, maxBg, targetBg, activePlugin.getActivePump().getBaseBasalRate(), iobArray, glucoseStatus, mealData,
|
|
||||||
lastAutosensResult.ratio, //autosensDataRatio
|
|
||||||
isTempTarget,
|
|
||||||
smbAllowed.value(),
|
|
||||||
uam.value(),
|
|
||||||
advancedFiltering.value(),
|
|
||||||
activePlugin.getActiveBgSource().getClass().getSimpleName().equals("DexcomPlugin")
|
|
||||||
);
|
|
||||||
} catch (JSONException e) {
|
|
||||||
fabricPrivacy.logException(e);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
long now = System.currentTimeMillis();
|
|
||||||
|
|
||||||
DetermineBasalResultSMB determineBasalResultSMB = determineBasalAdapterSMBJS.invoke();
|
|
||||||
profiler.log(LTag.APS, "SMB calculation", start);
|
|
||||||
if (determineBasalResultSMB == null) {
|
|
||||||
getAapsLogger().error(LTag.APS, "SMB calculation returned null");
|
|
||||||
lastDetermineBasalAdapterSMBJS = null;
|
|
||||||
lastAPSResult = null;
|
|
||||||
lastAPSRun = 0;
|
|
||||||
} else {
|
|
||||||
// TODO still needed with oref1?
|
|
||||||
// Fix bug determine basal
|
|
||||||
if (determineBasalResultSMB.getRate() == 0d && determineBasalResultSMB.getDuration() == 0 && !treatmentsPlugin.isTempBasalInProgress())
|
|
||||||
determineBasalResultSMB.setTempBasalRequested(false);
|
|
||||||
|
|
||||||
determineBasalResultSMB.setIob(iobArray[0]);
|
|
||||||
|
|
||||||
try {
|
|
||||||
determineBasalResultSMB.getJson().put("timestamp", DateUtil.toISOString(now));
|
|
||||||
} catch (JSONException e) {
|
|
||||||
getAapsLogger().error(LTag.APS, "Unhandled exception", e);
|
|
||||||
}
|
|
||||||
|
|
||||||
determineBasalResultSMB.setInputConstraints(inputConstraints);
|
|
||||||
|
|
||||||
lastDetermineBasalAdapterSMBJS = determineBasalAdapterSMBJS;
|
|
||||||
lastAPSResult = determineBasalResultSMB;
|
|
||||||
lastAPSRun = now;
|
|
||||||
}
|
|
||||||
rxBus.send(new EventOpenAPSUpdateGui());
|
|
||||||
|
|
||||||
//deviceStatus.suggested = determineBasalResultAMA.json;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
@Override
|
|
||||||
public Constraint<Boolean> isSuperBolusEnabled(Constraint<Boolean> value) {
|
|
||||||
value.set(getAapsLogger(), false);
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -0,0 +1,202 @@
|
||||||
|
package info.nightscout.androidaps.plugins.aps.openAPSSMB
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import androidx.preference.PreferenceFragmentCompat
|
||||||
|
import androidx.preference.SwitchPreference
|
||||||
|
import dagger.android.HasAndroidInjector
|
||||||
|
import info.nightscout.androidaps.R
|
||||||
|
import info.nightscout.androidaps.data.Profile
|
||||||
|
import info.nightscout.androidaps.interfaces.*
|
||||||
|
import info.nightscout.androidaps.logging.AAPSLogger
|
||||||
|
import info.nightscout.androidaps.logging.LTag
|
||||||
|
import info.nightscout.androidaps.plugins.aps.events.EventOpenAPSUpdateGui
|
||||||
|
import info.nightscout.androidaps.plugins.aps.events.EventOpenAPSUpdateResultGui
|
||||||
|
import info.nightscout.androidaps.plugins.aps.loop.ScriptReader
|
||||||
|
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
||||||
|
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
|
||||||
|
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensResult
|
||||||
|
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus
|
||||||
|
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin
|
||||||
|
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin
|
||||||
|
import info.nightscout.androidaps.utils.DateUtil
|
||||||
|
import info.nightscout.androidaps.utils.HardLimits
|
||||||
|
import info.nightscout.androidaps.utils.Profiler
|
||||||
|
import info.nightscout.androidaps.utils.Round
|
||||||
|
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||||
|
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
||||||
|
import javax.inject.Inject
|
||||||
|
import javax.inject.Singleton
|
||||||
|
|
||||||
|
@Singleton
|
||||||
|
open class OpenAPSSMBPlugin @Inject constructor(
|
||||||
|
injector: HasAndroidInjector,
|
||||||
|
aapsLogger: AAPSLogger,
|
||||||
|
private val rxBus: RxBusWrapper,
|
||||||
|
private val constraintChecker: ConstraintChecker,
|
||||||
|
resourceHelper: ResourceHelper,
|
||||||
|
private val profileFunction: ProfileFunction,
|
||||||
|
private val context: Context,
|
||||||
|
private val activePlugin: ActivePluginProvider,
|
||||||
|
private val treatmentsPlugin: TreatmentsPlugin,
|
||||||
|
private val iobCobCalculatorPlugin: IobCobCalculatorPlugin,
|
||||||
|
private val hardLimits: HardLimits,
|
||||||
|
private val profiler: Profiler,
|
||||||
|
private val sp: SP
|
||||||
|
) : PluginBase(PluginDescription()
|
||||||
|
.mainType(PluginType.APS)
|
||||||
|
.fragmentClass(OpenAPSSMBFragment::class.java.name)
|
||||||
|
.pluginIcon(R.drawable.ic_generic_icon)
|
||||||
|
.pluginName(R.string.openapssmb)
|
||||||
|
.shortName(R.string.smb_shortname)
|
||||||
|
.preferencesId(R.xml.pref_openapssmb)
|
||||||
|
.description(R.string.description_smb)
|
||||||
|
.setDefault(),
|
||||||
|
aapsLogger, resourceHelper, injector
|
||||||
|
), APSInterface, ConstraintsInterface {
|
||||||
|
|
||||||
|
// last values
|
||||||
|
override var lastAPSRun: Long = 0
|
||||||
|
override var lastAPSResult: DetermineBasalResultSMB? = null
|
||||||
|
var lastDetermineBasalAdapterSMBJS: DetermineBasalAdapterSMBJS? = null
|
||||||
|
var lastAutosensResult = AutosensResult()
|
||||||
|
|
||||||
|
override fun specialEnableCondition(): Boolean {
|
||||||
|
return try {
|
||||||
|
activePlugin.activePump.pumpDescription.isTempBasalCapable
|
||||||
|
} catch (ignored: Exception) {
|
||||||
|
// may fail during initialization
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun specialShowInListCondition(): Boolean {
|
||||||
|
val pump = activePlugin.activePump
|
||||||
|
return pump.pumpDescription.isTempBasalCapable
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun preprocessPreferences(preferenceFragment: PreferenceFragmentCompat) {
|
||||||
|
super.preprocessPreferences(preferenceFragment)
|
||||||
|
val smbAlwaysEnabled = sp.getBoolean(R.string.key_enableSMB_always, false)
|
||||||
|
preferenceFragment.findPreference<SwitchPreference>(resourceHelper.gs(R.string.key_enableSMB_with_COB))?.isVisible = !smbAlwaysEnabled
|
||||||
|
preferenceFragment.findPreference<SwitchPreference>(resourceHelper.gs(R.string.key_enableSMB_with_temptarget))?.isVisible = !smbAlwaysEnabled
|
||||||
|
preferenceFragment.findPreference<SwitchPreference>(resourceHelper.gs(R.string.key_enableSMB_after_carbs))?.isVisible = !smbAlwaysEnabled
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun invoke(initiator: String, tempBasalFallback: Boolean) {
|
||||||
|
aapsLogger.debug(LTag.APS, "invoke from $initiator tempBasalFallback: $tempBasalFallback")
|
||||||
|
lastAPSResult = null
|
||||||
|
val glucoseStatus = GlucoseStatus(injector).glucoseStatusData
|
||||||
|
val profile = profileFunction.getProfile()
|
||||||
|
val pump = activePlugin.activePump
|
||||||
|
if (profile == null) {
|
||||||
|
rxBus.send(EventOpenAPSUpdateResultGui(resourceHelper.gs(R.string.noprofileselected)))
|
||||||
|
aapsLogger.debug(LTag.APS, resourceHelper.gs(R.string.noprofileselected))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (!isEnabled(PluginType.APS)) {
|
||||||
|
rxBus.send(EventOpenAPSUpdateResultGui(resourceHelper.gs(R.string.openapsma_disabled)))
|
||||||
|
aapsLogger.debug(LTag.APS, resourceHelper.gs(R.string.openapsma_disabled))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (glucoseStatus == null) {
|
||||||
|
rxBus.send(EventOpenAPSUpdateResultGui(resourceHelper.gs(R.string.openapsma_noglucosedata)))
|
||||||
|
aapsLogger.debug(LTag.APS, resourceHelper.gs(R.string.openapsma_noglucosedata))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
val inputConstraints = Constraint(0.0) // fake. only for collecting all results
|
||||||
|
val maxBasal = constraintChecker.getMaxBasalAllowed(profile).also {
|
||||||
|
inputConstraints.copyReasons(it)
|
||||||
|
}.value()
|
||||||
|
var start = System.currentTimeMillis()
|
||||||
|
var startPart = System.currentTimeMillis()
|
||||||
|
profiler.log(LTag.APS, "getMealData()", startPart)
|
||||||
|
val maxIob = constraintChecker.getMaxIOBAllowed().also { maxIOBAllowedConstraint ->
|
||||||
|
inputConstraints.copyReasons(maxIOBAllowedConstraint)
|
||||||
|
}.value()
|
||||||
|
|
||||||
|
var minBg = hardLimits.verifyHardLimits(Round.roundTo(profile.targetLowMgdl, 0.1), "minBg", hardLimits.VERY_HARD_LIMIT_MIN_BG[0].toDouble(), hardLimits.VERY_HARD_LIMIT_MIN_BG[1].toDouble())
|
||||||
|
var maxBg = hardLimits.verifyHardLimits(Round.roundTo(profile.targetHighMgdl, 0.1), "maxBg", hardLimits.VERY_HARD_LIMIT_MAX_BG[0].toDouble(), hardLimits.VERY_HARD_LIMIT_MAX_BG[1].toDouble())
|
||||||
|
var targetBg = hardLimits.verifyHardLimits(profile.targetMgdl, "targetBg", hardLimits.VERY_HARD_LIMIT_TARGET_BG[0].toDouble(), hardLimits.VERY_HARD_LIMIT_TARGET_BG[1].toDouble())
|
||||||
|
var isTempTarget = false
|
||||||
|
treatmentsPlugin.getTempTargetFromHistory(System.currentTimeMillis())?.let { tempTarget ->
|
||||||
|
isTempTarget = true
|
||||||
|
minBg = hardLimits.verifyHardLimits(tempTarget.low, "minBg", hardLimits.VERY_HARD_LIMIT_TEMP_MIN_BG[0].toDouble(), hardLimits.VERY_HARD_LIMIT_TEMP_MIN_BG[1].toDouble())
|
||||||
|
maxBg = hardLimits.verifyHardLimits(tempTarget.high, "maxBg", hardLimits.VERY_HARD_LIMIT_TEMP_MAX_BG[0].toDouble(), hardLimits.VERY_HARD_LIMIT_TEMP_MAX_BG[1].toDouble())
|
||||||
|
targetBg = hardLimits.verifyHardLimits(tempTarget.target(), "targetBg", hardLimits.VERY_HARD_LIMIT_TEMP_TARGET_BG[0].toDouble(), hardLimits.VERY_HARD_LIMIT_TEMP_TARGET_BG[1].toDouble())
|
||||||
|
}
|
||||||
|
if (!hardLimits.checkOnlyHardLimits(profile.dia, "dia", hardLimits.minDia(), hardLimits.maxDia())) return
|
||||||
|
if (!hardLimits.checkOnlyHardLimits(profile.getIcTimeFromMidnight(Profile.secondsFromMidnight()), "carbratio", hardLimits.minIC(), hardLimits.maxIC())) return
|
||||||
|
if (!hardLimits.checkOnlyHardLimits(profile.isfMgdl, "sens", hardLimits.MINISF, hardLimits.MAXISF)) return
|
||||||
|
if (!hardLimits.checkOnlyHardLimits(profile.maxDailyBasal, "max_daily_basal", 0.02, hardLimits.maxBasal())) return
|
||||||
|
if (!hardLimits.checkOnlyHardLimits(pump.baseBasalRate, "current_basal", 0.01, hardLimits.maxBasal())) return
|
||||||
|
startPart = System.currentTimeMillis()
|
||||||
|
if (constraintChecker.isAutosensModeEnabled().value()) {
|
||||||
|
val autosensData = iobCobCalculatorPlugin.getLastAutosensDataSynchronized("OpenAPSPlugin")
|
||||||
|
if (autosensData == null) {
|
||||||
|
rxBus.send(EventOpenAPSUpdateResultGui(resourceHelper.gs(R.string.openaps_noasdata)))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
lastAutosensResult = autosensData.autosensResult
|
||||||
|
} else {
|
||||||
|
lastAutosensResult.sensResult = "autosens disabled"
|
||||||
|
}
|
||||||
|
val iobArray = iobCobCalculatorPlugin.calculateIobArrayForSMB(lastAutosensResult, SMBDefaults.exercise_mode, SMBDefaults.half_basal_exercise_target, isTempTarget)
|
||||||
|
profiler.log(LTag.APS, "calculateIobArrayInDia()", startPart)
|
||||||
|
startPart = System.currentTimeMillis()
|
||||||
|
val smbAllowed = Constraint(!tempBasalFallback).also {
|
||||||
|
constraintChecker.isSMBModeEnabled(it)
|
||||||
|
inputConstraints.copyReasons(it)
|
||||||
|
}
|
||||||
|
val advancedFiltering = Constraint(!tempBasalFallback).also {
|
||||||
|
constraintChecker.isAdvancedFilteringEnabled(it)
|
||||||
|
inputConstraints.copyReasons(it)
|
||||||
|
}
|
||||||
|
val uam = Constraint(true).also {
|
||||||
|
constraintChecker.isUAMEnabled(it)
|
||||||
|
inputConstraints.copyReasons(it)
|
||||||
|
}
|
||||||
|
profiler.log(LTag.APS, "detectSensitivityAndCarbAbsorption()", startPart)
|
||||||
|
profiler.log(LTag.APS, "SMB data gathering", start)
|
||||||
|
start = System.currentTimeMillis()
|
||||||
|
|
||||||
|
DetermineBasalAdapterSMBJS(ScriptReader(context), injector).also { determineBasalAdapterSMBJS ->
|
||||||
|
determineBasalAdapterSMBJS.setData(profile, maxIob, maxBasal, minBg, maxBg, targetBg,
|
||||||
|
activePlugin.activePump.baseBasalRate,
|
||||||
|
iobArray,
|
||||||
|
glucoseStatus,
|
||||||
|
iobCobCalculatorPlugin.mealData,
|
||||||
|
lastAutosensResult.ratio,
|
||||||
|
isTempTarget,
|
||||||
|
smbAllowed.value(),
|
||||||
|
uam.value(),
|
||||||
|
advancedFiltering.value(),
|
||||||
|
activePlugin.activeBgSource.javaClass.simpleName == "DexcomPlugin")
|
||||||
|
val now = System.currentTimeMillis()
|
||||||
|
val determineBasalResultSMB = determineBasalAdapterSMBJS.invoke()
|
||||||
|
profiler.log(LTag.APS, "SMB calculation", start)
|
||||||
|
if (determineBasalResultSMB == null) {
|
||||||
|
aapsLogger.error(LTag.APS, "SMB calculation returned null")
|
||||||
|
lastDetermineBasalAdapterSMBJS = null
|
||||||
|
lastAPSResult = null
|
||||||
|
lastAPSRun = 0
|
||||||
|
} else {
|
||||||
|
// TODO still needed with oref1?
|
||||||
|
// Fix bug determine basal
|
||||||
|
if (determineBasalResultSMB.rate == 0.0 && determineBasalResultSMB.duration == 0 && !treatmentsPlugin.isTempBasalInProgress) determineBasalResultSMB.tempBasalRequested = false
|
||||||
|
determineBasalResultSMB.iob = iobArray[0]
|
||||||
|
determineBasalResultSMB.json?.put("timestamp", DateUtil.toISOString(now))
|
||||||
|
determineBasalResultSMB.inputConstraints = inputConstraints
|
||||||
|
lastDetermineBasalAdapterSMBJS = determineBasalAdapterSMBJS
|
||||||
|
lastAPSResult = determineBasalResultSMB
|
||||||
|
lastAPSRun = now
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rxBus.send(EventOpenAPSUpdateGui())
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun isSuperBolusEnabled(value: Constraint<Boolean>): Constraint<Boolean> {
|
||||||
|
value[aapsLogger] = false
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
}
|
|
@ -196,19 +196,19 @@ class ObjectivesFragment : DaggerFragment() {
|
||||||
if (task.shouldBeIgnored()) continue
|
if (task.shouldBeIgnored()) continue
|
||||||
// name
|
// name
|
||||||
val name = TextView(holder.binding.progress.context)
|
val name = TextView(holder.binding.progress.context)
|
||||||
name.text = resourceHelper.gs(task.task) + ":"
|
name.text = "${resourceHelper.gs(task.task)}:"
|
||||||
name.setTextColor(-0x1)
|
name.setTextColor(-0x1)
|
||||||
holder.binding.progress.addView(name, LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT)
|
holder.binding.progress.addView(name, LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT)
|
||||||
// hint
|
// hint
|
||||||
task.hints.forEach { h ->
|
task.hints.forEach { h ->
|
||||||
if (!task.isCompleted)
|
if (!task.isCompleted())
|
||||||
holder.binding.progress.addView(h.generate(context))
|
context?.let { holder.binding.progress.addView(h.generate(it)) }
|
||||||
}
|
}
|
||||||
// state
|
// state
|
||||||
val state = TextView(holder.binding.progress.context)
|
val state = TextView(holder.binding.progress.context)
|
||||||
state.setTextColor(-0x1)
|
state.setTextColor(-0x1)
|
||||||
val basicHTML = "<font color=\"%1\$s\"><b>%2\$s</b></font>"
|
val basicHTML = "<font color=\"%1\$s\"><b>%2\$s</b></font>"
|
||||||
val formattedHTML = String.format(basicHTML, if (task.isCompleted) "#4CAF50" else "#FF9800", task.progress)
|
val formattedHTML = String.format(basicHTML, if (task.isCompleted()) "#4CAF50" else "#FF9800", task.progress)
|
||||||
state.text = HtmlHelper.fromHtml(formattedHTML)
|
state.text = HtmlHelper.fromHtml(formattedHTML)
|
||||||
state.gravity = Gravity.END
|
state.gravity = Gravity.END
|
||||||
holder.binding.progress.addView(state, LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT)
|
holder.binding.progress.addView(state, LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT)
|
||||||
|
@ -307,7 +307,7 @@ class ObjectivesFragment : DaggerFragment() {
|
||||||
holder.binding.unstart.setOnClickListener {
|
holder.binding.unstart.setOnClickListener {
|
||||||
activity?.let { activity ->
|
activity?.let { activity ->
|
||||||
OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.objectives), resourceHelper.gs(R.string.doyouwantresetstart), Runnable {
|
OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.objectives), resourceHelper.gs(R.string.doyouwantresetstart), Runnable {
|
||||||
uel.log("OBJECTVE UNSTARTED", i1 = position + 1)
|
uel.log("OBJECTIVE UNSTARTED", i1 = position + 1)
|
||||||
objective.startedOn = 0
|
objective.startedOn = 0
|
||||||
scrollToCurrentObjective()
|
scrollToCurrentObjective()
|
||||||
rxBus.send(EventObjectivesUpdateGui())
|
rxBus.send(EventObjectivesUpdateGui())
|
||||||
|
@ -332,7 +332,7 @@ class ObjectivesFragment : DaggerFragment() {
|
||||||
holder.binding.inputhint.visibility = View.VISIBLE
|
holder.binding.inputhint.visibility = View.VISIBLE
|
||||||
holder.binding.enterbutton.setOnClickListener {
|
holder.binding.enterbutton.setOnClickListener {
|
||||||
val input = holder.binding.input.text.toString()
|
val input = holder.binding.input.text.toString()
|
||||||
objective.specialAction(activity, input)
|
activity?.let { activity -> objective.specialAction(activity, input) }
|
||||||
rxBus.send(EventObjectivesUpdateGui())
|
rxBus.send(EventObjectivesUpdateGui())
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -80,6 +80,7 @@ class ObjectivesExamDialog : DaggerDialogFragment() {
|
||||||
// Options
|
// Options
|
||||||
binding.examOptions.removeAllViews()
|
binding.examOptions.removeAllViews()
|
||||||
task.options.forEach {
|
task.options.forEach {
|
||||||
|
context?.let { context ->
|
||||||
val cb = it.generate(context)
|
val cb = it.generate(context)
|
||||||
if (task.answered) {
|
if (task.answered) {
|
||||||
cb.isEnabled = false
|
cb.isEnabled = false
|
||||||
|
@ -88,20 +89,21 @@ class ObjectivesExamDialog : DaggerDialogFragment() {
|
||||||
}
|
}
|
||||||
binding.examOptions.addView(cb)
|
binding.examOptions.addView(cb)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// Hints
|
// Hints
|
||||||
binding.examHints.removeAllViews()
|
binding.examHints.removeAllViews()
|
||||||
for (h in task.hints) {
|
for (h in task.hints) {
|
||||||
binding.examHints.addView(h.generate(context))
|
context?.let { binding.examHints.addView(h.generate(it)) }
|
||||||
}
|
}
|
||||||
// Disabled to
|
// Disabled to
|
||||||
binding.examDisabledto.text = resourceHelper.gs(R.string.answerdisabledto, dateUtil.timeString(task.disabledTo))
|
binding.examDisabledto.text = resourceHelper.gs(R.string.answerdisabledto, dateUtil.timeString(task.disabledTo))
|
||||||
binding.examDisabledto.visibility = if (task.isEnabledAnswer) View.GONE else View.VISIBLE
|
binding.examDisabledto.visibility = if (task.isEnabledAnswer()) View.GONE else View.VISIBLE
|
||||||
// Buttons
|
// Buttons
|
||||||
binding.examVerify.isEnabled = !task.answered && task.isEnabledAnswer
|
binding.examVerify.isEnabled = !task.answered && task.isEnabledAnswer()
|
||||||
binding.examVerify.setOnClickListener {
|
binding.examVerify.setOnClickListener {
|
||||||
var result = true
|
var result = true
|
||||||
for (o in task.options) {
|
for (o in task.options) {
|
||||||
val option: Option = o as Option
|
val option: Option = o
|
||||||
result = result && option.evaluate()
|
result = result && option.evaluate()
|
||||||
}
|
}
|
||||||
task.answered = result
|
task.answered = result
|
||||||
|
@ -133,14 +135,14 @@ class ObjectivesExamDialog : DaggerDialogFragment() {
|
||||||
binding.nextUnansweredButton.isEnabled = !objective.isCompleted
|
binding.nextUnansweredButton.isEnabled = !objective.isCompleted
|
||||||
binding.nextUnansweredButton.setOnClickListener {
|
binding.nextUnansweredButton.setOnClickListener {
|
||||||
for (i in (currentTask + 1) until objective.tasks.size) {
|
for (i in (currentTask + 1) until objective.tasks.size) {
|
||||||
if (!objective.tasks[i].isCompleted) {
|
if (!objective.tasks[i].isCompleted()) {
|
||||||
currentTask = i
|
currentTask = i
|
||||||
updateGui()
|
updateGui()
|
||||||
return@setOnClickListener
|
return@setOnClickListener
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (i in 0..currentTask) {
|
for (i in 0..currentTask) {
|
||||||
if (!objective.tasks[i].isCompleted) {
|
if (!objective.tasks[i].isCompleted()) {
|
||||||
currentTask = i
|
currentTask = i
|
||||||
updateGui()
|
updateGui()
|
||||||
return@setOnClickListener
|
return@setOnClickListener
|
||||||
|
|
|
@ -1,295 +0,0 @@
|
||||||
package info.nightscout.androidaps.plugins.constraints.objectives.objectives;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.graphics.Color;
|
|
||||||
import android.text.util.Linkify;
|
|
||||||
import android.widget.CheckBox;
|
|
||||||
import android.widget.TextView;
|
|
||||||
|
|
||||||
import androidx.annotation.StringRes;
|
|
||||||
import androidx.fragment.app.FragmentActivity;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import javax.inject.Inject;
|
|
||||||
|
|
||||||
import dagger.android.HasAndroidInjector;
|
|
||||||
import info.nightscout.androidaps.R;
|
|
||||||
import info.nightscout.androidaps.utils.DateUtil;
|
|
||||||
import info.nightscout.androidaps.utils.T;
|
|
||||||
import info.nightscout.androidaps.utils.resources.ResourceHelper;
|
|
||||||
import info.nightscout.androidaps.utils.sharedPreferences.SP;
|
|
||||||
|
|
||||||
public abstract class Objective {
|
|
||||||
@Inject public SP sp;
|
|
||||||
@Inject public ResourceHelper resourceHelper;
|
|
||||||
|
|
||||||
private final String spName;
|
|
||||||
@StringRes private final int objective;
|
|
||||||
@StringRes private final int gate;
|
|
||||||
private long startedOn;
|
|
||||||
private long accomplishedOn;
|
|
||||||
List<Task> tasks = new ArrayList<>();
|
|
||||||
public boolean hasSpecialInput = false;
|
|
||||||
|
|
||||||
public Objective(HasAndroidInjector injector, String spName, @StringRes int objective, @StringRes int gate) {
|
|
||||||
injector.androidInjector().inject(this);
|
|
||||||
this.spName = spName;
|
|
||||||
this.objective = objective;
|
|
||||||
this.gate = gate;
|
|
||||||
startedOn = sp.getLong("Objectives_" + spName + "_started", 0L);
|
|
||||||
accomplishedOn = sp.getLong("Objectives_" + spName + "_accomplished", 0L);
|
|
||||||
if ((accomplishedOn - DateUtil.now()) > T.hours(3).msecs() || (startedOn - DateUtil.now()) > T.hours(3).msecs()) { // more than 3 hours in the future
|
|
||||||
startedOn = 0;
|
|
||||||
accomplishedOn = 0;
|
|
||||||
}
|
|
||||||
setupTasks(tasks);
|
|
||||||
for (Task task : tasks) task.objective = this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isCompleted() {
|
|
||||||
for (Task task : tasks) {
|
|
||||||
if (!task.shouldBeIgnored() && !task.isCompleted())
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isCompleted(long trueTime) {
|
|
||||||
for (Task task : tasks) {
|
|
||||||
if (!task.shouldBeIgnored() && !task.isCompleted(trueTime))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isAccomplished() {
|
|
||||||
return accomplishedOn != 0 && accomplishedOn < DateUtil.now();
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isStarted() {
|
|
||||||
return startedOn != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getStartedOn() {
|
|
||||||
return startedOn;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getObjective() {
|
|
||||||
return objective;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getGate() {
|
|
||||||
return gate;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setStartedOn(long startedOn) {
|
|
||||||
this.startedOn = startedOn;
|
|
||||||
sp.putLong("Objectives_" + spName + "_started", startedOn);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setAccomplishedOn(long accomplishedOn) {
|
|
||||||
this.accomplishedOn = accomplishedOn;
|
|
||||||
sp.putLong("Objectives_" + spName + "_accomplished", accomplishedOn);
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getAccomplishedOn() {
|
|
||||||
return accomplishedOn;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void setupTasks(List<Task> tasks) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<Task> getTasks() {
|
|
||||||
return tasks;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean specialActionEnabled() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void specialAction(FragmentActivity activity, String input) {
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract class Task {
|
|
||||||
@StringRes
|
|
||||||
private final int task;
|
|
||||||
private Objective objective;
|
|
||||||
ArrayList<Hint> hints = new ArrayList<>();
|
|
||||||
|
|
||||||
public Task(@StringRes int task) {
|
|
||||||
this.task = task;
|
|
||||||
}
|
|
||||||
|
|
||||||
public @StringRes int getTask() {
|
|
||||||
return task;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected Objective getObjective() {
|
|
||||||
return objective;
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract boolean isCompleted();
|
|
||||||
|
|
||||||
public boolean isCompleted(long trueTime) {
|
|
||||||
return isCompleted();
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getProgress() {
|
|
||||||
return resourceHelper.gs(isCompleted() ? R.string.completed_well_done : R.string.not_completed_yet);
|
|
||||||
}
|
|
||||||
|
|
||||||
Task hint(Hint hint) {
|
|
||||||
hints.add(hint);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ArrayList<Hint> getHints() {
|
|
||||||
return hints;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean shouldBeIgnored() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class MinimumDurationTask extends Task {
|
|
||||||
|
|
||||||
private final long minimumDuration;
|
|
||||||
|
|
||||||
MinimumDurationTask(long minimumDuration) {
|
|
||||||
super(R.string.time_elapsed);
|
|
||||||
this.minimumDuration = minimumDuration;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isCompleted() {
|
|
||||||
return getObjective().isStarted() && System.currentTimeMillis() - getObjective().getStartedOn() >= minimumDuration;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isCompleted(long trueTime) {
|
|
||||||
return getObjective().isStarted() && trueTime - getObjective().getStartedOn() >= minimumDuration;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getProgress() {
|
|
||||||
return getDurationText(System.currentTimeMillis() - getObjective().getStartedOn())
|
|
||||||
+ " / " + getDurationText(minimumDuration);
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getDurationText(long duration) {
|
|
||||||
int days = (int) Math.floor((double) duration / T.days(1).msecs());
|
|
||||||
int hours = (int) Math.floor((double) duration / T.hours(1).msecs());
|
|
||||||
int minutes = (int) Math.floor((double) duration / T.mins(1).msecs());
|
|
||||||
if (days > 0) return resourceHelper.gq(R.plurals.days, days, days);
|
|
||||||
else if (hours > 0) return resourceHelper.gq(R.plurals.hours, hours, hours);
|
|
||||||
else return resourceHelper.gq(R.plurals.minutes, minutes, minutes);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class ExamTask extends Task {
|
|
||||||
@StringRes
|
|
||||||
int question;
|
|
||||||
ArrayList<Option> options = new ArrayList<>();
|
|
||||||
private final String spIdentifier;
|
|
||||||
private boolean answered;
|
|
||||||
private long disabledTo;
|
|
||||||
|
|
||||||
ExamTask(@StringRes int task, @StringRes int question, String spIdentifier) {
|
|
||||||
super(task);
|
|
||||||
this.question = question;
|
|
||||||
this.spIdentifier = spIdentifier;
|
|
||||||
answered = sp.getBoolean("ExamTask_" + spIdentifier, false);
|
|
||||||
disabledTo = sp.getLong("DisabledTo_" + spIdentifier, 0L);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setDisabledTo(long newState) {
|
|
||||||
disabledTo = newState;
|
|
||||||
sp.putLong("DisabledTo_" + spIdentifier, disabledTo);
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getDisabledTo() {
|
|
||||||
return disabledTo;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isEnabledAnswer() {
|
|
||||||
return disabledTo < DateUtil.now();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setAnswered(boolean newState) {
|
|
||||||
answered = newState;
|
|
||||||
sp.putBoolean("ExamTask_" + spIdentifier, answered);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean getAnswered() {
|
|
||||||
return answered;
|
|
||||||
}
|
|
||||||
|
|
||||||
ExamTask option(Option option) {
|
|
||||||
options.add(option);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public @StringRes int getQuestion() {
|
|
||||||
return question;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<Objective.Option> getOptions() {
|
|
||||||
return options;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isCompleted() {
|
|
||||||
return answered;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class Option {
|
|
||||||
@StringRes int option;
|
|
||||||
boolean isCorrect;
|
|
||||||
|
|
||||||
CheckBox cb; // TODO: change it, this will block releasing memeory
|
|
||||||
|
|
||||||
Option(@StringRes int option, boolean isCorrect) {
|
|
||||||
this.option = option;
|
|
||||||
this.isCorrect = isCorrect;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isCorrect() {
|
|
||||||
return isCorrect;
|
|
||||||
}
|
|
||||||
|
|
||||||
public CheckBox generate(Context context) {
|
|
||||||
cb = new CheckBox(context);
|
|
||||||
cb.setText(option);
|
|
||||||
return cb;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean evaluate() {
|
|
||||||
boolean selection = cb.isChecked();
|
|
||||||
if (selection && isCorrect) return true;
|
|
||||||
return !selection && !isCorrect;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class Hint {
|
|
||||||
@StringRes int hint;
|
|
||||||
|
|
||||||
Hint(@StringRes int hint) {
|
|
||||||
this.hint = hint;
|
|
||||||
}
|
|
||||||
|
|
||||||
public TextView generate(Context context) {
|
|
||||||
TextView textView = new TextView(context);
|
|
||||||
textView.setText(hint);
|
|
||||||
textView.setAutoLinkMask(Linkify.WEB_URLS);
|
|
||||||
textView.setLinksClickable(true);
|
|
||||||
textView.setLinkTextColor(Color.YELLOW);
|
|
||||||
Linkify.addLinks(textView, Linkify.WEB_URLS);
|
|
||||||
return textView;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,183 @@
|
||||||
|
package info.nightscout.androidaps.plugins.constraints.objectives.objectives
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.graphics.Color
|
||||||
|
import android.text.util.Linkify
|
||||||
|
import android.widget.CheckBox
|
||||||
|
import android.widget.TextView
|
||||||
|
import androidx.annotation.StringRes
|
||||||
|
import androidx.fragment.app.FragmentActivity
|
||||||
|
import dagger.android.HasAndroidInjector
|
||||||
|
import info.nightscout.androidaps.R
|
||||||
|
import info.nightscout.androidaps.utils.DateUtil
|
||||||
|
import info.nightscout.androidaps.utils.T
|
||||||
|
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||||
|
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
||||||
|
import java.util.*
|
||||||
|
import javax.inject.Inject
|
||||||
|
import kotlin.math.floor
|
||||||
|
|
||||||
|
abstract class Objective(injector: HasAndroidInjector, spName: String, @StringRes objective: Int, @StringRes gate: Int) {
|
||||||
|
|
||||||
|
@Inject lateinit var sp: SP
|
||||||
|
@Inject lateinit var resourceHelper: ResourceHelper
|
||||||
|
|
||||||
|
private val spName: String
|
||||||
|
@StringRes val objective: Int
|
||||||
|
@StringRes val gate: Int
|
||||||
|
var startedOn: Long = 0
|
||||||
|
set(value) {
|
||||||
|
field = value
|
||||||
|
sp.putLong("Objectives_" + spName + "_started", startedOn)
|
||||||
|
}
|
||||||
|
var accomplishedOn: Long = 0
|
||||||
|
set(value) {
|
||||||
|
field = value
|
||||||
|
sp.putLong("Objectives_" + spName + "_accomplished", value)
|
||||||
|
}
|
||||||
|
|
||||||
|
var tasks: MutableList<Task> = ArrayList()
|
||||||
|
|
||||||
|
var hasSpecialInput = false
|
||||||
|
|
||||||
|
val isCompleted: Boolean
|
||||||
|
get() {
|
||||||
|
for (task in tasks) {
|
||||||
|
if (!task.shouldBeIgnored() && !task.isCompleted()) return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
injector.androidInjector().inject(this)
|
||||||
|
this.spName = spName
|
||||||
|
this.objective = objective
|
||||||
|
this.gate = gate
|
||||||
|
startedOn = sp.getLong("Objectives_" + spName + "_started", 0L)
|
||||||
|
accomplishedOn = sp.getLong("Objectives_" + spName + "_accomplished", 0L)
|
||||||
|
if (accomplishedOn - DateUtil.now() > T.hours(3).msecs() || startedOn - DateUtil.now() > T.hours(3).msecs()) { // more than 3 hours in the future
|
||||||
|
startedOn = 0
|
||||||
|
accomplishedOn = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun isCompleted(trueTime: Long): Boolean {
|
||||||
|
for (task in tasks) {
|
||||||
|
if (!task.shouldBeIgnored() && !task.isCompleted(trueTime)) return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
val isAccomplished: Boolean
|
||||||
|
get() = accomplishedOn != 0L && accomplishedOn < DateUtil.now()
|
||||||
|
val isStarted: Boolean
|
||||||
|
get() = startedOn != 0L
|
||||||
|
|
||||||
|
open fun specialActionEnabled(): Boolean {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
open fun specialAction(activity: FragmentActivity, input: String) {}
|
||||||
|
|
||||||
|
abstract inner class Task(var objective: Objective, @StringRes val task: Int) {
|
||||||
|
|
||||||
|
var hints = ArrayList<Hint>()
|
||||||
|
|
||||||
|
abstract fun isCompleted(): Boolean
|
||||||
|
|
||||||
|
open fun isCompleted(trueTime: Long): Boolean = isCompleted
|
||||||
|
|
||||||
|
open val progress: String
|
||||||
|
get() = resourceHelper.gs(if (isCompleted) R.string.completed_well_done else R.string.not_completed_yet)
|
||||||
|
|
||||||
|
fun hint(hint: Hint): Task {
|
||||||
|
hints.add(hint)
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
open fun shouldBeIgnored(): Boolean = false
|
||||||
|
}
|
||||||
|
|
||||||
|
inner class MinimumDurationTask internal constructor(objective: Objective, private val minimumDuration: Long) : Task(objective, R.string.time_elapsed) {
|
||||||
|
|
||||||
|
override fun isCompleted(): Boolean =
|
||||||
|
objective.isStarted && System.currentTimeMillis() - objective.startedOn >= minimumDuration
|
||||||
|
|
||||||
|
override fun isCompleted(trueTime: Long): Boolean {
|
||||||
|
return objective.isStarted && trueTime - objective.startedOn >= minimumDuration
|
||||||
|
}
|
||||||
|
|
||||||
|
override val progress: String
|
||||||
|
get() = (getDurationText(System.currentTimeMillis() - objective.startedOn)
|
||||||
|
+ " / " + getDurationText(minimumDuration))
|
||||||
|
|
||||||
|
private fun getDurationText(duration: Long): String {
|
||||||
|
val days = floor(duration.toDouble() / T.days(1).msecs()).toInt()
|
||||||
|
val hours = floor(duration.toDouble() / T.hours(1).msecs()).toInt()
|
||||||
|
val minutes = floor(duration.toDouble() / T.mins(1).msecs()).toInt()
|
||||||
|
return when {
|
||||||
|
days > 0 -> resourceHelper.gq(R.plurals.days, days, days)
|
||||||
|
hours > 0 -> resourceHelper.gq(R.plurals.hours, hours, hours)
|
||||||
|
else -> resourceHelper.gq(R.plurals.minutes, minutes, minutes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inner class ExamTask internal constructor(objective: Objective, @StringRes task: Int, @StringRes val question: Int, private val spIdentifier: String) : Task(objective, task) {
|
||||||
|
|
||||||
|
var options = ArrayList<Option>()
|
||||||
|
var answered: Boolean = false
|
||||||
|
set(value) {
|
||||||
|
field = value
|
||||||
|
sp.putBoolean("ExamTask_$spIdentifier", value)
|
||||||
|
}
|
||||||
|
var disabledTo: Long = 0
|
||||||
|
set(value) {
|
||||||
|
field = value
|
||||||
|
sp.putLong("DisabledTo_$spIdentifier", value)
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
answered = sp.getBoolean("ExamTask_$spIdentifier", false)
|
||||||
|
disabledTo = sp.getLong("DisabledTo_$spIdentifier", 0L)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun isCompleted(): Boolean = answered
|
||||||
|
|
||||||
|
fun isEnabledAnswer(): Boolean = disabledTo < DateUtil.now()
|
||||||
|
|
||||||
|
fun option(option: Option): ExamTask {
|
||||||
|
options.add(option)
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inner class Option internal constructor(@StringRes var option: Int, var isCorrect: Boolean) {
|
||||||
|
|
||||||
|
var cb: CheckBox? = null // TODO: change it, this will block releasing memory
|
||||||
|
|
||||||
|
fun generate(context: Context): CheckBox {
|
||||||
|
cb = CheckBox(context)
|
||||||
|
cb?.setText(option)
|
||||||
|
return cb!!
|
||||||
|
}
|
||||||
|
|
||||||
|
fun evaluate(): Boolean {
|
||||||
|
val selection = cb!!.isChecked
|
||||||
|
return if (selection && isCorrect) true else !selection && !isCorrect
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inner class Hint internal constructor(@StringRes var hint: Int) {
|
||||||
|
|
||||||
|
fun generate(context: Context): TextView {
|
||||||
|
val textView = TextView(context)
|
||||||
|
textView.setText(hint)
|
||||||
|
textView.autoLinkMask = Linkify.WEB_URLS
|
||||||
|
textView.linksClickable = true
|
||||||
|
textView.setLinkTextColor(Color.YELLOW)
|
||||||
|
Linkify.addLinks(textView, Linkify.WEB_URLS)
|
||||||
|
return textView
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,91 +0,0 @@
|
||||||
package info.nightscout.androidaps.plugins.constraints.objectives.objectives;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import javax.inject.Inject;
|
|
||||||
|
|
||||||
import dagger.android.HasAndroidInjector;
|
|
||||||
import info.nightscout.androidaps.R;
|
|
||||||
import info.nightscout.androidaps.interfaces.APSInterface;
|
|
||||||
import info.nightscout.androidaps.interfaces.ActivePluginProvider;
|
|
||||||
import info.nightscout.androidaps.interfaces.PluginBase;
|
|
||||||
import info.nightscout.androidaps.interfaces.PluginType;
|
|
||||||
import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin;
|
|
||||||
import info.nightscout.androidaps.plugins.general.nsclient.NSClientPlugin;
|
|
||||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin;
|
|
||||||
import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpPlugin;
|
|
||||||
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin;
|
|
||||||
import info.nightscout.androidaps.utils.DateUtil;
|
|
||||||
import info.nightscout.androidaps.utils.sharedPreferences.SP;
|
|
||||||
|
|
||||||
public class Objective0 extends Objective {
|
|
||||||
@Inject SP sp;
|
|
||||||
@Inject ActivePluginProvider activePlugin;
|
|
||||||
@Inject VirtualPumpPlugin virtualPumpPlugin;
|
|
||||||
@Inject TreatmentsPlugin treatmentsPlugin;
|
|
||||||
@Inject LoopPlugin loopPlugin;
|
|
||||||
@Inject NSClientPlugin nsClientPlugin;
|
|
||||||
@Inject IobCobCalculatorPlugin iobCobCalculatorPlugin;
|
|
||||||
|
|
||||||
public Objective0(HasAndroidInjector injector) {
|
|
||||||
super(injector, "config", R.string.objectives_0_objective, R.string.objectives_0_gate);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void setupTasks(List<Task> tasks) {
|
|
||||||
tasks.add(new Task(R.string.objectives_bgavailableinns) {
|
|
||||||
@Override
|
|
||||||
public boolean isCompleted() {
|
|
||||||
return sp.getBoolean(R.string.key_ObjectivesbgIsAvailableInNS, false);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
tasks.add(new Task(R.string.nsclienthaswritepermission) {
|
|
||||||
@Override
|
|
||||||
public boolean isCompleted() {
|
|
||||||
return nsClientPlugin.hasWritePermission();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
tasks.add(new Task(R.string.virtualpump_uploadstatus_title) {
|
|
||||||
@Override
|
|
||||||
public boolean isCompleted() {
|
|
||||||
return sp.getBoolean(R.string.key_virtualpump_uploadstatus, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean shouldBeIgnored() {
|
|
||||||
return !virtualPumpPlugin.isEnabled(PluginType.PUMP);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
tasks.add(new Task(R.string.objectives_pumpstatusavailableinns) {
|
|
||||||
@Override
|
|
||||||
public boolean isCompleted() {
|
|
||||||
return sp.getBoolean(R.string.key_ObjectivespumpStatusIsAvailableInNS, false);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
tasks.add(new Task(R.string.hasbgdata) {
|
|
||||||
@Override
|
|
||||||
public boolean isCompleted() {
|
|
||||||
return iobCobCalculatorPlugin.lastBg() != null;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
tasks.add(new Task(R.string.loopenabled) {
|
|
||||||
@Override
|
|
||||||
public boolean isCompleted() {
|
|
||||||
return loopPlugin.isEnabled(PluginType.LOOP);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
tasks.add(new Task(R.string.apsselected) {
|
|
||||||
@Override
|
|
||||||
public boolean isCompleted() {
|
|
||||||
APSInterface usedAPS = activePlugin.getActiveAPS();
|
|
||||||
return ((PluginBase) usedAPS).isEnabled(PluginType.APS);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
tasks.add(new Task(R.string.activate_profile) {
|
|
||||||
@Override
|
|
||||||
public boolean isCompleted() {
|
|
||||||
return treatmentsPlugin.getProfileSwitchFromHistory(DateUtil.now()) != null;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,72 @@
|
||||||
|
package info.nightscout.androidaps.plugins.constraints.objectives.objectives
|
||||||
|
|
||||||
|
import dagger.android.HasAndroidInjector
|
||||||
|
import info.nightscout.androidaps.R
|
||||||
|
import info.nightscout.androidaps.interfaces.ActivePluginProvider
|
||||||
|
import info.nightscout.androidaps.interfaces.PluginBase
|
||||||
|
import info.nightscout.androidaps.interfaces.PluginType
|
||||||
|
import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin
|
||||||
|
import info.nightscout.androidaps.plugins.general.nsclient.NSClientPlugin
|
||||||
|
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin
|
||||||
|
import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpPlugin
|
||||||
|
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin
|
||||||
|
import info.nightscout.androidaps.utils.DateUtil
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class Objective0(injector: HasAndroidInjector) : Objective(injector, "config", R.string.objectives_0_objective, R.string.objectives_0_gate) {
|
||||||
|
|
||||||
|
@Inject lateinit var activePlugin: ActivePluginProvider
|
||||||
|
@Inject lateinit var virtualPumpPlugin: VirtualPumpPlugin
|
||||||
|
@Inject lateinit var treatmentsPlugin: TreatmentsPlugin
|
||||||
|
@Inject lateinit var loopPlugin: LoopPlugin
|
||||||
|
@Inject lateinit var nsClientPlugin: NSClientPlugin
|
||||||
|
@Inject lateinit var iobCobCalculatorPlugin: IobCobCalculatorPlugin
|
||||||
|
|
||||||
|
init {
|
||||||
|
tasks.add(object : Task(this, R.string.objectives_bgavailableinns) {
|
||||||
|
override fun isCompleted(): Boolean {
|
||||||
|
return sp.getBoolean(R.string.key_ObjectivesbgIsAvailableInNS, false)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
tasks.add(object : Task(this, R.string.nsclienthaswritepermission) {
|
||||||
|
override fun isCompleted(): Boolean {
|
||||||
|
return nsClientPlugin.hasWritePermission()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
tasks.add(object : Task(this, R.string.virtualpump_uploadstatus_title) {
|
||||||
|
override fun isCompleted(): Boolean {
|
||||||
|
return sp.getBoolean(R.string.key_virtualpump_uploadstatus, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun shouldBeIgnored(): Boolean {
|
||||||
|
return !virtualPumpPlugin.isEnabled(PluginType.PUMP)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
tasks.add(object : Task(this, R.string.objectives_pumpstatusavailableinns) {
|
||||||
|
override fun isCompleted(): Boolean {
|
||||||
|
return sp.getBoolean(R.string.key_ObjectivespumpStatusIsAvailableInNS, false)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
tasks.add(object : Task(this, R.string.hasbgdata) {
|
||||||
|
override fun isCompleted(): Boolean {
|
||||||
|
return iobCobCalculatorPlugin.lastBg() != null
|
||||||
|
}
|
||||||
|
})
|
||||||
|
tasks.add(object : Task(this, R.string.loopenabled) {
|
||||||
|
override fun isCompleted(): Boolean {
|
||||||
|
return loopPlugin.isEnabled(PluginType.LOOP)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
tasks.add(object : Task(this, R.string.apsselected) {
|
||||||
|
override fun isCompleted(): Boolean {
|
||||||
|
val usedAPS = activePlugin.activeAPS
|
||||||
|
return (usedAPS as PluginBase).isEnabled(PluginType.APS)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
tasks.add(object : Task(this, R.string.activate_profile) {
|
||||||
|
override fun isCompleted(): Boolean {
|
||||||
|
return treatmentsPlugin.getProfileSwitchFromHistory(DateUtil.now()) != null
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,67 +0,0 @@
|
||||||
package info.nightscout.androidaps.plugins.constraints.objectives.objectives;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import javax.inject.Inject;
|
|
||||||
|
|
||||||
import dagger.android.HasAndroidInjector;
|
|
||||||
import info.nightscout.androidaps.R;
|
|
||||||
import info.nightscout.androidaps.interfaces.PluginType;
|
|
||||||
import info.nightscout.androidaps.plugins.general.actions.ActionsPlugin;
|
|
||||||
import info.nightscout.androidaps.utils.sharedPreferences.SP;
|
|
||||||
|
|
||||||
public class Objective1 extends Objective {
|
|
||||||
@Inject SP sp;
|
|
||||||
@Inject ActionsPlugin actionsPlugin;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
public Objective1(HasAndroidInjector injector) {
|
|
||||||
super(injector, "usage", R.string.objectives_usage_objective, R.string.objectives_usage_gate);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void setupTasks(List<Task> tasks) {
|
|
||||||
tasks.add(new Task(R.string.objectives_useprofileswitch) {
|
|
||||||
@Override
|
|
||||||
public boolean isCompleted() {
|
|
||||||
return sp.getBoolean(R.string.key_objectiveuseprofileswitch, false);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
tasks.add(new Task(R.string.objectives_usedisconnectpump) {
|
|
||||||
@Override
|
|
||||||
public boolean isCompleted() {
|
|
||||||
return sp.getBoolean(R.string.key_objectiveusedisconnect, false);
|
|
||||||
}
|
|
||||||
}.hint(new Hint(R.string.disconnectpump_hint)));
|
|
||||||
tasks.add(new Task(R.string.objectives_usereconnectpump) {
|
|
||||||
@Override
|
|
||||||
public boolean isCompleted() {
|
|
||||||
return sp.getBoolean(R.string.key_objectiveusereconnect, false);
|
|
||||||
}
|
|
||||||
}.hint(new Hint(R.string.disconnectpump_hint)));
|
|
||||||
tasks.add(new Task(R.string.objectives_usetemptarget) {
|
|
||||||
@Override
|
|
||||||
public boolean isCompleted() {
|
|
||||||
return sp.getBoolean(R.string.key_objectiveusetemptarget, false);
|
|
||||||
}
|
|
||||||
}.hint(new Hint(R.string.usetemptarget_hint)));
|
|
||||||
tasks.add(new Task(R.string.objectives_useactions) {
|
|
||||||
@Override
|
|
||||||
public boolean isCompleted() {
|
|
||||||
return sp.getBoolean(R.string.key_objectiveuseactions, false) && actionsPlugin.isEnabled(PluginType.GENERAL) && actionsPlugin.isFragmentVisible();
|
|
||||||
}
|
|
||||||
}.hint(new Hint(R.string.useaction_hint)));
|
|
||||||
tasks.add(new Task(R.string.objectives_useloop) {
|
|
||||||
@Override
|
|
||||||
public boolean isCompleted() {
|
|
||||||
return sp.getBoolean(R.string.key_objectiveuseloop, false);
|
|
||||||
}
|
|
||||||
}.hint(new Hint(R.string.useaction_hint)));
|
|
||||||
tasks.add(new Task(R.string.objectives_usescale) {
|
|
||||||
@Override
|
|
||||||
public boolean isCompleted() {
|
|
||||||
return sp.getBoolean(R.string.key_objectiveusescale, false);
|
|
||||||
}
|
|
||||||
}.hint(new Hint(R.string.usescale_hint)));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,50 @@
|
||||||
|
package info.nightscout.androidaps.plugins.constraints.objectives.objectives
|
||||||
|
|
||||||
|
import dagger.android.HasAndroidInjector
|
||||||
|
import info.nightscout.androidaps.R
|
||||||
|
import info.nightscout.androidaps.interfaces.PluginType
|
||||||
|
import info.nightscout.androidaps.plugins.general.actions.ActionsPlugin
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class Objective1 @Inject constructor(injector: HasAndroidInjector) : Objective(injector, "usage", R.string.objectives_usage_objective, R.string.objectives_usage_gate) {
|
||||||
|
|
||||||
|
@Inject lateinit var actionsPlugin: ActionsPlugin
|
||||||
|
|
||||||
|
init {
|
||||||
|
tasks.add(object : Task(this, R.string.objectives_useprofileswitch) {
|
||||||
|
override fun isCompleted(): Boolean {
|
||||||
|
return sp.getBoolean(R.string.key_objectiveuseprofileswitch, false)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
tasks.add(object : Task(this, R.string.objectives_usedisconnectpump) {
|
||||||
|
override fun isCompleted(): Boolean {
|
||||||
|
return sp.getBoolean(R.string.key_objectiveusedisconnect, false)
|
||||||
|
}
|
||||||
|
}.hint(Hint(R.string.disconnectpump_hint)))
|
||||||
|
tasks.add(object : Task(this, R.string.objectives_usereconnectpump) {
|
||||||
|
override fun isCompleted(): Boolean {
|
||||||
|
return sp.getBoolean(R.string.key_objectiveusereconnect, false)
|
||||||
|
}
|
||||||
|
}.hint(Hint(R.string.disconnectpump_hint)))
|
||||||
|
tasks.add(object : Task(this, R.string.objectives_usetemptarget) {
|
||||||
|
override fun isCompleted(): Boolean {
|
||||||
|
return sp.getBoolean(R.string.key_objectiveusetemptarget, false)
|
||||||
|
}
|
||||||
|
}.hint(Hint(R.string.usetemptarget_hint)))
|
||||||
|
tasks.add(object : Task(this, R.string.objectives_useactions) {
|
||||||
|
override fun isCompleted(): Boolean {
|
||||||
|
return sp.getBoolean(R.string.key_objectiveuseactions, false) && actionsPlugin.isEnabled(PluginType.GENERAL) && actionsPlugin.isFragmentVisible()
|
||||||
|
}
|
||||||
|
}.hint(Hint(R.string.useaction_hint)))
|
||||||
|
tasks.add(object : Task(this, R.string.objectives_useloop) {
|
||||||
|
override fun isCompleted(): Boolean {
|
||||||
|
return sp.getBoolean(R.string.key_objectiveuseloop, false)
|
||||||
|
}
|
||||||
|
}.hint(Hint(R.string.useaction_hint)))
|
||||||
|
tasks.add(object : Task(this, R.string.objectives_usescale) {
|
||||||
|
override fun isCompleted(): Boolean {
|
||||||
|
return sp.getBoolean(R.string.key_objectiveusescale, false)
|
||||||
|
}
|
||||||
|
}.hint(Hint(R.string.usescale_hint)))
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,19 +0,0 @@
|
||||||
package info.nightscout.androidaps.plugins.constraints.objectives.objectives;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import dagger.android.HasAndroidInjector;
|
|
||||||
import info.nightscout.androidaps.R;
|
|
||||||
import info.nightscout.androidaps.utils.T;
|
|
||||||
|
|
||||||
public class Objective10 extends Objective {
|
|
||||||
|
|
||||||
public Objective10(HasAndroidInjector injector) {
|
|
||||||
super(injector, "auto", R.string.objectives_auto_objective, R.string.objectives_auto_gate);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void setupTasks(List<Task> tasks) {
|
|
||||||
tasks.add(new MinimumDurationTask(T.days(28).msecs()));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
package info.nightscout.androidaps.plugins.constraints.objectives.objectives
|
||||||
|
|
||||||
|
import dagger.android.HasAndroidInjector
|
||||||
|
import info.nightscout.androidaps.R
|
||||||
|
import info.nightscout.androidaps.utils.T
|
||||||
|
|
||||||
|
class Objective10(injector: HasAndroidInjector) : Objective(injector, "auto", R.string.objectives_auto_objective, R.string.objectives_auto_gate) {
|
||||||
|
|
||||||
|
init {
|
||||||
|
tasks.add(MinimumDurationTask(this, T.days(28).msecs()))
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,222 +0,0 @@
|
||||||
package info.nightscout.androidaps.plugins.constraints.objectives.objectives;
|
|
||||||
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import dagger.android.HasAndroidInjector;
|
|
||||||
import info.nightscout.androidaps.MainApp;
|
|
||||||
import info.nightscout.androidaps.R;
|
|
||||||
|
|
||||||
public class Objective2 extends Objective {
|
|
||||||
|
|
||||||
|
|
||||||
public Objective2(HasAndroidInjector injector) {
|
|
||||||
super(injector, "exam", R.string.objectives_exam_objective, R.string.objectives_exam_gate);
|
|
||||||
for (Task task : tasks) {
|
|
||||||
if (!task.isCompleted()) setAccomplishedOn(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void setupTasks(List<Task> tasks) {
|
|
||||||
tasks.add(new ExamTask(R.string.prerequisites_label, R.string.prerequisites_what, "prerequisites")
|
|
||||||
.option(new Option(R.string.prerequisites_nightscout, true))
|
|
||||||
.option(new Option(R.string.prerequisites_computer, true))
|
|
||||||
.option(new Option(R.string.prerequisites_pump, true))
|
|
||||||
.option(new Option(R.string.prerequisites_beanandroiddeveloper, false))
|
|
||||||
.hint(new Hint(R.string.prerequisites_hint1))
|
|
||||||
);
|
|
||||||
tasks.add(new ExamTask(R.string.prerequisites2_label, R.string.prerequisites2_what, "prerequisites2")
|
|
||||||
.option(new Option(R.string.prerequisites2_profile, true))
|
|
||||||
.option(new Option(R.string.prerequisites2_device, true))
|
|
||||||
.option(new Option(R.string.prerequisites2_internet, false))
|
|
||||||
.option(new Option(R.string.prerequisites2_supportedcgm, true))
|
|
||||||
.hint(new Hint(R.string.prerequisites2_hint1))
|
|
||||||
);
|
|
||||||
tasks.add(new ExamTask(R.string.basaltest_label, R.string.basaltest_when,"basaltest")
|
|
||||||
.option(new Option(R.string.basaltest_fixed, false))
|
|
||||||
.option(new Option(R.string.basaltest_havingregularhighlow, true))
|
|
||||||
.option(new Option(R.string.basaltest_weekly, false))
|
|
||||||
.option(new Option(R.string.basaltest_beforeloop, true))
|
|
||||||
.hint(new Hint(R.string.basaltest_hint1))
|
|
||||||
);
|
|
||||||
tasks.add(new ExamTask(R.string.dia_label_exam, R.string.dia_whatmeansdia,"dia")
|
|
||||||
.option(new Option(R.string.dia_profile, true))
|
|
||||||
.option(new Option(R.string.dia_minimumis5h, true))
|
|
||||||
.option(new Option(R.string.dia_meaningisequaltodiapump, false))
|
|
||||||
.option(new Option(R.string.dia_valuemustbedetermined, true))
|
|
||||||
.hint(new Hint(R.string.dia_hint1))
|
|
||||||
);
|
|
||||||
tasks.add(new ExamTask(R.string.isf_label_exam, R.string.blank,"isf")
|
|
||||||
.option(new Option(R.string.isf_decreasingvalue, true))
|
|
||||||
.option(new Option(R.string.isf_preferences, false))
|
|
||||||
.option(new Option(R.string.isf_increasingvalue, false))
|
|
||||||
.option(new Option(R.string.isf_noeffect, false))
|
|
||||||
.hint(new Hint(R.string.isf_hint1))
|
|
||||||
.hint(new Hint(R.string.isf_hint2))
|
|
||||||
);
|
|
||||||
tasks.add(new ExamTask(R.string.ic_label_exam, R.string.blank,"ic")
|
|
||||||
.option(new Option(R.string.ic_increasingvalue, true))
|
|
||||||
.option(new Option(R.string.ic_decreasingvalue, false))
|
|
||||||
.option(new Option(R.string.ic_multiple, true))
|
|
||||||
.option(new Option(R.string.ic_isf, false))
|
|
||||||
.hint(new Hint(R.string.ic_hint1))
|
|
||||||
);
|
|
||||||
tasks.add(new ExamTask(R.string.hypott_label, R.string.hypott_whenhypott,"hypott")
|
|
||||||
.option(new Option(R.string.hypott_preventoversmb, true))
|
|
||||||
.option(new Option(R.string.hypott_exercise, false))
|
|
||||||
.option(new Option(R.string.hypott_wrongbasal, false))
|
|
||||||
.option(new Option(R.string.hypott_0basal, false))
|
|
||||||
.hint(new Hint(R.string.hypott_hint1))
|
|
||||||
);
|
|
||||||
tasks.add(new ExamTask(R.string.profileswitch_label, R.string.profileswitch_pctwillchange,"profileswitch")
|
|
||||||
.option(new Option(R.string.profileswitch_basallower, true))
|
|
||||||
.option(new Option(R.string.profileswitch_isfhigher, true))
|
|
||||||
.option(new Option(R.string.profileswitch_iclower, false))
|
|
||||||
.option(new Option(R.string.profileswitch_unchanged, false))
|
|
||||||
.hint(new Hint(R.string.profileswitch_hint1))
|
|
||||||
);
|
|
||||||
tasks.add(new ExamTask(R.string.profileswitch2_label, R.string.profileswitch2_pctwillchange,"profileswitch2")
|
|
||||||
.option(new Option(R.string.profileswitch2_bghigher, false))
|
|
||||||
.option(new Option(R.string.profileswitch2_basalhigher, true))
|
|
||||||
.option(new Option(R.string.profileswitch2_bgunchanged, true))
|
|
||||||
.option(new Option(R.string.profileswitch2_isfhigher, false))
|
|
||||||
.hint(new Hint(R.string.profileswitch_hint1))
|
|
||||||
);
|
|
||||||
tasks.add(new ExamTask(R.string.profileswitchtime_label, R.string.profileswitchtime_iwant,"profileswitchtime")
|
|
||||||
.option(new Option(R.string.profileswitchtime_2, false))
|
|
||||||
.option(new Option(R.string.profileswitchtime__2, true))
|
|
||||||
.option(new Option(R.string.profileswitchtime_tt, false))
|
|
||||||
.option(new Option(R.string.profileswitchtime_100, false))
|
|
||||||
.hint(new Hint(R.string.profileswitchtime_hint1))
|
|
||||||
);
|
|
||||||
tasks.add(new ExamTask(R.string.profileswitch4_label, R.string.blank,"profileswitch4")
|
|
||||||
.option(new Option(R.string.profileswitch4_rates, true))
|
|
||||||
.option(new Option(R.string.profileswitch4_internet, true))
|
|
||||||
.option(new Option(R.string.profileswitch4_sufficient, false))
|
|
||||||
.option(new Option(R.string.profileswitch4_multi, true))
|
|
||||||
.hint(new Hint(R.string.profileswitch_hint1))
|
|
||||||
);
|
|
||||||
tasks.add(new ExamTask(R.string.exerciseprofile_label, R.string.exerciseprofile_whattodo,"exercise")
|
|
||||||
.option(new Option(R.string.exerciseprofile_switchprofileabove100, false))
|
|
||||||
.option(new Option(R.string.exerciseprofile_switchprofilebelow100, true))
|
|
||||||
.option(new Option(R.string.exerciseprofile_suspendloop, false))
|
|
||||||
.option(new Option(R.string.exerciseprofile_leaveat100, false))
|
|
||||||
.hint(new Hint(R.string.exerciseprofile_hint1))
|
|
||||||
);
|
|
||||||
tasks.add(new ExamTask(R.string.exercise_label, R.string.exercise_whattodo,"exercise2")
|
|
||||||
.option(new Option(R.string.exercise_settt, true))
|
|
||||||
.option(new Option(R.string.exercise_setfinished, false))
|
|
||||||
.option(new Option(R.string.exercise_setunchanged, false))
|
|
||||||
.option(new Option(R.string.exercise_15g, false))
|
|
||||||
.hint(new Hint(R.string.exercise_hint1))
|
|
||||||
);
|
|
||||||
tasks.add(new ExamTask(R.string.noisycgm_label, R.string.noisycgm_whattodo,"noisycgm")
|
|
||||||
.option(new Option(R.string.noisycgm_nothing, false))
|
|
||||||
.option(new Option(R.string.noisycgm_pause, true))
|
|
||||||
.option(new Option(R.string.noisycgm_replacesensor, true))
|
|
||||||
.option(new Option(R.string.noisycgm_checksmoothing, true))
|
|
||||||
.hint(new Hint(R.string.noisycgm_hint1))
|
|
||||||
);
|
|
||||||
tasks.add(new ExamTask(R.string.pumpdisconnect_label, R.string.blank,"pumpdisconnect")
|
|
||||||
.option(new Option(R.string.pumpdisconnect_unnecessary, false))
|
|
||||||
.option(new Option(R.string.pumpdisconnect_missinginsulin, true))
|
|
||||||
.option(new Option(R.string.pumpdisconnect_notstop, false))
|
|
||||||
.option(new Option(R.string.pumpdisconnect_openloop, false))
|
|
||||||
.hint(new Hint(R.string.pumpdisconnect_hint1))
|
|
||||||
);
|
|
||||||
tasks.add(new ExamTask(R.string.insulin_label, R.string.insulin_ultrarapid,"insulin")
|
|
||||||
.option(new Option(R.string.insulin_novorapid, false))
|
|
||||||
.option(new Option(R.string.insulin_humalog, false))
|
|
||||||
.option(new Option(R.string.insulin_actrapid, false))
|
|
||||||
.option(new Option(R.string.insulin_fiasp, true))
|
|
||||||
.hint(new Hint(R.string.insulin_hint1))
|
|
||||||
);
|
|
||||||
tasks.add(new ExamTask(R.string.sensitivity_label, R.string.blank,"sensitivity")
|
|
||||||
.option(new Option(R.string.sensitivity_adjust, true))
|
|
||||||
.option(new Option(R.string.sensitivity_edit, false))
|
|
||||||
.option(new Option(R.string.sensitivity_cannula, true))
|
|
||||||
.option(new Option(R.string.sensitivity_time, true))
|
|
||||||
.hint(new Hint(R.string.sensitivity_hint1))
|
|
||||||
);
|
|
||||||
tasks.add(new ExamTask(R.string.objectives_label, R.string.objectives_howtosave,"objectives")
|
|
||||||
.option(new Option(R.string.objectives_notesettings, false))
|
|
||||||
.option(new Option(R.string.objectives_afterobjective, true))
|
|
||||||
.option(new Option(R.string.objectives_afterchange, true))
|
|
||||||
.option(new Option(R.string.objectives_afterinitialsetup, true))
|
|
||||||
.hint(new Hint(R.string.objectives_hint1))
|
|
||||||
.hint(new Hint(R.string.objectives_hint2))
|
|
||||||
);
|
|
||||||
tasks.add(new ExamTask(R.string.objectives2_label, R.string.objectives_howtosave,"objectives2")
|
|
||||||
.option(new Option(R.string.objectives2_maintenance, true))
|
|
||||||
.option(new Option(R.string.objectives2_internalstorage, true))
|
|
||||||
.option(new Option(R.string.objectives2_cloud, true))
|
|
||||||
.option(new Option(R.string.objectives2_easyrestore, false))
|
|
||||||
.hint(new Hint(R.string.objectives_hint1))
|
|
||||||
.hint(new Hint(R.string.objectives_hint2))
|
|
||||||
);
|
|
||||||
tasks.add(new ExamTask(R.string.update_label, R.string.blank,"update")
|
|
||||||
.option(new Option(R.string.update_git, true))
|
|
||||||
.option(new Option(R.string.update_askfriend, false))
|
|
||||||
.option(new Option(R.string.update_keys, true))
|
|
||||||
.option(new Option(R.string.update_asap, true))
|
|
||||||
.hint(new Hint(R.string.update_hint1))
|
|
||||||
);
|
|
||||||
tasks.add(new ExamTask(R.string.troubleshooting_label, R.string.troubleshooting_wheretoask,"troubleshooting")
|
|
||||||
.option(new Option(R.string.troubleshooting_fb, true))
|
|
||||||
.option(new Option(R.string.troubleshooting_wiki, true))
|
|
||||||
.option(new Option(R.string.troubleshooting_gitter, true))
|
|
||||||
.option(new Option(R.string.troubleshooting_yourendo, false))
|
|
||||||
.hint(new Hint(R.string.troubleshooting_hint1))
|
|
||||||
.hint(new Hint(R.string.troubleshooting_hint2))
|
|
||||||
.hint(new Hint(R.string.troubleshooting_hint3))
|
|
||||||
);
|
|
||||||
tasks.add(new ExamTask(R.string.wrongcarbs_label, R.string.wrongcarbs_whattodo,"wrongcarbs")
|
|
||||||
.option(new Option(R.string.wrongcarbs_addinsulin, false))
|
|
||||||
.option(new Option(R.string.wrongcarbs_treatmentstab, true))
|
|
||||||
.option(new Option(R.string.wrongcarbs_donothing, false))
|
|
||||||
.option(new Option(R.string.wrongcarbs_bolus, false))
|
|
||||||
);
|
|
||||||
tasks.add(new ExamTask(R.string.wronginsulin_label, R.string.wronginsulin_whattodo,"wronginsulin")
|
|
||||||
.option(new Option(R.string.wronginsulin_careportal, false))
|
|
||||||
.option(new Option(R.string.wronginsulin_compare, true))
|
|
||||||
.option(new Option(R.string.wronginsulin_prime, true))
|
|
||||||
.option(new Option(R.string.wrongcarbs_donothing, false))
|
|
||||||
);
|
|
||||||
tasks.add(new ExamTask(R.string.iob_label, R.string.blank,"iob")
|
|
||||||
.option(new Option(R.string.iob_value, true))
|
|
||||||
.option(new Option(R.string.iob_hightemp, false))
|
|
||||||
.option(new Option(R.string.iob_negiob, true))
|
|
||||||
.option(new Option(R.string.iob_posiob, true))
|
|
||||||
);
|
|
||||||
tasks.add(new ExamTask(R.string.breadgrams_label, R.string.blank,"breadgrams")
|
|
||||||
.option(new Option(R.string.breadgrams_grams, true))
|
|
||||||
.option(new Option(R.string.breadgrams_exchange, false))
|
|
||||||
.option(new Option(R.string.breadgrams_decay, true))
|
|
||||||
.option(new Option(R.string.breadgrams_calc, true))
|
|
||||||
.hint(new Hint(R.string.breadgrams_hint1))
|
|
||||||
);
|
|
||||||
tasks.add(new ExamTask(R.string.extendedcarbs_label, R.string.extendedcarbs_handling,"extendedcarbs")
|
|
||||||
.option(new Option(R.string.extendedcarbs_future, true))
|
|
||||||
.option(new Option(R.string.extendedcarbs_free, false))
|
|
||||||
.option(new Option(R.string.extendedcarbs_fat, true))
|
|
||||||
.option(new Option(R.string.extendedcarbs_rescue, false))
|
|
||||||
.hint(new Hint(R.string.extendedcarbs_hint1))
|
|
||||||
);
|
|
||||||
tasks.add(new ExamTask(R.string.nsclient_label, R.string.nsclient_howcanyou,"nsclient")
|
|
||||||
.option(new Option(R.string.nsclient_nightscout, true))
|
|
||||||
.option(new Option(R.string.nsclient_dexcomfollow, true))
|
|
||||||
.option(new Option(R.string.nsclient_data, true))
|
|
||||||
.option(new Option(R.string.nsclient_fullcontrol, false))
|
|
||||||
.hint(new Hint(R.string.nsclient_hint1))
|
|
||||||
);
|
|
||||||
tasks.add(new ExamTask(R.string.other_medication_label, R.string.other_medication_text,"otherMedicationWarning")
|
|
||||||
.option(new Option(R.string.yes, true))
|
|
||||||
.option(new Option(R.string.no, false))
|
|
||||||
);
|
|
||||||
|
|
||||||
for (Task task : tasks)
|
|
||||||
Collections.shuffle(((ExamTask)task).options);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -0,0 +1,211 @@
|
||||||
|
package info.nightscout.androidaps.plugins.constraints.objectives.objectives
|
||||||
|
|
||||||
|
import dagger.android.HasAndroidInjector
|
||||||
|
import info.nightscout.androidaps.R
|
||||||
|
|
||||||
|
@Suppress("SpellCheckingInspection")
|
||||||
|
class Objective2(injector: HasAndroidInjector) : Objective(injector, "exam", R.string.objectives_exam_objective, R.string.objectives_exam_gate) {
|
||||||
|
|
||||||
|
init {
|
||||||
|
tasks.add(ExamTask(this, R.string.prerequisites_label, R.string.prerequisites_what, "prerequisites")
|
||||||
|
.option(Option(R.string.prerequisites_nightscout, true))
|
||||||
|
.option(Option(R.string.prerequisites_computer, true))
|
||||||
|
.option(Option(R.string.prerequisites_pump, true))
|
||||||
|
.option(Option(R.string.prerequisites_beanandroiddeveloper, false))
|
||||||
|
.hint(Hint(R.string.prerequisites_hint1))
|
||||||
|
)
|
||||||
|
tasks.add(ExamTask(this, R.string.prerequisites2_label, R.string.prerequisites2_what, "prerequisites2")
|
||||||
|
.option(Option(R.string.prerequisites2_profile, true))
|
||||||
|
.option(Option(R.string.prerequisites2_device, true))
|
||||||
|
.option(Option(R.string.prerequisites2_internet, false))
|
||||||
|
.option(Option(R.string.prerequisites2_supportedcgm, true))
|
||||||
|
.hint(Hint(R.string.prerequisites2_hint1))
|
||||||
|
)
|
||||||
|
tasks.add(ExamTask(this, R.string.basaltest_label, R.string.basaltest_when, "basaltest")
|
||||||
|
.option(Option(R.string.basaltest_fixed, false))
|
||||||
|
.option(Option(R.string.basaltest_havingregularhighlow, true))
|
||||||
|
.option(Option(R.string.basaltest_weekly, false))
|
||||||
|
.option(Option(R.string.basaltest_beforeloop, true))
|
||||||
|
.hint(Hint(R.string.basaltest_hint1))
|
||||||
|
)
|
||||||
|
tasks.add(ExamTask(this, R.string.dia_label_exam, R.string.dia_whatmeansdia, "dia")
|
||||||
|
.option(Option(R.string.dia_profile, true))
|
||||||
|
.option(Option(R.string.dia_minimumis5h, true))
|
||||||
|
.option(Option(R.string.dia_meaningisequaltodiapump, false))
|
||||||
|
.option(Option(R.string.dia_valuemustbedetermined, true))
|
||||||
|
.hint(Hint(R.string.dia_hint1))
|
||||||
|
)
|
||||||
|
tasks.add(ExamTask(this, R.string.isf_label_exam, R.string.blank, "isf")
|
||||||
|
.option(Option(R.string.isf_decreasingvalue, true))
|
||||||
|
.option(Option(R.string.isf_preferences, false))
|
||||||
|
.option(Option(R.string.isf_increasingvalue, false))
|
||||||
|
.option(Option(R.string.isf_noeffect, false))
|
||||||
|
.hint(Hint(R.string.isf_hint1))
|
||||||
|
.hint(Hint(R.string.isf_hint2))
|
||||||
|
)
|
||||||
|
tasks.add(ExamTask(this, R.string.ic_label_exam, R.string.blank, "ic")
|
||||||
|
.option(Option(R.string.ic_increasingvalue, true))
|
||||||
|
.option(Option(R.string.ic_decreasingvalue, false))
|
||||||
|
.option(Option(R.string.ic_multiple, true))
|
||||||
|
.option(Option(R.string.ic_isf, false))
|
||||||
|
.hint(Hint(R.string.ic_hint1))
|
||||||
|
)
|
||||||
|
tasks.add(ExamTask(this, R.string.hypott_label, R.string.hypott_whenhypott, "hypott")
|
||||||
|
.option(Option(R.string.hypott_preventoversmb, true))
|
||||||
|
.option(Option(R.string.hypott_exercise, false))
|
||||||
|
.option(Option(R.string.hypott_wrongbasal, false))
|
||||||
|
.option(Option(R.string.hypott_0basal, false))
|
||||||
|
.hint(Hint(R.string.hypott_hint1))
|
||||||
|
)
|
||||||
|
tasks.add(ExamTask(this, R.string.profileswitch_label, R.string.profileswitch_pctwillchange, "profileswitch")
|
||||||
|
.option(Option(R.string.profileswitch_basallower, true))
|
||||||
|
.option(Option(R.string.profileswitch_isfhigher, true))
|
||||||
|
.option(Option(R.string.profileswitch_iclower, false))
|
||||||
|
.option(Option(R.string.profileswitch_unchanged, false))
|
||||||
|
.hint(Hint(R.string.profileswitch_hint1))
|
||||||
|
)
|
||||||
|
tasks.add(ExamTask(this, R.string.profileswitch2_label, R.string.profileswitch2_pctwillchange, "profileswitch2")
|
||||||
|
.option(Option(R.string.profileswitch2_bghigher, false))
|
||||||
|
.option(Option(R.string.profileswitch2_basalhigher, true))
|
||||||
|
.option(Option(R.string.profileswitch2_bgunchanged, true))
|
||||||
|
.option(Option(R.string.profileswitch2_isfhigher, false))
|
||||||
|
.hint(Hint(R.string.profileswitch_hint1))
|
||||||
|
)
|
||||||
|
tasks.add(ExamTask(this, R.string.profileswitchtime_label, R.string.profileswitchtime_iwant, "profileswitchtime")
|
||||||
|
.option(Option(R.string.profileswitchtime_2, false))
|
||||||
|
.option(Option(R.string.profileswitchtime__2, true))
|
||||||
|
.option(Option(R.string.profileswitchtime_tt, false))
|
||||||
|
.option(Option(R.string.profileswitchtime_100, false))
|
||||||
|
.hint(Hint(R.string.profileswitchtime_hint1))
|
||||||
|
)
|
||||||
|
tasks.add(ExamTask(this, R.string.profileswitch4_label, R.string.blank, "profileswitch4")
|
||||||
|
.option(Option(R.string.profileswitch4_rates, true))
|
||||||
|
.option(Option(R.string.profileswitch4_internet, true))
|
||||||
|
.option(Option(R.string.profileswitch4_sufficient, false))
|
||||||
|
.option(Option(R.string.profileswitch4_multi, true))
|
||||||
|
.hint(Hint(R.string.profileswitch_hint1))
|
||||||
|
)
|
||||||
|
tasks.add(ExamTask(this, R.string.exerciseprofile_label, R.string.exerciseprofile_whattodo, "exercise")
|
||||||
|
.option(Option(R.string.exerciseprofile_switchprofileabove100, false))
|
||||||
|
.option(Option(R.string.exerciseprofile_switchprofilebelow100, true))
|
||||||
|
.option(Option(R.string.exerciseprofile_suspendloop, false))
|
||||||
|
.option(Option(R.string.exerciseprofile_leaveat100, false))
|
||||||
|
.hint(Hint(R.string.exerciseprofile_hint1))
|
||||||
|
)
|
||||||
|
tasks.add(ExamTask(this, R.string.exercise_label, R.string.exercise_whattodo, "exercise2")
|
||||||
|
.option(Option(R.string.exercise_settt, true))
|
||||||
|
.option(Option(R.string.exercise_setfinished, false))
|
||||||
|
.option(Option(R.string.exercise_setunchanged, false))
|
||||||
|
.option(Option(R.string.exercise_15g, false))
|
||||||
|
.hint(Hint(R.string.exercise_hint1))
|
||||||
|
)
|
||||||
|
tasks.add(ExamTask(this, R.string.noisycgm_label, R.string.noisycgm_whattodo, "noisycgm")
|
||||||
|
.option(Option(R.string.noisycgm_nothing, false))
|
||||||
|
.option(Option(R.string.noisycgm_pause, true))
|
||||||
|
.option(Option(R.string.noisycgm_replacesensor, true))
|
||||||
|
.option(Option(R.string.noisycgm_checksmoothing, true))
|
||||||
|
.hint(Hint(R.string.noisycgm_hint1))
|
||||||
|
)
|
||||||
|
tasks.add(ExamTask(this, R.string.pumpdisconnect_label, R.string.blank, "pumpdisconnect")
|
||||||
|
.option(Option(R.string.pumpdisconnect_unnecessary, false))
|
||||||
|
.option(Option(R.string.pumpdisconnect_missinginsulin, true))
|
||||||
|
.option(Option(R.string.pumpdisconnect_notstop, false))
|
||||||
|
.option(Option(R.string.pumpdisconnect_openloop, false))
|
||||||
|
.hint(Hint(R.string.pumpdisconnect_hint1))
|
||||||
|
)
|
||||||
|
tasks.add(ExamTask(this, R.string.insulin_label, R.string.insulin_ultrarapid, "insulin")
|
||||||
|
.option(Option(R.string.insulin_novorapid, false))
|
||||||
|
.option(Option(R.string.insulin_humalog, false))
|
||||||
|
.option(Option(R.string.insulin_actrapid, false))
|
||||||
|
.option(Option(R.string.insulin_fiasp, true))
|
||||||
|
.hint(Hint(R.string.insulin_hint1))
|
||||||
|
)
|
||||||
|
tasks.add(ExamTask(this, R.string.sensitivity_label, R.string.blank, "sensitivity")
|
||||||
|
.option(Option(R.string.sensitivity_adjust, true))
|
||||||
|
.option(Option(R.string.sensitivity_edit, false))
|
||||||
|
.option(Option(R.string.sensitivity_cannula, true))
|
||||||
|
.option(Option(R.string.sensitivity_time, true))
|
||||||
|
.hint(Hint(R.string.sensitivity_hint1))
|
||||||
|
)
|
||||||
|
tasks.add(ExamTask(this, R.string.objectives_label, R.string.objectives_howtosave, "objectives")
|
||||||
|
.option(Option(R.string.objectives_notesettings, false))
|
||||||
|
.option(Option(R.string.objectives_afterobjective, true))
|
||||||
|
.option(Option(R.string.objectives_afterchange, true))
|
||||||
|
.option(Option(R.string.objectives_afterinitialsetup, true))
|
||||||
|
.hint(Hint(R.string.objectives_hint1))
|
||||||
|
.hint(Hint(R.string.objectives_hint2))
|
||||||
|
)
|
||||||
|
tasks.add(ExamTask(this, R.string.objectives2_label, R.string.objectives_howtosave, "objectives2")
|
||||||
|
.option(Option(R.string.objectives2_maintenance, true))
|
||||||
|
.option(Option(R.string.objectives2_internalstorage, true))
|
||||||
|
.option(Option(R.string.objectives2_cloud, true))
|
||||||
|
.option(Option(R.string.objectives2_easyrestore, false))
|
||||||
|
.hint(Hint(R.string.objectives_hint1))
|
||||||
|
.hint(Hint(R.string.objectives_hint2))
|
||||||
|
)
|
||||||
|
tasks.add(ExamTask(this, R.string.update_label, R.string.blank, "update")
|
||||||
|
.option(Option(R.string.update_git, true))
|
||||||
|
.option(Option(R.string.update_askfriend, false))
|
||||||
|
.option(Option(R.string.update_keys, true))
|
||||||
|
.option(Option(R.string.update_asap, true))
|
||||||
|
.hint(Hint(R.string.update_hint1))
|
||||||
|
)
|
||||||
|
tasks.add(ExamTask(this, R.string.troubleshooting_label, R.string.troubleshooting_wheretoask, "troubleshooting")
|
||||||
|
.option(Option(R.string.troubleshooting_fb, true))
|
||||||
|
.option(Option(R.string.troubleshooting_wiki, true))
|
||||||
|
.option(Option(R.string.troubleshooting_gitter, true))
|
||||||
|
.option(Option(R.string.troubleshooting_yourendo, false))
|
||||||
|
.hint(Hint(R.string.troubleshooting_hint1))
|
||||||
|
.hint(Hint(R.string.troubleshooting_hint2))
|
||||||
|
.hint(Hint(R.string.troubleshooting_hint3))
|
||||||
|
)
|
||||||
|
tasks.add(ExamTask(this, R.string.wrongcarbs_label, R.string.wrongcarbs_whattodo, "wrongcarbs")
|
||||||
|
.option(Option(R.string.wrongcarbs_addinsulin, false))
|
||||||
|
.option(Option(R.string.wrongcarbs_treatmentstab, true))
|
||||||
|
.option(Option(R.string.wrongcarbs_donothing, false))
|
||||||
|
.option(Option(R.string.wrongcarbs_bolus, false))
|
||||||
|
)
|
||||||
|
tasks.add(ExamTask(this, R.string.wronginsulin_label, R.string.wronginsulin_whattodo, "wronginsulin")
|
||||||
|
.option(Option(R.string.wronginsulin_careportal, false))
|
||||||
|
.option(Option(R.string.wronginsulin_compare, true))
|
||||||
|
.option(Option(R.string.wronginsulin_prime, true))
|
||||||
|
.option(Option(R.string.wrongcarbs_donothing, false))
|
||||||
|
)
|
||||||
|
tasks.add(ExamTask(this, R.string.iob_label, R.string.blank, "iob")
|
||||||
|
.option(Option(R.string.iob_value, true))
|
||||||
|
.option(Option(R.string.iob_hightemp, false))
|
||||||
|
.option(Option(R.string.iob_negiob, true))
|
||||||
|
.option(Option(R.string.iob_posiob, true))
|
||||||
|
)
|
||||||
|
tasks.add(ExamTask(this, R.string.breadgrams_label, R.string.blank, "breadgrams")
|
||||||
|
.option(Option(R.string.breadgrams_grams, true))
|
||||||
|
.option(Option(R.string.breadgrams_exchange, false))
|
||||||
|
.option(Option(R.string.breadgrams_decay, true))
|
||||||
|
.option(Option(R.string.breadgrams_calc, true))
|
||||||
|
.hint(Hint(R.string.breadgrams_hint1))
|
||||||
|
)
|
||||||
|
tasks.add(ExamTask(this, R.string.extendedcarbs_label, R.string.extendedcarbs_handling, "extendedcarbs")
|
||||||
|
.option(Option(R.string.extendedcarbs_future, true))
|
||||||
|
.option(Option(R.string.extendedcarbs_free, false))
|
||||||
|
.option(Option(R.string.extendedcarbs_fat, true))
|
||||||
|
.option(Option(R.string.extendedcarbs_rescue, false))
|
||||||
|
.hint(Hint(R.string.extendedcarbs_hint1))
|
||||||
|
)
|
||||||
|
tasks.add(ExamTask(this, R.string.nsclient_label, R.string.nsclient_howcanyou, "nsclient")
|
||||||
|
.option(Option(R.string.nsclient_nightscout, true))
|
||||||
|
.option(Option(R.string.nsclient_dexcomfollow, true))
|
||||||
|
.option(Option(R.string.nsclient_data, true))
|
||||||
|
.option(Option(R.string.nsclient_fullcontrol, false))
|
||||||
|
.hint(Hint(R.string.nsclient_hint1))
|
||||||
|
)
|
||||||
|
tasks.add(ExamTask(this, R.string.other_medication_label, R.string.other_medication_text, "otherMedicationWarning")
|
||||||
|
.option(Option(R.string.yes, true))
|
||||||
|
.option(Option(R.string.no, false))
|
||||||
|
)
|
||||||
|
for (task in tasks) (task as ExamTask).options.shuffle()
|
||||||
|
|
||||||
|
for (task in tasks) {
|
||||||
|
if (!task.isCompleted()) accomplishedOn = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,61 +0,0 @@
|
||||||
package info.nightscout.androidaps.plugins.constraints.objectives.objectives;
|
|
||||||
|
|
||||||
import androidx.fragment.app.FragmentActivity;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import javax.inject.Inject;
|
|
||||||
|
|
||||||
import dagger.android.HasAndroidInjector;
|
|
||||||
import info.nightscout.androidaps.R;
|
|
||||||
import info.nightscout.androidaps.plugins.constraints.objectives.ObjectivesPlugin;
|
|
||||||
import info.nightscout.androidaps.plugins.general.nsclient.NSClientPlugin;
|
|
||||||
import info.nightscout.androidaps.plugins.general.nsclient.services.NSClientService;
|
|
||||||
import info.nightscout.androidaps.utils.T;
|
|
||||||
import info.nightscout.androidaps.utils.resources.ResourceHelper;
|
|
||||||
import info.nightscout.androidaps.utils.sharedPreferences.SP;
|
|
||||||
|
|
||||||
public class Objective3 extends Objective {
|
|
||||||
@Inject SP sp;
|
|
||||||
@Inject ObjectivesPlugin objectivesPlugin;
|
|
||||||
@Inject ResourceHelper resourceHelper;
|
|
||||||
@Inject NSClientPlugin nsClientPlugin;
|
|
||||||
|
|
||||||
private final int MANUAL_ENACTS_NEEDED = 20;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
public Objective3(HasAndroidInjector injector) {
|
|
||||||
super(injector, "openloop", R.string.objectives_openloop_objective, R.string.objectives_openloop_gate);
|
|
||||||
// disable option for skipping objectives for now
|
|
||||||
// hasSpecialInput = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void setupTasks(List<Task> tasks) {
|
|
||||||
tasks.add(new MinimumDurationTask(T.days(7).msecs()));
|
|
||||||
tasks.add(new Task(R.string.objectives_manualenacts) {
|
|
||||||
@Override
|
|
||||||
public boolean isCompleted() {
|
|
||||||
return sp.getInt(R.string.key_ObjectivesmanualEnacts, 0) >= MANUAL_ENACTS_NEEDED;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getProgress() {
|
|
||||||
if (sp.getInt(R.string.key_ObjectivesmanualEnacts, 0) >= MANUAL_ENACTS_NEEDED)
|
|
||||||
return resourceHelper.gs(R.string.completed_well_done);
|
|
||||||
else
|
|
||||||
return sp.getInt(R.string.key_ObjectivesmanualEnacts, 0) + " / " + MANUAL_ENACTS_NEEDED;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean specialActionEnabled() {
|
|
||||||
return NSClientService.isConnected && NSClientService.hasWriteAuth;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void specialAction(FragmentActivity activity, String input) {
|
|
||||||
objectivesPlugin.completeObjectives(activity, input);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
package info.nightscout.androidaps.plugins.constraints.objectives.objectives
|
||||||
|
|
||||||
|
import androidx.fragment.app.FragmentActivity
|
||||||
|
import dagger.android.HasAndroidInjector
|
||||||
|
import info.nightscout.androidaps.R
|
||||||
|
import info.nightscout.androidaps.plugins.constraints.objectives.ObjectivesPlugin
|
||||||
|
import info.nightscout.androidaps.plugins.general.nsclient.NSClientPlugin
|
||||||
|
import info.nightscout.androidaps.plugins.general.nsclient.services.NSClientService
|
||||||
|
import info.nightscout.androidaps.utils.T
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
@Suppress("SpellCheckingInspection")
|
||||||
|
class Objective3 @Inject constructor(injector: HasAndroidInjector) : Objective(injector, "openloop", R.string.objectives_openloop_objective, R.string.objectives_openloop_gate) {
|
||||||
|
|
||||||
|
@Inject lateinit var objectivesPlugin: ObjectivesPlugin
|
||||||
|
@Inject lateinit var nsClientPlugin: NSClientPlugin
|
||||||
|
|
||||||
|
init {
|
||||||
|
tasks.add(MinimumDurationTask(this, T.days(7).msecs()))
|
||||||
|
tasks.add(object : Task(this, R.string.objectives_manualenacts) {
|
||||||
|
override fun isCompleted(): Boolean {
|
||||||
|
return sp.getInt(R.string.key_ObjectivesmanualEnacts, 0) >= MANUAL_ENACTS_NEEDED
|
||||||
|
}
|
||||||
|
|
||||||
|
override val progress: String
|
||||||
|
get() = if (sp.getInt(R.string.key_ObjectivesmanualEnacts, 0) >= MANUAL_ENACTS_NEEDED) resourceHelper.gs(R.string.completed_well_done) else sp.getInt(R.string.key_ObjectivesmanualEnacts, 0).toString() + " / " + MANUAL_ENACTS_NEEDED
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun specialActionEnabled(): Boolean =
|
||||||
|
NSClientService.isConnected && NSClientService.hasWriteAuth
|
||||||
|
|
||||||
|
override fun specialAction(activity: FragmentActivity, input: String) {
|
||||||
|
objectivesPlugin.completeObjectives(activity, input)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
private const val MANUAL_ENACTS_NEEDED = 20
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,11 +0,0 @@
|
||||||
package info.nightscout.androidaps.plugins.constraints.objectives.objectives;
|
|
||||||
|
|
||||||
import dagger.android.HasAndroidInjector;
|
|
||||||
import info.nightscout.androidaps.R;
|
|
||||||
|
|
||||||
public class Objective4 extends Objective {
|
|
||||||
|
|
||||||
public Objective4(HasAndroidInjector injector) {
|
|
||||||
super(injector, "maxbasal", R.string.objectives_maxbasal_objective, R.string.objectives_maxbasal_gate);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
package info.nightscout.androidaps.plugins.constraints.objectives.objectives
|
||||||
|
|
||||||
|
import dagger.android.HasAndroidInjector
|
||||||
|
import info.nightscout.androidaps.R
|
||||||
|
|
||||||
|
@Suppress("SpellCheckingInspection")
|
||||||
|
class Objective4(injector: HasAndroidInjector) : Objective(injector, "maxbasal", R.string.objectives_maxbasal_objective, R.string.objectives_maxbasal_gate)
|
|
@ -1,32 +0,0 @@
|
||||||
package info.nightscout.androidaps.plugins.constraints.objectives.objectives;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import javax.inject.Inject;
|
|
||||||
|
|
||||||
import dagger.android.HasAndroidInjector;
|
|
||||||
import info.nightscout.androidaps.R;
|
|
||||||
import info.nightscout.androidaps.interfaces.Constraint;
|
|
||||||
import info.nightscout.androidaps.plugins.constraints.safety.SafetyPlugin;
|
|
||||||
import info.nightscout.androidaps.utils.T;
|
|
||||||
|
|
||||||
public class Objective5 extends Objective {
|
|
||||||
@Inject SafetyPlugin safetyPlugin;
|
|
||||||
|
|
||||||
public Objective5(HasAndroidInjector injector) {
|
|
||||||
super(injector, "maxiobzero", R.string.objectives_maxiobzero_objective, R.string.objectives_maxiobzero_gate);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void setupTasks(List<Task> tasks) {
|
|
||||||
tasks.add(new MinimumDurationTask(T.days(5).msecs()));
|
|
||||||
tasks.add(new Task(R.string.closedmodeenabled) {
|
|
||||||
@Override
|
|
||||||
public boolean isCompleted() {
|
|
||||||
Constraint<Boolean> closedLoopEnabled = new Constraint<>(true);
|
|
||||||
safetyPlugin.isClosedLoopAllowed(closedLoopEnabled);
|
|
||||||
return closedLoopEnabled.value();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
package info.nightscout.androidaps.plugins.constraints.objectives.objectives
|
||||||
|
|
||||||
|
import dagger.android.HasAndroidInjector
|
||||||
|
import info.nightscout.androidaps.R
|
||||||
|
import info.nightscout.androidaps.interfaces.Constraint
|
||||||
|
import info.nightscout.androidaps.plugins.constraints.safety.SafetyPlugin
|
||||||
|
import info.nightscout.androidaps.utils.T
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
@Suppress("SpellCheckingInspection")
|
||||||
|
class Objective5(injector: HasAndroidInjector) : Objective(injector, "maxiobzero", R.string.objectives_maxiobzero_objective, R.string.objectives_maxiobzero_gate) {
|
||||||
|
|
||||||
|
@Inject lateinit var safetyPlugin: SafetyPlugin
|
||||||
|
|
||||||
|
init {
|
||||||
|
tasks.add(MinimumDurationTask(this, T.days(5).msecs()))
|
||||||
|
tasks.add(object : Task(this, R.string.closedmodeenabled) {
|
||||||
|
override fun isCompleted(): Boolean {
|
||||||
|
val closedLoopEnabled = Constraint(true)
|
||||||
|
safetyPlugin.isClosedLoopAllowed(closedLoopEnabled)
|
||||||
|
return closedLoopEnabled.value()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,30 +0,0 @@
|
||||||
package info.nightscout.androidaps.plugins.constraints.objectives.objectives;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import javax.inject.Inject;
|
|
||||||
|
|
||||||
import dagger.android.HasAndroidInjector;
|
|
||||||
import info.nightscout.androidaps.R;
|
|
||||||
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker;
|
|
||||||
import info.nightscout.androidaps.utils.T;
|
|
||||||
|
|
||||||
public class Objective6 extends Objective {
|
|
||||||
@Inject ConstraintChecker constraintChecker;
|
|
||||||
|
|
||||||
public Objective6(HasAndroidInjector injector) {
|
|
||||||
super(injector, "maxiob", R.string.objectives_maxiob_objective, R.string.objectives_maxiob_gate);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void setupTasks(List<Task> tasks) {
|
|
||||||
tasks.add(new MinimumDurationTask(T.days(1).msecs()));
|
|
||||||
tasks.add(new Task(R.string.maxiobset) {
|
|
||||||
@Override
|
|
||||||
public boolean isCompleted() {
|
|
||||||
double maxIOB = constraintChecker.getMaxIOBAllowed().value();
|
|
||||||
return maxIOB > 0;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
package info.nightscout.androidaps.plugins.constraints.objectives.objectives
|
||||||
|
|
||||||
|
import dagger.android.HasAndroidInjector
|
||||||
|
import info.nightscout.androidaps.R
|
||||||
|
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
|
||||||
|
import info.nightscout.androidaps.utils.T
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
@Suppress("SpellCheckingInspection")
|
||||||
|
class Objective6(injector: HasAndroidInjector) : Objective(injector, "maxiob", R.string.objectives_maxiob_objective, R.string.objectives_maxiob_gate) {
|
||||||
|
|
||||||
|
@Inject lateinit var constraintChecker: ConstraintChecker
|
||||||
|
|
||||||
|
init {
|
||||||
|
tasks.add(MinimumDurationTask(this, T.days(1).msecs()))
|
||||||
|
tasks.add(object : Task(this, R.string.maxiobset) {
|
||||||
|
override fun isCompleted(): Boolean {
|
||||||
|
val maxIOB = constraintChecker.getMaxIOBAllowed().value()
|
||||||
|
return maxIOB > 0
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,19 +0,0 @@
|
||||||
package info.nightscout.androidaps.plugins.constraints.objectives.objectives;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import dagger.android.HasAndroidInjector;
|
|
||||||
import info.nightscout.androidaps.R;
|
|
||||||
import info.nightscout.androidaps.utils.T;
|
|
||||||
|
|
||||||
public class Objective7 extends Objective {
|
|
||||||
|
|
||||||
public Objective7(HasAndroidInjector injector) {
|
|
||||||
super(injector, "autosens", R.string.objectives_autosens_objective, R.string.objectives_autosens_gate);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void setupTasks(List<Task> tasks) {
|
|
||||||
tasks.add(new MinimumDurationTask(T.days(7).msecs()));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
package info.nightscout.androidaps.plugins.constraints.objectives.objectives
|
||||||
|
|
||||||
|
import dagger.android.HasAndroidInjector
|
||||||
|
import info.nightscout.androidaps.R
|
||||||
|
import info.nightscout.androidaps.utils.T
|
||||||
|
|
||||||
|
class Objective7(injector: HasAndroidInjector) : Objective(injector, "autosens", R.string.objectives_autosens_objective, R.string.objectives_autosens_gate) {
|
||||||
|
|
||||||
|
init {
|
||||||
|
tasks.add(MinimumDurationTask(this, T.days(7).msecs()))
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,19 +0,0 @@
|
||||||
package info.nightscout.androidaps.plugins.constraints.objectives.objectives;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import dagger.android.HasAndroidInjector;
|
|
||||||
import info.nightscout.androidaps.R;
|
|
||||||
import info.nightscout.androidaps.utils.T;
|
|
||||||
|
|
||||||
public class Objective8 extends Objective {
|
|
||||||
|
|
||||||
public Objective8(HasAndroidInjector injector) {
|
|
||||||
super(injector, "ama", R.string.objectives_ama_objective, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void setupTasks(List<Task> tasks) {
|
|
||||||
tasks.add(new MinimumDurationTask(T.days(28).msecs()));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
package info.nightscout.androidaps.plugins.constraints.objectives.objectives
|
||||||
|
|
||||||
|
import dagger.android.HasAndroidInjector
|
||||||
|
import info.nightscout.androidaps.R
|
||||||
|
import info.nightscout.androidaps.utils.T
|
||||||
|
|
||||||
|
class Objective8(injector: HasAndroidInjector) : Objective(injector, "ama", R.string.objectives_ama_objective, 0) {
|
||||||
|
|
||||||
|
init {
|
||||||
|
tasks.add(MinimumDurationTask(this, T.days(28).msecs()))
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,19 +0,0 @@
|
||||||
package info.nightscout.androidaps.plugins.constraints.objectives.objectives;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import dagger.android.HasAndroidInjector;
|
|
||||||
import info.nightscout.androidaps.R;
|
|
||||||
import info.nightscout.androidaps.utils.T;
|
|
||||||
|
|
||||||
public class Objective9 extends Objective {
|
|
||||||
|
|
||||||
public Objective9(HasAndroidInjector injector) {
|
|
||||||
super(injector, "smb", R.string.objectives_smb_objective, R.string.objectives_smb_gate);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void setupTasks(List<Task> tasks) {
|
|
||||||
tasks.add(new MinimumDurationTask(T.days(28).msecs()));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
package info.nightscout.androidaps.plugins.constraints.objectives.objectives
|
||||||
|
|
||||||
|
import dagger.android.HasAndroidInjector
|
||||||
|
import info.nightscout.androidaps.R
|
||||||
|
import info.nightscout.androidaps.utils.T
|
||||||
|
|
||||||
|
class Objective9(injector: HasAndroidInjector) : Objective(injector, "smb", R.string.objectives_smb_objective, R.string.objectives_smb_gate) {
|
||||||
|
|
||||||
|
init {
|
||||||
|
tasks.add(MinimumDurationTask(this, T.days(28).msecs()))
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,289 +0,0 @@
|
||||||
package info.nightscout.androidaps.plugins.constraints.safety;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
|
|
||||||
import javax.inject.Inject;
|
|
||||||
import javax.inject.Singleton;
|
|
||||||
|
|
||||||
import dagger.android.HasAndroidInjector;
|
|
||||||
import info.nightscout.androidaps.Config;
|
|
||||||
import info.nightscout.androidaps.R;
|
|
||||||
import info.nightscout.androidaps.data.Profile;
|
|
||||||
import info.nightscout.androidaps.interfaces.ActivePluginProvider;
|
|
||||||
import info.nightscout.androidaps.interfaces.BgSourceInterface;
|
|
||||||
import info.nightscout.androidaps.interfaces.Constraint;
|
|
||||||
import info.nightscout.androidaps.interfaces.ConstraintsInterface;
|
|
||||||
import info.nightscout.androidaps.interfaces.PluginBase;
|
|
||||||
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.logging.AAPSLogger;
|
|
||||||
import info.nightscout.androidaps.plugins.aps.openAPSAMA.OpenAPSAMAPlugin;
|
|
||||||
import info.nightscout.androidaps.plugins.aps.openAPSSMB.OpenAPSSMBPlugin;
|
|
||||||
import info.nightscout.androidaps.plugins.bus.RxBusWrapper;
|
|
||||||
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker;
|
|
||||||
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;
|
|
||||||
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin;
|
|
||||||
import info.nightscout.androidaps.utils.DecimalFormatter;
|
|
||||||
import info.nightscout.androidaps.utils.HardLimits;
|
|
||||||
import info.nightscout.androidaps.utils.Round;
|
|
||||||
import info.nightscout.androidaps.utils.buildHelper.BuildHelper;
|
|
||||||
import info.nightscout.androidaps.utils.resources.ResourceHelper;
|
|
||||||
import info.nightscout.androidaps.utils.sharedPreferences.SP;
|
|
||||||
|
|
||||||
@Singleton
|
|
||||||
public class SafetyPlugin extends PluginBase implements ConstraintsInterface {
|
|
||||||
|
|
||||||
private final SP sp;
|
|
||||||
private final RxBusWrapper rxBus;
|
|
||||||
private final ConstraintChecker constraintChecker;
|
|
||||||
private final OpenAPSAMAPlugin openAPSAMAPlugin;
|
|
||||||
private final OpenAPSSMBPlugin openAPSSMBPlugin;
|
|
||||||
private final SensitivityOref1Plugin sensitivityOref1Plugin;
|
|
||||||
private final ActivePluginProvider activePlugin;
|
|
||||||
private final HardLimits hardLimits;
|
|
||||||
private final BuildHelper buildHelper;
|
|
||||||
private final TreatmentsPlugin treatmentsPlugin;
|
|
||||||
private final Config config;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
public SafetyPlugin(
|
|
||||||
HasAndroidInjector injector,
|
|
||||||
AAPSLogger aapsLogger,
|
|
||||||
ResourceHelper resourceHelper,
|
|
||||||
SP sp,
|
|
||||||
RxBusWrapper rxBus,
|
|
||||||
ConstraintChecker constraintChecker,
|
|
||||||
OpenAPSAMAPlugin openAPSAMAPlugin,
|
|
||||||
OpenAPSSMBPlugin openAPSSMBPlugin,
|
|
||||||
SensitivityOref1Plugin sensitivityOref1Plugin,
|
|
||||||
ActivePluginProvider activePlugin,
|
|
||||||
HardLimits hardLimits,
|
|
||||||
BuildHelper buildHelper,
|
|
||||||
TreatmentsPlugin treatmentsPlugin,
|
|
||||||
Config config
|
|
||||||
) {
|
|
||||||
super(new PluginDescription()
|
|
||||||
.mainType(PluginType.CONSTRAINTS)
|
|
||||||
.neverVisible(true)
|
|
||||||
.alwaysEnabled(true)
|
|
||||||
.showInList(false)
|
|
||||||
.pluginName(R.string.safety)
|
|
||||||
.preferencesId(R.xml.pref_safety),
|
|
||||||
aapsLogger, resourceHelper, injector
|
|
||||||
);
|
|
||||||
this.sp = sp;
|
|
||||||
this.rxBus = rxBus;
|
|
||||||
this.constraintChecker = constraintChecker;
|
|
||||||
this.openAPSAMAPlugin = openAPSAMAPlugin;
|
|
||||||
this.openAPSSMBPlugin = openAPSSMBPlugin;
|
|
||||||
this.sensitivityOref1Plugin = sensitivityOref1Plugin;
|
|
||||||
this.activePlugin = activePlugin;
|
|
||||||
this.hardLimits = hardLimits;
|
|
||||||
this.buildHelper = buildHelper;
|
|
||||||
this.treatmentsPlugin = treatmentsPlugin;
|
|
||||||
this.config = config;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constraints interface
|
|
||||||
**/
|
|
||||||
@NonNull @Override
|
|
||||||
public Constraint<Boolean> isLoopInvocationAllowed(@NonNull Constraint<Boolean> value) {
|
|
||||||
if (!activePlugin.getActivePump().getPumpDescription().isTempBasalCapable)
|
|
||||||
value.set(getAapsLogger(), false, getResourceHelper().gs(R.string.pumpisnottempbasalcapable), this);
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull @Override
|
|
||||||
public Constraint<Boolean> isClosedLoopAllowed(@NonNull Constraint<Boolean> value) {
|
|
||||||
String mode = sp.getString(R.string.key_aps_mode, "open");
|
|
||||||
if ((mode.equals("open")))
|
|
||||||
value.set(getAapsLogger(), false, getResourceHelper().gs(R.string.closedmodedisabledinpreferences), this);
|
|
||||||
|
|
||||||
if (!buildHelper.isEngineeringModeOrRelease()) {
|
|
||||||
if (value.value()) {
|
|
||||||
Notification n = new Notification(Notification.TOAST_ALARM, getResourceHelper().gs(R.string.closed_loop_disabled_on_dev_branch), Notification.NORMAL);
|
|
||||||
rxBus.send(new EventNewNotification(n));
|
|
||||||
}
|
|
||||||
value.set(getAapsLogger(), false, getResourceHelper().gs(R.string.closed_loop_disabled_on_dev_branch), this);
|
|
||||||
}
|
|
||||||
PumpInterface pump = activePlugin.getActivePump();
|
|
||||||
if (!pump.isFakingTempsByExtendedBoluses() && treatmentsPlugin.isInHistoryExtendedBoluslInProgress()) {
|
|
||||||
value.set(getAapsLogger(), false, getResourceHelper().gs(R.string.closed_loop_disabled_with_eb), this);
|
|
||||||
}
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull @Override
|
|
||||||
public Constraint<Boolean> isAutosensModeEnabled(@NonNull Constraint<Boolean> value) {
|
|
||||||
boolean enabled = sp.getBoolean(R.string.key_openapsama_useautosens, false);
|
|
||||||
if (!enabled)
|
|
||||||
value.set(getAapsLogger(), false, getResourceHelper().gs(R.string.autosensdisabledinpreferences), this);
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull @Override
|
|
||||||
public Constraint<Boolean> isSMBModeEnabled(@NonNull Constraint<Boolean> value) {
|
|
||||||
boolean enabled = sp.getBoolean(R.string.key_use_smb, false);
|
|
||||||
if (!enabled)
|
|
||||||
value.set(getAapsLogger(), false, getResourceHelper().gs(R.string.smbdisabledinpreferences), this);
|
|
||||||
Constraint<Boolean> closedLoop = constraintChecker.isClosedLoopAllowed();
|
|
||||||
if (!closedLoop.value())
|
|
||||||
value.set(getAapsLogger(), false, getResourceHelper().gs(R.string.smbnotallowedinopenloopmode), this);
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull @Override
|
|
||||||
public Constraint<Boolean> isUAMEnabled(@NonNull Constraint<Boolean> value) {
|
|
||||||
boolean enabled = sp.getBoolean(R.string.key_use_uam, false);
|
|
||||||
if (!enabled)
|
|
||||||
value.set(getAapsLogger(), false, getResourceHelper().gs(R.string.uamdisabledinpreferences), this);
|
|
||||||
boolean oref1Enabled = sensitivityOref1Plugin.isEnabled(PluginType.SENSITIVITY);
|
|
||||||
if (!oref1Enabled)
|
|
||||||
value.set(getAapsLogger(), false, getResourceHelper().gs(R.string.uamdisabledoref1notselected), this);
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull @Override
|
|
||||||
public Constraint<Boolean> isAdvancedFilteringEnabled(@NonNull Constraint<Boolean> value) {
|
|
||||||
BgSourceInterface bgSource = activePlugin.getActiveBgSource();
|
|
||||||
|
|
||||||
if (!bgSource.advancedFilteringSupported())
|
|
||||||
value.set(getAapsLogger(), false, getResourceHelper().gs(R.string.smbalwaysdisabled), this);
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull @Override
|
|
||||||
public Constraint<Double> applyBasalConstraints(Constraint<Double> absoluteRate, @NonNull Profile profile) {
|
|
||||||
|
|
||||||
absoluteRate.setIfGreater(getAapsLogger(), 0d, String.format(getResourceHelper().gs(R.string.limitingbasalratio), 0d, getResourceHelper().gs(R.string.itmustbepositivevalue)), this);
|
|
||||||
|
|
||||||
if (config.getAPS()) {
|
|
||||||
double maxBasal = sp.getDouble(R.string.key_openapsma_max_basal, 1d);
|
|
||||||
if (maxBasal < profile.getMaxDailyBasal()) {
|
|
||||||
maxBasal = profile.getMaxDailyBasal();
|
|
||||||
absoluteRate.addReason(getResourceHelper().gs(R.string.increasingmaxbasal), this);
|
|
||||||
}
|
|
||||||
absoluteRate.setIfSmaller(getAapsLogger(), maxBasal, String.format(getResourceHelper().gs(R.string.limitingbasalratio), maxBasal, getResourceHelper().gs(R.string.maxvalueinpreferences)), this);
|
|
||||||
|
|
||||||
// Check percentRate but absolute rate too, because we know real current basal in pump
|
|
||||||
double maxBasalMult = sp.getDouble(R.string.key_openapsama_current_basal_safety_multiplier, 4d);
|
|
||||||
double maxFromBasalMult = Math.floor(maxBasalMult * profile.getBasal() * 100) / 100;
|
|
||||||
absoluteRate.setIfSmaller(getAapsLogger(), maxFromBasalMult, String.format(getResourceHelper().gs(R.string.limitingbasalratio), maxFromBasalMult, getResourceHelper().gs(R.string.maxbasalmultiplier)), this);
|
|
||||||
|
|
||||||
double maxBasalFromDaily = sp.getDouble(R.string.key_openapsama_max_daily_safety_multiplier, 3d);
|
|
||||||
double maxFromDaily = Math.floor(profile.getMaxDailyBasal() * maxBasalFromDaily * 100) / 100;
|
|
||||||
absoluteRate.setIfSmaller(getAapsLogger(), maxFromDaily, String.format(getResourceHelper().gs(R.string.limitingbasalratio), maxFromDaily, getResourceHelper().gs(R.string.maxdailybasalmultiplier)), this);
|
|
||||||
}
|
|
||||||
|
|
||||||
absoluteRate.setIfSmaller(getAapsLogger(), hardLimits.maxBasal(), String.format(getResourceHelper().gs(R.string.limitingbasalratio), hardLimits.maxBasal(), getResourceHelper().gs(R.string.hardlimit)), this);
|
|
||||||
|
|
||||||
PumpInterface pump = activePlugin.getActivePump();
|
|
||||||
// check for pump max
|
|
||||||
if (pump.getPumpDescription().tempBasalStyle == PumpDescription.ABSOLUTE) {
|
|
||||||
double pumpLimit = pump.getPumpDescription().pumpType.getTbrSettings().getMaxDose();
|
|
||||||
absoluteRate.setIfSmaller(getAapsLogger(), pumpLimit, String.format(getResourceHelper().gs(R.string.limitingbasalratio), pumpLimit, getResourceHelper().gs(R.string.pumplimit)), this);
|
|
||||||
}
|
|
||||||
|
|
||||||
// do rounding
|
|
||||||
if (pump.getPumpDescription().tempBasalStyle == PumpDescription.ABSOLUTE) {
|
|
||||||
absoluteRate.set(getAapsLogger(), Round.roundTo(absoluteRate.value(), pump.getPumpDescription().tempAbsoluteStep));
|
|
||||||
}
|
|
||||||
return absoluteRate;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull @Override
|
|
||||||
public Constraint<Integer> applyBasalPercentConstraints(Constraint<Integer> percentRate, Profile profile) {
|
|
||||||
|
|
||||||
Double currentBasal = profile.getBasal();
|
|
||||||
double absoluteRate = currentBasal * ((double) percentRate.originalValue() / 100);
|
|
||||||
|
|
||||||
percentRate.addReason("Percent rate " + percentRate.originalValue() + "% recalculated to " + DecimalFormatter.to2Decimal(absoluteRate) + " U/h with current basal " + DecimalFormatter.to2Decimal(currentBasal) + " U/h", this);
|
|
||||||
|
|
||||||
Constraint<Double> absoluteConstraint = new Constraint<>(absoluteRate);
|
|
||||||
applyBasalConstraints(absoluteConstraint, profile);
|
|
||||||
percentRate.copyReasons(absoluteConstraint);
|
|
||||||
|
|
||||||
PumpInterface pump = activePlugin.getActivePump();
|
|
||||||
|
|
||||||
int percentRateAfterConst = Double.valueOf(absoluteConstraint.value() / currentBasal * 100).intValue();
|
|
||||||
if (percentRateAfterConst < 100)
|
|
||||||
percentRateAfterConst = Round.ceilTo((double) percentRateAfterConst, (double) pump.getPumpDescription().tempPercentStep).intValue();
|
|
||||||
else
|
|
||||||
percentRateAfterConst = Round.floorTo((double) percentRateAfterConst, (double) pump.getPumpDescription().tempPercentStep).intValue();
|
|
||||||
|
|
||||||
percentRate.set(getAapsLogger(), percentRateAfterConst, String.format(getResourceHelper().gs(R.string.limitingpercentrate), percentRateAfterConst, getResourceHelper().gs(R.string.pumplimit)), this);
|
|
||||||
|
|
||||||
if (pump.getPumpDescription().tempBasalStyle == PumpDescription.PERCENT) {
|
|
||||||
double pumpLimit = pump.getPumpDescription().pumpType.getTbrSettings().getMaxDose();
|
|
||||||
percentRate.setIfSmaller(getAapsLogger(), (int) pumpLimit, String.format(getResourceHelper().gs(R.string.limitingbasalratio), pumpLimit, getResourceHelper().gs(R.string.pumplimit)), this);
|
|
||||||
}
|
|
||||||
|
|
||||||
return percentRate;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull @Override
|
|
||||||
public Constraint<Double> applyBolusConstraints(Constraint<Double> insulin) {
|
|
||||||
insulin.setIfGreater(getAapsLogger(), 0d, String.format(getResourceHelper().gs(R.string.limitingbolus), 0d, getResourceHelper().gs(R.string.itmustbepositivevalue)), this);
|
|
||||||
|
|
||||||
Double maxBolus = sp.getDouble(R.string.key_treatmentssafety_maxbolus, 3d);
|
|
||||||
insulin.setIfSmaller(getAapsLogger(), maxBolus, String.format(getResourceHelper().gs(R.string.limitingbolus), maxBolus, getResourceHelper().gs(R.string.maxvalueinpreferences)), this);
|
|
||||||
|
|
||||||
insulin.setIfSmaller(getAapsLogger(), hardLimits.maxBolus(), String.format(getResourceHelper().gs(R.string.limitingbolus), hardLimits.maxBolus(), getResourceHelper().gs(R.string.hardlimit)), this);
|
|
||||||
|
|
||||||
PumpInterface pump = activePlugin.getActivePump();
|
|
||||||
double rounded = pump.getPumpDescription().pumpType.determineCorrectBolusSize(insulin.value());
|
|
||||||
insulin.setIfDifferent(getAapsLogger(), rounded, getResourceHelper().gs(R.string.pumplimit), this);
|
|
||||||
return insulin;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull @Override
|
|
||||||
public Constraint<Double> applyExtendedBolusConstraints(Constraint<Double> insulin) {
|
|
||||||
insulin.setIfGreater(getAapsLogger(), 0d, String.format(getResourceHelper().gs(R.string.limitingextendedbolus), 0d, getResourceHelper().gs(R.string.itmustbepositivevalue)), this);
|
|
||||||
|
|
||||||
Double maxBolus = sp.getDouble(R.string.key_treatmentssafety_maxbolus, 3d);
|
|
||||||
insulin.setIfSmaller(getAapsLogger(), maxBolus, String.format(getResourceHelper().gs(R.string.limitingextendedbolus), maxBolus, getResourceHelper().gs(R.string.maxvalueinpreferences)), this);
|
|
||||||
|
|
||||||
insulin.setIfSmaller(getAapsLogger(), hardLimits.maxBolus(), String.format(getResourceHelper().gs(R.string.limitingextendedbolus), hardLimits.maxBolus(), getResourceHelper().gs(R.string.hardlimit)), this);
|
|
||||||
|
|
||||||
PumpInterface pump = activePlugin.getActivePump();
|
|
||||||
double rounded = pump.getPumpDescription().pumpType.determineCorrectExtendedBolusSize(insulin.value());
|
|
||||||
insulin.setIfDifferent(getAapsLogger(), rounded, getResourceHelper().gs(R.string.pumplimit), this);
|
|
||||||
return insulin;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull @Override
|
|
||||||
public Constraint<Integer> applyCarbsConstraints(Constraint<Integer> carbs) {
|
|
||||||
carbs.setIfGreater(getAapsLogger(), 0, String.format(getResourceHelper().gs(R.string.limitingcarbs), 0, getResourceHelper().gs(R.string.itmustbepositivevalue)), this);
|
|
||||||
|
|
||||||
Integer maxCarbs = sp.getInt(R.string.key_treatmentssafety_maxcarbs, 48);
|
|
||||||
carbs.setIfSmaller(getAapsLogger(), maxCarbs, String.format(getResourceHelper().gs(R.string.limitingcarbs), maxCarbs, getResourceHelper().gs(R.string.maxvalueinpreferences)), this);
|
|
||||||
|
|
||||||
return carbs;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull @Override
|
|
||||||
public Constraint<Double> applyMaxIOBConstraints(@NonNull Constraint<Double> maxIob) {
|
|
||||||
double maxIobPref;
|
|
||||||
String apsmode = sp.getString(R.string.key_aps_mode, "open");
|
|
||||||
if (openAPSSMBPlugin.isEnabled(PluginType.APS))
|
|
||||||
maxIobPref = sp.getDouble(R.string.key_openapssmb_max_iob, 3d);
|
|
||||||
else
|
|
||||||
maxIobPref = sp.getDouble(R.string.key_openapsma_max_iob, 1.5d);
|
|
||||||
maxIob.setIfSmaller(getAapsLogger(), maxIobPref, String.format(getResourceHelper().gs(R.string.limitingiob), maxIobPref, getResourceHelper().gs(R.string.maxvalueinpreferences)), this);
|
|
||||||
|
|
||||||
if (openAPSAMAPlugin.isEnabled(PluginType.APS))
|
|
||||||
maxIob.setIfSmaller(getAapsLogger(), hardLimits.maxIobAMA(), String.format(getResourceHelper().gs(R.string.limitingiob), hardLimits.maxIobAMA(), getResourceHelper().gs(R.string.hardlimit)), this);
|
|
||||||
if (openAPSSMBPlugin.isEnabled(PluginType.APS))
|
|
||||||
maxIob.setIfSmaller(getAapsLogger(), hardLimits.maxIobSMB(), String.format(getResourceHelper().gs(R.string.limitingiob), hardLimits.maxIobSMB(), getResourceHelper().gs(R.string.hardlimit)), this);
|
|
||||||
if ((apsmode.equals("lgs")))
|
|
||||||
maxIob.setIfSmaller(getAapsLogger(), hardLimits.getMAXIOB_LGS(), String.format(getResourceHelper().gs(R.string.limitingiob), hardLimits.getMAXIOB_LGS(), getResourceHelper().gs(R.string.lowglucosesuspend)), this);
|
|
||||||
|
|
||||||
return maxIob;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -0,0 +1,195 @@
|
||||||
|
package info.nightscout.androidaps.plugins.constraints.safety
|
||||||
|
|
||||||
|
import dagger.android.HasAndroidInjector
|
||||||
|
import info.nightscout.androidaps.Config
|
||||||
|
import info.nightscout.androidaps.R
|
||||||
|
import info.nightscout.androidaps.data.Profile
|
||||||
|
import info.nightscout.androidaps.interfaces.*
|
||||||
|
import info.nightscout.androidaps.logging.AAPSLogger
|
||||||
|
import info.nightscout.androidaps.plugins.aps.openAPSAMA.OpenAPSAMAPlugin
|
||||||
|
import info.nightscout.androidaps.plugins.aps.openAPSSMB.OpenAPSSMBPlugin
|
||||||
|
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
||||||
|
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
|
||||||
|
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
|
||||||
|
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin
|
||||||
|
import info.nightscout.androidaps.utils.DecimalFormatter
|
||||||
|
import info.nightscout.androidaps.utils.HardLimits
|
||||||
|
import info.nightscout.androidaps.utils.Round
|
||||||
|
import info.nightscout.androidaps.utils.buildHelper.BuildHelper
|
||||||
|
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||||
|
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
||||||
|
import javax.inject.Inject
|
||||||
|
import javax.inject.Singleton
|
||||||
|
import kotlin.math.floor
|
||||||
|
|
||||||
|
@Singleton
|
||||||
|
class SafetyPlugin @Inject constructor(
|
||||||
|
injector: HasAndroidInjector,
|
||||||
|
aapsLogger: AAPSLogger,
|
||||||
|
resourceHelper: ResourceHelper,
|
||||||
|
private val sp: SP,
|
||||||
|
private val rxBus: RxBusWrapper,
|
||||||
|
private val constraintChecker: ConstraintChecker,
|
||||||
|
private val openAPSAMAPlugin: OpenAPSAMAPlugin,
|
||||||
|
private val openAPSSMBPlugin: OpenAPSSMBPlugin,
|
||||||
|
private val sensitivityOref1Plugin: SensitivityOref1Plugin,
|
||||||
|
private val activePlugin: ActivePluginProvider,
|
||||||
|
private val hardLimits: HardLimits,
|
||||||
|
private val buildHelper: BuildHelper,
|
||||||
|
private val treatmentsPlugin: TreatmentsPlugin,
|
||||||
|
private val config: Config
|
||||||
|
) : PluginBase(PluginDescription()
|
||||||
|
.mainType(PluginType.CONSTRAINTS)
|
||||||
|
.neverVisible(true)
|
||||||
|
.alwaysEnabled(true)
|
||||||
|
.showInList(false)
|
||||||
|
.pluginName(R.string.safety)
|
||||||
|
.preferencesId(R.xml.pref_safety),
|
||||||
|
aapsLogger, resourceHelper, injector
|
||||||
|
), ConstraintsInterface {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constraints interface
|
||||||
|
*/
|
||||||
|
override fun isLoopInvocationAllowed(value: Constraint<Boolean>): Constraint<Boolean> {
|
||||||
|
if (!activePlugin.activePump.pumpDescription.isTempBasalCapable) value[aapsLogger, false, resourceHelper.gs(R.string.pumpisnottempbasalcapable)] = this
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun isClosedLoopAllowed(value: Constraint<Boolean>): Constraint<Boolean> {
|
||||||
|
val mode = sp.getString(R.string.key_aps_mode, "open")
|
||||||
|
if (mode == "open") value[aapsLogger, false, resourceHelper.gs(R.string.closedmodedisabledinpreferences)] = this
|
||||||
|
if (!buildHelper.isEngineeringModeOrRelease()) {
|
||||||
|
if (value.value()) {
|
||||||
|
val n = Notification(Notification.TOAST_ALARM, resourceHelper.gs(R.string.closed_loop_disabled_on_dev_branch), Notification.NORMAL)
|
||||||
|
rxBus.send(EventNewNotification(n))
|
||||||
|
}
|
||||||
|
value[aapsLogger, false, resourceHelper.gs(R.string.closed_loop_disabled_on_dev_branch)] = this
|
||||||
|
}
|
||||||
|
val pump = activePlugin.activePump
|
||||||
|
if (!pump.isFakingTempsByExtendedBoluses && treatmentsPlugin.isInHistoryExtendedBoluslInProgress) {
|
||||||
|
value[aapsLogger, false, resourceHelper.gs(R.string.closed_loop_disabled_with_eb)] = this
|
||||||
|
}
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun isAutosensModeEnabled(value: Constraint<Boolean>): Constraint<Boolean> {
|
||||||
|
val enabled = sp.getBoolean(R.string.key_openapsama_useautosens, false)
|
||||||
|
if (!enabled) value[aapsLogger, false, resourceHelper.gs(R.string.autosensdisabledinpreferences)] = this
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun isSMBModeEnabled(value: Constraint<Boolean>): Constraint<Boolean> {
|
||||||
|
val enabled = sp.getBoolean(R.string.key_use_smb, false)
|
||||||
|
if (!enabled) value[aapsLogger, false, resourceHelper.gs(R.string.smbdisabledinpreferences)] = this
|
||||||
|
val closedLoop = constraintChecker.isClosedLoopAllowed()
|
||||||
|
if (!closedLoop.value()) value[aapsLogger, false, resourceHelper.gs(R.string.smbnotallowedinopenloopmode)] = this
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun isUAMEnabled(value: Constraint<Boolean>): Constraint<Boolean> {
|
||||||
|
val enabled = sp.getBoolean(R.string.key_use_uam, false)
|
||||||
|
if (!enabled) value[aapsLogger, false, resourceHelper.gs(R.string.uamdisabledinpreferences)] = this
|
||||||
|
val oref1Enabled = sensitivityOref1Plugin.isEnabled(PluginType.SENSITIVITY)
|
||||||
|
if (!oref1Enabled) value[aapsLogger, false, resourceHelper.gs(R.string.uamdisabledoref1notselected)] = this
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun isAdvancedFilteringEnabled(value: Constraint<Boolean>): Constraint<Boolean> {
|
||||||
|
val bgSource = activePlugin.activeBgSource
|
||||||
|
if (!bgSource.advancedFilteringSupported()) value[aapsLogger, false, resourceHelper.gs(R.string.smbalwaysdisabled)] = this
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun applyBasalConstraints(absoluteRate: Constraint<Double>, profile: Profile): Constraint<Double> {
|
||||||
|
absoluteRate.setIfGreater(aapsLogger, 0.0, String.format(resourceHelper.gs(R.string.limitingbasalratio), 0.0, resourceHelper.gs(R.string.itmustbepositivevalue)), this)
|
||||||
|
if (config.APS) {
|
||||||
|
var maxBasal = sp.getDouble(R.string.key_openapsma_max_basal, 1.0)
|
||||||
|
if (maxBasal < profile.maxDailyBasal) {
|
||||||
|
maxBasal = profile.maxDailyBasal
|
||||||
|
absoluteRate.addReason(resourceHelper.gs(R.string.increasingmaxbasal), this)
|
||||||
|
}
|
||||||
|
absoluteRate.setIfSmaller(aapsLogger, maxBasal, String.format(resourceHelper.gs(R.string.limitingbasalratio), maxBasal, resourceHelper.gs(R.string.maxvalueinpreferences)), this)
|
||||||
|
|
||||||
|
// Check percentRate but absolute rate too, because we know real current basal in pump
|
||||||
|
val maxBasalMultiplier = sp.getDouble(R.string.key_openapsama_current_basal_safety_multiplier, 4.0)
|
||||||
|
val maxFromBasalMultiplier = floor(maxBasalMultiplier * profile.basal * 100) / 100
|
||||||
|
absoluteRate.setIfSmaller(aapsLogger, maxFromBasalMultiplier, String.format(resourceHelper.gs(R.string.limitingbasalratio), maxFromBasalMultiplier, resourceHelper.gs(R.string.maxbasalmultiplier)), this)
|
||||||
|
val maxBasalFromDaily = sp.getDouble(R.string.key_openapsama_max_daily_safety_multiplier, 3.0)
|
||||||
|
val maxFromDaily = floor(profile.maxDailyBasal * maxBasalFromDaily * 100) / 100
|
||||||
|
absoluteRate.setIfSmaller(aapsLogger, maxFromDaily, String.format(resourceHelper.gs(R.string.limitingbasalratio), maxFromDaily, resourceHelper.gs(R.string.maxdailybasalmultiplier)), this)
|
||||||
|
}
|
||||||
|
absoluteRate.setIfSmaller(aapsLogger, hardLimits.maxBasal(), String.format(resourceHelper.gs(R.string.limitingbasalratio), hardLimits.maxBasal(), resourceHelper.gs(R.string.hardlimit)), this)
|
||||||
|
val pump = activePlugin.activePump
|
||||||
|
// check for pump max
|
||||||
|
if (pump.pumpDescription.tempBasalStyle == PumpDescription.ABSOLUTE) {
|
||||||
|
val pumpLimit = pump.pumpDescription.pumpType.tbrSettings.maxDose
|
||||||
|
absoluteRate.setIfSmaller(aapsLogger, pumpLimit, String.format(resourceHelper.gs(R.string.limitingbasalratio), pumpLimit, resourceHelper.gs(R.string.pumplimit)), this)
|
||||||
|
}
|
||||||
|
|
||||||
|
// do rounding
|
||||||
|
if (pump.pumpDescription.tempBasalStyle == PumpDescription.ABSOLUTE) {
|
||||||
|
absoluteRate[aapsLogger] = Round.roundTo(absoluteRate.value(), pump.pumpDescription.tempAbsoluteStep)
|
||||||
|
}
|
||||||
|
return absoluteRate
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun applyBasalPercentConstraints(percentRate: Constraint<Int>, profile: Profile): Constraint<Int> {
|
||||||
|
val currentBasal = profile.basal
|
||||||
|
val absoluteRate = currentBasal * (percentRate.originalValue().toDouble() / 100)
|
||||||
|
percentRate.addReason("Percent rate " + percentRate.originalValue() + "% recalculated to " + DecimalFormatter.to2Decimal(absoluteRate) + " U/h with current basal " + DecimalFormatter.to2Decimal(currentBasal) + " U/h", this)
|
||||||
|
val absoluteConstraint = Constraint(absoluteRate)
|
||||||
|
applyBasalConstraints(absoluteConstraint, profile)
|
||||||
|
percentRate.copyReasons(absoluteConstraint)
|
||||||
|
val pump = activePlugin.activePump
|
||||||
|
var percentRateAfterConst = java.lang.Double.valueOf(absoluteConstraint.value() / currentBasal * 100).toInt()
|
||||||
|
percentRateAfterConst = if (percentRateAfterConst < 100) Round.ceilTo(percentRateAfterConst.toDouble(), pump.pumpDescription.tempPercentStep.toDouble()).toInt() else Round.floorTo(percentRateAfterConst.toDouble(), pump.pumpDescription.tempPercentStep.toDouble()).toInt()
|
||||||
|
percentRate[aapsLogger, percentRateAfterConst, String.format(resourceHelper.gs(R.string.limitingpercentrate), percentRateAfterConst, resourceHelper.gs(R.string.pumplimit))] = this
|
||||||
|
if (pump.pumpDescription.tempBasalStyle == PumpDescription.PERCENT) {
|
||||||
|
val pumpLimit = pump.pumpDescription.pumpType.tbrSettings.maxDose
|
||||||
|
percentRate.setIfSmaller(aapsLogger, pumpLimit.toInt(), String.format(resourceHelper.gs(R.string.limitingbasalratio), pumpLimit, resourceHelper.gs(R.string.pumplimit)), this)
|
||||||
|
}
|
||||||
|
return percentRate
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun applyBolusConstraints(insulin: Constraint<Double>): Constraint<Double> {
|
||||||
|
insulin.setIfGreater(aapsLogger, 0.0, String.format(resourceHelper.gs(R.string.limitingbolus), 0.0, resourceHelper.gs(R.string.itmustbepositivevalue)), this)
|
||||||
|
val maxBolus = sp.getDouble(R.string.key_treatmentssafety_maxbolus, 3.0)
|
||||||
|
insulin.setIfSmaller(aapsLogger, maxBolus, String.format(resourceHelper.gs(R.string.limitingbolus), maxBolus, resourceHelper.gs(R.string.maxvalueinpreferences)), this)
|
||||||
|
insulin.setIfSmaller(aapsLogger, hardLimits.maxBolus(), String.format(resourceHelper.gs(R.string.limitingbolus), hardLimits.maxBolus(), resourceHelper.gs(R.string.hardlimit)), this)
|
||||||
|
val pump = activePlugin.activePump
|
||||||
|
val rounded = pump.pumpDescription.pumpType.determineCorrectBolusSize(insulin.value())
|
||||||
|
insulin.setIfDifferent(aapsLogger, rounded, resourceHelper.gs(R.string.pumplimit), this)
|
||||||
|
return insulin
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun applyExtendedBolusConstraints(insulin: Constraint<Double>): Constraint<Double> {
|
||||||
|
insulin.setIfGreater(aapsLogger, 0.0, String.format(resourceHelper.gs(R.string.limitingextendedbolus), 0.0, resourceHelper.gs(R.string.itmustbepositivevalue)), this)
|
||||||
|
val maxBolus = sp.getDouble(R.string.key_treatmentssafety_maxbolus, 3.0)
|
||||||
|
insulin.setIfSmaller(aapsLogger, maxBolus, String.format(resourceHelper.gs(R.string.limitingextendedbolus), maxBolus, resourceHelper.gs(R.string.maxvalueinpreferences)), this)
|
||||||
|
insulin.setIfSmaller(aapsLogger, hardLimits.maxBolus(), String.format(resourceHelper.gs(R.string.limitingextendedbolus), hardLimits.maxBolus(), resourceHelper.gs(R.string.hardlimit)), this)
|
||||||
|
val pump = activePlugin.activePump
|
||||||
|
val rounded = pump.pumpDescription.pumpType.determineCorrectExtendedBolusSize(insulin.value())
|
||||||
|
insulin.setIfDifferent(aapsLogger, rounded, resourceHelper.gs(R.string.pumplimit), this)
|
||||||
|
return insulin
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun applyCarbsConstraints(carbs: Constraint<Int>): Constraint<Int> {
|
||||||
|
carbs.setIfGreater(aapsLogger, 0, String.format(resourceHelper.gs(R.string.limitingcarbs), 0, resourceHelper.gs(R.string.itmustbepositivevalue)), this)
|
||||||
|
val maxCarbs = sp.getInt(R.string.key_treatmentssafety_maxcarbs, 48)
|
||||||
|
carbs.setIfSmaller(aapsLogger, maxCarbs, String.format(resourceHelper.gs(R.string.limitingcarbs), maxCarbs, resourceHelper.gs(R.string.maxvalueinpreferences)), this)
|
||||||
|
return carbs
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun applyMaxIOBConstraints(maxIob: Constraint<Double>): Constraint<Double> {
|
||||||
|
val apsMode = sp.getString(R.string.key_aps_mode, "open")
|
||||||
|
val maxIobPref: Double = if (openAPSSMBPlugin.isEnabled(PluginType.APS)) sp.getDouble(R.string.key_openapssmb_max_iob, 3.0) else sp.getDouble(R.string.key_openapsma_max_iob, 1.5)
|
||||||
|
maxIob.setIfSmaller(aapsLogger, maxIobPref, String.format(resourceHelper.gs(R.string.limitingiob), maxIobPref, resourceHelper.gs(R.string.maxvalueinpreferences)), this)
|
||||||
|
if (openAPSAMAPlugin.isEnabled(PluginType.APS)) maxIob.setIfSmaller(aapsLogger, hardLimits.maxIobAMA(), String.format(resourceHelper.gs(R.string.limitingiob), hardLimits.maxIobAMA(), resourceHelper.gs(R.string.hardlimit)), this)
|
||||||
|
if (openAPSSMBPlugin.isEnabled(PluginType.APS)) maxIob.setIfSmaller(aapsLogger, hardLimits.maxIobSMB(), String.format(resourceHelper.gs(R.string.limitingiob), hardLimits.maxIobSMB(), resourceHelper.gs(R.string.hardlimit)), this)
|
||||||
|
if (apsMode == "lgs") maxIob.setIfSmaller(aapsLogger, hardLimits.MAXIOB_LGS, String.format(resourceHelper.gs(R.string.limitingiob), hardLimits.MAXIOB_LGS, resourceHelper.gs(R.string.lowglucosesuspend)), this)
|
||||||
|
return maxIob
|
||||||
|
}
|
||||||
|
}
|
|
@ -33,7 +33,6 @@ import info.nightscout.androidaps.skins.SkinProvider
|
||||||
import info.nightscout.androidaps.utils.FabricPrivacy
|
import info.nightscout.androidaps.utils.FabricPrivacy
|
||||||
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
|
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
|
||||||
import info.nightscout.androidaps.utils.buildHelper.BuildHelper
|
import info.nightscout.androidaps.utils.buildHelper.BuildHelper
|
||||||
import io.reactivex.rxkotlin.plusAssign
|
|
||||||
import info.nightscout.androidaps.utils.extensions.toVisibility
|
import info.nightscout.androidaps.utils.extensions.toVisibility
|
||||||
import info.nightscout.androidaps.utils.protection.ProtectionCheck
|
import info.nightscout.androidaps.utils.protection.ProtectionCheck
|
||||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||||
|
@ -42,6 +41,7 @@ import info.nightscout.androidaps.utils.sharedPreferences.SP
|
||||||
import info.nightscout.androidaps.utils.ui.SingleClickButton
|
import info.nightscout.androidaps.utils.ui.SingleClickButton
|
||||||
import info.nightscout.androidaps.utils.ui.UIRunnable
|
import info.nightscout.androidaps.utils.ui.UIRunnable
|
||||||
import io.reactivex.disposables.CompositeDisposable
|
import io.reactivex.disposables.CompositeDisposable
|
||||||
|
import io.reactivex.rxkotlin.plusAssign
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
@ -158,12 +158,7 @@ class ActionsFragment : DaggerFragment() {
|
||||||
commandQueue.cancelExtended(object : Callback() {
|
commandQueue.cancelExtended(object : Callback() {
|
||||||
override fun run() {
|
override fun run() {
|
||||||
if (!result.success) {
|
if (!result.success) {
|
||||||
val i = Intent(ctx, ErrorHelperActivity::class.java)
|
ErrorHelperActivity.runAlarm(ctx, result.comment, resourceHelper.gs(R.string.extendedbolusdeliveryerror), R.raw.boluserror)
|
||||||
i.putExtra("soundid", R.raw.boluserror)
|
|
||||||
i.putExtra("status", result.comment)
|
|
||||||
i.putExtra("title", resourceHelper.gs(R.string.extendedbolusdeliveryerror))
|
|
||||||
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
|
||||||
ctx.startActivity(i)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -178,12 +173,7 @@ class ActionsFragment : DaggerFragment() {
|
||||||
commandQueue.cancelTempBasal(true, object : Callback() {
|
commandQueue.cancelTempBasal(true, object : Callback() {
|
||||||
override fun run() {
|
override fun run() {
|
||||||
if (!result.success) {
|
if (!result.success) {
|
||||||
val i = Intent(ctx, ErrorHelperActivity::class.java)
|
ErrorHelperActivity.runAlarm(ctx, result.comment, resourceHelper.gs(R.string.tempbasaldeliveryerror), R.raw.boluserror)
|
||||||
i.putExtra("soundid", R.raw.boluserror)
|
|
||||||
i.putExtra("status", result.comment)
|
|
||||||
i.putExtra("title", resourceHelper.gs(R.string.tempbasaldeliveryerror))
|
|
||||||
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
|
||||||
ctx.startActivity(i)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package info.nightscout.androidaps.plugins.general.automation.actions
|
package info.nightscout.androidaps.plugins.general.automation.actions
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
|
||||||
import android.widget.LinearLayout
|
import android.widget.LinearLayout
|
||||||
import androidx.annotation.DrawableRes
|
import androidx.annotation.DrawableRes
|
||||||
import dagger.android.HasAndroidInjector
|
import dagger.android.HasAndroidInjector
|
||||||
|
@ -29,6 +28,7 @@ class ActionAlarm(injector: HasAndroidInjector) : Action(injector) {
|
||||||
constructor(injector: HasAndroidInjector, text: String) : this(injector) {
|
constructor(injector: HasAndroidInjector, text: String) : this(injector) {
|
||||||
this.text = InputString(injector, text)
|
this.text = InputString(injector, text)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun friendlyName(): Int = R.string.alarm
|
override fun friendlyName(): Int = R.string.alarm
|
||||||
override fun shortDescription(): String = resourceHelper.gs(R.string.alarm_message, text.value)
|
override fun shortDescription(): String = resourceHelper.gs(R.string.alarm_message, text.value)
|
||||||
@DrawableRes override fun icon(): Int = R.drawable.ic_access_alarm_24dp
|
@DrawableRes override fun icon(): Int = R.drawable.ic_access_alarm_24dp
|
||||||
|
@ -36,13 +36,7 @@ class ActionAlarm(injector: HasAndroidInjector) : Action(injector) {
|
||||||
override fun isValid(): Boolean = text.value.isNotEmpty()
|
override fun isValid(): Boolean = text.value.isNotEmpty()
|
||||||
|
|
||||||
override fun doAction(callback: Callback) {
|
override fun doAction(callback: Callback) {
|
||||||
val i = Intent(context, ErrorHelperActivity::class.java)
|
ErrorHelperActivity.runAlarm(context, text.value, resourceHelper.gs(R.string.alarm), R.raw.modern_alarm)
|
||||||
i.putExtra("soundid", R.raw.modern_alarm)
|
|
||||||
i.putExtra("status", text.value)
|
|
||||||
i.putExtra("title", resourceHelper.gs(R.string.alarm))
|
|
||||||
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
|
||||||
context.startActivity(i)
|
|
||||||
|
|
||||||
callback.result(PumpEnactResult(injector).success(true).comment(R.string.ok))?.run()
|
callback.result(PumpEnactResult(injector).success(true).comment(R.string.ok))?.run()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,10 @@
|
||||||
package info.nightscout.androidaps.plugins.general.automation.elements
|
package info.nightscout.androidaps.plugins.general.automation.elements
|
||||||
|
|
||||||
import android.view.View
|
|
||||||
import android.view.ViewGroup
|
|
||||||
import android.widget.LinearLayout
|
import android.widget.LinearLayout
|
||||||
import androidx.annotation.StringRes
|
import androidx.annotation.StringRes
|
||||||
import com.dpro.widgets.WeekdaysPicker
|
|
||||||
import dagger.android.HasAndroidInjector
|
import dagger.android.HasAndroidInjector
|
||||||
import info.nightscout.androidaps.R
|
import info.nightscout.androidaps.R
|
||||||
|
import info.nightscout.androidaps.utils.ui.WeekdayPicker
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
class InputWeekDay(injector: HasAndroidInjector) : Element(injector) {
|
class InputWeekDay(injector: HasAndroidInjector) : Element(injector) {
|
||||||
|
@ -78,13 +76,10 @@ class InputWeekDay(injector: HasAndroidInjector) : Element(injector) {
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun addToLayout(root: LinearLayout) {
|
override fun addToLayout(root: LinearLayout) {
|
||||||
val weekdaysPicker = WeekdaysPicker(root.context)
|
WeekdayPicker(root.context).apply {
|
||||||
weekdaysPicker.setEditable(true)
|
setSelectedDays(getSelectedDays())
|
||||||
weekdaysPicker.selectedDays = getSelectedDays()
|
setOnWeekdaysChangeListener { i: Int, selected: Boolean -> set(DayOfWeek.fromCalendarInt(i), selected) }
|
||||||
weekdaysPicker.setOnWeekdaysChangeListener { _: View?, i: Int, list: List<Int?> -> set(DayOfWeek.fromCalendarInt(i), list.contains(i)) }
|
root.addView(this)
|
||||||
weekdaysPicker.layoutParams = LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
|
}
|
||||||
weekdaysPicker.sundayFirstDay = Calendar.getInstance().firstDayOfWeek == Calendar.SUNDAY
|
|
||||||
weekdaysPicker.redrawDays()
|
|
||||||
root.addView(weekdaysPicker)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -129,7 +129,7 @@ class NSSettingsStatus @Inject constructor(
|
||||||
fun handleNewData(nightscoutVersionName: String, nightscoutVersionCode: Int, status: JSONObject) {
|
fun handleNewData(nightscoutVersionName: String, nightscoutVersionCode: Int, status: JSONObject) {
|
||||||
this.nightscoutVersionName = nightscoutVersionName
|
this.nightscoutVersionName = nightscoutVersionName
|
||||||
aapsLogger.debug(LTag.NSCLIENT, "Got versions: Nightscout: $nightscoutVersionName")
|
aapsLogger.debug(LTag.NSCLIENT, "Got versions: Nightscout: $nightscoutVersionName")
|
||||||
if (nightscoutVersionCode < config.SUPPORTEDNSVERSION) {
|
if (nightscoutVersionCode != 0 && nightscoutVersionCode < config.SUPPORTEDNSVERSION) {
|
||||||
val notification = Notification(Notification.OLD_NS, resourceHelper.gs(R.string.unsupportednsversion), Notification.NORMAL)
|
val notification = Notification(Notification.OLD_NS, resourceHelper.gs(R.string.unsupportednsversion), Notification.NORMAL)
|
||||||
rxBus.send(EventNewNotification(notification))
|
rxBus.send(EventNewNotification(notification))
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -43,7 +43,7 @@ import info.nightscout.androidaps.plugins.general.nsclient.data.NSDeviceStatus
|
||||||
import info.nightscout.androidaps.plugins.general.overview.activities.QuickWizardListActivity
|
import info.nightscout.androidaps.plugins.general.overview.activities.QuickWizardListActivity
|
||||||
import info.nightscout.androidaps.plugins.general.overview.graphData.GraphData
|
import info.nightscout.androidaps.plugins.general.overview.graphData.GraphData
|
||||||
import info.nightscout.androidaps.plugins.general.overview.notifications.NotificationStore
|
import info.nightscout.androidaps.plugins.general.overview.notifications.NotificationStore
|
||||||
import info.nightscout.androidaps.plugins.general.wear.ActionStringHandler
|
import info.nightscout.androidaps.plugins.general.wear.events.EventWearDoAction
|
||||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus
|
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus
|
||||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin
|
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin
|
||||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventAutosensCalculationFinished
|
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventAutosensCalculationFinished
|
||||||
|
@ -99,7 +99,6 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
|
||||||
@Inject lateinit var dexcomMediator: DexcomPlugin.DexcomMediator
|
@Inject lateinit var dexcomMediator: DexcomPlugin.DexcomMediator
|
||||||
@Inject lateinit var xdripPlugin: XdripPlugin
|
@Inject lateinit var xdripPlugin: XdripPlugin
|
||||||
@Inject lateinit var notificationStore: NotificationStore
|
@Inject lateinit var notificationStore: NotificationStore
|
||||||
@Inject lateinit var actionStringHandler: ActionStringHandler
|
|
||||||
@Inject lateinit var quickWizard: QuickWizard
|
@Inject lateinit var quickWizard: QuickWizard
|
||||||
@Inject lateinit var buildHelper: BuildHelper
|
@Inject lateinit var buildHelper: BuildHelper
|
||||||
@Inject lateinit var commandQueue: CommandQueue
|
@Inject lateinit var commandQueue: CommandQueue
|
||||||
|
@ -346,7 +345,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
|
||||||
uel.log("ACCEPT TEMP BASAL")
|
uel.log("ACCEPT TEMP BASAL")
|
||||||
binding.buttonsLayout.acceptTempButton.visibility = View.GONE
|
binding.buttonsLayout.acceptTempButton.visibility = View.GONE
|
||||||
(context?.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager).cancel(Constants.notificationID)
|
(context?.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager).cancel(Constants.notificationID)
|
||||||
actionStringHandler.handleInitiate("cancelChangeRequest")
|
rxBus.send(EventWearDoAction("cancelChangeRequest"))
|
||||||
loopPlugin.acceptChangeRequest()
|
loopPlugin.acceptChangeRequest()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -66,7 +66,7 @@ class GraphData(
|
||||||
bgReadingsArray = iobCobCalculatorPlugin.bgReadings
|
bgReadingsArray = iobCobCalculatorPlugin.bgReadings
|
||||||
if (bgReadingsArray?.isEmpty() != false) {
|
if (bgReadingsArray?.isEmpty() != false) {
|
||||||
aapsLogger.debug("No BG data.")
|
aapsLogger.debug("No BG data.")
|
||||||
maxY = 10.0
|
maxY = if (units == Constants.MGDL) 180.0 else 10.0
|
||||||
minY = 0.0
|
minY = 0.0
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,10 @@ import info.nightscout.androidaps.Constants
|
||||||
import info.nightscout.androidaps.MainApp
|
import info.nightscout.androidaps.MainApp
|
||||||
import info.nightscout.androidaps.R
|
import info.nightscout.androidaps.R
|
||||||
import info.nightscout.androidaps.dana.DanaPump
|
import info.nightscout.androidaps.dana.DanaPump
|
||||||
|
import info.nightscout.androidaps.danaRKorean.DanaRKoreanPlugin
|
||||||
|
import info.nightscout.androidaps.danaRv2.DanaRv2Plugin
|
||||||
|
import info.nightscout.androidaps.danar.DanaRPlugin
|
||||||
|
import info.nightscout.androidaps.danars.DanaRSPlugin
|
||||||
import info.nightscout.androidaps.data.DetailedBolusInfo
|
import info.nightscout.androidaps.data.DetailedBolusInfo
|
||||||
import info.nightscout.androidaps.data.Profile
|
import info.nightscout.androidaps.data.Profile
|
||||||
import info.nightscout.androidaps.db.CareportalEvent
|
import info.nightscout.androidaps.db.CareportalEvent
|
||||||
|
@ -18,23 +22,23 @@ import info.nightscout.androidaps.interfaces.ActivePluginProvider
|
||||||
import info.nightscout.androidaps.interfaces.CommandQueueProvider
|
import info.nightscout.androidaps.interfaces.CommandQueueProvider
|
||||||
import info.nightscout.androidaps.interfaces.Constraint
|
import info.nightscout.androidaps.interfaces.Constraint
|
||||||
import info.nightscout.androidaps.interfaces.PluginBase
|
import info.nightscout.androidaps.interfaces.PluginBase
|
||||||
|
import info.nightscout.androidaps.interfaces.ProfileFunction
|
||||||
import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin
|
import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin
|
||||||
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
||||||
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
|
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
|
||||||
import info.nightscout.androidaps.interfaces.ProfileFunction
|
|
||||||
import info.nightscout.androidaps.plugins.general.overview.events.EventDismissNotification
|
import info.nightscout.androidaps.plugins.general.overview.events.EventDismissNotification
|
||||||
|
import info.nightscout.androidaps.plugins.general.wear.events.EventWearDoAction
|
||||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin
|
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin
|
||||||
import info.nightscout.androidaps.danar.DanaRPlugin
|
|
||||||
import info.nightscout.androidaps.danaRKorean.DanaRKoreanPlugin
|
|
||||||
import info.nightscout.androidaps.danars.DanaRSPlugin
|
|
||||||
import info.nightscout.androidaps.danaRv2.DanaRv2Plugin
|
|
||||||
import info.nightscout.androidaps.plugins.pump.insight.LocalInsightPlugin
|
import info.nightscout.androidaps.plugins.pump.insight.LocalInsightPlugin
|
||||||
import info.nightscout.androidaps.plugins.treatments.CarbsGenerator
|
import info.nightscout.androidaps.plugins.treatments.CarbsGenerator
|
||||||
import info.nightscout.androidaps.queue.Callback
|
import info.nightscout.androidaps.queue.Callback
|
||||||
import info.nightscout.androidaps.utils.*
|
import info.nightscout.androidaps.utils.*
|
||||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||||
|
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
||||||
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
||||||
import info.nightscout.androidaps.utils.wizard.BolusWizard
|
import info.nightscout.androidaps.utils.wizard.BolusWizard
|
||||||
|
import io.reactivex.disposables.CompositeDisposable
|
||||||
|
import io.reactivex.rxkotlin.plusAssign
|
||||||
import java.text.DateFormat
|
import java.text.DateFormat
|
||||||
import java.text.DecimalFormat
|
import java.text.DecimalFormat
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
|
@ -46,6 +50,7 @@ import javax.inject.Singleton
|
||||||
class ActionStringHandler @Inject constructor(
|
class ActionStringHandler @Inject constructor(
|
||||||
private val sp: SP,
|
private val sp: SP,
|
||||||
private val rxBus: RxBusWrapper,
|
private val rxBus: RxBusWrapper,
|
||||||
|
private val aapsSchedulers: AapsSchedulers,
|
||||||
private val resourceHelper: ResourceHelper,
|
private val resourceHelper: ResourceHelper,
|
||||||
private val injector: HasAndroidInjector,
|
private val injector: HasAndroidInjector,
|
||||||
private val context: Context,
|
private val context: Context,
|
||||||
|
@ -53,6 +58,7 @@ class ActionStringHandler @Inject constructor(
|
||||||
private val profileFunction: ProfileFunction,
|
private val profileFunction: ProfileFunction,
|
||||||
private val loopPlugin: LoopPlugin,
|
private val loopPlugin: LoopPlugin,
|
||||||
private val wearPlugin: WearPlugin,
|
private val wearPlugin: WearPlugin,
|
||||||
|
private val fabricPrivacy: FabricPrivacy,
|
||||||
private val commandQueue: CommandQueueProvider,
|
private val commandQueue: CommandQueueProvider,
|
||||||
private val activePlugin: ActivePluginProvider,
|
private val activePlugin: ActivePluginProvider,
|
||||||
private val iobCobCalculatorPlugin: IobCobCalculatorPlugin,
|
private val iobCobCalculatorPlugin: IobCobCalculatorPlugin,
|
||||||
|
@ -73,10 +79,18 @@ class ActionStringHandler @Inject constructor(
|
||||||
private var lastConfirmActionString: String? = null
|
private var lastConfirmActionString: String? = null
|
||||||
private var lastBolusWizard: BolusWizard? = null
|
private var lastBolusWizard: BolusWizard? = null
|
||||||
|
|
||||||
// TODO Adrian use RxBus instead of Lazy + cross dependency
|
private val disposable = CompositeDisposable()
|
||||||
|
|
||||||
|
init {
|
||||||
|
disposable += rxBus
|
||||||
|
.toObservable(EventWearDoAction::class.java)
|
||||||
|
.observeOn(aapsSchedulers.main)
|
||||||
|
.subscribe({ handleInitiate(it.action) }, fabricPrivacy::logException)
|
||||||
|
}
|
||||||
|
|
||||||
@Synchronized
|
@Synchronized
|
||||||
fun handleInitiate(actionString: String) {
|
private fun handleInitiate(actionString: String) {
|
||||||
if (!sp.getBoolean("wearcontrol", false)) return
|
if (!sp.getBoolean(R.string.key_wear_control, false)) return
|
||||||
lastBolusWizard = null
|
lastBolusWizard = null
|
||||||
var rTitle = "CONFIRM" //TODO: i18n
|
var rTitle = "CONFIRM" //TODO: i18n
|
||||||
var rMessage = ""
|
var rMessage = ""
|
||||||
|
@ -459,7 +473,7 @@ class ActionStringHandler @Inject constructor(
|
||||||
|
|
||||||
@Synchronized
|
@Synchronized
|
||||||
fun handleConfirmation(actionString: String) {
|
fun handleConfirmation(actionString: String) {
|
||||||
if (!sp.getBoolean("wearcontrol", false)) return
|
if (!sp.getBoolean(R.string.key_wear_control, false)) return
|
||||||
//Guard from old or duplicate confirmations
|
//Guard from old or duplicate confirmations
|
||||||
if (lastConfirmActionString == null) return
|
if (lastConfirmActionString == null) return
|
||||||
if (lastConfirmActionString != actionString) return
|
if (lastConfirmActionString != actionString) return
|
||||||
|
@ -614,13 +628,5 @@ class ActionStringHandler @Inject constructor(
|
||||||
lastSentTimestamp = System.currentTimeMillis()
|
lastSentTimestamp = System.currentTimeMillis()
|
||||||
lastConfirmActionString = null
|
lastConfirmActionString = null
|
||||||
lastBolusWizard = null
|
lastBolusWizard = null
|
||||||
} /*
|
|
||||||
public synchronized static void expectNotificationAction(String message, int id) {
|
|
||||||
String actionstring = "dismissoverviewnotification " + id;
|
|
||||||
WearPlugin.getPlugin().requestActionConfirmation("DISMISS", message, actionstring);
|
|
||||||
lastSentTimestamp = System.currentTimeMillis();
|
|
||||||
lastConfirmActionString = actionstring;
|
|
||||||
lastBolusWizard = null;
|
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
}
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
package info.nightscout.androidaps.plugins.general.wear.events
|
||||||
|
|
||||||
|
import info.nightscout.androidaps.events.Event
|
||||||
|
|
||||||
|
class EventWearDoAction (val action: String) : Event()
|
|
@ -45,9 +45,10 @@ import info.nightscout.androidaps.interfaces.ProfileFunction;
|
||||||
import info.nightscout.androidaps.logging.AAPSLogger;
|
import info.nightscout.androidaps.logging.AAPSLogger;
|
||||||
import info.nightscout.androidaps.logging.LTag;
|
import info.nightscout.androidaps.logging.LTag;
|
||||||
import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin;
|
import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin;
|
||||||
|
import info.nightscout.androidaps.plugins.bus.RxBusWrapper;
|
||||||
import info.nightscout.androidaps.plugins.general.nsclient.data.NSDeviceStatus;
|
import info.nightscout.androidaps.plugins.general.nsclient.data.NSDeviceStatus;
|
||||||
import info.nightscout.androidaps.plugins.general.wear.ActionStringHandler;
|
|
||||||
import info.nightscout.androidaps.plugins.general.wear.WearPlugin;
|
import info.nightscout.androidaps.plugins.general.wear.WearPlugin;
|
||||||
|
import info.nightscout.androidaps.plugins.general.wear.events.EventWearDoAction;
|
||||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus;
|
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus;
|
||||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin;
|
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin;
|
||||||
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin;
|
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin;
|
||||||
|
@ -65,6 +66,7 @@ public class WatchUpdaterService extends WearableListenerService implements Goog
|
||||||
@Inject public WearPlugin wearPlugin;
|
@Inject public WearPlugin wearPlugin;
|
||||||
@Inject public ResourceHelper resourceHelper;
|
@Inject public ResourceHelper resourceHelper;
|
||||||
@Inject public SP sp;
|
@Inject public SP sp;
|
||||||
|
@Inject public RxBusWrapper rxBus;
|
||||||
@Inject public ProfileFunction profileFunction;
|
@Inject public ProfileFunction profileFunction;
|
||||||
@Inject public DefaultValueHelper defaultValueHelper;
|
@Inject public DefaultValueHelper defaultValueHelper;
|
||||||
@Inject public NSDeviceStatus nsDeviceStatus;
|
@Inject public NSDeviceStatus nsDeviceStatus;
|
||||||
|
@ -72,7 +74,6 @@ public class WatchUpdaterService extends WearableListenerService implements Goog
|
||||||
@Inject public LoopPlugin loopPlugin;
|
@Inject public LoopPlugin loopPlugin;
|
||||||
@Inject public IobCobCalculatorPlugin iobCobCalculatorPlugin;
|
@Inject public IobCobCalculatorPlugin iobCobCalculatorPlugin;
|
||||||
@Inject public TreatmentsPlugin treatmentsPlugin;
|
@Inject public TreatmentsPlugin treatmentsPlugin;
|
||||||
@Inject public ActionStringHandler actionStringHandler;
|
|
||||||
@Inject public AppRepository repository;
|
@Inject public AppRepository repository;
|
||||||
@Inject ReceiverStatusStore receiverStatusStore;
|
@Inject ReceiverStatusStore receiverStatusStore;
|
||||||
@Inject Config config;
|
@Inject Config config;
|
||||||
|
@ -260,13 +261,13 @@ public class WatchUpdaterService extends WearableListenerService implements Goog
|
||||||
if (event != null && event.getPath().equals(WEARABLE_INITIATE_ACTIONSTRING_PATH)) {
|
if (event != null && event.getPath().equals(WEARABLE_INITIATE_ACTIONSTRING_PATH)) {
|
||||||
String actionstring = new String(event.getData());
|
String actionstring = new String(event.getData());
|
||||||
aapsLogger.debug(LTag.WEAR, "Wear: " + actionstring);
|
aapsLogger.debug(LTag.WEAR, "Wear: " + actionstring);
|
||||||
actionStringHandler.handleInitiate(actionstring);
|
rxBus.send(new EventWearDoAction(actionstring));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event != null && event.getPath().equals(WEARABLE_CONFIRM_ACTIONSTRING_PATH)) {
|
if (event != null && event.getPath().equals(WEARABLE_CONFIRM_ACTIONSTRING_PATH)) {
|
||||||
String actionstring = new String(event.getData());
|
String actionstring = new String(event.getData());
|
||||||
aapsLogger.debug(LTag.WEAR, "Wear Confirm: " + actionstring);
|
aapsLogger.debug(LTag.WEAR, "Wear Confirm: " + actionstring);
|
||||||
actionStringHandler.handleConfirmation(actionstring);
|
rxBus.send(new EventWearDoAction(actionstring));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -288,10 +289,6 @@ public class WatchUpdaterService extends WearableListenerService implements Goog
|
||||||
if (wearIntegration()) {
|
if (wearIntegration()) {
|
||||||
|
|
||||||
final DataMap dataMap = dataMapSingleBG(lastBG, glucoseStatus);
|
final DataMap dataMap = dataMapSingleBG(lastBG, glucoseStatus);
|
||||||
if (dataMap == null) {
|
|
||||||
ToastUtils.showToastInUiThread(this, resourceHelper.gs(R.string.noprofile));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
(new SendToDataLayerThread(WEARABLE_DATA_PATH, googleApiClient)).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, dataMap);
|
(new SendToDataLayerThread(WEARABLE_DATA_PATH, googleApiClient)).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, dataMap);
|
||||||
}
|
}
|
||||||
|
@ -743,12 +740,12 @@ public class WatchUpdaterService extends WearableListenerService implements Goog
|
||||||
private void sendPreferences() {
|
private void sendPreferences() {
|
||||||
if (googleApiClient != null && googleApiClient.isConnected()) {
|
if (googleApiClient != null && googleApiClient.isConnected()) {
|
||||||
|
|
||||||
boolean wearcontrol = sp.getBoolean("wearcontrol", false);
|
boolean wearcontrol = sp.getBoolean(R.string.key_wear_control, false);
|
||||||
|
|
||||||
PutDataMapRequest dataMapRequest = PutDataMapRequest.create(NEW_PREFERENCES_PATH);
|
PutDataMapRequest dataMapRequest = PutDataMapRequest.create(NEW_PREFERENCES_PATH);
|
||||||
//unique content
|
//unique content
|
||||||
dataMapRequest.getDataMap().putLong("timestamp", System.currentTimeMillis());
|
dataMapRequest.getDataMap().putLong("timestamp", System.currentTimeMillis());
|
||||||
dataMapRequest.getDataMap().putBoolean("wearcontrol", wearcontrol);
|
dataMapRequest.getDataMap().putBoolean(resourceHelper.gs(R.string.key_wear_control), wearcontrol);
|
||||||
PutDataRequest putDataRequest = dataMapRequest.asPutDataRequest();
|
PutDataRequest putDataRequest = dataMapRequest.asPutDataRequest();
|
||||||
Wearable.DataApi.putDataItem(googleApiClient, putDataRequest);
|
Wearable.DataApi.putDataItem(googleApiClient, putDataRequest);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -17,6 +17,8 @@ import info.nightscout.androidaps.logging.LTag
|
||||||
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
||||||
import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientRestart
|
import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientRestart
|
||||||
import info.nightscout.androidaps.plugins.profile.ns.events.EventNSProfileUpdateGUI
|
import info.nightscout.androidaps.plugins.profile.ns.events.EventNSProfileUpdateGUI
|
||||||
|
import info.nightscout.androidaps.receivers.BundleStore
|
||||||
|
import info.nightscout.androidaps.receivers.DataReceiver
|
||||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||||
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
||||||
import org.json.JSONObject
|
import org.json.JSONObject
|
||||||
|
@ -87,13 +89,16 @@ class NSProfilePlugin @Inject constructor(
|
||||||
@Inject lateinit var nsProfilePlugin: NSProfilePlugin
|
@Inject lateinit var nsProfilePlugin: NSProfilePlugin
|
||||||
@Inject lateinit var aapsLogger: AAPSLogger
|
@Inject lateinit var aapsLogger: AAPSLogger
|
||||||
@Inject lateinit var rxBus: RxBusWrapper
|
@Inject lateinit var rxBus: RxBusWrapper
|
||||||
|
@Inject lateinit var bundleStore: BundleStore
|
||||||
|
|
||||||
init {
|
init {
|
||||||
(context.applicationContext as HasAndroidInjector).androidInjector().inject(this)
|
(context.applicationContext as HasAndroidInjector).androidInjector().inject(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun doWork(): Result {
|
override fun doWork(): Result {
|
||||||
inputData.getString("profile")?.let { profileString ->
|
val bundle = bundleStore.pickup(inputData.getLong(DataReceiver.STORE_KEY, -1))
|
||||||
|
?: return Result.failure()
|
||||||
|
bundle.getString("profile")?.let { profileString ->
|
||||||
nsProfilePlugin.profile = ProfileStore(injector, JSONObject(profileString))
|
nsProfilePlugin.profile = ProfileStore(injector, JSONObject(profileString))
|
||||||
nsProfilePlugin.storeNSProfile()
|
nsProfilePlugin.storeNSProfile()
|
||||||
if (nsProfilePlugin.isEnabled()) {
|
if (nsProfilePlugin.isEnabled()) {
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package info.nightscout.androidaps.plugins.treatments
|
package info.nightscout.androidaps.plugins.treatments
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
|
||||||
import info.nightscout.androidaps.R
|
import info.nightscout.androidaps.R
|
||||||
import info.nightscout.androidaps.activities.ErrorHelperActivity
|
import info.nightscout.androidaps.activities.ErrorHelperActivity
|
||||||
import info.nightscout.androidaps.data.DetailedBolusInfo
|
import info.nightscout.androidaps.data.DetailedBolusInfo
|
||||||
|
@ -47,12 +46,7 @@ class CarbsGenerator @Inject constructor(
|
||||||
commandQueue.bolus(carbInfo, object : Callback() {
|
commandQueue.bolus(carbInfo, object : Callback() {
|
||||||
override fun run() {
|
override fun run() {
|
||||||
if (!result.success) {
|
if (!result.success) {
|
||||||
val i = Intent(context, ErrorHelperActivity::class.java)
|
ErrorHelperActivity.runAlarm(context, result.comment, resourceHelper.gs(R.string.treatmentdeliveryerror), R.raw.boluserror)
|
||||||
i.putExtra("soundid", R.raw.boluserror)
|
|
||||||
i.putExtra("status", result.comment)
|
|
||||||
i.putExtra("title", resourceHelper.gs(R.string.treatmentdeliveryerror))
|
|
||||||
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
|
||||||
context.startActivity(i)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package info.nightscout.androidaps.plugins.treatments;
|
package info.nightscout.androidaps.plugins.treatments;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
@ -679,12 +678,7 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface
|
||||||
|
|
||||||
String status = String.format(resourceHelper.gs(R.string.error_adding_treatment_message), treatment.insulin, (int) treatment.carbs, dateUtil.dateAndTimeString(treatment.date));
|
String status = String.format(resourceHelper.gs(R.string.error_adding_treatment_message), treatment.insulin, (int) treatment.carbs, dateUtil.dateAndTimeString(treatment.date));
|
||||||
|
|
||||||
Intent i = new Intent(context, ErrorHelperActivity.class);
|
ErrorHelperActivity.Companion.runAlarm(context, status, resourceHelper.gs(R.string.error_adding_treatment_title), R.raw.error);
|
||||||
i.putExtra("soundid", R.raw.error);
|
|
||||||
i.putExtra("title", resourceHelper.gs(R.string.error_adding_treatment_title));
|
|
||||||
i.putExtra("status", status);
|
|
||||||
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
|
||||||
context.startActivity(i);
|
|
||||||
|
|
||||||
Bundle bundle = new Bundle();
|
Bundle bundle = new Bundle();
|
||||||
bundle.putString(FirebaseAnalytics.Param.ITEM_LIST_ID, "TreatmentClash");
|
bundle.putString(FirebaseAnalytics.Param.ITEM_LIST_ID, "TreatmentClash");
|
||||||
|
|
|
@ -116,12 +116,7 @@ class CommandQueue @Inject constructor(
|
||||||
setProfile(it, object : Callback() {
|
setProfile(it, object : Callback() {
|
||||||
override fun run() {
|
override fun run() {
|
||||||
if (!result.success) {
|
if (!result.success) {
|
||||||
val i = Intent(context, ErrorHelperActivity::class.java)
|
ErrorHelperActivity.runAlarm(context, result.comment, resourceHelper.gs(R.string.failedupdatebasalprofile), R.raw.boluserror)
|
||||||
i.putExtra("soundid", R.raw.boluserror)
|
|
||||||
i.putExtra("status", result.comment)
|
|
||||||
i.putExtra("title", resourceHelper.gs(R.string.failedupdatebasalprofile))
|
|
||||||
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
|
||||||
context.startActivity(i)
|
|
||||||
}
|
}
|
||||||
if (result.enacted) rxBus.send(EventNewBasalProfile())
|
if (result.enacted) rxBus.send(EventNewBasalProfile())
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,9 +61,7 @@ open class DataReceiver : DaggerBroadcastReceiver() {
|
||||||
}.build()).build()
|
}.build()).build()
|
||||||
Intents.ACTION_NEW_PROFILE ->
|
Intents.ACTION_NEW_PROFILE ->
|
||||||
OneTimeWorkRequest.Builder(NSProfilePlugin.NSProfileWorker::class.java)
|
OneTimeWorkRequest.Builder(NSProfilePlugin.NSProfileWorker::class.java)
|
||||||
.setInputData(Data.Builder().also {
|
.setInputData(bundleInputData(bundle, intent)).build()
|
||||||
it.copyString("profile", bundle, null)
|
|
||||||
}.build()).build()
|
|
||||||
Intents.ACTION_NEW_SGV ->
|
Intents.ACTION_NEW_SGV ->
|
||||||
OneTimeWorkRequest.Builder(NSClientSourcePlugin.NSClientSourceWorker::class.java)
|
OneTimeWorkRequest.Builder(NSClientSourcePlugin.NSClientSourceWorker::class.java)
|
||||||
.setInputData(Data.Builder().also {
|
.setInputData(Data.Builder().also {
|
||||||
|
|
|
@ -74,11 +74,11 @@ class SWDefinition @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
private val screenSetupWizard = SWScreen(injector, R.string.nav_setupwizard)
|
private val screenSetupWizard = SWScreen(injector, R.string.nav_setupwizard)
|
||||||
.add(SWInfotext(injector)
|
.add(SWInfoText(injector)
|
||||||
.label(R.string.welcometosetupwizard))
|
.label(R.string.welcometosetupwizard))
|
||||||
private val screenEula = SWScreen(injector, R.string.end_user_license_agreement)
|
private val screenEula = SWScreen(injector, R.string.end_user_license_agreement)
|
||||||
.skippable(false)
|
.skippable(false)
|
||||||
.add(SWInfotext(injector)
|
.add(SWInfoText(injector)
|
||||||
.label(R.string.end_user_license_agreement_text))
|
.label(R.string.end_user_license_agreement_text))
|
||||||
.add(SWBreak(injector))
|
.add(SWBreak(injector))
|
||||||
.add(SWButton(injector)
|
.add(SWButton(injector)
|
||||||
|
@ -112,7 +112,7 @@ class SWDefinition @Inject constructor(
|
||||||
.comment(R.string.high_mark_comment))
|
.comment(R.string.high_mark_comment))
|
||||||
private val screenPermissionBattery = SWScreen(injector, R.string.permission)
|
private val screenPermissionBattery = SWScreen(injector, R.string.permission)
|
||||||
.skippable(false)
|
.skippable(false)
|
||||||
.add(SWInfotext(injector)
|
.add(SWInfoText(injector)
|
||||||
.label(resourceHelper.gs(R.string.needwhitelisting, resourceHelper.gs(R.string.app_name))))
|
.label(resourceHelper.gs(R.string.needwhitelisting, resourceHelper.gs(R.string.app_name))))
|
||||||
.add(SWBreak(injector))
|
.add(SWBreak(injector))
|
||||||
.add(SWButton(injector)
|
.add(SWButton(injector)
|
||||||
|
@ -123,7 +123,7 @@ class SWDefinition @Inject constructor(
|
||||||
.validator { !androidPermission.permissionNotGranted(activity, Manifest.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS) }
|
.validator { !androidPermission.permissionNotGranted(activity, Manifest.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS) }
|
||||||
private val screenPermissionBt = SWScreen(injector, R.string.permission)
|
private val screenPermissionBt = SWScreen(injector, R.string.permission)
|
||||||
.skippable(false)
|
.skippable(false)
|
||||||
.add(SWInfotext(injector)
|
.add(SWInfoText(injector)
|
||||||
.label(resourceHelper.gs(R.string.needlocationpermission)))
|
.label(resourceHelper.gs(R.string.needlocationpermission)))
|
||||||
.add(SWBreak(injector))
|
.add(SWBreak(injector))
|
||||||
.add(SWButton(injector)
|
.add(SWButton(injector)
|
||||||
|
@ -134,7 +134,7 @@ class SWDefinition @Inject constructor(
|
||||||
.validator { !androidPermission.permissionNotGranted(activity, Manifest.permission.ACCESS_FINE_LOCATION) }
|
.validator { !androidPermission.permissionNotGranted(activity, Manifest.permission.ACCESS_FINE_LOCATION) }
|
||||||
private val screenPermissionStore = SWScreen(injector, R.string.permission)
|
private val screenPermissionStore = SWScreen(injector, R.string.permission)
|
||||||
.skippable(false)
|
.skippable(false)
|
||||||
.add(SWInfotext(injector)
|
.add(SWInfoText(injector)
|
||||||
.label(resourceHelper.gs(R.string.needstoragepermission)))
|
.label(resourceHelper.gs(R.string.needstoragepermission)))
|
||||||
.add(SWBreak(injector))
|
.add(SWBreak(injector))
|
||||||
.add(SWButton(injector)
|
.add(SWButton(injector)
|
||||||
|
@ -144,7 +144,7 @@ class SWDefinition @Inject constructor(
|
||||||
.visibility { androidPermission.permissionNotGranted(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE) }
|
.visibility { androidPermission.permissionNotGranted(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE) }
|
||||||
.validator { !androidPermission.permissionNotGranted(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE) }
|
.validator { !androidPermission.permissionNotGranted(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE) }
|
||||||
private val screenImport = SWScreen(injector, R.string.nav_import)
|
private val screenImport = SWScreen(injector, R.string.nav_import)
|
||||||
.add(SWInfotext(injector)
|
.add(SWInfoText(injector)
|
||||||
.label(R.string.storedsettingsfound))
|
.label(R.string.storedsettingsfound))
|
||||||
.add(SWBreak(injector))
|
.add(SWBreak(injector))
|
||||||
.add(SWButton(injector)
|
.add(SWButton(injector)
|
||||||
|
@ -153,7 +153,7 @@ class SWDefinition @Inject constructor(
|
||||||
.visibility { importExportPrefs.prefsFileExists() && !androidPermission.permissionNotGranted(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE) }
|
.visibility { importExportPrefs.prefsFileExists() && !androidPermission.permissionNotGranted(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE) }
|
||||||
private val screenNsClient = SWScreen(injector, R.string.nsclientinternal_title)
|
private val screenNsClient = SWScreen(injector, R.string.nsclientinternal_title)
|
||||||
.skippable(true)
|
.skippable(true)
|
||||||
.add(SWInfotext(injector)
|
.add(SWInfoText(injector)
|
||||||
.label(R.string.nsclientinfotext))
|
.label(R.string.nsclientinfotext))
|
||||||
.add(SWBreak(injector))
|
.add(SWBreak(injector))
|
||||||
.add(SWButton(injector)
|
.add(SWButton(injector)
|
||||||
|
@ -183,19 +183,19 @@ class SWDefinition @Inject constructor(
|
||||||
.visibility { !(nsClientPlugin.nsClientService != null && NSClientService.isConnected && NSClientService.hasWriteAuth) }
|
.visibility { !(nsClientPlugin.nsClientService != null && NSClientService.isConnected && NSClientService.hasWriteAuth) }
|
||||||
private val screenPatientName = SWScreen(injector, R.string.patient_name)
|
private val screenPatientName = SWScreen(injector, R.string.patient_name)
|
||||||
.skippable(true)
|
.skippable(true)
|
||||||
.add(SWInfotext(injector)
|
.add(SWInfoText(injector)
|
||||||
.label(R.string.patient_name_summary))
|
.label(R.string.patient_name_summary))
|
||||||
.add(SWEditString(injector)
|
.add(SWEditString(injector)
|
||||||
.validator(SWTextValidator(String::isNotEmpty))
|
.validator(SWTextValidator(String::isNotEmpty))
|
||||||
.preferenceId(R.string.key_patient_name))
|
.preferenceId(R.string.key_patient_name))
|
||||||
private val screenMasterPassword = SWScreen(injector, R.string.master_password)
|
private val screenMasterPassword = SWScreen(injector, R.string.master_password)
|
||||||
.skippable(false)
|
.skippable(false)
|
||||||
.add(SWInfotext(injector)
|
.add(SWInfoText(injector)
|
||||||
.label(R.string.master_password))
|
.label(R.string.master_password))
|
||||||
.add(SWEditEncryptedPassword(injector, cryptoUtil)
|
.add(SWEditEncryptedPassword(injector, cryptoUtil)
|
||||||
.preferenceId(R.string.key_master_password))
|
.preferenceId(R.string.key_master_password))
|
||||||
.add(SWBreak(injector))
|
.add(SWBreak(injector))
|
||||||
.add(SWInfotext(injector)
|
.add(SWInfoText(injector)
|
||||||
.label(R.string.master_password_summary))
|
.label(R.string.master_password_summary))
|
||||||
.validator { !cryptoUtil.checkPassword("", sp.getString(R.string.key_master_password, "")) }
|
.validator { !cryptoUtil.checkPassword("", sp.getString(R.string.key_master_password, "")) }
|
||||||
private val screenAge = SWScreen(injector, R.string.patientage)
|
private val screenAge = SWScreen(injector, R.string.patientage)
|
||||||
|
@ -206,7 +206,20 @@ class SWDefinition @Inject constructor(
|
||||||
.preferenceId(R.string.key_age)
|
.preferenceId(R.string.key_age)
|
||||||
.label(R.string.patientage)
|
.label(R.string.patientage)
|
||||||
.comment(R.string.patientage_summary))
|
.comment(R.string.patientage_summary))
|
||||||
.validator { sp.contains(R.string.key_age) }
|
.add(SWBreak(injector))
|
||||||
|
.add(SWEditNumber(injector, 3.0, 0.1, 25.0)
|
||||||
|
.preferenceId(R.string.key_treatmentssafety_maxbolus)
|
||||||
|
.updateDelay(5)
|
||||||
|
.label(R.string.treatmentssafety_maxbolus_title)
|
||||||
|
.comment(R.string.common_values))
|
||||||
|
.add(SWEditNumber(injector, 48.0, 1.0, 100.0)
|
||||||
|
.preferenceId(R.string.key_treatmentssafety_maxcarbs)
|
||||||
|
.updateDelay(5)
|
||||||
|
.label(R.string.treatmentssafety_maxcarbs_title)
|
||||||
|
.comment(R.string.common_values))
|
||||||
|
.validator { sp.contains(R.string.key_age)
|
||||||
|
&& sp.getDouble(R.string.key_treatmentssafety_maxbolus, 0.0) > 0
|
||||||
|
&& sp.getDouble(R.string.key_treatmentssafety_maxcarbs, 0.0) > 0 }
|
||||||
private val screenInsulin = SWScreen(injector, R.string.configbuilder_insulin)
|
private val screenInsulin = SWScreen(injector, R.string.configbuilder_insulin)
|
||||||
.skippable(false)
|
.skippable(false)
|
||||||
.add(SWPlugin(injector, this)
|
.add(SWPlugin(injector, this)
|
||||||
|
@ -214,7 +227,7 @@ class SWDefinition @Inject constructor(
|
||||||
.makeVisible(false)
|
.makeVisible(false)
|
||||||
.label(R.string.configbuilder_insulin))
|
.label(R.string.configbuilder_insulin))
|
||||||
.add(SWBreak(injector))
|
.add(SWBreak(injector))
|
||||||
.add(SWInfotext(injector)
|
.add(SWInfoText(injector)
|
||||||
.label(R.string.diawarning))
|
.label(R.string.diawarning))
|
||||||
private val screenBgSource = SWScreen(injector, R.string.configbuilder_bgsource)
|
private val screenBgSource = SWScreen(injector, R.string.configbuilder_bgsource)
|
||||||
.skippable(false)
|
.skippable(false)
|
||||||
|
@ -224,7 +237,7 @@ class SWDefinition @Inject constructor(
|
||||||
.add(SWBreak(injector))
|
.add(SWBreak(injector))
|
||||||
private val screenProfile = SWScreen(injector, R.string.configbuilder_profile)
|
private val screenProfile = SWScreen(injector, R.string.configbuilder_profile)
|
||||||
.skippable(false)
|
.skippable(false)
|
||||||
.add(SWInfotext(injector)
|
.add(SWInfoText(injector)
|
||||||
.label(R.string.setupwizard_profile_description))
|
.label(R.string.setupwizard_profile_description))
|
||||||
.add(SWBreak(injector))
|
.add(SWBreak(injector))
|
||||||
.add(SWPlugin(injector, this)
|
.add(SWPlugin(injector, this)
|
||||||
|
@ -232,7 +245,7 @@ class SWDefinition @Inject constructor(
|
||||||
.label(R.string.configbuilder_profile))
|
.label(R.string.configbuilder_profile))
|
||||||
private val screenNsProfile = SWScreen(injector, R.string.nsprofile)
|
private val screenNsProfile = SWScreen(injector, R.string.nsprofile)
|
||||||
.skippable(false)
|
.skippable(false)
|
||||||
.add(SWInfotext(injector)
|
.add(SWInfoText(injector)
|
||||||
.label(R.string.adjustprofileinns))
|
.label(R.string.adjustprofileinns))
|
||||||
.add(SWFragment(injector, this)
|
.add(SWFragment(injector, this)
|
||||||
.add(NSProfileFragment()))
|
.add(NSProfileFragment()))
|
||||||
|
@ -246,7 +259,7 @@ class SWDefinition @Inject constructor(
|
||||||
.visibility { localProfilePlugin.isEnabled(PluginType.PROFILE) }
|
.visibility { localProfilePlugin.isEnabled(PluginType.PROFILE) }
|
||||||
private val screenProfileSwitch = SWScreen(injector, R.string.careportal_profileswitch)
|
private val screenProfileSwitch = SWScreen(injector, R.string.careportal_profileswitch)
|
||||||
.skippable(false)
|
.skippable(false)
|
||||||
.add(SWInfotext(injector)
|
.add(SWInfoText(injector)
|
||||||
.label(R.string.profileswitch_ismissing))
|
.label(R.string.profileswitch_ismissing))
|
||||||
.add(SWButton(injector)
|
.add(SWButton(injector)
|
||||||
.text(R.string.doprofileswitch)
|
.text(R.string.doprofileswitch)
|
||||||
|
@ -259,11 +272,11 @@ class SWDefinition @Inject constructor(
|
||||||
.option(PluginType.PUMP, R.string.configbuilder_pump_description)
|
.option(PluginType.PUMP, R.string.configbuilder_pump_description)
|
||||||
.label(R.string.configbuilder_pump))
|
.label(R.string.configbuilder_pump))
|
||||||
.add(SWBreak(injector))
|
.add(SWBreak(injector))
|
||||||
.add(SWInfotext(injector)
|
.add(SWInfoText(injector)
|
||||||
.label(R.string.setupwizard_pump_pump_not_initialized)
|
.label(R.string.setupwizard_pump_pump_not_initialized)
|
||||||
.visibility { !isPumpInitialized() })
|
.visibility { !isPumpInitialized() })
|
||||||
.add( // Omnipod only
|
.add( // Omnipod only
|
||||||
SWInfotext(injector)
|
SWInfoText(injector)
|
||||||
.label(R.string.setupwizard_pump_waiting_for_riley_link_connection)
|
.label(R.string.setupwizard_pump_waiting_for_riley_link_connection)
|
||||||
.visibility {
|
.visibility {
|
||||||
val activePump = activePlugin.activePump
|
val activePump = activePlugin.activePump
|
||||||
|
@ -295,7 +308,7 @@ class SWDefinition @Inject constructor(
|
||||||
|
|
||||||
private val screenAps = SWScreen(injector, R.string.configbuilder_aps)
|
private val screenAps = SWScreen(injector, R.string.configbuilder_aps)
|
||||||
.skippable(false)
|
.skippable(false)
|
||||||
.add(SWInfotext(injector)
|
.add(SWInfoText(injector)
|
||||||
.label(R.string.setupwizard_aps_description))
|
.label(R.string.setupwizard_aps_description))
|
||||||
.add(SWBreak(injector))
|
.add(SWBreak(injector))
|
||||||
.add(SWPlugin(injector, this)
|
.add(SWPlugin(injector, this)
|
||||||
|
@ -314,7 +327,7 @@ class SWDefinition @Inject constructor(
|
||||||
.validator { sp.contains(R.string.key_aps_mode) }
|
.validator { sp.contains(R.string.key_aps_mode) }
|
||||||
private val screenLoop = SWScreen(injector, R.string.configbuilder_loop)
|
private val screenLoop = SWScreen(injector, R.string.configbuilder_loop)
|
||||||
.skippable(false)
|
.skippable(false)
|
||||||
.add(SWInfotext(injector)
|
.add(SWInfoText(injector)
|
||||||
.label(R.string.setupwizard_loop_description))
|
.label(R.string.setupwizard_loop_description))
|
||||||
.add(SWBreak(injector))
|
.add(SWBreak(injector))
|
||||||
.add(SWButton(injector)
|
.add(SWButton(injector)
|
||||||
|
@ -328,7 +341,7 @@ class SWDefinition @Inject constructor(
|
||||||
.visibility { !loopPlugin.isEnabled(PluginType.LOOP) && config.APS }
|
.visibility { !loopPlugin.isEnabled(PluginType.LOOP) && config.APS }
|
||||||
private val screenSensitivity = SWScreen(injector, R.string.configbuilder_sensitivity)
|
private val screenSensitivity = SWScreen(injector, R.string.configbuilder_sensitivity)
|
||||||
.skippable(false)
|
.skippable(false)
|
||||||
.add(SWInfotext(injector)
|
.add(SWInfoText(injector)
|
||||||
.label(R.string.setupwizard_sensitivity_description))
|
.label(R.string.setupwizard_sensitivity_description))
|
||||||
.add(SWHtmlLink(injector)
|
.add(SWHtmlLink(injector)
|
||||||
.label(R.string.setupwizard_sensitivity_url))
|
.label(R.string.setupwizard_sensitivity_url))
|
||||||
|
@ -338,7 +351,7 @@ class SWDefinition @Inject constructor(
|
||||||
.label(R.string.configbuilder_sensitivity))
|
.label(R.string.configbuilder_sensitivity))
|
||||||
private val getScreenObjectives = SWScreen(injector, R.string.objectives)
|
private val getScreenObjectives = SWScreen(injector, R.string.objectives)
|
||||||
.skippable(false)
|
.skippable(false)
|
||||||
.add(SWInfotext(injector)
|
.add(SWInfoText(injector)
|
||||||
.label(R.string.startobjective))
|
.label(R.string.startobjective))
|
||||||
.add(SWBreak(injector))
|
.add(SWBreak(injector))
|
||||||
.add(SWFragment(injector, this)
|
.add(SWFragment(injector, this)
|
||||||
|
|
|
@ -6,7 +6,7 @@ import android.widget.TextView
|
||||||
import dagger.android.HasAndroidInjector
|
import dagger.android.HasAndroidInjector
|
||||||
import info.nightscout.androidaps.setupwizard.SWValidator
|
import info.nightscout.androidaps.setupwizard.SWValidator
|
||||||
|
|
||||||
class SWBreak(injector: HasAndroidInjector) : SWItem(injector, Type.TEXT) {
|
class SWBreak(injector: HasAndroidInjector) : SWItem(injector, Type.BREAK) {
|
||||||
private var l: TextView? = null
|
private var l: TextView? = null
|
||||||
private var visibilityValidator: SWValidator? = null
|
private var visibilityValidator: SWValidator? = null
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,60 @@
|
||||||
|
package info.nightscout.androidaps.setupwizard.elements
|
||||||
|
|
||||||
|
import android.graphics.Typeface
|
||||||
|
import android.text.Editable
|
||||||
|
import android.text.TextWatcher
|
||||||
|
import android.view.View
|
||||||
|
import android.widget.LinearLayout
|
||||||
|
import android.widget.TextView
|
||||||
|
import dagger.android.HasAndroidInjector
|
||||||
|
import info.nightscout.androidaps.setupwizard.SWNumberValidator
|
||||||
|
import info.nightscout.androidaps.utils.SafeParse
|
||||||
|
import info.nightscout.androidaps.utils.ui.NumberPicker
|
||||||
|
import java.text.DecimalFormat
|
||||||
|
|
||||||
|
class SWEditNumber(injector: HasAndroidInjector, private val init: Double, private val min: Double, private val max: Double) : SWItem(injector, Type.DECIMAL_NUMBER) {
|
||||||
|
|
||||||
|
private val validator: SWNumberValidator = SWNumberValidator { value -> value in min..max }
|
||||||
|
private var updateDelay = 0
|
||||||
|
|
||||||
|
override fun generateDialog(layout: LinearLayout) {
|
||||||
|
val context = layout.context
|
||||||
|
val watcher: TextWatcher = object : TextWatcher {
|
||||||
|
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {}
|
||||||
|
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
|
||||||
|
if (validator.isValid(SafeParse.stringToDouble(s.toString())))
|
||||||
|
save(s.toString(), updateDelay.toLong())
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun afterTextChanged(s: Editable) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
val l = TextView(context)
|
||||||
|
l.id = View.generateViewId()
|
||||||
|
label?.let { l.setText(it) }
|
||||||
|
l.setTypeface(l.typeface, Typeface.BOLD)
|
||||||
|
layout.addView(l)
|
||||||
|
val initValue = sp.getDouble(preferenceId, init)
|
||||||
|
val numberPicker = NumberPicker(context)
|
||||||
|
numberPicker.setParams(initValue, min, max, 0.1, DecimalFormat("0.0"), false, null, watcher)
|
||||||
|
|
||||||
|
layout.addView(numberPicker)
|
||||||
|
val c = TextView(context)
|
||||||
|
c.id = View.generateViewId()
|
||||||
|
comment?.let { c.setText(it) }
|
||||||
|
c.setTypeface(c.typeface, Typeface.ITALIC)
|
||||||
|
layout.addView(c)
|
||||||
|
super.generateDialog(layout)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun preferenceId(preferenceId: Int): SWEditNumber {
|
||||||
|
this.preferenceId = preferenceId
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
fun updateDelay(updateDelay: Int): SWEditNumber {
|
||||||
|
this.updateDelay = updateDelay
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -16,11 +16,11 @@ import info.nightscout.androidaps.utils.SafeParse
|
||||||
import java.text.DecimalFormat
|
import java.text.DecimalFormat
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class SWEditNumberWithUnits(injector: HasAndroidInjector, private val init: Double, private val min: Double, private val max: Double) : SWItem(injector, Type.UNITNUMBER) {
|
class SWEditNumberWithUnits(injector: HasAndroidInjector, private val init: Double, private val min: Double, private val max: Double) : SWItem(injector, Type.UNIT_NUMBER) {
|
||||||
|
|
||||||
@Inject lateinit var profileFunction: ProfileFunction
|
@Inject lateinit var profileFunction: ProfileFunction
|
||||||
|
|
||||||
private val validator: SWNumberValidator? = SWNumberValidator { value -> value >= min && value <= max }
|
private val validator: SWNumberValidator = SWNumberValidator { value -> value in min..max }
|
||||||
private var updateDelay = 0
|
private var updateDelay = 0
|
||||||
|
|
||||||
override fun generateDialog(layout: LinearLayout) {
|
override fun generateDialog(layout: LinearLayout) {
|
||||||
|
@ -28,7 +28,7 @@ class SWEditNumberWithUnits(injector: HasAndroidInjector, private val init: Doub
|
||||||
val watcher: TextWatcher = object : TextWatcher {
|
val watcher: TextWatcher = object : TextWatcher {
|
||||||
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {}
|
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {}
|
||||||
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
|
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
|
||||||
if (validator != null && validator.isValid(SafeParse.stringToDouble(s.toString())))
|
if (validator.isValid(SafeParse.stringToDouble(s.toString())))
|
||||||
save(s.toString(), updateDelay.toLong())
|
save(s.toString(), updateDelay.toLong())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -38,7 +38,7 @@ class SWEditUrl(injector: HasAndroidInjector) : SWItem(injector, Type.URL) {
|
||||||
editText.addTextChangedListener(object : TextWatcher {
|
editText.addTextChangedListener(object : TextWatcher {
|
||||||
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {}
|
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {}
|
||||||
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
|
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
|
||||||
if (Patterns.WEB_URL.matcher(s).matches()) save(s.toString(), updateDelay.toLong()) else rxBus.send(EventSWLabel(resourceHelper.gs(R.string.error_url_not_valid)))
|
if (Patterns.WEB_URL.matcher(s).matches()) save(s.toString(), updateDelay) else rxBus.send(EventSWLabel(resourceHelper.gs(R.string.error_url_not_valid)))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun afterTextChanged(s: Editable) {}
|
override fun afterTextChanged(s: Editable) {}
|
||||||
|
|
|
@ -8,7 +8,7 @@ import androidx.annotation.StringRes
|
||||||
import dagger.android.HasAndroidInjector
|
import dagger.android.HasAndroidInjector
|
||||||
import info.nightscout.androidaps.setupwizard.SWValidator
|
import info.nightscout.androidaps.setupwizard.SWValidator
|
||||||
|
|
||||||
class SWHtmlLink(injector: HasAndroidInjector) : SWItem(injector, Type.HTMLLINK) {
|
class SWHtmlLink(injector: HasAndroidInjector) : SWItem(injector, Type.HTML_LINK) {
|
||||||
|
|
||||||
private var textLabel: String? = null
|
private var textLabel: String? = null
|
||||||
private var l: TextView? = null
|
private var l: TextView? = null
|
||||||
|
|
|
@ -6,22 +6,22 @@ import android.widget.TextView
|
||||||
import dagger.android.HasAndroidInjector
|
import dagger.android.HasAndroidInjector
|
||||||
import info.nightscout.androidaps.setupwizard.SWValidator
|
import info.nightscout.androidaps.setupwizard.SWValidator
|
||||||
|
|
||||||
class SWInfotext(injector: HasAndroidInjector) : SWItem(injector, Type.TEXT) {
|
class SWInfoText(injector: HasAndroidInjector) : SWItem(injector, Type.TEXT) {
|
||||||
private var textLabel: String? = null
|
private var textLabel: String? = null
|
||||||
private var l: TextView? = null
|
private var l: TextView? = null
|
||||||
private var visibilityValidator: SWValidator? = null
|
private var visibilityValidator: SWValidator? = null
|
||||||
|
|
||||||
override fun label(label: Int): SWInfotext {
|
override fun label(label: Int): SWInfoText {
|
||||||
this.label = label
|
this.label = label
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
fun label(newLabel: String): SWInfotext {
|
fun label(newLabel: String): SWInfoText {
|
||||||
textLabel = newLabel
|
textLabel = newLabel
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
fun visibility(visibilityValidator: SWValidator): SWInfotext {
|
fun visibility(visibilityValidator: SWValidator): SWInfoText {
|
||||||
this.visibilityValidator = visibilityValidator
|
this.visibilityValidator = visibilityValidator
|
||||||
return this
|
return this
|
||||||
}
|
}
|
|
@ -27,25 +27,18 @@ open class SWItem(val injector: HasAndroidInjector, var type: Type) {
|
||||||
private var scheduledEventPost: ScheduledFuture<*>? = null
|
private var scheduledEventPost: ScheduledFuture<*>? = null
|
||||||
|
|
||||||
init {
|
init {
|
||||||
|
@Suppress("LeakingThis")
|
||||||
injector.androidInjector().inject(this)
|
injector.androidInjector().inject(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class Type {
|
enum class Type {
|
||||||
NONE, TEXT, HTMLLINK, BREAK, LISTENER, URL, STRING, NUMBER, DECIMALNUMBER, CHECKBOX, RADIOBUTTON, PLUGIN, BUTTON, FRAGMENT, UNITNUMBER
|
NONE, TEXT, HTML_LINK, BREAK, LISTENER, URL, STRING, NUMBER, DECIMAL_NUMBER, RADIOBUTTON, PLUGIN, BUTTON, FRAGMENT, UNIT_NUMBER
|
||||||
}
|
}
|
||||||
|
|
||||||
var label: Int? = null
|
var label: Int? = null
|
||||||
var comment: Int? = null
|
var comment: Int? = null
|
||||||
var preferenceId = 0
|
var preferenceId = 0
|
||||||
|
|
||||||
fun getLabel(): String {
|
|
||||||
return label?.let { resourceHelper.gs(it) } ?: ""
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getComment(): String {
|
|
||||||
return comment?.let { resourceHelper.gs(it) } ?: ""
|
|
||||||
}
|
|
||||||
|
|
||||||
open fun label(@StringRes label: Int): SWItem {
|
open fun label(@StringRes label: Int): SWItem {
|
||||||
this.label = label
|
this.label = label
|
||||||
return this
|
return this
|
||||||
|
@ -72,6 +65,7 @@ open class SWItem(val injector: HasAndroidInjector, var type: Type) {
|
||||||
|
|
||||||
fun scheduleChange(updateDelay: Long) {
|
fun scheduleChange(updateDelay: Long) {
|
||||||
class PostRunnable : Runnable {
|
class PostRunnable : Runnable {
|
||||||
|
|
||||||
override fun run() {
|
override fun run() {
|
||||||
aapsLogger.debug(LTag.CORE, "Firing EventPreferenceChange")
|
aapsLogger.debug(LTag.CORE, "Firing EventPreferenceChange")
|
||||||
rxBus.send(EventPreferenceChange(resourceHelper, preferenceId))
|
rxBus.send(EventPreferenceChange(resourceHelper, preferenceId))
|
||||||
|
|
|
@ -89,7 +89,7 @@ class SWPlugin(injector: HasAndroidInjector, val definition: SWDefinition) : SWI
|
||||||
super.generateDialog(layout)
|
super.generateDialog(layout)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun addConfiguration(layout: LinearLayout, plugin: PluginBase) {
|
private fun addConfiguration(layout: LinearLayout, plugin: PluginBase) {
|
||||||
if (plugin.preferencesId != -1) {
|
if (plugin.preferencesId != -1) {
|
||||||
fragment = MyPreferenceFragment()
|
fragment = MyPreferenceFragment()
|
||||||
fragment?.arguments = Bundle().also { it.putInt("id", plugin.preferencesId) }
|
fragment?.arguments = Bundle().also { it.putInt("id", plugin.preferencesId) }
|
||||||
|
|
|
@ -29,12 +29,12 @@ class SWRadioButton(injector: HasAndroidInjector) : SWItem(injector, Type.RADIOB
|
||||||
|
|
||||||
override fun generateDialog(layout: LinearLayout) {
|
override fun generateDialog(layout: LinearLayout) {
|
||||||
val context = layout.context
|
val context = layout.context
|
||||||
val pdesc = TextView(context)
|
val desc = TextView(context)
|
||||||
pdesc.text = getComment()
|
comment?.let { desc.setText(it) }
|
||||||
val params = LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)
|
val params = LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)
|
||||||
params.setMargins(0, 0, 0, 40)
|
params.setMargins(0, 0, 0, 40)
|
||||||
pdesc.layoutParams = params
|
desc.layoutParams = params
|
||||||
layout.addView(pdesc)
|
layout.addView(desc)
|
||||||
|
|
||||||
// Get if there is already value in SP
|
// Get if there is already value in SP
|
||||||
val previousValue = sp.getString(preferenceId, "none")
|
val previousValue = sp.getString(preferenceId, "none")
|
||||||
|
@ -43,12 +43,12 @@ class SWRadioButton(injector: HasAndroidInjector) : SWItem(injector, Type.RADIOB
|
||||||
radioGroup?.orientation = LinearLayout.VERTICAL
|
radioGroup?.orientation = LinearLayout.VERTICAL
|
||||||
radioGroup?.visibility = View.VISIBLE
|
radioGroup?.visibility = View.VISIBLE
|
||||||
for (i in labels().indices) {
|
for (i in labels().indices) {
|
||||||
val rdbtn = RadioButton(context)
|
val rdBtn = RadioButton(context)
|
||||||
rdbtn.id = View.generateViewId()
|
rdBtn.id = View.generateViewId()
|
||||||
rdbtn.text = labels()[i]
|
rdBtn.text = labels()[i]
|
||||||
if (previousValue == values()[i]) rdbtn.isChecked = true
|
if (previousValue == values()[i]) rdBtn.isChecked = true
|
||||||
rdbtn.tag = i
|
rdBtn.tag = i
|
||||||
radioGroup!!.addView(rdbtn)
|
radioGroup!!.addView(rdBtn)
|
||||||
}
|
}
|
||||||
radioGroup!!.setOnCheckedChangeListener { group: RadioGroup, checkedId: Int ->
|
radioGroup!!.setOnCheckedChangeListener { group: RadioGroup, checkedId: Int ->
|
||||||
val i = group.findViewById<View>(checkedId).tag as Int
|
val i = group.findViewById<View>(checkedId).tag as Int
|
||||||
|
|
|
@ -361,12 +361,7 @@ class BolusWizard @Inject constructor(
|
||||||
commandQueue.bolus(this, object : Callback() {
|
commandQueue.bolus(this, object : Callback() {
|
||||||
override fun run() {
|
override fun run() {
|
||||||
if (!result.success) {
|
if (!result.success) {
|
||||||
val i = Intent(ctx, ErrorHelperActivity::class.java)
|
ErrorHelperActivity.runAlarm(ctx, result.comment, resourceHelper.gs(R.string.treatmentdeliveryerror), R.raw.boluserror)
|
||||||
i.putExtra("soundid", R.raw.boluserror)
|
|
||||||
i.putExtra("status", result.comment)
|
|
||||||
i.putExtra("title", resourceHelper.gs(R.string.treatmentdeliveryerror))
|
|
||||||
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
|
||||||
ctx.startActivity(i)
|
|
||||||
} else
|
} else
|
||||||
scheduleEatReminder()
|
scheduleEatReminder()
|
||||||
}
|
}
|
||||||
|
@ -394,12 +389,7 @@ class BolusWizard @Inject constructor(
|
||||||
commandQueue.tempBasalAbsolute(0.0, 120, true, profile, object : Callback() {
|
commandQueue.tempBasalAbsolute(0.0, 120, true, profile, object : Callback() {
|
||||||
override fun run() {
|
override fun run() {
|
||||||
if (!result.success) {
|
if (!result.success) {
|
||||||
val i = Intent(ctx, ErrorHelperActivity::class.java)
|
ErrorHelperActivity.runAlarm(ctx, result.comment, resourceHelper.gs(R.string.tempbasaldeliveryerror), R.raw.boluserror)
|
||||||
i.putExtra("soundid", R.raw.boluserror)
|
|
||||||
i.putExtra("status", result.comment)
|
|
||||||
i.putExtra("title", resourceHelper.gs(R.string.tempbasaldeliveryerror))
|
|
||||||
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
|
||||||
ctx.startActivity(i)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -409,9 +399,9 @@ class BolusWizard @Inject constructor(
|
||||||
override fun run() {
|
override fun run() {
|
||||||
if (!result.success) {
|
if (!result.success) {
|
||||||
val i = Intent(ctx, ErrorHelperActivity::class.java)
|
val i = Intent(ctx, ErrorHelperActivity::class.java)
|
||||||
i.putExtra("soundid", R.raw.boluserror)
|
i.putExtra(ErrorHelperActivity.SOUND_ID, R.raw.boluserror)
|
||||||
i.putExtra("status", result.comment)
|
i.putExtra(ErrorHelperActivity.STATUS, result.comment)
|
||||||
i.putExtra("title", resourceHelper.gs(R.string.tempbasaldeliveryerror))
|
i.putExtra(ErrorHelperActivity.TITLE, resourceHelper.gs(R.string.tempbasaldeliveryerror))
|
||||||
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||||
ctx.startActivity(i)
|
ctx.startActivity(i)
|
||||||
}
|
}
|
||||||
|
@ -435,12 +425,7 @@ class BolusWizard @Inject constructor(
|
||||||
commandQueue.bolus(this, object : Callback() {
|
commandQueue.bolus(this, object : Callback() {
|
||||||
override fun run() {
|
override fun run() {
|
||||||
if (!result.success) {
|
if (!result.success) {
|
||||||
val i = Intent(ctx, ErrorHelperActivity::class.java)
|
ErrorHelperActivity.runAlarm(ctx, result.comment, resourceHelper.gs(R.string.treatmentdeliveryerror), R.raw.boluserror)
|
||||||
i.putExtra("soundid", R.raw.boluserror)
|
|
||||||
i.putExtra("status", result.comment)
|
|
||||||
i.putExtra("title", resourceHelper.gs(R.string.treatmentdeliveryerror))
|
|
||||||
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
|
||||||
ctx.startActivity(i)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -420,6 +420,7 @@
|
||||||
<string name="basal_shortname">BAZ</string>
|
<string name="basal_shortname">BAZ</string>
|
||||||
<string name="deviation_shortname">ODCH</string>
|
<string name="deviation_shortname">ODCH</string>
|
||||||
<string name="activity_shortname">AKT</string>
|
<string name="activity_shortname">AKT</string>
|
||||||
|
<string name="bgi_shortname">-BGI</string>
|
||||||
<string name="abs_insulin_shortname">ABS</string>
|
<string name="abs_insulin_shortname">ABS</string>
|
||||||
<string name="devslope_shortname">DEVSLOPE</string>
|
<string name="devslope_shortname">DEVSLOPE</string>
|
||||||
<string name="nav_about">O aplikaci</string>
|
<string name="nav_about">O aplikaci</string>
|
||||||
|
@ -627,6 +628,7 @@
|
||||||
<string name="ns_autobackfill_summary">Automaticky doplňovat chybějící glykémie z NS</string>
|
<string name="ns_autobackfill_summary">Automaticky doplňovat chybějící glykémie z NS</string>
|
||||||
<string name="loop_smbsetbypump_label">SMB provedené pumpou</string>
|
<string name="loop_smbsetbypump_label">SMB provedené pumpou</string>
|
||||||
<string name="overview_show_activity">Aktivita</string>
|
<string name="overview_show_activity">Aktivita</string>
|
||||||
|
<string name="overview_show_bgi">Vliv na hladinu glukózy</string>
|
||||||
<string name="overview_show_sensitivity">Citlivost</string>
|
<string name="overview_show_sensitivity">Citlivost</string>
|
||||||
<string name="overview_show_deviations">Odchylky</string>
|
<string name="overview_show_deviations">Odchylky</string>
|
||||||
<string name="overview_show_cob">Zbývající sacharidy</string>
|
<string name="overview_show_cob">Zbývající sacharidy</string>
|
||||||
|
@ -1156,4 +1158,7 @@
|
||||||
<string name="graph_menu_divider_header">Graf</string>
|
<string name="graph_menu_divider_header">Graf</string>
|
||||||
<string name="chart_menu">Možnosti grafu</string>
|
<string name="chart_menu">Možnosti grafu</string>
|
||||||
<string name="clear_filter">Vymazat filtr</string>
|
<string name="clear_filter">Vymazat filtr</string>
|
||||||
|
<string name="trend_arrow">Šipka trendu</string>
|
||||||
|
<string name="cannula">Kanyla</string>
|
||||||
|
<string name="userentry">Vstup uživatele</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -420,6 +420,7 @@
|
||||||
<string name="basal_shortname">BAS</string>
|
<string name="basal_shortname">BAS</string>
|
||||||
<string name="deviation_shortname">DEV</string>
|
<string name="deviation_shortname">DEV</string>
|
||||||
<string name="activity_shortname">ACT</string>
|
<string name="activity_shortname">ACT</string>
|
||||||
|
<string name="bgi_shortname">-BGI</string>
|
||||||
<string name="abs_insulin_shortname">ABS</string>
|
<string name="abs_insulin_shortname">ABS</string>
|
||||||
<string name="devslope_shortname">DEVSLOPE</string>
|
<string name="devslope_shortname">DEVSLOPE</string>
|
||||||
<string name="nav_about">Über</string>
|
<string name="nav_about">Über</string>
|
||||||
|
@ -627,6 +628,7 @@
|
||||||
<string name="ns_autobackfill_summary">Lade fehlende Blutzuckerwerte automatisch aus Nightscout nach.</string>
|
<string name="ns_autobackfill_summary">Lade fehlende Blutzuckerwerte automatisch aus Nightscout nach.</string>
|
||||||
<string name="loop_smbsetbypump_label">SMB von der Pumpe abgegeben</string>
|
<string name="loop_smbsetbypump_label">SMB von der Pumpe abgegeben</string>
|
||||||
<string name="overview_show_activity">Aktivität</string>
|
<string name="overview_show_activity">Aktivität</string>
|
||||||
|
<string name="overview_show_bgi">Blutzuckerwirkung</string>
|
||||||
<string name="overview_show_sensitivity">Sensitivität</string>
|
<string name="overview_show_sensitivity">Sensitivität</string>
|
||||||
<string name="overview_show_deviations">Abweichungen</string>
|
<string name="overview_show_deviations">Abweichungen</string>
|
||||||
<string name="overview_show_cob">Aktive Kohlenhydrate</string>
|
<string name="overview_show_cob">Aktive Kohlenhydrate</string>
|
||||||
|
@ -1157,4 +1159,7 @@ Unerwartetes Verhalten.</string>
|
||||||
<string name="graph_menu_divider_header">Diagramm</string>
|
<string name="graph_menu_divider_header">Diagramm</string>
|
||||||
<string name="chart_menu">Diagrammmenü</string>
|
<string name="chart_menu">Diagrammmenü</string>
|
||||||
<string name="clear_filter">Filter löschen</string>
|
<string name="clear_filter">Filter löschen</string>
|
||||||
|
<string name="trend_arrow">Trendpfeil</string>
|
||||||
|
<string name="cannula">Kanüle</string>
|
||||||
|
<string name="userentry">Benutzereingabe</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -421,6 +421,7 @@ L\'ENSEMBLE DES RISQUES LIÉS À LA QUALITÉ ET À LA PERFORMANCE DU PROGRAMME S
|
||||||
<string name="basal_shortname">BAS</string>
|
<string name="basal_shortname">BAS</string>
|
||||||
<string name="deviation_shortname">DEV</string>
|
<string name="deviation_shortname">DEV</string>
|
||||||
<string name="activity_shortname">ACT</string>
|
<string name="activity_shortname">ACT</string>
|
||||||
|
<string name="bgi_shortname">-IGly</string>
|
||||||
<string name="abs_insulin_shortname">ABS</string>
|
<string name="abs_insulin_shortname">ABS</string>
|
||||||
<string name="devslope_shortname">PENTEDEV</string>
|
<string name="devslope_shortname">PENTEDEV</string>
|
||||||
<string name="nav_about">À propos</string>
|
<string name="nav_about">À propos</string>
|
||||||
|
@ -628,6 +629,7 @@ L\'ENSEMBLE DES RISQUES LIÉS À LA QUALITÉ ET À LA PERFORMANCE DU PROGRAMME S
|
||||||
<string name="ns_autobackfill_summary">Remplissage automatique des glycémies manquantes en utilisant NS</string>
|
<string name="ns_autobackfill_summary">Remplissage automatique des glycémies manquantes en utilisant NS</string>
|
||||||
<string name="loop_smbsetbypump_label">SMB défini par la pompe</string>
|
<string name="loop_smbsetbypump_label">SMB défini par la pompe</string>
|
||||||
<string name="overview_show_activity">Activité</string>
|
<string name="overview_show_activity">Activité</string>
|
||||||
|
<string name="overview_show_bgi">Impact glycémique</string>
|
||||||
<string name="overview_show_sensitivity">Sensibilité</string>
|
<string name="overview_show_sensitivity">Sensibilité</string>
|
||||||
<string name="overview_show_deviations">Déviations</string>
|
<string name="overview_show_deviations">Déviations</string>
|
||||||
<string name="overview_show_cob">Glucides actifs</string>
|
<string name="overview_show_cob">Glucides actifs</string>
|
||||||
|
@ -1159,4 +1161,5 @@ L\'ENSEMBLE DES RISQUES LIÉS À LA QUALITÉ ET À LA PERFORMANCE DU PROGRAMME S
|
||||||
<string name="clear_filter">Effacer le filtre</string>
|
<string name="clear_filter">Effacer le filtre</string>
|
||||||
<string name="trend_arrow">Flèche de tendance</string>
|
<string name="trend_arrow">Flèche de tendance</string>
|
||||||
<string name="cannula">Canule</string>
|
<string name="cannula">Canule</string>
|
||||||
|
<string name="userentry">Entrées utilisateur</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -420,6 +420,7 @@
|
||||||
<string name="basal_shortname">BAS</string>
|
<string name="basal_shortname">BAS</string>
|
||||||
<string name="deviation_shortname">DEV</string>
|
<string name="deviation_shortname">DEV</string>
|
||||||
<string name="activity_shortname">ATT</string>
|
<string name="activity_shortname">ATT</string>
|
||||||
|
<string name="bgi_shortname">-BGI</string>
|
||||||
<string name="abs_insulin_shortname">ASS</string>
|
<string name="abs_insulin_shortname">ASS</string>
|
||||||
<string name="devslope_shortname">PENDEV</string>
|
<string name="devslope_shortname">PENDEV</string>
|
||||||
<string name="nav_about">Informazioni su</string>
|
<string name="nav_about">Informazioni su</string>
|
||||||
|
@ -627,6 +628,7 @@
|
||||||
<string name="ns_autobackfill_summary">Riempimento automatico glicemie mancanti da NS</string>
|
<string name="ns_autobackfill_summary">Riempimento automatico glicemie mancanti da NS</string>
|
||||||
<string name="loop_smbsetbypump_label">SMB impostato dal micro</string>
|
<string name="loop_smbsetbypump_label">SMB impostato dal micro</string>
|
||||||
<string name="overview_show_activity">Attività</string>
|
<string name="overview_show_activity">Attività</string>
|
||||||
|
<string name="overview_show_bgi">Impatto glicemia (BGI)</string>
|
||||||
<string name="overview_show_sensitivity">Sensibilità</string>
|
<string name="overview_show_sensitivity">Sensibilità</string>
|
||||||
<string name="overview_show_deviations">Deviazioni</string>
|
<string name="overview_show_deviations">Deviazioni</string>
|
||||||
<string name="overview_show_cob">CHO attivi</string>
|
<string name="overview_show_cob">CHO attivi</string>
|
||||||
|
@ -1158,4 +1160,5 @@
|
||||||
<string name="clear_filter">Cancella filtro</string>
|
<string name="clear_filter">Cancella filtro</string>
|
||||||
<string name="trend_arrow">Freccia trend</string>
|
<string name="trend_arrow">Freccia trend</string>
|
||||||
<string name="cannula">Cannula</string>
|
<string name="cannula">Cannula</string>
|
||||||
|
<string name="userentry">Inserimento utente</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
<string name="objectives_maxiob_objective">כוונון הלולאה הסגורה, תוך העלאה של ערך ה- IOB מעל 0 ובסופו של דבר הורדת ערכי המטרה של רמת הסוכר</string>
|
<string name="objectives_maxiob_objective">כוונון הלולאה הסגורה, תוך העלאה של ערך ה- IOB מעל 0 ובסופו של דבר הורדת ערכי המטרה של רמת הסוכר</string>
|
||||||
<string name="objectives_maxiob_gate">לפני הורדת ערך רמת הסוכר, הפעל במשך מס\' ימים, עם לפחות לילה אחד ללא התרעת רמת סוכר נמוכה</string>
|
<string name="objectives_maxiob_gate">לפני הורדת ערך רמת הסוכר, הפעל במשך מס\' ימים, עם לפחות לילה אחד ללא התרעת רמת סוכר נמוכה</string>
|
||||||
<string name="objectives_autosens_objective">במידת הצורך, בצעו התאמת בזאלי ויחסים, ולאחר מכן הפעילו את Autosens</string>
|
<string name="objectives_autosens_objective">במידת הצורך, בצעו התאמת בזאלי ויחסים, ולאחר מכן הפעילו את Autosens</string>
|
||||||
<string name="objectives_autosens_gate">שבוע של הפעלה מוצלחת של הלולאה במשך היום, עם הוספת ערכי פחמימות רגילים</string>
|
<string name="objectives_autosens_gate">שבוע של הפעלה מוצלחת של הלולאה במשך שעות היום, עם הוספת ערכי פחמימות רגילים</string>
|
||||||
<string name="objectives_ama_objective">הפעלת פונקציות נוספות לשימוש במשך היום, לדוגמה AMA (סיוע ארוחות מתקדם)</string>
|
<string name="objectives_ama_objective">הפעלת פונקציות נוספות לשימוש במשך היום, לדוגמה AMA (סיוע ארוחות מתקדם)</string>
|
||||||
<string name="objectives_smb_objective">הפעלת פונקציות נוספות לשימוש במשך היום, כגון סופר מיקרו בולוסים (SMB)</string>
|
<string name="objectives_smb_objective">הפעלת פונקציות נוספות לשימוש במשך היום, כגון סופר מיקרו בולוסים (SMB)</string>
|
||||||
<string name="objectives_auto_objective">הפעלת אוטומציה</string>
|
<string name="objectives_auto_objective">הפעלת אוטומציה</string>
|
||||||
|
|
|
@ -156,7 +156,7 @@
|
||||||
<string name="nav_import">יבא הגדרות</string>
|
<string name="nav_import">יבא הגדרות</string>
|
||||||
<string name="openapsma_maxbasal_title">מינון בזאלי זמני מקסימלי (יח\'\\שעה)</string>
|
<string name="openapsma_maxbasal_title">מינון בזאלי זמני מקסימלי (יח\'\\שעה)</string>
|
||||||
<string name="openapsma_maxbasal_summary">ערך זה נקרא בזאלי מרבי ב-OpenAPS</string>
|
<string name="openapsma_maxbasal_summary">ערך זה נקרא בזאלי מרבי ב-OpenAPS</string>
|
||||||
<string name="openapsma_maxiob_title">בזאלי פעיל מרבי ש-OpenAPS יכול לספק [U]</string>
|
<string name="openapsma_maxiob_title">בזאלי פעיל מרבי ש-OpenAPS יכול לספק (יחידות) </string>
|
||||||
<string name="openapsma_maxiob_summary">ערך זה נקרא אינסולין פעיל מקסימלי (Max IOB) ב-OpenAPS. זהו מקסימום האינסולין הפעיל ב-[U] ש-APS מאפשר.</string>
|
<string name="openapsma_maxiob_summary">ערך זה נקרא אינסולין פעיל מקסימלי (Max IOB) ב-OpenAPS. זהו מקסימום האינסולין הפעיל ב-[U] ש-APS מאפשר.</string>
|
||||||
<string name="password_preferences_encrypt_prompt">אתם תתבקשו למלא סיסמה ראשית שתשמש להצפנת ההעדפות המיוצאות.</string>
|
<string name="password_preferences_encrypt_prompt">אתם תתבקשו למלא סיסמה ראשית שתשמש להצפנת ההעדפות המיוצאות.</string>
|
||||||
<string name="password_preferences_decrypt_prompt">אתם תתבקשו למלא סיסמה ראשית שתשמש לפיענוח ההעדפות המיובאות.</string>
|
<string name="password_preferences_decrypt_prompt">אתם תתבקשו למלא סיסמה ראשית שתשמש לפיענוח ההעדפות המיובאות.</string>
|
||||||
|
@ -217,7 +217,7 @@
|
||||||
<string name="smscommunicator_remotecommandnotallowed">פקודה מרוחקת אינה מותרת</string>
|
<string name="smscommunicator_remotecommandnotallowed">פקודה מרוחקת אינה מותרת</string>
|
||||||
<string name="smscommunicator_remotebolusnotallowed">בולוס מרחוק אינו זמין. נסו שוב מאוחר יותר.</string>
|
<string name="smscommunicator_remotebolusnotallowed">בולוס מרחוק אינו זמין. נסו שוב מאוחר יותר.</string>
|
||||||
<string name="smscommunicator_basalreplywithcode">להפעלת בזאלי %1$.2f יח\' לשעה למשך %2$d דקות יש להשיב עם הקוד %3$s</string>
|
<string name="smscommunicator_basalreplywithcode">להפעלת בזאלי %1$.2f יח\' לשעה למשך %2$d דקות יש להשיב עם הקוד %3$s</string>
|
||||||
<string name="smscommunicator_profilereplywithcode">להחלפת פרופיל ל- %1$s %2$d % הקש קוד %3$s</string>
|
<string name="smscommunicator_profilereplywithcode">להחלפת פרופיל ל- %1$s %2$d %% הקש את הקוד %3$s</string>
|
||||||
<string name="smscommunicator_extendedreplywithcode">למתן בולוס ממושך %1$.2f יח\' למשך %2$d דקות יש להשיב עם הקוד %3$s</string>
|
<string name="smscommunicator_extendedreplywithcode">למתן בולוס ממושך %1$.2f יח\' למשך %2$d דקות יש להשיב עם הקוד %3$s</string>
|
||||||
<string name="smscommunicator_carbsreplywithcode">למתן %1$d גר\' ב-%2$s יש להשיב עם הקוד %3$s</string>
|
<string name="smscommunicator_carbsreplywithcode">למתן %1$d גר\' ב-%2$s יש להשיב עם הקוד %3$s</string>
|
||||||
<string name="smscommunicator_basalpctreplywithcode">להפעלת בזאלי %1$d%% למשך %2$d דקות הקש קוד %3$s</string>
|
<string name="smscommunicator_basalpctreplywithcode">להפעלת בזאלי %1$d%% למשך %2$d דקות הקש קוד %3$s</string>
|
||||||
|
@ -312,7 +312,7 @@
|
||||||
<string name="openapsama_current_basal_safety_multiplier_summary">ערך ברירת מחדל: 4 זהו החצי השני של מנגנון הגנה עיקרי של OpenAPS, והחצי השני של \"3x max daily; 4x current\" במנגנוני ההגנה. המשמעות היא שהמינון הבזאלי, ללא קשר למקסימום שנקבע במשאבה, אינו יכול להיות גבוה יותר ממספר זה כפול הקצב הבזאלי הנוכחי. מיועד למנוע כניסה לתחומים מסוכנים ע\"י קביעת קצב בזאלי גבוה לפני הבנה של פעולת האלגוריתם. שוב: ברירת המחדל היא x4, רוב המשתמשים לעולם אינם צריכים לשנות ערך זה ואם הם מרגישים שמנגנון הגנה זה מפריע להם, הפתרון הוא בשינוי של הגדרות אחרות.</string>
|
<string name="openapsama_current_basal_safety_multiplier_summary">ערך ברירת מחדל: 4 זהו החצי השני של מנגנון הגנה עיקרי של OpenAPS, והחצי השני של \"3x max daily; 4x current\" במנגנוני ההגנה. המשמעות היא שהמינון הבזאלי, ללא קשר למקסימום שנקבע במשאבה, אינו יכול להיות גבוה יותר ממספר זה כפול הקצב הבזאלי הנוכחי. מיועד למנוע כניסה לתחומים מסוכנים ע\"י קביעת קצב בזאלי גבוה לפני הבנה של פעולת האלגוריתם. שוב: ברירת המחדל היא x4, רוב המשתמשים לעולם אינם צריכים לשנות ערך זה ואם הם מרגישים שמנגנון הגנה זה מפריע להם, הפתרון הוא בשינוי של הגדרות אחרות.</string>
|
||||||
<string name="openapsama_autosens_max_summary">ערך ברירת מחדל: 1.2\nזוהי מגבלת המכפיל של autosens (ובקרוב autotune) שמגדירה 20%% כיחס מקסימלי של autosens, אשר קובע בתורו את גובה הבזאלי המקסימלי, גובהו המינימלי של יחס התיקון, ואת המינימום של ערכי המטרה האפשריים.</string>
|
<string name="openapsama_autosens_max_summary">ערך ברירת מחדל: 1.2\nזוהי מגבלת המכפיל של autosens (ובקרוב autotune) שמגדירה 20%% כיחס מקסימלי של autosens, אשר קובע בתורו את גובה הבזאלי המקסימלי, גובהו המינימלי של יחס התיקון, ואת המינימום של ערכי המטרה האפשריים.</string>
|
||||||
<string name="openapsama_autosens_min_summary">ערך ברירת מחדל: 0.7\nבצד השני של מגבלות הבטיחות של autosens, ערך זה מגביל את יכולתו של autosens להוריד את הערכים הבזאליים ועד כמה יכול להעלות את יחס התיקון ואת ערכי מטרת הסוכר בדם.</string>
|
<string name="openapsama_autosens_min_summary">ערך ברירת מחדל: 0.7\nבצד השני של מגבלות הבטיחות של autosens, ערך זה מגביל את יכולתו של autosens להוריד את הערכים הבזאליים ועד כמה יכול להעלות את יחס התיקון ואת ערכי מטרת הסוכר בדם.</string>
|
||||||
<string name="openapsama_autosens_adjusttargets">Autosens מווסת גם את ערכי המטרה</string>
|
<string name="openapsama_autosens_adjusttargets">וויסות ערכי מטרה ע\"י Autosens</string>
|
||||||
<string name="openapsama_autosens_adjusttargets_summary">ערך ברירת מחדל: התאמה מדויקת\n נועד לאפשר ל-Autosens לשנות את המטרה של ערכי הסוכר, בנוסף ליחס התיקון והבזאלים.</string>
|
<string name="openapsama_autosens_adjusttargets_summary">ערך ברירת מחדל: התאמה מדויקת\n נועד לאפשר ל-Autosens לשנות את המטרה של ערכי הסוכר, בנוסף ליחס התיקון והבזאלים.</string>
|
||||||
<string name="openapsama_bolussnooze_dia_divisor_summary">ערך ברירת מחדל: 2\n מעכב בולוס מופעל אחרי שאתם מזריקים בולוס ארוחה, כך שהלולאה לא תפצה ע\"י בזאלי זמני נמוך אחרי הארוחה. הדוגמה כאן וברירת המחדל היא 2; כך שהגדרה של משך פעילות אינסולין של 3 שעות משמעה שהעיכוב יחלוף בהדרגה בתוך 1.5 שעות (3 ש\' לחלק ל-2).</string>
|
<string name="openapsama_bolussnooze_dia_divisor_summary">ערך ברירת מחדל: 2\n מעכב בולוס מופעל אחרי שאתם מזריקים בולוס ארוחה, כך שהלולאה לא תפצה ע\"י בזאלי זמני נמוך אחרי הארוחה. הדוגמה כאן וברירת המחדל היא 2; כך שהגדרה של משך פעילות אינסולין של 3 שעות משמעה שהעיכוב יחלוף בהדרגה בתוך 1.5 שעות (3 ש\' לחלק ל-2).</string>
|
||||||
<string name="openapsama_min_5m_carbimpact_summary">ערך ברירת מחדל: 3.0 (AMA) או 8.0 (SMB). זוהי הגדרת ברירת מחדל לספיגת פחמימות ב-5 דקות. ברירת המחדל היא 3mg/dL/5min. פעולה זו משפיעה על קצב הדעיכה של פחמ\' פעילות, ועל הנחת קצב ספיגת הפחמ\' בחישוב רמות סוכר עתידיות כשהן בירידה מהירה מהצפוי או עליה איטית מהצפוי.</string>
|
<string name="openapsama_min_5m_carbimpact_summary">ערך ברירת מחדל: 3.0 (AMA) או 8.0 (SMB). זוהי הגדרת ברירת מחדל לספיגת פחמימות ב-5 דקות. ברירת המחדל היא 3mg/dL/5min. פעולה זו משפיעה על קצב הדעיכה של פחמ\' פעילות, ועל הנחת קצב ספיגת הפחמ\' בחישוב רמות סוכר עתידיות כשהן בירידה מהירה מהצפוי או עליה איטית מהצפוי.</string>
|
||||||
|
@ -420,6 +420,7 @@
|
||||||
<string name="basal_shortname">בזאל\'</string>
|
<string name="basal_shortname">בזאל\'</string>
|
||||||
<string name="deviation_shortname">סטייה</string>
|
<string name="deviation_shortname">סטייה</string>
|
||||||
<string name="activity_shortname">פעילות</string>
|
<string name="activity_shortname">פעילות</string>
|
||||||
|
<string name="bgi_shortname">השפעה</string>
|
||||||
<string name="abs_insulin_shortname">אבס\'</string>
|
<string name="abs_insulin_shortname">אבס\'</string>
|
||||||
<string name="devslope_shortname">שיפוע</string>
|
<string name="devslope_shortname">שיפוע</string>
|
||||||
<string name="nav_about">אודות</string>
|
<string name="nav_about">אודות</string>
|
||||||
|
@ -627,6 +628,7 @@
|
||||||
<string name="ns_autobackfill_summary">לטעינת הנתונים האוטומטית חסרים נתוני סוכר מ-Nightscout</string>
|
<string name="ns_autobackfill_summary">לטעינת הנתונים האוטומטית חסרים נתוני סוכר מ-Nightscout</string>
|
||||||
<string name="loop_smbsetbypump_label">SMB מוגדר באמצעות משאבה</string>
|
<string name="loop_smbsetbypump_label">SMB מוגדר באמצעות משאבה</string>
|
||||||
<string name="overview_show_activity">פעילות</string>
|
<string name="overview_show_activity">פעילות</string>
|
||||||
|
<string name="overview_show_bgi">השפעת הסוכר בדם</string>
|
||||||
<string name="overview_show_sensitivity">רגישות</string>
|
<string name="overview_show_sensitivity">רגישות</string>
|
||||||
<string name="overview_show_deviations">חריגות</string>
|
<string name="overview_show_deviations">חריגות</string>
|
||||||
<string name="overview_show_cob">פחמימות פעילות</string>
|
<string name="overview_show_cob">פחמימות פעילות</string>
|
||||||
|
@ -676,7 +678,7 @@
|
||||||
<string name="smbnotallowedinopenloopmode">SMB אינו פעיל במצב לולאה פתוחה</string>
|
<string name="smbnotallowedinopenloopmode">SMB אינו פעיל במצב לולאה פתוחה</string>
|
||||||
<string name="food_short">מזון</string>
|
<string name="food_short">מזון</string>
|
||||||
<string name="reset">איפוס</string>
|
<string name="reset">איפוס</string>
|
||||||
<string name="openapssmb_maxiob_title">מינון אינסולין פעיל מרבי ממנו OpenAPS לא יחרוג [U]</string>
|
<string name="openapssmb_maxiob_title">מינון אינסולין פעיל מרבי ממנו OpenAPS לא יחרוג (יחידות) </string>
|
||||||
<string name="openapssmb_maxiob_summary">ב-OpenAPS ערך זה נקרא מקסימום אינסולין פעיל (maxIOB). \nלא יוזרק עוד אינסולין אם כמות האינסולין הפעיל הנוכחי גדול מערך זה</string>
|
<string name="openapssmb_maxiob_summary">ב-OpenAPS ערך זה נקרא מקסימום אינסולין פעיל (maxIOB). \nלא יוזרק עוד אינסולין אם כמות האינסולין הפעיל הנוכחי גדול מערך זה</string>
|
||||||
<string name="pump_stopped">המשאבה נעצרה</string>
|
<string name="pump_stopped">המשאבה נעצרה</string>
|
||||||
<string name="pump_started">המשאבה הופעלה</string>
|
<string name="pump_started">המשאבה הופעלה</string>
|
||||||
|
@ -702,8 +704,8 @@
|
||||||
<string name="connectionsettings_title">הגדרות חיבור</string>
|
<string name="connectionsettings_title">הגדרות חיבור</string>
|
||||||
<string name="ns_wifi_allowedssids">SSID מורשים (מופרדים בנקודה-פסיק)</string>
|
<string name="ns_wifi_allowedssids">SSID מורשים (מופרדים בנקודה-פסיק)</string>
|
||||||
<string name="ns_allowroaming">אפשר חיבור בנדידה</string>
|
<string name="ns_allowroaming">אפשר חיבור בנדידה</string>
|
||||||
<string name="openapsama_autosens_max">יחס autosens מקסימלי</string>
|
<string name="openapsama_autosens_max">יחס Autosens מקסימלי</string>
|
||||||
<string name="openapsama_autosens_min">יחס autosens מינימלי</string>
|
<string name="openapsama_autosens_min">יחס Autosens מינימלי</string>
|
||||||
<string name="openapsama_bolussnooze_dia_divisor">נמנום בולוס - מחלק משך פעילות אינסולין</string>
|
<string name="openapsama_bolussnooze_dia_divisor">נמנום בולוס - מחלק משך פעילות אינסולין</string>
|
||||||
<string name="openapsama_max_daily_safety_multiplier">מכפלת בטיחות בזאלי יומי מירבי</string>
|
<string name="openapsama_max_daily_safety_multiplier">מכפלת בטיחות בזאלי יומי מירבי</string>
|
||||||
<string name="openapsama_current_basal_safety_multiplier">מכפלת בטיחות בזאלי נוכחי</string>
|
<string name="openapsama_current_basal_safety_multiplier">מכפלת בטיחות בזאלי נוכחי</string>
|
||||||
|
@ -771,7 +773,7 @@
|
||||||
<string name="delete_logs">מחק רישומים</string>
|
<string name="delete_logs">מחק רישומים</string>
|
||||||
<string name="error_adding_treatment_message">לא ניתן להוסיף טיפול (אינסולין: %1$.2f, פחמ\': %2$d, בשעה: %3$s) לטיפולים. נא לבדוק ולהוסיף רשומה באופן ידני כנדרש.</string>
|
<string name="error_adding_treatment_message">לא ניתן להוסיף טיפול (אינסולין: %1$.2f, פחמ\': %2$d, בשעה: %3$s) לטיפולים. נא לבדוק ולהוסיף רשומה באופן ידני כנדרש.</string>
|
||||||
<string name="generated_ecarbs_note">פחמימות ממושכות: %1$d גר\' (%2$d ש\'), עיכוב %3$d דק\'</string>
|
<string name="generated_ecarbs_note">פחמימות ממושכות: %1$d גר\' (%2$d ש\'), עיכוב %3$d דק\'</string>
|
||||||
<string name="openaps_noasdata">אין נתוני autosens זמינים</string>
|
<string name="openaps_noasdata">אין נתוני Autosens זמינים</string>
|
||||||
<string name="nav_logsettings">הגדרות יומן רישום</string>
|
<string name="nav_logsettings">הגדרות יומן רישום</string>
|
||||||
<string name="resettodefaults">אפס לברירת המחדל</string>
|
<string name="resettodefaults">אפס לברירת המחדל</string>
|
||||||
<string name="nsmalfunction">תקלה ב-NSClient. שקלו להפעיל את Nightscout ו-NSClient מחדש.</string>
|
<string name="nsmalfunction">תקלה ב-NSClient. שקלו להפעיל את Nightscout ו-NSClient מחדש.</string>
|
||||||
|
@ -1158,4 +1160,5 @@
|
||||||
<string name="clear_filter">נקה סינון</string>
|
<string name="clear_filter">נקה סינון</string>
|
||||||
<string name="trend_arrow">חץ מגמה</string>
|
<string name="trend_arrow">חץ מגמה</string>
|
||||||
<string name="cannula">צינורית</string>
|
<string name="cannula">צינורית</string>
|
||||||
|
<string name="userentry">קלט המשתמש</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -420,6 +420,7 @@
|
||||||
<string name="basal_shortname">BAS</string>
|
<string name="basal_shortname">BAS</string>
|
||||||
<string name="deviation_shortname">DEV</string>
|
<string name="deviation_shortname">DEV</string>
|
||||||
<string name="activity_shortname">AKT</string>
|
<string name="activity_shortname">AKT</string>
|
||||||
|
<string name="bgi_shortname">-BGI</string>
|
||||||
<string name="abs_insulin_shortname">ABS</string>
|
<string name="abs_insulin_shortname">ABS</string>
|
||||||
<string name="devslope_shortname">DEVSLOPE</string>
|
<string name="devslope_shortname">DEVSLOPE</string>
|
||||||
<string name="nav_about">Om</string>
|
<string name="nav_about">Om</string>
|
||||||
|
@ -627,6 +628,7 @@
|
||||||
<string name="ns_autobackfill_summary">Hente manglende BS data fra NS</string>
|
<string name="ns_autobackfill_summary">Hente manglende BS data fra NS</string>
|
||||||
<string name="loop_smbsetbypump_label">SMB satt med pumpe</string>
|
<string name="loop_smbsetbypump_label">SMB satt med pumpe</string>
|
||||||
<string name="overview_show_activity">Aktivitet</string>
|
<string name="overview_show_activity">Aktivitet</string>
|
||||||
|
<string name="overview_show_bgi">Blodsukkerpåvirkning</string>
|
||||||
<string name="overview_show_sensitivity">Sensitivitet</string>
|
<string name="overview_show_sensitivity">Sensitivitet</string>
|
||||||
<string name="overview_show_deviations">Avvik</string>
|
<string name="overview_show_deviations">Avvik</string>
|
||||||
<string name="overview_show_cob">Aktive KH (COB)</string>
|
<string name="overview_show_cob">Aktive KH (COB)</string>
|
||||||
|
@ -1158,4 +1160,5 @@
|
||||||
<string name="clear_filter">Nullstill filtre</string>
|
<string name="clear_filter">Nullstill filtre</string>
|
||||||
<string name="trend_arrow">Trend pil</string>
|
<string name="trend_arrow">Trend pil</string>
|
||||||
<string name="cannula">Kanyle</string>
|
<string name="cannula">Kanyle</string>
|
||||||
|
<string name="userentry">Bruker registrering</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -96,7 +96,7 @@
|
||||||
<string name="whatistrue">Seleccione todas as respostas correctas.</string>
|
<string name="whatistrue">Seleccione todas as respostas correctas.</string>
|
||||||
<string name="update_git">Precisa ter Git instalado e configurado no computador.</string>
|
<string name="update_git">Precisa ter Git instalado e configurado no computador.</string>
|
||||||
<string name="update_asap">Quando as versões actualizadas do AndroidAPS são lançadas, as versões anteriores podem ser remotamente limitadas após um tempo específico.</string>
|
<string name="update_asap">Quando as versões actualizadas do AndroidAPS são lançadas, as versões anteriores podem ser remotamente limitadas após um tempo específico.</string>
|
||||||
<string name="update_keys">Deve guardar e anotar a localização da sua keystore e usar a mesma chave de assinatura para actualizações como para a instalação anterior.</string>
|
<string name="update_keys">Deve guardar e anotar a localização da sua keystore e utilizar a mesma chave de assinatura para actualizações como para a instalação anterior.</string>
|
||||||
<string name="update_neverupdate">Nunca actualize se o sistema estiver a funcionar bem.</string>
|
<string name="update_neverupdate">Nunca actualize se o sistema estiver a funcionar bem.</string>
|
||||||
<string name="update_askfriend">Se tiver dificuldade em construir o apk, pode instalar um apk que foi construído por um amigo.</string>
|
<string name="update_askfriend">Se tiver dificuldade em construir o apk, pode instalar um apk que foi construído por um amigo.</string>
|
||||||
<string name="update_hint1">https://androidaps.readthedocs.io/en/latest/EN/Installing-AndroidAPS/Update-to-new-version.html#update-to-a-new-version-or-branch</string>
|
<string name="update_hint1">https://androidaps.readthedocs.io/en/latest/EN/Installing-AndroidAPS/Update-to-new-version.html#update-to-a-new-version-or-branch</string>
|
||||||
|
@ -110,7 +110,7 @@
|
||||||
<string name="troubleshooting_hint2">https://www.facebook.com/groups/AndroidAPSUsers/</string>
|
<string name="troubleshooting_hint2">https://www.facebook.com/groups/AndroidAPSUsers/</string>
|
||||||
<string name="troubleshooting_hint3">https://gitter.im/MilosKozak/AndroidAPS</string>
|
<string name="troubleshooting_hint3">https://gitter.im/MilosKozak/AndroidAPS</string>
|
||||||
<string name="insulin_label">Plugins de Insulina</string>
|
<string name="insulin_label">Plugins de Insulina</string>
|
||||||
<string name="insulin_ultrarapid">Qual insulina deve usar com o plugin Ultra-Rapid Oref?</string>
|
<string name="insulin_ultrarapid">Qual insulina deve utilizar com o plugin Ultra-Rapid Oref?</string>
|
||||||
<string name="insulin_fiasp">Fiasp®</string>
|
<string name="insulin_fiasp">Fiasp®</string>
|
||||||
<string name="insulin_novorapid">NovoRapid®/Novolog®</string>
|
<string name="insulin_novorapid">NovoRapid®/Novolog®</string>
|
||||||
<string name="insulin_humalog">Humalog ®</string>
|
<string name="insulin_humalog">Humalog ®</string>
|
||||||
|
@ -148,7 +148,7 @@
|
||||||
<string name="breadgrams_calc">Se os níveis de glicose no sangue estiverem fora dos valores aceitáveis (muito baixos ou muito altos) a calculadora de bólus pode ser usada para fornecer sugestões para correções de hidratos ou insulina.</string>
|
<string name="breadgrams_calc">Se os níveis de glicose no sangue estiverem fora dos valores aceitáveis (muito baixos ou muito altos) a calculadora de bólus pode ser usada para fornecer sugestões para correções de hidratos ou insulina.</string>
|
||||||
<string name="breadgrams_hint1">https://androidaps.readthedocs.io/en/latest/EN/Getting-Started/FAQ.html#insulin-to-carb-ratio-ic-g-u</string>
|
<string name="breadgrams_hint1">https://androidaps.readthedocs.io/en/latest/EN/Getting-Started/FAQ.html#insulin-to-carb-ratio-ic-g-u</string>
|
||||||
<string name="extendedcarbs_label">hidratos-e</string>
|
<string name="extendedcarbs_label">hidratos-e</string>
|
||||||
<string name="extendedcarbs_handling">Para que poderia usar os hidratos-e (hidratos estendidos)?</string>
|
<string name="extendedcarbs_handling">Para que poderia utilizar os hidratos-e (hidratos estendidos)?</string>
|
||||||
<string name="extendedcarbs_future">Para agendar hidratos no futuro, possivelmente distribuídos num intervalo (semelhante a um bólus estendido que distribui insulina por um intervalo).</string>
|
<string name="extendedcarbs_future">Para agendar hidratos no futuro, possivelmente distribuídos num intervalo (semelhante a um bólus estendido que distribui insulina por um intervalo).</string>
|
||||||
<string name="extendedcarbs_free">Para registar hidratos \'livres\' ingeridos em exercícios que deseja esconder do AndroidAPS.</string>
|
<string name="extendedcarbs_free">Para registar hidratos \'livres\' ingeridos em exercícios que deseja esconder do AndroidAPS.</string>
|
||||||
<string name="extendedcarbs_fat">Os hidratos-e (distribuídos no futuro) podem ajudar o AndroidAPS a lidar com comidas gorduras/proteínas elevadas.</string>
|
<string name="extendedcarbs_fat">Os hidratos-e (distribuídos no futuro) podem ajudar o AndroidAPS a lidar com comidas gorduras/proteínas elevadas.</string>
|
||||||
|
@ -169,7 +169,7 @@
|
||||||
<string name="isf_profile">A alteração do valor do FSI no seu perfil é suficiente para aplicar a mudança.</string>
|
<string name="isf_profile">A alteração do valor do FSI no seu perfil é suficiente para aplicar a mudança.</string>
|
||||||
<string name="isf_hint1">https://androidaps.readthedocs.io/en/latest/EN/Getting-Started/FAQ.html#insulin-sensitivity-factor-isf-mmol-l-u-or-mg-dl-u</string>
|
<string name="isf_hint1">https://androidaps.readthedocs.io/en/latest/EN/Getting-Started/FAQ.html#insulin-sensitivity-factor-isf-mmol-l-u-or-mg-dl-u</string>
|
||||||
<string name="isf_hint2">https://androidaps.readthedocs.io/en/latest/EN/Usage/Profiles.html</string>
|
<string name="isf_hint2">https://androidaps.readthedocs.io/en/latest/EN/Usage/Profiles.html</string>
|
||||||
<string name="ic_multiple">Pode usar mais de um valor para o rácio I:HC no seu perfil.</string>
|
<string name="ic_multiple">Pode utilizar mais de um valor para o rácio I:HC no seu perfil.</string>
|
||||||
<string name="ic_isf">Se alterar o seu FSI no perfil, também deve mudar a taxa de I:HC.</string>
|
<string name="ic_isf">Se alterar o seu FSI no perfil, também deve mudar a taxa de I:HC.</string>
|
||||||
<string name="ic_label_exam">Rácio Insulina por Hidratos de Carbono (Rácio I:HC)</string>
|
<string name="ic_label_exam">Rácio Insulina por Hidratos de Carbono (Rácio I:HC)</string>
|
||||||
<string name="ic_increasingvalue">Rácios I:HC mais altos levam a menos insulina administrada para uma dada quantidade de hidratos.</string>
|
<string name="ic_increasingvalue">Rácios I:HC mais altos levam a menos insulina administrada para uma dada quantidade de hidratos.</string>
|
||||||
|
@ -211,5 +211,5 @@
|
||||||
<string name="basalhelp_facebook">Facebook</string>
|
<string name="basalhelp_facebook">Facebook</string>
|
||||||
<string name="other_medication_label">Outra Medicação. Por favor, leia declaração abaixo e marque a caixa para aceitá-la.</string>
|
<string name="other_medication_label">Outra Medicação. Por favor, leia declaração abaixo e marque a caixa para aceitá-la.</string>
|
||||||
<string name="other_medication_text">AndroidAPS reduz as taxas de basal ou suspende a administração de insulina para aumentar a quantidade de açúcar no sangue. Os medicamentos da classe inibidores SGLT2 (gliflozins) podem evitar aumentos da glicose no sangue e, por conseguinte, podem produzir uma perigosa deficiência de insulina que leva à DKA.
|
<string name="other_medication_text">AndroidAPS reduz as taxas de basal ou suspende a administração de insulina para aumentar a quantidade de açúcar no sangue. Os medicamentos da classe inibidores SGLT2 (gliflozins) podem evitar aumentos da glicose no sangue e, por conseguinte, podem produzir uma perigosa deficiência de insulina que leva à DKA.
|
||||||
\nOs nomes comuns são: Invokana®, Forxiga®, Jardiance®, Steglatro®, Suglat®, Apleway®, Deberza®, Synjardy®, Vokanamet®, Xigduo®,\n\nPrometo pelo presente que não tomarei tal medicação ao usar o AndroidAPS ou que desactivarei o loop antes de usar tais medicamentos.</string>
|
\nOs nomes comuns são: Invokana®, Forxiga®, Jardiance®, Steglatro®, Suglat®, Apleway®, Deberza®, Synjardy®, Vokanamet®, Xigduo®,\n\nPrometo pelo presente que não tomarei tal medicação ao U«ytilizar o AndroidAPS ou que desactivarei o loop antes de usar tais medicamentos.</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
<string name="nav_resetdb">Reinicializar Base de Dados</string>
|
<string name="nav_resetdb">Reinicializar Base de Dados</string>
|
||||||
<string name="reset_db_confirm">Quer realmente reiniciar a base de dados?</string>
|
<string name="reset_db_confirm">Quer realmente reiniciar a base de dados?</string>
|
||||||
<string name="nav_exit">Sair</string>
|
<string name="nav_exit">Sair</string>
|
||||||
<string name="ns_sync_use_absolute_title">Usar sempre valores absolutos de basal</string>
|
<string name="ns_sync_use_absolute_title">Utilizar sempre valores absolutos de basal</string>
|
||||||
<string name="alert_dialog_permission_battery_optimization_failed">Este dispositivo não parece suportar a optimização de bateria na lista de permissões - pode ter problemas de desempenho.</string>
|
<string name="alert_dialog_permission_battery_optimization_failed">Este dispositivo não parece suportar a optimização de bateria na lista de permissões - pode ter problemas de desempenho.</string>
|
||||||
<string name="description_actions">Alguns botões para aceder rapidamente a funções comuns</string>
|
<string name="description_actions">Alguns botões para aceder rapidamente a funções comuns</string>
|
||||||
<string name="description_config_builder">Usado para configurar os plugins ativos</string>
|
<string name="description_config_builder">Usado para configurar os plugins ativos</string>
|
||||||
|
@ -86,7 +86,7 @@
|
||||||
<string name="virtualpump">Bomba virtual</string>
|
<string name="virtualpump">Bomba virtual</string>
|
||||||
<string name="careportal">Careportal</string>
|
<string name="careportal">Careportal</string>
|
||||||
<string name="configbuilder_pump">Bomba</string>
|
<string name="configbuilder_pump">Bomba</string>
|
||||||
<string name="configbuilder_pump_description">Qual a bomba que gostaria de usar com AndroidAPS?</string>
|
<string name="configbuilder_pump_description">Qual a bomba que gostaria de utilizar com AndroidAPS?</string>
|
||||||
<string name="configbuilder_treatments">Tratamentos</string>
|
<string name="configbuilder_treatments">Tratamentos</string>
|
||||||
<string name="configbuilder_treatments_description">Qual o plugin que deve ser usado para os tratamentos?</string>
|
<string name="configbuilder_treatments_description">Qual o plugin que deve ser usado para os tratamentos?</string>
|
||||||
<string name="configbuilder_profile">Perfil</string>
|
<string name="configbuilder_profile">Perfil</string>
|
||||||
|
@ -285,7 +285,7 @@
|
||||||
<string name="array_of_elements">Array de %1$d elementos.\nValor actual:</string>
|
<string name="array_of_elements">Array de %1$d elementos.\nValor actual:</string>
|
||||||
<string name="openapsma_autosensdata_label">Dados Autosens</string>
|
<string name="openapsma_autosensdata_label">Dados Autosens</string>
|
||||||
<string name="openapsma_scriptdebugdata_label">Script debug</string>
|
<string name="openapsma_scriptdebugdata_label">Script debug</string>
|
||||||
<string name="openapsama_useautosens">Usar função Autosens</string>
|
<string name="openapsama_useautosens">Utilizar função Autosens</string>
|
||||||
<string name="refresheventsfromnightscout">Actualizar tratamentos do NS</string>
|
<string name="refresheventsfromnightscout">Actualizar tratamentos do NS</string>
|
||||||
<string name="deletefuturetreatments">Apagar tratamentos do futuro</string>
|
<string name="deletefuturetreatments">Apagar tratamentos do futuro</string>
|
||||||
<string name="eatingsoon">Comer Brevemente</string>
|
<string name="eatingsoon">Comer Brevemente</string>
|
||||||
|
@ -305,7 +305,7 @@
|
||||||
<string name="wear_shortname">WEAR</string>
|
<string name="wear_shortname">WEAR</string>
|
||||||
<string name="smscommunicator_shortname">SMS</string>
|
<string name="smscommunicator_shortname">SMS</string>
|
||||||
<string name="short_tabtitles">Abreviar títulos dos separadores</string>
|
<string name="short_tabtitles">Abreviar títulos dos separadores</string>
|
||||||
<string name="always_use_shortavg">Usar sempre delta médio curto em vez de delta simples</string>
|
<string name="always_use_shortavg">Utilizar sempre delta médio curto em vez de delta simples</string>
|
||||||
<string name="always_use_shortavg_summary">Útil quando há ruído nos dados de fontes sem filtro como xDrip+.</string>
|
<string name="always_use_shortavg_summary">Útil quando há ruído nos dados de fontes sem filtro como xDrip+.</string>
|
||||||
<string name="profile">Perfil</string>
|
<string name="profile">Perfil</string>
|
||||||
<string name="openapsama_max_daily_safety_multiplier_summary">Valor padrão: 3 Por segurança é o valor limite estabelecido por OpenAPS. O que faz é limitar a basal a x3 a basal mázima. Se necessário modificar este valor, por favor ter em conta que os dados apontam para que os limites de segurança sejam - 3 x max diario ou 4x valor actual (qual seja menor) como valores máximos.</string>
|
<string name="openapsama_max_daily_safety_multiplier_summary">Valor padrão: 3 Por segurança é o valor limite estabelecido por OpenAPS. O que faz é limitar a basal a x3 a basal mázima. Se necessário modificar este valor, por favor ter em conta que os dados apontam para que os limites de segurança sejam - 3 x max diario ou 4x valor actual (qual seja menor) como valores máximos.</string>
|
||||||
|
@ -398,7 +398,7 @@
|
||||||
<string name="ultrafastactinginsulincomment">Fiasp</string>
|
<string name="ultrafastactinginsulincomment">Fiasp</string>
|
||||||
<string name="insulin_shortname">INS</string>
|
<string name="insulin_shortname">INS</string>
|
||||||
<string name="enablesuperbolus">Activar superbólus no assistente</string>
|
<string name="enablesuperbolus">Activar superbólus no assistente</string>
|
||||||
<string name="enablesuperbolus_summary">Habilite a funcionalidade de superbolus no assistente. Não habilite até que aprenda o funcionamento. PODE CAUSAR OVERDOSE DE INSULINA SE USAR INDISCRIMINADAMENTE!</string>
|
<string name="enablesuperbolus_summary">Active a funcionalidade de superbolus no assistente. Não active até que aprenda o funcionamento. PODE CAUSAR OVERDOSE DE INSULINA SE UTILIZAR INDISCRIMINADAMENTE!</string>
|
||||||
<string name="show_statuslights">Mostrar luzes de estado no ecrã principal</string>
|
<string name="show_statuslights">Mostrar luzes de estado no ecrã principal</string>
|
||||||
<string name="statuslights_cage_warning">Limite aviso idade canula [h]</string>
|
<string name="statuslights_cage_warning">Limite aviso idade canula [h]</string>
|
||||||
<string name="statuslights_cage_critical">Limite Crítico Idade Canula [h]</string>
|
<string name="statuslights_cage_critical">Limite Crítico Idade Canula [h]</string>
|
||||||
|
@ -420,6 +420,7 @@
|
||||||
<string name="basal_shortname">BAS</string>
|
<string name="basal_shortname">BAS</string>
|
||||||
<string name="deviation_shortname">DESV</string>
|
<string name="deviation_shortname">DESV</string>
|
||||||
<string name="activity_shortname">ACT</string>
|
<string name="activity_shortname">ACT</string>
|
||||||
|
<string name="bgi_shortname">-IG</string>
|
||||||
<string name="abs_insulin_shortname">ABS</string>
|
<string name="abs_insulin_shortname">ABS</string>
|
||||||
<string name="devslope_shortname">DESVINCLI</string>
|
<string name="devslope_shortname">DESVINCLI</string>
|
||||||
<string name="nav_about">Acerca</string>
|
<string name="nav_about">Acerca</string>
|
||||||
|
@ -508,7 +509,7 @@
|
||||||
<string name="executingrightnow">Comando será executado agora</string>
|
<string name="executingrightnow">Comando será executado agora</string>
|
||||||
<string name="pump_unreachable">Bomba inacessível</string>
|
<string name="pump_unreachable">Bomba inacessível</string>
|
||||||
<string name="missed_bg_readings">Leituras Glicose perdidas</string>
|
<string name="missed_bg_readings">Leituras Glicose perdidas</string>
|
||||||
<string name="raise_notifications_as_android_notifications">Usar as notificações do sistema para alertas e notificações</string>
|
<string name="raise_notifications_as_android_notifications">Utilizar as notificações do sistema para alertas e notificações</string>
|
||||||
<string name="gradually_increase_notification_volume">Aumentar gradualmente o volume de alertas e notificações</string>
|
<string name="gradually_increase_notification_volume">Aumentar gradualmente o volume de alertas e notificações</string>
|
||||||
<string name="localalertsettings_title">Alertas local</string>
|
<string name="localalertsettings_title">Alertas local</string>
|
||||||
<string name="enable_missed_bg_readings_alert">Alerta caso nenhuma Glicose seja recebida</string>
|
<string name="enable_missed_bg_readings_alert">Alerta caso nenhuma Glicose seja recebida</string>
|
||||||
|
@ -627,6 +628,7 @@
|
||||||
<string name="ns_autobackfill_summary">Preencher Glicose em falta com NS</string>
|
<string name="ns_autobackfill_summary">Preencher Glicose em falta com NS</string>
|
||||||
<string name="loop_smbsetbypump_label">SMB definido pela bomba</string>
|
<string name="loop_smbsetbypump_label">SMB definido pela bomba</string>
|
||||||
<string name="overview_show_activity">Actividade</string>
|
<string name="overview_show_activity">Actividade</string>
|
||||||
|
<string name="overview_show_bgi">Impacto Glicose</string>
|
||||||
<string name="overview_show_sensitivity">Sensibilidade</string>
|
<string name="overview_show_sensitivity">Sensibilidade</string>
|
||||||
<string name="overview_show_deviations">Desvios</string>
|
<string name="overview_show_deviations">Desvios</string>
|
||||||
<string name="overview_show_cob">Hidratos a Bordo (COB)</string>
|
<string name="overview_show_cob">Hidratos a Bordo (COB)</string>
|
||||||
|
@ -727,7 +729,7 @@
|
||||||
<string name="nsclientinfotext">ClienteNS gere a ligação ao Nightscout. Pode saltar esta parte mas não será possível passar os objectivos até que o configure.</string>
|
<string name="nsclientinfotext">ClienteNS gere a ligação ao Nightscout. Pode saltar esta parte mas não será possível passar os objectivos até que o configure.</string>
|
||||||
<string name="diawarning">Lembre-se: novos perfis de insulina requerem diâmetro de pelo menos 5h. DIA 5–6h no novo perfil é igual ao diâmetro 3h nos antigos perfis de insulina.</string>
|
<string name="diawarning">Lembre-se: novos perfis de insulina requerem diâmetro de pelo menos 5h. DIA 5–6h no novo perfil é igual ao diâmetro 3h nos antigos perfis de insulina.</string>
|
||||||
<string name="setupwizard_profile_description">Por favor seleccione a fonte do perfil. Se o paciente é uma criança deverá utilizar perfil NS. Se ninguém o está a seguir no Nightscout provavelmente preferirá um perfil Local. Lembre-se que apenas está a escolher a fonte de perfil. Para o utilizar terá que o activar executando \"Troca Perfil\"</string>
|
<string name="setupwizard_profile_description">Por favor seleccione a fonte do perfil. Se o paciente é uma criança deverá utilizar perfil NS. Se ninguém o está a seguir no Nightscout provavelmente preferirá um perfil Local. Lembre-se que apenas está a escolher a fonte de perfil. Para o utilizar terá que o activar executando \"Troca Perfil\"</string>
|
||||||
<string name="setupwizard_aps_description">Seleccione um dos algoritmos disponíveis. Eles são classificados do mais antigo para o mais recente. Algoritmo mais recente é geralmente mais forte e mais agressivo. Assim, se é novo looper, poderá provavelmente começar com AMA e não com a versão mais recente. Não se esqueça de ler a documentação de OpenAPS e configurá-lo antes de usar.</string>
|
<string name="setupwizard_aps_description">Seleccione um dos algoritmos disponíveis. Eles são classificados do mais antigo para o mais recente. Algoritmo mais recente é geralmente mais forte e mais agressivo. Assim, se é novo looper, poderá provavelmente começar com AMA e não com a versão mais recente. Não se esqueça de ler a documentação de OpenAPS e configurá-lo antes de utilizar.</string>
|
||||||
<string name="setupwizard_pump_waiting_for_riley_link_connection">Por favor, configure o seu RileyLink abaixo. Depois de seleccionar um RileyLink, será possível continuar a configuração quando o estado do RileyLink estiver \"Conectado\". Isso pode levar um minuto.\n</string>
|
<string name="setupwizard_pump_waiting_for_riley_link_connection">Por favor, configure o seu RileyLink abaixo. Depois de seleccionar um RileyLink, será possível continuar a configuração quando o estado do RileyLink estiver \"Conectado\". Isso pode levar um minuto.\n</string>
|
||||||
<string name="setupwizard_pump_pump_not_initialized"><b>Nota:</b> Pode continuar confguração uma vez que a bomba foi configurada.\n</string>
|
<string name="setupwizard_pump_pump_not_initialized"><b>Nota:</b> Pode continuar confguração uma vez que a bomba foi configurada.\n</string>
|
||||||
<string name="startobjective">Iniciar primeiro objectivo</string>
|
<string name="startobjective">Iniciar primeiro objectivo</string>
|
||||||
|
@ -801,7 +803,7 @@
|
||||||
<string name="log_operating_mode_changes">Alterações do modo de funcionamento de registo</string>
|
<string name="log_operating_mode_changes">Alterações do modo de funcionamento de registo</string>
|
||||||
<string name="log_alerts">Alertas de registo</string>
|
<string name="log_alerts">Alertas de registo</string>
|
||||||
<string name="enable_tbr_emulation">Activar a emulação DBT</string>
|
<string name="enable_tbr_emulation">Activar a emulação DBT</string>
|
||||||
<string name="enable_tbr_emulation_summary">Usar bólus prolongados em vez de basais temporárias para contornar o limite de 250%%</string>
|
<string name="enable_tbr_emulation_summary">Utilizar bólus prolongados em vez de basais temporárias para contornar o limite de 250%%</string>
|
||||||
<string name="disable_vibration">Desactivar vibrações na entrega manual de bólus</string>
|
<string name="disable_vibration">Desactivar vibrações na entrega manual de bólus</string>
|
||||||
<string name="disable_vibration_summary">Para bólus e bólus estendidos (só disponível com o firmware Insight 3.x)</string>
|
<string name="disable_vibration_summary">Para bólus e bólus estendidos (só disponível com o firmware Insight 3.x)</string>
|
||||||
<string name="disable_vibration_auto">Desactivar vibrações na entrega automática de bólus</string>
|
<string name="disable_vibration_auto">Desactivar vibrações na entrega automática de bólus</string>
|
||||||
|
@ -883,9 +885,9 @@
|
||||||
<string name="or">Ou</string>
|
<string name="or">Ou</string>
|
||||||
<string name="xor">Exclusivo ou</string>
|
<string name="xor">Exclusivo ou</string>
|
||||||
<string name="atspecifiedtime">Às %1$s</string>
|
<string name="atspecifiedtime">Às %1$s</string>
|
||||||
<string name="use_network_location">Usar localização da rede</string>
|
<string name="use_network_location">Utilizar localização da rede</string>
|
||||||
<string name="use_gps_location">Usar localização GPS</string>
|
<string name="use_gps_location">Utilizar localização GPS</string>
|
||||||
<string name="use_passive_location">Usar localização passiva</string>
|
<string name="use_passive_location">Utilizar localização passiva</string>
|
||||||
<string name="locationservice">Serviço de localização</string>
|
<string name="locationservice">Serviço de localização</string>
|
||||||
<string name="automation_short">Auto</string>
|
<string name="automation_short">Auto</string>
|
||||||
<string name="automation">Automatização</string>
|
<string name="automation">Automatização</string>
|
||||||
|
@ -900,7 +902,7 @@
|
||||||
<string name="title_tidepool_password">Senha Login</string>
|
<string name="title_tidepool_password">Senha Login</string>
|
||||||
<string name="title_tidepool_test_login">Teste de Conta Tidepool</string>
|
<string name="title_tidepool_test_login">Teste de Conta Tidepool</string>
|
||||||
<string name="summary_tidepool_dev_servers">Se activado, envio será para https://int-app.tidepool.org em vez do habitual https://app.tidepool.org/</string>
|
<string name="summary_tidepool_dev_servers">Se activado, envio será para https://int-app.tidepool.org em vez do habitual https://app.tidepool.org/</string>
|
||||||
<string name="title_tidepool_dev_servers">Usar servidores de integração (teste)</string>
|
<string name="title_tidepool_dev_servers">Utilizar servidores de integração (teste)</string>
|
||||||
<string name="tidepool">Tidepool</string>
|
<string name="tidepool">Tidepool</string>
|
||||||
<string name="tidepool_shortname">TDP</string>
|
<string name="tidepool_shortname">TDP</string>
|
||||||
<string name="description_tidepool">Enviar dados para Tidepool</string>
|
<string name="description_tidepool">Enviar dados para Tidepool</string>
|
||||||
|
@ -1147,7 +1149,7 @@
|
||||||
<string name="advisoralarm">Executar alarme quando for tempo de comer</string>
|
<string name="advisoralarm">Executar alarme quando for tempo de comer</string>
|
||||||
<string name="alarminxmin">Executar alarme em %1$d min</string>
|
<string name="alarminxmin">Executar alarme em %1$d min</string>
|
||||||
<string name="bolusadvisor">Guia de Bólus</string>
|
<string name="bolusadvisor">Guia de Bólus</string>
|
||||||
<string name="bolusadvisormessage">Tem glicemia alta. Em vez de comer agora é recomendado esperar por uma melhor glicemia. Quer fazer um bólus de correção agora e lembrá-lo quando fôr hora de comer? Neste caso nenhum hidrato será registado e deve usar o assistente novamente quando for lembrado.</string>
|
<string name="bolusadvisormessage">Tem glicemia alta. Em vez de comer agora é recomendado esperar por uma melhor glicemia. Quer fazer um bólus de correção agora e lembrá-lo quando fôr hora de comer? Neste caso nenhum hidrato será registado e deve utilizar o assistente novamente quando for lembrado.</string>
|
||||||
<string name="enablebolusadvisor">Activar Guia de Bólus</string>
|
<string name="enablebolusadvisor">Activar Guia de Bólus</string>
|
||||||
<string name="enablebolusadvisor_summary">Use lembrete para começar a comer mais tarde em vez di resultado do assistente durante a glicemia alta (\"pré-bolus\")</string>
|
<string name="enablebolusadvisor_summary">Use lembrete para começar a comer mais tarde em vez di resultado do assistente durante a glicemia alta (\"pré-bolus\")</string>
|
||||||
<string name="time_to_eat">Hora de comer!\nExecutar assistente de Bólus e fazer cálculo novamente.</string>
|
<string name="time_to_eat">Hora de comer!\nExecutar assistente de Bólus e fazer cálculo novamente.</string>
|
||||||
|
@ -1158,4 +1160,5 @@
|
||||||
<string name="clear_filter">Limpar filtros</string>
|
<string name="clear_filter">Limpar filtros</string>
|
||||||
<string name="trend_arrow">Seta de tendência</string>
|
<string name="trend_arrow">Seta de tendência</string>
|
||||||
<string name="cannula">Cânula</string>
|
<string name="cannula">Cânula</string>
|
||||||
|
<string name="userentry">Entrada de Utilizador</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -420,6 +420,7 @@
|
||||||
<string name="basal_shortname">БАЗ</string>
|
<string name="basal_shortname">БАЗ</string>
|
||||||
<string name="deviation_shortname">ОТКЛН</string>
|
<string name="deviation_shortname">ОТКЛН</string>
|
||||||
<string name="activity_shortname">НАГР</string>
|
<string name="activity_shortname">НАГР</string>
|
||||||
|
<string name="bgi_shortname">-BGI</string>
|
||||||
<string name="abs_insulin_shortname">НАДО</string>
|
<string name="abs_insulin_shortname">НАДО</string>
|
||||||
<string name="devslope_shortname">ЛИНОТКЛН</string>
|
<string name="devslope_shortname">ЛИНОТКЛН</string>
|
||||||
<string name="nav_about">о приложении</string>
|
<string name="nav_about">о приложении</string>
|
||||||
|
@ -627,6 +628,7 @@
|
||||||
<string name="ns_autobackfill_summary">Заполнять пропущенные данные из NS</string>
|
<string name="ns_autobackfill_summary">Заполнять пропущенные данные из NS</string>
|
||||||
<string name="loop_smbsetbypump_label">Супер микро болюс SMB задан помпой</string>
|
<string name="loop_smbsetbypump_label">Супер микро болюс SMB задан помпой</string>
|
||||||
<string name="overview_show_activity">Нагрузка</string>
|
<string name="overview_show_activity">Нагрузка</string>
|
||||||
|
<string name="overview_show_bgi">Влияние глюкозы</string>
|
||||||
<string name="overview_show_sensitivity">Чувствительность</string>
|
<string name="overview_show_sensitivity">Чувствительность</string>
|
||||||
<string name="overview_show_deviations">Отклонение</string>
|
<string name="overview_show_deviations">Отклонение</string>
|
||||||
<string name="overview_show_cob">Активные углеводы COB</string>
|
<string name="overview_show_cob">Активные углеводы COB</string>
|
||||||
|
@ -1160,4 +1162,5 @@ Context | Edit Context</string>
|
||||||
<string name="clear_filter">Очистить фильтр</string>
|
<string name="clear_filter">Очистить фильтр</string>
|
||||||
<string name="trend_arrow">Стрелка тренда</string>
|
<string name="trend_arrow">Стрелка тренда</string>
|
||||||
<string name="cannula">Катетер помпы</string>
|
<string name="cannula">Катетер помпы</string>
|
||||||
|
<string name="userentry">Запись пользователя</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -1381,5 +1381,6 @@
|
||||||
<string name="trend_arrow">Trend arrow</string>
|
<string name="trend_arrow">Trend arrow</string>
|
||||||
<string name="cannula">Cannula</string>
|
<string name="cannula">Cannula</string>
|
||||||
<string name="userentry">User entry</string>
|
<string name="userentry">User entry</string>
|
||||||
|
<string name="common_values">Use values of your largest food you usually eat\n</string>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -8,18 +8,18 @@
|
||||||
|
|
||||||
<SwitchPreference
|
<SwitchPreference
|
||||||
android:defaultValue="false"
|
android:defaultValue="false"
|
||||||
android:key="wearcontrol"
|
android:key="@string/key_wear_control"
|
||||||
android:summary="@string/wearcontrol_summary"
|
android:summary="@string/wearcontrol_summary"
|
||||||
android:title="@string/wearcontrol_title" />
|
android:title="@string/wearcontrol_title" />
|
||||||
|
|
||||||
<PreferenceCategory
|
<PreferenceCategory
|
||||||
android:dependency="wearcontrol"
|
android:dependency="@string/key_wear_control"
|
||||||
android:summary="@string/wear_wizard_settings_summary"
|
android:summary="@string/wear_wizard_settings_summary"
|
||||||
android:title="@string/wear_wizard_settings">
|
android:title="@string/wear_wizard_settings">
|
||||||
|
|
||||||
<CheckBoxPreference
|
<CheckBoxPreference
|
||||||
android:defaultValue="true"
|
android:defaultValue="true"
|
||||||
android:dependency="wearcontrol"
|
android:dependency="@string/key_wear_control"
|
||||||
android:key="@string/key_wearwizard_bg"
|
android:key="@string/key_wearwizard_bg"
|
||||||
android:title="@string/treatments_wizard_bg_label" />
|
android:title="@string/treatments_wizard_bg_label" />
|
||||||
|
|
||||||
|
@ -31,25 +31,25 @@
|
||||||
|
|
||||||
<CheckBoxPreference
|
<CheckBoxPreference
|
||||||
android:defaultValue="false"
|
android:defaultValue="false"
|
||||||
android:dependency="wearcontrol"
|
android:dependency="@string/key_wear_control"
|
||||||
android:key="@string/key_wearwizard_trend"
|
android:key="@string/key_wearwizard_trend"
|
||||||
android:title="@string/treatments_wizard_bgtrend_label" />
|
android:title="@string/treatments_wizard_bgtrend_label" />
|
||||||
|
|
||||||
<CheckBoxPreference
|
<CheckBoxPreference
|
||||||
android:defaultValue="true"
|
android:defaultValue="true"
|
||||||
android:dependency="wearcontrol"
|
android:dependency="@string/key_wear_control"
|
||||||
android:key="@string/key_wearwizard_cob"
|
android:key="@string/key_wearwizard_cob"
|
||||||
android:title="@string/treatments_wizard_cob_label" />
|
android:title="@string/treatments_wizard_cob_label" />
|
||||||
|
|
||||||
<CheckBoxPreference
|
<CheckBoxPreference
|
||||||
android:defaultValue="true"
|
android:defaultValue="true"
|
||||||
android:dependency="wearcontrol"
|
android:dependency="@string/key_wear_control"
|
||||||
android:key="@string/key_wearwizard_bolusiob"
|
android:key="@string/key_wearwizard_bolusiob"
|
||||||
android:title="@string/treatments_wizard_bolusiob_label" />
|
android:title="@string/treatments_wizard_bolusiob_label" />
|
||||||
|
|
||||||
<CheckBoxPreference
|
<CheckBoxPreference
|
||||||
android:defaultValue="true"
|
android:defaultValue="true"
|
||||||
android:dependency="wearcontrol"
|
android:dependency="@string/key_wear_control"
|
||||||
android:key="@string/key_wearwizard_basaliob"
|
android:key="@string/key_wearwizard_basaliob"
|
||||||
android:title="@string/treatments_wizard_basaliob_label" />
|
android:title="@string/treatments_wizard_basaliob_label" />
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,9 @@ import info.nightscout.androidaps.MainApp
|
||||||
import info.nightscout.androidaps.R
|
import info.nightscout.androidaps.R
|
||||||
import info.nightscout.androidaps.TestBaseWithProfile
|
import info.nightscout.androidaps.TestBaseWithProfile
|
||||||
import info.nightscout.androidaps.dana.DanaPump
|
import info.nightscout.androidaps.dana.DanaPump
|
||||||
|
import info.nightscout.androidaps.danar.DanaRPlugin
|
||||||
|
import info.nightscout.androidaps.danars.DanaRSPlugin
|
||||||
|
import info.nightscout.androidaps.logging.UserEntryLogger
|
||||||
import info.nightscout.androidaps.plugins.aps.openAPSAMA.OpenAPSAMAPlugin
|
import info.nightscout.androidaps.plugins.aps.openAPSAMA.OpenAPSAMAPlugin
|
||||||
import info.nightscout.androidaps.plugins.aps.openAPSSMB.OpenAPSSMBPlugin
|
import info.nightscout.androidaps.plugins.aps.openAPSSMB.OpenAPSSMBPlugin
|
||||||
import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin
|
import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin
|
||||||
|
@ -20,8 +23,6 @@ import info.nightscout.androidaps.plugins.general.nsclient.UploadQueue
|
||||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin
|
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin
|
||||||
import info.nightscout.androidaps.plugins.pump.combo.ComboPlugin
|
import info.nightscout.androidaps.plugins.pump.combo.ComboPlugin
|
||||||
import info.nightscout.androidaps.plugins.pump.common.bolusInfo.DetailedBolusInfoStorage
|
import info.nightscout.androidaps.plugins.pump.common.bolusInfo.DetailedBolusInfoStorage
|
||||||
import info.nightscout.androidaps.danar.DanaRPlugin
|
|
||||||
import info.nightscout.androidaps.danars.DanaRSPlugin
|
|
||||||
import info.nightscout.androidaps.plugins.pump.insight.LocalInsightPlugin
|
import info.nightscout.androidaps.plugins.pump.insight.LocalInsightPlugin
|
||||||
import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpPlugin
|
import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpPlugin
|
||||||
import info.nightscout.androidaps.plugins.sensitivity.SensitivityOref1Plugin
|
import info.nightscout.androidaps.plugins.sensitivity.SensitivityOref1Plugin
|
||||||
|
@ -46,7 +47,7 @@ import java.util.*
|
||||||
* Created by mike on 18.03.2018.
|
* Created by mike on 18.03.2018.
|
||||||
*/
|
*/
|
||||||
@RunWith(PowerMockRunner::class)
|
@RunWith(PowerMockRunner::class)
|
||||||
@PrepareForTest(MainApp::class, ConfigBuilderPlugin::class, ConstraintChecker::class, SP::class, Context::class, OpenAPSAMAPlugin::class, OpenAPSSMBPlugin::class, TreatmentsPlugin::class, TreatmentService::class, VirtualPumpPlugin::class, DetailedBolusInfoStorage::class, GlimpPlugin::class, Profiler::class)
|
@PrepareForTest(MainApp::class, ConfigBuilderPlugin::class, ConstraintChecker::class, SP::class, Context::class, OpenAPSAMAPlugin::class, OpenAPSSMBPlugin::class, TreatmentsPlugin::class, TreatmentService::class, VirtualPumpPlugin::class, DetailedBolusInfoStorage::class, GlimpPlugin::class, Profiler::class, UserEntryLogger::class)
|
||||||
class ConstraintsCheckerTest : TestBaseWithProfile() {
|
class ConstraintsCheckerTest : TestBaseWithProfile() {
|
||||||
|
|
||||||
@Mock lateinit var activePlugin: ActivePluginProvider
|
@Mock lateinit var activePlugin: ActivePluginProvider
|
||||||
|
@ -61,6 +62,7 @@ class ConstraintsCheckerTest : TestBaseWithProfile() {
|
||||||
@Mock lateinit var profiler: Profiler
|
@Mock lateinit var profiler: Profiler
|
||||||
@Mock lateinit var nsUpload: NSUpload
|
@Mock lateinit var nsUpload: NSUpload
|
||||||
@Mock lateinit var uploadQueue: UploadQueue
|
@Mock lateinit var uploadQueue: UploadQueue
|
||||||
|
@Mock lateinit var uel: UserEntryLogger
|
||||||
|
|
||||||
private var buildHelper = BuildHelper(Config())
|
private var buildHelper = BuildHelper(Config())
|
||||||
lateinit var danaPump: DanaPump
|
lateinit var danaPump: DanaPump
|
||||||
|
@ -115,12 +117,12 @@ class ConstraintsCheckerTest : TestBaseWithProfile() {
|
||||||
|
|
||||||
danaPump = DanaPump(aapsLogger, sp, injector)
|
danaPump = DanaPump(aapsLogger, sp, injector)
|
||||||
hardLimits = HardLimits(aapsLogger, rxBus, sp, resourceHelper, context, nsUpload)
|
hardLimits = HardLimits(aapsLogger, rxBus, sp, resourceHelper, context, nsUpload)
|
||||||
objectivesPlugin = ObjectivesPlugin(injector, aapsLogger, resourceHelper, activePlugin, sp, Config())
|
objectivesPlugin = ObjectivesPlugin(injector, aapsLogger, resourceHelper, activePlugin, sp, Config(), uel)
|
||||||
comboPlugin = ComboPlugin(injector, aapsLogger, rxBus, resourceHelper, profileFunction, treatmentsPlugin, sp, commandQueue, context)
|
comboPlugin = ComboPlugin(injector, aapsLogger, rxBus, resourceHelper, profileFunction, treatmentsPlugin, sp, commandQueue, context)
|
||||||
danaRPlugin = DanaRPlugin(injector, aapsLogger, aapsSchedulers, rxBus, context, resourceHelper, constraintChecker, activePlugin, sp, commandQueue, danaPump, dateUtil, fabricPrivacy)
|
danaRPlugin = DanaRPlugin(injector, aapsLogger, aapsSchedulers, rxBus, context, resourceHelper, constraintChecker, activePlugin, sp, commandQueue, danaPump, dateUtil, fabricPrivacy)
|
||||||
danaRSPlugin = DanaRSPlugin(injector, aapsLogger, aapsSchedulers, rxBus, context, resourceHelper, constraintChecker, profileFunction, activePluginProvider, sp, commandQueue, danaPump, detailedBolusInfoStorage, fabricPrivacy, dateUtil)
|
danaRSPlugin = DanaRSPlugin(injector, aapsLogger, aapsSchedulers, rxBus, context, resourceHelper, constraintChecker, profileFunction, activePluginProvider, sp, commandQueue, danaPump, detailedBolusInfoStorage, fabricPrivacy, dateUtil)
|
||||||
insightPlugin = LocalInsightPlugin(injector, aapsLogger, rxBus, resourceHelper, treatmentsPlugin, sp, commandQueue, profileFunction, nsUpload, context, uploadQueue, Config(), dateUtil)
|
insightPlugin = LocalInsightPlugin(injector, aapsLogger, rxBus, resourceHelper, treatmentsPlugin, sp, commandQueue, profileFunction, nsUpload, context, uploadQueue, Config(), dateUtil)
|
||||||
openAPSSMBPlugin = OpenAPSSMBPlugin(injector, aapsLogger, rxBus, constraintChecker, resourceHelper, profileFunction, context, activePlugin, treatmentsPlugin, iobCobCalculatorPlugin, hardLimits, profiler, fabricPrivacy, sp)
|
openAPSSMBPlugin = OpenAPSSMBPlugin(injector, aapsLogger, rxBus, constraintChecker, resourceHelper, profileFunction, context, activePlugin, treatmentsPlugin, iobCobCalculatorPlugin, hardLimits, profiler, sp)
|
||||||
openAPSAMAPlugin = OpenAPSAMAPlugin(injector, aapsLogger, rxBus, constraintChecker, resourceHelper, profileFunction, context, activePlugin, treatmentsPlugin, iobCobCalculatorPlugin, hardLimits, profiler, fabricPrivacy)
|
openAPSAMAPlugin = OpenAPSAMAPlugin(injector, aapsLogger, rxBus, constraintChecker, resourceHelper, profileFunction, context, activePlugin, treatmentsPlugin, iobCobCalculatorPlugin, hardLimits, profiler, fabricPrivacy)
|
||||||
safetyPlugin = SafetyPlugin(injector, aapsLogger, resourceHelper, sp, rxBus, constraintChecker, openAPSAMAPlugin, openAPSSMBPlugin, sensitivityOref1Plugin, activePlugin, hardLimits, buildHelper, treatmentsPlugin, Config())
|
safetyPlugin = SafetyPlugin(injector, aapsLogger, resourceHelper, sp, rxBus, constraintChecker, openAPSAMAPlugin, openAPSSMBPlugin, sensitivityOref1Plugin, activePlugin, hardLimits, buildHelper, treatmentsPlugin, Config())
|
||||||
val constraintsPluginsList = ArrayList<PluginBase>()
|
val constraintsPluginsList = ArrayList<PluginBase>()
|
||||||
|
|
|
@ -2,7 +2,6 @@ package info.nightscout.androidaps.plugins.aps.loop
|
||||||
|
|
||||||
import android.app.NotificationManager
|
import android.app.NotificationManager
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import dagger.Lazy
|
|
||||||
import dagger.android.AndroidInjector
|
import dagger.android.AndroidInjector
|
||||||
import dagger.android.HasAndroidInjector
|
import dagger.android.HasAndroidInjector
|
||||||
import info.nightscout.androidaps.Config
|
import info.nightscout.androidaps.Config
|
||||||
|
@ -16,7 +15,6 @@ import info.nightscout.androidaps.interfaces.PumpDescription
|
||||||
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
||||||
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
|
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
|
||||||
import info.nightscout.androidaps.plugins.general.nsclient.NSUpload
|
import info.nightscout.androidaps.plugins.general.nsclient.NSUpload
|
||||||
import info.nightscout.androidaps.plugins.general.wear.ActionStringHandler
|
|
||||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin
|
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin
|
||||||
import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpPlugin
|
import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpPlugin
|
||||||
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin
|
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin
|
||||||
|
@ -48,7 +46,6 @@ class LoopPluginTest : TestBase() {
|
||||||
@Mock lateinit var activePlugin: ActivePluginProvider
|
@Mock lateinit var activePlugin: ActivePluginProvider
|
||||||
@Mock lateinit var treatmentsPlugin: TreatmentsPlugin
|
@Mock lateinit var treatmentsPlugin: TreatmentsPlugin
|
||||||
@Mock lateinit var virtualPumpPlugin: VirtualPumpPlugin
|
@Mock lateinit var virtualPumpPlugin: VirtualPumpPlugin
|
||||||
@Mock lateinit var actionStringHandler: Lazy<ActionStringHandler>
|
|
||||||
@Mock lateinit var iobCobCalculatorPlugin: IobCobCalculatorPlugin
|
@Mock lateinit var iobCobCalculatorPlugin: IobCobCalculatorPlugin
|
||||||
@Mock lateinit var fabricPrivacy: FabricPrivacy
|
@Mock lateinit var fabricPrivacy: FabricPrivacy
|
||||||
@Mock lateinit var receiverStatusStore: ReceiverStatusStore
|
@Mock lateinit var receiverStatusStore: ReceiverStatusStore
|
||||||
|
@ -62,7 +59,7 @@ class LoopPluginTest : TestBase() {
|
||||||
@Before fun prepareMock() {
|
@Before fun prepareMock() {
|
||||||
hardLimits = HardLimits(aapsLogger, rxBus, sp, resourceHelper, context, nsUpload)
|
hardLimits = HardLimits(aapsLogger, rxBus, sp, resourceHelper, context, nsUpload)
|
||||||
|
|
||||||
loopPlugin = LoopPlugin(injector, aapsLogger, aapsSchedulers, rxBus, sp, Config(), constraintChecker, resourceHelper, profileFunction, context, commandQueue, activePlugin, treatmentsPlugin, virtualPumpPlugin, actionStringHandler, iobCobCalculatorPlugin, receiverStatusStore, fabricPrivacy, nsUpload, hardLimits)
|
loopPlugin = LoopPlugin(injector, aapsLogger, aapsSchedulers, rxBus, sp, Config(), constraintChecker, resourceHelper, profileFunction, context, commandQueue, activePlugin, treatmentsPlugin, virtualPumpPlugin, iobCobCalculatorPlugin, receiverStatusStore, fabricPrivacy, nsUpload, hardLimits)
|
||||||
`when`(activePlugin.activePump).thenReturn(virtualPumpPlugin)
|
`when`(activePlugin.activePump).thenReturn(virtualPumpPlugin)
|
||||||
`when`(context.getSystemService(Context.NOTIFICATION_SERVICE)).thenReturn(notificationManager)
|
`when`(context.getSystemService(Context.NOTIFICATION_SERVICE)).thenReturn(notificationManager)
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ import dagger.android.HasAndroidInjector
|
||||||
import info.nightscout.androidaps.TestBase
|
import info.nightscout.androidaps.TestBase
|
||||||
import info.nightscout.androidaps.interfaces.ActivePluginProvider
|
import info.nightscout.androidaps.interfaces.ActivePluginProvider
|
||||||
import info.nightscout.androidaps.interfaces.CommandQueueProvider
|
import info.nightscout.androidaps.interfaces.CommandQueueProvider
|
||||||
|
import info.nightscout.androidaps.logging.UserEntryLogger
|
||||||
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
||||||
import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpPlugin
|
import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpPlugin
|
||||||
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin
|
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin
|
||||||
|
@ -15,9 +16,11 @@ import org.junit.Before
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.runner.RunWith
|
import org.junit.runner.RunWith
|
||||||
import org.mockito.Mock
|
import org.mockito.Mock
|
||||||
|
import org.powermock.core.classloader.annotations.PrepareForTest
|
||||||
import org.powermock.modules.junit4.PowerMockRunner
|
import org.powermock.modules.junit4.PowerMockRunner
|
||||||
|
|
||||||
@RunWith(PowerMockRunner::class)
|
@RunWith(PowerMockRunner::class)
|
||||||
|
@PrepareForTest(UserEntryLogger::class)
|
||||||
class ConfigBuilderPluginTest : TestBase() {
|
class ConfigBuilderPluginTest : TestBase() {
|
||||||
|
|
||||||
@Mock lateinit var virtualPumpPlugin: Lazy<VirtualPumpPlugin>
|
@Mock lateinit var virtualPumpPlugin: Lazy<VirtualPumpPlugin>
|
||||||
|
@ -27,6 +30,7 @@ class ConfigBuilderPluginTest : TestBase() {
|
||||||
@Mock lateinit var resourceHelper: ResourceHelper
|
@Mock lateinit var resourceHelper: ResourceHelper
|
||||||
@Mock lateinit var commandQueue: CommandQueueProvider
|
@Mock lateinit var commandQueue: CommandQueueProvider
|
||||||
@Mock lateinit var activePlugin: ActivePluginProvider
|
@Mock lateinit var activePlugin: ActivePluginProvider
|
||||||
|
@Mock lateinit var uel: UserEntryLogger
|
||||||
|
|
||||||
private lateinit var configBuilderPlugin: ConfigBuilderPlugin
|
private lateinit var configBuilderPlugin: ConfigBuilderPlugin
|
||||||
|
|
||||||
|
@ -43,6 +47,6 @@ class ConfigBuilderPluginTest : TestBase() {
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
fun prepareMock() {
|
fun prepareMock() {
|
||||||
configBuilderPlugin = ConfigBuilderPlugin(injector, aapsLogger, resourceHelper, sp, RxBusWrapper(aapsSchedulers), activePlugin)
|
configBuilderPlugin = ConfigBuilderPlugin(injector, aapsLogger, resourceHelper, sp, RxBusWrapper(aapsSchedulers), activePlugin, uel)
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -7,6 +7,7 @@ import info.nightscout.androidaps.R
|
||||||
import info.nightscout.androidaps.TestBase
|
import info.nightscout.androidaps.TestBase
|
||||||
import info.nightscout.androidaps.interfaces.ActivePluginProvider
|
import info.nightscout.androidaps.interfaces.ActivePluginProvider
|
||||||
import info.nightscout.androidaps.interfaces.Constraint
|
import info.nightscout.androidaps.interfaces.Constraint
|
||||||
|
import info.nightscout.androidaps.logging.UserEntryLogger
|
||||||
import info.nightscout.androidaps.plugins.constraints.objectives.objectives.Objective
|
import info.nightscout.androidaps.plugins.constraints.objectives.objectives.Objective
|
||||||
import info.nightscout.androidaps.utils.DateUtil
|
import info.nightscout.androidaps.utils.DateUtil
|
||||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||||
|
@ -17,14 +18,17 @@ import org.junit.Test
|
||||||
import org.junit.runner.RunWith
|
import org.junit.runner.RunWith
|
||||||
import org.mockito.Mock
|
import org.mockito.Mock
|
||||||
import org.mockito.Mockito.`when`
|
import org.mockito.Mockito.`when`
|
||||||
|
import org.powermock.core.classloader.annotations.PrepareForTest
|
||||||
import org.powermock.modules.junit4.PowerMockRunner
|
import org.powermock.modules.junit4.PowerMockRunner
|
||||||
|
|
||||||
|
@PrepareForTest(UserEntryLogger::class)
|
||||||
@RunWith(PowerMockRunner::class)
|
@RunWith(PowerMockRunner::class)
|
||||||
class ObjectivesPluginTest : TestBase() {
|
class ObjectivesPluginTest : TestBase() {
|
||||||
|
|
||||||
@Mock lateinit var resourceHelper: ResourceHelper
|
@Mock lateinit var resourceHelper: ResourceHelper
|
||||||
@Mock lateinit var activePlugin: ActivePluginProvider
|
@Mock lateinit var activePlugin: ActivePluginProvider
|
||||||
@Mock lateinit var sp: SP
|
@Mock lateinit var sp: SP
|
||||||
|
@Mock lateinit var uel: UserEntryLogger
|
||||||
|
|
||||||
private lateinit var objectivesPlugin: ObjectivesPlugin
|
private lateinit var objectivesPlugin: ObjectivesPlugin
|
||||||
|
|
||||||
|
@ -38,7 +42,7 @@ class ObjectivesPluginTest : TestBase() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Before fun prepareMock() {
|
@Before fun prepareMock() {
|
||||||
objectivesPlugin = ObjectivesPlugin(injector, aapsLogger, resourceHelper, activePlugin, sp, Config())
|
objectivesPlugin = ObjectivesPlugin(injector, aapsLogger, resourceHelper, activePlugin, sp, Config(), uel)
|
||||||
objectivesPlugin.onStart()
|
objectivesPlugin.onStart()
|
||||||
`when`(resourceHelper.gs(R.string.objectivenotstarted)).thenReturn("Objective %1\$d not started")
|
`when`(resourceHelper.gs(R.string.objectivenotstarted)).thenReturn("Objective %1\$d not started")
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,7 @@ import org.mockito.Mock
|
||||||
import org.mockito.Mockito.`when`
|
import org.mockito.Mockito.`when`
|
||||||
import org.powermock.core.classloader.annotations.PrepareForTest
|
import org.powermock.core.classloader.annotations.PrepareForTest
|
||||||
|
|
||||||
@PrepareForTest(VirtualPumpPlugin::class, RxBusWrapper::class, LocalProfilePlugin::class, SmsCommunicatorPlugin::class, ConfigBuilderPlugin::class)
|
@PrepareForTest(VirtualPumpPlugin::class, RxBusWrapper::class, LocalProfilePlugin::class, SmsCommunicatorPlugin::class, ConfigBuilderPlugin::class, LoopPlugin::class)
|
||||||
open class ActionsTestBase : TestBaseWithProfile() {
|
open class ActionsTestBase : TestBaseWithProfile() {
|
||||||
|
|
||||||
@Mock lateinit var sp: SP
|
@Mock lateinit var sp: SP
|
||||||
|
|
|
@ -11,7 +11,6 @@ import org.junit.Assert
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.runner.RunWith
|
import org.junit.runner.RunWith
|
||||||
import org.mockito.Mock
|
import org.mockito.Mock
|
||||||
import org.mockito.Mockito
|
|
||||||
import org.mockito.Mockito.`when`
|
import org.mockito.Mockito.`when`
|
||||||
import org.powermock.core.classloader.annotations.PrepareForTest
|
import org.powermock.core.classloader.annotations.PrepareForTest
|
||||||
import org.powermock.modules.junit4.PowerMockRunner
|
import org.powermock.modules.junit4.PowerMockRunner
|
||||||
|
@ -24,6 +23,7 @@ class ClassicPrefsFormatTest : TestBase() {
|
||||||
|
|
||||||
@Mock lateinit var resourceHelper: ResourceHelper
|
@Mock lateinit var resourceHelper: ResourceHelper
|
||||||
@Mock lateinit var sp: SP
|
@Mock lateinit var sp: SP
|
||||||
|
@Mock lateinit var file: MockedFile
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun preferenceLoadingTest() {
|
fun preferenceLoadingTest() {
|
||||||
|
@ -53,8 +53,9 @@ class ClassicPrefsFormatTest : TestBase() {
|
||||||
classicFormat.savePreferences(getMockedFile(), prefs)
|
classicFormat.savePreferences(getMockedFile(), prefs)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class MockedFile(s: String) : File(s)
|
||||||
|
|
||||||
private fun getMockedFile(): File {
|
private fun getMockedFile(): File {
|
||||||
val file = Mockito.mock(File::class.java)
|
|
||||||
`when`(file.exists()).thenReturn(true)
|
`when`(file.exists()).thenReturn(true)
|
||||||
`when`(file.canRead()).thenReturn(true)
|
`when`(file.canRead()).thenReturn(true)
|
||||||
`when`(file.canWrite()).thenReturn(true)
|
`when`(file.canWrite()).thenReturn(true)
|
||||||
|
|
|
@ -28,6 +28,7 @@ class EncryptedPrefsFormatTest : TestBase() {
|
||||||
|
|
||||||
@Mock lateinit var resourceHelper: ResourceHelper
|
@Mock lateinit var resourceHelper: ResourceHelper
|
||||||
@Mock lateinit var sp: SP
|
@Mock lateinit var sp: SP
|
||||||
|
@Mock lateinit var file: MockedFile
|
||||||
|
|
||||||
private var cryptoUtil: CryptoUtil = CryptoUtil(aapsLogger)
|
private var cryptoUtil: CryptoUtil = CryptoUtil(aapsLogger)
|
||||||
|
|
||||||
|
@ -228,8 +229,9 @@ class EncryptedPrefsFormatTest : TestBase() {
|
||||||
encryptedFormat.loadPreferences(getMockedFile(), "sikret")
|
encryptedFormat.loadPreferences(getMockedFile(), "sikret")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class MockedFile(s: String) : File(s)
|
||||||
|
|
||||||
private fun getMockedFile(): File {
|
private fun getMockedFile(): File {
|
||||||
val file = Mockito.mock(File::class.java)
|
|
||||||
Mockito.`when`(file.exists()).thenReturn(true)
|
Mockito.`when`(file.exists()).thenReturn(true)
|
||||||
Mockito.`when`(file.canRead()).thenReturn(true)
|
Mockito.`when`(file.canRead()).thenReturn(true)
|
||||||
Mockito.`when`(file.canWrite()).thenReturn(true)
|
Mockito.`when`(file.canWrite()).thenReturn(true)
|
||||||
|
|
|
@ -16,6 +16,7 @@ import info.nightscout.androidaps.interfaces.CommandQueueProvider
|
||||||
import info.nightscout.androidaps.interfaces.Constraint
|
import info.nightscout.androidaps.interfaces.Constraint
|
||||||
import info.nightscout.androidaps.interfaces.PluginType
|
import info.nightscout.androidaps.interfaces.PluginType
|
||||||
import info.nightscout.androidaps.interfaces.PumpDescription
|
import info.nightscout.androidaps.interfaces.PumpDescription
|
||||||
|
import info.nightscout.androidaps.logging.UserEntryLogger
|
||||||
import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin
|
import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin
|
||||||
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
|
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
|
||||||
import info.nightscout.androidaps.plugins.general.smsCommunicator.otp.OneTimePassword
|
import info.nightscout.androidaps.plugins.general.smsCommunicator.otp.OneTimePassword
|
||||||
|
@ -50,7 +51,7 @@ import org.powermock.modules.junit4.PowerMockRunner
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
@RunWith(PowerMockRunner::class)
|
@RunWith(PowerMockRunner::class)
|
||||||
@PrepareForTest(ConstraintChecker::class, FabricPrivacy::class, VirtualPumpPlugin::class, XdripCalibrations::class, SmsManager::class, CommandQueue::class, LocalProfilePlugin::class, DateUtil::class, IobCobCalculatorPlugin::class, OneTimePassword::class)
|
@PrepareForTest(ConstraintChecker::class, FabricPrivacy::class, VirtualPumpPlugin::class, XdripCalibrations::class, SmsManager::class, CommandQueue::class, LocalProfilePlugin::class, DateUtil::class, IobCobCalculatorPlugin::class, OneTimePassword::class, UserEntryLogger::class, LoopPlugin::class)
|
||||||
class SmsCommunicatorPluginTest : TestBaseWithProfile() {
|
class SmsCommunicatorPluginTest : TestBaseWithProfile() {
|
||||||
|
|
||||||
@Mock lateinit var context: Context
|
@Mock lateinit var context: Context
|
||||||
|
@ -65,6 +66,7 @@ class SmsCommunicatorPluginTest : TestBaseWithProfile() {
|
||||||
@Mock lateinit var treatmentService: TreatmentService
|
@Mock lateinit var treatmentService: TreatmentService
|
||||||
@Mock lateinit var otp: OneTimePassword
|
@Mock lateinit var otp: OneTimePassword
|
||||||
@Mock lateinit var xdripCalibrations: XdripCalibrations
|
@Mock lateinit var xdripCalibrations: XdripCalibrations
|
||||||
|
@Mock lateinit var uel: UserEntryLogger
|
||||||
|
|
||||||
var injector: HasAndroidInjector = HasAndroidInjector {
|
var injector: HasAndroidInjector = HasAndroidInjector {
|
||||||
AndroidInjector {
|
AndroidInjector {
|
||||||
|
@ -104,7 +106,7 @@ class SmsCommunicatorPluginTest : TestBaseWithProfile() {
|
||||||
`when`(SmsManager.getDefault()).thenReturn(smsManager)
|
`when`(SmsManager.getDefault()).thenReturn(smsManager)
|
||||||
`when`(sp.getString(R.string.key_smscommunicator_allowednumbers, "")).thenReturn("1234;5678")
|
`when`(sp.getString(R.string.key_smscommunicator_allowednumbers, "")).thenReturn("1234;5678")
|
||||||
|
|
||||||
smsCommunicatorPlugin = SmsCommunicatorPlugin(injector, aapsLogger, resourceHelper, aapsSchedulers, sp, constraintChecker, rxBus, profileFunction, fabricPrivacy, activePlugin, commandQueue, loopPlugin, iobCobCalculatorPlugin, xdripCalibrations, otp, Config(), DateUtil(context))
|
smsCommunicatorPlugin = SmsCommunicatorPlugin(injector, aapsLogger, resourceHelper, aapsSchedulers, sp, constraintChecker, rxBus, profileFunction, fabricPrivacy, activePlugin, commandQueue, loopPlugin, iobCobCalculatorPlugin, xdripCalibrations, otp, Config(), DateUtil(context), uel)
|
||||||
smsCommunicatorPlugin.setPluginEnabled(PluginType.GENERAL, true)
|
smsCommunicatorPlugin.setPluginEnabled(PluginType.GENERAL, true)
|
||||||
Mockito.doAnswer { invocation: InvocationOnMock ->
|
Mockito.doAnswer { invocation: InvocationOnMock ->
|
||||||
val callback = invocation.getArgument<Callback>(1)
|
val callback = invocation.getArgument<Callback>(1)
|
||||||
|
|
14
build.gradle
14
build.gradle
|
@ -4,19 +4,19 @@ buildscript {
|
||||||
ext {
|
ext {
|
||||||
kotlin_version = '1.4.30'
|
kotlin_version = '1.4.30'
|
||||||
coreVersion = '1.3.2'
|
coreVersion = '1.3.2'
|
||||||
rxjava_version = '2.2.20'
|
rxjava_version = '2.2.21'
|
||||||
rxandroid_version = '2.1.1'
|
rxandroid_version = '2.1.1'
|
||||||
rxkotlin_version = '2.4.0'
|
rxkotlin_version = '2.4.0'
|
||||||
room_version = '2.2.6'
|
room_version = '2.2.6'
|
||||||
lifecycle_version = '2.3.0'
|
lifecycle_version = '2.3.0'
|
||||||
dagger_version = '2.31.2'
|
dagger_version = '2.32'
|
||||||
coroutinesVersion = '1.4.1'
|
coroutinesVersion = '1.4.1'
|
||||||
activityVersion = '1.2.0'
|
activityVersion = '1.2.0'
|
||||||
fragmentktx_version = '1.3.0-rc01'
|
fragmentktx_version = '1.3.0-rc02'
|
||||||
ormLiteVersion = '4.46'
|
ormLiteVersion = '4.46'
|
||||||
nav_version = '2.3.2'
|
nav_version = '2.3.3'
|
||||||
appcompat_version = '1.2.0'
|
appcompat_version = '1.2.0'
|
||||||
material_version = '1.2.1'
|
material_version = '1.3.0'
|
||||||
constraintlayout_version = '2.0.4'
|
constraintlayout_version = '2.0.4'
|
||||||
preferencektx_version = '1.1.1'
|
preferencektx_version = '1.1.1'
|
||||||
commonslang3_version = '3.11'
|
commonslang3_version = '3.11'
|
||||||
|
@ -24,8 +24,8 @@ buildscript {
|
||||||
jodatime_version = '2.10.10'
|
jodatime_version = '2.10.10'
|
||||||
work_version = '2.5.0'
|
work_version = '2.5.0'
|
||||||
|
|
||||||
junit_version = '4.13.1'
|
junit_version = '4.13.2'
|
||||||
mockitoVersion = '2.8.47'
|
mockitoVersion = '3.7.7'
|
||||||
powermockVersion = '2.0.9'
|
powermockVersion = '2.0.9'
|
||||||
dexmakerVersion = "1.2"
|
dexmakerVersion = "1.2"
|
||||||
retrofit2Version = '2.9.0'
|
retrofit2Version = '2.9.0'
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue