Merge tag '2.6.0' into omnipod_eros_dev

This commit is contained in:
Bart Sopers 2020-03-03 21:33:31 +01:00
commit 3eea2598f2
438 changed files with 17378 additions and 11682 deletions

11
.gitignore vendored
View file

@ -6,10 +6,17 @@
/captures /captures
*.apk *.apk
build/ build/
.idea/ .idea/*
!.idea/codeStyles/
app/src/main/jniLibs app/src/main/jniLibs
full/ full/
debug/ debug/
release/ release/
app/com.crashlytics.settings.json app/com.crashlytics.settings.json
app/session_analytics.tap app/session_analytics.tap
.project
.settings/org.eclipse.buildship.core.prefs
app/.classpath
app/.settings/org.eclipse.buildship.core.prefs
wear/.classpath
wear/.settings/org.eclipse.buildship.core.prefs

View file

@ -0,0 +1,134 @@
<component name="ProjectCodeStyleConfiguration">
<code_scheme name="Project" version="173">
<option name="AUTODETECT_INDENTS" value="false" />
<JetCodeStyleSettings>
<option name="ALIGN_IN_COLUMNS_CASE_BRANCH" value="true" />
<option name="NAME_COUNT_TO_USE_STAR_IMPORT" value="6" />
<option name="NAME_COUNT_TO_USE_STAR_IMPORT_FOR_MEMBERS" value="6" />
<option name="BLANK_LINES_AROUND_BLOCK_WHEN_BRANCHES" value="1" />
</JetCodeStyleSettings>
<codeStyleSettings language="XML">
<indentOptions>
<option name="CONTINUATION_INDENT_SIZE" value="4" />
</indentOptions>
<arrangement>
<rules>
<section>
<rule>
<match>
<AND>
<NAME>xmlns:android</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>xmlns:.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:id</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:name</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>name</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>style</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
<order>ANDROID_ATTRIBUTE_ORDER</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>.*</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
</rules>
</arrangement>
</codeStyleSettings>
<codeStyleSettings language="kotlin">
<option name="LINE_COMMENT_AT_FIRST_COLUMN" value="false" />
<option name="LINE_COMMENT_ADD_SPACE" value="true" />
<option name="KEEP_BLANK_LINES_IN_DECLARATIONS" value="1" />
<option name="KEEP_BLANK_LINES_IN_CODE" value="1" />
<option name="KEEP_BLANK_LINES_BEFORE_RBRACE" value="1" />
<option name="BLANK_LINES_AFTER_CLASS_HEADER" value="1" />
<indentOptions>
<option name="CONTINUATION_INDENT_SIZE" value="4" />
</indentOptions>
</codeStyleSettings>
</code_scheme>
</component>

View file

@ -0,0 +1,5 @@
<component name="ProjectCodeStyleConfiguration">
<state>
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
</state>
</component>

View file

@ -228,8 +228,10 @@ dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs') implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation 'com.google.android.gms:play-services-wearable:17.0.0' implementation 'com.google.android.gms:play-services-wearable:17.0.0'
implementation 'com.google.firebase:firebase-core:17.2.0' implementation 'com.google.firebase:firebase-core:17.2.1'
implementation("com.crashlytics.sdk.android:crashlytics:2.9.9@aar") { implementation 'com.google.firebase:firebase-auth:19.2.0'
implementation 'com.google.firebase:firebase-database:19.2.0'
implementation('com.crashlytics.sdk.android:crashlytics:2.10.1@aar') {
transitive = true; transitive = true;
} }
@ -237,11 +239,11 @@ dependencies {
implementation 'androidx.legacy:legacy-support-v13:1.0.0' implementation 'androidx.legacy:legacy-support-v13:1.0.0'
implementation 'androidx.legacy:legacy-support-v4:1.0.0' implementation 'androidx.legacy:legacy-support-v4:1.0.0'
implementation 'androidx.cardview:cardview:1.0.0' implementation 'androidx.cardview:cardview:1.0.0'
implementation 'androidx.recyclerview:recyclerview:1.0.0' implementation 'androidx.recyclerview:recyclerview:1.1.0'
implementation 'androidx.gridlayout:gridlayout:1.0.0' implementation 'androidx.gridlayout:gridlayout:1.0.0'
implementation 'com.google.android.material:material:1.0.0' implementation 'com.google.android.material:material:1.0.0'
implementation 'androidx.percentlayout:percentlayout:1.0.0' implementation 'androidx.percentlayout:percentlayout:1.0.0'
implementation "com.wdullaer:materialdatetimepicker:2.3.0" implementation 'com.wdullaer:materialdatetimepicker:4.2.3'
implementation "io.reactivex.rxjava2:rxandroid:2.1.1" implementation "io.reactivex.rxjava2:rxandroid:2.1.1"
@ -250,11 +252,11 @@ dependencies {
implementation("com.github.tony19:logback-android-classic:1.1.1-6") { implementation("com.github.tony19:logback-android-classic:1.1.1-6") {
exclude group: "com.google.android", module: "android" exclude group: "com.google.android", module: "android"
} }
implementation "org.apache.commons:commons-lang3:3.7" implementation "org.apache.commons:commons-lang3:3.9"
implementation "org.slf4j:slf4j-api:1.7.21" implementation "org.slf4j:slf4j-api:1.7.29"
// Graphview cannot be upgraded // Graphview cannot be upgraded
implementation "com.jjoe64:graphview:4.0.1" implementation "com.jjoe64:graphview:4.0.1"
implementation "com.joanzapata.iconify:android-iconify-fontawesome:2.1.1" implementation "com.joanzapata.iconify:android-iconify-fontawesome:2.2.2"
implementation 'androidx.constraintlayout:constraintlayout:1.1.3' implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
implementation(name: "android-edittext-validator-v1.3.4-mod", ext: "aar") implementation(name: "android-edittext-validator-v1.3.4-mod", ext: "aar")
implementation(name: "com.atech-software.android.library.wizardpager-1.1.1", ext: "aar") implementation(name: "com.atech-software.android.library.wizardpager-1.1.1", ext: "aar")
@ -268,26 +270,29 @@ dependencies {
// excluding org.json which is provided by Android // excluding org.json which is provided by Android
exclude group: "org.json", module: "json" exclude group: "org.json", module: "json"
} }
implementation "com.google.code.gson:gson:2.8.5" implementation "com.google.code.gson:gson:2.8.6"
implementation "com.google.guava:guava:24.1-jre" implementation ("com.google.guava:guava:24.1-jre") {
exclude group: "com.google.code.findbugs", module: "jsr305"
}
implementation 'com.google.code.findbugs:jsr305:3.0.2'
implementation "net.danlew:android.joda:2.9.9.1" implementation "net.danlew:android.joda:2.10.3"
implementation "uk.com.robust-it:cloning:1.9.9"
implementation 'org.mozilla:rhino:1.7.7.2' implementation 'org.mozilla:rhino:1.7.11'
implementation 'com.github.DavidProdinger:weekdays-selector:1.1.0' implementation 'com.github.DavidProdinger:weekdays-selector:1.1.0'
testImplementation "junit:junit:4.12" testImplementation "junit:junit:4.12"
testImplementation "org.json:json:20140107" testImplementation "org.json:json:20190722"
testImplementation "org.mockito:mockito-core:2.8.47" testImplementation "org.mockito:mockito-core:2.8.47"
testImplementation "org.powermock:powermock-api-mockito2:${powermockVersion}" testImplementation "org.powermock:powermock-api-mockito2:${powermockVersion}"
testImplementation "org.powermock:powermock-module-junit4-rule-agent:${powermockVersion}" testImplementation "org.powermock:powermock-module-junit4-rule-agent:${powermockVersion}"
testImplementation "org.powermock:powermock-module-junit4-rule:${powermockVersion}" testImplementation "org.powermock:powermock-module-junit4-rule:${powermockVersion}"
testImplementation "org.powermock:powermock-module-junit4:${powermockVersion}" testImplementation "org.powermock:powermock-module-junit4:${powermockVersion}"
testImplementation "joda-time:joda-time:2.9.9" testImplementation "joda-time:joda-time:2.10.5"
testImplementation("com.google.truth:truth:0.39") { testImplementation("com.google.truth:truth:0.39") {
exclude group: "com.google.guava", module: "guava" exclude group: "com.google.guava", module: "guava"
exclude group: "com.google.code.findbugs", module: "jsr305"
} }
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"
@ -297,20 +302,25 @@ dependencies {
} }
*/ */
androidTestImplementation "org.mockito:mockito-core:2.8.47"
androidTestImplementation "com.google.dexmaker:dexmaker:${dexmakerVersion}"
androidTestImplementation "com.google.dexmaker:dexmaker-mockito:${dexmakerVersion}"
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version" implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
// new for tidepool // new for tidepool
implementation 'com.squareup.okhttp3:okhttp:3.10.0' implementation 'com.squareup.okhttp3:okhttp:4.2.2'
implementation 'com.squareup.okhttp3:logging-interceptor:3.10.0' implementation 'com.squareup.okhttp3:logging-interceptor:4.2.2'
implementation "com.squareup.retrofit2:retrofit:2.4.0" implementation "com.squareup.retrofit2:retrofit:2.6.2"
implementation "com.squareup.retrofit2:adapter-rxjava2:2.4.0" implementation "com.squareup.retrofit2:adapter-rxjava2:2.6.2"
implementation "com.squareup.retrofit2:converter-gson:2.4.0" implementation "com.squareup.retrofit2:converter-gson:2.6.2"
// Phone checker
implementation 'com.scottyab:rootbeer-lib:0.0.7'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0-alpha03'
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test:rules:1.3.0-alpha03'
androidTestImplementation 'com.google.code.findbugs:jsr305:3.0.2'
androidTestImplementation 'androidx.test.uiautomator:uiautomator:2.2.0'
} }
@ -337,7 +347,37 @@ task copyLibs(dependsOn: downloadAndUnzipFile, type: Copy) {
task full_clean(type: Delete) { task full_clean(type: Delete) {
delete file("src/main/jniLibs") delete file("src/main/jniLibs")
} }
/*
// Run 'adb' shell command to clear application data of main app for 'debug' variant
task clearMainAppData(type: Exec) {
// we have to iterate to find the 'debug' variant to obtain a variant reference
android.applicationVariants.all { variant ->
if (variant.name == "fullDebug") {
def applicationId = [variant.mergedFlavor.applicationId, variant.buildType.applicationIdSuffix].findAll().join()
def clearDataCommand = ['adb', 'shell', 'pm', 'clear', applicationId]
println "Clearing application data of ${variant.name} variant: [${clearDataCommand}]"
def stdout = new ByteArrayOutputStream()
exec {
commandLine clearDataCommand
standardOutput = stdout
}
String result = stdout.toString().trim()
if (!result.startsWith("Success")) {
println result
throw new GradleException(clearDataCommand.join(" "))
}
}
}
}
// Clear Application Data (once) before running instrumentation test
tasks.whenTaskAdded { task ->
// Both of these targets are equivalent today, although in future connectedCheck
// will also include connectedUiAutomatorTest (not implemented yet)
if(task.name == "connectedAndroidTest" || task.name == "connectedCheck"){
task.dependsOn(clearMainAppData)
}
}
*/
clean.dependsOn full_clean clean.dependsOn full_clean
preBuild.dependsOn copyLibs preBuild.dependsOn copyLibs

View file

@ -13,7 +13,12 @@
"package_name": "info.nightscout.aapspumpcontrol" "package_name": "info.nightscout.aapspumpcontrol"
} }
}, },
"oauth_client": [], "oauth_client": [
{
"client_id": "477603612366-a925drvlvs7qn7gt73r585erbqto8c79.apps.googleusercontent.com",
"client_type": 3
}
],
"api_key": [ "api_key": [
{ {
"current_key": "AIzaSyDcZpDRMaGjdhihXp531cVYM6LkEL8KbgM" "current_key": "AIzaSyDcZpDRMaGjdhihXp531cVYM6LkEL8KbgM"
@ -37,7 +42,12 @@
"package_name": "info.nightscout.androidaps" "package_name": "info.nightscout.androidaps"
} }
}, },
"oauth_client": [], "oauth_client": [
{
"client_id": "477603612366-a925drvlvs7qn7gt73r585erbqto8c79.apps.googleusercontent.com",
"client_type": 3
}
],
"api_key": [ "api_key": [
{ {
"current_key": "AIzaSyDcZpDRMaGjdhihXp531cVYM6LkEL8KbgM" "current_key": "AIzaSyDcZpDRMaGjdhihXp531cVYM6LkEL8KbgM"
@ -61,7 +71,12 @@
"package_name": "info.nightscout.nsclient" "package_name": "info.nightscout.nsclient"
} }
}, },
"oauth_client": [], "oauth_client": [
{
"client_id": "477603612366-a925drvlvs7qn7gt73r585erbqto8c79.apps.googleusercontent.com",
"client_type": 3
}
],
"api_key": [ "api_key": [
{ {
"current_key": "AIzaSyDcZpDRMaGjdhihXp531cVYM6LkEL8KbgM" "current_key": "AIzaSyDcZpDRMaGjdhihXp531cVYM6LkEL8KbgM"
@ -85,7 +100,12 @@
"package_name": "info.nightscout.nsclient2" "package_name": "info.nightscout.nsclient2"
} }
}, },
"oauth_client": [], "oauth_client": [
{
"client_id": "477603612366-a925drvlvs7qn7gt73r585erbqto8c79.apps.googleusercontent.com",
"client_type": 3
}
],
"api_key": [ "api_key": [
{ {
"current_key": "AIzaSyDcZpDRMaGjdhihXp531cVYM6LkEL8KbgM" "current_key": "AIzaSyDcZpDRMaGjdhihXp531cVYM6LkEL8KbgM"

Binary file not shown.

View file

@ -1,13 +0,0 @@
package info.nightscout.androidaps;
import android.app.Application;
import android.test.ApplicationTestCase;
/**
* <a href="http://d.android.com/tools/testing/testing_android.html">Testing Fundamentals</a>
*/
public class ApplicationTest extends ApplicationTestCase<Application> {
public ApplicationTest() {
super(Application.class);
}
}

View file

@ -0,0 +1,35 @@
package info.nightscout.androidaps
import androidx.test.espresso.ViewAction
import androidx.test.espresso.ViewInteraction
import androidx.test.espresso.assertion.ViewAssertions.matches
import androidx.test.espresso.matcher.ViewMatchers
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.uiautomator.UiDevice
import androidx.test.uiautomator.UiSelector
fun ViewInteraction.isDisplayed(): Boolean {
try {
check(matches(ViewMatchers.isDisplayed()))
return true
} catch (e: Throwable) {
return false
}
}
fun ViewInteraction.waitAndPerform(viewActions: ViewAction): ViewInteraction? {
val startTime = System.currentTimeMillis()
while (!isDisplayed()) {
Thread.sleep(100)
if (System.currentTimeMillis() - startTime >= 5000) {
throw AssertionError("View not visible after 5000 milliseconds")
}
}
return perform(viewActions)
}
fun clickOkInDialog() {
val uiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
val button = uiDevice.findObject(UiSelector().clickable(true).checkable(false).index(1))
if (button.exists() && button.isEnabled) button.click()
}

View file

@ -0,0 +1,116 @@
package info.nightscout.androidaps
import android.os.SystemClock
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.LargeTest
import androidx.test.rule.ActivityTestRule
import androidx.test.rule.GrantPermissionRule
import info.nightscout.androidaps.data.Profile
import info.nightscout.androidaps.interfaces.PluginBase
import info.nightscout.androidaps.interfaces.PluginType
import info.nightscout.androidaps.interfaces.PumpInterface
import info.nightscout.androidaps.logging.L
import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin
import info.nightscout.androidaps.plugins.aps.openAPSSMB.OpenAPSSMBPlugin
import info.nightscout.androidaps.plugins.configBuilder.ProfileFunctions
import info.nightscout.androidaps.plugins.constraints.objectives.ObjectivesPlugin
import info.nightscout.androidaps.plugins.general.actions.ActionsPlugin
import info.nightscout.androidaps.plugins.insulin.InsulinOrefUltraRapidActingPlugin
import info.nightscout.androidaps.plugins.profile.local.LocalProfilePlugin
import info.nightscout.androidaps.plugins.pump.danaRv2.DanaRv2Plugin
import info.nightscout.androidaps.plugins.sensitivity.SensitivityOref1Plugin
import info.nightscout.androidaps.plugins.source.RandomBgPlugin
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.SP
import info.nightscout.androidaps.utils.isRunningTest
import org.json.JSONObject
import org.junit.Assert
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.slf4j.LoggerFactory
@LargeTest
@RunWith(AndroidJUnit4::class)
class RealPumpTest {
private val log = LoggerFactory.getLogger(L.CORE)
companion object {
val pump: PumpInterface = DanaRv2Plugin.getPlugin()
const val R_PASSWORD = 1234
const val R_SERIAL = "PBB00013LR_P"
}
private val validProfile = "{\"dia\":\"6\",\"carbratio\":[{\"time\":\"00:00\",\"value\":\"30\"}],\"carbs_hr\":\"20\",\"delay\":\"20\",\"sens\":[{\"time\":\"00:00\",\"value\":\"10\"},{\"time\":\"2:00\",\"value\":\"11\"}],\"timezone\":\"UTC\",\"basal\":[{\"time\":\"00:00\",\"value\":\"0.1\"}],\"target_low\":[{\"time\":\"00:00\",\"value\":\"4\"}],\"target_high\":[{\"time\":\"00:00\",\"value\":\"5\"}],\"startDate\":\"1970-01-01T00:00:00.000Z\",\"units\":\"mmol\"}"
@Rule
@JvmField
var mActivityTestRule = ActivityTestRule(MainActivity::class.java)
@Rule
@JvmField
var mGrantPermissionRule: GrantPermissionRule =
GrantPermissionRule.grant(
android.Manifest.permission.ACCESS_FINE_LOCATION,
android.Manifest.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS,
android.Manifest.permission.WRITE_EXTERNAL_STORAGE
)
@Before
fun clear() {
SP.clear()
SP.putBoolean(R.string.key_setupwizard_processed, true)
SP.putString(R.string.key_aps_mode, "closed")
MainApp.getDbHelper().resetDatabases()
MainApp.devBranch = false
}
private fun preparePlugins() {
// Source
RandomBgPlugin.performPluginSwitch(true, PluginType.BGSOURCE)
// Profile
LocalProfilePlugin.performPluginSwitch(true, PluginType.PROFILE)
val profile = Profile(JSONObject(validProfile), Constants.MGDL)
Assert.assertTrue(profile.isValid("Test"))
LocalProfilePlugin.profiles.clear()
LocalProfilePlugin.numOfProfiles = 0
val singleProfile = LocalProfilePlugin.SingleProfile().copyFrom(profile, "TestProfile")
LocalProfilePlugin.addProfile(singleProfile)
ProfileFunctions.doProfileSwitch(LocalProfilePlugin.createProfileStore(), "TestProfile", 0, 100, 0, DateUtil.now())
// Insulin
InsulinOrefUltraRapidActingPlugin.getPlugin().performPluginSwitch(true, PluginType.INSULIN)
// Pump
SP.putInt(R.string.key_danar_password, R_PASSWORD)
SP.putString(R.string.key_danar_bt_name, R_SERIAL)
(pump as PluginBase).performPluginSwitch(true, PluginType.PUMP)
// Sensitivity
SensitivityOref1Plugin.getPlugin().performPluginSwitch(true, PluginType.SENSITIVITY)
// APS
OpenAPSSMBPlugin.getPlugin().performPluginSwitch(true, PluginType.APS)
LoopPlugin.getPlugin().performPluginSwitch(true, PluginType.LOOP)
// Enable common
ActionsPlugin.performPluginSwitch(true, PluginType.GENERAL)
// Disable unneeded
MainApp.getPluginsList().remove(ObjectivesPlugin)
}
@Test
fun doTest() {
Assert.assertTrue(isRunningTest())
preparePlugins()
while (!pump.isInitialized) {
log.debug("Waiting for initialization")
SystemClock.sleep(1000)
}
while (true) {
log.debug("Tick")
SystemClock.sleep(1000)
}
}
}

View file

@ -0,0 +1,231 @@
package info.nightscout.androidaps
import android.os.SystemClock
import android.view.View
import android.view.ViewGroup
import androidx.test.espresso.Espresso.onData
import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.action.ViewActions
import androidx.test.espresso.action.ViewActions.click
import androidx.test.espresso.action.ViewActions.scrollTo
import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
import androidx.test.espresso.matcher.ViewMatchers.withClassName
import androidx.test.espresso.matcher.ViewMatchers.withId
import androidx.test.espresso.matcher.ViewMatchers.withTagValue
import androidx.test.espresso.matcher.ViewMatchers.withText
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.LargeTest
import androidx.test.rule.ActivityTestRule
import androidx.test.rule.GrantPermissionRule
import info.nightscout.androidaps.interfaces.PluginType
import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin
import info.nightscout.androidaps.plugins.aps.openAPSSMB.OpenAPSSMBPlugin
import info.nightscout.androidaps.plugins.configBuilder.ProfileFunctions
import info.nightscout.androidaps.plugins.constraints.objectives.ObjectivesPlugin
import info.nightscout.androidaps.plugins.profile.local.LocalProfilePlugin
import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpPlugin
import info.nightscout.androidaps.plugins.sensitivity.SensitivityOref1Plugin
import info.nightscout.androidaps.plugins.source.RandomBgPlugin
import info.nightscout.androidaps.setupwizard.SetupWizardActivity
import info.nightscout.androidaps.utils.HardLimits
import info.nightscout.androidaps.utils.SP
import info.nightscout.androidaps.utils.isRunningTest
import org.hamcrest.CoreMatchers.allOf
import org.hamcrest.Description
import org.hamcrest.Matcher
import org.hamcrest.Matchers
import org.hamcrest.TypeSafeMatcher
import org.junit.Assert
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
@LargeTest
@RunWith(AndroidJUnit4::class)
class SetupWizardActivityTest {
@Rule
@JvmField
var mActivityTestRule = ActivityTestRule(SetupWizardActivity::class.java)
@Rule
@JvmField
var mGrantPermissionRule: GrantPermissionRule =
GrantPermissionRule.grant(
android.Manifest.permission.ACCESS_FINE_LOCATION,
android.Manifest.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS,
android.Manifest.permission.WRITE_EXTERNAL_STORAGE
)
@Before
fun clear() {
SP.clear()
}
/*
To run from command line
gradlew connectedFullDebugAndroidTest
do not run when your production phone is connected !!!
do this before for running in emulator
adb shell settings put global window_animation_scale 0 &
adb shell settings put global transition_animation_scale 0 &
adb shell settings put global animator_duration_scale 0 &
*/
@Test
fun setupWizardActivityTest() {
SP.clear()
Assert.assertTrue(isRunningTest())
// Welcome page
onView(withId(R.id.next_button)).perform(click())
// Language selection
onView(withText("English")).perform(scrollTo(), click())
onView(withId(R.id.next_button)).waitAndPerform(click())
// Agreement page
onView(withText("I UNDERSTAND AND AGREE")).perform(scrollTo(), click())
onView(withId(R.id.next_button)).waitAndPerform(click())
// Location permission
var askButton = onView(withText("Ask for permission"))
if (askButton.isDisplayed()) {
askButton.perform(scrollTo(), click())
onView(withId(R.id.next_button)).waitAndPerform(click())
}
// Store permission
askButton = onView(withText("Ask for permission"))
if (askButton.isDisplayed()) {
askButton.perform(scrollTo(), click())
onView(withText("OK")).perform(click())
onView(withId(R.id.next_button)).waitAndPerform(click())
}
// Import settings : skip of found
askButton = onView(withText("IMPORT SETTINGS"))
if (askButton.isDisplayed()) {
onView(withId(R.id.next_button)).waitAndPerform(click())
}
// Units selection
onView(withText("mmol/L")).perform(scrollTo(), click())
onView(withId(R.id.next_button)).perform(click())
// Display target selection
onView(withText("4.2")).perform(scrollTo(), ViewActions.replaceText("5"))
onView(withText("10.0")).perform(scrollTo(), ViewActions.replaceText("11"))
onView(withId(R.id.next_button)).perform(click())
// NSClient
onView(withId(R.id.next_button)).perform(click())
// Age selection
onView(withText("Adult")).perform(scrollTo(), click())
onView(withId(R.id.next_button)).waitAndPerform(click())
// Insulin selection
onView(withText("Ultra-Rapid Oref")).perform(scrollTo(), click())
onView(withId(R.id.next_button)).waitAndPerform(click())
// BG source selection
onView(withText("Random BG")).perform(scrollTo(), click())
onView(withId(R.id.next_button)).waitAndPerform(click())
// Profile selection
onView(withText("Local Profile")).perform(scrollTo(), click())
onView(withId(R.id.next_button)).waitAndPerform(click())
// Local profile - DIA
onView(withTagValue(Matchers.`is`("LP_DIA"))).perform(scrollTo(), ViewActions.replaceText("6.0"))
// Local profile - IC
onView(withId(R.id.ic_tab)).perform(scrollTo(), click())
onView(Matchers.allOf(withTagValue(Matchers.`is`("IC-1-0")), isDisplayed()))
.perform(ViewActions.replaceText("2"), ViewActions.closeSoftKeyboard())
// Local profile - ISF
onView(withId(R.id.isf_tab)).perform(scrollTo(), click())
onView(Matchers.allOf(withTagValue(Matchers.`is`("ISF-1-0")), isDisplayed()))
.perform(ViewActions.replaceText("3"), ViewActions.closeSoftKeyboard())
// Local profile - BAS
onView(withId(R.id.basal_tab)).perform(scrollTo(), click())
onView(childAtPosition(Matchers.allOf(withId(R.id.localprofile_basal), childAtPosition(withClassName(Matchers.`is`("android.widget.LinearLayout")), 6)), 2))
.perform(scrollTo(), click())
onView(Matchers.allOf(withTagValue(Matchers.`is`("BASAL-1-0")), isDisplayed()))
.perform(ViewActions.replaceText("1.1"), ViewActions.closeSoftKeyboard())
onView(Matchers.allOf(withTagValue(Matchers.`is`("BASAL-1-1")), isDisplayed()))
.perform(ViewActions.replaceText("1.2"), ViewActions.closeSoftKeyboard())
onView(Matchers.allOf(withId(R.id.timelistedit_time), childAtPosition(childAtPosition(withId(R.id.localprofile_basal), 2), 0)))
.perform(scrollTo(), click())
onData(Matchers.anything()).inAdapterView(childAtPosition(withClassName(Matchers.`is`("android.widget.PopupWindow\$PopupBackgroundView")), 0)).atPosition(13)
.perform(click())
// Local profile - TARGET
onView(withId(R.id.target_tab)).perform(scrollTo(), click())
onView(Matchers.allOf(withTagValue(Matchers.`is`("TARGET-1-0")), isDisplayed()))
.perform(ViewActions.replaceText("6"), ViewActions.closeSoftKeyboard())
onView(Matchers.allOf(withTagValue(Matchers.`is`("TARGET-2-0")), isDisplayed()))
.perform(ViewActions.replaceText("6.5"), ViewActions.closeSoftKeyboard())
onView(withText("Save")).perform(scrollTo(), click())
onView(Matchers.allOf(withId(R.id.localprofile_profileswitch), isDisplayed()))
.perform(scrollTo(), click())
onView(allOf(withId(R.id.ok), isDisplayed())).perform(click())
// confirm dialog
//onView(Matchers.allOf(withText("OK"), isDisplayed())).perform(click()) not working on real phone
clickOkInDialog()
onView(withId(R.id.next_button)).waitAndPerform(click())
// Profile switch
askButton = onView(withText("Do Profile Switch"))
if (askButton.isDisplayed()) {
askButton.perform(scrollTo(), click())
onView(allOf(withId(R.id.ok), isDisplayed())).perform(click())
// onView(Matchers.allOf(withText("OK"), isDisplayed())).perform(click()) not working on real phone
clickOkInDialog()
while (ProfileFunctions.getInstance().profile == null) SystemClock.sleep(100)
onView(withId(R.id.next_button)).waitAndPerform(click())
}
// Pump
onView(withText("Virtual Pump")).perform(scrollTo(), click())
onView(withId(R.id.next_button)).waitAndPerform(click())
// APS
onView(withText("OpenAPS SMB")).perform(scrollTo(), click())
onView(withId(R.id.next_button)).waitAndPerform(click())
// Open Closed Loop
onView(withText("Closed Loop")).perform(scrollTo(), click())
onView(withId(R.id.next_button)).waitAndPerform(click())
// Loop
askButton = onView(withText("Enable loop"))
if (askButton.isDisplayed()) {
askButton.perform(scrollTo(), click())
onView(withId(R.id.next_button)).waitAndPerform(click())
}
// Sensitivity
onView(withText("Sensitivity Oref1")).perform(scrollTo(), click())
onView(withId(R.id.next_button)).waitAndPerform(click())
// Objectives
onView(allOf(withText("Start"), isDisplayed())).perform(scrollTo(), click())
onView(withId(R.id.finish_button)).waitAndPerform(click())
// Verify settings
Assert.assertEquals(Constants.MMOL, ProfileFunctions.getSystemUnits())
Assert.assertEquals(17.0, HardLimits.maxBolus(), 0.0001) // Adult
Assert.assertTrue(RandomBgPlugin.isEnabled(PluginType.BGSOURCE))
Assert.assertTrue(LocalProfilePlugin.isEnabled(PluginType.PROFILE))
val p = ProfileFunctions.getInstance().profile
Assert.assertNotNull(p)
Assert.assertEquals(2.0, p!!.ic, 0.0001)
Assert.assertEquals(3.0 * Constants.MMOLL_TO_MGDL, p.isfMgdl, 0.0001)
Assert.assertEquals(1.1, p.getBasalTimeFromMidnight(0), 0.0001)
Assert.assertEquals(6.0 * Constants.MMOLL_TO_MGDL, p.targetLowMgdl, 0.0001)
Assert.assertTrue(VirtualPumpPlugin.getPlugin().isEnabled(PluginType.PUMP))
Assert.assertTrue(OpenAPSSMBPlugin.getPlugin().isEnabled(PluginType.APS))
Assert.assertTrue(LoopPlugin.getPlugin().isEnabled(PluginType.LOOP))
Assert.assertTrue(SensitivityOref1Plugin.getPlugin().isEnabled(PluginType.SENSITIVITY))
Assert.assertTrue(ObjectivesPlugin.objectives[0].isStarted)
}
private fun childAtPosition(
parentMatcher: Matcher<View>, position: Int): Matcher<View> {
return object : TypeSafeMatcher<View>() {
override fun describeTo(description: Description) {
description.appendText("Child at position $position in parent ")
parentMatcher.describeTo(description)
}
public override fun matchesSafely(view: View): Boolean {
val parent = view.parent
return parent is ViewGroup && parentMatcher.matches(parent)
&& view == parent.getChildAt(position)
}
}
}
}

View file

@ -52,12 +52,11 @@
</activity> </activity>
<activity android:name=".activities.PreferencesActivity" /> <activity android:name=".activities.PreferencesActivity" />
<activity <activity
android:name=".plugins.general.overview.dialogs.BolusProgressHelperActivity" android:name=".activities.BolusProgressHelperActivity"
android:theme="@style/Theme.AppCompat.Translucent" /> android:theme="@style/Theme.AppCompat.Translucent" />
<activity <activity
android:name=".plugins.general.overview.dialogs.ErrorHelperActivity" android:name=".activities.ErrorHelperActivity"
android:theme="@style/Theme.AppCompat.Translucent" /> android:theme="@style/Theme.AppCompat.Translucent" />
<activity android:name=".activities.AgreementActivity" />
<activity android:name=".plugins.pump.danaR.activities.DanaRHistoryActivity" /> <activity android:name=".plugins.pump.danaR.activities.DanaRHistoryActivity" />
<activity android:name=".plugins.pump.danaR.activities.DanaRUserOptionsActivity" /> <activity android:name=".plugins.pump.danaR.activities.DanaRUserOptionsActivity" />
<activity android:name=".activities.TDDStatsActivity" /> <activity android:name=".activities.TDDStatsActivity" />
@ -77,6 +76,8 @@
</activity> </activity>
<activity android:name=".plugins.pump.danaRS.activities.PairingHelperActivity" /> <activity android:name=".plugins.pump.danaRS.activities.PairingHelperActivity" />
<activity android:name=".activities.HistoryBrowseActivity" /> <activity android:name=".activities.HistoryBrowseActivity" />
<activity android:name=".activities.SurveyActivity" />
<activity android:name=".activities.StatsActivity" />
<!-- Receive new BG readings from other local apps --> <!-- Receive new BG readings from other local apps -->
<receiver <receiver
@ -115,7 +116,7 @@
<!-- Auto start --> <!-- Auto start -->
<receiver <receiver
android:name=".plugins.general.nsclient.receivers.AutoStartReceiver" android:name=".receivers.AutoStartReceiver"
android:enabled="true" android:enabled="true"
android:exported="true"> android:exported="true">
<intent-filter> <intent-filter>
@ -123,16 +124,6 @@
</intent-filter> </intent-filter>
</receiver> </receiver>
<!-- NSClient -->
<receiver
android:name=".plugins.general.nsclient.receivers.DBAccessReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="info.nightscout.client.DBACCESS" />
</intent-filter>
</receiver>
<!-- Network change local receiver --> <!-- Network change local receiver -->
<receiver android:name=".receivers.NetworkChangeReceiver"> <receiver android:name=".receivers.NetworkChangeReceiver">
<intent-filter> <intent-filter>

View file

@ -1,2 +1,4 @@
#Demo certificate #Demo certificate
51:6D:12:67:4C:27:F4:9B:9F:E5:42:9B:01:B3:98:E4:66:2B:85:B7:A8:DD:70:32:B7:6A:D7:97:9A:0D:97:10 51:6D:12:67:4C:27:F4:9B:9F:E5:42:9B:01:B3:98:E4:66:2B:85:B7:A8:DD:70:32:B7:6A:D7:97:9A:0D:97:10
#Leaked
55:5D:70:C9:BE:10:41:7E:4B:01:A9:C4:C6:44:4A:F8:69:71:35:25:ED:95:23:16:C7:15:E8:EB:C6:08:FC:B1

View file

@ -25,8 +25,6 @@ public class Constants {
public static final int hoursToKeepInDatabase = 72; public static final int hoursToKeepInDatabase = 72;
public static final int daysToKeepHistoryInDatabase = 30; public static final int daysToKeepHistoryInDatabase = 30;
public static final long keepAliveMsecs = 5 * 60 * 1000L;
// SMS COMMUNICATOR // SMS COMMUNICATOR
public static final long remoteBolusMinDistance = 15 * 60 * 1000L; public static final long remoteBolusMinDistance = 15 * 60 * 1000L;
@ -78,4 +76,15 @@ public class Constants {
//Storage [MB] //Storage [MB]
public static final long MINIMUM_FREE_SPACE = 200; public static final long MINIMUM_FREE_SPACE = 200;
// Overview
public static final double LOWMARK = 76.0;
public static final double HIGHMARK = 180.0;
// STATISTICS
public static final double STATS_TARGET_LOW_MMOL = 3.9;
public static final double STATS_TARGET_HIGH_MMOL = 7.8;
public static final double STATS_RANGE_LOW_MMOL = 3.9;
public static final double STATS_RANGE_HIGH_MMOL = 10.0;
} }

View file

@ -37,12 +37,11 @@ import com.joanzapata.iconify.fonts.FontAwesomeModule;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import info.nightscout.androidaps.activities.AgreementActivity;
import info.nightscout.androidaps.activities.HistoryBrowseActivity; import info.nightscout.androidaps.activities.HistoryBrowseActivity;
import info.nightscout.androidaps.activities.NoSplashAppCompatActivity; import info.nightscout.androidaps.activities.NoSplashAppCompatActivity;
import info.nightscout.androidaps.activities.PreferencesActivity; import info.nightscout.androidaps.activities.PreferencesActivity;
import info.nightscout.androidaps.activities.SingleFragmentActivity; import info.nightscout.androidaps.activities.SingleFragmentActivity;
import info.nightscout.androidaps.data.Profile; import info.nightscout.androidaps.activities.StatsActivity;
import info.nightscout.androidaps.events.EventAppExit; import info.nightscout.androidaps.events.EventAppExit;
import info.nightscout.androidaps.events.EventPreferenceChange; import info.nightscout.androidaps.events.EventPreferenceChange;
import info.nightscout.androidaps.events.EventRebuildTabs; import info.nightscout.androidaps.events.EventRebuildTabs;
@ -51,7 +50,6 @@ import info.nightscout.androidaps.interfaces.PluginType;
import info.nightscout.androidaps.logging.L; import info.nightscout.androidaps.logging.L;
import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin; import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin;
import info.nightscout.androidaps.plugins.bus.RxBus; import info.nightscout.androidaps.plugins.bus.RxBus;
import info.nightscout.androidaps.plugins.configBuilder.ProfileFunctions;
import info.nightscout.androidaps.plugins.constraints.versionChecker.VersionCheckerUtilsKt; import info.nightscout.androidaps.plugins.constraints.versionChecker.VersionCheckerUtilsKt;
import info.nightscout.androidaps.plugins.general.nsclient.data.NSSettingsStatus; import info.nightscout.androidaps.plugins.general.nsclient.data.NSSettingsStatus;
import info.nightscout.androidaps.setupwizard.SetupWizardActivity; import info.nightscout.androidaps.setupwizard.SetupWizardActivity;
@ -65,6 +63,8 @@ import info.nightscout.androidaps.utils.SP;
import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.CompositeDisposable; import io.reactivex.disposables.CompositeDisposable;
import static info.nightscout.androidaps.utils.EspressoTestHelperKt.isRunningRealPumpTest;
public class MainActivity extends NoSplashAppCompatActivity { public class MainActivity extends NoSplashAppCompatActivity {
private static Logger log = LoggerFactory.getLogger(L.CORE); private static Logger log = LoggerFactory.getLogger(L.CORE);
private CompositeDisposable disposable = new CompositeDisposable(); private CompositeDisposable disposable = new CompositeDisposable();
@ -94,8 +94,6 @@ public class MainActivity extends NoSplashAppCompatActivity {
// initialize screen wake lock // initialize screen wake lock
processPreferenceChange(new EventPreferenceChange(R.string.key_keep_screen_on)); processPreferenceChange(new EventPreferenceChange(R.string.key_keep_screen_on));
doMigrations();
final ViewPager viewPager = findViewById(R.id.pager); final ViewPager viewPager = findViewById(R.id.pager);
viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() { viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override @Override
@ -141,11 +139,9 @@ public class MainActivity extends NoSplashAppCompatActivity {
.subscribe(this::processPreferenceChange, FabricPrivacy::logException) .subscribe(this::processPreferenceChange, FabricPrivacy::logException)
); );
if (!SP.getBoolean(R.string.key_setupwizard_processed, false)) { if (!SP.getBoolean(R.string.key_setupwizard_processed, false) && !isRunningRealPumpTest()) {
Intent intent = new Intent(this, SetupWizardActivity.class); Intent intent = new Intent(this, SetupWizardActivity.class);
startActivity(intent); startActivity(intent);
} else {
checkEula();
} }
AndroidPermission.notifyForStoragePermission(this); AndroidPermission.notifyForStoragePermission(this);
@ -153,6 +149,7 @@ public class MainActivity extends NoSplashAppCompatActivity {
if (Config.PUMPDRIVERS) { if (Config.PUMPDRIVERS) {
AndroidPermission.notifyForLocationPermissions(this); AndroidPermission.notifyForLocationPermissions(this);
AndroidPermission.notifyForSMSPermissions(this); AndroidPermission.notifyForSMSPermissions(this);
AndroidPermission.notifyForSystemWindowPermissions(this);
} }
} }
@ -237,49 +234,6 @@ public class MainActivity extends NoSplashAppCompatActivity {
} }
} }
private void checkEula() {
//SP.removeBoolean(R.string.key_i_understand);
boolean IUnderstand = SP.getBoolean(R.string.key_i_understand, false);
if (!IUnderstand) {
Intent intent = new Intent(getApplicationContext(), AgreementActivity.class);
startActivity(intent);
finish();
}
}
private void doMigrations() {
checkUpgradeToProfileTarget();
// guarantee that the unreachable threshold is at least 30 and of type String
// Added in 1.57 at 21.01.2018
int unreachable_threshold = SP.getInt(R.string.key_pump_unreachable_threshold, 30);
SP.remove(R.string.key_pump_unreachable_threshold);
if (unreachable_threshold < 30) unreachable_threshold = 30;
SP.putString(R.string.key_pump_unreachable_threshold, Integer.toString(unreachable_threshold));
}
private void checkUpgradeToProfileTarget() { // TODO: can be removed in the future
boolean oldKeyExists = SP.contains("openapsma_min_bg");
if (oldKeyExists) {
Profile profile = ProfileFunctions.getInstance().getProfile();
String oldRange = SP.getDouble("openapsma_min_bg", 0d) + " - " + SP.getDouble("openapsma_max_bg", 0d);
String newRange = "";
if (profile != null) {
newRange = profile.getTargetLow() + " - " + profile.getTargetHigh();
}
String message = "Target range is changed in current version.\n\nIt's not taken from preferences but from profile.\n\n!!! REVIEW YOUR SETTINGS !!!";
message += "\n\nOld settings: " + oldRange;
message += "\nProfile settings: " + newRange;
OKDialog.show(this, "Target range change", message, () -> {
SP.remove("openapsma_min_bg");
SP.remove("openapsma_max_bg");
SP.remove("openapsma_target_bg");
});
}
}
@Override @Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults); super.onRequestPermissionsResult(requestCode, permissions, grantResults);
@ -288,15 +242,13 @@ public class MainActivity extends NoSplashAppCompatActivity {
switch (requestCode) { switch (requestCode) {
case AndroidPermission.CASE_STORAGE: case AndroidPermission.CASE_STORAGE:
//show dialog after permission is granted //show dialog after permission is granted
AlertDialog.Builder alert = new AlertDialog.Builder(this); OKDialog.show(this, "", MainApp.gs(R.string.alert_dialog_storage_permission_text));
alert.setMessage(R.string.alert_dialog_storage_permission_text);
alert.setPositiveButton(R.string.ok, null);
alert.show();
break; break;
case AndroidPermission.CASE_LOCATION: case AndroidPermission.CASE_LOCATION:
case AndroidPermission.CASE_SMS: case AndroidPermission.CASE_SMS:
case AndroidPermission.CASE_BATTERY: case AndroidPermission.CASE_BATTERY:
case AndroidPermission.CASE_PHONE_STATE: case AndroidPermission.CASE_PHONE_STATE:
case AndroidPermission.CASE_SYSTEM_WINDOW:
break; break;
} }
} }
@ -365,9 +317,7 @@ public class MainActivity extends NoSplashAppCompatActivity {
return true; return true;
case R.id.nav_exit: case R.id.nav_exit:
log.debug("Exiting"); log.debug("Exiting");
MainApp.instance().stopKeepAliveService();
RxBus.INSTANCE.send(new EventAppExit()); RxBus.INSTANCE.send(new EventAppExit());
MainApp.closeDbHelper();
finish(); finish();
System.runFinalization(); System.runFinalization();
System.exit(0); System.exit(0);
@ -381,6 +331,14 @@ public class MainActivity extends NoSplashAppCompatActivity {
startActivity(i); startActivity(i);
}, null); }, null);
return true; return true;
/*
case R.id.nav_survey:
startActivity(new Intent(this, SurveyActivity.class));
return true;
*/
case R.id.nav_stats:
startActivity(new Intent(this, StatsActivity.class));
return true;
} }
return actionBarDrawerToggle.onOptionsItemSelected(item); return actionBarDrawerToggle.onOptionsItemSelected(item);
} }

View file

@ -1,12 +1,14 @@
package info.nightscout.androidaps; package info.nightscout.androidaps;
import android.app.Application; import android.app.Application;
import android.content.BroadcastReceiver;
import android.content.IntentFilter; import android.content.IntentFilter;
import android.content.res.Resources; import android.content.res.Resources;
import android.os.SystemClock; import android.os.SystemClock;
import androidx.annotation.ColorRes;
import androidx.annotation.PluralsRes; import androidx.annotation.PluralsRes;
import androidx.annotation.StringRes;
import androidx.core.content.ContextCompat;
import androidx.localbroadcastmanager.content.LocalBroadcastManager; import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import com.crashlytics.android.Crashlytics; import com.crashlytics.android.Crashlytics;
@ -15,6 +17,7 @@ import com.j256.ormlite.android.apptools.OpenHelperManager;
import net.danlew.android.joda.JodaTimeAndroid; import net.danlew.android.joda.JodaTimeAndroid;
import org.json.JSONException;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -22,6 +25,7 @@ import java.io.File;
import java.util.ArrayList; import java.util.ArrayList;
import info.nightscout.androidaps.data.ConstraintChecker; import info.nightscout.androidaps.data.ConstraintChecker;
import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.db.DatabaseHelper; import info.nightscout.androidaps.db.DatabaseHelper;
import info.nightscout.androidaps.interfaces.PluginBase; import info.nightscout.androidaps.interfaces.PluginBase;
import info.nightscout.androidaps.interfaces.PluginType; import info.nightscout.androidaps.interfaces.PluginType;
@ -32,6 +36,7 @@ import info.nightscout.androidaps.plugins.aps.openAPSAMA.OpenAPSAMAPlugin;
import info.nightscout.androidaps.plugins.aps.openAPSMA.OpenAPSMAPlugin; import info.nightscout.androidaps.plugins.aps.openAPSMA.OpenAPSMAPlugin;
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;
import info.nightscout.androidaps.plugins.configBuilder.ProfileFunctions;
import info.nightscout.androidaps.plugins.constraints.dstHelper.DstHelperPlugin; import info.nightscout.androidaps.plugins.constraints.dstHelper.DstHelperPlugin;
import info.nightscout.androidaps.plugins.constraints.objectives.ObjectivesPlugin; import info.nightscout.androidaps.plugins.constraints.objectives.ObjectivesPlugin;
import info.nightscout.androidaps.plugins.constraints.safety.SafetyPlugin; import info.nightscout.androidaps.plugins.constraints.safety.SafetyPlugin;
@ -46,8 +51,6 @@ import info.nightscout.androidaps.plugins.general.maintenance.LoggerUtils;
import info.nightscout.androidaps.plugins.general.maintenance.MaintenancePlugin; import info.nightscout.androidaps.plugins.general.maintenance.MaintenancePlugin;
import info.nightscout.androidaps.plugins.general.nsclient.NSClientPlugin; import info.nightscout.androidaps.plugins.general.nsclient.NSClientPlugin;
import info.nightscout.androidaps.plugins.general.nsclient.NSUpload; import info.nightscout.androidaps.plugins.general.nsclient.NSUpload;
import info.nightscout.androidaps.plugins.general.nsclient.receivers.AckAlarmReceiver;
import info.nightscout.androidaps.plugins.general.nsclient.receivers.DBAccessReceiver;
import info.nightscout.androidaps.plugins.general.overview.OverviewPlugin; import info.nightscout.androidaps.plugins.general.overview.OverviewPlugin;
import info.nightscout.androidaps.plugins.general.persistentNotification.PersistentNotificationPlugin; import info.nightscout.androidaps.plugins.general.persistentNotification.PersistentNotificationPlugin;
import info.nightscout.androidaps.plugins.general.smsCommunicator.SmsCommunicatorPlugin; import info.nightscout.androidaps.plugins.general.smsCommunicator.SmsCommunicatorPlugin;
@ -59,7 +62,6 @@ import info.nightscout.androidaps.plugins.insulin.InsulinOrefUltraRapidActingPlu
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin; import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin;
import info.nightscout.androidaps.plugins.profile.local.LocalProfilePlugin; import info.nightscout.androidaps.plugins.profile.local.LocalProfilePlugin;
import info.nightscout.androidaps.plugins.profile.ns.NSProfilePlugin; import info.nightscout.androidaps.plugins.profile.ns.NSProfilePlugin;
import info.nightscout.androidaps.plugins.profile.simple.SimpleProfilePlugin;
import info.nightscout.androidaps.plugins.pump.combo.ComboPlugin; import info.nightscout.androidaps.plugins.pump.combo.ComboPlugin;
import info.nightscout.androidaps.plugins.pump.danaR.DanaRPlugin; import info.nightscout.androidaps.plugins.pump.danaR.DanaRPlugin;
import info.nightscout.androidaps.plugins.pump.danaRKorean.DanaRKoreanPlugin; import info.nightscout.androidaps.plugins.pump.danaRKorean.DanaRKoreanPlugin;
@ -74,6 +76,7 @@ import info.nightscout.androidaps.plugins.sensitivity.SensitivityAAPSPlugin;
import info.nightscout.androidaps.plugins.sensitivity.SensitivityOref0Plugin; import info.nightscout.androidaps.plugins.sensitivity.SensitivityOref0Plugin;
import info.nightscout.androidaps.plugins.sensitivity.SensitivityOref1Plugin; import info.nightscout.androidaps.plugins.sensitivity.SensitivityOref1Plugin;
import info.nightscout.androidaps.plugins.sensitivity.SensitivityWeightedAveragePlugin; import info.nightscout.androidaps.plugins.sensitivity.SensitivityWeightedAveragePlugin;
import info.nightscout.androidaps.plugins.source.RandomBgPlugin;
import info.nightscout.androidaps.plugins.source.SourceDexcomPlugin; import info.nightscout.androidaps.plugins.source.SourceDexcomPlugin;
import info.nightscout.androidaps.plugins.source.SourceEversensePlugin; import info.nightscout.androidaps.plugins.source.SourceEversensePlugin;
import info.nightscout.androidaps.plugins.source.SourceGlimpPlugin; import info.nightscout.androidaps.plugins.source.SourceGlimpPlugin;
@ -88,8 +91,10 @@ import info.nightscout.androidaps.receivers.KeepAliveReceiver;
import info.nightscout.androidaps.receivers.NSAlarmReceiver; import info.nightscout.androidaps.receivers.NSAlarmReceiver;
import info.nightscout.androidaps.receivers.TimeDateOrTZChangeReceiver; import info.nightscout.androidaps.receivers.TimeDateOrTZChangeReceiver;
import info.nightscout.androidaps.services.Intents; import info.nightscout.androidaps.services.Intents;
import info.nightscout.androidaps.utils.ActivityMonitor;
import info.nightscout.androidaps.utils.FabricPrivacy; import info.nightscout.androidaps.utils.FabricPrivacy;
import info.nightscout.androidaps.utils.LocaleHelper; import info.nightscout.androidaps.utils.LocaleHelper;
import info.nightscout.androidaps.utils.SP;
import io.fabric.sdk.android.Fabric; import io.fabric.sdk.android.Fabric;
import static info.nightscout.androidaps.plugins.constraints.versionChecker.VersionCheckerUtilsKt.triggerCheckVersion; import static info.nightscout.androidaps.plugins.constraints.versionChecker.VersionCheckerUtilsKt.triggerCheckVersion;
@ -97,7 +102,6 @@ import static info.nightscout.androidaps.plugins.constraints.versionChecker.Vers
public class MainApp extends Application { public class MainApp extends Application {
private static Logger log = LoggerFactory.getLogger(L.CORE); private static Logger log = LoggerFactory.getLogger(L.CORE);
private static KeepAliveReceiver keepAliveReceiver;
private static MainApp sInstance; private static MainApp sInstance;
public static Resources sResources; public static Resources sResources;
@ -110,11 +114,7 @@ public class MainApp extends Application {
private static ArrayList<PluginBase> pluginsList = null; private static ArrayList<PluginBase> pluginsList = null;
private static DataReceiver dataReceiver = new DataReceiver(); private static DataReceiver dataReceiver = new DataReceiver();
private static NSAlarmReceiver alarmReciever = new NSAlarmReceiver(); private static NSAlarmReceiver alarmReceiver = new NSAlarmReceiver();
private static AckAlarmReceiver ackAlarmReciever = new AckAlarmReceiver();
private static DBAccessReceiver dbAccessReciever = new DBAccessReceiver();
private LocalBroadcastManager lbm;
BroadcastReceiver btReceiver;
TimeDateOrTZChangeReceiver timeDateOrTZChangeReceiver; TimeDateOrTZChangeReceiver timeDateOrTZChangeReceiver;
public static boolean devBranch; public static boolean devBranch;
@ -147,6 +147,8 @@ public class MainApp extends Application {
log.error("Error with Fabric init! " + e); log.error("Error with Fabric init! " + e);
} }
registerActivityLifecycleCallbacks(ActivityMonitor.INSTANCE);
mFirebaseAnalytics = FirebaseAnalytics.getInstance(this); mFirebaseAnalytics = FirebaseAnalytics.getInstance(this);
mFirebaseAnalytics.setAnalyticsCollectionEnabled(!Boolean.getBoolean("disableFirebase")); mFirebaseAnalytics.setAnalyticsCollectionEnabled(!Boolean.getBoolean("disableFirebase"));
@ -166,7 +168,6 @@ public class MainApp extends Application {
//trigger here to see the new version on app start after an update //trigger here to see the new version on app start after an update
triggerCheckVersion(); triggerCheckVersion();
//setBTReceiver();
if (pluginsList == null) { if (pluginsList == null) {
pluginsList = new ArrayList<>(); pluginsList = new ArrayList<>();
@ -192,14 +193,13 @@ public class MainApp extends Application {
pluginsList.add(OmnipodPumpPlugin.getPlugin()); pluginsList.add(OmnipodPumpPlugin.getPlugin());
if (!Config.NSCLIENT) pluginsList.add(MDIPlugin.getPlugin()); if (!Config.NSCLIENT) pluginsList.add(MDIPlugin.getPlugin());
pluginsList.add(VirtualPumpPlugin.getPlugin()); pluginsList.add(VirtualPumpPlugin.getPlugin());
pluginsList.add(CareportalPlugin.getPlugin()); if (Config.NSCLIENT) pluginsList.add(CareportalPlugin.getPlugin());
if (Config.APS) pluginsList.add(LoopPlugin.getPlugin()); if (Config.APS) pluginsList.add(LoopPlugin.getPlugin());
if (Config.APS) pluginsList.add(OpenAPSMAPlugin.getPlugin()); if (Config.APS) pluginsList.add(OpenAPSMAPlugin.getPlugin());
if (Config.APS) pluginsList.add(OpenAPSAMAPlugin.getPlugin()); if (Config.APS) pluginsList.add(OpenAPSAMAPlugin.getPlugin());
if (Config.APS) pluginsList.add(OpenAPSSMBPlugin.getPlugin()); if (Config.APS) pluginsList.add(OpenAPSSMBPlugin.getPlugin());
pluginsList.add(NSProfilePlugin.getPlugin()); pluginsList.add(NSProfilePlugin.getPlugin());
if (!Config.NSCLIENT) pluginsList.add(SimpleProfilePlugin.getPlugin()); if (!Config.NSCLIENT) pluginsList.add(LocalProfilePlugin.INSTANCE);
if (!Config.NSCLIENT) pluginsList.add(LocalProfilePlugin.getPlugin());
pluginsList.add(TreatmentsPlugin.getPlugin()); pluginsList.add(TreatmentsPlugin.getPlugin());
if (!Config.NSCLIENT) pluginsList.add(SafetyPlugin.getPlugin()); if (!Config.NSCLIENT) pluginsList.add(SafetyPlugin.getPlugin());
if (!Config.NSCLIENT) pluginsList.add(VersionCheckerPlugin.INSTANCE); if (!Config.NSCLIENT) pluginsList.add(VersionCheckerPlugin.INSTANCE);
@ -214,6 +214,7 @@ public class MainApp extends Application {
pluginsList.add(SourcePoctechPlugin.getPlugin()); pluginsList.add(SourcePoctechPlugin.getPlugin());
pluginsList.add(SourceTomatoPlugin.getPlugin()); pluginsList.add(SourceTomatoPlugin.getPlugin());
pluginsList.add(SourceEversensePlugin.getPlugin()); pluginsList.add(SourceEversensePlugin.getPlugin());
pluginsList.add(RandomBgPlugin.INSTANCE);
if (!Config.NSCLIENT) pluginsList.add(SmsCommunicatorPlugin.INSTANCE); if (!Config.NSCLIENT) pluginsList.add(SmsCommunicatorPlugin.INSTANCE);
pluginsList.add(FoodPlugin.getPlugin()); pluginsList.add(FoodPlugin.getPlugin());
@ -240,13 +241,40 @@ public class MainApp extends Application {
new Thread(() -> { new Thread(() -> {
SystemClock.sleep(5000); SystemClock.sleep(5000);
ConfigBuilderPlugin.getPlugin().getCommandQueue().readStatus("Initialization", null); ConfigBuilderPlugin.getPlugin().getCommandQueue().readStatus("Initialization", null);
startKeepAliveService();
}).start(); }).start();
} }
new Thread(() -> KeepAliveReceiver.setAlarm(this)).start();
doMigrations();
}
private void doMigrations() {
// guarantee that the unreachable threshold is at least 30 and of type String
// Added in 1.57 at 21.01.2018
int unreachable_threshold = SP.getInt(R.string.key_pump_unreachable_threshold, 30);
SP.remove(R.string.key_pump_unreachable_threshold);
if (unreachable_threshold < 30) unreachable_threshold = 30;
SP.putString(R.string.key_pump_unreachable_threshold, Integer.toString(unreachable_threshold));
// 2.5 -> 2.6
if (!SP.contains(R.string.key_units)) {
String newUnits = Constants.MGDL;
Profile p = ProfileFunctions.getInstance().getProfile();
if (p != null && p.getData() != null && p.getData().has("units")) {
try {
newUnits = p.getData().getString("units");
} catch (JSONException e) {
log.error("Unhandled exception", e);
}
}
SP.putString(R.string.key_units, newUnits);
}
} }
private void registerLocalBroadcastReceiver() { private void registerLocalBroadcastReceiver() {
lbm = LocalBroadcastManager.getInstance(this); LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(this);
lbm.registerReceiver(dataReceiver, new IntentFilter(Intents.ACTION_NEW_TREATMENT)); lbm.registerReceiver(dataReceiver, new IntentFilter(Intents.ACTION_NEW_TREATMENT));
lbm.registerReceiver(dataReceiver, new IntentFilter(Intents.ACTION_CHANGED_TREATMENT)); lbm.registerReceiver(dataReceiver, new IntentFilter(Intents.ACTION_CHANGED_TREATMENT));
lbm.registerReceiver(dataReceiver, new IntentFilter(Intents.ACTION_REMOVED_TREATMENT)); lbm.registerReceiver(dataReceiver, new IntentFilter(Intents.ACTION_REMOVED_TREATMENT));
@ -261,39 +289,21 @@ public class MainApp extends Application {
lbm.registerReceiver(dataReceiver, new IntentFilter(Intents.ACTION_NEW_CAL)); lbm.registerReceiver(dataReceiver, new IntentFilter(Intents.ACTION_NEW_CAL));
//register alarms //register alarms
lbm.registerReceiver(alarmReciever, new IntentFilter(Intents.ACTION_ALARM)); lbm.registerReceiver(alarmReceiver, new IntentFilter(Intents.ACTION_ALARM));
lbm.registerReceiver(alarmReciever, new IntentFilter(Intents.ACTION_ANNOUNCEMENT)); lbm.registerReceiver(alarmReceiver, new IntentFilter(Intents.ACTION_ANNOUNCEMENT));
lbm.registerReceiver(alarmReciever, new IntentFilter(Intents.ACTION_CLEAR_ALARM)); lbm.registerReceiver(alarmReceiver, new IntentFilter(Intents.ACTION_CLEAR_ALARM));
lbm.registerReceiver(alarmReciever, new IntentFilter(Intents.ACTION_URGENT_ALARM)); lbm.registerReceiver(alarmReceiver, new IntentFilter(Intents.ACTION_URGENT_ALARM));
//register ack alarm
lbm.registerReceiver(ackAlarmReciever, new IntentFilter(Intents.ACTION_ACK_ALARM));
//register dbaccess
lbm.registerReceiver(dbAccessReciever, new IntentFilter(Intents.ACTION_DATABASE));
this.timeDateOrTZChangeReceiver = new TimeDateOrTZChangeReceiver(); this.timeDateOrTZChangeReceiver = new TimeDateOrTZChangeReceiver();
this.timeDateOrTZChangeReceiver.registerBroadcasts(this); this.timeDateOrTZChangeReceiver.registerBroadcasts(this);
} }
private void startKeepAliveService() { public static String gs(@StringRes int id) {
if (keepAliveReceiver == null) {
keepAliveReceiver = new KeepAliveReceiver();
keepAliveReceiver.setAlarm(this);
}
}
public void stopKeepAliveService() {
if (keepAliveReceiver != null)
KeepAliveReceiver.cancelAlarm(this);
}
public static String gs(int id) {
return sResources.getString(id); return sResources.getString(id);
} }
public static String gs(int id, Object... args) { public static String gs(@StringRes int id, Object... args) {
return sResources.getString(id, args); return sResources.getString(id, args);
} }
@ -301,8 +311,8 @@ public class MainApp extends Application {
return sResources.getQuantityString(id, quantity, args); return sResources.getQuantityString(id, quantity, args);
} }
public static int gc(int id) { public static int gc(@ColorRes int id) {
return sResources.getColor(id); return ContextCompat.getColor(instance(), id);
} }
public static MainApp instance() { public static MainApp instance() {
@ -313,13 +323,6 @@ public class MainApp extends Application {
return sDatabaseHelper; return sDatabaseHelper;
} }
public static void closeDbHelper() {
if (sDatabaseHelper != null) {
sDatabaseHelper.close();
sDatabaseHelper = null;
}
}
public static FirebaseAnalytics getFirebaseAnalytics() { public static FirebaseAnalytics getFirebaseAnalytics() {
return mFirebaseAnalytics; return mFirebaseAnalytics;
} }
@ -422,20 +425,12 @@ public class MainApp extends Application {
public void onTerminate() { public void onTerminate() {
if (L.isEnabled(L.CORE)) if (L.isEnabled(L.CORE))
log.debug("onTerminate"); log.debug("onTerminate");
super.onTerminate();
if (sDatabaseHelper != null) {
sDatabaseHelper.close();
sDatabaseHelper = null;
}
if (btReceiver != null) { if (timeDateOrTZChangeReceiver != null)
unregisterReceiver(btReceiver);
}
if (timeDateOrTZChangeReceiver != null) {
unregisterReceiver(timeDateOrTZChangeReceiver); unregisterReceiver(timeDateOrTZChangeReceiver);
} unregisterActivityLifecycleCallbacks(ActivityMonitor.INSTANCE);
KeepAliveReceiver.cancelAlarm(this);
super.onTerminate();
} }
public static int dpToPx(int dp) { public static int dpToPx(int dp) {

View file

@ -1,44 +0,0 @@
package info.nightscout.androidaps.activities;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.CheckBox;
import info.nightscout.androidaps.MainActivity;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.utils.SP;
public class AgreementActivity extends NoSplashActivity {
boolean IUnderstand;
CheckBox agreeCheckBox;
Button saveButton;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_agreement);
IUnderstand = SP.getBoolean(R.string.key_i_understand, false);
setContentView(R.layout.activity_agreement);
agreeCheckBox = (CheckBox)findViewById(R.id.agreementCheckBox);
agreeCheckBox.setChecked(IUnderstand);
saveButton = (Button)findViewById(R.id.agreementSaveButton);
addListenerOnButton();
}
public void addListenerOnButton() {
saveButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
SP.putBoolean(R.string.key_i_understand, agreeCheckBox.isChecked());
Intent intent = new Intent(getApplicationContext(), MainActivity.class);
startActivity(intent);
finish();
}
});
}
}

View file

@ -0,0 +1,14 @@
package info.nightscout.androidaps.activities
import android.os.Bundle
import info.nightscout.androidaps.dialogs.BolusProgressDialog
class BolusProgressHelperActivity : DialogAppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
BolusProgressDialog()
.setHelperActivity(this)
.setInsulin(intent.getDoubleExtra("insulin", 0.0))
.show(supportFragmentManager, "BolusProgress")
}
}

View file

@ -0,0 +1,11 @@
package info.nightscout.androidaps.activities
import android.content.Context
import androidx.appcompat.app.AppCompatActivity
import info.nightscout.androidaps.utils.LocaleHelper
open class DialogAppCompatActivity : AppCompatActivity() {
public override fun attachBaseContext(newBase: Context) {
super.attachBaseContext(LocaleHelper.wrap(newBase))
}
}

View file

@ -1,12 +1,12 @@
package info.nightscout.androidaps.plugins.general.overview.dialogs package info.nightscout.androidaps.activities
import android.os.Bundle import android.os.Bundle
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.activities.NoSplashAppCompatActivity import info.nightscout.androidaps.dialogs.ErrorDialog
import info.nightscout.androidaps.plugins.general.nsclient.NSUpload import info.nightscout.androidaps.plugins.general.nsclient.NSUpload
import info.nightscout.androidaps.utils.SP import info.nightscout.androidaps.utils.SP
class ErrorHelperActivity : NoSplashAppCompatActivity() { class ErrorHelperActivity : DialogAppCompatActivity() {
@Override @Override
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {

View file

@ -45,7 +45,7 @@ import info.nightscout.androidaps.utils.T;
import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.CompositeDisposable; import io.reactivex.disposables.CompositeDisposable;
public class HistoryBrowseActivity extends NoSplashActivity { public class HistoryBrowseActivity extends NoSplashAppCompatActivity {
private static Logger log = LoggerFactory.getLogger(HistoryBrowseActivity.class); private static Logger log = LoggerFactory.getLogger(HistoryBrowseActivity.class);
private CompositeDisposable disposable = new CompositeDisposable(); private CompositeDisposable disposable = new CompositeDisposable();
@ -150,7 +150,7 @@ public class HistoryBrowseActivity extends NoSplashActivity {
); );
dpd.setThemeDark(true); dpd.setThemeDark(true);
dpd.dismissOnPause(true); dpd.dismissOnPause(true);
dpd.show(getFragmentManager(), "Datepickerdialog"); dpd.show(getSupportFragmentManager(), "Datepickerdialog");
}); });
bgGraph.getGridLabelRenderer().setGridColor(MainApp.gc(R.color.graphgrid)); bgGraph.getGridLabelRenderer().setGridColor(MainApp.gc(R.color.graphgrid));
@ -231,9 +231,8 @@ public class HistoryBrowseActivity extends NoSplashActivity {
noProfile.setVisibility(View.GONE); noProfile.setVisibility(View.GONE);
} }
final String units = profile.getUnits(); final double lowLine = OverviewPlugin.INSTANCE.determineLowLine();
final double lowLine = OverviewPlugin.INSTANCE.determineLowLine(units); final double highLine = OverviewPlugin.INSTANCE.determineHighLine();
final double highLine = OverviewPlugin.INSTANCE.determineHighLine(units);
buttonDate.setText(DateUtil.dateAndTimeString(start)); buttonDate.setText(DateUtil.dateAndTimeString(start));
buttonZoom.setText(String.valueOf(rangeToDisplay)); buttonZoom.setText(String.valueOf(rangeToDisplay));

View file

@ -1,13 +0,0 @@
package info.nightscout.androidaps.activities
import android.app.Activity
import android.os.Bundle
import info.nightscout.androidaps.R
open class NoSplashActivity : Activity() {
public override fun onCreate(savedInstanceState: Bundle?) {
setTheme(R.style.AppTheme_NoActionBar)
super.onCreate(savedInstanceState)
}
}

View file

@ -1,12 +1,18 @@
package info.nightscout.androidaps.activities package info.nightscout.androidaps.activities
import android.content.Context
import android.os.Bundle import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.utils.LocaleHelper
open class NoSplashAppCompatActivity : AppCompatActivity() { open class NoSplashAppCompatActivity : AppCompatActivity() {
public override fun onCreate(savedInstanceState: Bundle?) { public override fun onCreate(savedInstanceState: Bundle?) {
setTheme(R.style.AppTheme_NoActionBar) setTheme(R.style.AppTheme_NoActionBar)
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
} }
public override fun attachBaseContext(newBase: Context) {
super.attachBaseContext(LocaleHelper.wrap(newBase))
}
} }

View file

@ -1,5 +1,6 @@
package info.nightscout.androidaps.activities; package info.nightscout.androidaps.activities;
import android.content.Context;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.os.Bundle; import android.os.Bundle;
import android.preference.EditTextPreference; import android.preference.EditTextPreference;
@ -12,9 +13,12 @@ import android.preference.PreferenceManager;
import android.preference.PreferenceScreen; import android.preference.PreferenceScreen;
import android.preference.SwitchPreference; import android.preference.SwitchPreference;
import java.util.Arrays;
import info.nightscout.androidaps.Config; import info.nightscout.androidaps.Config;
import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R; import info.nightscout.androidaps.R;
import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.events.EventPreferenceChange; import info.nightscout.androidaps.events.EventPreferenceChange;
import info.nightscout.androidaps.events.EventRebuildTabs; import info.nightscout.androidaps.events.EventRebuildTabs;
import info.nightscout.androidaps.interfaces.PluginBase; import info.nightscout.androidaps.interfaces.PluginBase;
@ -48,8 +52,10 @@ import info.nightscout.androidaps.plugins.sensitivity.SensitivityOref0Plugin;
import info.nightscout.androidaps.plugins.sensitivity.SensitivityOref1Plugin; import info.nightscout.androidaps.plugins.sensitivity.SensitivityOref1Plugin;
import info.nightscout.androidaps.plugins.sensitivity.SensitivityWeightedAveragePlugin; import info.nightscout.androidaps.plugins.sensitivity.SensitivityWeightedAveragePlugin;
import info.nightscout.androidaps.plugins.source.SourceDexcomPlugin; import info.nightscout.androidaps.plugins.source.SourceDexcomPlugin;
import info.nightscout.androidaps.utils.LocaleHelper;
import info.nightscout.androidaps.utils.OKDialog; import info.nightscout.androidaps.utils.OKDialog;
import info.nightscout.androidaps.utils.SP; import info.nightscout.androidaps.utils.SP;
import info.nightscout.androidaps.utils.SafeParse;
public class PreferencesActivity extends PreferenceActivity implements SharedPreferences.OnSharedPreferenceChangeListener { public class PreferencesActivity extends PreferenceActivity implements SharedPreferences.OnSharedPreferenceChangeListener {
MyPreferenceFragment myPreferenceFragment; MyPreferenceFragment myPreferenceFragment;
@ -66,23 +72,49 @@ public class PreferencesActivity extends PreferenceActivity implements SharedPre
PreferenceManager.getDefaultSharedPreferences(this).registerOnSharedPreferenceChangeListener(this); PreferenceManager.getDefaultSharedPreferences(this).registerOnSharedPreferenceChangeListener(this);
} }
@Override
public void attachBaseContext(Context newBase) {
super.attachBaseContext(LocaleHelper.INSTANCE.wrap(newBase));
}
@Override @Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
RxBus.INSTANCE.send(new EventPreferenceChange(key)); RxBus.INSTANCE.send(new EventPreferenceChange(key));
if (key.equals("language")) { if (key.equals(MainApp.gs(R.string.key_language))) {
RxBus.INSTANCE.send(new EventRebuildTabs(true)); RxBus.INSTANCE.send(new EventRebuildTabs(true));
//recreate() does not update language so better close settings //recreate() does not update language so better close settings
finish(); finish();
} }
if (key.equals("short_tabtitles")) { if (key.equals(MainApp.gs(R.string.key_short_tabtitles))) {
RxBus.INSTANCE.send(new EventRebuildTabs()); RxBus.INSTANCE.send(new EventRebuildTabs());
} }
if (key.equals(MainApp.gs(R.string.key_units))) {
recreate();
return;
}
if (key.equals(MainApp.gs(R.string.key_openapsama_useautosens)) && SP.getBoolean(R.string.key_openapsama_useautosens, false)) { if (key.equals(MainApp.gs(R.string.key_openapsama_useautosens)) && SP.getBoolean(R.string.key_openapsama_useautosens, false)) {
OKDialog.show(this, MainApp.gs(R.string.configbuilder_sensitivity), MainApp.gs(R.string.sensitivity_warning), null); OKDialog.show(this, MainApp.gs(R.string.configbuilder_sensitivity), MainApp.gs(R.string.sensitivity_warning));
} }
updatePrefSummary(myPreferenceFragment.findPreference(key)); updatePrefSummary(myPreferenceFragment.findPreference(key));
} }
private static void adjustUnitDependentPrefs(Preference pref) {
// convert preferences values to current units
String[] unitDependent = new String[]{
MainApp.gs(R.string.key_hypo_target),
MainApp.gs(R.string.key_activity_target),
MainApp.gs(R.string.key_eatingsoon_target),
MainApp.gs(R.string.key_high_mark),
MainApp.gs(R.string.key_low_mark)
};
if (Arrays.asList(unitDependent).contains(pref.getKey())) {
EditTextPreference editTextPref = (EditTextPreference) pref;
String converted = Profile.toCurrentUnitsString(SafeParse.stringToDouble(editTextPref.getText()));
editTextPref.setSummary(converted);
editTextPref.setText(converted);
}
}
private static void updatePrefSummary(Preference pref) { private static void updatePrefSummary(Preference pref) {
if (pref instanceof ListPreference) { if (pref instanceof ListPreference) {
ListPreference listPref = (ListPreference) pref; ListPreference listPref = (ListPreference) pref;
@ -101,6 +133,8 @@ public class PreferencesActivity extends PreferenceActivity implements SharedPre
} }
} }
} }
if (pref != null)
adjustUnitDependentPrefs(pref);
} }
public static void initSummary(Preference p) { public static void initSummary(Preference p) {
@ -143,8 +177,8 @@ public class PreferencesActivity extends PreferenceActivity implements SharedPre
if (!Config.NSCLIENT) { if (!Config.NSCLIENT) {
addPreferencesFromResource(R.xml.pref_password); addPreferencesFromResource(R.xml.pref_password);
} }
addPreferencesFromResource(R.xml.pref_general);
addPreferencesFromResource(R.xml.pref_age); addPreferencesFromResource(R.xml.pref_age);
addPreferencesFromResource(R.xml.pref_language);
addPreferencesFromResource(R.xml.pref_overview); addPreferencesFromResource(R.xml.pref_overview);

View file

@ -3,7 +3,7 @@ package info.nightscout.androidaps.activities
import android.os.Bundle import android.os.Bundle
import info.nightscout.androidaps.plugins.source.SourceDexcomPlugin import info.nightscout.androidaps.plugins.source.SourceDexcomPlugin
class RequestDexcomPermissionActivity : NoSplashAppCompatActivity() { class RequestDexcomPermissionActivity : DialogAppCompatActivity() {
private val requestCode = "AndroidAPS <3".map { it.toInt() }.sum() private val requestCode = "AndroidAPS <3".map { it.toInt() }.sum()

View file

@ -1,60 +0,0 @@
package info.nightscout.androidaps.activities;
import android.content.Intent;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.interfaces.PluginBase;
import info.nightscout.androidaps.utils.PasswordProtection;
public class SingleFragmentActivity extends AppCompatActivity {
private PluginBase plugin;
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_single_fragment);
this.plugin = MainApp.getPluginsList().get(getIntent().getIntExtra("plugin", -1));
setTitle(plugin.getName());
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDisplayShowHomeEnabled(true);
if (savedInstanceState == null) {
getSupportFragmentManager().beginTransaction().replace(R.id.frame_layout,
Fragment.instantiate(this, plugin.pluginDescription.getFragmentClass())).commit();
}
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == android.R.id.home) {
finish();
return true;
}
else if (item.getItemId() == R.id.nav_plugin_preferences) {
PasswordProtection.QueryPassword(this, R.string.settings_password, "settings_password", () -> {
Intent i = new Intent(this, PreferencesActivity.class);
i.putExtra("id", plugin.getPreferencesId());
startActivity(i);
}, null);
return true;
}
return false;
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
if (plugin.getPreferencesId() != -1)
getMenuInflater().inflate(R.menu.menu_single_fragment, menu);
return super.onCreateOptionsMenu(menu);
}
}

View file

@ -0,0 +1,53 @@
package info.nightscout.androidaps.activities
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.view.Menu
import android.view.MenuItem
import androidx.appcompat.app.AppCompatActivity
import info.nightscout.androidaps.MainApp
import info.nightscout.androidaps.R
import info.nightscout.androidaps.interfaces.PluginBase
import info.nightscout.androidaps.utils.LocaleHelper
import info.nightscout.androidaps.utils.PasswordProtection
class SingleFragmentActivity : AppCompatActivity() {
private var plugin: PluginBase? = null
public override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_single_fragment)
plugin = MainApp.getPluginsList()[intent.getIntExtra("plugin", -1)]
title = plugin?.name
supportActionBar?.setDisplayHomeAsUpEnabled(true)
supportActionBar?.setDisplayShowHomeEnabled(true)
if (savedInstanceState == null) {
supportFragmentManager.beginTransaction().replace(R.id.frame_layout,
supportFragmentManager.fragmentFactory.instantiate(ClassLoader.getSystemClassLoader(), plugin?.pluginDescription?.fragmentClass!!)).commit()
}
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
if (item.itemId == android.R.id.home) {
finish()
return true
} else if (item.itemId == R.id.nav_plugin_preferences) {
PasswordProtection.QueryPassword(this, R.string.settings_password, "settings_password", Runnable {
val i = Intent(this, PreferencesActivity::class.java)
i.putExtra("id", plugin?.preferencesId)
startActivity(i)
}, null)
return true
}
return false
}
override fun onCreateOptionsMenu(menu: Menu): Boolean {
if (plugin?.preferencesId != -1) menuInflater.inflate(R.menu.menu_single_fragment, menu)
return super.onCreateOptionsMenu(menu)
}
public override fun attachBaseContext(newBase: Context) {
super.attachBaseContext(LocaleHelper.wrap(newBase))
}
}

View file

@ -0,0 +1,30 @@
package info.nightscout.androidaps.activities
import android.os.Bundle
import info.nightscout.androidaps.MainApp
import info.nightscout.androidaps.R
import info.nightscout.androidaps.utils.ActivityMonitor
import info.nightscout.androidaps.utils.OKDialog
import info.nightscout.androidaps.utils.TddCalculator
import info.nightscout.androidaps.utils.TirCalculator
import kotlinx.android.synthetic.main.stats_activity.*
class StatsActivity : NoSplashAppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.stats_activity)
stats_tdds.text = TddCalculator.stats()
stats_tir.text = TirCalculator.stats()
stats_activity.text = ActivityMonitor.stats()
ok.setOnClickListener { finish() }
stats_reset.setOnClickListener {
OKDialog.showConfirmation(this, MainApp.gs(R.string.doyouwantresetstats), Runnable {
ActivityMonitor.reset()
recreate()
})
}
}
}

View file

@ -0,0 +1,110 @@
package info.nightscout.androidaps.activities
import android.os.Bundle
import android.widget.ArrayAdapter
import com.google.firebase.auth.FirebaseAuth
import com.google.firebase.database.FirebaseDatabase
import info.nightscout.androidaps.R
import info.nightscout.androidaps.data.defaultProfile.DefaultProfile
import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin
import info.nightscout.androidaps.plugins.configBuilder.ProfileFunctions
import info.nightscout.androidaps.dialogs.ProfileViewerDialog
import info.nightscout.androidaps.utils.*
import kotlinx.android.synthetic.main.survey_activity.*
import org.slf4j.LoggerFactory
class SurveyActivity : NoSplashAppCompatActivity() {
private val log = LoggerFactory.getLogger(SurveyActivity::class.java)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.survey_activity)
survey_id.text = InstanceId.instanceId()
val profileStore = ConfigBuilderPlugin.getPlugin().activeProfileInterface?.profile
val profileList = profileStore?.getProfileList() ?: return
survey_spinner.adapter = ArrayAdapter(this, R.layout.spinner_centered, profileList)
survey_tdds.text = TddCalculator.stats()
survey_tir.text = TirCalculator.stats()
survey_activity.text = ActivityMonitor.stats()
survey_profile.setOnClickListener {
val age = SafeParse.stringToDouble(survey_age.text.toString())
val weight = SafeParse.stringToDouble(survey_weight.text.toString())
val tdd = SafeParse.stringToDouble(survey_tdd.text.toString())
if (age < 1 || age > 120) {
ToastUtils.showToastInUiThread(this, R.string.invalidage)
return@setOnClickListener
}
if ((weight < 5 || weight > 150) && tdd == 0.0) {
ToastUtils.showToastInUiThread(this, R.string.invalidweight)
return@setOnClickListener
}
if ((tdd < 5 || tdd > 150) && weight == 0.0) {
ToastUtils.showToastInUiThread(this, R.string.invalidweight)
return@setOnClickListener
}
val profile = DefaultProfile().profile(age, tdd, weight, ProfileFunctions.getSystemUnits())
val args = Bundle()
args.putLong("time", DateUtil.now())
args.putInt("mode", ProfileViewerDialog.Mode.CUSTOM_PROFILE.ordinal)
args.putString("customProfile", profile.data.toString())
args.putString("customProfileUnits", profile.units)
args.putString("customProfileName", "Age: $age TDD: $tdd Weight: $weight")
val pvd = ProfileViewerDialog()
pvd.arguments = args
pvd.show(supportFragmentManager, "ProfileViewDialog")
}
survey_submit.setOnClickListener {
val r = FirebaseRecord()
r.id = InstanceId.instanceId()
r.age = SafeParse.stringToInt(survey_age.text.toString())
r.weight = SafeParse.stringToInt(survey_weight.text.toString())
if (r.age < 1 || r.age > 120) {
ToastUtils.showToastInUiThread(this, R.string.invalidage)
return@setOnClickListener
}
if (r.weight < 5 || r.weight > 150) {
ToastUtils.showToastInUiThread(this, R.string.invalidweight)
return@setOnClickListener
}
if (survey_spinner.selectedItem == null)
return@setOnClickListener
val profileName = survey_spinner.selectedItem.toString()
val specificProfile = profileStore.getSpecificProfile(profileName)
r.profileJson = specificProfile.toString()
val auth = FirebaseAuth.getInstance()
auth.signInAnonymously()
.addOnCompleteListener(this) { task ->
if (task.isSuccessful) {
log.debug("signInAnonymously:success")
val user = auth.currentUser // TODO: do we need this, seems unused?
val database = FirebaseDatabase.getInstance().reference
database.child("survey").child(r.id).setValue(r)
} else {
log.error("signInAnonymously:failure", task.exception)
ToastUtils.showToastInUiThread(this, "Authentication failed.")
//updateUI(null)
}
// ...
}
finish()
}
}
inner class FirebaseRecord {
var id = ""
var age: Int = 0
var weight: Int = 0
var profileJson = "ghfg"
}
}

View file

@ -54,7 +54,7 @@ import info.nightscout.androidaps.utils.SafeParse;
import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.CompositeDisposable; import io.reactivex.disposables.CompositeDisposable;
public class TDDStatsActivity extends NoSplashActivity { public class TDDStatsActivity extends NoSplashAppCompatActivity {
private static Logger log = LoggerFactory.getLogger(TDDStatsActivity.class); private static Logger log = LoggerFactory.getLogger(TDDStatsActivity.class);
private CompositeDisposable disposable = new CompositeDisposable(); private CompositeDisposable disposable = new CompositeDisposable();

View file

@ -1,7 +1,5 @@
package info.nightscout.androidaps.data; package info.nightscout.androidaps.data;
import com.rits.cloning.Cloner;
import org.json.JSONException; import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;
import org.slf4j.Logger; import org.slf4j.Logger;
@ -37,8 +35,19 @@ public class IobTotal implements DataPointWithLabelInterface {
public IobTotal copy() { public IobTotal copy() {
Cloner cloner = new Cloner(); IobTotal i = new IobTotal(time);
return cloner.deepClone(this); i.iob = iob;
i.activity = activity;
i.bolussnooze = bolussnooze;
i.basaliob = basaliob;
i.netbasalinsulin = netbasalinsulin;
i.hightempinsulin = hightempinsulin;
i.lastBolusTime = lastBolusTime;
if (iobWithZeroTemp != null) i.iobWithZeroTemp = iobWithZeroTemp.copy();
i.netInsulin = netInsulin;
i.netRatio = netRatio;
i.extendedBolusInsulin = extendedBolusInsulin;
return i;
} }
public IobTotal(long time) { public IobTotal(long time) {
@ -137,7 +146,7 @@ public class IobTotal implements DataPointWithLabelInterface {
// DataPoint interface // DataPoint interface
int color; private int color;
@Override @Override
public double getX() { public double getX() {

View file

@ -19,6 +19,7 @@ import info.nightscout.androidaps.interfaces.PumpDescription;
import info.nightscout.androidaps.interfaces.PumpInterface; import info.nightscout.androidaps.interfaces.PumpInterface;
import info.nightscout.androidaps.plugins.bus.RxBus; import info.nightscout.androidaps.plugins.bus.RxBus;
import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin; import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.configBuilder.ProfileFunctions;
import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification; import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification;
import info.nightscout.androidaps.plugins.general.overview.notifications.Notification; import info.nightscout.androidaps.plugins.general.overview.notifications.Notification;
import info.nightscout.androidaps.utils.DateUtil; import info.nightscout.androidaps.utils.DateUtil;
@ -76,6 +77,11 @@ public class Profile {
} }
} }
// Constructor from profileStore JSON
public Profile(JSONObject json) {
init(json, 100, 0);
}
public Profile(JSONObject json, int percentage, int timeshift) { public Profile(JSONObject json, int percentage, int timeshift) {
init(json, percentage, timeshift); init(json, percentage, timeshift);
} }
@ -101,8 +107,6 @@ public class Profile {
units = json.getString("units").toLowerCase(); units = json.getString("units").toLowerCase();
if (json.has("dia")) if (json.has("dia"))
dia = json.getDouble("dia"); dia = json.getDouble("dia");
if (json.has("dia"))
dia = json.getDouble("dia");
if (json.has("timezone")) if (json.has("timezone"))
timeZone = TimeZone.getTimeZone(json.getString("timezone")); timeZone = TimeZone.getTimeZone(json.getString("timezone"));
isf = json.getJSONArray("sens"); isf = json.getJSONArray("sens");
@ -150,7 +154,7 @@ public class Profile {
return units; return units;
} }
public TimeZone getTimeZone() { TimeZone getTimeZone() {
return timeZone; return timeZone;
} }
@ -163,7 +167,7 @@ public class Profile {
double multiplier = getMultiplier(array); double multiplier = getMultiplier(array);
LongSparseArray<Double> sparse = new LongSparseArray<>(); LongSparseArray<Double> sparse = new LongSparseArray<>();
for (Integer index = 0; index < array.length(); index++) { for (int index = 0; index < array.length(); index++) {
try { try {
final JSONObject o = array.getJSONObject(index); final JSONObject o = array.getJSONObject(index);
long tas = 0; long tas = 0;
@ -386,15 +390,15 @@ public class Profile {
return retValue; return retValue;
} }
public double getIsf() { public double getIsfMgdl() {
return getIsfTimeFromMidnight(secondsFromMidnight()); return toMgdl(getIsfTimeFromMidnight(secondsFromMidnight()), units);
} }
public double getIsf(long time) { public double getIsfMgdl(long time) {
return getIsfTimeFromMidnight(secondsFromMidnight(time)); return toMgdl(getIsfTimeFromMidnight(secondsFromMidnight(time)), units);
} }
double getIsfTimeFromMidnight(int timeAsSeconds) { public double getIsfTimeFromMidnight(int timeAsSeconds) {
if (isf_v == null) if (isf_v == null)
isf_v = convertToSparseArray(isf); isf_v = convertToSparseArray(isf);
return getValueToTime(isf_v, timeAsSeconds); return getValueToTime(isf_v, timeAsSeconds);
@ -406,15 +410,15 @@ public class Profile {
return getValuesList(isf_v, null, new DecimalFormat("0.0"), getUnits() + MainApp.gs(R.string.profile_per_unit)); return getValuesList(isf_v, null, new DecimalFormat("0.0"), getUnits() + MainApp.gs(R.string.profile_per_unit));
} }
public ProfileValue[] getIsfs() { public ProfileValue[] getIsfsMgdl() {
if (isf_v == null) if (isf_v == null)
isf_v = convertToSparseArray(ic); isf_v = convertToSparseArray(ic);
ProfileValue[] ret = new ProfileValue[isf_v.size()]; ProfileValue[] ret = new ProfileValue[isf_v.size()];
for (Integer index = 0; index < isf_v.size(); index++) { for (int index = 0; index < isf_v.size(); index++) {
Integer tas = (int) isf_v.keyAt(index); int tas = (int) isf_v.keyAt(index);
double value = isf_v.valueAt(index); double value = isf_v.valueAt(index);
ret[index] = new ProfileValue(tas, value); ret[index] = new ProfileValue(tas, toMgdl(value, units));
} }
return ret; return ret;
} }
@ -507,44 +511,44 @@ public class Profile {
return ret; return ret;
} }
public double getTarget() { public double getTargetMgdl() {
return getTarget(secondsFromMidnight()); return getTargetMgdl(secondsFromMidnight());
} }
protected double getTarget(int timeAsSeconds) { public double getTargetMgdl(int timeAsSeconds) {
return (getTargetLowTimeFromMidnight(timeAsSeconds) + getTargetHighTimeFromMidnight(timeAsSeconds)) / 2; return toMgdl((getTargetLowTimeFromMidnight(timeAsSeconds) + getTargetHighTimeFromMidnight(timeAsSeconds)) / 2, units);
} }
public double getTargetLow() { public double getTargetLowMgdl() {
return getTargetLowTimeFromMidnight(secondsFromMidnight()); return toMgdl(getTargetLowTimeFromMidnight(secondsFromMidnight()), units);
} }
public double getTargetLow(long time) { public double getTargetLowMgdl(long time) {
return getTargetLowTimeFromMidnight(secondsFromMidnight(time)); return toMgdl(getTargetLowTimeFromMidnight(secondsFromMidnight(time)), units);
} }
public double getTargetLowTimeFromMidnight(int timeAsSeconds) { double getTargetLowTimeFromMidnight(int timeAsSeconds) {
if (targetLow_v == null) if (targetLow_v == null)
targetLow_v = convertToSparseArray(targetLow); targetLow_v = convertToSparseArray(targetLow);
return getValueToTime(targetLow_v, timeAsSeconds); return getValueToTime(targetLow_v, timeAsSeconds);
} }
public double getTargetHigh() { public double getTargetHighMgdl() {
return getTargetHighTimeFromMidnight(secondsFromMidnight()); return toMgdl(getTargetHighTimeFromMidnight(secondsFromMidnight()), units);
} }
public double getTargetHigh(long time) { public double getTargetHighMgdl(long time) {
return getTargetHighTimeFromMidnight(secondsFromMidnight(time)); return toMgdl(getTargetHighTimeFromMidnight(secondsFromMidnight(time)), units);
} }
public double getTargetHighTimeFromMidnight(int timeAsSeconds) { double getTargetHighTimeFromMidnight(int timeAsSeconds) {
if (targetHigh_v == null) if (targetHigh_v == null)
targetHigh_v = convertToSparseArray(targetHigh); targetHigh_v = convertToSparseArray(targetHigh);
return getValueToTime(targetHigh_v, timeAsSeconds); return getValueToTime(targetHigh_v, timeAsSeconds);
} }
public class TargetValue { public class TargetValue {
public TargetValue(int timeAsSeconds, double low, double high) { TargetValue(int timeAsSeconds, double low, double high) {
this.timeAsSeconds = timeAsSeconds; this.timeAsSeconds = timeAsSeconds;
this.low = low; this.low = low;
this.high = high; this.high = high;
@ -571,17 +575,17 @@ public class Profile {
return ret; return ret;
} }
public ProfileValue[] getSingleTargets() { public ProfileValue[] getSingleTargetsMgdl() {
if (targetLow_v == null) if (targetLow_v == null)
targetLow_v = convertToSparseArray(targetLow); targetLow_v = convertToSparseArray(targetLow);
if (targetHigh_v == null) if (targetHigh_v == null)
targetHigh_v = convertToSparseArray(targetHigh); targetHigh_v = convertToSparseArray(targetHigh);
ProfileValue[] ret = new ProfileValue[targetLow_v.size()]; ProfileValue[] ret = new ProfileValue[targetLow_v.size()];
for (Integer index = 0; index < targetLow_v.size(); index++) { for (int index = 0; index < targetLow_v.size(); index++) {
Integer tas = (int) targetLow_v.keyAt(index); int tas = (int) targetLow_v.keyAt(index);
double target = (targetLow_v.valueAt(index) + targetHigh_v.valueAt(index)) / 2; double target = (targetLow_v.valueAt(index) + targetHigh_v.valueAt(index)) / 2;
ret[index] = new ProfileValue(tas, target); ret[index] = new ProfileValue(tas, toMgdl(target, units));
} }
return ret; return ret;
} }
@ -597,7 +601,7 @@ public class Profile {
public double getMaxDailyBasal() { public double getMaxDailyBasal() {
double max = 0d; double max = 0d;
for (int hour = 0; hour < 24; hour++) { for (int hour = 0; hour < 24; hour++) {
double value = getBasalTimeFromMidnight((Integer) (hour * 60 * 60)); double value = getBasalTimeFromMidnight(hour * 60 * 60);
if (value > max) max = value; if (value > max) max = value;
} }
return max; return max;
@ -629,22 +633,39 @@ public class Profile {
else return value * Constants.MGDL_TO_MMOLL; else return value * Constants.MGDL_TO_MMOLL;
} }
public static double toUnits(Double valueInMgdl, Double valueInMmol, String units) { public static double fromMmolToUnits(double value, String units) {
if (units.equals(Constants.MMOL)) return value;
else return value * Constants.MMOLL_TO_MGDL;
}
public static double toUnits(double valueInMgdl, double valueInMmol, String units) {
if (units.equals(Constants.MGDL)) return valueInMgdl; if (units.equals(Constants.MGDL)) return valueInMgdl;
else return valueInMmol; else return valueInMmol;
} }
public static String toUnitsString(Double valueInMgdl, Double valueInMmol, String units) { public static String toUnitsString(double valueInMgdl, double valueInMmol, String units) {
if (units.equals(Constants.MGDL)) return DecimalFormatter.to0Decimal(valueInMgdl); if (units.equals(Constants.MGDL)) return DecimalFormatter.to0Decimal(valueInMgdl);
else return DecimalFormatter.to1Decimal(valueInMmol); else return DecimalFormatter.to1Decimal(valueInMmol);
} }
public static String toSignedUnitsString(Double valueInMgdl, Double valueInMmol, String units) { public static String toSignedUnitsString(double valueInMgdl, double valueInMmol, String units) {
if (units.equals(Constants.MGDL)) if (units.equals(Constants.MGDL))
return (valueInMgdl > 0 ? "+" : "") + DecimalFormatter.to0Decimal(valueInMgdl); return (valueInMgdl > 0 ? "+" : "") + DecimalFormatter.to0Decimal(valueInMgdl);
else return (valueInMmol > 0 ? "+" : "") + DecimalFormatter.to1Decimal(valueInMmol); else return (valueInMmol > 0 ? "+" : "") + DecimalFormatter.to1Decimal(valueInMmol);
} }
public static double toCurrentUnits(double anyBg) {
if (anyBg < 32) return fromMmolToUnits(anyBg, ProfileFunctions.getSystemUnits());
else return fromMgdlToUnits(anyBg, ProfileFunctions.getSystemUnits());
}
public static String toCurrentUnitsString(double anyBg) {
if (anyBg < 32)
return toUnitsString(anyBg * Constants.MMOLL_TO_MGDL, anyBg, ProfileFunctions.getSystemUnits());
else
return toUnitsString(anyBg, anyBg * Constants.MGDL_TO_MMOLL, ProfileFunctions.getSystemUnits());
}
// targets are stored in mg/dl but profile vary // targets are stored in mg/dl but profile vary
public static String toTargetRangeString(double low, double high, String sourceUnits, String units) { public static String toTargetRangeString(double low, double high, String sourceUnits, String units) {
double lowMgdl = toMgdl(low, sourceUnits); double lowMgdl = toMgdl(low, sourceUnits);
@ -683,6 +704,113 @@ public class Profile {
return timeshift; return timeshift;
} }
public Profile convertToNonCustomizedProfile() {
JSONObject o = new JSONObject();
try {
o.put("units", units);
o.put("dia", dia);
o.put("timezone", timeZone.getID());
// SENS
JSONArray sens = new JSONArray();
double lastValue = -1d;
for (int i = 0; i < 24; i++) {
int timeAsSeconds = i * 60 * 60;
double value = getIsfTimeFromMidnight(timeAsSeconds);
if (value != lastValue) {
JSONObject item = new JSONObject();
String time;
DecimalFormat df = new DecimalFormat("00");
time = df.format(i) + ":00";
item.put("time", time);
item.put("timeAsSeconds", timeAsSeconds);
item.put("value", value);
lastValue = value;
sens.put(item);
}
}
o.put("sens", sens);
// CARBRATIO
JSONArray carbratio = new JSONArray();
lastValue = -1d;
for (int i = 0; i < 24; i++) {
int timeAsSeconds = i * 60 * 60;
double value = getIcTimeFromMidnight(timeAsSeconds);
if (value != lastValue) {
JSONObject item = new JSONObject();
String time;
DecimalFormat df = new DecimalFormat("00");
time = df.format(i) + ":00";
item.put("time", time);
item.put("timeAsSeconds", timeAsSeconds);
item.put("value", value);
lastValue = value;
carbratio.put(item);
}
}
o.put("carbratio", carbratio);
// BASAL
JSONArray basal = new JSONArray();
lastValue = -1d;
for (int i = 0; i < 24; i++) {
int timeAsSeconds = i * 60 * 60;
double value = getBasalTimeFromMidnight(timeAsSeconds);
if (value != lastValue) {
JSONObject item = new JSONObject();
String time;
DecimalFormat df = new DecimalFormat("00");
time = df.format(i) + ":00";
item.put("time", time);
item.put("timeAsSeconds", timeAsSeconds);
item.put("value", value);
lastValue = value;
basal.put(item);
}
}
o.put("basal", basal);
// TARGET_LOW
JSONArray target_low = new JSONArray();
lastValue = -1d;
for (int i = 0; i < 24; i++) {
int timeAsSeconds = i * 60 * 60;
double value = getTargetLowTimeFromMidnight(timeAsSeconds);
if (value != lastValue) {
JSONObject item = new JSONObject();
String time;
DecimalFormat df = new DecimalFormat("00");
time = df.format(i) + ":00";
item.put("time", time);
item.put("timeAsSeconds", timeAsSeconds);
item.put("value", value);
lastValue = value;
target_low.put(item);
}
}
o.put("target_low", target_low);
// TARGET_HIGH
JSONArray target_high = new JSONArray();
lastValue = -1d;
for (int i = 0; i < 24; i++) {
int timeAsSeconds = i * 60 * 60;
double value = getTargetHighTimeFromMidnight(timeAsSeconds);
if (value != lastValue) {
JSONObject item = new JSONObject();
String time;
DecimalFormat df = new DecimalFormat("00");
time = df.format(i) + ":00";
item.put("time", time);
item.put("timeAsSeconds", timeAsSeconds);
item.put("value", value);
lastValue = value;
target_high.put(item);
}
}
o.put("target_high", target_high);
} catch (JSONException e) {
log.error("Unhandled exception" + e);
}
return new Profile(o);
}
public boolean isProfileTheSame(Profile otherProfile) { public boolean isProfileTheSame(Profile otherProfile) {
@ -704,5 +832,4 @@ public class Profile {
return true; return true;
} }
} }

View file

@ -1,118 +0,0 @@
package info.nightscout.androidaps.data;
import androidx.annotation.Nullable;
import androidx.collection.ArrayMap;
import org.json.JSONException;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.Iterator;
import info.nightscout.androidaps.Constants;
/**
* Created by mike on 01.06.2017.
*/
public class ProfileStore {
private static Logger log = LoggerFactory.getLogger(ProfileStore.class);
private JSONObject json = null;
private String units = Constants.MGDL;
ArrayMap<String, Profile> cachedObjects = new ArrayMap<>();
public ProfileStore(JSONObject json) {
this.json = json;
getDefaultProfile(); // initialize units
}
public JSONObject getData() {
return json;
}
@Nullable
public Profile getDefaultProfile() {
Profile profile = null;
try {
String defaultProfileName = json.getString("defaultProfile");
JSONObject store = json.getJSONObject("store");
if (store.has(defaultProfileName)) {
profile = cachedObjects.get(defaultProfileName);
if (profile == null) {
if (store.has("units"))
units = store.getString("units");
profile = new Profile(store.getJSONObject(defaultProfileName), units);
units = profile.getUnits();
cachedObjects.put(defaultProfileName, profile);
}
}
} catch (JSONException e) {
log.error("Unhandled exception", e);
}
return profile;
}
@Nullable
public String getDefaultProfileName() {
String defaultProfileName = null;
try {
defaultProfileName = json.getString("defaultProfile");
JSONObject store = json.getJSONObject("store");
if (store.has(defaultProfileName)) {
return defaultProfileName;
}
} catch (JSONException e) {
log.error("Unhandled exception", e);
}
return defaultProfileName;
}
public String getUnits() {
return units;
}
@Nullable
public Profile getSpecificProfile(String profileName) {
Profile profile = null;
try {
JSONObject store = json.getJSONObject("store");
if (store.has(profileName)) {
profile = cachedObjects.get(profileName);
if (profile == null) {
if (store.has("units"))
units = store.getString("units");
profile = new Profile(store.getJSONObject(profileName), units);
units = profile.getUnits();
cachedObjects.put(profileName, profile);
}
}
} catch (JSONException e) {
log.error("Unhandled exception", e);
}
return profile;
}
public ArrayList<CharSequence> getProfileList() {
ArrayList<CharSequence> ret = new ArrayList<CharSequence>();
JSONObject store;
try {
store = json.getJSONObject("store");
Iterator<?> keys = store.keys();
while (keys.hasNext()) {
String profileName = (String) keys.next();
ret.add(profileName);
}
} catch (JSONException e) {
log.error("Unhandled exception", e);
}
return ret;
}
}

View file

@ -0,0 +1,60 @@
package info.nightscout.androidaps.data
import androidx.collection.ArrayMap
import info.nightscout.androidaps.utils.JsonHelper
import org.json.JSONException
import org.json.JSONObject
import org.slf4j.LoggerFactory
import java.util.*
class ProfileStore(val data: JSONObject) {
private val log = LoggerFactory.getLogger(ProfileStore::class.java)
private val cachedObjects = ArrayMap<String, Profile>()
private fun getStore(): JSONObject? {
try {
if (data.has("store")) return data.getJSONObject("store")
} catch (e: JSONException) {
log.error("Unhandled exception", e)
}
return null
}
fun getDefaultProfile(): Profile? = getDefaultProfileName()?.let { getSpecificProfile(it) }
fun getDefaultProfileName(): String? {
val defaultProfileName = data.getString("defaultProfile")
return getStore()?.has(defaultProfileName)?.let { defaultProfileName }
}
fun getProfileList(): ArrayList<CharSequence> {
val ret = ArrayList<CharSequence>()
getStore()?.keys()?.let { keys ->
while (keys.hasNext()) {
val profileName = keys.next() as String
ret.add(profileName)
}
}
return ret
}
fun getSpecificProfile(profileName: String): Profile? {
var profile: Profile? = null
getStore()?.let { store ->
if (store.has(profileName)) {
profile = cachedObjects[profileName]
if (profile == null) {
JsonHelper.safeGetJSONObject(store, profileName, null)?.let { profileObject ->
// take units from profile and if N/A from store
JsonHelper.safeGetStringAllowNull(profileObject, "units", JsonHelper.safeGetString(data, "units"))?.let { units ->
profile = Profile(profileObject, units)
cachedObjects[profileName] = profile
}
}
}
}
}
return profile
}
}

View file

@ -11,6 +11,7 @@ import info.nightscout.androidaps.R;
import info.nightscout.androidaps.db.BgReading; import info.nightscout.androidaps.db.BgReading;
import info.nightscout.androidaps.db.TempTarget; import info.nightscout.androidaps.db.TempTarget;
import info.nightscout.androidaps.interfaces.TreatmentsInterface; import info.nightscout.androidaps.interfaces.TreatmentsInterface;
import info.nightscout.androidaps.plugins.configBuilder.ProfileFunctions;
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.CobInfo; import info.nightscout.androidaps.plugins.iob.iobCobCalculator.CobInfo;
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;
@ -74,7 +75,7 @@ public class QuickWizardEntry {
//BG //BG
double bg = 0; double bg = 0;
if (lastBG != null && useBG() == YES) { if (lastBG != null && useBG() == YES) {
bg = lastBG.valueToUnits(profile.getUnits()); bg = lastBG.valueToUnits(ProfileFunctions.getSystemUnits());
} }
// COB // COB
@ -124,7 +125,8 @@ public class QuickWizardEntry {
trend = true; trend = true;
} }
return new BolusWizard(profile, profileName, tempTarget, carbs(), cob, bg, 0d, 100, true, useCOB() == YES, bolusIOB, basalIOB, superBolus, useTempTarget() == YES, trend, "QuickWizard"); double percentage = SP.getDouble(R.string.key_boluswizard_percentage, 100.0);
return new BolusWizard(profile, profileName, tempTarget, carbs(), cob, bg, 0d, percentage, true, useCOB() == YES, bolusIOB, basalIOB, superBolus, useTempTarget() == YES, trend, "QuickWizard");
} }
public String buttonText() { public String buttonText() {

View file

@ -0,0 +1,145 @@
package info.nightscout.androidaps.data.defaultProfile
import info.nightscout.androidaps.data.Profile
import info.nightscout.androidaps.utils.Round
import org.json.JSONArray
import org.json.JSONObject
import java.util.*
class DefaultProfile {
var oneToFive: TreeMap<Double, Array<Double>> = TreeMap()
var sixToEleven: TreeMap<Double, Array<Double>> = TreeMap()
var twelveToSeventeen: TreeMap<Double, Array<Double>> = TreeMap()
var eighteenToTwentyfor: TreeMap<Double, Array<Double>> = TreeMap()
fun profile(age: Double, tdd: Double, weight: Double, units: String): Profile {
val profile = JSONObject()
if (age >= 1 && age < 6) {
val _tdd = if (tdd == 0.0) 0.6 * weight else tdd
closest(oneToFive, _tdd * 0.3)?.let { array -> profile.put("basal", arrayToJson(array)) }
val ic = Round.roundTo(250.0 / _tdd, 1.0)
profile.put("carbratio", singleValueArray(ic, arrayOf( 0.0, -4.0, -1.0, -2.0, -4.0, 0.0, -4.0)))
val isf = Round.roundTo(200.0 / _tdd, 0.1)
profile.put("sens", singleValueArray(isf, arrayOf( 0.0, -2.0, -0.0, -0.0, -2.0, 0.0, -2.0)))
} else if (age >= 6 && age < 12) {
val _tdd = if (tdd == 0.0) 0.8 * weight else tdd
closest(sixToEleven, _tdd * 0.4)?.let { array -> profile.put("basal", arrayToJson(array)) }
val ic = Round.roundTo(375.0 / _tdd, 1.0)
profile.put("carbratio", singleValueArray(ic, arrayOf( 0.0, -3.0, 0.0, -1.0, -3.0, 0.0, -2.0)))
val isf = Round.roundTo(170.0 / _tdd, 0.1)
profile.put("sens", singleValueArray(isf, arrayOf( 0.0, -1.0, -0.0, -0.0, -1.0, 0.0, -1.0)))
} else if (age >= 12 && age < 17) {
val _tdd = if (tdd == 0.0) 1.0 * weight else tdd
closest(twelveToSeventeen, _tdd * 0.5)?.let { array -> profile.put("basal", arrayToJson(array)) }
val ic = Round.roundTo(500.0 / _tdd, 1.0)
profile.put("carbratio", singleValueArray(ic, arrayOf( 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, -1.0)))
val isf = Round.roundTo(100.0 / _tdd, 0.1)
profile.put("sens", singleValueArray(isf, arrayOf( 0.2, 0.0, 0.2, 0.2, 0.0, 0.2, 0.2)))
} else if (age >= 18) {
}
profile.put("dia", 5.0)
profile.put("carbs_hr", 20) // not used
profile.put("delay", 5.0) // not used
profile.put("timezone", TimeZone.getDefault().getID())
profile.put("target_high", JSONArray().put(JSONObject().put("time", "00:00").put("value", Profile.fromMgdlToUnits(108.0, units))))
profile.put("target_low", JSONArray().put(JSONObject().put("time", "00:00").put("value", Profile.fromMgdlToUnits(108.0, units))))
return Profile(profile, units)
}
init {
oneToFive[1.00] = arrayOf(0.050, 0.050, 0.050, 0.050, 0.050, 0.050, 0.075, 0.075, 0.075, 0.050, 0.050, 0.050, 0.050, 0.050, 0.075, 0.075, 0.050, 0.050, 0.050, 0.075, 0.075, 0.075, 0.050, 0.050)
oneToFive[1.13] = arrayOf(0.050, 0.050, 0.050, 0.050, 0.050, 0.050, 0.075, 0.075, 0.075, 0.050, 0.050, 0.050, 0.050, 0.050, 0.075, 0.075, 0.050, 0.050, 0.050, 0.075, 0.075, 0.075, 0.050, 0.050)
oneToFive[1.25] = arrayOf(0.050, 0.050, 0.050, 0.050, 0.050, 0.050, 0.075, 0.075, 0.075, 0.050, 0.050, 0.050, 0.050, 0.050, 0.075, 0.075, 0.050, 0.050, 0.050, 0.075, 0.075, 0.100, 0.050, 0.050)
oneToFive[1.38] = arrayOf(0.050, 0.050, 0.050, 0.050, 0.050, 0.050, 0.075, 0.075, 0.075, 0.050, 0.050, 0.050, 0.050, 0.050, 0.075, 0.075, 0.050, 0.050, 0.050, 0.075, 0.075, 0.100, 0.050, 0.050)
oneToFive[1.50] = arrayOf(0.050, 0.050, 0.050, 0.050, 0.050, 0.050, 0.075, 0.075, 0.075, 0.050, 0.050, 0.050, 0.050, 0.050, 0.075, 0.075, 0.050, 0.050, 0.050, 0.075, 0.100, 0.100, 0.050, 0.050)
oneToFive[1.75] = arrayOf(0.050, 0.050, 0.050, 0.050, 0.050, 0.050, 0.075, 0.075, 0.100, 0.050, 0.050, 0.050, 0.060, 0.060, 0.075, 0.075, 0.050, 0.050, 0.050, 0.100, 0.125, 0.100, 0.050, 0.050)
oneToFive[2.00] = arrayOf(0.050, 0.050, 0.050, 0.050, 0.050, 0.050, 0.075, 0.075, 0.100, 0.075, 0.050, 0.050, 0.065, 0.065, 0.075, 0.075, 0.050, 0.050, 0.050, 0.100, 0.125, 0.100, 0.050, 0.050)
oneToFive[2.25] = arrayOf(0.050, 0.050, 0.050, 0.050, 0.075, 0.075, 0.100, 0.100, 0.100, 0.075, 0.060, 0.060, 0.070, 0.070, 0.100, 0.100, 0.050, 0.050, 0.050, 0.125, 0.150, 0.125, 0.065, 0.050)
oneToFive[2.50] = arrayOf(0.050, 0.050, 0.050, 0.050, 0.075, 0.075, 0.100, 0.125, 0.125, 0.100, 0.065, 0.065, 0.075, 0.075, 0.125, 0.125, 0.060, 0.060, 0.060, 0.150, 0.150, 0.150, 0.070, 0.060)
oneToFive[2.75] = arrayOf(0.075, 0.075, 0.075, 0.100, 0.100, 0.100, 0.125, 0.150, 0.125, 0.100, 0.070, 0.070, 0.080, 0.080, 0.150, 0.150, 0.070, 0.070, 0.070, 0.175, 0.175, 0.175, 0.080, 0.070)
oneToFive[3.25] = arrayOf(0.100, 0.100, 0.100, 0.125, 0.125, 0.125, 0.150, 0.150, 0.150, 0.100, 0.080, 0.080, 0.100, 0.100, 0.175, 0.175, 0.075, 0.075, 0.075, 0.200, 0.200, 0.200, 0.090, 0.080)
oneToFive[3.75] = arrayOf(0.125, 0.125, 0.125, 0.125, 0.125, 0.125, 0.175, 0.175, 0.175, 0.100, 0.085, 0.085, 0.110, 0.110, 0.185, 0.185, 0.080, 0.080, 0.080, 0.225, 0.225, 0.225, 0.100, 0.090)
oneToFive[4.25] = arrayOf(0.125, 0.125, 0.130, 0.140, 0.140, 0.140, 0.200, 0.200, 0.200, 0.125, 0.090, 0.090, 0.120, 0.120, 0.200, 0.200, 0.100, 0.100, 0.100, 0.250, 0.250, 0.250, 0.125, 0.100)
oneToFive[4.75] = arrayOf(0.125, 0.130, 0.135, 0.150, 0.150, 0.150, 0.200, 0.225, 0.200, 0.125, 0.100, 0.100, 0.125, 0.125, 0.250, 0.200, 0.110, 0.125, 0.125, 0.275, 0.275, 0.275, 0.130, 0.125)
oneToFive[5.25] = arrayOf(0.150, 0.150, 0.150, 0.170, 0.170, 0.170, 0.225, 0.225, 0.225, 0.130, 0.125, 0.125, 0.140, 0.140, 0.250, 0.250, 0.150, 0.150, 0.150, 0.300, 0.300, 0.300, 0.150, 0.150)
oneToFive[6.00] = arrayOf(0.170, 0.170, 0.175, 0.200, 0.200, 0.200, 0.250, 0.250, 0.250, 0.150, 0.125, 0.125, 0.150, 0.150, 0.275, 0.275, 0.170, 0.150, 0.150, 0.350, 0.350, 0.350, 0.175, 0.150)
oneToFive[6.75] = arrayOf(0.200, 0.200, 0.200, 0.225, 0.225, 0.225, 0.275, 0.275, 0.275, 0.200, 0.130, 0.130, 0.175, 0.175, 0.300, 0.300, 0.170, 0.175, 0.175, 0.375, 0.375, 0.375, 0.200, 0.175)
oneToFive[7.50] = arrayOf(0.225, 0.230, 0.235, 0.250, 0.250, 0.250, 0.300, 0.300, 0.300, 0.250, 0.150, 0.150, 0.200, 0.200, 0.325, 0.325, 0.200, 0.200, 0.200, 0.400, 0.450, 0.400, 0.350, 0.200)
sixToEleven[5.26] = arrayOf(0.18, 0.18, 0.18, 0.20, 0.20, 0.23, 0.25, 0.25, 0.25, 0.18, 0.15, 0.13, 0.15, 0.15, 0.25, 0.25, 0.20, 0.15, 0.18, 0.25, 0.25, 0.25, 0.23, 0.20)
sixToEleven[5.61] = arrayOf(0.18, 0.20, 0.20, 0.23, 0.23, 0.25, 0.28, 0.28, 0.25, 0.20, 0.15, 0.13, 0.15, 0.18, 0.25, 0.25, 0.20, 0.15, 0.18, 0.28, 0.25, 0.25, 0.23, 0.20)
sixToEleven[5.93] = arrayOf(0.20, 0.20, 0.23, 0.25, 0.25, 0.25, 0.30, 0.30, 0.30, 0.25, 0.15, 0.15, 0.18, 0.18, 0.28, 0.28, 0.20, 0.20, 0.20, 0.28, 0.28, 0.28, 0.25, 0.23)
sixToEleven[6.26] = arrayOf(0.20, 0.23, 0.23, 0.25, 0.25, 0.28, 0.33, 0.30, 0.30, 0.25, 0.18, 0.15, 0.18, 0.18, 0.28, 0.28, 0.23, 0.20, 0.20, 0.28, 0.30, 0.28, 0.25, 0.23)
sixToEleven[6.60] = arrayOf(0.23, 0.23, 0.25, 0.25, 0.25, 0.28, 0.33, 0.33, 0.33, 0.28, 0.18, 0.15, 0.18, 0.18, 0.30, 0.28, 0.23, 0.23, 0.20, 0.30, 0.30, 0.30, 0.25, 0.25)
sixToEleven[7.26] = arrayOf(0.23, 0.25, 0.28, 0.28, 0.30, 0.33, 0.38, 0.35, 0.35, 0.30, 0.18, 0.18, 0.18, 0.19, 0.33, 0.30, 0.25, 0.23, 0.23, 0.33, 0.33, 0.33, 0.30, 0.25)
sixToEleven[7.92] = arrayOf(0.25, 0.25, 0.28, 0.30, 0.33, 0.35, 0.38, 0.38, 0.38, 0.35, 0.20, 0.20, 0.23, 0.25, 0.35, 0.33, 0.30, 0.25, 0.25, 0.35, 0.35, 0.35, 0.33, 0.28)
sixToEleven[8.57] = arrayOf(0.28, 0.28, 0.30, 0.30, 0.33, 0.38, 0.40, 0.43, 0.40, 0.38, 0.25, 0.25, 0.25, 0.28, 0.38, 0.38, 0.33, 0.28, 0.28, 0.38, 0.40, 0.38, 0.35, 0.30)
sixToEleven[9.24] = arrayOf(0.30, 0.33, 0.35, 0.38, 0.40, 0.40, 0.43, 0.45, 0.43, 0.40, 0.30, 0.25, 0.28, 0.28, 0.38, 0.40, 0.33, 0.30, 0.30, 0.40, 0.43, 0.40, 0.38, 0.35)
sixToEleven[9.89] = arrayOf(0.35, 0.35, 0.38, 0.40, 0.40, 0.43, 0.45, 0.48, 0.45, 0.40, 0.30, 0.25, 0.28, 0.30, 0.40, 0.43, 0.35, 0.33, 0.33, 0.43, 0.45, 0.43, 0.40, 0.38)
sixToEleven[10.56] = arrayOf(0.38, 0.38, 0.40, 0.43, 0.45, 0.45, 0.48, 0.50, 0.48, 0.40, 0.35, 0.25, 0.30, 0.33, 0.43, 0.45, 0.35, 0.35, 0.35, 0.45, 0.48, 0.45, 0.43, 0.40)
sixToEleven[11.21] = arrayOf(0.40, 0.43, 0.43, 0.45, 0.48, 0.50, 0.53, 0.55, 0.50, 0.40, 0.35, 0.30, 0.33, 0.33, 0.45, 0.48, 0.38, 0.35, 0.37, 0.50, 0.50, 0.48, 0.45, 0.43)
sixToEleven[11.88] = arrayOf(0.43, 0.43, 0.45, 0.45, 0.48, 0.50, 0.55, 0.58, 0.50, 0.40, 0.35, 0.33, 0.33, 0.33, 0.48, 0.50, 0.40, 0.38, 0.38, 0.53, 0.53, 0.50, 0.48, 0.45)
sixToEleven[12.53] = arrayOf(0.45, 0.45, 0.48, 0.50, 0.53, 0.55, 0.60, 0.60, 0.60, 0.45, 0.40, 0.35, 0.35, 0.38, 0.50, 0.53, 0.40, 0.38, 0.38, 0.55, 0.58, 0.55, 0.50, 0.48)
sixToEleven[13.19] = arrayOf(0.48, 0.48, 0.50, 0.55, 0.58, 0.60, 0.65, 0.65, 0.65, 0.50, 0.45, 0.36, 0.38, 0.40, 0.55, 0.55, 0.45, 0.40, 0.40, 0.60, 0.60, 0.58, 0.55, 0.50)
sixToEleven[14.18] = arrayOf(0.53, 0.53, 0.55, 0.60, 0.65, 0.68, 0.70, 0.70, 0.68, 0.60, 0.55, 0.40, 0.40, 0.45, 0.60, 0.60, 0.50, 0.45, 0.45, 0.63, 0.65, 0.63, 0.60, 0.60)
sixToEleven[15.17] = arrayOf(0.55, 0.58, 0.60, 0.65, 0.70, 0.70, 0.75, 0.75, 0.70, 0.65, 0.60, 0.42, 0.42, 0.45, 0.65, 0.65, 0.60, 0.50, 0.50, 0.68, 0.68, 0.65, 0.63, 0.63)
sixToEleven[16.50] = arrayOf(0.60, 0.63, 0.65, 0.70, 0.70, 0.70, 0.80, 0.80, 0.80, 0.70, 0.60, 0.45, 0.45, 0.50, 0.65, 0.70, 0.60, 0.55, 0.55, 0.75, 0.75, 0.70, 0.65, 0.65)
twelveToSeventeen[10.70] = arrayOf(0.30, 0.30, 0.30, 0.30, 0.40, 0.40, 0.60, 0.60, 0.60, 0.40, 0.35, 0.30, 0.30, 0.35, 0.45, 0.50, 0.40, 0.30, 0.30, 0.40, 0.50, 0.40, 0.40, 0.30)
twelveToSeventeen[11.10] = arrayOf(0.30, 0.30, 0.30, 0.35, 0.40, 0.45, 0.60, 0.60, 0.60, 0.40, 0.40, 0.30, 0.35, 0.40, 0.50, 0.50, 0.30, 0.30, 0.30, 0.50, 0.50, 0.50, 0.30, 0.30)
twelveToSeventeen[11.60] = arrayOf(0.30, 0.30, 0.35, 0.45, 0.45, 0.50, 0.65, 0.65, 0.65, 0.45, 0.40, 0.40, 0.40, 0.40, 0.50, 0.55, 0.55, 0.45, 0.45, 0.50, 0.50, 0.50, 0.40, 0.40)
twelveToSeventeen[13.00] = arrayOf(0.40, 0.40, 0.40, 0.50, 0.55, 0.60, 0.70, 0.70, 0.70, 0.60, 0.50, 0.40, 0.40, 0.40, 0.50, 0.60, 0.60, 0.50, 0.50, 0.60, 0.60, 0.60, 0.40, 0.30)
twelveToSeventeen[15.60] = arrayOf(0.45, 0.50, 0.50, 0.60, 0.65, 0.70, 0.80, 0.80, 0.80, 0.70, 0.60, 0.60, 0.50, 0.50, 0.60, 0.70, 0.70, 0.60, 0.60, 0.60, 0.70, 0.70, 0.50, 0.50)
twelveToSeventeen[17.00] = arrayOf(0.50, 0.55, 0.60, 0.70, 0.75, 0.80, 1.00, 1.00, 1.00, 0.80, 0.70, 0.60, 0.60, 0.60, 0.70, 0.80, 0.80, 0.65, 0.65, 0.65, 0.70, 0.70, 0.60, 0.60)
twelveToSeventeen[18.00] = arrayOf(0.60, 0.65, 0.70, 0.80, 0.85, 0.90, 1.10, 1.10, 1.10, 0.90, 0.80, 0.60, 0.60, 0.60, 0.70, 0.80, 0.80, 0.70, 0.65, 0.70, 0.75, 0.70, 0.60, 0.60)
twelveToSeventeen[20.20] = arrayOf(0.70, 0.75, 0.80, 0.90, 0.95, 1.00, 1.10, 1.10, 1.10, 0.90, 0.80, 0.70, 0.70, 0.70, 0.80, 0.90, 0.90, 0.75, 0.75, 0.75, 0.80, 0.80, 0.70, 0.70)
twelveToSeventeen[21.60] = arrayOf(0.75, 0.80, 0.90, 0.90, 1.00, 1.00, 1.20, 1.20, 1.20, 0.90, 0.80, 0.70, 0.70, 0.70, 0.90, 1.00, 1.00, 0.80, 0.80, 0.80, 0.80, 0.80, 0.70, 0.70)
twelveToSeventeen[23.80] = arrayOf(0.75, 0.80, 0.90, 1.00, 1.10, 1.10, 1.20, 1.20, 1.20, 1.00, 0.90, 0.80, 0.80, 0.80, 0.90, 1.10, 1.10, 0.90, 0.90, 0.90, 1.00, 1.00, 0.80, 0.80)
twelveToSeventeen[26.10] = arrayOf(0.80, 0.80, 0.90, 1.00, 1.20, 1.20, 1.30, 1.30, 1.30, 1.10, 1.00, 0.90, 0.90, 0.90, 1.00, 1.20, 1.10, 0.90, 0.90, 1.00, 1.00, 1.00, 0.90, 0.90)
twelveToSeventeen[28.00] = arrayOf(0.90, 0.90, 1.00, 1.10, 1.10, 1.20, 1.30, 1.30, 1.30, 1.20, 1.00, 1.00, 1.00, 1.00, 1.20, 1.20, 1.20, 1.00, 1.00, 1.10, 1.10, 1.10, 0.90, 0.90)
twelveToSeventeen[30.10] = arrayOf(1.00, 1.00, 1.10, 1.20, 1.30, 1.40, 1.50, 1.50, 1.50, 1.30, 1.20, 1.00, 1.00, 1.00, 1.30, 1.40, 1.40, 1.00, 1.00, 1.15, 1.15, 1.10, 1.00, 1.00)
twelveToSeventeen[32.60] = arrayOf(1.10, 1.10, 1.20, 1.20, 1.40, 1.50, 1.50, 1.50, 1.50, 1.30, 1.20, 1.10, 1.10, 1.10, 1.40, 1.50, 1.40, 1.10, 1.10, 1.20, 1.20, 1.20, 1.10, 1.10)
twelveToSeventeen[35.20] = arrayOf(1.20, 1.20, 1.30, 1.40, 1.50, 1.60, 1.70, 1.70, 1.50, 1.40, 1.20, 1.10, 1.10, 1.10, 1.40, 1.50, 1.60, 1.40, 1.20, 1.20, 1.30, 1.30, 1.20, 1.20)
twelveToSeventeen[39.00] = arrayOf(1.30, 1.30, 1.40, 1.60, 1.60, 1.60, 1.90, 1.90, 1.90, 1.50, 1.30, 1.20, 1.20, 1.30, 1.50, 1.60, 1.70, 1.80, 1.50, 1.50, 1.60, 1.60, 1.30, 1.30)
twelveToSeventeen[42.80] = arrayOf(1.40, 1.40, 1.50, 1.70, 1.80, 1.80, 2.00, 2.00, 2.00, 1.80, 1.80, 1.50, 1.50, 1.50, 1.60, 1.70, 1.80, 1.90, 1.60, 1.60, 1.70, 1.70, 1.50, 1.50)
twelveToSeventeen[47.30] = arrayOf(1.50, 1.50, 1.70, 1.70, 2.00, 2.00, 2.20, 2.30, 2.20, 2.00, 1.80, 1.60, 1.60, 1.60, 1.80, 2.00, 2.10, 1.90, 1.80, 1.80, 2.00, 2.00, 1.60, 1.60)
}
private fun closest(map: TreeMap<Double, Array<Double>>, key: Double): Array<Double>? {
val low = map.floorEntry(key)
val high = map.ceilingEntry(key)
var res: Array<Double>? = null
if (low != null && high != null) {
res = if (Math.abs(key - low.key) < Math.abs(key - high.key))
low.value
else
high.value
} else if (low != null || high != null) {
res = if (low != null) low.value else high.value
}
return res
}
fun arrayToJson(b: Array<Double>): JSONArray {
val basals = JSONArray()
for (i in 0..23) {
val time = String.format(Locale.ENGLISH, "%02d:00", i)
basals.put(JSONObject().put("time", time).put("value", b[i].toString()))
}
return basals
}
fun singleValueArray(value: Double, sample: Array<Double>): JSONArray {
val array = JSONArray()
array.put(JSONObject().put("time", "00:00").put("value", value + sample[0]))
array.put(JSONObject().put("time", "06:00").put("value", value + sample[1]))
array.put(JSONObject().put("time", "09:00").put("value", value + sample[2]))
array.put(JSONObject().put("time", "11:00").put("value", value + sample[3]))
array.put(JSONObject().put("time", "14:00").put("value", value + sample[4]))
array.put(JSONObject().put("time", "16:00").put("value", value + sample[5]))
array.put(JSONObject().put("time", "19:00").put("value", value + sample[6]))
return array
}
}

View file

@ -7,6 +7,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.util.Date; import java.util.Date;
import java.util.List;
import java.util.Objects; import java.util.Objects;
import info.nightscout.androidaps.Constants; import info.nightscout.androidaps.Constants;
@ -19,10 +20,11 @@ import info.nightscout.androidaps.plugins.general.overview.OverviewPlugin;
import info.nightscout.androidaps.plugins.general.overview.graphExtensions.DataPointWithLabelInterface; import info.nightscout.androidaps.plugins.general.overview.graphExtensions.DataPointWithLabelInterface;
import info.nightscout.androidaps.plugins.general.overview.graphExtensions.PointsWithLabelGraphSeries; import info.nightscout.androidaps.plugins.general.overview.graphExtensions.PointsWithLabelGraphSeries;
import info.nightscout.androidaps.utils.DecimalFormatter; import info.nightscout.androidaps.utils.DecimalFormatter;
import info.nightscout.androidaps.utils.T;
@DatabaseTable(tableName = DatabaseHelper.DATABASE_BGREADINGS) @DatabaseTable(tableName = DatabaseHelper.DATABASE_BGREADINGS)
public class BgReading implements DataPointWithLabelInterface { public class BgReading implements DataPointWithLabelInterface {
private static Logger log = LoggerFactory.getLogger(L.DATABASE); private static Logger log = LoggerFactory.getLogger(L.GLUCOSE);
@DatabaseField(id = true) @DatabaseField(id = true)
public long date; public long date;
@ -73,9 +75,10 @@ public class BgReading implements DataPointWithLabelInterface {
public String directionToSymbol() { public String directionToSymbol() {
String symbol = ""; String symbol = "";
if (direction == null) { if (direction == null)
symbol = "??"; direction = calculateDirection();
} else if (direction.compareTo("DoubleDown") == 0) {
if (direction.compareTo("DoubleDown") == 0) {
symbol = "\u21ca"; symbol = "\u21ca";
} else if (direction.compareTo("SingleDown") == 0) { } else if (direction.compareTo("SingleDown") == 0) {
symbol = "\u2193"; symbol = "\u2193";
@ -95,18 +98,13 @@ public class BgReading implements DataPointWithLabelInterface {
return symbol; return symbol;
} }
public static boolean isSlopeNameInvalid(String direction) { private static boolean isSlopeNameInvalid(String direction) {
if (direction.compareTo("NOT_COMPUTABLE") == 0 || return direction.compareTo("NOT_COMPUTABLE") == 0 ||
direction.compareTo("NOT COMPUTABLE") == 0 || direction.compareTo("NOT COMPUTABLE") == 0 ||
direction.compareTo("OUT_OF_RANGE") == 0 || direction.compareTo("OUT_OF_RANGE") == 0 ||
direction.compareTo("OUT OF RANGE") == 0 || direction.compareTo("OUT OF RANGE") == 0 ||
direction.compareTo("NONE") == 0 || direction.compareTo("NONE") == 0 ||
direction.compareTo("NotComputable") == 0 direction.compareTo("NotComputable") == 0;
) {
return true;
} else {
return false;
}
} }
@ -123,7 +121,8 @@ public class BgReading implements DataPointWithLabelInterface {
public boolean isDataChanging(BgReading other) { public boolean isDataChanging(BgReading other) {
if (date != other.date) { if (date != other.date) {
log.error("Comparing different"); if (L.isEnabled(L.GLUCOSE))
log.error("Comparing different");
return false; return false;
} }
if (value != other.value) if (value != other.value)
@ -133,7 +132,8 @@ public class BgReading implements DataPointWithLabelInterface {
public boolean isEqual(BgReading other) { public boolean isEqual(BgReading other) {
if (date != other.date) { if (date != other.date) {
log.error("Comparing different"); if (L.isEnabled(L.GLUCOSE))
log.error("Comparing different");
return false; return false;
} }
if (value != other.value) if (value != other.value)
@ -149,7 +149,8 @@ public class BgReading implements DataPointWithLabelInterface {
public void copyFrom(BgReading other) { public void copyFrom(BgReading other) {
if (date != other.date) { if (date != other.date) {
log.error("Copying different"); if (L.isEnabled(L.GLUCOSE))
log.error("Copying different");
return; return;
} }
value = other.value; value = other.value;
@ -181,8 +182,7 @@ public class BgReading implements DataPointWithLabelInterface {
@Override @Override
public double getY() { public double getY() {
String units = ProfileFunctions.getInstance().getProfileUnits(); return valueToUnits(ProfileFunctions.getSystemUnits());
return valueToUnits(units);
} }
@Override @Override
@ -215,9 +215,9 @@ public class BgReading implements DataPointWithLabelInterface {
@Override @Override
public int getColor() { public int getColor() {
String units = ProfileFunctions.getInstance().getProfileUnits(); String units = ProfileFunctions.getSystemUnits();
Double lowLine = OverviewPlugin.INSTANCE.determineLowLine(units); Double lowLine = OverviewPlugin.INSTANCE.determineLowLine();
Double highLine = OverviewPlugin.INSTANCE.determineHighLine(units); Double highLine = OverviewPlugin.INSTANCE.determineHighLine();
int color = MainApp.gc(R.color.inrange); int color = MainApp.gc(R.color.inrange);
if (isPrediction()) if (isPrediction())
return getPredectionColor(); return getPredectionColor();
@ -246,4 +246,53 @@ public class BgReading implements DataPointWithLabelInterface {
return isaCOBPrediction || isCOBPrediction || isIOBPrediction || isUAMPrediction || isZTPrediction; return isaCOBPrediction || isCOBPrediction || isIOBPrediction || isUAMPrediction || isZTPrediction;
} }
// Copied from xDrip+
String calculateDirection() {
// Rework to get bgreaings from internal DB and calculate on that base
List<BgReading> bgReadingsList = MainApp.getDbHelper().getAllBgreadingsDataFromTime(this.date - T.mins(10).msecs(), false);
if (bgReadingsList == null || bgReadingsList.size() < 2)
return "NONE";
BgReading current = bgReadingsList.get(1);
BgReading previous = bgReadingsList.get(0);
if (bgReadingsList.get(1).date < bgReadingsList.get(0).date) {
current = bgReadingsList.get(0);
previous = bgReadingsList.get(1);
}
double slope;
// Avoid division by 0
if (current.date == previous.date)
slope = 0;
else
slope = (previous.value - current.value) / (previous.date - current.date);
if (L.isEnabled(L.GLUCOSE))
log.debug("Slope is :" + slope + " delta " + (previous.value - current.value) + " date difference " + (current.date - previous.date));
double slope_by_minute = slope * 60000;
String arrow = "NONE";
if (slope_by_minute <= (-3.5)) {
arrow = "DoubleDown";
} else if (slope_by_minute <= (-2)) {
arrow = "SingleDown";
} else if (slope_by_minute <= (-1)) {
arrow = "FortyFiveDown";
} else if (slope_by_minute <= (1)) {
arrow = "Flat";
} else if (slope_by_minute <= (2)) {
arrow = "FortyFiveUp";
} else if (slope_by_minute <= (3.5)) {
arrow = "SingleUp";
} else if (slope_by_minute <= (40)) {
arrow = "DoubleUp";
}
if (L.isEnabled(L.GLUCOSE))
log.debug("Direction set to: " + arrow);
return arrow;
}
} }

View file

@ -167,7 +167,7 @@ public class CareportalEvent implements DataPointWithLabelInterface, Interval {
@Override @Override
public double getY() { public double getY() {
String units = ProfileFunctions.getInstance().getProfileUnits(); String units = ProfileFunctions.getSystemUnits();
if (eventType.equals(MBG)) { if (eventType.equals(MBG)) {
double mbg = 0d; double mbg = 0d;
try { try {

View file

@ -3,6 +3,7 @@ package info.nightscout.androidaps.db;
import android.content.Context; import android.content.Context;
import android.database.DatabaseUtils; import android.database.DatabaseUtils;
import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteDatabase;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import com.j256.ormlite.android.apptools.OrmLiteSqliteOpenHelper; import com.j256.ormlite.android.apptools.OrmLiteSqliteOpenHelper;
@ -32,7 +33,7 @@ import java.util.concurrent.TimeUnit;
import info.nightscout.androidaps.Constants; import info.nightscout.androidaps.Constants;
import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.plugins.bus.RxBus; import info.nightscout.androidaps.plugins.bus.RxBus;
import info.nightscout.androidaps.data.OverlappingIntervals; import info.nightscout.androidaps.data.NonOverlappingIntervals;
import info.nightscout.androidaps.data.Profile; import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.data.ProfileStore; import info.nightscout.androidaps.data.ProfileStore;
import info.nightscout.androidaps.events.EventCareportalEventChange; import info.nightscout.androidaps.events.EventCareportalEventChange;
@ -198,15 +199,6 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
return newVersion; return newVersion;
} }
/**
* Close the database connections and clear any cached DAOs.
*/
@Override
public void close() {
super.close();
}
public long size(String database) { public long size(String database) {
return DatabaseUtils.queryNumEntries(getReadableDatabase(), database); return DatabaseUtils.queryNumEntries(getReadableDatabase(), database);
} }
@ -569,12 +561,8 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
// ------------- DbRequests handling ------------------- // ------------- DbRequests handling -------------------
public void create(DbRequest dbr) { public void create(DbRequest dbr) throws SQLException {
try {
getDaoDbRequest().create(dbr); getDaoDbRequest().create(dbr);
} catch (SQLException e) {
log.error("Unhandled exception", e);
}
} }
public int delete(DbRequest dbr) { public int delete(DbRequest dbr) {
@ -783,8 +771,8 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
TempTarget tempTarget = new TempTarget() TempTarget tempTarget = new TempTarget()
.date(trJson.getLong("mills")) .date(trJson.getLong("mills"))
.duration(JsonHelper.safeGetInt(trJson, "duration")) .duration(JsonHelper.safeGetInt(trJson, "duration"))
.low(Profile.toMgdl(trJson.getDouble("targetBottom"), units)) .low(Profile.toMgdl(JsonHelper.safeGetDouble(trJson, "targetBottom"), units))
.high(Profile.toMgdl(trJson.getDouble("targetTop"), units)) .high(Profile.toMgdl(JsonHelper.safeGetDouble(trJson, "targetTop"), units))
.reason(JsonHelper.safeGetString(trJson, "reason", "")) .reason(JsonHelper.safeGetString(trJson, "reason", ""))
._id(trJson.getString("_id")) ._id(trJson.getString("_id"))
.source(Source.NIGHTSCOUT); .source(Source.NIGHTSCOUT);
@ -1436,7 +1424,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
QueryBuilder<CareportalEvent, Long> queryBuilder = getDaoCareportalEvents().queryBuilder(); QueryBuilder<CareportalEvent, Long> queryBuilder = getDaoCareportalEvents().queryBuilder();
queryBuilder.orderBy("date", false); queryBuilder.orderBy("date", false);
Where where = queryBuilder.where(); Where where = queryBuilder.where();
where.eq("eventType", event); where.eq("eventType", event).and().isNotNull("json");
queryBuilder.limit(1L); queryBuilder.limit(1L);
PreparedQuery<CareportalEvent> preparedQuery = queryBuilder.prepare(); PreparedQuery<CareportalEvent> preparedQuery = queryBuilder.prepare();
careportalEvents = getDaoCareportalEvents().query(preparedQuery); careportalEvents = getDaoCareportalEvents().query(preparedQuery);
@ -1456,10 +1444,10 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
QueryBuilder<CareportalEvent, Long> queryBuilder = getDaoCareportalEvents().queryBuilder(); QueryBuilder<CareportalEvent, Long> queryBuilder = getDaoCareportalEvents().queryBuilder();
queryBuilder.orderBy("date", ascending); queryBuilder.orderBy("date", ascending);
Where where = queryBuilder.where(); Where where = queryBuilder.where();
where.ge("date", mills); where.ge("date", mills).and().isNotNull("json").and().isNotNull("eventType");
PreparedQuery<CareportalEvent> preparedQuery = queryBuilder.prepare(); PreparedQuery<CareportalEvent> preparedQuery = queryBuilder.prepare();
careportalEvents = getDaoCareportalEvents().query(preparedQuery); careportalEvents = getDaoCareportalEvents().query(preparedQuery);
preprocessOpenAPSOfflineEvents(careportalEvents); careportalEvents = preprocessOpenAPSOfflineEvents(careportalEvents);
return careportalEvents; return careportalEvents;
} catch (SQLException e) { } catch (SQLException e) {
log.error("Unhandled exception", e); log.error("Unhandled exception", e);
@ -1473,10 +1461,10 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
QueryBuilder<CareportalEvent, Long> queryBuilder = getDaoCareportalEvents().queryBuilder(); QueryBuilder<CareportalEvent, Long> queryBuilder = getDaoCareportalEvents().queryBuilder();
queryBuilder.orderBy("date", ascending); queryBuilder.orderBy("date", ascending);
Where where = queryBuilder.where(); Where where = queryBuilder.where();
where.between("date", start, end); where.between("date", start, end).and().isNotNull("json").and().isNotNull("eventType");
PreparedQuery<CareportalEvent> preparedQuery = queryBuilder.prepare(); PreparedQuery<CareportalEvent> preparedQuery = queryBuilder.prepare();
careportalEvents = getDaoCareportalEvents().query(preparedQuery); careportalEvents = getDaoCareportalEvents().query(preparedQuery);
preprocessOpenAPSOfflineEvents(careportalEvents); careportalEvents = preprocessOpenAPSOfflineEvents(careportalEvents);
return careportalEvents; return careportalEvents;
} catch (SQLException e) { } catch (SQLException e) {
log.error("Unhandled exception", e); log.error("Unhandled exception", e);
@ -1484,14 +1472,16 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
return new ArrayList<>(); return new ArrayList<>();
} }
public void preprocessOpenAPSOfflineEvents(List<CareportalEvent> list) { public List<CareportalEvent> preprocessOpenAPSOfflineEvents(List<CareportalEvent> list) {
OverlappingIntervals offlineEvents = new OverlappingIntervals(); NonOverlappingIntervals offlineEvents = new NonOverlappingIntervals();
List<CareportalEvent> other = new ArrayList<>();
for (int i = 0; i < list.size(); i++) { for (int i = 0; i < list.size(); i++) {
CareportalEvent event = list.get(i); CareportalEvent event = list.get(i);
if (!event.eventType.equals(CareportalEvent.OPENAPSOFFLINE)) continue; if (event.eventType.equals(CareportalEvent.OPENAPSOFFLINE)) offlineEvents.add(event);
offlineEvents.add(event); else other.add(event);
} }
other.addAll(offlineEvents.getList());
return other;
} }
public List<CareportalEvent> getCareportalEventsFromTime(long mills, String type, boolean ascending) { public List<CareportalEvent> getCareportalEventsFromTime(long mills, String type, boolean ascending) {
@ -1500,10 +1490,10 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
QueryBuilder<CareportalEvent, Long> queryBuilder = getDaoCareportalEvents().queryBuilder(); QueryBuilder<CareportalEvent, Long> queryBuilder = getDaoCareportalEvents().queryBuilder();
queryBuilder.orderBy("date", ascending); queryBuilder.orderBy("date", ascending);
Where where = queryBuilder.where(); Where where = queryBuilder.where();
where.ge("date", mills).and().eq("eventType", type); where.ge("date", mills).and().eq("eventType", type).and().isNotNull("json");
PreparedQuery<CareportalEvent> preparedQuery = queryBuilder.prepare(); PreparedQuery<CareportalEvent> preparedQuery = queryBuilder.prepare();
careportalEvents = getDaoCareportalEvents().query(preparedQuery); careportalEvents = getDaoCareportalEvents().query(preparedQuery);
preprocessOpenAPSOfflineEvents(careportalEvents); careportalEvents = preprocessOpenAPSOfflineEvents(careportalEvents);
return careportalEvents; return careportalEvents;
} catch (SQLException e) { } catch (SQLException e) {
log.error("Unhandled exception", e); log.error("Unhandled exception", e);
@ -1516,9 +1506,11 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
List<CareportalEvent> careportalEvents; List<CareportalEvent> careportalEvents;
QueryBuilder<CareportalEvent, Long> queryBuilder = getDaoCareportalEvents().queryBuilder(); QueryBuilder<CareportalEvent, Long> queryBuilder = getDaoCareportalEvents().queryBuilder();
queryBuilder.orderBy("date", ascending); queryBuilder.orderBy("date", ascending);
Where where = queryBuilder.where();
where.isNotNull("json").and().isNotNull("eventType");
PreparedQuery<CareportalEvent> preparedQuery = queryBuilder.prepare(); PreparedQuery<CareportalEvent> preparedQuery = queryBuilder.prepare();
careportalEvents = getDaoCareportalEvents().query(preparedQuery); careportalEvents = getDaoCareportalEvents().query(preparedQuery);
preprocessOpenAPSOfflineEvents(careportalEvents); careportalEvents = preprocessOpenAPSOfflineEvents(careportalEvents);
return careportalEvents; return careportalEvents;
} catch (SQLException e) { } catch (SQLException e) {
log.error("Unhandled exception", e); log.error("Unhandled exception", e);
@ -1603,15 +1595,23 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
// ---------------- ProfileSwitch handling --------------- // ---------------- ProfileSwitch handling ---------------
public List<ProfileSwitch> getProfileSwitchData(boolean ascending) { public List<ProfileSwitch> getProfileSwitchData(long from, boolean ascending) {
try { try {
Dao<ProfileSwitch, Long> daoProfileSwitch = getDaoProfileSwitch(); Dao<ProfileSwitch, Long> daoProfileSwitch = getDaoProfileSwitch();
List<ProfileSwitch> profileSwitches; List<ProfileSwitch> profileSwitches;
QueryBuilder<ProfileSwitch, Long> queryBuilder = daoProfileSwitch.queryBuilder(); QueryBuilder<ProfileSwitch, Long> queryBuilder = daoProfileSwitch.queryBuilder();
queryBuilder.orderBy("date", ascending); queryBuilder.orderBy("date", ascending);
queryBuilder.limit(100L); queryBuilder.limit(100L);
Where where = queryBuilder.where();
where.ge("date", from);
PreparedQuery<ProfileSwitch> preparedQuery = queryBuilder.prepare(); PreparedQuery<ProfileSwitch> preparedQuery = queryBuilder.prepare();
profileSwitches = daoProfileSwitch.query(preparedQuery); profileSwitches = daoProfileSwitch.query(preparedQuery);
//add last one without duration
ProfileSwitch last = getLastProfileSwitchWithoutDuration();
if (last != null) {
if (!profileSwitches.contains(last))
profileSwitches.add(last);
}
return profileSwitches; return profileSwitches;
} catch (SQLException e) { } catch (SQLException e) {
log.error("Unhandled exception", e); log.error("Unhandled exception", e);
@ -1619,6 +1619,28 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
return new ArrayList<>(); return new ArrayList<>();
} }
@Nullable
private ProfileSwitch getLastProfileSwitchWithoutDuration() {
try {
Dao<ProfileSwitch, Long> daoProfileSwitch = getDaoProfileSwitch();
List<ProfileSwitch> profileSwitches;
QueryBuilder<ProfileSwitch, Long> queryBuilder = daoProfileSwitch.queryBuilder();
queryBuilder.orderBy("date", false);
queryBuilder.limit(1L);
Where where = queryBuilder.where();
where.eq("durationInMinutes", 0);
PreparedQuery<ProfileSwitch> preparedQuery = queryBuilder.prepare();
profileSwitches = daoProfileSwitch.query(preparedQuery);
if (profileSwitches.size() > 0)
return profileSwitches.get(0);
else
return null;
} catch (SQLException e) {
log.error("Unhandled exception", e);
}
return null;
}
public List<ProfileSwitch> getProfileSwitchEventsFromTime(long mills, boolean ascending) { public List<ProfileSwitch> getProfileSwitchEventsFromTime(long mills, boolean ascending) {
try { try {
Dao<ProfileSwitch, Long> daoProfileSwitch = getDaoProfileSwitch(); Dao<ProfileSwitch, Long> daoProfileSwitch = getDaoProfileSwitch();

View file

@ -11,6 +11,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import info.nightscout.androidaps.logging.L; import info.nightscout.androidaps.logging.L;
import info.nightscout.androidaps.utils.DateUtil;
/** /**
* Created by mike on 27.02.2016. * Created by mike on 27.02.2016.
@ -40,66 +41,55 @@ public class DbRequest {
} }
// dbAdd // dbAdd
public DbRequest(String action, String collection, String nsClientID, JSONObject data) { public DbRequest(String action, String collection, JSONObject json) {
this.action = action; this.action = action;
this.collection = collection; this.collection = collection;
this.data = data.toString(); this.nsClientID = "" + DateUtil.now();
this.nsClientID = nsClientID; try {
json.put("NSCLIENT_ID", nsClientID);
} catch (JSONException e) {
e.printStackTrace();
}
this.data = json.toString();
this._id = ""; this._id = "";
} }
// dbUpdate, dbUpdateUnset // dbUpdate, dbUpdateUnset
public DbRequest(String action, String collection, String nsClientID, String _id, JSONObject data) { public DbRequest(String action, String collection, String _id, JSONObject json) {
this.action = action; this.action = action;
this.collection = collection; this.collection = collection;
this.data = data.toString(); this.nsClientID = "" + DateUtil.now();
this.nsClientID = nsClientID; try {
json.put("NSCLIENT_ID", nsClientID);
} catch (JSONException e) {
e.printStackTrace();
}
this.data = json.toString();
this._id = _id; this._id = _id;
} }
// dbRemove // dbRemove
public DbRequest(String action, String collection, String nsClientID, String _id) { public DbRequest(String action, String collection,
String _id) {
JSONObject json = new JSONObject();
this.action = action; this.action = action;
this.collection = collection; this.collection = collection;
this.data = new JSONObject().toString(); this.nsClientID = "" + DateUtil.now();
this.nsClientID = nsClientID; try {
json.put("NSCLIENT_ID", nsClientID);
} catch (JSONException e) {
e.printStackTrace();
}
this.data = json.toString();
this._id = _id; this._id = _id;
} }
public String hash() { public String log() {
return Hashing.sha1().hashString(action + collection + _id + data.toString(), Charsets.UTF_8).toString(); return
} "\nnsClientID:" + nsClientID +
"\naction:" + action +
public JSONObject toJSON() { "\ncollection:" + collection +
JSONObject object = new JSONObject(); "\ndata:" + data +
try { "\n_id:" + _id;
object.put("action", action);
object.put("collection", collection);
object.put("data", new JSONObject(data));
if (_id != null) object.put("_id", _id);
if (nsClientID != null) object.put("nsClientID", nsClientID);
} catch (JSONException e) {
log.error("Unhandled exception", e);
}
return object;
}
public static DbRequest fromJSON(JSONObject jsonObject) {
DbRequest result = new DbRequest();
try {
if (jsonObject.has("action"))
result.action = jsonObject.getString("action");
if (jsonObject.has("collection"))
result.collection = jsonObject.getString("collection");
if (jsonObject.has("data"))
result.data = jsonObject.getJSONObject("data").toString();
if (jsonObject.has("_id"))
result._id = jsonObject.getString("_id");
if (jsonObject.has("nsClientID"))
result.nsClientID = jsonObject.getString("nsClientID");
} catch (JSONException e) {
log.error("Unhandled exception", e);
}
return result;
} }
} }

View file

@ -259,11 +259,11 @@ public class ExtendedBolus implements Interval, DataPointWithLabelInterface {
double sensitivityRatio = lastAutosensResult.ratio; double sensitivityRatio = lastAutosensResult.ratio;
double normalTarget = 100; double normalTarget = 100;
if (exercise_mode && isTempTarget && profile.getTarget() >= normalTarget + 5) { if (exercise_mode && isTempTarget && profile.getTargetMgdl() >= normalTarget + 5) {
// w/ target 100, temp target 110 = .89, 120 = 0.8, 140 = 0.67, 160 = .57, and 200 = .44 // w/ target 100, temp target 110 = .89, 120 = 0.8, 140 = 0.67, 160 = .57, and 200 = .44
// e.g.: Sensitivity ratio set to 0.8 based on temp target of 120; Adjusting basal from 1.65 to 1.35; ISF from 58.9 to 73.6 // e.g.: Sensitivity ratio set to 0.8 based on temp target of 120; Adjusting basal from 1.65 to 1.35; ISF from 58.9 to 73.6
double c = half_basal_exercise_target - normalTarget; double c = half_basal_exercise_target - normalTarget;
sensitivityRatio = c / (c + profile.getTarget() - normalTarget); sensitivityRatio = c / (c + profile.getTargetMgdl() - normalTarget);
} }
if (realDuration > 0) { if (realDuration > 0) {
@ -325,8 +325,8 @@ public class ExtendedBolus implements Interval, DataPointWithLabelInterface {
} }
public String toStringMedium() { public String toStringMedium() {
return "E " + DecimalFormatter.to2Decimal(absoluteRate()) + "U/h (" return DecimalFormatter.to2Decimal(absoluteRate()) + "U/h "
+ getRealDuration() + "/" + durationInMinutes + ") "; + getRealDuration() + "/" + durationInMinutes + "'";
} }
public String toStringTotal() { public String toStringTotal() {

View file

@ -6,8 +6,11 @@ import com.j256.ormlite.table.DatabaseTable;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.logging.L; import info.nightscout.androidaps.logging.L;
import info.nightscout.androidaps.plugins.pump.common.utils.DateTimeUtil; import info.nightscout.androidaps.plugins.pump.common.utils.DateTimeUtil;
import info.nightscout.androidaps.utils.DateUtil;
/** /**
* Created by mike on 20.09.2017. * Created by mike on 20.09.2017.
@ -56,4 +59,12 @@ public class TDD {
", total=" + total + ", total=" + total +
']'; ']';
} }
public String toText() {
return MainApp.gs(R.string.tddformat, DateUtil.dateStringShort(date), total, bolus, basal);
}
public String toText(int days) {
return MainApp.gs(R.string.tddformat, String.format("%d ", days) + MainApp.gs(R.string.days), total, bolus, basal);
}
} }

View file

@ -299,11 +299,11 @@ public class TemporaryBasal implements Interval, DbObjectBase {
double sensitivityRatio = lastAutosensResult.ratio; double sensitivityRatio = lastAutosensResult.ratio;
double normalTarget = 100; double normalTarget = 100;
if (exercise_mode && isTempTarget && profile.getTarget() >= normalTarget + 5) { if (exercise_mode && isTempTarget && profile.getTargetMgdl() >= normalTarget + 5) {
// w/ target 100, temp target 110 = .89, 120 = 0.8, 140 = 0.67, 160 = .57, and 200 = .44 // w/ target 100, temp target 110 = .89, 120 = 0.8, 140 = 0.67, 160 = .57, and 200 = .44
// e.g.: Sensitivity ratio set to 0.8 based on temp target of 120; Adjusting basal from 1.65 to 1.35; ISF from 58.9 to 73.6 // e.g.: Sensitivity ratio set to 0.8 based on temp target of 120; Adjusting basal from 1.65 to 1.35; ISF from 58.9 to 73.6
double c = half_basal_exercise_target - normalTarget; double c = half_basal_exercise_target - normalTarget;
sensitivityRatio = c / (c + profile.getTarget() - normalTarget); sensitivityRatio = c / (c + profile.getTargetMgdl() - normalTarget);
} }
if (realDuration > 0) { if (realDuration > 0) {

View file

@ -0,0 +1,159 @@
package info.nightscout.androidaps.dialogs
import android.app.Activity
import android.os.Bundle
import android.os.SystemClock
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.Window
import android.view.WindowManager
import androidx.fragment.app.DialogFragment
import info.nightscout.androidaps.MainApp
import info.nightscout.androidaps.R
import info.nightscout.androidaps.activities.BolusProgressHelperActivity
import info.nightscout.androidaps.events.EventPumpStatusChanged
import info.nightscout.androidaps.logging.L
import info.nightscout.androidaps.plugins.bus.RxBus.toObservable
import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin
import info.nightscout.androidaps.plugins.general.overview.events.EventDismissBolusProgressIfRunning
import info.nightscout.androidaps.plugins.general.overview.events.EventOverviewBolusProgress
import info.nightscout.androidaps.utils.FabricPrivacy
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable
import kotlinx.android.synthetic.main.dialog_bolusprogress.*
import org.slf4j.LoggerFactory
class BolusProgressDialog : DialogFragment() {
private val log = LoggerFactory.getLogger(L.UI)
private val disposable = CompositeDisposable()
companion object {
private val DEFAULT_STATE = MainApp.gs(R.string.waitingforpump)
@JvmField
var bolusEnded = false
@JvmField
var stopPressed = false
}
private var running = true
private var amount = 0.0
private var state: String? = null
private var helpActivity: BolusProgressHelperActivity? = null
fun setInsulin(amount: Double): BolusProgressDialog {
this.amount = amount
bolusEnded = false
return this
}
fun setHelperActivity(activity: BolusProgressHelperActivity): BolusProgressDialog {
helpActivity = activity
return this
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
dialog?.window?.requestFeature(Window.FEATURE_NO_TITLE)
dialog?.window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN)
isCancelable = false
dialog?.setCanceledOnTouchOutside(false)
return inflater.inflate(R.layout.dialog_bolusprogress, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
overview_bolusprogress_title.text = String.format(MainApp.gs(R.string.overview_bolusprogress_goingtodeliver), amount)
overview_bolusprogress_stop.setOnClickListener {
if (L.isEnabled(L.UI)) log.debug("Stop bolus delivery button pressed")
stopPressed = true
overview_bolusprogress_stoppressed.visibility = View.VISIBLE
overview_bolusprogress_stop.visibility = View.INVISIBLE
ConfigBuilderPlugin.getPlugin().commandQueue.cancelAllBoluses()
}
overview_bolusprogress_progressbar.max = 100
state = savedInstanceState?.getString("state", DEFAULT_STATE) ?: DEFAULT_STATE
overview_bolusprogress_status.text = state
stopPressed = false
}
override fun onStart() {
super.onStart()
dialog?.window?.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
}
override fun onResume() {
super.onResume()
if (L.isEnabled(L.UI)) log.debug("onResume")
if (!ConfigBuilderPlugin.getPlugin().commandQueue.bolusInQueue())
bolusEnded = true
if (bolusEnded) dismiss()
else running = true
disposable.add(toObservable(EventPumpStatusChanged::class.java)
.observeOn(AndroidSchedulers.mainThread())
.subscribe({ overview_bolusprogress_status.text = it.getStatus() }) { FabricPrivacy.logException(it) }
)
disposable.add(toObservable(EventDismissBolusProgressIfRunning::class.java)
.observeOn(AndroidSchedulers.mainThread())
.subscribe({ if (running) dismiss() }) { FabricPrivacy.logException(it) }
)
disposable.add(toObservable(EventOverviewBolusProgress::class.java)
.observeOn(AndroidSchedulers.mainThread())
.subscribe({
if (L.isEnabled(L.UI)) log.debug("Status: " + it.status + " Percent: " + it.percent)
overview_bolusprogress_status.text = it.status
overview_bolusprogress_progressbar.progress = it.percent
if (it.percent == 100) {
overview_bolusprogress_stop.visibility = View.INVISIBLE
scheduleDismiss()
}
state = it.status
}) { FabricPrivacy.logException(it) }
)
}
override fun dismiss() {
if (L.isEnabled(L.UI)) log.debug("dismiss")
try {
super.dismiss()
} catch (e: IllegalStateException) {
// dialog not running yet. onResume will try again. Set bolusEnded to make extra
// sure onResume will catch this
bolusEnded = true
log.error("Unhandled exception", e)
}
helpActivity?.finish()
}
override fun onPause() {
super.onPause()
if (L.isEnabled(L.UI)) log.debug("onPause")
running = false
disposable.clear()
}
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
outState.putString("state", state)
}
private fun scheduleDismiss() {
if (L.isEnabled(L.UI)) log.debug("scheduleDismiss")
Thread(Runnable {
SystemClock.sleep(5000)
bolusEnded = true
val activity: Activity? = activity
activity?.runOnUiThread {
if (running) {
if (L.isEnabled(L.UI)) log.debug("executing")
try {
dismiss()
} catch (e: Exception) {
log.error("Unhandled exception", e)
}
}
}
}).start()
}
}

View file

@ -0,0 +1,69 @@
package info.nightscout.androidaps.dialogs
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.google.common.base.Joiner
import info.nightscout.androidaps.Constants
import info.nightscout.androidaps.MainApp
import info.nightscout.androidaps.R
import info.nightscout.androidaps.data.Profile
import info.nightscout.androidaps.plugins.configBuilder.ProfileFunctions
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus
import info.nightscout.androidaps.utils.HtmlHelper
import info.nightscout.androidaps.utils.OKDialog
import info.nightscout.androidaps.utils.XdripCalibrations
import kotlinx.android.synthetic.main.dialog_calibration.*
import kotlinx.android.synthetic.main.okcancel.*
import java.text.DecimalFormat
import java.util.*
class CalibrationDialog : DialogFragmentWithDate() {
override fun onSaveInstanceState(savedInstanceState: Bundle) {
super.onSaveInstanceState(savedInstanceState)
savedInstanceState.putDouble("overview_calibration_bg", overview_calibration_bg.value)
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
onCreateViewGeneral()
return inflater.inflate(R.layout.dialog_calibration, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val units = ProfileFunctions.getSystemUnits()
val bg = Profile.fromMgdlToUnits(GlucoseStatus.getGlucoseStatusData()?.glucose
?: 0.0, units)
if (units == Constants.MMOL)
overview_calibration_bg.setParams(savedInstanceState?.getDouble("overview_calibration_bg")
?: bg, 2.0, 30.0, 0.1, DecimalFormat("0.0"), false, ok)
else
overview_calibration_bg.setParams(savedInstanceState?.getDouble("overview_calibration_bg")
?: bg, 36.0, 500.0, 1.0, DecimalFormat("0"), false, ok)
overview_calibration_units.text = if (units == Constants.MMOL) MainApp.gs(R.string.mmol) else MainApp.gs(R.string.mgdl)
}
override fun submit() :Boolean {
val units = ProfileFunctions.getSystemUnits()
val unitLabel = if (units == Constants.MMOL) MainApp.gs(R.string.mmol) else MainApp.gs(R.string.mgdl)
val actions: LinkedList<String?> = LinkedList()
val bg = overview_calibration_bg.value
actions.add(MainApp.gs(R.string.treatments_wizard_bg_label) + ": " + Profile.toCurrentUnitsString(bg) + " " + unitLabel)
if (bg > 0) {
activity?.let { activity ->
OKDialog.showConfirmation(activity, MainApp.gs(R.string.overview_calibration), HtmlHelper.fromHtml(Joiner.on("<br/>").join(actions)), Runnable {
log.debug("USER ENTRY: CALIBRATION $bg")
XdripCalibrations.confirmAndSendCalibration(bg, context)
})
}
} else
activity?.let { activity ->
OKDialog.show(activity, MainApp.gs(R.string.overview_calibration), MainApp.gs(R.string.no_action_selected))
}
return true
}
}

View file

@ -0,0 +1,228 @@
package info.nightscout.androidaps.dialogs
import android.os.Bundle
import android.text.Editable
import android.text.TextWatcher
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.google.common.base.Joiner
import info.nightscout.androidaps.Constants
import info.nightscout.androidaps.MainApp
import info.nightscout.androidaps.R
import info.nightscout.androidaps.data.Profile
import info.nightscout.androidaps.db.CareportalEvent
import info.nightscout.androidaps.db.DatabaseHelper
import info.nightscout.androidaps.db.Source
import info.nightscout.androidaps.db.TempTarget
import info.nightscout.androidaps.interfaces.Constraint
import info.nightscout.androidaps.plugins.configBuilder.ProfileFunctions
import info.nightscout.androidaps.plugins.general.nsclient.NSUpload
import info.nightscout.androidaps.plugins.treatments.CarbsGenerator
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin
import info.nightscout.androidaps.utils.*
import kotlinx.android.synthetic.main.dialog_carbs.*
import kotlinx.android.synthetic.main.notes.*
import kotlinx.android.synthetic.main.okcancel.*
import java.text.DecimalFormat
import java.util.*
import kotlin.math.max
class CarbsDialog : DialogFragmentWithDate() {
companion object {
private const val FAV1_DEFAULT = 5
private const val FAV2_DEFAULT = 10
private const val FAV3_DEFAULT = 20
}
private val maxCarbs = MainApp.getConstraintChecker().maxCarbsAllowed.value().toDouble()
private val textWatcher: TextWatcher = object : TextWatcher {
override fun afterTextChanged(s: Editable) {
validateInputs()
}
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {}
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {}
}
private fun validateInputs() {
val time = overview_carbs_time.value.toInt()
if (time > 12 * 60 || time < -12 * 60) {
overview_carbs_time.value = 0.0
ToastUtils.showToastInUiThread(MainApp.instance().applicationContext, MainApp.gs(R.string.constraintapllied))
}
if (overview_carbs_duration.value > 10) {
overview_carbs_duration.value = 0.0
ToastUtils.showToastInUiThread(MainApp.instance().applicationContext, MainApp.gs(R.string.constraintapllied))
}
if (overview_carbs_carbs.value.toInt() > maxCarbs) {
overview_carbs_carbs.value = 0.0
ToastUtils.showToastInUiThread(MainApp.instance().applicationContext, MainApp.gs(R.string.carbsconstraintapplied))
}
}
override fun onSaveInstanceState(savedInstanceState: Bundle) {
super.onSaveInstanceState(savedInstanceState)
savedInstanceState.putDouble("overview_carbs_time", overview_carbs_time.value)
savedInstanceState.putDouble("overview_carbs_duration", overview_carbs_duration.value)
savedInstanceState.putDouble("overview_carbs_carbs", overview_carbs_carbs.value)
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
onCreateViewGeneral()
return inflater.inflate(R.layout.dialog_carbs, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
overview_carbs_time.setParams(savedInstanceState?.getDouble("overview_carbs_time")
?: 0.0, -12 * 60.0, 12 * 60.0, 5.0, DecimalFormat("0"), false, ok, textWatcher)
overview_carbs_duration.setParams(savedInstanceState?.getDouble("overview_carbs_duration")
?: 0.0, 0.0, 10.0, 1.0, DecimalFormat("0"), false, ok, textWatcher)
overview_carbs_carbs.setParams(savedInstanceState?.getDouble("overview_carbs_carbs")
?: 0.0, 0.0, maxCarbs, 1.0, DecimalFormat("0"), false, ok, textWatcher)
overview_carbs_plus1.text = toSignedString(SP.getInt(R.string.key_carbs_button_increment_1, FAV1_DEFAULT))
overview_carbs_plus1.setOnClickListener {
overview_carbs_carbs.value = max(0.0, overview_carbs_carbs.value
+ SP.getInt(R.string.key_carbs_button_increment_1, FAV1_DEFAULT))
validateInputs()
}
overview_carbs_plus2.text = toSignedString(SP.getInt(R.string.key_carbs_button_increment_2, FAV2_DEFAULT))
overview_carbs_plus2.setOnClickListener {
overview_carbs_carbs.value = max(0.0, overview_carbs_carbs.value
+ SP.getInt(R.string.key_carbs_button_increment_2, FAV2_DEFAULT))
validateInputs()
}
overview_carbs_plus3.text = toSignedString(SP.getInt(R.string.key_carbs_button_increment_3, FAV3_DEFAULT))
overview_carbs_plus3.setOnClickListener {
overview_carbs_carbs.value = max(0.0, overview_carbs_carbs.value
+ SP.getInt(R.string.key_carbs_button_increment_3, FAV3_DEFAULT))
validateInputs()
}
DatabaseHelper.actualBg()?.let { bgReading ->
if (bgReading.value < 72)
overview_carbs_hypo_tt.setChecked(true)
}
overview_carbs_hypo_tt.setOnClickListener {
overview_carbs_activity_tt.isChecked = false
overview_carbs_eating_soon_tt.isChecked = false
}
overview_carbs_activity_tt.setOnClickListener {
overview_carbs_hypo_tt.isChecked = false
overview_carbs_eating_soon_tt.isChecked = false
}
overview_carbs_eating_soon_tt.setOnClickListener {
overview_carbs_hypo_tt.isChecked = false
overview_carbs_activity_tt.isChecked = false
}
}
private fun toSignedString(value: Int): String {
return if (value > 0) "+$value" else value.toString()
}
override fun submit(): Boolean {
val carbs = overview_carbs_carbs.value.toInt()
val carbsAfterConstraints = MainApp.getConstraintChecker().applyCarbsConstraints(Constraint(carbs)).value()
val units = ProfileFunctions.getSystemUnits()
val activityTTDuration = DefaultValueHelper.determineActivityTTDuration()
val activityTT = DefaultValueHelper.determineActivityTT()
val eatingSoonTTDuration = DefaultValueHelper.determineEatingSoonTTDuration()
val eatingSoonTT = DefaultValueHelper.determineEatingSoonTT()
val hypoTTDuration = DefaultValueHelper.determineHypoTTDuration()
val hypoTT = DefaultValueHelper.determineHypoTT()
val actions: LinkedList<String?> = LinkedList()
val unitLabel = if (units == Constants.MMOL) MainApp.gs(R.string.mmol) else MainApp.gs(R.string.mgdl)
val activitySelected = overview_carbs_activity_tt.isChecked
if (activitySelected)
actions.add(MainApp.gs(R.string.temptargetshort) + ": " + "<font color='" + MainApp.gc(R.color.tempTargetConfirmation) + "'>" + DecimalFormatter.to1Decimal(activityTT) + " " + unitLabel + " (" + activityTTDuration + " " + MainApp.gs(R.string.unit_minute_short) + ")</font>")
val eatingSoonSelected = overview_carbs_eating_soon_tt.isChecked
if (eatingSoonSelected)
actions.add(MainApp.gs(R.string.temptargetshort) + ": " + "<font color='" + MainApp.gc(R.color.tempTargetConfirmation) + "'>" + DecimalFormatter.to1Decimal(eatingSoonTT) + " " + unitLabel + " (" + eatingSoonTTDuration + " " + MainApp.gs(R.string.unit_minute_short) + ")</font>")
val hypoSelected = overview_carbs_hypo_tt.isChecked
if (hypoSelected)
actions.add(MainApp.gs(R.string.temptargetshort) + ": " + "<font color='" + MainApp.gc(R.color.tempTargetConfirmation) + "'>" + DecimalFormatter.to1Decimal(hypoTT) + " " + unitLabel + " (" + hypoTTDuration + " " + MainApp.gs(R.string.unit_minute_short) + ")</font>")
val timeOffset = overview_carbs_time.value.toInt()
val time = eventTime + timeOffset * 1000 * 60
if (timeOffset != 0)
actions.add(MainApp.gs(R.string.time) + ": " + DateUtil.dateAndTimeString(time))
val duration = overview_carbs_duration.value.toInt()
if (duration > 0)
actions.add(MainApp.gs(R.string.duration) + ": " + duration + MainApp.gs(R.string.shorthour))
if (carbsAfterConstraints > 0) {
actions.add(MainApp.gs(R.string.carbs) + ": " + "<font color='" + MainApp.gc(R.color.carbs) + "'>" + MainApp.gs(R.string.format_carbs, carbsAfterConstraints) + "</font>")
if (carbsAfterConstraints != carbs)
actions.add("<font color='" + MainApp.gc(R.color.warning) + "'>" + MainApp.gs(R.string.carbsconstraintapplied) + "</font>")
}
val notes = notes.text.toString()
if (notes.isNotEmpty())
actions.add(MainApp.gs(R.string.careportal_newnstreatment_notes_label) + ": " + notes)
if (eventTimeChanged)
actions.add(MainApp.gs(R.string.time) + ": " + DateUtil.dateAndTimeString(eventTime))
if (carbsAfterConstraints > 0 || activitySelected || eatingSoonSelected || hypoSelected) {
activity?.let { activity ->
OKDialog.showConfirmation(activity, MainApp.gs(R.string.carbs), HtmlHelper.fromHtml(Joiner.on("<br/>").join(actions)), Runnable {
if (activitySelected) {
log.debug("USER ENTRY: TEMPTARGET ACTIVITY $activityTT duration: $activityTTDuration")
val tempTarget = TempTarget()
.date(eventTime)
.duration(activityTTDuration)
.reason(MainApp.gs(R.string.activity))
.source(Source.USER)
.low(Profile.toMgdl(activityTT, ProfileFunctions.getSystemUnits()))
.high(Profile.toMgdl(activityTT, ProfileFunctions.getSystemUnits()))
TreatmentsPlugin.getPlugin().addToHistoryTempTarget(tempTarget)
} else if (eatingSoonSelected) {
log.debug("USER ENTRY: TEMPTARGET EATING SOON $eatingSoonTT duration: $eatingSoonTTDuration")
val tempTarget = TempTarget()
.date(eventTime)
.duration(eatingSoonTTDuration)
.reason(MainApp.gs(R.string.eatingsoon))
.source(Source.USER)
.low(Profile.toMgdl(eatingSoonTT, ProfileFunctions.getSystemUnits()))
.high(Profile.toMgdl(eatingSoonTT, ProfileFunctions.getSystemUnits()))
TreatmentsPlugin.getPlugin().addToHistoryTempTarget(tempTarget)
} else if (hypoSelected) {
log.debug("USER ENTRY: TEMPTARGET HYPO $hypoTT duration: $hypoTTDuration")
val tempTarget = TempTarget()
.date(eventTime)
.duration(hypoTTDuration)
.reason(MainApp.gs(R.string.hypo))
.source(Source.USER)
.low(Profile.toMgdl(hypoTT, ProfileFunctions.getSystemUnits()))
.high(Profile.toMgdl(hypoTT, ProfileFunctions.getSystemUnits()))
TreatmentsPlugin.getPlugin().addToHistoryTempTarget(tempTarget)
}
if (carbsAfterConstraints > 0) {
if (duration == 0) {
log.debug("USER ENTRY: CARBS $carbsAfterConstraints time: $time")
CarbsGenerator.createCarb(carbsAfterConstraints, time, CareportalEvent.CARBCORRECTION, notes)
} else {
log.debug("USER ENTRY: CARBS $carbsAfterConstraints time: $time duration: $duration")
CarbsGenerator.generateCarbs(carbsAfterConstraints, time, duration, notes)
NSUpload.uploadEvent(CareportalEvent.NOTE, time - 2000, MainApp.gs(R.string.generated_ecarbs_note, carbsAfterConstraints, duration, timeOffset))
}
}
}, null)
}
} else
activity?.let { activity ->
OKDialog.show(activity, MainApp.gs(R.string.carbs), MainApp.gs(R.string.no_action_selected))
}
return true
}
}

View file

@ -0,0 +1,190 @@
package info.nightscout.androidaps.dialogs
import android.os.Bundle
import android.text.Editable
import android.text.TextWatcher
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Button
import androidx.annotation.StringRes
import com.google.common.base.Joiner
import info.nightscout.androidaps.Constants
import info.nightscout.androidaps.MainApp
import info.nightscout.androidaps.R
import info.nightscout.androidaps.data.Profile
import info.nightscout.androidaps.db.CareportalEvent
import info.nightscout.androidaps.db.Source
import info.nightscout.androidaps.plugins.configBuilder.ProfileFunctions
import info.nightscout.androidaps.plugins.general.nsclient.NSUpload
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.HtmlHelper
import info.nightscout.androidaps.utils.OKDialog
import info.nightscout.androidaps.utils.SP
import info.nightscout.androidaps.utils.Translator
import kotlinx.android.synthetic.main.dialog_care.*
import kotlinx.android.synthetic.main.notes.*
import kotlinx.android.synthetic.main.okcancel.*
import org.json.JSONObject
import java.text.DecimalFormat
import java.util.*
class CareDialog : DialogFragmentWithDate() {
enum class EventType {
BGCHECK,
SENSOR_INSERT,
BATTERY_CHANGE,
NOTE,
EXERCISE
}
private var options: EventType = EventType.BGCHECK
@StringRes
private var event: Int = R.string.none
fun setOptions(options: EventType, @StringRes event: Int): CareDialog {
this.options = options
this.event = event
return this
}
override fun onSaveInstanceState(savedInstanceState: Bundle) {
super.onSaveInstanceState(savedInstanceState)
savedInstanceState.putDouble("actions_care_bg", actions_care_bg.value)
savedInstanceState.putDouble("actions_care_duration", actions_care_duration.value)
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
onCreateViewGeneral()
return inflater.inflate(R.layout.dialog_care, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
actions_care_icon.setImageResource(when (options) {
EventType.BGCHECK -> R.drawable.icon_cp_bgcheck
EventType.SENSOR_INSERT -> R.drawable.icon_cp_cgm_insert
EventType.BATTERY_CHANGE -> R.drawable.icon_cp_pump_battery
EventType.NOTE -> R.drawable.icon_cp_note
EventType.EXERCISE -> R.drawable.icon_cp_exercise
})
actions_care_title.text = MainApp.gs(when (options) {
EventType.BGCHECK -> R.string.careportal_bgcheck
EventType.SENSOR_INSERT -> R.string.careportal_cgmsensorinsert
EventType.BATTERY_CHANGE -> R.string.careportal_pumpbatterychange
EventType.NOTE -> R.string.careportal_note
EventType.EXERCISE -> R.string.careportal_exercise
})
when (options) {
EventType.BGCHECK -> {
action_care_duration_layout.visibility = View.GONE
}
EventType.SENSOR_INSERT,
EventType.BATTERY_CHANGE -> {
action_care_bg_layout.visibility = View.GONE
actions_care_bgsource.visibility = View.GONE
action_care_duration_layout.visibility = View.GONE
}
EventType.NOTE,
EventType.EXERCISE -> {
action_care_bg_layout.visibility = View.GONE
actions_care_bgsource.visibility = View.GONE
}
}
val bg = Profile.fromMgdlToUnits(GlucoseStatus.getGlucoseStatusData()?.glucose
?: 0.0, ProfileFunctions.getSystemUnits())
val bgTextWatcher: TextWatcher = object : TextWatcher {
override fun afterTextChanged(s: Editable) {}
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {}
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
if (actions_care_sensor.isChecked) actions_care_meter.isChecked = true
}
}
if (ProfileFunctions.getSystemUnits() == Constants.MMOL) {
actions_care_bgunits.text = MainApp.gs(R.string.mmol)
actions_care_bg.setParams(savedInstanceState?.getDouble("actions_care_bg")
?: bg, 2.0, 30.0, 0.1, DecimalFormat("0.0"), false, ok, bgTextWatcher)
} else {
actions_care_bgunits.text = MainApp.gs(R.string.mgdl)
actions_care_bg.setParams(savedInstanceState?.getDouble("actions_care_bg")
?: bg, 36.0, 500.0, 1.0, DecimalFormat("0"), false, ok, bgTextWatcher)
}
actions_care_duration.setParams(savedInstanceState?.getDouble("actions_care_duration")
?: 0.0, 0.0, Constants.MAX_PROFILE_SWITCH_DURATION, 10.0, DecimalFormat("0"), false, ok)
if (options == EventType.NOTE)
notes_layout?.visibility = View.VISIBLE // independent to preferences
}
override fun submit(): Boolean {
val enteredBy = SP.getString("careportal_enteredby", "")
val unitResId = if (ProfileFunctions.getSystemUnits() == Constants.MGDL) R.string.mgdl else R.string.mmol
val json = JSONObject()
val actions: LinkedList<String> = LinkedList()
if (options == EventType.BGCHECK) {
val type =
when {
actions_care_meter.isChecked -> "Finger"
actions_care_sensor.isChecked -> "Sensor"
else -> "Manual"
}
actions.add(MainApp.gs(R.string.careportal_newnstreatment_glucosetype) + ": " + Translator.translate(type))
actions.add(MainApp.gs(R.string.treatments_wizard_bg_label) + ": " + Profile.toCurrentUnitsString(actions_care_bg.value) + " " + MainApp.gs(unitResId))
json.put("glucose", actions_care_bg.value)
json.put("glucoseType", type)
}
if (options == EventType.NOTE || options == EventType.EXERCISE) {
actions.add(MainApp.gs(R.string.careportal_newnstreatment_duration_label) + ": " + MainApp.gs(R.string.format_mins, actions_care_duration.value.toInt()))
json.put("duration", actions_care_duration.value.toInt())
}
val notes = notes.text.toString()
if (notes.isNotEmpty()) {
actions.add(MainApp.gs(R.string.careportal_newnstreatment_notes_label) + ": " + notes)
json.put("notes", notes)
}
eventTime -= eventTime % 1000
if (eventTimeChanged)
actions.add(MainApp.gs(R.string.time) + ": " + DateUtil.dateAndTimeString(eventTime))
json.put("created_at", DateUtil.toISOString(eventTime))
json.put("mills", eventTime)
json.put("eventType", when (options) {
EventType.BGCHECK -> CareportalEvent.BGCHECK
EventType.SENSOR_INSERT -> CareportalEvent.SENSORCHANGE
EventType.BATTERY_CHANGE -> CareportalEvent.PUMPBATTERYCHANGE
EventType.NOTE -> CareportalEvent.NOTE
EventType.EXERCISE -> CareportalEvent.EXERCISE
})
json.put("units", ProfileFunctions.getSystemUnits())
if (enteredBy.isNotEmpty())
json.put("enteredBy", enteredBy)
activity?.let { activity ->
OKDialog.showConfirmation(activity, MainApp.gs(event), HtmlHelper.fromHtml(Joiner.on("<br/>").join(actions)), Runnable {
val careportalEvent = CareportalEvent()
careportalEvent.date = eventTime
careportalEvent.source = Source.USER
careportalEvent.eventType = when (options) {
EventType.BGCHECK -> CareportalEvent.BGCHECK
EventType.SENSOR_INSERT -> CareportalEvent.SENSORCHANGE
EventType.BATTERY_CHANGE -> CareportalEvent.PUMPBATTERYCHANGE
EventType.NOTE -> CareportalEvent.NOTE
EventType.EXERCISE -> CareportalEvent.EXERCISE
}
careportalEvent.json = json.toString()
log.debug("USER ENTRY: CAREPORTAL ${careportalEvent.eventType} json: ${careportalEvent.json}")
MainApp.getDbHelper().createOrUpdate(careportalEvent)
NSUpload.uploadCareportalEntryToNS(json)
}, null)
}
return true
}
}

View file

@ -0,0 +1,124 @@
package info.nightscout.androidaps.dialogs
import android.app.DatePickerDialog
import android.app.TimePickerDialog
import android.os.Bundle
import android.text.format.DateFormat
import android.view.View
import android.view.ViewGroup
import android.view.Window
import android.view.WindowManager
import androidx.fragment.app.DialogFragment
import info.nightscout.androidaps.R
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.SP
import info.nightscout.androidaps.utils.toVisibility
import kotlinx.android.synthetic.main.datetime.*
import kotlinx.android.synthetic.main.notes.*
import kotlinx.android.synthetic.main.okcancel.*
import org.slf4j.LoggerFactory
import java.util.*
abstract class DialogFragmentWithDate : DialogFragment() {
val log = LoggerFactory.getLogger(DialogFragmentWithDate::class.java)
var eventTime = DateUtil.now()
var eventTimeChanged = false
//one shot guards
private var okClicked: Boolean = false
companion object {
private var seconds: Int = (Math.random() * 59.0).toInt()
}
override fun onStart() {
super.onStart()
dialog?.window?.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
}
override fun onSaveInstanceState(savedInstanceState: Bundle) {
super.onSaveInstanceState(savedInstanceState)
savedInstanceState.putLong("eventTime", eventTime)
savedInstanceState.putBoolean("eventTimeChanged", eventTimeChanged)
}
fun onCreateViewGeneral() {
dialog?.window?.requestFeature(Window.FEATURE_NO_TITLE)
dialog?.window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN)
isCancelable = true
dialog?.setCanceledOnTouchOutside(false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
eventTime = savedInstanceState?.getLong("eventTime") ?: DateUtil.now()
eventTimeChanged = savedInstanceState?.getBoolean("eventTimeChanged") ?: false
overview_eventdate?.text = DateUtil.dateString(eventTime)
overview_eventtime?.text = DateUtil.timeString(eventTime)
// create an OnDateSetListener
val dateSetListener = DatePickerDialog.OnDateSetListener { _, year, monthOfYear, dayOfMonth ->
val cal = Calendar.getInstance()
cal.timeInMillis = eventTime
cal.set(Calendar.YEAR, year)
cal.set(Calendar.MONTH, monthOfYear)
cal.set(Calendar.DAY_OF_MONTH, dayOfMonth)
eventTime = cal.timeInMillis
eventTimeChanged = true
overview_eventdate?.text = DateUtil.dateString(eventTime)
}
overview_eventdate?.setOnClickListener {
context?.let {
val cal = Calendar.getInstance()
cal.timeInMillis = eventTime
DatePickerDialog(it, dateSetListener,
cal.get(Calendar.YEAR),
cal.get(Calendar.MONTH),
cal.get(Calendar.DAY_OF_MONTH)
).show()
}
}
// create an OnTimeSetListener
val timeSetListener = TimePickerDialog.OnTimeSetListener { _, hour, minute ->
val cal = Calendar.getInstance()
cal.timeInMillis = eventTime
cal.set(Calendar.HOUR_OF_DAY, hour)
cal.set(Calendar.MINUTE, minute)
cal.set(Calendar.SECOND, seconds++) // randomize seconds to prevent creating record of the same time, if user choose time manually
eventTime = cal.timeInMillis
eventTimeChanged = true
overview_eventtime?.text = DateUtil.timeString(eventTime)
}
overview_eventtime?.setOnClickListener {
context?.let {
val cal = Calendar.getInstance()
cal.timeInMillis = eventTime
TimePickerDialog(it, timeSetListener,
cal.get(Calendar.HOUR_OF_DAY),
cal.get(Calendar.MINUTE),
DateFormat.is24HourFormat(context)
).show()
}
}
notes_layout?.visibility = SP.getBoolean(R.string.key_show_notes_entry_dialogs, false).toVisibility()
ok.setOnClickListener {
synchronized(okClicked) {
if (okClicked) {
log.debug("guarding: ok already clicked")
} else {
okClicked = true
if (submit()) dismiss()
else okClicked = false
}
}
}
cancel.setOnClickListener { dismiss() }
}
abstract fun submit(): Boolean
}

View file

@ -1,5 +1,4 @@
package info.nightscout.androidaps.plugins.general.overview.dialogs package info.nightscout.androidaps.dialogs
import android.content.ClipData import android.content.ClipData
import android.content.ClipboardManager import android.content.ClipboardManager
@ -10,11 +9,14 @@ import android.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.view.Window
import android.view.WindowManager
import androidx.fragment.app.DialogFragment import androidx.fragment.app.DialogFragment
import info.nightscout.androidaps.MainApp import info.nightscout.androidaps.MainApp
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.activities.ErrorHelperActivity
import info.nightscout.androidaps.services.AlarmSoundService import info.nightscout.androidaps.services.AlarmSoundService
import kotlinx.android.synthetic.main.overview_error_dialog.* import kotlinx.android.synthetic.main.dialog_error.*
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
import java.util.* import java.util.*
@ -29,26 +31,30 @@ class ErrorDialog : DialogFragment() {
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? { savedInstanceState: Bundle?): View? {
dialog?.setTitle(title) dialog?.window?.requestFeature(Window.FEATURE_NO_TITLE)
isCancelable = false dialog?.window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN)
isCancelable = true
dialog?.setCanceledOnTouchOutside(false)
savedInstanceState?.let { bundle -> savedInstanceState?.let { bundle ->
bundle.getString("status")?.let { status = it } bundle.getString("status")?.let { status = it }
bundle.getString("title")?.let { title = it } bundle.getString("title")?.let { title = it }
sound = bundle.getInt("sound", R.raw.error) sound = bundle.getInt("sound", R.raw.error)
} }
return inflater.inflate(R.layout.overview_error_dialog, container, false) log.debug("Error dialog displayed")
return inflater.inflate(R.layout.dialog_error, container, false)
} }
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
error_title.text = title
overview_error_ok.setOnClickListener { overview_error_ok.setOnClickListener {
log.debug("Error dialog ok button pressed") log.debug("USER ENTRY: Error dialog ok button pressed")
dismiss() dismiss()
} }
overview_error_mute.setOnClickListener { overview_error_mute.setOnClickListener {
log.debug("Error dialog mute button pressed") log.debug("USER ENTRY: Error dialog mute button pressed")
stopAlarm() stopAlarm()
} }
copyToClipboard() copyToClipboard()
@ -70,9 +76,13 @@ class ErrorDialog : DialogFragment() {
bundle.putInt("sound", sound) bundle.putInt("sound", sound)
} }
override fun onStart() {
super.onStart()
dialog?.window?.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
}
override fun onResume() { override fun onResume() {
super.onResume() super.onResume()
dialog?.window?.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
overview_error_status.text = status overview_error_status.text = status
} }
@ -95,5 +105,5 @@ class ErrorDialog : DialogFragment() {
} }
private fun stopAlarm() = private fun stopAlarm() =
MainApp.instance().stopService(Intent(MainApp.instance().applicationContext, AlarmSoundService::class.java)) MainApp.instance().stopService(Intent(MainApp.instance().applicationContext, AlarmSoundService::class.java))
} }

View file

@ -0,0 +1,83 @@
package info.nightscout.androidaps.dialogs
import android.content.Intent
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.google.common.base.Joiner
import info.nightscout.androidaps.MainApp
import info.nightscout.androidaps.R
import info.nightscout.androidaps.activities.ErrorHelperActivity
import info.nightscout.androidaps.interfaces.Constraint
import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin
import info.nightscout.androidaps.queue.Callback
import info.nightscout.androidaps.utils.HtmlHelper
import info.nightscout.androidaps.utils.OKDialog
import info.nightscout.androidaps.utils.SafeParse
import kotlinx.android.synthetic.main.dialog_extendedbolus.*
import kotlinx.android.synthetic.main.okcancel.*
import java.text.DecimalFormat
import java.util.*
import kotlin.math.abs
class ExtendedBolusDialog : DialogFragmentWithDate() {
override fun onSaveInstanceState(savedInstanceState: Bundle) {
super.onSaveInstanceState(savedInstanceState)
savedInstanceState.putDouble("actions_extendedbolus_insulin", actions_extendedbolus_insulin.value)
savedInstanceState.putDouble("actions_extendedbolus_duration", actions_extendedbolus_duration.value)
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
onCreateViewGeneral()
return inflater.inflate(R.layout.dialog_extendedbolus, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val pumpDescription = ConfigBuilderPlugin.getPlugin().activePump?.pumpDescription ?: return
val maxInsulin = MainApp.getConstraintChecker().maxExtendedBolusAllowed.value()
val extendedStep = pumpDescription.extendedBolusStep
actions_extendedbolus_insulin.setParams(savedInstanceState?.getDouble("actions_extendedbolus_insulin")
?: extendedStep, extendedStep, maxInsulin, extendedStep, DecimalFormat("0.00"), false, ok)
val extendedDurationStep = pumpDescription.extendedBolusDurationStep
val extendedMaxDuration = pumpDescription.extendedBolusMaxDuration
actions_extendedbolus_duration.setParams(savedInstanceState?.getDouble("actions_extendedbolus_duration")
?: extendedDurationStep, extendedDurationStep, extendedMaxDuration, extendedDurationStep, DecimalFormat("0"), false, ok)
}
override fun submit(): Boolean {
val insulin = SafeParse.stringToDouble(actions_extendedbolus_insulin.text)
val durationInMinutes = SafeParse.stringToInt(actions_extendedbolus_duration.text)
val actions: LinkedList<String> = LinkedList()
val insulinAfterConstraint = MainApp.getConstraintChecker().applyExtendedBolusConstraints(Constraint(insulin)).value()
actions.add(MainApp.gs(R.string.formatinsulinunits, insulinAfterConstraint))
actions.add(MainApp.gs(R.string.duration) + ": " + MainApp.gs(R.string.format_mins, durationInMinutes))
if (abs(insulinAfterConstraint - insulin) > 0.01)
actions.add("<font color='" + MainApp.gc(R.color.warning) + "'>" + MainApp.gs(R.string.constraintapllied) + "</font>")
activity?.let { activity ->
OKDialog.showConfirmation(activity, MainApp.gs(R.string.extended_bolus), HtmlHelper.fromHtml(Joiner.on("<br/>").join(actions)), Runnable {
log.debug("USER ENTRY: EXTENDED BOLUS $insulinAfterConstraint duration: $durationInMinutes")
ConfigBuilderPlugin.getPlugin().commandQueue.extendedBolus(insulinAfterConstraint, durationInMinutes, object : Callback() {
override fun run() {
if (!result.success) {
val i = Intent(MainApp.instance(), ErrorHelperActivity::class.java)
i.putExtra("soundid", R.raw.boluserror)
i.putExtra("status", result.comment)
i.putExtra("title", MainApp.gs(R.string.treatmentdeliveryerror))
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
MainApp.instance().startActivity(i)
}
}
})
}, null)
}
return true
}
}

View file

@ -0,0 +1,172 @@
package info.nightscout.androidaps.dialogs
import android.content.Intent
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.google.common.base.Joiner
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.db.CareportalEvent
import info.nightscout.androidaps.db.Source
import info.nightscout.androidaps.interfaces.Constraint
import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin
import info.nightscout.androidaps.plugins.general.nsclient.NSUpload
import info.nightscout.androidaps.queue.Callback
import info.nightscout.androidaps.utils.*
import kotlinx.android.synthetic.main.dialog_fill.*
import kotlinx.android.synthetic.main.notes.*
import kotlinx.android.synthetic.main.okcancel.*
import org.json.JSONException
import org.json.JSONObject
import java.util.*
import kotlin.math.abs
class FillDialog : DialogFragmentWithDate() {
override fun onSaveInstanceState(savedInstanceState: Bundle) {
super.onSaveInstanceState(savedInstanceState)
savedInstanceState.putDouble("fill_insulinamount", fill_insulinamount.value)
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
onCreateViewGeneral()
return inflater.inflate(R.layout.dialog_fill, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val maxInsulin = MainApp.getConstraintChecker().maxBolusAllowed.value()
val bolusStep = ConfigBuilderPlugin.getPlugin().activePump!!.pumpDescription.bolusStep
fill_insulinamount.setParams(savedInstanceState?.getDouble("fill_insulinamount")
?: 0.0, 0.0, maxInsulin, bolusStep, DecimalFormatter.pumpSupportedBolusFormat(), true, ok)
val amount1 = SP.getDouble("fill_button1", 0.3)
if (amount1 > 0) {
fill_preset_button1.visibility = View.VISIBLE
fill_preset_button1.text = DecimalFormatter.toPumpSupportedBolus(amount1) // + "U");
fill_preset_button1.setOnClickListener { fill_insulinamount.value = amount1 }
} else {
fill_preset_button1.visibility = View.GONE
}
val amount2 = SP.getDouble("fill_button2", 0.0)
if (amount2 > 0) {
fill_preset_button2.visibility = View.VISIBLE
fill_preset_button2.text = DecimalFormatter.toPumpSupportedBolus(amount2) // + "U");
fill_preset_button2.setOnClickListener { fill_insulinamount.value = amount2 }
} else {
fill_preset_button2.visibility = View.GONE
}
val amount3 = SP.getDouble("fill_button3", 0.0)
if (amount3 > 0) {
fill_preset_button3.visibility = View.VISIBLE
fill_preset_button3.text = DecimalFormatter.toPumpSupportedBolus(amount3) // + "U");
fill_preset_button3.setOnClickListener { fill_insulinamount.value = amount3 }
} else {
fill_preset_button3.visibility = View.GONE
}
}
override fun submit(): Boolean {
val insulin = SafeParse.stringToDouble(fill_insulinamount.text)
val actions: LinkedList<String?> = LinkedList()
val insulinAfterConstraints = MainApp.getConstraintChecker().applyBolusConstraints(Constraint(insulin)).value()
if (insulinAfterConstraints > 0) {
actions.add(MainApp.gs(R.string.fillwarning))
actions.add("")
actions.add(MainApp.gs(R.string.bolus) + ": " + "<font color='" + MainApp.gc(R.color.colorInsulinButton) + "'>" + DecimalFormatter.toPumpSupportedBolus(insulinAfterConstraints) + MainApp.gs(R.string.insulin_unit_shortname) + "</font>")
if (abs(insulinAfterConstraints - insulin) > 0.01)
actions.add(MainApp.gs(R.string.bolusconstraintappliedwarning, MainApp.gc(R.color.warning), insulin, insulinAfterConstraints))
}
val siteChange = fill_catheter_change.isChecked
if (siteChange)
actions.add("" + "<font color='" + MainApp.gc(R.color.actionsConfirm) + "'>" + MainApp.gs(R.string.record_pump_site_change) + "</font>")
val insulinChange = fill_cartridge_change.isChecked
if (insulinChange)
actions.add("" + "<font color='" + MainApp.gc(R.color.actionsConfirm) + "'>" + MainApp.gs(R.string.record_insulin_cartridge_change) + "</font>")
val notes = notes.text.toString()
if (notes.isNotEmpty())
actions.add(MainApp.gs(R.string.careportal_newnstreatment_notes_label) + ": " + notes)
eventTime -= eventTime % 1000
if (eventTimeChanged)
actions.add(MainApp.gs(R.string.time) + ": " + DateUtil.dateAndTimeString(eventTime))
if (insulinAfterConstraints > 0 || fill_catheter_change.isChecked || fill_cartridge_change.isChecked) {
activity?.let { activity ->
OKDialog.showConfirmation(activity, MainApp.gs(R.string.primefill), HtmlHelper.fromHtml(Joiner.on("<br/>").join(actions)), Runnable {
if (insulinAfterConstraints > 0) {
log.debug("USER ENTRY: PRIME BOLUS $insulinAfterConstraints")
requestPrimeBolus(insulinAfterConstraints, notes)
}
if (siteChange) {
log.debug("USER ENTRY: SITE CHANGE")
generateCareportalEvent(CareportalEvent.SITECHANGE, eventTime, notes)
}
if (insulinChange) {
// add a second for case of both checked
log.debug("USER ENTRY: INSULIN CHANGE")
generateCareportalEvent(CareportalEvent.INSULINCHANGE, eventTime + 1000, notes)
}
}, null)
}
} else {
activity?.let { activity ->
OKDialog.show(activity, MainApp.gs(R.string.primefill), MainApp.gs(R.string.no_action_selected))
}
}
dismiss()
return true
}
private fun requestPrimeBolus(insulin: Double, notes: String) {
val detailedBolusInfo = DetailedBolusInfo()
detailedBolusInfo.insulin = insulin
detailedBolusInfo.context = context
detailedBolusInfo.source = Source.USER
detailedBolusInfo.isValid = false // do not count it in IOB (for pump history)
detailedBolusInfo.notes = notes
ConfigBuilderPlugin.getPlugin().commandQueue.bolus(detailedBolusInfo, object : Callback() {
override fun run() {
if (!result.success) {
val i = Intent(MainApp.instance(), ErrorHelperActivity::class.java)
i.putExtra("soundid", R.raw.boluserror)
i.putExtra("status", result.comment)
i.putExtra("title", MainApp.gs(R.string.treatmentdeliveryerror))
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
MainApp.instance().startActivity(i)
}
}
})
}
private fun generateCareportalEvent(eventType: String, time: Long, notes: String) {
val careportalEvent = CareportalEvent()
careportalEvent.source = Source.USER
careportalEvent.date = time
careportalEvent.json = generateJson(eventType, time, notes).toString()
careportalEvent.eventType = eventType
MainApp.getDbHelper().createOrUpdate(careportalEvent)
NSUpload.uploadEvent(eventType, time, notes)
}
private fun generateJson(careportalEvent: String, time: Long, notes: String): JSONObject {
val data = JSONObject()
try {
data.put("eventType", careportalEvent)
data.put("created_at", DateUtil.toISOString(time))
data.put("mills", time)
data.put("enteredBy", SP.getString("careportal_enteredby", MainApp.gs(R.string.app_name)))
if (notes.isNotEmpty()) data.put("notes", notes)
} catch (ignored: JSONException) {
}
return data
}
}

View file

@ -0,0 +1,196 @@
package info.nightscout.androidaps.dialogs
import android.content.Intent
import android.os.Bundle
import android.text.Editable
import android.text.TextWatcher
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.google.common.base.Joiner
import info.nightscout.androidaps.Constants
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.db.CareportalEvent
import info.nightscout.androidaps.db.Source
import info.nightscout.androidaps.db.TempTarget
import info.nightscout.androidaps.interfaces.Constraint
import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin
import info.nightscout.androidaps.plugins.configBuilder.ProfileFunctions
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin
import info.nightscout.androidaps.queue.Callback
import info.nightscout.androidaps.utils.*
import kotlinx.android.synthetic.main.dialog_insulin.*
import kotlinx.android.synthetic.main.notes.*
import kotlinx.android.synthetic.main.okcancel.*
import java.text.DecimalFormat
import java.util.*
import kotlin.math.abs
import kotlin.math.max
class InsulinDialog : DialogFragmentWithDate() {
companion object {
private const val PLUS1_DEFAULT = 0.5
private const val PLUS2_DEFAULT = 1.0
private const val PLUS3_DEFAULT = 2.0
}
private val maxInsulin = MainApp.getConstraintChecker().maxBolusAllowed.value()
private val textWatcher: TextWatcher = object : TextWatcher {
override fun afterTextChanged(s: Editable) {
validateInputs()
}
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {}
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {}
}
private fun validateInputs() {
if (abs(overview_insulin_time.value.toInt()) > 12 * 60) {
overview_insulin_time.value = 0.0
ToastUtils.showToastInUiThread(MainApp.instance().applicationContext, MainApp.gs(R.string.constraintapllied))
}
if (overview_insulin_amount.value > maxInsulin) {
overview_insulin_amount.value = 0.0
ToastUtils.showToastInUiThread(MainApp.instance().applicationContext, MainApp.gs(R.string.bolusconstraintapplied))
}
}
override fun onSaveInstanceState(savedInstanceState: Bundle) {
super.onSaveInstanceState(savedInstanceState)
savedInstanceState.putDouble("overview_insulin_time", overview_insulin_time.value)
savedInstanceState.putDouble("overview_insulin_amount", overview_insulin_amount.value)
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
onCreateViewGeneral()
return inflater.inflate(R.layout.dialog_insulin, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
overview_insulin_time.setParams(savedInstanceState?.getDouble("overview_insulin_time")
?: 0.0, -12 * 60.0, 12 * 60.0, 5.0, DecimalFormat("0"), false, ok, textWatcher)
overview_insulin_amount.setParams(savedInstanceState?.getDouble("overview_insulin_amount")
?: 0.0, 0.0, maxInsulin, ConfigBuilderPlugin.getPlugin().activePump!!.pumpDescription.bolusStep, DecimalFormatter.pumpSupportedBolusFormat(), false, ok, textWatcher)
overview_insulin_plus05.text = toSignedString(SP.getDouble(MainApp.gs(R.string.key_insulin_button_increment_1), PLUS1_DEFAULT))
overview_insulin_plus05.setOnClickListener {
overview_insulin_amount.value = max(0.0, overview_insulin_amount.value
+ SP.getDouble(MainApp.gs(R.string.key_insulin_button_increment_1), PLUS1_DEFAULT))
validateInputs()
}
overview_insulin_plus10.text = toSignedString(SP.getDouble(MainApp.gs(R.string.key_insulin_button_increment_2), PLUS2_DEFAULT))
overview_insulin_plus10.setOnClickListener {
overview_insulin_amount.value = max(0.0, overview_insulin_amount.value
+ SP.getDouble(MainApp.gs(R.string.key_insulin_button_increment_2), PLUS2_DEFAULT))
validateInputs()
}
overview_insulin_plus20.text = toSignedString(SP.getDouble(MainApp.gs(R.string.key_insulin_button_increment_3), PLUS3_DEFAULT))
overview_insulin_plus20.setOnClickListener {
overview_insulin_amount.value = Math.max(0.0, overview_insulin_amount.value
+ SP.getDouble(MainApp.gs(R.string.key_insulin_button_increment_3), PLUS3_DEFAULT))
validateInputs()
}
overview_insulin_time_layout.visibility = View.GONE
overview_insulin_record_only.setOnCheckedChangeListener { _, isChecked: Boolean ->
overview_insulin_time_layout.visibility = isChecked.toVisibility()
}
}
private fun toSignedString(value: Double): String {
val formatted = DecimalFormatter.toPumpSupportedBolus(value)
return if (value > 0) "+$formatted" else formatted
}
override fun submit(): Boolean {
val pumpDescription = ConfigBuilderPlugin.getPlugin().activePump?.pumpDescription
?: return false
val insulin = SafeParse.stringToDouble(overview_insulin_amount.text)
val insulinAfterConstraints = MainApp.getConstraintChecker().applyBolusConstraints(Constraint(insulin)).value()
val actions: LinkedList<String?> = LinkedList()
val units = ProfileFunctions.getSystemUnits()
val unitLabel = if (units == Constants.MMOL) MainApp.gs(R.string.mmol) else MainApp.gs(R.string.mgdl)
val recordOnlyChecked = overview_insulin_record_only.isChecked
val eatingSoonChecked = overview_insulin_start_eating_soon_tt.isChecked
if (insulinAfterConstraints > 0) {
actions.add(MainApp.gs(R.string.bolus) + ": " + "<font color='" + MainApp.gc(R.color.bolus) + "'>" + DecimalFormatter.toPumpSupportedBolus(insulinAfterConstraints) + MainApp.gs(R.string.insulin_unit_shortname) + "</font>")
if (recordOnlyChecked)
actions.add("<font color='" + MainApp.gc(R.color.warning) + "'>" + MainApp.gs(R.string.bolusrecordedonly) + "</font>")
if (abs(insulinAfterConstraints - insulin) > pumpDescription.pumpType.determineCorrectBolusStepSize(insulinAfterConstraints))
actions.add(MainApp.gs(R.string.bolusconstraintappliedwarning, MainApp.gc(R.color.warning), insulin, insulinAfterConstraints))
}
val eatingSoonTTDuration = DefaultValueHelper.determineEatingSoonTTDuration()
val eatingSoonTT = DefaultValueHelper.determineEatingSoonTT()
if (eatingSoonChecked)
actions.add(MainApp.gs(R.string.temptargetshort) + ": " + "<font color='" + MainApp.gc(R.color.tempTargetConfirmation) + "'>" + DecimalFormatter.to1Decimal(eatingSoonTT) + " " + unitLabel + " (" + eatingSoonTTDuration + " " + MainApp.gs(R.string.unit_minute_short) + ")</font>")
val timeOffset = overview_insulin_time.value.toInt()
val time = DateUtil.now() + T.mins(timeOffset.toLong()).msecs()
if (timeOffset != 0)
actions.add(MainApp.gs(R.string.time) + ": " + DateUtil.dateAndTimeString(time))
val notes = notes.text.toString()
if (notes.isNotEmpty())
actions.add(MainApp.gs(R.string.careportal_newnstreatment_notes_label) + ": " + notes)
if (insulinAfterConstraints > 0 || eatingSoonChecked) {
activity?.let { activity ->
OKDialog.showConfirmation(activity, MainApp.gs(R.string.bolus), HtmlHelper.fromHtml(Joiner.on("<br/>").join(actions)), Runnable {
if (eatingSoonChecked) {
log.debug("USER ENTRY: TEMPTARGET EATING SOON $eatingSoonTT duration: $eatingSoonTTDuration")
val tempTarget = TempTarget()
.date(System.currentTimeMillis())
.duration(eatingSoonTTDuration)
.reason(MainApp.gs(R.string.eatingsoon))
.source(Source.USER)
.low(Profile.toMgdl(eatingSoonTT, ProfileFunctions.getSystemUnits()))
.high(Profile.toMgdl(eatingSoonTT, ProfileFunctions.getSystemUnits()))
TreatmentsPlugin.getPlugin().addToHistoryTempTarget(tempTarget)
}
if (insulinAfterConstraints > 0) {
val detailedBolusInfo = DetailedBolusInfo()
detailedBolusInfo.eventType = CareportalEvent.CORRECTIONBOLUS
detailedBolusInfo.insulin = insulinAfterConstraints
detailedBolusInfo.context = context
detailedBolusInfo.source = Source.USER
detailedBolusInfo.notes = notes
if (recordOnlyChecked) {
log.debug("USER ENTRY: BOLUS RECORD ONLY $insulinAfterConstraints")
detailedBolusInfo.date = time
TreatmentsPlugin.getPlugin().addToHistoryTreatment(detailedBolusInfo, false)
} else {
log.debug("USER ENTRY: BOLUS $insulinAfterConstraints")
detailedBolusInfo.date = DateUtil.now()
ConfigBuilderPlugin.getPlugin().commandQueue.bolus(detailedBolusInfo, object : Callback() {
override fun run() {
if (!result.success) {
val i = Intent(MainApp.instance(), ErrorHelperActivity::class.java)
i.putExtra("soundid", R.raw.boluserror)
i.putExtra("status", result.comment)
i.putExtra("title", MainApp.gs(R.string.treatmentdeliveryerror))
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
MainApp.instance().startActivity(i)
}
}
})
}
}
})
}
} else
activity?.let { activity ->
OKDialog.show(activity, MainApp.gs(R.string.bolus), MainApp.gs(R.string.no_action_selected))
}
return true
}
}

View file

@ -0,0 +1,106 @@
package info.nightscout.androidaps.dialogs
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ArrayAdapter
import com.google.common.base.Joiner
import info.nightscout.androidaps.Constants
import info.nightscout.androidaps.MainApp
import info.nightscout.androidaps.R
import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin
import info.nightscout.androidaps.plugins.configBuilder.ProfileFunctions
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.HtmlHelper
import info.nightscout.androidaps.utils.OKDialog
import kotlinx.android.synthetic.main.dialog_profileswitch.*
import kotlinx.android.synthetic.main.notes.*
import kotlinx.android.synthetic.main.okcancel.*
import java.text.DecimalFormat
import java.util.*
class ProfileSwitchDialog : DialogFragmentWithDate() {
override fun onSaveInstanceState(savedInstanceState: Bundle) {
super.onSaveInstanceState(savedInstanceState)
savedInstanceState.putDouble("overview_profileswitch_duration", overview_profileswitch_duration.value)
savedInstanceState.putDouble("overview_profileswitch_percentage", overview_profileswitch_percentage.value)
savedInstanceState.putDouble("overview_profileswitch_timeshift", overview_profileswitch_timeshift.value)
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
onCreateViewGeneral()
return inflater.inflate(R.layout.dialog_profileswitch, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
overview_profileswitch_duration.setParams(savedInstanceState?.getDouble("overview_profileswitch_duration")
?: 0.0, 0.0, Constants.MAX_PROFILE_SWITCH_DURATION, 10.0, DecimalFormat("0"), false, ok)
overview_profileswitch_percentage.setParams(savedInstanceState?.getDouble("overview_profileswitch_percentage")
?: 100.0, Constants.CPP_MIN_PERCENTAGE.toDouble(), Constants.CPP_MAX_PERCENTAGE.toDouble(), 1.0, DecimalFormat("0"), false, ok)
overview_profileswitch_timeshift.setParams(savedInstanceState?.getDouble("overview_profileswitch_timeshift")
?: 0.0, Constants.CPP_MIN_TIMESHIFT.toDouble(), Constants.CPP_MAX_TIMESHIFT.toDouble(), 1.0, DecimalFormat("0"), false, ok)
// profile
context?.let { context ->
val profileStore = ConfigBuilderPlugin.getPlugin().activeProfileInterface?.profile
?: return
val profileList = profileStore.getProfileList()
val adapter = ArrayAdapter(context, R.layout.spinner_centered, profileList)
overview_profileswitch_profile.adapter = adapter
// set selected to actual profile
for (p in profileList.indices)
if (profileList[p] == ProfileFunctions.getInstance().getProfileName(false))
overview_profileswitch_profile.setSelection(p)
} ?: return
TreatmentsPlugin.getPlugin().getProfileSwitchFromHistory(DateUtil.now())?.let { ps ->
if (ps.isCPP) {
overview_profileswitch_reuselayout.visibility = View.VISIBLE
overview_profileswitch_reusebutton.text = MainApp.gs(R.string.reuse) + " " + ps.percentage + "% " + ps.timeshift + "h"
overview_profileswitch_reusebutton.setOnClickListener {
overview_profileswitch_percentage.value = ps.percentage.toDouble()
overview_profileswitch_timeshift.value = ps.timeshift.toDouble()
}
} else {
overview_profileswitch_reuselayout.visibility = View.GONE
}
}
}
override fun submit(): Boolean {
val profileStore = ConfigBuilderPlugin.getPlugin().activeProfileInterface?.profile
?: return false
val actions: LinkedList<String> = LinkedList()
val duration = overview_profileswitch_duration.value
if (duration > 0)
actions.add(MainApp.gs(R.string.duration) + ": " + MainApp.gs(R.string.format_hours, duration))
val profile = overview_profileswitch_profile.selectedItem.toString()
actions.add(MainApp.gs(R.string.profile) + ": " + profile)
val percent = overview_profileswitch_percentage.value.toInt()
if (percent != 100)
actions.add(MainApp.gs(R.string.percent) + ": " + percent + "%")
val timeShift = overview_profileswitch_timeshift.value.toInt()
if (timeShift != 0)
actions.add(MainApp.gs(R.string.careportal_newnstreatment_timeshift_label) + ": " + MainApp.gs(R.string.format_hours, timeShift.toDouble()))
val notes = notes.text.toString()
if (notes.isNotEmpty())
actions.add(MainApp.gs(R.string.careportal_newnstreatment_notes_label) + ": " + notes)
if (eventTimeChanged)
actions.add(MainApp.gs(R.string.time) + ": " + DateUtil.dateAndTimeString(eventTime))
activity?.let { activity ->
OKDialog.showConfirmation(activity, MainApp.gs(R.string.careportal_profileswitch), HtmlHelper.fromHtml(Joiner.on("<br/>").join(actions)), Runnable {
log.debug("USER ENTRY: PROFILE SWITCH $profile percent: $percent timeshift: $timeShift duration: $duration")
ProfileFunctions.doProfileSwitch(profileStore, profile, duration.toInt(), percent, timeShift, eventTime)
})
}
return true
}
}

View file

@ -1,29 +1,34 @@
package info.nightscout.androidaps.plugins.treatments.fragments package info.nightscout.androidaps.dialogs
import android.os.Bundle import android.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.view.Window
import android.view.WindowManager
import androidx.fragment.app.DialogFragment import androidx.fragment.app.DialogFragment
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.data.Profile import info.nightscout.androidaps.data.Profile
import info.nightscout.androidaps.interfaces.ProfileInterface
import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin
import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.DateUtil
import kotlinx.android.synthetic.main.close.* import kotlinx.android.synthetic.main.close.*
import kotlinx.android.synthetic.main.profileviewer_fragment.* import kotlinx.android.synthetic.main.dialog_profileviewer.*
import org.json.JSONObject
class ProfileViewerDialog : DialogFragment() { class ProfileViewerDialog : DialogFragment() {
private var time: Long = 0 private var time: Long = 0
enum class Mode(val i: Int) { enum class Mode(val i: Int) {
RUNNING_PROFILE(1), RUNNING_PROFILE(1),
PUMP_PROFILE(2) CUSTOM_PROFILE(2)
} }
private var mode: Mode = Mode.RUNNING_PROFILE; private var mode: Mode = Mode.RUNNING_PROFILE
private var customProfileJson: String = ""
private var customProfileName: String = ""
private var customProfileUnits: String = Constants.MGDL
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? { savedInstanceState: Bundle?): View? {
@ -31,19 +36,23 @@ class ProfileViewerDialog : DialogFragment() {
(savedInstanceState ?: arguments)?.let { bundle -> (savedInstanceState ?: arguments)?.let { bundle ->
time = bundle.getLong("time", 0) time = bundle.getLong("time", 0)
mode = Mode.values()[bundle.getInt("mode", Mode.RUNNING_PROFILE.ordinal)] mode = Mode.values()[bundle.getInt("mode", Mode.RUNNING_PROFILE.ordinal)]
customProfileJson = bundle.getString("customProfile", "")
customProfileUnits = bundle.getString("customProfileUnits", Constants.MGDL)
customProfileName = bundle.getString("customProfileName", "")
} }
return inflater.inflate(R.layout.profileviewer_fragment, container, false) dialog?.window?.requestFeature(Window.FEATURE_NO_TITLE)
dialog?.window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN)
isCancelable = true
dialog?.setCanceledOnTouchOutside(false)
return inflater.inflate(R.layout.dialog_profileviewer, container, false)
} }
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
close.setOnClickListener { dismiss() } close.setOnClickListener { dismiss() }
profileview_reload.setOnClickListener {
ConfigBuilderPlugin.getPlugin().commandQueue.readStatus("ProfileViewDialog", null)
dismiss()
}
val profile: Profile? val profile: Profile?
val profileName: String? val profileName: String?
@ -53,15 +62,14 @@ class ProfileViewerDialog : DialogFragment() {
profile = TreatmentsPlugin.getPlugin().getProfileSwitchFromHistory(time)?.profileObject profile = TreatmentsPlugin.getPlugin().getProfileSwitchFromHistory(time)?.profileObject
profileName = TreatmentsPlugin.getPlugin().getProfileSwitchFromHistory(time)?.customizedName profileName = TreatmentsPlugin.getPlugin().getProfileSwitchFromHistory(time)?.customizedName
date = DateUtil.dateAndTimeString(TreatmentsPlugin.getPlugin().getProfileSwitchFromHistory(time)?.date date = DateUtil.dateAndTimeString(TreatmentsPlugin.getPlugin().getProfileSwitchFromHistory(time)?.date
?: 0) ?: 0)
profileview_reload.visibility = View.GONE
profileview_datelayout.visibility = View.VISIBLE profileview_datelayout.visibility = View.VISIBLE
} }
Mode.PUMP_PROFILE -> {
profile = (ConfigBuilderPlugin.getPlugin().activePump as ProfileInterface?)?.profile?.defaultProfile Mode.CUSTOM_PROFILE -> {
profileName = (ConfigBuilderPlugin.getPlugin().activePump as ProfileInterface?)?.profileName profile = Profile(JSONObject(customProfileJson), customProfileUnits)
profileName = customProfileName
date = "" date = ""
profileview_reload.visibility = View.VISIBLE
profileview_datelayout.visibility = View.GONE profileview_datelayout.visibility = View.GONE
} }
} }
@ -83,15 +91,18 @@ class ProfileViewerDialog : DialogFragment() {
} }
} }
override fun onResume() { override fun onStart() {
super.onStart()
dialog?.window?.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT) dialog?.window?.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)
super.onResume()
} }
override fun onSaveInstanceState(bundle: Bundle) { override fun onSaveInstanceState(bundle: Bundle) {
super.onSaveInstanceState(bundle) super.onSaveInstanceState(bundle)
bundle.putLong("time", time) bundle.putLong("time", time)
bundle.putInt("mode", mode.ordinal) bundle.putInt("mode", mode.ordinal)
bundle.putString("customProfile", customProfileJson)
bundle.putString("customProfileName", customProfileName)
bundle.putString("customProfileUnits", customProfileUnits)
} }
} }

View file

@ -0,0 +1,117 @@
package info.nightscout.androidaps.dialogs
import android.content.Intent
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.google.common.base.Joiner
import info.nightscout.androidaps.MainApp
import info.nightscout.androidaps.R
import info.nightscout.androidaps.activities.ErrorHelperActivity
import info.nightscout.androidaps.interfaces.Constraint
import info.nightscout.androidaps.interfaces.PumpDescription
import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin
import info.nightscout.androidaps.plugins.configBuilder.ProfileFunctions
import info.nightscout.androidaps.queue.Callback
import info.nightscout.androidaps.utils.HtmlHelper
import info.nightscout.androidaps.utils.OKDialog
import info.nightscout.androidaps.utils.SafeParse
import kotlinx.android.synthetic.main.dialog_tempbasal.*
import kotlinx.android.synthetic.main.okcancel.*
import java.text.DecimalFormat
import java.util.*
import kotlin.math.abs
class TempBasalDialog : DialogFragmentWithDate() {
private var isPercentPump = true
override fun onSaveInstanceState(savedInstanceState: Bundle) {
super.onSaveInstanceState(savedInstanceState)
savedInstanceState.putDouble("actions_tempbasal_duration", actions_tempbasal_duration.value)
savedInstanceState.putDouble("actions_tempbasal_basalpercentinput", actions_tempbasal_basalpercentinput.value)
savedInstanceState.putDouble("actions_tempbasal_basalabsoluteinput", actions_tempbasal_basalabsoluteinput.value)
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
onCreateViewGeneral()
return inflater.inflate(R.layout.dialog_tempbasal, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val pumpDescription = ConfigBuilderPlugin.getPlugin().activePump?.pumpDescription ?: return
val profile = ProfileFunctions.getInstance().profile ?: return
val maxTempPercent = pumpDescription.maxTempPercent.toDouble()
val tempPercentStep = pumpDescription.tempPercentStep.toDouble()
actions_tempbasal_basalpercentinput.setParams(savedInstanceState?.getDouble("actions_tempbasal_basalpercentinput")
?: 100.0, 0.0, maxTempPercent, tempPercentStep, DecimalFormat("0"), true, ok)
actions_tempbasal_basalabsoluteinput.setParams(savedInstanceState?.getDouble("actions_tempbasal_basalabsoluteinput")
?: profile.basal, 0.0, pumpDescription.maxTempAbsolute, pumpDescription.tempAbsoluteStep, DecimalFormat("0.00"), true, ok)
val tempDurationStep = pumpDescription.tempDurationStep.toDouble()
val tempMaxDuration = pumpDescription.tempMaxDuration.toDouble()
actions_tempbasal_duration.setParams(savedInstanceState?.getDouble("actions_tempbasal_duration")
?: tempDurationStep, tempDurationStep, tempMaxDuration, tempDurationStep, DecimalFormat("0"), false, ok)
isPercentPump = pumpDescription.tempBasalStyle and PumpDescription.PERCENT == PumpDescription.PERCENT
if (isPercentPump) {
actions_tempbasal_percent_layout.visibility = View.VISIBLE
actions_tempbasal_absolute_layout.visibility = View.GONE
} else {
actions_tempbasal_percent_layout.visibility = View.GONE
actions_tempbasal_absolute_layout.visibility = View.VISIBLE
}
}
override fun submit(): Boolean {
var percent = 0
var absolute = 0.0
val durationInMinutes = SafeParse.stringToInt(actions_tempbasal_duration.text)
val profile = ProfileFunctions.getInstance().profile ?: return false
val actions: LinkedList<String> = LinkedList()
if (isPercentPump) {
val basalPercentInput = SafeParse.stringToInt(actions_tempbasal_basalpercentinput.text)
percent = MainApp.getConstraintChecker().applyBasalPercentConstraints(Constraint(basalPercentInput), profile).value()
actions.add(MainApp.gs(R.string.pump_tempbasal_label)+ ": $percent%")
actions.add(MainApp.gs(R.string.duration) + ": " + MainApp.gs(R.string.format_mins, durationInMinutes))
if (percent != basalPercentInput) actions.add(MainApp.gs(R.string.constraintapllied))
} else {
val basalAbsoluteInput = SafeParse.stringToDouble(actions_tempbasal_basalabsoluteinput.text)
absolute = MainApp.getConstraintChecker().applyBasalConstraints(Constraint(basalAbsoluteInput), profile).value()
actions.add(MainApp.gs(R.string.pump_tempbasal_label)+ ": " + MainApp.gs(R.string.pump_basebasalrate, absolute))
actions.add(MainApp.gs(R.string.duration) + ": " + MainApp.gs(R.string.format_mins, durationInMinutes))
if (abs(absolute - basalAbsoluteInput) > 0.01)
actions.add("<font color='" + MainApp.gc(R.color.warning) + "'>" + MainApp.gs(R.string.constraintapllied) + "</font>")
}
activity?.let { activity ->
OKDialog.showConfirmation(activity, MainApp.gs(R.string.pump_tempbasal_label), HtmlHelper.fromHtml(Joiner.on("<br/>").join(actions)), Runnable {
val callback: Callback = object : Callback() {
override fun run() {
if (!result.success) {
val i = Intent(MainApp.instance(), ErrorHelperActivity::class.java)
i.putExtra("soundid", R.raw.boluserror)
i.putExtra("status", result.comment)
i.putExtra("title", MainApp.gs(R.string.tempbasaldeliveryerror))
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
MainApp.instance().startActivity(i)
}
}
}
if (isPercentPump) {
log.debug("USER ENTRY: TEMP BASAL $percent% duration: $durationInMinutes")
ConfigBuilderPlugin.getPlugin().commandQueue.tempBasalPercent(percent, durationInMinutes, true, profile, callback)
} else {
log.debug("USER ENTRY: TEMP BASAL $absolute duration: $durationInMinutes")
ConfigBuilderPlugin.getPlugin().commandQueue.tempBasalAbsolute(absolute, durationInMinutes, true, profile, callback)
}
})
}
return true
}
}

View file

@ -0,0 +1,153 @@
package info.nightscout.androidaps.dialogs
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.AdapterView
import android.widget.ArrayAdapter
import com.google.common.base.Joiner
import com.google.common.collect.Lists
import info.nightscout.androidaps.Constants
import info.nightscout.androidaps.MainApp
import info.nightscout.androidaps.R
import info.nightscout.androidaps.data.Profile
import info.nightscout.androidaps.db.Source
import info.nightscout.androidaps.db.TempTarget
import info.nightscout.androidaps.plugins.configBuilder.ProfileFunctions
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.DefaultValueHelper
import info.nightscout.androidaps.utils.HtmlHelper
import info.nightscout.androidaps.utils.OKDialog
import info.nightscout.androidaps.utils.SP
import kotlinx.android.synthetic.main.dialog_temptarget.*
import kotlinx.android.synthetic.main.okcancel.*
import java.text.DecimalFormat
import java.util.*
class TempTargetDialog : DialogFragmentWithDate() {
override fun onSaveInstanceState(savedInstanceState: Bundle) {
super.onSaveInstanceState(savedInstanceState)
savedInstanceState.putDouble("overview_temptarget_duration", overview_temptarget_duration.value)
savedInstanceState.putDouble("overview_temptarget_temptarget", overview_temptarget_temptarget.value)
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
onCreateViewGeneral()
return inflater.inflate(R.layout.dialog_temptarget, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
overview_temptarget_duration.setParams(savedInstanceState?.getDouble("overview_temptarget_duration")
?: 0.0, 0.0, Constants.MAX_PROFILE_SWITCH_DURATION, 10.0, DecimalFormat("0"), false, ok)
if (ProfileFunctions.getSystemUnits() == Constants.MMOL)
overview_temptarget_temptarget.setParams(
savedInstanceState?.getDouble("overview_temptarget_temptarget")
?: Constants.MIN_TT_MMOL,
Constants.MIN_TT_MMOL, Constants.MAX_TT_MMOL, 0.1, DecimalFormat("0.0"), false, ok)
else
overview_temptarget_temptarget.setParams(
savedInstanceState?.getDouble("overview_temptarget_temptarget")
?: Constants.MIN_TT_MGDL,
Constants.MIN_TT_MGDL, Constants.MAX_TT_MGDL, 1.0, DecimalFormat("0"), false, ok)
val units = ProfileFunctions.getSystemUnits()
overview_temptarget_units.text = if (units == Constants.MMOL) MainApp.gs(R.string.mmol) else MainApp.gs(R.string.mgdl)
// temp target
context?.let { context ->
val reasonList: List<String> = Lists.newArrayList(
MainApp.gs(R.string.manual),
MainApp.gs(R.string.cancel),
MainApp.gs(R.string.eatingsoon),
MainApp.gs(R.string.activity),
MainApp.gs(R.string.hypo)
)
val adapterReason = ArrayAdapter(context, R.layout.spinner_centered, reasonList)
overview_temptarget_reason.adapter = adapterReason
overview_temptarget_reason.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
override fun onItemSelected(parent: AdapterView<*>?, view: View, position: Int, id: Long) {
val defaultDuration: Double
val defaultTarget: Double
when (reasonList[position]) {
MainApp.gs(R.string.eatingsoon) -> {
defaultDuration = DefaultValueHelper.determineEatingSoonTTDuration().toDouble()
defaultTarget = DefaultValueHelper.determineEatingSoonTT()
}
MainApp.gs(R.string.activity) -> {
defaultDuration = DefaultValueHelper.determineActivityTTDuration().toDouble()
defaultTarget = DefaultValueHelper.determineActivityTT()
}
MainApp.gs(R.string.hypo) -> {
defaultDuration = DefaultValueHelper.determineHypoTTDuration().toDouble()
defaultTarget = DefaultValueHelper.determineHypoTT()
}
MainApp.gs(R.string.cancel) -> {
defaultDuration = 0.0
defaultTarget = 0.0
}
else -> {
defaultDuration = overview_temptarget_duration.value
defaultTarget = overview_temptarget_temptarget.value
}
}
overview_temptarget_temptarget.value = defaultTarget
overview_temptarget_duration.value = defaultDuration
}
override fun onNothingSelected(parent: AdapterView<*>?) {}
}
}
}
override fun submit(): Boolean {
val actions: LinkedList<String> = LinkedList()
val reason = overview_temptarget_reason.selectedItem.toString()
val unitResId = if (ProfileFunctions.getSystemUnits() == Constants.MGDL) R.string.mgdl else R.string.mmol
val target = overview_temptarget_temptarget.value
val duration = overview_temptarget_duration.value.toInt()
if (target != 0.0 && duration != 0) {
actions.add(MainApp.gs(R.string.reason) + ": " + reason)
actions.add(MainApp.gs(R.string.nsprofileview_target_label) + ": " + Profile.toCurrentUnitsString(target) + " " + MainApp.gs(unitResId))
actions.add(MainApp.gs(R.string.duration) + ": " + MainApp.gs(R.string.format_mins, duration))
} else {
actions.add(MainApp.gs(R.string.stoptemptarget))
}
if (eventTimeChanged)
actions.add(MainApp.gs(R.string.time) + ": " + DateUtil.dateAndTimeString(eventTime))
activity?.let { activity ->
OKDialog.showConfirmation(activity, MainApp.gs(R.string.careportal_temporarytarget), HtmlHelper.fromHtml(Joiner.on("<br/>").join(actions)), Runnable {
log.debug("USER ENTRY: TEMP TARGET $target duration: $duration")
if (target == 0.0 || duration == 0) {
val tempTarget = TempTarget()
.date(eventTime)
.duration(0)
.low(0.0).high(0.0)
.source(Source.USER)
TreatmentsPlugin.getPlugin().addToHistoryTempTarget(tempTarget)
} else {
val tempTarget = TempTarget()
.date(eventTime)
.duration(duration.toInt())
.reason(reason)
.source(Source.USER)
.low(Profile.toMgdl(target, ProfileFunctions.getSystemUnits()))
.high(Profile.toMgdl(target, ProfileFunctions.getSystemUnits()))
TreatmentsPlugin.getPlugin().addToHistoryTempTarget(tempTarget)
}
if (duration == 10) SP.putBoolean(R.string.key_objectiveusetemptarget, true)
})
}
return true
}
}

View file

@ -0,0 +1,133 @@
package info.nightscout.androidaps.dialogs
import android.content.Intent
import android.os.Bundle
import android.text.Editable
import android.text.TextWatcher
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.google.common.base.Joiner
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.db.CareportalEvent
import info.nightscout.androidaps.db.Source
import info.nightscout.androidaps.interfaces.Constraint
import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin
import info.nightscout.androidaps.queue.Callback
import info.nightscout.androidaps.utils.DecimalFormatter
import info.nightscout.androidaps.utils.HtmlHelper
import info.nightscout.androidaps.utils.OKDialog
import info.nightscout.androidaps.utils.SafeParse
import info.nightscout.androidaps.utils.ToastUtils
import kotlinx.android.synthetic.main.dialog_treatment.*
import kotlinx.android.synthetic.main.okcancel.*
import java.text.DecimalFormat
import java.util.*
import kotlin.math.abs
class TreatmentDialog : DialogFragmentWithDate() {
private var maxCarbs = MainApp.getConstraintChecker().maxCarbsAllowed.value().toDouble()
private var maxInsulin = MainApp.getConstraintChecker().maxBolusAllowed.value()
private val textWatcher: TextWatcher = object : TextWatcher {
override fun afterTextChanged(s: Editable) {}
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {}
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
validateInputs()
}
}
private fun validateInputs() {
if (SafeParse.stringToInt(overview_treatment_carbs.text) > maxCarbs) {
overview_treatment_carbs.value = 0.0
ToastUtils.showToastInUiThread(MainApp.instance().applicationContext, MainApp.gs(R.string.carbsconstraintapplied))
}
if (SafeParse.stringToDouble(overview_treatment_insulin.text) > maxInsulin) {
overview_treatment_insulin.value = 0.0
ToastUtils.showToastInUiThread(MainApp.instance().applicationContext, MainApp.gs(R.string.bolusconstraintapplied))
}
}
override fun onSaveInstanceState(savedInstanceState: Bundle) {
super.onSaveInstanceState(savedInstanceState)
savedInstanceState.putDouble("overview_treatment_carbs", overview_treatment_carbs.value)
savedInstanceState.putDouble("overview_treatment_insulin", overview_treatment_insulin.value)
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
onCreateViewGeneral()
return inflater.inflate(R.layout.dialog_treatment, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val pumpDescription = ConfigBuilderPlugin.getPlugin().activePump?.pumpDescription ?: return
overview_treatment_carbs.setParams(savedInstanceState?.getDouble("overview_treatment_carbs")
?: 0.0, 0.0, maxCarbs, 1.0, DecimalFormat("0"), false, ok, textWatcher)
overview_treatment_insulin.setParams(savedInstanceState?.getDouble("overview_treatment_insulin")
?: 0.0, 0.0, maxInsulin, pumpDescription.bolusStep, DecimalFormatter.pumpSupportedBolusFormat(), false, ok, textWatcher)
}
override fun submit(): Boolean {
val pumpDescription = ConfigBuilderPlugin.getPlugin().activePump?.pumpDescription
?: return false
val insulin = SafeParse.stringToDouble(overview_treatment_insulin.text)
val carbs = SafeParse.stringToInt(overview_treatment_carbs.text)
val recordOnlyChecked = overview_treatment_record_only.isChecked
val actions: LinkedList<String?> = LinkedList()
val insulinAfterConstraints = MainApp.getConstraintChecker().applyBolusConstraints(Constraint(insulin)).value()
val carbsAfterConstraints = MainApp.getConstraintChecker().applyCarbsConstraints(Constraint(carbs)).value()
if (insulinAfterConstraints > 0) {
actions.add(MainApp.gs(R.string.bolus) + ": " + "<font color='" + MainApp.gc(R.color.bolus) + "'>" + DecimalFormatter.toPumpSupportedBolus(insulinAfterConstraints) + MainApp.gs(R.string.insulin_unit_shortname) + "</font>")
if (recordOnlyChecked)
actions.add("<font color='" + MainApp.gc(R.color.warning) + "'>" + MainApp.gs(R.string.bolusrecordedonly) + "</font>")
if (abs(insulinAfterConstraints - insulin) > pumpDescription.pumpType.determineCorrectBolusStepSize(insulinAfterConstraints))
actions.add(MainApp.gs(R.string.bolusconstraintappliedwarning, MainApp.gc(R.color.warning), insulin, insulinAfterConstraints))
}
if (carbsAfterConstraints > 0) {
actions.add(MainApp.gs(R.string.carbs) + ": " + "<font color='" + MainApp.gc(R.color.carbs) + "'>" + MainApp.gs(R.string.format_carbs, carbsAfterConstraints) + "</font>")
if (carbsAfterConstraints != carbs)
actions.add("<font color='" + MainApp.gc(R.color.warning) + "'>" + MainApp.gs(R.string.carbsconstraintapplied) + "</font>")
}
if (insulinAfterConstraints > 0 || carbsAfterConstraints > 0) {
activity?.let { activity ->
OKDialog.showConfirmation(activity, MainApp.gs(R.string.overview_treatment_label), HtmlHelper.fromHtml(Joiner.on("<br/>").join(actions)), Runnable {
log.debug("USER ENTRY: BOLUS insulin $insulin carbs: $carbs")
val detailedBolusInfo = DetailedBolusInfo()
if (insulinAfterConstraints == 0.0) detailedBolusInfo.eventType = CareportalEvent.CARBCORRECTION
if (carbsAfterConstraints == 0) detailedBolusInfo.eventType = CareportalEvent.CORRECTIONBOLUS
detailedBolusInfo.insulin = insulinAfterConstraints
detailedBolusInfo.carbs = carbsAfterConstraints.toDouble()
detailedBolusInfo.context = context
detailedBolusInfo.source = Source.USER
if (!(recordOnlyChecked && (detailedBolusInfo.insulin > 0 || pumpDescription.storesCarbInfo))) {
ConfigBuilderPlugin.getPlugin().commandQueue.bolus(detailedBolusInfo, object : Callback() {
override fun run() {
if (!result.success) {
val i = Intent(MainApp.instance(), ErrorHelperActivity::class.java)
i.putExtra("soundid", R.raw.boluserror)
i.putExtra("status", result.comment)
i.putExtra("title", MainApp.gs(R.string.treatmentdeliveryerror))
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
MainApp.instance().startActivity(i)
}
}
})
} else
TreatmentsPlugin.getPlugin().addToHistoryTreatment(detailedBolusInfo, false)
})
}
} else
activity?.let { activity ->
OKDialog.show(activity, MainApp.gs(R.string.overview_treatment_label), MainApp.gs(R.string.no_action_selected))
}
return true
}
}

View file

@ -1,10 +1,13 @@
package info.nightscout.androidaps.plugins.general.overview.dialogs package info.nightscout.androidaps.dialogs
import android.content.Context
import android.os.Bundle import android.os.Bundle
import android.text.Editable import android.text.Editable
import android.text.TextWatcher import android.text.TextWatcher
import android.view.* import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.Window
import android.view.WindowManager
import android.widget.AdapterView import android.widget.AdapterView
import android.widget.AdapterView.OnItemSelectedListener import android.widget.AdapterView.OnItemSelectedListener
import android.widget.ArrayAdapter import android.widget.ArrayAdapter
@ -26,7 +29,7 @@ import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin
import info.nightscout.androidaps.utils.* import info.nightscout.androidaps.utils.*
import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable import io.reactivex.disposables.CompositeDisposable
import kotlinx.android.synthetic.main.overview_wizard_dialog.* import kotlinx.android.synthetic.main.dialog_wizard.*
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
import java.text.DecimalFormat import java.text.DecimalFormat
import java.util.* import java.util.*
@ -36,16 +39,13 @@ class WizardDialog : DialogFragment() {
private val log = LoggerFactory.getLogger(WizardDialog::class.java) private val log = LoggerFactory.getLogger(WizardDialog::class.java)
private var wizard: BolusWizard? = null private var wizard: BolusWizard? = null
private var parentContext: Context? = null
//one shot guards //one shot guards
private var okClicked: Boolean = false private var okClicked: Boolean = false
private val textWatcher = object : TextWatcher { private val textWatcher = object : TextWatcher {
override fun afterTextChanged(s: Editable) {} override fun afterTextChanged(s: Editable) {}
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) {
calculateInsulin() calculateInsulin()
} }
@ -53,21 +53,11 @@ class WizardDialog : DialogFragment() {
private var disposable: CompositeDisposable = CompositeDisposable() private var disposable: CompositeDisposable = CompositeDisposable()
override fun onAttach(context: Context) {
super.onAttach(context)
this.parentContext = context
}
override fun onStart() { override fun onStart() {
super.onStart() super.onStart()
dialog?.window?.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT) dialog?.window?.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
} }
override fun onDetach() {
super.onDetach()
this.parentContext = null
}
override fun onSaveInstanceState(savedInstanceState: Bundle) { override fun onSaveInstanceState(savedInstanceState: Bundle) {
super.onSaveInstanceState(savedInstanceState) super.onSaveInstanceState(savedInstanceState)
savedInstanceState.putDouble("treatments_wizard_bg_input", treatments_wizard_bg_input.value) savedInstanceState.putDouble("treatments_wizard_bg_input", treatments_wizard_bg_input.value)
@ -83,28 +73,28 @@ class WizardDialog : DialogFragment() {
isCancelable = true isCancelable = true
dialog?.setCanceledOnTouchOutside(false) dialog?.setCanceledOnTouchOutside(false)
return inflater.inflate(R.layout.overview_wizard_dialog, container, false) return inflater.inflate(R.layout.dialog_wizard, container, false)
} }
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
loadCheckedStates() loadCheckedStates()
processCobCheckBox() processCobCheckBox()
treatments_wizard_sbcheckbox.visibility = if (SP.getBoolean(R.string.key_usesuperbolus, false)) View.VISIBLE else View.GONE treatments_wizard_sbcheckbox.visibility = SP.getBoolean(R.string.key_usesuperbolus, false).toVisibility()
treatments_wizard_notes_layout.visibility = if (SP.getBoolean(R.string.key_show_notes_entry_dialogs, false)) View.VISIBLE else View.GONE treatments_wizard_notes_layout.visibility = SP.getBoolean(R.string.key_show_notes_entry_dialogs, false).toVisibility()
val maxCarbs = MainApp.getConstraintChecker().maxCarbsAllowed.value() val maxCarbs = MainApp.getConstraintChecker().maxCarbsAllowed.value()
val maxCorrection = MainApp.getConstraintChecker().maxBolusAllowed.value() val maxCorrection = MainApp.getConstraintChecker().maxBolusAllowed.value()
treatments_wizard_bg_input.setParams(savedInstanceState?.getDouble("treatments_wizard_bg_input") treatments_wizard_bg_input.setParams(savedInstanceState?.getDouble("treatments_wizard_bg_input")
?: 0.0, 0.0, 500.0, 0.1, DecimalFormat("0.0"), false, ok, textWatcher) ?: 0.0, 0.0, 500.0, 0.1, DecimalFormat("0.0"), false, ok, textWatcher)
treatments_wizard_carbs_input.setParams(savedInstanceState?.getDouble("treatments_wizard_carbs_input") treatments_wizard_carbs_input.setParams(savedInstanceState?.getDouble("treatments_wizard_carbs_input")
?: 0.0, 0.0, maxCarbs.toDouble(), 1.0, DecimalFormat("0"), false, ok, textWatcher) ?: 0.0, 0.0, maxCarbs.toDouble(), 1.0, DecimalFormat("0"), false, ok, textWatcher)
val bolusStep = ConfigBuilderPlugin.getPlugin().activePump?.pumpDescription?.bolusStep val bolusStep = ConfigBuilderPlugin.getPlugin().activePump?.pumpDescription?.bolusStep
?: 0.1 ?: 0.1
treatments_wizard_correction_input.setParams(savedInstanceState?.getDouble("treatments_wizard_correction_input") treatments_wizard_correction_input.setParams(savedInstanceState?.getDouble("treatments_wizard_correction_input")
?: 0.0, -maxCorrection, maxCorrection, bolusStep, DecimalFormatter.pumpSupportedBolusFormat(), false, ok, textWatcher) ?: 0.0, -maxCorrection, maxCorrection, bolusStep, DecimalFormatter.pumpSupportedBolusFormat(), false, ok, textWatcher)
treatments_wizard_carb_time_input.setParams(savedInstanceState?.getDouble("treatments_wizard_carb_time_input") treatments_wizard_carb_time_input.setParams(savedInstanceState?.getDouble("treatments_wizard_carb_time_input")
?: 0.0, -60.0, 60.0, 5.0, DecimalFormat("0"), false, ok, textWatcher) ?: 0.0, -60.0, 60.0, 5.0, DecimalFormat("0"), false, ok, textWatcher)
initDialog() initDialog()
treatments_wizard_percent_used.text = MainApp.gs(R.string.format_percent, SP.getInt(R.string.key_boluswizard_percentage, 100)) treatments_wizard_percent_used.text = MainApp.gs(R.string.format_percent, SP.getInt(R.string.key_boluswizard_percentage, 100))
@ -115,7 +105,7 @@ class WizardDialog : DialogFragment() {
} else { } else {
okClicked = true okClicked = true
calculateInsulin() calculateInsulin()
parentContext?.let { context -> context?.let { context ->
wizard?.confirmAndExecute(context) wizard?.confirmAndExecute(context)
} }
} }
@ -124,23 +114,23 @@ class WizardDialog : DialogFragment() {
// cancel button // cancel button
cancel.setOnClickListener { dismiss() } cancel.setOnClickListener { dismiss() }
// checkboxes // checkboxes
treatments_wizard_bgcheckbox.setOnCheckedChangeListener { buttonView, _ -> onCheckedChanged(buttonView) } treatments_wizard_bgcheckbox.setOnCheckedChangeListener(::onCheckedChanged)
treatments_wizard_ttcheckbox.setOnCheckedChangeListener { buttonView, _ -> onCheckedChanged(buttonView) } treatments_wizard_ttcheckbox.setOnCheckedChangeListener(::onCheckedChanged)
treatments_wizard_cobcheckbox.setOnCheckedChangeListener { buttonView, _ -> onCheckedChanged(buttonView) } treatments_wizard_cobcheckbox.setOnCheckedChangeListener(::onCheckedChanged)
treatments_wizard_basaliobcheckbox.setOnCheckedChangeListener { buttonView, _ -> onCheckedChanged(buttonView) } treatments_wizard_basaliobcheckbox.setOnCheckedChangeListener(::onCheckedChanged)
treatments_wizard_bolusiobcheckbox.setOnCheckedChangeListener { buttonView, _ -> onCheckedChanged(buttonView) } treatments_wizard_bolusiobcheckbox.setOnCheckedChangeListener(::onCheckedChanged)
treatments_wizard_bgtrendcheckbox.setOnCheckedChangeListener { buttonView, _ -> onCheckedChanged(buttonView) } treatments_wizard_bgtrendcheckbox.setOnCheckedChangeListener(::onCheckedChanged)
treatments_wizard_sbcheckbox.setOnCheckedChangeListener { buttonView, _ -> onCheckedChanged(buttonView) } treatments_wizard_sbcheckbox.setOnCheckedChangeListener(::onCheckedChanged)
val showCalc = SP.getBoolean(MainApp.gs(R.string.key_wizard_calculation_visible), false) val showCalc = SP.getBoolean(MainApp.gs(R.string.key_wizard_calculation_visible), false)
treatments_wizard_delimiter.visibility = if (showCalc) View.VISIBLE else View.GONE treatments_wizard_delimiter.visibility = showCalc.toVisibility()
treatments_wizard_resulttable.visibility = if (showCalc) View.VISIBLE else View.GONE treatments_wizard_resulttable.visibility = showCalc.toVisibility()
treatments_wizard_calculationcheckbox.isChecked = showCalc treatments_wizard_calculationcheckbox.isChecked = showCalc
treatments_wizard_calculationcheckbox.setOnCheckedChangeListener { _, isChecked -> treatments_wizard_calculationcheckbox.setOnCheckedChangeListener { _, isChecked ->
run { run {
SP.putBoolean(MainApp.gs(R.string.key_wizard_calculation_visible), isChecked) SP.putBoolean(MainApp.gs(R.string.key_wizard_calculation_visible), isChecked)
treatments_wizard_delimiter.visibility = if (isChecked) View.VISIBLE else View.GONE treatments_wizard_delimiter.visibility = isChecked.toVisibility()
treatments_wizard_resulttable.visibility = if (isChecked) View.VISIBLE else View.GONE treatments_wizard_resulttable.visibility = isChecked.toVisibility()
} }
} }
// profile spinner // profile spinner
@ -157,13 +147,13 @@ class WizardDialog : DialogFragment() {
} }
// bus // bus
disposable.add(RxBus disposable.add(RxBus
.toObservable(EventAutosensCalculationFinished::class.java) .toObservable(EventAutosensCalculationFinished::class.java)
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
.subscribe({ .subscribe({
activity?.runOnUiThread { calculateInsulin() } activity?.runOnUiThread { calculateInsulin() }
}, { }, {
FabricPrivacy.logException(it) FabricPrivacy.logException(it)
}) })
) )
} }
@ -173,7 +163,7 @@ class WizardDialog : DialogFragment() {
disposable.clear() disposable.clear()
} }
private fun onCheckedChanged(buttonView: CompoundButton) { private fun onCheckedChanged(buttonView: CompoundButton, @Suppress("UNUSED_PARAMETER") state: Boolean) {
saveCheckedStates() saveCheckedStates()
treatments_wizard_ttcheckbox.isEnabled = treatments_wizard_bgcheckbox.isChecked && TreatmentsPlugin.getPlugin().tempTargetFromHistory != null treatments_wizard_ttcheckbox.isEnabled = treatments_wizard_bgcheckbox.isChecked && TreatmentsPlugin.getPlugin().tempTargetFromHistory != null
if (buttonView.id == treatments_wizard_cobcheckbox.id) if (buttonView.id == treatments_wizard_cobcheckbox.id)
@ -214,15 +204,14 @@ class WizardDialog : DialogFragment() {
} }
val profileList: ArrayList<CharSequence> val profileList: ArrayList<CharSequence>
profileList = profileStore.profileList profileList = profileStore.getProfileList()
profileList.add(0, MainApp.gs(R.string.active)) profileList.add(0, MainApp.gs(R.string.active))
context?.let { context -> context?.let { context ->
val adapter = ArrayAdapter(context, R.layout.spinner_centered, profileList) val adapter = ArrayAdapter(context, R.layout.spinner_centered, profileList)
treatments_wizard_profile.adapter = adapter treatments_wizard_profile.adapter = adapter
} ?: return } ?: return
val units = ProfileFunctions.getSystemUnits()
val units = profile.units
treatments_wizard_bgunits.text = units treatments_wizard_bgunits.text = units
if (units == Constants.MGDL) if (units == Constants.MGDL)
treatments_wizard_bg_input.setStep(1.0) treatments_wizard_bg_input.setStep(1.0)
@ -250,7 +239,7 @@ class WizardDialog : DialogFragment() {
calculateInsulin() calculateInsulin()
treatments_wizard_percent_used.visibility = if (SP.getInt(R.string.key_boluswizard_percentage, 100) != 100) View.VISIBLE else View.GONE treatments_wizard_percent_used.visibility = (SP.getInt(R.string.key_boluswizard_percentage, 100) != 100).toVisibility()
} }
private fun calculateInsulin() { private fun calculateInsulin() {
@ -291,18 +280,18 @@ class WizardDialog : DialogFragment() {
val carbTime = SafeParse.stringToInt(treatments_wizard_carb_time_input.text) val carbTime = SafeParse.stringToInt(treatments_wizard_carb_time_input.text)
wizard = BolusWizard(specificProfile, profileName, tempTarget, carbsAfterConstraint, cob, bg, correction, wizard = BolusWizard(specificProfile, profileName, tempTarget, carbsAfterConstraint, cob, bg, correction,
SP.getInt(R.string.key_boluswizard_percentage, 100).toDouble(), SP.getInt(R.string.key_boluswizard_percentage, 100).toDouble(),
treatments_wizard_bgcheckbox.isChecked, treatments_wizard_bgcheckbox.isChecked,
treatments_wizard_cobcheckbox.isChecked, treatments_wizard_cobcheckbox.isChecked,
treatments_wizard_bolusiobcheckbox.isChecked, treatments_wizard_bolusiobcheckbox.isChecked,
treatments_wizard_basaliobcheckbox.isChecked, treatments_wizard_basaliobcheckbox.isChecked,
treatments_wizard_sbcheckbox.isChecked, treatments_wizard_sbcheckbox.isChecked,
treatments_wizard_ttcheckbox.isChecked, treatments_wizard_ttcheckbox.isChecked,
treatments_wizard_bgtrendcheckbox.isChecked, treatments_wizard_bgtrendcheckbox.isChecked,
treatment_wizard_notes.text.toString(), carbTime) treatment_wizard_notes.text.toString(), carbTime)
wizard?.let { wizard -> wizard?.let { wizard ->
treatments_wizard_bg.text = String.format(MainApp.gs(R.string.format_bg_isf), BgReading().value(Profile.toMgdl(bg, specificProfile.units)).valueToUnitsToString(specificProfile.units), wizard.sens) treatments_wizard_bg.text = String.format(MainApp.gs(R.string.format_bg_isf), BgReading().value(Profile.toMgdl(bg, ProfileFunctions.getSystemUnits())).valueToUnitsToString(ProfileFunctions.getSystemUnits()), wizard.sens)
treatments_wizard_bginsulin.text = StringUtils.formatInsulin(wizard.insulinFromBG) treatments_wizard_bginsulin.text = StringUtils.formatInsulin(wizard.insulinFromBG)
treatments_wizard_carbs.text = String.format(MainApp.gs(R.string.format_carbs_ic), carbs.toDouble(), wizard.ic) treatments_wizard_carbs.text = String.format(MainApp.gs(R.string.format_carbs_ic), carbs.toDouble(), wizard.ic)
@ -320,8 +309,8 @@ class WizardDialog : DialogFragment() {
// Trend // Trend
if (treatments_wizard_bgtrendcheckbox.isChecked && wizard.glucoseStatus != null) { if (treatments_wizard_bgtrendcheckbox.isChecked && wizard.glucoseStatus != null) {
treatments_wizard_bgtrend.text = ((if (wizard.trend > 0) "+" else "") treatments_wizard_bgtrend.text = ((if (wizard.trend > 0) "+" else "")
+ Profile.toUnitsString(wizard.trend * 3, wizard.trend * 3 / Constants.MMOLL_TO_MGDL, specificProfile.units) + Profile.toUnitsString(wizard.trend * 3, wizard.trend * 3 / Constants.MMOLL_TO_MGDL, ProfileFunctions.getSystemUnits())
+ " " + specificProfile.units) + " " + ProfileFunctions.getSystemUnits())
} else { } else {
treatments_wizard_bgtrend.text = "" treatments_wizard_bgtrend.text = ""
} }

View file

@ -4,7 +4,6 @@ import android.os.SystemClock;
import android.preference.Preference; import android.preference.Preference;
import android.preference.PreferenceFragment; import android.preference.PreferenceFragment;
import androidx.appcompat.app.AlertDialog;
import androidx.fragment.app.FragmentActivity; import androidx.fragment.app.FragmentActivity;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@ -20,6 +19,7 @@ import info.nightscout.androidaps.plugins.bus.RxBus;
import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin; import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.configBuilder.EventConfigBuilderUpdateGui; import info.nightscout.androidaps.plugins.configBuilder.EventConfigBuilderUpdateGui;
import info.nightscout.androidaps.queue.CommandQueue; import info.nightscout.androidaps.queue.CommandQueue;
import info.nightscout.androidaps.utils.OKDialog;
import info.nightscout.androidaps.utils.SP; import info.nightscout.androidaps.utils.SP;
/** /**
@ -58,27 +58,23 @@ public abstract class PluginBase {
if (allowHardwarePump || activity == null) { if (allowHardwarePump || activity == null) {
performPluginSwitch(newState, type); performPluginSwitch(newState, type);
} else { } else {
AlertDialog.Builder builder = new AlertDialog.Builder(activity); OKDialog.showConfirmation(activity, MainApp.gs(R.string.allow_hardware_pump_text), () -> {
builder.setMessage(R.string.allow_hardware_pump_text) performPluginSwitch(newState, type);
.setPositiveButton(R.string.yes, (dialog, id) -> { SP.putBoolean("allow_hardware_pump", true);
performPluginSwitch(newState, type); if (L.isEnabled(L.PUMP))
SP.putBoolean("allow_hardware_pump", true); log.debug("First time HW pump allowed!");
if (L.isEnabled(L.PUMP)) }, () -> {
log.debug("First time HW pump allowed!"); RxBus.INSTANCE.send(new EventConfigBuilderUpdateGui());
}) if (L.isEnabled(L.PUMP))
.setNegativeButton(R.string.cancel, (dialog, id) -> { log.debug("User does not allow switching to HW pump!");
RxBus.INSTANCE.send(new EventConfigBuilderUpdateGui()); });
if (L.isEnabled(L.PUMP))
log.debug("User does not allow switching to HW pump!");
});
builder.create().show();
} }
} else { } else {
performPluginSwitch(newState, type); performPluginSwitch(newState, type);
} }
} }
private void performPluginSwitch(boolean enabled, PluginType type) { public void performPluginSwitch(boolean enabled, PluginType type) {
setPluginEnabled(type, enabled); setPluginEnabled(type, enabled);
setFragmentVisible(type, enabled); setFragmentVisible(type, enabled);
ConfigBuilderPlugin.getPlugin().processOnEnabledCategoryChanged(this, getType()); ConfigBuilderPlugin.getPlugin().processOnEnabledCategoryChanged(this, getType());

View file

@ -29,8 +29,8 @@ public class PluginDescription {
return this; return this;
} }
public PluginDescription alwaysVisible(boolean alwayVisible) { public PluginDescription alwaysVisible(boolean alwaysVisible) {
this.alwaysVisible = alwayVisible; this.alwaysVisible = alwaysVisible;
return this; return this;
} }

View file

@ -10,6 +10,5 @@ import info.nightscout.androidaps.data.ProfileStore;
public interface ProfileInterface { public interface ProfileInterface {
@Nullable @Nullable
ProfileStore getProfile(); ProfileStore getProfile();
String getUnits();
String getProfileName(); String getProfileName();
} }

View file

@ -31,7 +31,7 @@ public interface TreatmentsInterface {
MealData getMealData(); MealData getMealData();
List<Treatment> getTreatmentsFromHistory(); List<Treatment> getTreatmentsFromHistory();
List<Treatment> getTreatments5MinBackFromHistory(long time); List<Treatment> getCarbTreatments5MinBackFromHistory(long time);
List<Treatment> getTreatmentsFromHistoryAfterTimestamp(long timestamp); List<Treatment> getTreatmentsFromHistoryAfterTimestamp(long timestamp);
long getLastBolusTime(); long getLastBolusTime();

View file

@ -381,13 +381,11 @@ public class DeviceStatus {
try { try {
if (device != null) record.put("device", device); if (device != null) record.put("device", device);
if (pump != null) record.put("pump", pump); if (pump != null) record.put("pump", pump);
if (suggested != null) { JSONObject openaps = new JSONObject();
JSONObject openaps = new JSONObject(); if (enacted != null) openaps.put("enacted", enacted);
if (enacted != null) openaps.put("enacted", enacted); if (suggested != null) openaps.put("suggested", suggested);
if (suggested != null) openaps.put("suggested", suggested); if (iob != null) openaps.put("iob", iob);
if (iob != null) openaps.put("iob", iob); record.put("openaps", openaps);
record.put("openaps", openaps);
}
if (uploaderBattery != 0) record.put("uploaderBattery", uploaderBattery); if (uploaderBattery != 0) record.put("uploaderBattery", uploaderBattery);
if (created_at != null) record.put("created_at", created_at); if (created_at != null) record.put("created_at", created_at);
} catch (JSONException e) { } catch (JSONException e) {

View file

@ -1,6 +1,5 @@
package info.nightscout.androidaps.plugins.aps.loop package info.nightscout.androidaps.plugins.aps.loop
import android.os.Bundle import android.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
@ -12,7 +11,11 @@ import info.nightscout.androidaps.interfaces.Constraint
import info.nightscout.androidaps.plugins.aps.loop.events.EventLoopSetLastRunGui 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.EventLoopUpdateGui
import info.nightscout.androidaps.plugins.bus.RxBus import info.nightscout.androidaps.plugins.bus.RxBus
import info.nightscout.androidaps.utils.* import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.HtmlHelper
import info.nightscout.androidaps.utils.SP
import info.nightscout.androidaps.utils.plusAssign
import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable import io.reactivex.disposables.CompositeDisposable
import kotlinx.android.synthetic.main.loop_fragment.* import kotlinx.android.synthetic.main.loop_fragment.*
@ -39,23 +42,21 @@ class LoopFragment : Fragment() {
override fun onResume() { override fun onResume() {
super.onResume() super.onResume()
disposable += RxBus disposable += RxBus
.toObservable(EventLoopUpdateGui::class.java) .toObservable(EventLoopUpdateGui::class.java)
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
.subscribe({ .subscribe({
updateGUI() updateGUI()
}, { }, {
FabricPrivacy.logException(it) FabricPrivacy.logException(it)
}) })
disposable += RxBus disposable += RxBus
.toObservable(EventLoopSetLastRunGui::class.java) .toObservable(EventLoopSetLastRunGui::class.java)
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
.subscribe({ .subscribe({
clearGUI() clearGUI()
loop_lastrun.text = it.text loop_lastrun?.text = it.text
}, { }, { FabricPrivacy.logException(it) })
FabricPrivacy.logException(it)
})
updateGUI() updateGUI()
SP.putBoolean(R.string.key_objectiveuseloop, true) SP.putBoolean(R.string.key_objectiveuseloop, true)
@ -71,39 +72,44 @@ class LoopFragment : Fragment() {
fun updateGUI() { fun updateGUI() {
if (loop_request == null) return if (loop_request == null) return
LoopPlugin.lastRun?.let { LoopPlugin.lastRun?.let {
loop_request.text = it.request?.toSpanned() ?: "" loop_request?.text = it.request?.toSpanned() ?: ""
loop_constraintsprocessed.text = it.constraintsProcessed?.toSpanned() ?: "" loop_constraintsprocessed?.text = it.constraintsProcessed?.toSpanned() ?: ""
loop_source.text = it.source ?: "" loop_source?.text = it.source ?: ""
loop_lastrun.text = it.lastAPSRun?.let { lastRun -> DateUtil.dateAndTimeString(lastRun.time) } loop_lastrun?.text = it.lastAPSRun?.let { lastRun -> DateUtil.dateAndTimeString(lastRun.time) }
?: "" ?: ""
loop_lastenact.text = it.lastAPSRun?.let { lastEnact -> DateUtil.dateAndTimeString(lastEnact.time) } loop_smbrequest_time?.text = DateUtil.dateAndTimeAndSecondsString(it.lastSMBRequest)
?: "" loop_smbexecution_time?.text = DateUtil.dateAndTimeAndSecondsString(it.lastSMBEnact)
loop_tbrsetbypump.text = it.tbrSetByPump?.let { tbrSetByPump -> HtmlHelper.fromHtml(tbrSetByPump.toHtml()) } loop_tbrrequest_time?.text = DateUtil.dateAndTimeAndSecondsString(it.lastTBRRequest)
?: "" loop_tbrexecution_time?.text = DateUtil.dateAndTimeAndSecondsString(it.lastTBREnact)
loop_smbsetbypump.text = it.smbSetByPump?.let { smbSetByPump -> HtmlHelper.fromHtml(smbSetByPump.toHtml()) }
?: "" loop_tbrsetbypump?.text = it.tbrSetByPump?.let { tbrSetByPump -> HtmlHelper.fromHtml(tbrSetByPump.toHtml()) }
?: ""
loop_smbsetbypump?.text = it.smbSetByPump?.let { smbSetByPump -> HtmlHelper.fromHtml(smbSetByPump.toHtml()) }
?: ""
val constraints = val constraints =
it.constraintsProcessed?.let { constraintsProcessed -> it.constraintsProcessed?.let { constraintsProcessed ->
val allConstraints = Constraint(0.0) val allConstraints = Constraint(0.0)
constraintsProcessed.rateConstraint?.let { rateConstraint -> allConstraints.copyReasons(rateConstraint) } constraintsProcessed.rateConstraint?.let { rateConstraint -> allConstraints.copyReasons(rateConstraint) }
constraintsProcessed.smbConstraint?.let { smbConstraint -> allConstraints.copyReasons(smbConstraint) } constraintsProcessed.smbConstraint?.let { smbConstraint -> allConstraints.copyReasons(smbConstraint) }
allConstraints.mostLimitedReasons allConstraints.mostLimitedReasons
} ?: "" } ?: ""
loop_constraints.text = constraints loop_constraints?.text = constraints
} }
} }
@Synchronized @Synchronized
private fun clearGUI() { private fun clearGUI() {
if (loop_request == null) return loop_request?.text = ""
loop_request.text = "" loop_constraints?.text = ""
loop_constraints.text = "" loop_constraintsprocessed?.text = ""
loop_constraintsprocessed.text = "" loop_source?.text = ""
loop_source.text = "" loop_lastrun?.text = ""
loop_lastrun.text = "" loop_smbrequest_time?.text = ""
loop_lastenact.text = "" loop_smbexecution_time?.text = ""
loop_tbrsetbypump.text = "" loop_tbrrequest_time?.text = ""
loop_smbsetbypump.text = "" loop_tbrexecution_time?.text = ""
loop_tbrsetbypump?.text = ""
loop_smbsetbypump?.text = ""
} }
} }

View file

@ -14,6 +14,8 @@ import android.os.SystemClock;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.core.app.NotificationCompat; import androidx.core.app.NotificationCompat;
import org.json.JSONException;
import org.json.JSONObject;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -50,17 +52,17 @@ import info.nightscout.androidaps.plugins.bus.RxBus;
import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin; import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.configBuilder.ProfileFunctions; import info.nightscout.androidaps.plugins.configBuilder.ProfileFunctions;
import info.nightscout.androidaps.plugins.general.nsclient.NSUpload; import info.nightscout.androidaps.plugins.general.nsclient.NSUpload;
import info.nightscout.androidaps.plugins.general.overview.dialogs.ErrorHelperActivity; import info.nightscout.androidaps.activities.ErrorHelperActivity;
import info.nightscout.androidaps.plugins.general.wear.ActionStringHandler; import info.nightscout.androidaps.plugins.general.wear.ActionStringHandler;
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventAutosensCalculationFinished; import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventAutosensCalculationFinished;
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;
import info.nightscout.androidaps.queue.Callback; import info.nightscout.androidaps.queue.Callback;
import info.nightscout.androidaps.queue.commands.Command; import info.nightscout.androidaps.queue.commands.Command;
import info.nightscout.androidaps.utils.DateUtil;
import info.nightscout.androidaps.utils.FabricPrivacy; import info.nightscout.androidaps.utils.FabricPrivacy;
import info.nightscout.androidaps.utils.SP; import info.nightscout.androidaps.utils.SP;
import info.nightscout.androidaps.utils.T; import info.nightscout.androidaps.utils.T;
import info.nightscout.androidaps.utils.ToastUtils;
import io.reactivex.disposables.CompositeDisposable; import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.schedulers.Schedulers; import io.reactivex.schedulers.Schedulers;
@ -85,9 +87,9 @@ public class LoopPlugin extends PluginBase {
return loopPlugin; return loopPlugin;
} }
private long loopSuspendedTill = 0L; // end of manual loop suspend private long loopSuspendedTill; // end of manual loop suspend
private boolean isSuperBolus = false; private boolean isSuperBolus;
private boolean isDisconnected = false; private boolean isDisconnected;
public class LastRun { public class LastRun {
public APSResult request = null; public APSResult request = null;
@ -96,8 +98,11 @@ public class LoopPlugin extends PluginBase {
public PumpEnactResult smbSetByPump = null; public PumpEnactResult smbSetByPump = null;
public String source = null; public String source = null;
public Date lastAPSRun = null; public Date lastAPSRun = null;
public Date lastEnact = null; public long lastTBREnact = 0;
public Date lastOpenModeAccept; public long lastSMBEnact = 0;
public long lastTBRRequest = 0;
public long lastSMBRequest = 0;
public long lastOpenModeAccept;
} }
static public LastRun lastRun = null; static public LastRun lastRun = null;
@ -343,6 +348,10 @@ public class LoopPlugin extends PluginBase {
lastRun.source = ((PluginBase) usedAPS).getName(); lastRun.source = ((PluginBase) usedAPS).getName();
lastRun.tbrSetByPump = null; lastRun.tbrSetByPump = null;
lastRun.smbSetByPump = null; lastRun.smbSetByPump = null;
lastRun.lastTBREnact = 0;
lastRun.lastTBRRequest = 0;
lastRun.lastSMBEnact = 0;
lastRun.lastSMBRequest = 0;
NSUpload.uploadDeviceStatus(); NSUpload.uploadDeviceStatus();
@ -379,14 +388,17 @@ public class LoopPlugin extends PluginBase {
public void run() { public void run() {
if (result.enacted || result.success) { if (result.enacted || result.success) {
lastRun.tbrSetByPump = result; lastRun.tbrSetByPump = result;
lastRun.lastEnact = lastRun.lastAPSRun; lastRun.lastTBRRequest = lastRun.lastAPSRun.getTime();
lastRun.lastTBREnact = DateUtil.now();
RxBus.INSTANCE.send(new EventLoopUpdateGui());
applySMBRequest(resultAfterConstraints, new Callback() { applySMBRequest(resultAfterConstraints, new Callback() {
@Override @Override
public void run() { public void run() {
//Callback is only called if a bolus was acutally requested //Callback is only called if a bolus was acutally requested
if (result.enacted || result.success) { if (result.enacted || result.success) {
lastRun.smbSetByPump = result; lastRun.smbSetByPump = result;
lastRun.lastEnact = lastRun.lastAPSRun; lastRun.lastSMBRequest = lastRun.lastAPSRun.getTime();
lastRun.lastSMBEnact = DateUtil.now();
} else { } else {
new Thread(() -> { new Thread(() -> {
SystemClock.sleep(1000); SystemClock.sleep(1000);
@ -466,8 +478,9 @@ public class LoopPlugin extends PluginBase {
public void run() { public void run() {
if (result.enacted) { if (result.enacted) {
lastRun.tbrSetByPump = result; lastRun.tbrSetByPump = result;
lastRun.lastEnact = new Date(); lastRun.lastTBRRequest = lastRun.lastAPSRun.getTime();
lastRun.lastOpenModeAccept = new Date(); lastRun.lastTBREnact = DateUtil.now();
lastRun.lastOpenModeAccept = DateUtil.now();
NSUpload.uploadDeviceStatus(); NSUpload.uploadDeviceStatus();
SP.incInt(R.string.key_ObjectivesmanualEnacts); SP.incInt(R.string.key_ObjectivesmanualEnacts);
} }
@ -686,7 +699,7 @@ public class LoopPlugin extends PluginBase {
} }
}); });
} }
NSUpload.uploadOpenAPSOffline(durationInMinutes); createOfflineEvent(durationInMinutes);
} }
public void suspendLoop(int durationInMinutes) { public void suspendLoop(int durationInMinutes) {
@ -704,7 +717,23 @@ public class LoopPlugin extends PluginBase {
} }
} }
}); });
NSUpload.uploadOpenAPSOffline(durationInMinutes); createOfflineEvent(durationInMinutes);
} }
public void createOfflineEvent(int durationInMinutes) {
JSONObject data = new JSONObject();
try {
data.put("eventType", CareportalEvent.OPENAPSOFFLINE);
data.put("duration", durationInMinutes);
} catch (JSONException e) {
log.error("Unhandled exception", e);
}
CareportalEvent event = new CareportalEvent();
event.date = DateUtil.now();
event.source = Source.USER;
event.eventType = CareportalEvent.OPENAPSOFFLINE;
event.json = data.toString();
MainApp.getDbHelper().createOrUpdate(event);
NSUpload.uploadOpenAPSOffline(event);
}
} }

View file

@ -23,6 +23,7 @@ import javax.annotation.Nullable;
import info.nightscout.androidaps.Constants; 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.plugins.configBuilder.ProfileFunctions;
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus; import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus;
import info.nightscout.androidaps.data.IobTotal; import info.nightscout.androidaps.data.IobTotal;
import info.nightscout.androidaps.data.MealData; import info.nightscout.androidaps.data.MealData;
@ -194,8 +195,6 @@ public class DetermineBasalAdapterAMAJS {
double autosensDataRatio, double autosensDataRatio,
boolean tempTargetSet) throws JSONException { boolean tempTargetSet) throws JSONException {
String units = profile.getUnits();
mProfile = new JSONObject(); mProfile = new JSONObject();
mProfile.put("max_iob", maxIob); mProfile.put("max_iob", maxIob);
mProfile.put("dia", Math.min(profile.getDia(), 3d)); mProfile.put("dia", Math.min(profile.getDia(), 3d));
@ -206,7 +205,7 @@ public class DetermineBasalAdapterAMAJS {
mProfile.put("max_bg", maxBg); mProfile.put("max_bg", maxBg);
mProfile.put("target_bg", targetBg); mProfile.put("target_bg", targetBg);
mProfile.put("carb_ratio", profile.getIc()); mProfile.put("carb_ratio", profile.getIc());
mProfile.put("sens", Profile.toMgdl(profile.getIsf(), units)); mProfile.put("sens", profile.getIsfMgdl());
mProfile.put("max_daily_safety_multiplier", SP.getInt(R.string.key_openapsama_max_daily_safety_multiplier, 3)); 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("current_basal_safety_multiplier", SP.getDouble(R.string.key_openapsama_current_basal_safety_multiplier, 4d));
mProfile.put("skip_neutral_temps", true); mProfile.put("skip_neutral_temps", true);
@ -220,7 +219,7 @@ public class DetermineBasalAdapterAMAJS {
mProfile.put("min_5m_carbimpact", SP.getDouble(R.string.key_openapsama_min_5m_carbimpact, SMBDefaults.min_5m_carbimpact)); mProfile.put("min_5m_carbimpact", SP.getDouble(R.string.key_openapsama_min_5m_carbimpact, SMBDefaults.min_5m_carbimpact));
} }
if (units.equals(Constants.MMOL)) { if (ProfileFunctions.getSystemUnits().equals(Constants.MMOL)) {
mProfile.put("out_units", "mmol/L"); mProfile.put("out_units", "mmol/L");
} }

View file

@ -107,6 +107,13 @@ public class OpenAPSAMAPlugin extends PluginBase implements APSInterface {
return; return;
} }
if (pump == null) {
RxBus.INSTANCE.send(new EventOpenAPSUpdateResultGui(MainApp.gs(R.string.nopumpselected)));
if (L.isEnabled(L.APS))
log.debug(MainApp.gs(R.string.nopumpselected));
return;
}
if (!isEnabled(PluginType.APS)) { if (!isEnabled(PluginType.APS)) {
RxBus.INSTANCE.send(new EventOpenAPSUpdateResultGui(MainApp.gs(R.string.openapsma_disabled))); RxBus.INSTANCE.send(new EventOpenAPSUpdateResultGui(MainApp.gs(R.string.openapsma_disabled)));
if (L.isEnabled(L.APS)) if (L.isEnabled(L.APS))
@ -121,12 +128,10 @@ public class OpenAPSAMAPlugin extends PluginBase implements APSInterface {
return; return;
} }
String units = profile.getUnits();
double maxBasal = MainApp.getConstraintChecker().getMaxBasalAllowed(profile).value(); double maxBasal = MainApp.getConstraintChecker().getMaxBasalAllowed(profile).value();
double minBg = Profile.toMgdl(profile.getTargetLow(), units); double minBg = profile.getTargetLowMgdl();
double maxBg = Profile.toMgdl(profile.getTargetHigh(), units); double maxBg = profile.getTargetHighMgdl();
double targetBg = Profile.toMgdl(profile.getTarget(), units); double targetBg = profile.getTargetMgdl();
minBg = Round.roundTo(minBg, 0.1d); minBg = Round.roundTo(minBg, 0.1d);
maxBg = Round.roundTo(maxBg, 0.1d); maxBg = Round.roundTo(maxBg, 0.1d);
@ -162,7 +167,7 @@ public class OpenAPSAMAPlugin extends PluginBase implements APSInterface {
return; return;
if (!HardLimits.checkOnlyHardLimits(profile.getIcTimeFromMidnight(Profile.secondsFromMidnight()), "carbratio", HardLimits.MINIC, HardLimits.MAXIC)) if (!HardLimits.checkOnlyHardLimits(profile.getIcTimeFromMidnight(Profile.secondsFromMidnight()), "carbratio", HardLimits.MINIC, HardLimits.MAXIC))
return; return;
if (!HardLimits.checkOnlyHardLimits(Profile.toMgdl(profile.getIsf(), units), "sens", HardLimits.MINISF, HardLimits.MAXISF)) if (!HardLimits.checkOnlyHardLimits(profile.getIsfMgdl(), "sens", HardLimits.MINISF, HardLimits.MAXISF))
return; return;
if (!HardLimits.checkOnlyHardLimits(profile.getMaxDailyBasal(), "max_daily_basal", 0.02, HardLimits.maxBasal())) if (!HardLimits.checkOnlyHardLimits(profile.getMaxDailyBasal(), "max_daily_basal", 0.02, HardLimits.maxBasal()))
return; return;

View file

@ -20,6 +20,7 @@ import javax.annotation.Nullable;
import info.nightscout.androidaps.Constants; import info.nightscout.androidaps.Constants;
import info.nightscout.androidaps.R; import info.nightscout.androidaps.R;
import info.nightscout.androidaps.plugins.configBuilder.ProfileFunctions;
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus; import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus;
import info.nightscout.androidaps.data.IobTotal; import info.nightscout.androidaps.data.IobTotal;
import info.nightscout.androidaps.data.MealData; import info.nightscout.androidaps.data.MealData;
@ -160,8 +161,6 @@ public class DetermineBasalAdapterMAJS {
GlucoseStatus glucoseStatus, GlucoseStatus glucoseStatus,
MealData mealData) throws JSONException { MealData mealData) throws JSONException {
String units = profile.getUnits();
mProfile = new JSONObject(); mProfile = new JSONObject();
mProfile.put("max_iob", maxIob); mProfile.put("max_iob", maxIob);
mProfile.put("dia", Math.min(profile.getDia(), 3d)); mProfile.put("dia", Math.min(profile.getDia(), 3d));
@ -172,11 +171,11 @@ public class DetermineBasalAdapterMAJS {
mProfile.put("max_bg", maxBg); mProfile.put("max_bg", maxBg);
mProfile.put("target_bg", targetBg); mProfile.put("target_bg", targetBg);
mProfile.put("carb_ratio", profile.getIc()); mProfile.put("carb_ratio", profile.getIc());
mProfile.put("sens", Profile.toMgdl(profile.getIsf(), units)); mProfile.put("sens", profile.getIsfMgdl());
mProfile.put("current_basal", basalRate); mProfile.put("current_basal", basalRate);
if (units.equals(Constants.MMOL)) { if (ProfileFunctions.getSystemUnits().equals(Constants.MMOL)) {
mProfile.put("out_units", "mmol/L"); mProfile.put("out_units", "mmol/L");
} }

View file

@ -106,6 +106,13 @@ public class OpenAPSMAPlugin extends PluginBase implements APSInterface {
return; return;
} }
if (pump == null) {
RxBus.INSTANCE.send(new EventOpenAPSUpdateResultGui(MainApp.gs(R.string.nopumpselected)));
if (L.isEnabled(L.APS))
log.debug(MainApp.gs(R.string.nopumpselected));
return;
}
if (!isEnabled(PluginType.APS)) { if (!isEnabled(PluginType.APS)) {
RxBus.INSTANCE.send(new EventOpenAPSUpdateResultGui(MainApp.gs(R.string.openapsma_disabled))); RxBus.INSTANCE.send(new EventOpenAPSUpdateResultGui(MainApp.gs(R.string.openapsma_disabled)));
if (L.isEnabled(L.APS)) if (L.isEnabled(L.APS))
@ -120,13 +127,11 @@ public class OpenAPSMAPlugin extends PluginBase implements APSInterface {
return; return;
} }
String units = profile.getUnits();
double maxBasal = MainApp.getConstraintChecker().getMaxBasalAllowed(profile).value(); double maxBasal = MainApp.getConstraintChecker().getMaxBasalAllowed(profile).value();
double minBg = Profile.toMgdl(profile.getTargetLow(), units); double minBg = profile.getTargetLowMgdl();
double maxBg = Profile.toMgdl(profile.getTargetHigh(), units); double maxBg = profile.getTargetHighMgdl();
double targetBg = Profile.toMgdl(profile.getTarget(), units); double targetBg = profile.getTargetMgdl();
minBg = Round.roundTo(minBg, 0.1d); minBg = Round.roundTo(minBg, 0.1d);
maxBg = Round.roundTo(maxBg, 0.1d); maxBg = Round.roundTo(maxBg, 0.1d);
@ -160,7 +165,7 @@ public class OpenAPSMAPlugin extends PluginBase implements APSInterface {
return; return;
if (!checkOnlyHardLimits(profile.getIcTimeFromMidnight(Profile.secondsFromMidnight()), "carbratio", HardLimits.MINIC, HardLimits.MAXIC)) if (!checkOnlyHardLimits(profile.getIcTimeFromMidnight(Profile.secondsFromMidnight()), "carbratio", HardLimits.MINIC, HardLimits.MAXIC))
return; return;
if (!checkOnlyHardLimits(Profile.toMgdl(profile.getIsf(), units), "sens", HardLimits.MINISF, HardLimits.MAXISF)) if (!checkOnlyHardLimits(profile.getIsfMgdl(), "sens", HardLimits.MINISF, HardLimits.MAXISF))
return; return;
if (!checkOnlyHardLimits(profile.getMaxDailyBasal(), "max_daily_basal", 0.02, HardLimits.maxBasal())) if (!checkOnlyHardLimits(profile.getMaxDailyBasal(), "max_daily_basal", 0.02, HardLimits.maxBasal()))
return; return;

View file

@ -23,6 +23,7 @@ import javax.annotation.Nullable;
import info.nightscout.androidaps.Constants; 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.plugins.configBuilder.ProfileFunctions;
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus; import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus;
import info.nightscout.androidaps.data.IobTotal; import info.nightscout.androidaps.data.IobTotal;
import info.nightscout.androidaps.data.MealData; import info.nightscout.androidaps.data.MealData;
@ -219,8 +220,6 @@ public class DetermineBasalAdapterSMBJS {
boolean advancedFiltering boolean advancedFiltering
) throws JSONException { ) throws JSONException {
String units = profile.getUnits();
mProfile = new JSONObject(); mProfile = new JSONObject();
mProfile.put("max_iob", maxIob); mProfile.put("max_iob", maxIob);
@ -232,7 +231,7 @@ public class DetermineBasalAdapterSMBJS {
mProfile.put("max_bg", maxBg); mProfile.put("max_bg", maxBg);
mProfile.put("target_bg", targetBg); mProfile.put("target_bg", targetBg);
mProfile.put("carb_ratio", profile.getIc()); mProfile.put("carb_ratio", profile.getIc());
mProfile.put("sens", Profile.toMgdl(profile.getIsf(), units)); mProfile.put("sens", profile.getIsfMgdl());
mProfile.put("max_daily_safety_multiplier", SP.getInt(R.string.key_openapsama_max_daily_safety_multiplier, 3)); 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("current_basal_safety_multiplier", SP.getDouble(R.string.key_openapsama_current_basal_safety_multiplier, 4d));
@ -273,7 +272,7 @@ public class DetermineBasalAdapterSMBJS {
mProfile.put("temptargetSet", tempTargetSet); mProfile.put("temptargetSet", tempTargetSet);
mProfile.put("autosens_max", SafeParse.stringToDouble(SP.getString(R.string.key_openapsama_autosens_max, "1.2"))); mProfile.put("autosens_max", SafeParse.stringToDouble(SP.getString(R.string.key_openapsama_autosens_max, "1.2")));
if (units.equals(Constants.MMOL)) { if (ProfileFunctions.getSystemUnits().equals(Constants.MMOL)) {
mProfile.put("out_units", "mmol/L"); mProfile.put("out_units", "mmol/L");
} }

View file

@ -111,6 +111,13 @@ public class OpenAPSSMBPlugin extends PluginBase implements APSInterface, Constr
return; return;
} }
if (pump == null) {
RxBus.INSTANCE.send(new EventOpenAPSUpdateResultGui(MainApp.gs(R.string.nopumpselected)));
if (L.isEnabled(L.APS))
log.debug(MainApp.gs(R.string.nopumpselected));
return;
}
if (!isEnabled(PluginType.APS)) { if (!isEnabled(PluginType.APS)) {
RxBus.INSTANCE.send(new EventOpenAPSUpdateResultGui(MainApp.gs(R.string.openapsma_disabled))); RxBus.INSTANCE.send(new EventOpenAPSUpdateResultGui(MainApp.gs(R.string.openapsma_disabled)));
if (L.isEnabled(L.APS)) if (L.isEnabled(L.APS))
@ -125,16 +132,14 @@ public class OpenAPSSMBPlugin extends PluginBase implements APSInterface, Constr
return; return;
} }
String units = profile.getUnits();
Constraint<Double> inputConstraints = new Constraint<>(0d); // fake. only for collecting all results Constraint<Double> inputConstraints = new Constraint<>(0d); // fake. only for collecting all results
Constraint<Double> maxBasalConstraint = MainApp.getConstraintChecker().getMaxBasalAllowed(profile); Constraint<Double> maxBasalConstraint = MainApp.getConstraintChecker().getMaxBasalAllowed(profile);
inputConstraints.copyReasons(maxBasalConstraint); inputConstraints.copyReasons(maxBasalConstraint);
double maxBasal = maxBasalConstraint.value(); double maxBasal = maxBasalConstraint.value();
double minBg = Profile.toMgdl(profile.getTargetLow(), units); double minBg = profile.getTargetLowMgdl();
double maxBg = Profile.toMgdl(profile.getTargetHigh(), units); double maxBg = profile.getTargetHighMgdl();
double targetBg = Profile.toMgdl(profile.getTarget(), units); double targetBg = profile.getTargetMgdl();
minBg = Round.roundTo(minBg, 0.1d); minBg = Round.roundTo(minBg, 0.1d);
maxBg = Round.roundTo(maxBg, 0.1d); maxBg = Round.roundTo(maxBg, 0.1d);
@ -168,7 +173,7 @@ public class OpenAPSSMBPlugin extends PluginBase implements APSInterface, Constr
return; return;
if (!checkOnlyHardLimits(profile.getIcTimeFromMidnight(Profile.secondsFromMidnight()), "carbratio", HardLimits.MINIC, HardLimits.MAXIC)) if (!checkOnlyHardLimits(profile.getIcTimeFromMidnight(Profile.secondsFromMidnight()), "carbratio", HardLimits.MINIC, HardLimits.MAXIC))
return; return;
if (!checkOnlyHardLimits(Profile.toMgdl(profile.getIsf(), units), "sens", HardLimits.MINISF, HardLimits.MAXISF)) if (!checkOnlyHardLimits(profile.getIsfMgdl(), "sens", HardLimits.MINISF, HardLimits.MAXISF))
return; return;
if (!checkOnlyHardLimits(profile.getMaxDailyBasal(), "max_daily_basal", 0.02, HardLimits.maxBasal())) if (!checkOnlyHardLimits(profile.getMaxDailyBasal(), "max_daily_basal", 0.02, HardLimits.maxBasal()))
return; return;

View file

@ -2,7 +2,11 @@ package info.nightscout.androidaps.plugins.configBuilder
import android.content.Intent import android.content.Intent
import android.view.View import android.view.View
import android.widget.* import android.widget.CheckBox
import android.widget.ImageButton
import android.widget.LinearLayout
import android.widget.RadioButton
import android.widget.TextView
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.activities.PreferencesActivity import info.nightscout.androidaps.activities.PreferencesActivity
import info.nightscout.androidaps.events.EventRebuildTabs import info.nightscout.androidaps.events.EventRebuildTabs
@ -10,6 +14,7 @@ import info.nightscout.androidaps.interfaces.PluginBase
import info.nightscout.androidaps.interfaces.PluginType import info.nightscout.androidaps.interfaces.PluginType
import info.nightscout.androidaps.plugins.bus.RxBus import info.nightscout.androidaps.plugins.bus.RxBus
import info.nightscout.androidaps.utils.PasswordProtection import info.nightscout.androidaps.utils.PasswordProtection
import info.nightscout.androidaps.utils.toVisibility
class PluginViewHolder internal constructor(private val fragment: ConfigBuilderFragment, class PluginViewHolder internal constructor(private val fragment: ConfigBuilderFragment,
private val pluginType: PluginType, private val pluginType: PluginType,
@ -56,8 +61,8 @@ class PluginViewHolder internal constructor(private val fragment: ConfigBuilderF
} }
fun update() { fun update() {
enabledExclusive.visibility = if (areMultipleSelectionsAllowed(pluginType)) View.GONE else View.VISIBLE enabledExclusive.visibility = areMultipleSelectionsAllowed(pluginType).not().toVisibility()
enabledInclusive.visibility = if (areMultipleSelectionsAllowed(pluginType)) View.VISIBLE else View.GONE enabledInclusive.visibility = areMultipleSelectionsAllowed(pluginType).toVisibility()
enabledExclusive.isChecked = plugin.isEnabled(pluginType) enabledExclusive.isChecked = plugin.isEnabled(pluginType)
enabledInclusive.isChecked = plugin.isEnabled(pluginType) enabledInclusive.isChecked = plugin.isEnabled(pluginType)
enabledInclusive.isEnabled = !plugin.pluginDescription.alwaysEnabled enabledInclusive.isEnabled = !plugin.pluginDescription.alwaysEnabled
@ -70,7 +75,7 @@ class PluginViewHolder internal constructor(private val fragment: ConfigBuilderF
pluginDescription.text = plugin.description pluginDescription.text = plugin.description
} }
pluginPreferences.visibility = if (plugin.preferencesId == -1 || !plugin.isEnabled(pluginType)) View.INVISIBLE else View.VISIBLE pluginPreferences.visibility = if (plugin.preferencesId == -1 || !plugin.isEnabled(pluginType)) View.INVISIBLE else View.VISIBLE
pluginVisibility.visibility = if (plugin.hasFragment()) View.VISIBLE else View.INVISIBLE pluginVisibility.visibility = plugin.hasFragment().toVisibility()
pluginVisibility.isEnabled = !(plugin.pluginDescription.neverVisible || plugin.pluginDescription.alwaysVisible) && plugin.isEnabled(pluginType) pluginVisibility.isEnabled = !(plugin.pluginDescription.neverVisible || plugin.pluginDescription.alwaysVisible) && plugin.isEnabled(pluginType)
pluginVisibility.isChecked = plugin.isFragmentVisible pluginVisibility.isChecked = plugin.isFragmentVisible
} }

View file

@ -24,7 +24,7 @@ import info.nightscout.androidaps.interfaces.ProfileInterface;
import info.nightscout.androidaps.interfaces.TreatmentsInterface; import info.nightscout.androidaps.interfaces.TreatmentsInterface;
import info.nightscout.androidaps.logging.L; import info.nightscout.androidaps.logging.L;
import info.nightscout.androidaps.plugins.bus.RxBus; import info.nightscout.androidaps.plugins.bus.RxBus;
import info.nightscout.androidaps.plugins.general.overview.dialogs.ErrorHelperActivity; import info.nightscout.androidaps.activities.ErrorHelperActivity;
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin; import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin;
import info.nightscout.androidaps.queue.Callback; import info.nightscout.androidaps.queue.Callback;
import info.nightscout.androidaps.utils.DateUtil; import info.nightscout.androidaps.utils.DateUtil;
@ -124,9 +124,8 @@ public class ProfileFunctions {
return getProfile(System.currentTimeMillis()); return getProfile(System.currentTimeMillis());
} }
public String getProfileUnits() { public static String getSystemUnits() {
Profile profile = getProfile(); return SP.getString(R.string.key_units, Constants.MGDL);
return profile != null ? profile.getUnits() : Constants.MGDL;
} }
@Nullable @Nullable
@ -171,8 +170,8 @@ public class ProfileFunctions {
return profileSwitch; return profileSwitch;
} }
public static void doProfileSwitch(final ProfileStore profileStore, final String profileName, final int duration, final int percentage, final int timeshift) { public static void doProfileSwitch(final ProfileStore profileStore, final String profileName, final int duration, final int percentage, final int timeshift, final long date) {
ProfileSwitch profileSwitch = prepareProfileSwitch(profileStore, profileName, duration, percentage, timeshift, System.currentTimeMillis()); ProfileSwitch profileSwitch = prepareProfileSwitch(profileStore, profileName, duration, percentage, timeshift, date);
TreatmentsPlugin.getPlugin().addToHistoryProfileSwitch(profileSwitch); TreatmentsPlugin.getPlugin().addToHistoryProfileSwitch(profileSwitch);
if (percentage == 90 && duration == 10) if (percentage == 90 && duration == 10)
SP.putBoolean(R.string.key_objectiveuseprofileswitch, true); SP.putBoolean(R.string.key_objectiveuseprofileswitch, true);

View file

@ -28,6 +28,7 @@ import info.nightscout.androidaps.plugins.constraints.objectives.events.EventNtp
import info.nightscout.androidaps.plugins.constraints.objectives.events.EventObjectivesUpdateGui import info.nightscout.androidaps.plugins.constraints.objectives.events.EventObjectivesUpdateGui
import info.nightscout.androidaps.plugins.constraints.objectives.objectives.Objective.ExamTask import info.nightscout.androidaps.plugins.constraints.objectives.objectives.Objective.ExamTask
import info.nightscout.androidaps.receivers.NetworkChangeReceiver import info.nightscout.androidaps.receivers.NetworkChangeReceiver
import info.nightscout.androidaps.setupwizard.events.EventSWUpdate
import info.nightscout.androidaps.utils.* import info.nightscout.androidaps.utils.*
import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable import io.reactivex.disposables.CompositeDisposable
@ -71,13 +72,13 @@ class ObjectivesFragment : Fragment() {
override fun onResume() { override fun onResume() {
super.onResume() super.onResume()
disposable.add(RxBus disposable.add(RxBus
.toObservable(EventObjectivesUpdateGui::class.java) .toObservable(EventObjectivesUpdateGui::class.java)
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
.subscribe({ .subscribe({
objectives_recyclerview.adapter?.notifyDataSetChanged() objectives_recyclerview.adapter?.notifyDataSetChanged()
}, { }, {
FabricPrivacy.logException(it) FabricPrivacy.logException(it)
}) })
) )
} }
@ -217,6 +218,7 @@ class ObjectivesFragment : Fragment() {
scrollToCurrentObjective() scrollToCurrentObjective()
startUpdateTimer() startUpdateTimer()
RxBus.send(EventObjectivesUpdateGui()) RxBus.send(EventObjectivesUpdateGui())
RxBus.send(EventSWUpdate(false))
} else { } else {
// move out of UI thread // move out of UI thread
Thread { Thread {
@ -234,6 +236,7 @@ class ObjectivesFragment : Fragment() {
RxBus.send(EventNtpStatus(MainApp.gs(R.string.success), 100)) RxBus.send(EventNtpStatus(MainApp.gs(R.string.success), 100))
SystemClock.sleep(1000) SystemClock.sleep(1000)
RxBus.send(EventObjectivesUpdateGui()) RxBus.send(EventObjectivesUpdateGui())
RxBus.send(EventSWUpdate(false))
SystemClock.sleep(100) SystemClock.sleep(100)
scrollToCurrentObjective() scrollToCurrentObjective()
} else { } else {
@ -254,6 +257,7 @@ class ObjectivesFragment : Fragment() {
scrollToCurrentObjective() scrollToCurrentObjective()
startUpdateTimer() startUpdateTimer()
RxBus.send(EventObjectivesUpdateGui()) RxBus.send(EventObjectivesUpdateGui())
RxBus.send(EventSWUpdate(false))
} else } else
// move out of UI thread // move out of UI thread
Thread { Thread {
@ -270,6 +274,7 @@ class ObjectivesFragment : Fragment() {
RxBus.send(EventNtpStatus(MainApp.gs(R.string.success), 100)) RxBus.send(EventNtpStatus(MainApp.gs(R.string.success), 100))
SystemClock.sleep(1000) SystemClock.sleep(1000)
RxBus.send(EventObjectivesUpdateGui()) RxBus.send(EventObjectivesUpdateGui())
RxBus.send(EventSWUpdate(false))
SystemClock.sleep(100) SystemClock.sleep(100)
scrollToCurrentObjective() scrollToCurrentObjective()
} else { } else {
@ -280,16 +285,20 @@ class ObjectivesFragment : Fragment() {
}.start() }.start()
} }
holder.unStart.setOnClickListener { holder.unStart.setOnClickListener {
OKDialog.showConfirmation(activity, MainApp.gs(R.string.doyouwantresetstart)) { activity?.let { activity ->
objective.startedOn = 0 OKDialog.showConfirmation(activity, MainApp.gs(R.string.objectives), MainApp.gs(R.string.doyouwantresetstart), Runnable {
scrollToCurrentObjective() objective.startedOn = 0
RxBus.send(EventObjectivesUpdateGui()) scrollToCurrentObjective()
RxBus.send(EventObjectivesUpdateGui())
RxBus.send(EventSWUpdate(false))
})
} }
} }
holder.unFinish.setOnClickListener { holder.unFinish.setOnClickListener {
objective.accomplishedOn = 0 objective.accomplishedOn = 0
scrollToCurrentObjective() scrollToCurrentObjective()
RxBus.send(EventObjectivesUpdateGui()) RxBus.send(EventObjectivesUpdateGui())
RxBus.send(EventSWUpdate(false))
} }
if (objective.hasSpecialInput && !objective.isAccomplished && objective.isStarted && objective.specialActionEnabled()) { if (objective.hasSpecialInput && !objective.isAccomplished && objective.isStarted && objective.specialActionEnabled()) {
// generate random request code if none exists // generate random request code if none exists
@ -313,7 +322,6 @@ class ObjectivesFragment : Fragment() {
} }
} }
override fun getItemCount(): Int { override fun getItemCount(): Int {
return ObjectivesPlugin.objectives.size return ObjectivesPlugin.objectives.size
} }

View file

@ -122,9 +122,9 @@ object ObjectivesPlugin : PluginBase(PluginDescription()
SP.putLong("Objectives_" + "smb" + "_started", DateUtil.now()) SP.putLong("Objectives_" + "smb" + "_started", DateUtil.now())
SP.putLong("Objectives_" + "smb" + "_accomplished", DateUtil.now()) SP.putLong("Objectives_" + "smb" + "_accomplished", DateUtil.now())
setupObjectives() setupObjectives()
OKDialog.show(activity, "", MainApp.gs(R.string.codeaccepted), null) OKDialog.show(activity, MainApp.gs(R.string.objectives), MainApp.gs(R.string.codeaccepted))
} else { } else {
OKDialog.show(activity, "", MainApp.gs(R.string.codeinvalid), null) OKDialog.show(activity, MainApp.gs(R.string.objectives), MainApp.gs(R.string.codeinvalid))
} }
} }

View file

@ -14,7 +14,7 @@ import info.nightscout.androidaps.plugins.constraints.objectives.events.EventNtp
import info.nightscout.androidaps.utils.FabricPrivacy import info.nightscout.androidaps.utils.FabricPrivacy
import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable import io.reactivex.disposables.CompositeDisposable
import kotlinx.android.synthetic.main.overview_bolusprogress_dialog.* import kotlinx.android.synthetic.main.dialog_bolusprogress.*
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
class NtpProgressDialog : DialogFragment() { class NtpProgressDialog : DialogFragment() {
@ -33,16 +33,17 @@ class NtpProgressDialog : DialogFragment() {
state = savedInstanceState?.getString("state", DEFAULT_STATE) ?: DEFAULT_STATE state = savedInstanceState?.getString("state", DEFAULT_STATE) ?: DEFAULT_STATE
percent = savedInstanceState?.getInt("percent", 0) ?: 0 percent = savedInstanceState?.getInt("percent", 0) ?: 0
return inflater.inflate(R.layout.overview_bolusprogress_dialog, container, false) return inflater.inflate(R.layout.dialog_bolusprogress, container, false)
} }
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
overview_bolusprogress_stop.setOnClickListener { dismiss() } overview_bolusprogress_stop.setOnClickListener { dismiss() }
overview_bolusprogress_status.setText(state) overview_bolusprogress_status.text = state
overview_bolusprogress_progressbar.setMax(100) overview_bolusprogress_progressbar.max = 100
overview_bolusprogress_progressbar.setProgress(percent) overview_bolusprogress_progressbar.progress = percent
overview_bolusprogress_stop.text = MainApp.gs(R.string.close) overview_bolusprogress_stop.text = MainApp.gs(R.string.close)
overview_bolusprogress_title.text = MainApp.gs(R.string.please_wait)
} }
override fun onResume() { override fun onResume() {

View file

@ -0,0 +1,35 @@
package info.nightscout.androidaps.plugins.constraints.phoneChecker
import android.os.Build
import com.scottyab.rootbeer.RootBeer
import info.nightscout.androidaps.MainApp
import info.nightscout.androidaps.R
import info.nightscout.androidaps.interfaces.ConstraintsInterface
import info.nightscout.androidaps.interfaces.PluginBase
import info.nightscout.androidaps.interfaces.PluginDescription
import info.nightscout.androidaps.interfaces.PluginType
object PhoneCheckerPlugin : PluginBase(PluginDescription()
.mainType(PluginType.CONSTRAINTS)
.neverVisible(true)
.alwaysEnabled(true)
.showInList(false)
.pluginName(R.string.phonechecker)
), ConstraintsInterface {
var phoneRooted: Boolean = false
var devMode: Boolean = false
val phoneModel: String = Build.MODEL
val manufacturer: String = Build.MANUFACTURER
private fun isDevModeEnabled(): Boolean {
return android.provider.Settings.Secure.getInt(MainApp.instance().contentResolver,
android.provider.Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 0) != 0;
}
override fun onStart() {
super.onStart()
phoneRooted = RootBeer(MainApp.instance()).isRootedWithoutBusyBoxCheck()
devMode = isDevModeEnabled()
}
}

View file

@ -21,6 +21,7 @@ import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification; import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification;
import info.nightscout.androidaps.plugins.general.overview.notifications.Notification; import info.nightscout.androidaps.plugins.general.overview.notifications.Notification;
import info.nightscout.androidaps.plugins.sensitivity.SensitivityOref1Plugin; 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.DecimalFormatter;
import info.nightscout.androidaps.utils.HardLimits; import info.nightscout.androidaps.utils.HardLimits;
import info.nightscout.androidaps.utils.Round; import info.nightscout.androidaps.utils.Round;
@ -73,7 +74,10 @@ public class SafetyPlugin extends PluginBase implements ConstraintsInterface {
} }
value.set(false, MainApp.gs(R.string.closed_loop_disabled_on_dev_branch), this); value.set(false, MainApp.gs(R.string.closed_loop_disabled_on_dev_branch), this);
} }
PumpInterface pump = ConfigBuilderPlugin.getPlugin().getActivePump();
if (pump != null && !pump.isFakingTempsByExtendedBoluses() && TreatmentsPlugin.getPlugin().isInHistoryExtendedBoluslInProgress()) {
value.set(false, MainApp.gs(R.string.closed_loop_disabled_with_eb), this);
}
return value; return value;
} }

View file

@ -1,13 +1,19 @@
package info.nightscout.androidaps.plugins.constraints.versionChecker package info.nightscout.androidaps.plugins.constraints.versionChecker
import info.nightscout.androidaps.BuildConfig
import info.nightscout.androidaps.MainApp import info.nightscout.androidaps.MainApp
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.interfaces.* 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.plugins.bus.RxBus import info.nightscout.androidaps.plugins.bus.RxBus
import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification
import info.nightscout.androidaps.plugins.general.overview.notifications.Notification import info.nightscout.androidaps.plugins.general.overview.notifications.Notification
import info.nightscout.androidaps.utils.SP import info.nightscout.androidaps.utils.SP
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
import kotlin.math.roundToInt
/** /**
* Usually we would have a class here. * Usually we would have a class here.
@ -16,16 +22,23 @@ import java.util.concurrent.TimeUnit
* */ * */
object VersionCheckerPlugin : PluginBase(PluginDescription() object VersionCheckerPlugin : PluginBase(PluginDescription()
.mainType(PluginType.CONSTRAINTS) .mainType(PluginType.CONSTRAINTS)
.neverVisible(true) .neverVisible(true)
.alwaysEnabled(true) .alwaysEnabled(true)
.showInList(false) .showInList(false)
.pluginName(R.string.versionChecker)), ConstraintsInterface { .pluginName(R.string.versionChecker)), ConstraintsInterface {
private val gracePeriod: GracePeriod
get() = if ((BuildConfig.VERSION_NAME.contains("RC", ignoreCase = true))) {
GracePeriod.RC
} else {
GracePeriod.RELEASE
}
override fun isClosedLoopAllowed(value: Constraint<Boolean>): Constraint<Boolean> { override fun isClosedLoopAllowed(value: Constraint<Boolean>): Constraint<Boolean> {
checkWarning() checkWarning()
triggerCheckVersion() triggerCheckVersion()
return if (isOldVersion(GRACE_PERIOD_VERY_OLD)) return if (isOldVersion(gracePeriod.veryOld.daysToMillis()))
value.set(false, MainApp.gs(R.string.very_old_version), this) value.set(false, MainApp.gs(R.string.very_old_version), this)
else else
value value
@ -33,41 +46,49 @@ object VersionCheckerPlugin : PluginBase(PluginDescription()
private fun checkWarning() { private fun checkWarning() {
val now = System.currentTimeMillis() val now = System.currentTimeMillis()
if (!SP.contains(R.string.key_last_versionchecker_plugin_warning)) { if (!SP.contains(R.string.key_last_versionchecker_plugin_warning)) {
SP.putLong(R.string.key_last_versionchecker_plugin_warning, now) SP.putLong(R.string.key_last_versionchecker_plugin_warning, now)
return return
} }
if (isOldVersion(GRACE_PERIOD_WARNING) && shouldWarnAgain(now)) { if (isOldVersion(gracePeriod.warning.daysToMillis()) && shouldWarnAgain(now)) {
// store last notification time // store last notification time
SP.putLong(R.string.key_last_versionchecker_plugin_warning, now) SP.putLong(R.string.key_last_versionchecker_plugin_warning, now)
//notify //notify
val message = MainApp.gs(R.string.new_version_warning, Math.round((now - SP.getLong(R.string.key_last_time_this_version_detected, now)) / TimeUnit.DAYS.toMillis(1).toDouble())) val message = MainApp.gs(R.string.new_version_warning,
((now - SP.getLong(R.string.key_last_time_this_version_detected, now)) / 1L.daysToMillis().toDouble()).roundToInt(),
gracePeriod.old,
gracePeriod.veryOld
)
val notification = Notification(Notification.OLDVERSION, message, Notification.NORMAL) val notification = Notification(Notification.OLDVERSION, message, Notification.NORMAL)
RxBus.send(EventNewNotification(notification)) RxBus.send(EventNewNotification(notification))
} }
} }
private fun shouldWarnAgain(now: Long) = private fun shouldWarnAgain(now: Long) =
now > SP.getLong(R.string.key_last_versionchecker_plugin_warning, 0) + WARN_EVERY now > SP.getLong(R.string.key_last_versionchecker_plugin_warning, 0) + WARN_EVERY
override fun applyMaxIOBConstraints(maxIob: Constraint<Double>): Constraint<Double> = override fun applyMaxIOBConstraints(maxIob: Constraint<Double>): Constraint<Double> =
if (isOldVersion(GRACE_PERIOD_OLD)) if (isOldVersion(gracePeriod.old.daysToMillis()))
maxIob.set(0.toDouble(), MainApp.gs(R.string.old_version), this) maxIob.set(0.toDouble(), MainApp.gs(R.string.old_version), this)
else else
maxIob maxIob
private fun isOldVersion(gracePeriod: Long): Boolean { private fun isOldVersion(gracePeriod: Long): Boolean {
val now = System.currentTimeMillis() val now = System.currentTimeMillis()
return now > SP.getLong(R.string.key_last_time_this_version_detected, 0) + gracePeriod return now > SP.getLong(R.string.key_last_time_this_version_detected, 0) + gracePeriod
} }
val WARN_EVERY = TimeUnit.DAYS.toMillis(1) private val WARN_EVERY = TimeUnit.DAYS.toMillis(1)
val GRACE_PERIOD_WARNING = TimeUnit.DAYS.toMillis(30)
val GRACE_PERIOD_OLD = TimeUnit.DAYS.toMillis(60)
val GRACE_PERIOD_VERY_OLD = TimeUnit.DAYS.toMillis(90)
} }
enum class GracePeriod(val warning: Long, val old: Long, val veryOld: Long) {
RELEASE(30, 60, 90),
RC(1, 7, 14)
}
private fun Long.daysToMillis() = TimeUnit.DAYS.toMillis(this)

View file

@ -7,6 +7,7 @@ import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.LinearLayout import android.widget.LinearLayout
import androidx.core.content.ContextCompat
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import info.nightscout.androidaps.Config import info.nightscout.androidaps.Config
import info.nightscout.androidaps.MainApp import info.nightscout.androidaps.MainApp
@ -18,20 +19,27 @@ import info.nightscout.androidaps.plugins.bus.RxBus
import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin
import info.nightscout.androidaps.plugins.configBuilder.ProfileFunctions import info.nightscout.androidaps.plugins.configBuilder.ProfileFunctions
import info.nightscout.androidaps.plugins.general.actions.defs.CustomAction import info.nightscout.androidaps.plugins.general.actions.defs.CustomAction
import info.nightscout.androidaps.plugins.general.actions.dialogs.FillDialog import info.nightscout.androidaps.dialogs.CareDialog
import info.nightscout.androidaps.plugins.general.actions.dialogs.NewExtendedBolusDialog import info.nightscout.androidaps.dialogs.ExtendedBolusDialog
import info.nightscout.androidaps.plugins.general.actions.dialogs.NewTempBasalDialog import info.nightscout.androidaps.dialogs.FillDialog
import info.nightscout.androidaps.dialogs.TempBasalDialog
import info.nightscout.androidaps.plugins.general.careportal.CareportalFragment import info.nightscout.androidaps.plugins.general.careportal.CareportalFragment
import info.nightscout.androidaps.plugins.general.careportal.Dialogs.NewNSTreatmentDialog import info.nightscout.androidaps.activities.ErrorHelperActivity
import info.nightscout.androidaps.dialogs.ProfileSwitchDialog
import info.nightscout.androidaps.dialogs.TempTargetDialog
import info.nightscout.androidaps.logging.L
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin
import info.nightscout.androidaps.queue.Callback import info.nightscout.androidaps.queue.Callback
import info.nightscout.androidaps.utils.* import info.nightscout.androidaps.utils.*
import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable import io.reactivex.disposables.CompositeDisposable
import kotlinx.android.synthetic.main.actions_fragment.* import kotlinx.android.synthetic.main.actions_fragment.*
import kotlinx.android.synthetic.main.careportal_stats_fragment.*
import org.slf4j.LoggerFactory
import java.util.* import java.util.*
class ActionsFragment : Fragment() { class ActionsFragment : Fragment() {
private val log = LoggerFactory.getLogger(L.CORE)
private var disposable: CompositeDisposable = CompositeDisposable() private var disposable: CompositeDisposable = CompositeDisposable()
@ -47,39 +55,52 @@ class ActionsFragment : Fragment() {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
actions_profileswitch.setOnClickListener { actions_profileswitch.setOnClickListener {
val newDialog = NewNSTreatmentDialog() fragmentManager?.let { ProfileSwitchDialog().show(it, "Actions") }
val profileSwitch = CareportalFragment.PROFILESWITCH
profileSwitch.executeProfileSwitch = true
newDialog.setOptions(profileSwitch, R.string.careportal_profileswitch)
fragmentManager?.let { newDialog.show(it, "NewNSTreatmentDialog") }
} }
actions_temptarget.setOnClickListener { actions_temptarget.setOnClickListener {
val newTTDialog = NewNSTreatmentDialog() fragmentManager?.let { TempTargetDialog().show(it, "Actions") }
val temptarget = CareportalFragment.TEMPTARGET
temptarget.executeTempTarget = true
newTTDialog.setOptions(temptarget, R.string.careportal_temporarytarget)
fragmentManager?.let { newTTDialog.show(it, "NewNSTreatmentDialog") }
} }
actions_extendedbolus.setOnClickListener { actions_extendedbolus.setOnClickListener {
fragmentManager?.let { NewExtendedBolusDialog().show(it, "NewExtendedDialog") } context?.let { context ->
OKDialog.showConfirmation(context, MainApp.gs(R.string.extended_bolus), MainApp.gs(R.string.ebstopsloop),
Runnable {
fragmentManager?.let { ExtendedBolusDialog().show(it, "Actions") }
}, null)
}
} }
actions_extendedbolus_cancel.setOnClickListener { actions_extendedbolus_cancel.setOnClickListener {
if (TreatmentsPlugin.getPlugin().isInHistoryExtendedBoluslInProgress) { if (TreatmentsPlugin.getPlugin().isInHistoryExtendedBoluslInProgress) {
log.debug("USER ENTRY: CANCEL EXTENDED BOLUS")
ConfigBuilderPlugin.getPlugin().commandQueue.cancelExtended(object : Callback() { ConfigBuilderPlugin.getPlugin().commandQueue.cancelExtended(object : Callback() {
override fun run() { override fun run() {
if (!result.success) if (!result.success) {
ToastUtils.showToastInUiThread(MainApp.instance().applicationContext, MainApp.gs(R.string.extendedbolusdeliveryerror)) val i = Intent(MainApp.instance(), ErrorHelperActivity::class.java)
i.putExtra("soundid", R.raw.boluserror)
i.putExtra("status", result.comment)
i.putExtra("title", MainApp.gs(R.string.extendedbolusdeliveryerror))
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
MainApp.instance().startActivity(i)
}
} }
}) })
} }
} }
actions_settempbasal.setOnClickListener { fragmentManager?.let { NewTempBasalDialog().show(it, "NewTempDialog") } } actions_settempbasal.setOnClickListener {
fragmentManager?.let { TempBasalDialog().show(it, "Actions") }
}
actions_canceltempbasal.setOnClickListener { actions_canceltempbasal.setOnClickListener {
if (TreatmentsPlugin.getPlugin().isTempBasalInProgress) { if (TreatmentsPlugin.getPlugin().isTempBasalInProgress) {
log.debug("USER ENTRY: CANCEL TEMP BASAL")
ConfigBuilderPlugin.getPlugin().commandQueue.cancelTempBasal(true, object : Callback() { ConfigBuilderPlugin.getPlugin().commandQueue.cancelTempBasal(true, object : Callback() {
override fun run() { override fun run() {
if (!result.success) if (!result.success) {
ToastUtils.showToastInUiThread(MainApp.instance().applicationContext, MainApp.gs(R.string.tempbasaldeliveryerror)) val i = Intent(MainApp.instance(), ErrorHelperActivity::class.java)
i.putExtra("soundid", R.raw.boluserror)
i.putExtra("status", result.comment)
i.putExtra("title", MainApp.gs(R.string.tempbasaldeliveryerror))
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
MainApp.instance().startActivity(i)
}
} }
}) })
} }
@ -87,6 +108,21 @@ class ActionsFragment : Fragment() {
actions_fill.setOnClickListener { fragmentManager?.let { FillDialog().show(it, "FillDialog") } } actions_fill.setOnClickListener { fragmentManager?.let { FillDialog().show(it, "FillDialog") } }
actions_historybrowser.setOnClickListener { startActivity(Intent(context, HistoryBrowseActivity::class.java)) } actions_historybrowser.setOnClickListener { startActivity(Intent(context, HistoryBrowseActivity::class.java)) }
actions_tddstats.setOnClickListener { startActivity(Intent(context, TDDStatsActivity::class.java)) } actions_tddstats.setOnClickListener { startActivity(Intent(context, TDDStatsActivity::class.java)) }
actions_bgcheck.setOnClickListener {
fragmentManager?.let { CareDialog().setOptions(CareDialog.EventType.BGCHECK, R.string.careportal_bgcheck).show(it, "Actions") }
}
actions_cgmsensorinsert.setOnClickListener {
fragmentManager?.let { CareDialog().setOptions(CareDialog.EventType.SENSOR_INSERT, R.string.careportal_cgmsensorinsert).show(it, "Actions") }
}
actions_pumpbatterychange.setOnClickListener {
fragmentManager?.let { CareDialog().setOptions(CareDialog.EventType.BATTERY_CHANGE, R.string.careportal_pumpbatterychange).show(it, "Actions") }
}
actions_note.setOnClickListener {
fragmentManager?.let { CareDialog().setOptions(CareDialog.EventType.NOTE, R.string.careportal_note).show(it, "Actions") }
}
actions_exercise.setOnClickListener {
fragmentManager?.let { CareDialog().setOptions(CareDialog.EventType.EXERCISE, R.string.careportal_exercise).show(it, "Actions") }
}
SP.putBoolean(R.string.key_objectiveuseactions, true) SP.putBoolean(R.string.key_objectiveuseactions, true)
} }
@ -97,43 +133,27 @@ class ActionsFragment : Fragment() {
disposable += RxBus disposable += RxBus
.toObservable(EventInitializationChanged::class.java) .toObservable(EventInitializationChanged::class.java)
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
.subscribe({ .subscribe({ updateGui() }, { FabricPrivacy.logException(it) })
updateGui()
}, {
FabricPrivacy.logException(it)
})
disposable += RxBus disposable += RxBus
.toObservable(EventRefreshOverview::class.java) .toObservable(EventRefreshOverview::class.java)
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
.subscribe({ .subscribe({ updateGui() }, { FabricPrivacy.logException(it) })
updateGui()
}, {
FabricPrivacy.logException(it)
})
disposable += RxBus disposable += RxBus
.toObservable(EventExtendedBolusChange::class.java) .toObservable(EventExtendedBolusChange::class.java)
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
.subscribe({ .subscribe({ updateGui() }, { FabricPrivacy.logException(it) })
updateGui()
}, {
FabricPrivacy.logException(it)
})
disposable += RxBus disposable += RxBus
.toObservable(EventTempBasalChange::class.java) .toObservable(EventTempBasalChange::class.java)
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
.subscribe({ .subscribe({ updateGui() }, { FabricPrivacy.logException(it) })
updateGui()
}, {
FabricPrivacy.logException(it)
})
disposable += RxBus disposable += RxBus
.toObservable(EventCustomActionsChanged::class.java) .toObservable(EventCustomActionsChanged::class.java)
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
.subscribe({ .subscribe({ updateGui() }, { FabricPrivacy.logException(it) })
updateGui() disposable += RxBus
}, { .toObservable(EventCareportalEventChange::class.java)
FabricPrivacy.logException(it) .observeOn(AndroidSchedulers.mainThread())
}) .subscribe({ updateGui() }, { FabricPrivacy.logException(it) })
updateGui() updateGui()
} }
@ -164,7 +184,7 @@ class ActionsFragment : Fragment() {
actions_profileswitch?.visibility = if (!basalProfileEnabled || !pump.isInitialized || pump.isSuspended) View.GONE else View.VISIBLE actions_profileswitch?.visibility = if (!basalProfileEnabled || !pump.isInitialized || pump.isSuspended) View.GONE else View.VISIBLE
if (!pump.pumpDescription.isExtendedBolusCapable || !pump.isInitialized || pump.isSuspended || pump.isFakingTempsByExtendedBoluses || Config.APS) { if (!pump.pumpDescription.isExtendedBolusCapable || !pump.isInitialized || pump.isSuspended || pump.isFakingTempsByExtendedBoluses) {
actions_extendedbolus?.visibility = View.GONE actions_extendedbolus?.visibility = View.GONE
actions_extendedbolus_cancel?.visibility = View.GONE actions_extendedbolus_cancel?.visibility = View.GONE
} else { } else {
@ -172,7 +192,7 @@ class ActionsFragment : Fragment() {
if (activeExtendedBolus != null) { if (activeExtendedBolus != null) {
actions_extendedbolus?.visibility = View.GONE actions_extendedbolus?.visibility = View.GONE
actions_extendedbolus_cancel?.visibility = View.VISIBLE actions_extendedbolus_cancel?.visibility = View.VISIBLE
actions_extendedbolus_cancel?.text = MainApp.gs(R.string.cancel) + " " + activeExtendedBolus.toString() actions_extendedbolus_cancel?.text = MainApp.gs(R.string.cancel) + " " + activeExtendedBolus.toStringMedium()
} else { } else {
actions_extendedbolus?.visibility = View.VISIBLE actions_extendedbolus?.visibility = View.VISIBLE
actions_extendedbolus_cancel?.visibility = View.GONE actions_extendedbolus_cancel?.visibility = View.GONE
@ -198,8 +218,11 @@ class ActionsFragment : Fragment() {
if (!pump.pumpDescription.isRefillingCapable || !pump.isInitialized || pump.isSuspended) View.GONE if (!pump.pumpDescription.isRefillingCapable || !pump.isInitialized || pump.isSuspended) View.GONE
else View.VISIBLE else View.VISIBLE
actions_temptarget?.visibility = if (!Config.APS) View.GONE else View.VISIBLE actions_temptarget?.visibility = Config.APS.toVisibility()
actions_tddstats?.visibility = if (!pump.pumpDescription.supportsTDDs) View.GONE else View.VISIBLE actions_tddstats?.visibility = pump.pumpDescription.supportsTDDs.toVisibility()
activity?.let { activity ->
CareportalFragment.updateAge(activity, careportal_sensorage, careportal_insulinage, careportal_canulaage, careportal_pbage)
}
checkPumpCustomActions() checkPumpCustomActions()
} }
@ -224,8 +247,7 @@ class ActionsFragment : Fragment() {
val action = this.pumpCustomActions[b.text.toString()] val action = this.pumpCustomActions[b.text.toString()]
ConfigBuilderPlugin.getPlugin().activePump!!.executeCustomAction(action!!.customActionType) ConfigBuilderPlugin.getPlugin().activePump!!.executeCustomAction(action!!.customActionType)
} }
val top = activity?.let { ContextCompat.getDrawable(it, customAction.iconResourceId) }
val top = resources.getDrawable(customAction.iconResourceId)
btn.setCompoundDrawablesWithIntrinsicBounds(null, top, null, null) btn.setCompoundDrawablesWithIntrinsicBounds(null, top, null, null)
action_buttons_layout?.addView(btn) action_buttons_layout?.addView(btn)

View file

@ -1,5 +1,6 @@
package info.nightscout.androidaps.plugins.general.actions package info.nightscout.androidaps.plugins.general.actions
import info.nightscout.androidaps.Config
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.interfaces.PluginBase import info.nightscout.androidaps.interfaces.PluginBase
import info.nightscout.androidaps.interfaces.PluginDescription import info.nightscout.androidaps.interfaces.PluginDescription
@ -8,6 +9,8 @@ import info.nightscout.androidaps.interfaces.PluginType
object ActionsPlugin : PluginBase(PluginDescription() object ActionsPlugin : PluginBase(PluginDescription()
.mainType(PluginType.GENERAL) .mainType(PluginType.GENERAL)
.fragmentClass(ActionsFragment::class.qualifiedName) .fragmentClass(ActionsFragment::class.qualifiedName)
.enableByDefault(Config.APS || Config.PUMPCONTROL)
.visibleByDefault(Config.APS || Config.PUMPCONTROL)
.pluginName(R.string.actions) .pluginName(R.string.actions)
.shortName(R.string.actions_shortname) .shortName(R.string.actions_shortname)
.description(R.string.description_actions)) .description(R.string.description_actions))

View file

@ -1,63 +0,0 @@
package info.nightscout.androidaps.plugins.general.actions.defs;
import info.nightscout.androidaps.R;
/**
* Created by andy on 9/20/18.
*/
public class CustomAction {
private int name;
private String iconName;
private CustomActionType customActionType;
private int iconResourceId;
private boolean enabled = true;
public CustomAction(int nameResourceId, CustomActionType actionType) {
this(nameResourceId, actionType, R.drawable.icon_actions_profileswitch, true);
}
public CustomAction(int nameResourceId, CustomActionType actionType, int iconResourceId) {
this(nameResourceId, actionType, iconResourceId, true);
}
public CustomAction(int nameResourceId, CustomActionType actionType, boolean enabled) {
this(nameResourceId, actionType, R.drawable.icon_actions_profileswitch, enabled);
}
public CustomAction(int nameResourceId, CustomActionType actionType, int iconResourceId, boolean enabled) {
this.name = nameResourceId;
this.customActionType = actionType;
this.iconResourceId = iconResourceId;
this.enabled = enabled;
}
public int getName() {
return name;
}
public CustomActionType getCustomActionType() {
return customActionType;
}
public int getIconResourceId() {
return iconResourceId;
}
public boolean isEnabled() {
return enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
}

View file

@ -0,0 +1,10 @@
package info.nightscout.androidaps.plugins.general.actions.defs
import info.nightscout.androidaps.R
class CustomAction @JvmOverloads constructor(val name: Int, val customActionType: CustomActionType?, val iconResourceId: Int = R.drawable.icon_actions_profileswitch, var isEnabled: Boolean = true) {
constructor(nameResourceId: Int, actionType: CustomActionType?, enabled: Boolean) :
this(nameResourceId, actionType, R.drawable.icon_actions_profileswitch, enabled)
}

View file

@ -1,11 +0,0 @@
package info.nightscout.androidaps.plugins.general.actions.defs;
/**
* Created by andy on 9/20/18.
*/
public interface CustomActionType {
String getKey();
}

View file

@ -0,0 +1,5 @@
package info.nightscout.androidaps.plugins.general.actions.defs
interface CustomActionType {
val key: String?
}

View file

@ -1,255 +0,0 @@
package info.nightscout.androidaps.plugins.general.actions.dialogs;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import androidx.fragment.app.DialogFragment;
import androidx.appcompat.app.AlertDialog;
import android.text.Editable;
import android.text.Html;
import android.text.TextWatcher;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.LinearLayout;
import com.google.common.base.Joiner;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.LinkedList;
import java.util.List;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.data.DetailedBolusInfo;
import info.nightscout.androidaps.db.CareportalEvent;
import info.nightscout.androidaps.db.Source;
import info.nightscout.androidaps.interfaces.Constraint;
import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.general.nsclient.NSUpload;
import info.nightscout.androidaps.plugins.general.overview.dialogs.ErrorHelperActivity;
import info.nightscout.androidaps.queue.Callback;
import info.nightscout.androidaps.utils.DecimalFormatter;
import info.nightscout.androidaps.utils.NumberPicker;
import info.nightscout.androidaps.utils.SP;
import info.nightscout.androidaps.utils.SafeParse;
import info.nightscout.androidaps.utils.ToastUtils;
import static info.nightscout.androidaps.utils.DateUtil.now;
public class FillDialog extends DialogFragment implements OnClickListener {
private static Logger log = LoggerFactory.getLogger(FillDialog.class);
private CheckBox pumpSiteChangeCheckbox;
private CheckBox insulinCartridgeChangeCheckbox;
private NumberPicker editInsulin;
double amount1 = 0d;
double amount2 = 0d;
double amount3 = 0d;
private EditText notesEdit;
//one shot guards
private boolean accepted;
private boolean okClicked;
final private TextWatcher textWatcher = new TextWatcher() {
@Override
public void afterTextChanged(Editable s) {
validateInputs();
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
};
private void validateInputs() {
int time = editInsulin.getValue().intValue();
if (Math.abs(time) > 12 * 60) {
editInsulin.setValue(0d);
ToastUtils.showToastInUiThread(MainApp.instance().getApplicationContext(), MainApp.gs(R.string.constraintapllied));
}
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.actions_fill_dialog, container, false);
view.findViewById(R.id.ok).setOnClickListener(this);
view.findViewById(R.id.cancel).setOnClickListener(this);
getDialog().getWindow().requestFeature(Window.FEATURE_NO_TITLE);
getDialog().getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN);
pumpSiteChangeCheckbox = view.findViewById(R.id.fill_catheter_change);
insulinCartridgeChangeCheckbox = view.findViewById(R.id.fill_cartridge_change);
Double maxInsulin = MainApp.getConstraintChecker().getMaxBolusAllowed().value();
double bolusstep = ConfigBuilderPlugin.getPlugin().getActivePump().getPumpDescription().bolusStep;
editInsulin = view.findViewById(R.id.fill_insulinamount);
editInsulin.setParams(0d, 0d, maxInsulin, bolusstep, DecimalFormatter.pumpSupportedBolusFormat(), false, view.findViewById(R.id.ok), textWatcher);
Button preset1Button = view.findViewById(R.id.fill_preset_button1);
amount1 = SP.getDouble("fill_button1", 0.3);
if (amount1 > 0) {
preset1Button.setVisibility(View.VISIBLE);
preset1Button.setText(DecimalFormatter.toPumpSupportedBolus(amount1)); // + "U");
preset1Button.setOnClickListener(this);
} else {
preset1Button.setVisibility(View.GONE);
}
Button preset2Button = view.findViewById(R.id.fill_preset_button2);
amount2 = SP.getDouble("fill_button2", 0d);
if (amount2 > 0) {
preset2Button.setVisibility(View.VISIBLE);
preset2Button.setText(DecimalFormatter.toPumpSupportedBolus(amount2)); // + "U");
preset2Button.setOnClickListener(this);
} else {
preset2Button.setVisibility(View.GONE);
}
Button preset3Button = view.findViewById(R.id.fill_preset_button3);
amount3 = SP.getDouble("fill_button3", 0d);
if (amount3 > 0) {
preset3Button.setVisibility(View.VISIBLE);
preset3Button.setText(DecimalFormatter.toPumpSupportedBolus(amount3)); // + "U");
preset3Button.setOnClickListener(this);
} else {
preset3Button.setVisibility(View.GONE);
}
LinearLayout notesLayout = view.findViewById(R.id.fill_notes_layout);
notesLayout.setVisibility(SP.getBoolean(R.string.key_show_notes_entry_dialogs, false) ? View.VISIBLE : View.GONE);
notesEdit = view.findViewById(R.id.fill_notes);
setCancelable(true);
getDialog().setCanceledOnTouchOutside(false);
return view;
}
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.ok:
confirmAndDeliver();
break;
case R.id.cancel:
dismiss();
break;
case R.id.fill_preset_button1:
editInsulin.setValue(amount1);
break;
case R.id.fill_preset_button2:
editInsulin.setValue(amount2);
break;
case R.id.fill_preset_button3:
editInsulin.setValue(amount3);
break;
}
}
private synchronized void confirmAndDeliver() {
if (okClicked) {
log.debug("guarding: ok already clicked");
dismiss();
return;
}
okClicked = true;
try {
Double insulin = SafeParse.stringToDouble(editInsulin.getText());
List<String> confirmMessage = new LinkedList<>();
Double insulinAfterConstraints = MainApp.getConstraintChecker().applyBolusConstraints(new Constraint<>(insulin)).value();
if (insulinAfterConstraints > 0) {
confirmMessage.add(MainApp.gs(R.string.fillwarning));
confirmMessage.add("");
confirmMessage.add(MainApp.gs(R.string.bolus) + ": " + "<font color='" + MainApp.gc(R.color.colorCarbsButton) + "'>" + DecimalFormatter.toPumpSupportedBolus(insulinAfterConstraints) + "U" + "</font>");
if (Math.abs(insulinAfterConstraints - insulin) > 0.01d)
confirmMessage.add(MainApp.gs(R.string.bolusconstraintappliedwarning, MainApp.gc(R.color.warning), insulin, insulinAfterConstraints));
}
if (pumpSiteChangeCheckbox.isChecked())
confirmMessage.add("" + "<font color='" + MainApp.gc(R.color.actionsConfirm) + "'>" + MainApp.gs(R.string.record_pump_site_change) + "</font>");
if (insulinCartridgeChangeCheckbox.isChecked())
confirmMessage.add("" + "<font color='" + MainApp.gc(R.color.actionsConfirm) + "'>" + MainApp.gs(R.string.record_insulin_cartridge_change) + "</font>");
final String notes = notesEdit.getText().toString();
if (!notes.isEmpty()) {
confirmMessage.add(MainApp.gs(R.string.careportal_newnstreatment_notes_label) + ": " + notes);
}
final Double finalInsulinAfterConstraints = insulinAfterConstraints;
final Context context = getContext();
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setTitle(MainApp.gs(R.string.confirmation));
if (insulinAfterConstraints > 0 || pumpSiteChangeCheckbox.isChecked() || insulinCartridgeChangeCheckbox.isChecked()) {
builder.setMessage(Html.fromHtml(Joiner.on("<br/>").join(confirmMessage)));
builder.setPositiveButton(MainApp.gs(R.string.primefill), (dialog, id) -> {
synchronized (builder) {
if (accepted) {
log.debug("guarding: already accepted");
return;
}
accepted = true;
if (finalInsulinAfterConstraints > 0) {
DetailedBolusInfo detailedBolusInfo = new DetailedBolusInfo();
detailedBolusInfo.insulin = finalInsulinAfterConstraints;
detailedBolusInfo.context = context;
detailedBolusInfo.source = Source.USER;
detailedBolusInfo.isValid = false; // do not count it in IOB (for pump history)
detailedBolusInfo.notes = notes;
ConfigBuilderPlugin.getPlugin().getCommandQueue().bolus(detailedBolusInfo, new Callback() {
@Override
public void run() {
if (!result.success) {
Intent i = new Intent(MainApp.instance(), ErrorHelperActivity.class);
i.putExtra("soundid", R.raw.boluserror);
i.putExtra("status", result.comment);
i.putExtra("title", MainApp.gs(R.string.treatmentdeliveryerror));
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
MainApp.instance().startActivity(i);
}
}
});
}
if (pumpSiteChangeCheckbox.isChecked())
NSUpload.uploadEvent(CareportalEvent.SITECHANGE, now(), notes);
if (insulinCartridgeChangeCheckbox.isChecked())
NSUpload.uploadEvent(CareportalEvent.INSULINCHANGE, now() + 1000, notes);
}
});
} else {
builder.setMessage(MainApp.gs(R.string.no_action_selected));
}
builder.setNegativeButton(MainApp.gs(R.string.cancel), null);
builder.show();
dismiss();
} catch (RuntimeException e) {
log.error("Unhandled exception", e);
}
}
}

View file

@ -1,115 +0,0 @@
package info.nightscout.androidaps.plugins.general.actions.dialogs;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import androidx.fragment.app.DialogFragment;
import androidx.appcompat.app.AlertDialog;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.text.DecimalFormat;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.interfaces.Constraint;
import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.general.overview.dialogs.ErrorHelperActivity;
import info.nightscout.androidaps.queue.Callback;
import info.nightscout.androidaps.utils.NumberPicker;
import info.nightscout.androidaps.utils.SafeParse;
public class NewExtendedBolusDialog extends DialogFragment implements View.OnClickListener {
private static Logger log = LoggerFactory.getLogger(NewExtendedBolusDialog.class);
NumberPicker editInsulin;
NumberPicker editDuration;
public NewExtendedBolusDialog() {
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
getDialog().setTitle(MainApp.gs(R.string.overview_extendedbolus_button));
View view = inflater.inflate(R.layout.overview_newextendedbolus_dialog, container, false);
Double maxInsulin = MainApp.getConstraintChecker().getMaxExtendedBolusAllowed().value();
editInsulin = (NumberPicker) view.findViewById(R.id.overview_newextendedbolus_insulin);
editInsulin.setParams(0d, 0d, maxInsulin, 0.1d, new DecimalFormat("0.00"), false, view.findViewById(R.id.ok));
double extendedDurationStep = ConfigBuilderPlugin.getPlugin().getActivePump().getPumpDescription().extendedBolusDurationStep;
double extendedMaxDuration = ConfigBuilderPlugin.getPlugin().getActivePump().getPumpDescription().extendedBolusMaxDuration;
editDuration = (NumberPicker) view.findViewById(R.id.overview_newextendedbolus_duration);
editDuration.setParams(extendedDurationStep, extendedDurationStep, extendedMaxDuration, extendedDurationStep, new DecimalFormat("0"), false, view.findViewById(R.id.ok));
view.findViewById(R.id.ok).setOnClickListener(this);
view.findViewById(R.id.cancel).setOnClickListener(this);
setCancelable(true);
getDialog().setCanceledOnTouchOutside(false);
return view;
}
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.ok:
try {
Double insulin = SafeParse.stringToDouble(editInsulin.getText());
int durationInMinutes = SafeParse.stringToInt(editDuration.getText());
String confirmMessage = MainApp.gs(R.string.setextendedbolusquestion);
Double insulinAfterConstraint = MainApp.getConstraintChecker().applyExtendedBolusConstraints(new Constraint<>(insulin)).value();
confirmMessage += " " + insulinAfterConstraint + " U ";
confirmMessage += MainApp.gs(R.string.duration) + " " + durationInMinutes + "min ?";
if (Math.abs(insulinAfterConstraint - insulin) > 0.01d)
confirmMessage += "\n" + MainApp.gs(R.string.constraintapllied);
insulin = insulinAfterConstraint;
final Double finalInsulin = insulin;
final int finalDurationInMinutes = durationInMinutes;
final Context context = getContext();
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setTitle(MainApp.gs(R.string.confirmation));
builder.setMessage(confirmMessage);
builder.setPositiveButton(MainApp.gs(R.string.ok), new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
ConfigBuilderPlugin.getPlugin().getCommandQueue().extendedBolus(finalInsulin, finalDurationInMinutes, new Callback() {
@Override
public void run() {
if (!result.success) {
Intent i = new Intent(MainApp.instance(), ErrorHelperActivity.class);
i.putExtra("soundid", R.raw.boluserror);
i.putExtra("status", result.comment);
i.putExtra("title", MainApp.gs(R.string.treatmentdeliveryerror));
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
MainApp.instance().startActivity(i);
}
}
});
}
});
builder.setNegativeButton(MainApp.gs(R.string.cancel), null);
builder.show();
dismiss();
} catch (Exception e) {
log.error("Unhandled exception", e);
}
break;
case R.id.cancel:
dismiss();
break;
}
}
}

View file

@ -1,196 +0,0 @@
package info.nightscout.androidaps.plugins.general.actions.dialogs;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import androidx.fragment.app.DialogFragment;
import androidx.appcompat.app.AlertDialog;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.text.DecimalFormat;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.interfaces.Constraint;
import info.nightscout.androidaps.interfaces.PumpDescription;
import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.configBuilder.ProfileFunctions;
import info.nightscout.androidaps.plugins.general.overview.dialogs.ErrorHelperActivity;
import info.nightscout.androidaps.queue.Callback;
import info.nightscout.androidaps.utils.NumberPicker;
import info.nightscout.androidaps.utils.SafeParse;
public class NewTempBasalDialog extends DialogFragment implements View.OnClickListener, RadioGroup.OnCheckedChangeListener {
private static Logger log = LoggerFactory.getLogger(NewTempBasalDialog.class);
RadioButton percentRadio;
RadioButton absoluteRadio;
RadioGroup basalTypeRadioGroup;
LinearLayout typeSelectorLayout;
LinearLayout percentLayout;
LinearLayout absoluteLayout;
NumberPicker basalPercent;
NumberPicker basalAbsolute;
NumberPicker duration;
public NewTempBasalDialog() {
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
getDialog().setTitle(MainApp.gs(R.string.overview_tempbasal_button));
View view = inflater.inflate(R.layout.overview_newtempbasal_dialog, container, false);
percentLayout = (LinearLayout) view.findViewById(R.id.overview_newtempbasal_percent_layout);
absoluteLayout = (LinearLayout) view.findViewById(R.id.overview_newtempbasal_absolute_layout);
percentRadio = (RadioButton) view.findViewById(R.id.overview_newtempbasal_percent_radio);
basalTypeRadioGroup = (RadioGroup) view.findViewById(R.id.overview_newtempbasal_radiogroup);
absoluteRadio = (RadioButton) view.findViewById(R.id.overview_newtempbasal_absolute_radio);
typeSelectorLayout = (LinearLayout) view.findViewById(R.id.overview_newtempbasal_typeselector_layout);
PumpDescription pumpDescription = ConfigBuilderPlugin.getPlugin().getActivePump().getPumpDescription();
basalPercent = (NumberPicker) view.findViewById(R.id.overview_newtempbasal_basalpercentinput);
double maxTempPercent = pumpDescription.maxTempPercent;
double tempPercentStep = pumpDescription.tempPercentStep;
basalPercent.setParams(100d, 0d, maxTempPercent, tempPercentStep, new DecimalFormat("0"), true, view.findViewById(R.id.ok));
Profile profile = ProfileFunctions.getInstance().getProfile();
Double currentBasal = profile != null ? profile.getBasal() : 0d;
basalAbsolute = (NumberPicker) view.findViewById(R.id.overview_newtempbasal_basalabsoluteinput);
basalAbsolute.setParams(currentBasal, 0d, pumpDescription.maxTempAbsolute, pumpDescription.tempAbsoluteStep, new DecimalFormat("0.00"), true, view.findViewById(R.id.ok));
double tempDurationStep = pumpDescription.tempDurationStep;
double tempMaxDuration = pumpDescription.tempMaxDuration;
duration = (NumberPicker) view.findViewById(R.id.overview_newtempbasal_duration);
duration.setParams(tempDurationStep, tempDurationStep, tempMaxDuration, tempDurationStep, new DecimalFormat("0"), false, view.findViewById(R.id.ok));
if ((pumpDescription.tempBasalStyle & PumpDescription.PERCENT) == PumpDescription.PERCENT && (pumpDescription.tempBasalStyle & PumpDescription.ABSOLUTE) == PumpDescription.ABSOLUTE) {
// Both allowed
typeSelectorLayout.setVisibility(View.VISIBLE);
} else {
typeSelectorLayout.setVisibility(View.GONE);
}
if ((pumpDescription.tempBasalStyle & PumpDescription.PERCENT) == PumpDescription.PERCENT) {
percentRadio.setChecked(true);
absoluteRadio.setChecked(false);
percentLayout.setVisibility(View.VISIBLE);
absoluteLayout.setVisibility(View.GONE);
} else if ((pumpDescription.tempBasalStyle & PumpDescription.ABSOLUTE) == PumpDescription.ABSOLUTE) {
percentRadio.setChecked(false);
absoluteRadio.setChecked(true);
percentLayout.setVisibility(View.GONE);
absoluteLayout.setVisibility(View.VISIBLE);
}
view.findViewById(R.id.ok).setOnClickListener(this);
view.findViewById(R.id.cancel).setOnClickListener(this);
basalTypeRadioGroup.setOnCheckedChangeListener(this);
setCancelable(true);
getDialog().setCanceledOnTouchOutside(false);
return view;
}
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.ok:
try {
int percent = 0;
Double absolute = 0d;
final boolean setAsPercent = percentRadio.isChecked();
int durationInMinutes = SafeParse.stringToInt(duration.getText());
Profile profile = ProfileFunctions.getInstance().getProfile();
if (profile == null)
return;
String confirmMessage = MainApp.gs(R.string.setbasalquestion);
if (setAsPercent) {
int basalPercentInput = SafeParse.stringToInt(basalPercent.getText());
percent = MainApp.getConstraintChecker().applyBasalPercentConstraints(new Constraint<>(basalPercentInput), profile).value();
confirmMessage += "\n" + percent + "% ";
confirmMessage += "\n" + MainApp.gs(R.string.duration) + " " + durationInMinutes + "min ?";
if (percent != basalPercentInput)
confirmMessage += "\n" + MainApp.gs(R.string.constraintapllied);
} else {
Double basalAbsoluteInput = SafeParse.stringToDouble(basalAbsolute.getText());
absolute = MainApp.getConstraintChecker().applyBasalConstraints(new Constraint<>(basalAbsoluteInput), profile).value();
confirmMessage += "\n" + absolute + " U/h ";
confirmMessage += "\n" + MainApp.gs(R.string.duration) + " " + durationInMinutes + "min ?";
if (Math.abs(absolute - basalAbsoluteInput) > 0.01d)
confirmMessage += "\n" + MainApp.gs(R.string.constraintapllied);
}
final int finalBasalPercent = percent;
final Double finalBasal = absolute;
final int finalDurationInMinutes = durationInMinutes;
AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
builder.setTitle(MainApp.gs(R.string.confirmation));
builder.setMessage(confirmMessage);
builder.setPositiveButton(MainApp.gs(R.string.ok), new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
Callback callback = new Callback() {
@Override
public void run() {
if (!result.success) {
Intent i = new Intent(MainApp.instance(), ErrorHelperActivity.class);
i.putExtra("soundid", R.raw.boluserror);
i.putExtra("status", result.comment);
i.putExtra("title", MainApp.gs(R.string.tempbasaldeliveryerror));
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
MainApp.instance().startActivity(i);
}
}
};
if (setAsPercent) {
ConfigBuilderPlugin.getPlugin().getCommandQueue().tempBasalPercent(finalBasalPercent, finalDurationInMinutes, true, profile, callback);
} else {
ConfigBuilderPlugin.getPlugin().getCommandQueue().tempBasalAbsolute(finalBasal, finalDurationInMinutes, true, profile, callback);
}
}
});
builder.setNegativeButton(MainApp.gs(R.string.cancel), null);
builder.show();
dismiss();
} catch (Exception e) {
log.error("Unhandled exception", e);
}
break;
case R.id.cancel:
dismiss();
break;
}
}
@Override
public void onCheckedChanged(RadioGroup group, int checkedId) {
switch (checkedId) {
case R.id.overview_newtempbasal_percent_radio:
percentLayout.setVisibility(View.VISIBLE);
absoluteLayout.setVisibility(View.GONE);
break;
case R.id.overview_newtempbasal_absolute_radio:
percentLayout.setVisibility(View.GONE);
absoluteLayout.setVisibility(View.VISIBLE);
break;
}
}
}

View file

@ -1,27 +1,35 @@
package info.nightscout.androidaps.plugins.general.automation package info.nightscout.androidaps.plugins.general.automation
import android.os.Bundle import android.os.Bundle
import android.text.method.ScrollingMovementMethod
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.ItemTouchHelper
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.plugins.bus.RxBus import info.nightscout.androidaps.plugins.bus.RxBus
import info.nightscout.androidaps.plugins.general.automation.dialogs.EditEventDialog import info.nightscout.androidaps.plugins.general.automation.dialogs.EditEventDialog
import info.nightscout.androidaps.plugins.general.automation.dragHelpers.OnStartDragListener
import info.nightscout.androidaps.plugins.general.automation.dragHelpers.SimpleItemTouchHelperCallback
import info.nightscout.androidaps.plugins.general.automation.events.EventAutomationDataChanged import info.nightscout.androidaps.plugins.general.automation.events.EventAutomationDataChanged
import info.nightscout.androidaps.plugins.general.automation.events.EventAutomationUpdateGui import info.nightscout.androidaps.plugins.general.automation.events.EventAutomationUpdateGui
import info.nightscout.androidaps.utils.FabricPrivacy import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.HtmlHelper
import info.nightscout.androidaps.utils.plusAssign import info.nightscout.androidaps.utils.plusAssign
import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable import io.reactivex.disposables.CompositeDisposable
import kotlinx.android.synthetic.main.automation_fragment.* import kotlinx.android.synthetic.main.automation_fragment.*
class AutomationFragment : Fragment() { class AutomationFragment : Fragment(), OnStartDragListener {
private var disposable: CompositeDisposable = CompositeDisposable() private var disposable: CompositeDisposable = CompositeDisposable()
private var eventListAdapter: EventListAdapter? = null private var eventListAdapter: EventListAdapter? = null
private var itemTouchHelper: ItemTouchHelper? = null
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.automation_fragment, container, false) return inflater.inflate(R.layout.automation_fragment, container, false)
} }
@ -29,10 +37,12 @@ class AutomationFragment : Fragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
eventListAdapter = EventListAdapter(AutomationPlugin.automationEvents, fragmentManager, activity) eventListAdapter = EventListAdapter(AutomationPlugin.automationEvents, fragmentManager, activity, this)
automation_eventListView.layoutManager = LinearLayoutManager(context) automation_eventListView.layoutManager = LinearLayoutManager(context)
automation_eventListView.adapter = eventListAdapter automation_eventListView.adapter = eventListAdapter
automation_logView.setMovementMethod(ScrollingMovementMethod())
automation_fabAddEvent.setOnClickListener { automation_fabAddEvent.setOnClickListener {
val dialog = EditEventDialog() val dialog = EditEventDialog()
val args = Bundle() val args = Bundle()
@ -42,6 +52,10 @@ class AutomationFragment : Fragment() {
fragmentManager?.let { dialog.show(it, "EditEventDialog") } fragmentManager?.let { dialog.show(it, "EditEventDialog") }
} }
val callback: ItemTouchHelper.Callback = SimpleItemTouchHelperCallback(eventListAdapter!!)
itemTouchHelper = ItemTouchHelper(callback)
itemTouchHelper?.attachToRecyclerView(automation_eventListView)
} }
@Synchronized @Synchronized
@ -77,8 +91,12 @@ class AutomationFragment : Fragment() {
eventListAdapter?.notifyDataSetChanged() eventListAdapter?.notifyDataSetChanged()
val sb = StringBuilder() val sb = StringBuilder()
for (l in AutomationPlugin.executionLog.reversed()) for (l in AutomationPlugin.executionLog.reversed())
sb.append(l).append("\n") sb.append(l).append("<br>")
automation_logView?.text = sb.toString() automation_logView?.text = HtmlHelper.fromHtml(sb.toString())
}
override fun onStartDrag(viewHolder: RecyclerView.ViewHolder) {
itemTouchHelper?.startDrag(viewHolder);
} }
} }

View file

@ -161,7 +161,7 @@ object AutomationPlugin : PluginBase(PluginDescription()
private fun processActions() { private fun processActions() {
if (!isEnabled(PluginType.GENERAL)) if (!isEnabled(PluginType.GENERAL))
return return
if (LoopPlugin.getPlugin().isSuspended) { if (LoopPlugin.getPlugin().isSuspended || !LoopPlugin.getPlugin().isEnabled(PluginType.LOOP)) {
if (L.isEnabled(L.AUTOMATION)) if (L.isEnabled(L.AUTOMATION))
log.debug("Loop deactivated") log.debug("Loop deactivated")
return return
@ -178,10 +178,10 @@ object AutomationPlugin : PluginBase(PluginDescription()
val sb = StringBuilder() val sb = StringBuilder()
sb.append(DateUtil.timeString(DateUtil.now())) sb.append(DateUtil.timeString(DateUtil.now()))
sb.append(" ") sb.append(" ")
sb.append(if (result.success) "" else "X") sb.append(if (result.success) "" else "")
sb.append(" ") sb.append(" <b>")
sb.append(event.title) sb.append(event.title)
sb.append(": ") sb.append(":</b> ")
sb.append(action.shortDescription()) sb.append(action.shortDescription())
sb.append(": ") sb.append(": ")
sb.append(result.comment) sb.append(result.comment)

View file

@ -1,9 +1,12 @@
package info.nightscout.androidaps.plugins.general.automation; package info.nightscout.androidaps.plugins.general.automation;
import android.annotation.SuppressLint;
import android.app.Activity; import android.app.Activity;
import android.content.Context; import android.content.Context;
import android.graphics.Color;
import android.os.Bundle; import android.os.Bundle;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.CheckBox; import android.widget.CheckBox;
@ -17,6 +20,7 @@ import androidx.annotation.NonNull;
import androidx.fragment.app.FragmentManager; import androidx.fragment.app.FragmentManager;
import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView;
import java.util.Collections;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
@ -25,19 +29,26 @@ import info.nightscout.androidaps.R;
import info.nightscout.androidaps.plugins.bus.RxBus; import info.nightscout.androidaps.plugins.bus.RxBus;
import info.nightscout.androidaps.plugins.general.automation.actions.Action; import info.nightscout.androidaps.plugins.general.automation.actions.Action;
import info.nightscout.androidaps.plugins.general.automation.dialogs.EditEventDialog; import info.nightscout.androidaps.plugins.general.automation.dialogs.EditEventDialog;
import info.nightscout.androidaps.plugins.general.automation.dragHelpers.ItemTouchHelperAdapter;
import info.nightscout.androidaps.plugins.general.automation.dragHelpers.ItemTouchHelperViewHolder;
import info.nightscout.androidaps.plugins.general.automation.dragHelpers.OnStartDragListener;
import info.nightscout.androidaps.plugins.general.automation.events.EventAutomationDataChanged; import info.nightscout.androidaps.plugins.general.automation.events.EventAutomationDataChanged;
import info.nightscout.androidaps.plugins.general.automation.events.EventAutomationUpdateGui;
import info.nightscout.androidaps.plugins.general.automation.triggers.TriggerConnector; import info.nightscout.androidaps.plugins.general.automation.triggers.TriggerConnector;
import info.nightscout.androidaps.utils.OKDialog; import info.nightscout.androidaps.utils.OKDialog;
class EventListAdapter extends RecyclerView.Adapter<EventListAdapter.ViewHolder> { class EventListAdapter extends RecyclerView.Adapter<EventListAdapter.ViewHolder> implements ItemTouchHelperAdapter {
private final List<AutomationEvent> eventList; private final List<AutomationEvent> eventList;
private final FragmentManager fragmentManager; private final FragmentManager fragmentManager;
private final Activity activity; private final Activity activity;
EventListAdapter(List<AutomationEvent> events, FragmentManager fragmentManager, Activity activity) { private final OnStartDragListener mDragStartListener;
EventListAdapter(List<AutomationEvent> events, FragmentManager fragmentManager, Activity activity, OnStartDragListener dragStartListener) {
this.eventList = events; this.eventList = events;
this.fragmentManager = fragmentManager; this.fragmentManager = fragmentManager;
this.activity = activity; this.activity = activity;
mDragStartListener = dragStartListener;
} }
@NonNull @NonNull
@ -54,6 +65,7 @@ class EventListAdapter extends RecyclerView.Adapter<EventListAdapter.ViewHolder>
layout.addView(iv); layout.addView(iv);
} }
@SuppressLint("ClickableViewAccessibility")
@Override @Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) { public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
final AutomationEvent event = eventList.get(position); final AutomationEvent event = eventList.get(position);
@ -91,16 +103,10 @@ class EventListAdapter extends RecyclerView.Adapter<EventListAdapter.ViewHolder>
RxBus.INSTANCE.send(new EventAutomationDataChanged()); RxBus.INSTANCE.send(new EventAutomationDataChanged());
}); });
// remove event
holder.iconTrash.setOnClickListener(v ->
OKDialog.showConfirmation(activity, MainApp.gs(R.string.removerecord) + " " + event.getTitle(), () -> {
eventList.remove(event);
RxBus.INSTANCE.send(new EventAutomationDataChanged());
})
);
// edit event // edit event
holder.rootLayout.setOnClickListener(v -> { holder.rootLayout.setOnClickListener(v ->
{
//EditEventDialog dialog = EditEventDialog.Companion.newInstance(event, false); //EditEventDialog dialog = EditEventDialog.Companion.newInstance(event, false);
EditEventDialog dialog = new EditEventDialog(); EditEventDialog dialog = new EditEventDialog();
Bundle args = new Bundle(); Bundle args = new Bundle();
@ -110,6 +116,17 @@ class EventListAdapter extends RecyclerView.Adapter<EventListAdapter.ViewHolder>
if (fragmentManager != null) if (fragmentManager != null)
dialog.show(fragmentManager, "EditEventDialog"); dialog.show(fragmentManager, "EditEventDialog");
}); });
// Start a drag whenever the handle view it touched
holder.iconSort.setOnTouchListener((v, motionEvent) ->
{
if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
mDragStartListener.onStartDrag(holder);
return true;
}
return v.onTouchEvent(motionEvent);
});
} }
@Override @Override
@ -117,12 +134,33 @@ class EventListAdapter extends RecyclerView.Adapter<EventListAdapter.ViewHolder>
return eventList.size(); return eventList.size();
} }
static class ViewHolder extends RecyclerView.ViewHolder { @Override
public boolean onItemMove(int fromPosition, int toPosition) {
Collections.swap(eventList, fromPosition, toPosition);
notifyItemMoved(fromPosition, toPosition);
RxBus.INSTANCE.send(new EventAutomationDataChanged());
return true;
}
@Override
public void onItemDismiss(int position) {
OKDialog.showConfirmation(activity, MainApp.gs(R.string.removerecord) + " " + eventList.get(position).getTitle(),
() -> {
eventList.remove(position);
notifyItemRemoved(position);
RxBus.INSTANCE.send(new EventAutomationDataChanged());
RxBus.INSTANCE.send(new EventAutomationUpdateGui());
}, () -> {
RxBus.INSTANCE.send(new EventAutomationUpdateGui());
});
}
static class ViewHolder extends RecyclerView.ViewHolder implements ItemTouchHelperViewHolder {
final RelativeLayout rootLayout; final RelativeLayout rootLayout;
final LinearLayout iconLayout; final LinearLayout iconLayout;
final TextView eventTitle; final TextView eventTitle;
final Context context; final Context context;
final ImageView iconTrash; final ImageView iconSort;
final CheckBox enabled; final CheckBox enabled;
ViewHolder(View view, Context context) { ViewHolder(View view, Context context) {
@ -131,8 +169,18 @@ class EventListAdapter extends RecyclerView.Adapter<EventListAdapter.ViewHolder>
eventTitle = view.findViewById(R.id.viewEventTitle); eventTitle = view.findViewById(R.id.viewEventTitle);
rootLayout = view.findViewById(R.id.rootLayout); rootLayout = view.findViewById(R.id.rootLayout);
iconLayout = view.findViewById(R.id.iconLayout); iconLayout = view.findViewById(R.id.iconLayout);
iconTrash = view.findViewById(R.id.iconTrash); iconSort = view.findViewById(R.id.iconSort);
enabled = view.findViewById(R.id.automation_enabled); enabled = view.findViewById(R.id.automation_enabled);
} }
@Override
public void onItemSelected() {
itemView.setBackgroundColor(Color.LTGRAY);
}
@Override
public void onItemClear() {
itemView.setBackgroundColor(MainApp.gc(R.color.ribbonDefault));
}
} }
} }

View file

@ -28,7 +28,7 @@ public class ActionLoopResume extends Action {
if (LoopPlugin.getPlugin().isSuspended()) { if (LoopPlugin.getPlugin().isSuspended()) {
LoopPlugin.getPlugin().suspendTo(0); LoopPlugin.getPlugin().suspendTo(0);
ConfigBuilderPlugin.getPlugin().storeSettings("ActionLoopResume"); ConfigBuilderPlugin.getPlugin().storeSettings("ActionLoopResume");
NSUpload.uploadOpenAPSOffline(0); LoopPlugin.getPlugin().createOfflineEvent(0);
RxBus.INSTANCE.send(new EventRefreshOverview("ActionLoopResume")); RxBus.INSTANCE.send(new EventRefreshOverview("ActionLoopResume"));
if (callback != null) if (callback != null)
callback.result(new PumpEnactResult().success(true).comment(R.string.ok)).run(); callback.result(new PumpEnactResult().success(true).comment(R.string.ok)).run();

View file

@ -21,17 +21,29 @@ import info.nightscout.androidaps.plugins.general.automation.elements.InputProfi
import info.nightscout.androidaps.plugins.general.automation.elements.LabelWithElement; import info.nightscout.androidaps.plugins.general.automation.elements.LabelWithElement;
import info.nightscout.androidaps.plugins.general.automation.elements.LayoutBuilder; import info.nightscout.androidaps.plugins.general.automation.elements.LayoutBuilder;
import info.nightscout.androidaps.queue.Callback; import info.nightscout.androidaps.queue.Callback;
import info.nightscout.androidaps.utils.DateUtil;
import info.nightscout.androidaps.utils.JsonHelper; import info.nightscout.androidaps.utils.JsonHelper;
public class ActionProfileSwitch extends Action { public class ActionProfileSwitch extends Action {
private static Logger log = LoggerFactory.getLogger(L.AUTOMATION); private static Logger log = LoggerFactory.getLogger(L.AUTOMATION);
public InputProfileName inputProfileName = new InputProfileName(ProfileFunctions.getInstance().getProfileName()); InputProfileName inputProfileName;
String profileName = ""; String profileName = "";
public ActionProfileSwitch() { public ActionProfileSwitch() {
// Prevent action if active profile is already active // Prevent action if active profile is already active
// but we don't have a trigger IS_NOT_EQUAL // but we don't have a trigger IS_NOT_EQUAL
// so check is in the doRun() // so check is in the doRun()
ProfileInterface profileInterface = ConfigBuilderPlugin.getPlugin().getActiveProfileInterface();
if (profileInterface != null) {
ProfileStore profileStore = profileInterface.getProfile();
if (profileStore != null) {
String name = profileStore.getDefaultProfileName();
if (name != null) {
profileName = name;
}
}
}
inputProfileName = new InputProfileName(profileName);
} }
@Override @Override
@ -50,23 +62,43 @@ public class ActionProfileSwitch extends Action {
String activeProfileName = ProfileFunctions.getInstance().getProfileName(); String activeProfileName = ProfileFunctions.getInstance().getProfileName();
//Check for uninitialized profileName //Check for uninitialized profileName
if ( profileName.equals("")){ profileName = activeProfileName; } if ( profileName.equals("")){
log.error("Selected profile not initialized");
if (callback != null)
callback.result(new PumpEnactResult().success(false).comment(R.string.error_field_must_not_be_empty)).run();
return;
}
if ( ProfileFunctions.getInstance().getProfile() == null){
log.error("ProfileFunctions not initialized");
if (callback != null)
callback.result(new PumpEnactResult().success(false).comment(R.string.noprofile)).run();
return;
}
if (profileName.equals(activeProfileName)) { if (profileName.equals(activeProfileName)) {
// Profile is already switched if (L.isEnabled(L.AUTOMATION))
log.debug("Profile is already switched");
if (callback != null)
callback.result(new PumpEnactResult().success(true).comment(R.string.alreadyset)).run();
return; return;
} }
ProfileInterface activeProfile = ConfigBuilderPlugin.getPlugin().getActiveProfileInterface(); ProfileInterface activeProfile = ConfigBuilderPlugin.getPlugin().getActiveProfileInterface();
if (activeProfile == null) return; if (activeProfile == null) {
log.error("ProfileInterface not initialized");
if (callback != null)
callback.result(new PumpEnactResult().success(false).comment(R.string.noprofile)).run();
return;
}
ProfileStore profileStore = activeProfile.getProfile(); ProfileStore profileStore = activeProfile.getProfile();
if (profileStore == null) return; if (profileStore == null) return;
if(profileStore.getSpecificProfile(profileName) == null) { if(profileStore.getSpecificProfile(profileName) == null) {
if (L.isEnabled(L.AUTOMATION)) if (L.isEnabled(L.AUTOMATION))
log.error("Selected profile does not exist! - "+ profileName); log.error("Selected profile does not exist! - "+ profileName);
if (callback != null)
callback.result(new PumpEnactResult().success(false).comment(R.string.notexists)).run();
return; return;
} }
ProfileFunctions.doProfileSwitch(profileStore, profileName, 0, 100, 0); ProfileFunctions.doProfileSwitch(profileStore, profileName, 0, 100, 0, DateUtil.now());
if (callback != null) if (callback != null)
callback.result(new PumpEnactResult().success(true).comment(R.string.ok)).run(); callback.result(new PumpEnactResult().success(true).comment(R.string.ok)).run();
} }

View file

@ -75,7 +75,7 @@ public class ActionStartTempTarget extends Action {
int unitResId = value.getUnits().equals(Constants.MGDL) ? R.string.mgdl : R.string.mmol; int unitResId = value.getUnits().equals(Constants.MGDL) ? R.string.mgdl : R.string.mmol;
new LayoutBuilder() new LayoutBuilder()
.add(new LabelWithElement(MainApp.gs(R.string.careportal_temporarytarget) + " [" + MainApp.gs(unitResId) + "]", "", value)) .add(new LabelWithElement(MainApp.gs(R.string.careportal_temporarytarget) + "\n[" + MainApp.gs(unitResId) + "]", "", value))
.add(new LabelWithElement(MainApp.gs(R.string.careportal_newnstreatment_duration_min_label), "", duration)) .add(new LabelWithElement(MainApp.gs(R.string.careportal_newnstreatment_duration_min_label), "", duration))
.build(root); .build(root);
} }

View file

@ -32,7 +32,7 @@ class ActionListAdapter(private val fragmentManager: FragmentManager, private va
class ViewHolder(val view: View) : RecyclerView.ViewHolder(view) { class ViewHolder(val view: View) : RecyclerView.ViewHolder(view) {
fun bind(action: Action, fragmentManager: FragmentManager, recyclerView: RecyclerView.Adapter<ViewHolder>, position : Int, actionList: MutableList<Action>) { fun bind(action: Action, fragmentManager: FragmentManager, recyclerView: RecyclerView.Adapter<ViewHolder>, position: Int, actionList: MutableList<Action>) {
view.findViewById<LinearLayout>(R.id.automation_layoutText).setOnClickListener { view.findViewById<LinearLayout>(R.id.automation_layoutText).setOnClickListener {
if (action.hasDialog()) { if (action.hasDialog()) {
val args = Bundle() val args = Bundle()
@ -48,6 +48,7 @@ class ActionListAdapter(private val fragmentManager: FragmentManager, private va
recyclerView.notifyDataSetChanged() recyclerView.notifyDataSetChanged()
RxBus.send(EventAutomationUpdateGui()) RxBus.send(EventAutomationUpdateGui())
} }
if (action.icon().isPresent) view.findViewById<ImageView>(R.id.automation_action_image).setImageResource(action.icon().get())
view.findViewById<TextView>(R.id.automation_viewActionTitle).text = action.shortDescription() view.findViewById<TextView>(R.id.automation_viewActionTitle).text = action.shortDescription()
} }
} }

View file

@ -5,19 +5,18 @@ import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.RadioButton import android.widget.RadioButton
import androidx.fragment.app.DialogFragment
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.dialogs.DialogFragmentWithDate
import info.nightscout.androidaps.plugins.bus.RxBus import info.nightscout.androidaps.plugins.bus.RxBus
import info.nightscout.androidaps.plugins.general.automation.AutomationPlugin import info.nightscout.androidaps.plugins.general.automation.AutomationPlugin
import info.nightscout.androidaps.plugins.general.automation.actions.Action import info.nightscout.androidaps.plugins.general.automation.actions.Action
import info.nightscout.androidaps.plugins.general.automation.events.EventAutomationAddAction import info.nightscout.androidaps.plugins.general.automation.events.EventAutomationAddAction
import info.nightscout.androidaps.plugins.general.automation.events.EventAutomationUpdateGui import info.nightscout.androidaps.plugins.general.automation.events.EventAutomationUpdateGui
import kotlinx.android.synthetic.main.automation_dialog_choose_action.* import kotlinx.android.synthetic.main.automation_dialog_choose_action.*
import kotlinx.android.synthetic.main.okcancel.*
class ChooseActionDialog : DialogFragment() { class ChooseActionDialog : DialogFragmentWithDate() {
var checkedIndex = -1 private var checkedIndex = -1
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? { savedInstanceState: Bundle?): View? {
@ -26,7 +25,7 @@ class ChooseActionDialog : DialogFragment() {
checkedIndex = bundle.getInt("checkedIndex") checkedIndex = bundle.getInt("checkedIndex")
} }
dialog?.setCanceledOnTouchOutside(false) onCreateViewGeneral()
return inflater.inflate(R.layout.automation_dialog_choose_action, container, false) return inflater.inflate(R.layout.automation_dialog_choose_action, container, false)
} }
@ -42,27 +41,19 @@ class ChooseActionDialog : DialogFragment() {
if (checkedIndex != -1) if (checkedIndex != -1)
(automation_radioGroup.getChildAt(checkedIndex) as RadioButton).isChecked = true (automation_radioGroup.getChildAt(checkedIndex) as RadioButton).isChecked = true
}
// OK button override fun submit(): Boolean {
ok.setOnClickListener { instantiateAction()?.let {
dismiss() RxBus.send(EventAutomationAddAction(it))
instantiateAction()?.let { RxBus.send(EventAutomationUpdateGui())
RxBus.send(EventAutomationAddAction(it))
RxBus.send(EventAutomationUpdateGui())
}
} }
return true
// Cancel button
cancel.setOnClickListener { dismiss() }
} }
override fun onStart() { override fun onSaveInstanceState(savedInstanceState: Bundle) {
super.onStart() super.onSaveInstanceState(savedInstanceState)
dialog?.window?.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT) savedInstanceState.putInt("checkedIndex", determineCheckedIndex())
}
override fun onSaveInstanceState(bundle: Bundle) {
bundle.putInt("checkedIndex", determineCheckedIndex())
} }
private fun instantiateAction(): Action? { private fun instantiateAction(): Action? {
@ -86,5 +77,4 @@ class ChooseActionDialog : DialogFragment() {
} }
return -1 return -1
} }
} }

View file

@ -5,17 +5,15 @@ import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.RadioButton import android.widget.RadioButton
import androidx.fragment.app.DialogFragment
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.dialogs.DialogFragmentWithDate
import info.nightscout.androidaps.plugins.general.automation.AutomationPlugin import info.nightscout.androidaps.plugins.general.automation.AutomationPlugin
import info.nightscout.androidaps.plugins.general.automation.triggers.Trigger import info.nightscout.androidaps.plugins.general.automation.triggers.Trigger
import kotlinx.android.synthetic.main.automation_dialog_choose_trigger.* import kotlinx.android.synthetic.main.automation_dialog_choose_trigger.*
import kotlinx.android.synthetic.main.okcancel.*
class ChooseTriggerDialog : DialogFragment() { class ChooseTriggerDialog : DialogFragmentWithDate() {
private var checkedIndex = -1 private var checkedIndex = -1
private var clickListener: OnClickListener? = null private var clickListener: OnClickListener? = null
interface OnClickListener { interface OnClickListener {
@ -29,7 +27,7 @@ class ChooseTriggerDialog : DialogFragment() {
checkedIndex = bundle.getInt("checkedIndex") checkedIndex = bundle.getInt("checkedIndex")
} }
dialog?.setCanceledOnTouchOutside(false) onCreateViewGeneral()
return inflater.inflate(R.layout.automation_dialog_choose_trigger, container, false) return inflater.inflate(R.layout.automation_dialog_choose_trigger, container, false)
} }
@ -45,30 +43,22 @@ class ChooseTriggerDialog : DialogFragment() {
if (checkedIndex != -1) if (checkedIndex != -1)
(automation_chooseTriggerRadioGroup.getChildAt(checkedIndex) as RadioButton).isChecked = true (automation_chooseTriggerRadioGroup.getChildAt(checkedIndex) as RadioButton).isChecked = true
// OK button
ok.setOnClickListener {
dismiss()
instantiateTrigger()?.let {
clickListener?.onClick(it)
}
}
// Cancel button
cancel.setOnClickListener { dismiss() }
} }
override fun onStart() { override fun submit(): Boolean {
super.onStart() instantiateTrigger()?.let {
dialog?.window?.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT) clickListener?.onClick(it)
}
return true
} }
fun setOnClickListener(clickListener: OnClickListener) { fun setOnClickListener(clickListener: OnClickListener) {
this.clickListener = clickListener this.clickListener = clickListener
} }
override fun onSaveInstanceState(bundle: Bundle) { override fun onSaveInstanceState(savedInstanceState: Bundle) {
bundle.putInt("checkedIndex", determineCheckedIndex()) super.onSaveInstanceState(savedInstanceState)
savedInstanceState.putInt("checkedIndex", determineCheckedIndex())
} }
private fun instantiateTrigger(): Trigger? { private fun instantiateTrigger(): Trigger? {
@ -92,5 +82,4 @@ class ChooseTriggerDialog : DialogFragment() {
} }
return -1 return -1
} }
} }

View file

@ -4,16 +4,15 @@ import android.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.fragment.app.DialogFragment
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.dialogs.DialogFragmentWithDate
import info.nightscout.androidaps.plugins.bus.RxBus import info.nightscout.androidaps.plugins.bus.RxBus
import info.nightscout.androidaps.plugins.general.automation.actions.Action import info.nightscout.androidaps.plugins.general.automation.actions.Action
import info.nightscout.androidaps.plugins.general.automation.events.EventAutomationUpdateAction import info.nightscout.androidaps.plugins.general.automation.events.EventAutomationUpdateAction
import kotlinx.android.synthetic.main.automation_dialog_action.* import kotlinx.android.synthetic.main.automation_dialog_action.*
import kotlinx.android.synthetic.main.okcancel.*
import org.json.JSONObject import org.json.JSONObject
class EditActionDialog : DialogFragment() { class EditActionDialog : DialogFragmentWithDate() {
private var action: Action? = null private var action: Action? = null
private var actionPosition: Int = -1 private var actionPosition: Int = -1
@ -24,8 +23,7 @@ class EditActionDialog : DialogFragment() {
actionPosition = bundle.getInt("actionPosition", -1) actionPosition = bundle.getInt("actionPosition", -1)
bundle.getString("action")?.let { action = Action.instantiate(JSONObject(it)) } bundle.getString("action")?.let { action = Action.instantiate(JSONObject(it)) }
} }
onCreateViewGeneral()
dialog?.setCanceledOnTouchOutside(false)
return inflater.inflate(R.layout.automation_dialog_action, container, false) return inflater.inflate(R.layout.automation_dialog_action, container, false)
} }
@ -37,22 +35,13 @@ class EditActionDialog : DialogFragment() {
automation_editActionLayout.removeAllViews() automation_editActionLayout.removeAllViews()
it.generateDialog(automation_editActionLayout) it.generateDialog(automation_editActionLayout)
} }
// OK button
ok.setOnClickListener {
dismiss()
action?.let {
RxBus.send(EventAutomationUpdateAction(it, actionPosition))
}
}
// Cancel button
cancel.setOnClickListener { dismiss() }
} }
override fun onStart() { override fun submit(): Boolean {
super.onStart() action?.let {
dialog?.window?.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT) RxBus.send(EventAutomationUpdateAction(it, actionPosition))
}
return true
} }
override fun onSaveInstanceState(bundle: Bundle) { override fun onSaveInstanceState(bundle: Bundle) {

View file

@ -4,9 +4,9 @@ import android.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.fragment.app.DialogFragment
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.dialogs.DialogFragmentWithDate
import info.nightscout.androidaps.plugins.bus.RxBus import info.nightscout.androidaps.plugins.bus.RxBus
import info.nightscout.androidaps.plugins.general.automation.AutomationEvent import info.nightscout.androidaps.plugins.general.automation.AutomationEvent
import info.nightscout.androidaps.plugins.general.automation.AutomationPlugin import info.nightscout.androidaps.plugins.general.automation.AutomationPlugin
@ -17,9 +17,8 @@ import info.nightscout.androidaps.utils.ToastUtils
import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable import io.reactivex.disposables.CompositeDisposable
import kotlinx.android.synthetic.main.automation_dialog_event.* import kotlinx.android.synthetic.main.automation_dialog_event.*
import kotlinx.android.synthetic.main.okcancel.*
class EditEventDialog : DialogFragment() { class EditEventDialog : DialogFragmentWithDate() {
private var actionListAdapter: ActionListAdapter? = null private var actionListAdapter: ActionListAdapter? = null
private var event: AutomationEvent = AutomationEvent() private var event: AutomationEvent = AutomationEvent()
@ -35,7 +34,7 @@ class EditEventDialog : DialogFragment() {
bundle.getString("event")?.let { event = AutomationEvent().fromJSON(it) } bundle.getString("event")?.let { event = AutomationEvent().fromJSON(it) }
} }
dialog?.setCanceledOnTouchOutside(false) onCreateViewGeneral()
return inflater.inflate(R.layout.automation_dialog_event, container, false) return inflater.inflate(R.layout.automation_dialog_event, container, false)
} }
@ -60,39 +59,6 @@ class EditEventDialog : DialogFragment() {
automation_addAction.setOnClickListener { fragmentManager?.let { ChooseActionDialog().show(it, "ChooseActionDialog") } } automation_addAction.setOnClickListener { fragmentManager?.let { ChooseActionDialog().show(it, "ChooseActionDialog") } }
// OK button
ok.setOnClickListener {
// check for title
val title = automation_inputEventTitle.text.toString()
if (title.isEmpty()) {
ToastUtils.showToastInUiThread(context, R.string.automation_missing_task_name)
return@setOnClickListener
}
event.title = title
// check for at least one trigger
val con = event.trigger as TriggerConnector
if (con.size() == 0) {
ToastUtils.showToastInUiThread(context, R.string.automation_missing_trigger)
return@setOnClickListener
}
// check for at least one action
if (event.actions.isEmpty()) {
ToastUtils.showToastInUiThread(context, R.string.automation_missing_action)
return@setOnClickListener
}
// store
if (position == -1)
AutomationPlugin.automationEvents.add(event)
else
AutomationPlugin.automationEvents[position] = event
dismiss()
RxBus.send(EventAutomationDataChanged())
}
// Cancel button
cancel.setOnClickListener { dismiss() }
showPreconditions() showPreconditions()
disposable.add(RxBus disposable.add(RxBus
@ -137,9 +103,33 @@ class EditEventDialog : DialogFragment() {
) )
} }
override fun onStart() { override fun submit() : Boolean{
super.onStart() // check for title
dialog?.window?.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT) val title = automation_inputEventTitle.text.toString()
if (title.isEmpty()) {
ToastUtils.showToastInUiThread(context, R.string.automation_missing_task_name)
return false
}
event.title = title
// check for at least one trigger
val con = event.trigger as TriggerConnector
if (con.size() == 0) {
ToastUtils.showToastInUiThread(context, R.string.automation_missing_trigger)
return false
}
// check for at least one action
if (event.actions.isEmpty()) {
ToastUtils.showToastInUiThread(context, R.string.automation_missing_action)
return false
}
// store
if (position == -1)
AutomationPlugin.automationEvents.add(event)
else
AutomationPlugin.automationEvents[position] = event
RxBus.send(EventAutomationDataChanged())
return true
} }
override fun onDestroyView() { override fun onDestroyView() {
@ -147,10 +137,10 @@ class EditEventDialog : DialogFragment() {
disposable.clear() disposable.clear()
} }
override fun onSaveInstanceState(bundle: Bundle) { override fun onSaveInstanceState(savedInstanceState: Bundle) {
super.onSaveInstanceState(bundle) super.onSaveInstanceState(savedInstanceState)
bundle.putString("event", event.toJSON()) savedInstanceState.putString("event", event.toJSON())
bundle.putInt("position", position) savedInstanceState.putInt("position", position)
} }
private fun showPreconditions() { private fun showPreconditions() {
@ -164,5 +154,4 @@ class EditEventDialog : DialogFragment() {
automation_forcedTriggerDescriptionLabel.visibility = View.GONE automation_forcedTriggerDescriptionLabel.visibility = View.GONE
} }
} }
} }

View file

@ -4,15 +4,14 @@ import android.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.fragment.app.DialogFragment
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.dialogs.DialogFragmentWithDate
import info.nightscout.androidaps.plugins.bus.RxBus import info.nightscout.androidaps.plugins.bus.RxBus
import info.nightscout.androidaps.plugins.general.automation.events.EventAutomationUpdateTrigger import info.nightscout.androidaps.plugins.general.automation.events.EventAutomationUpdateTrigger
import info.nightscout.androidaps.plugins.general.automation.triggers.Trigger import info.nightscout.androidaps.plugins.general.automation.triggers.Trigger
import kotlinx.android.synthetic.main.automation_dialog_edit_trigger.* import kotlinx.android.synthetic.main.automation_dialog_edit_trigger.*
import kotlinx.android.synthetic.main.okcancel.*
class EditTriggerDialog : DialogFragment() { class EditTriggerDialog : DialogFragmentWithDate() {
private var trigger: Trigger? = null private var trigger: Trigger? = null
@ -23,7 +22,7 @@ class EditTriggerDialog : DialogFragment() {
bundle.getString("trigger")?.let { trigger = Trigger.instantiate(it) } bundle.getString("trigger")?.let { trigger = Trigger.instantiate(it) }
} }
dialog?.setCanceledOnTouchOutside(false) onCreateViewGeneral()
return inflater.inflate(R.layout.automation_dialog_edit_trigger, container, false) return inflater.inflate(R.layout.automation_dialog_edit_trigger, container, false)
} }
@ -32,24 +31,15 @@ class EditTriggerDialog : DialogFragment() {
// display root trigger // display root trigger
trigger?.generateDialog(automation_layoutTrigger, fragmentManager) trigger?.generateDialog(automation_layoutTrigger, fragmentManager)
// OK button
ok.setOnClickListener {
dismiss()
trigger?.let { trigger -> RxBus.send(EventAutomationUpdateTrigger(trigger)) }
}
// Cancel button
cancel.setOnClickListener { dismiss() }
} }
override fun onStart() { override fun submit():Boolean {
super.onStart() trigger?.let { trigger -> RxBus.send(EventAutomationUpdateTrigger(trigger)) }
dialog?.window?.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT) return true
} }
override fun onSaveInstanceState(bundle: Bundle) { override fun onSaveInstanceState(savedInstanceState: Bundle) {
super.onSaveInstanceState(bundle) super.onSaveInstanceState(savedInstanceState)
trigger?.let { bundle.putString("trigger", it.toJSON()) } trigger?.let { savedInstanceState.putString("trigger", it.toJSON()) }
} }
} }

View file

@ -75,7 +75,7 @@ public class TriggerListAdapter {
private Spinner createSpinner() { private Spinner createSpinner() {
Spinner spinner = new Spinner(mContext); Spinner spinner = new Spinner(mContext);
ArrayAdapter<String> spinnerArrayAdapter = new ArrayAdapter<>(mContext, android.R.layout.simple_spinner_item, TriggerConnector.Type.labels()); ArrayAdapter<String> spinnerArrayAdapter = new ArrayAdapter<>(mContext, R.layout.spinner_centered, TriggerConnector.Type.labels());
spinnerArrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); spinnerArrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner.setAdapter(spinnerArrayAdapter); spinner.setAdapter(spinnerArrayAdapter);
return spinner; return spinner;

Some files were not shown because too many files have changed in this diff Show more