Merge Upstream

This commit is contained in:
Tim Gunn 2020-01-29 22:37:44 +13:00
commit 0ea13b5671
No known key found for this signature in database
GPG key ID: C9BC1E9D0D0AED8C
334 changed files with 13264 additions and 9371 deletions

11
.gitignore vendored
View file

@ -6,10 +6,17 @@
/captures
*.apk
build/
.idea/
.idea/*
!.idea/codeStyles/
app/src/main/jniLibs
full/
debug/
release/
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,137 @@
<component name="ProjectCodeStyleConfiguration">
<code_scheme name="Project" version="173">
<option name="AUTODETECT_INDENTS" value="false" />
<AndroidXmlCodeStyleSettings>
<option name="ARRANGEMENT_SETTINGS_MIGRATED_TO_191" value="true" />
</AndroidXmlCodeStyleSettings>
<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

@ -226,6 +226,8 @@ dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation 'com.google.android.gms:play-services-wearable:17.0.0'
implementation 'com.google.firebase:firebase-core:17.2.1'
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;
}
@ -264,7 +266,10 @@ dependencies {
exclude group: "org.json", module: "json"
}
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.10.3"
@ -282,6 +287,7 @@ dependencies {
testImplementation "joda-time:joda-time:2.10.5"
testImplementation("com.google.truth:truth:0.39") {
exclude group: "com.google.guava", module: "guava"
exclude group: "com.google.code.findbugs", module: "jsr305"
}
testImplementation "org.skyscreamer:jsonassert:1.5.0"
testImplementation "org.hamcrest:hamcrest-all:1.3"
@ -291,9 +297,6 @@ 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-reflect:$kotlin_version"
@ -305,6 +308,13 @@ dependencies {
implementation "com.squareup.retrofit2:adapter-rxjava2:2.6.2"
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'
}

View file

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

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,27 @@
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
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)
}

View file

@ -0,0 +1,222 @@
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.*
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.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.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() {
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())
// Loction 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())
}
// 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())
onView(Matchers.allOf(withText("OK"), isDisplayed())).perform(click())
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())
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

@ -51,12 +51,11 @@
</activity>
<activity android:name=".activities.PreferencesActivity" />
<activity
android:name=".plugins.general.overview.dialogs.BolusProgressHelperActivity"
android:name=".activities.BolusProgressHelperActivity"
android:theme="@style/Theme.AppCompat.Translucent" />
<activity
android:name=".plugins.general.overview.dialogs.ErrorHelperActivity"
android:name=".activities.ErrorHelperActivity"
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.DanaRUserOptionsActivity" />
<activity android:name=".activities.TDDStatsActivity" />
@ -76,6 +75,8 @@
</activity>
<activity android:name=".plugins.pump.danaRS.activities.PairingHelperActivity" />
<activity android:name=".activities.HistoryBrowseActivity" />
<activity android:name=".activities.SurveyActivity" />
<activity android:name=".activities.StatsActivity" />
<!-- Receive new BG readings from other local apps -->
<receiver
@ -114,7 +115,7 @@
<!-- Auto start -->
<receiver
android:name=".plugins.general.nsclient.receivers.AutoStartReceiver"
android:name=".receivers.AutoStartReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
@ -122,16 +123,6 @@
</intent-filter>
</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 -->
<receiver android:name=".receivers.NetworkChangeReceiver">
<intent-filter>

View file

@ -25,8 +25,6 @@ public class Constants {
public static final int hoursToKeepInDatabase = 72;
public static final int daysToKeepHistoryInDatabase = 30;
public static final long keepAliveMsecs = 5 * 60 * 1000L;
// SMS COMMUNICATOR
public static final long remoteBolusMinDistance = 15 * 60 * 1000L;
@ -78,4 +76,15 @@ public class Constants {
//Storage [MB]
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

@ -41,6 +41,7 @@ import info.nightscout.androidaps.activities.HistoryBrowseActivity;
import info.nightscout.androidaps.activities.NoSplashAppCompatActivity;
import info.nightscout.androidaps.activities.PreferencesActivity;
import info.nightscout.androidaps.activities.SingleFragmentActivity;
import info.nightscout.androidaps.activities.StatsActivity;
import info.nightscout.androidaps.events.EventAppExit;
import info.nightscout.androidaps.events.EventPreferenceChange;
import info.nightscout.androidaps.events.EventRebuildTabs;
@ -56,6 +57,7 @@ import info.nightscout.androidaps.tabs.TabPageAdapter;
import info.nightscout.androidaps.utils.AndroidPermission;
import info.nightscout.androidaps.utils.FabricPrivacy;
import info.nightscout.androidaps.utils.LocaleHelper;
import info.nightscout.androidaps.utils.OKDialog;
import info.nightscout.androidaps.utils.PasswordProtection;
import info.nightscout.androidaps.utils.SP;
import io.reactivex.android.schedulers.AndroidSchedulers;
@ -90,8 +92,6 @@ public class MainActivity extends NoSplashAppCompatActivity {
// initialize screen wake lock
processPreferenceChange(new EventPreferenceChange(R.string.key_keep_screen_on));
doMigrations();
final ViewPager viewPager = findViewById(R.id.pager);
viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
@ -137,7 +137,7 @@ public class MainActivity extends NoSplashAppCompatActivity {
.subscribe(this::processPreferenceChange, FabricPrivacy::logException)
);
if (!SP.getBoolean(R.string.key_setupwizard_processed, false) || !SP.contains(R.string.key_units)) {
if (!SP.getBoolean(R.string.key_setupwizard_processed, false)) {
Intent intent = new Intent(this, SetupWizardActivity.class);
startActivity(intent);
}
@ -231,17 +231,6 @@ public class MainActivity extends NoSplashAppCompatActivity {
}
}
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));
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
@ -250,10 +239,7 @@ public class MainActivity extends NoSplashAppCompatActivity {
switch (requestCode) {
case AndroidPermission.CASE_STORAGE:
//show dialog after permission is granted
AlertDialog.Builder alert = new AlertDialog.Builder(this);
alert.setMessage(R.string.alert_dialog_storage_permission_text);
alert.setPositiveButton(R.string.ok, null);
alert.show();
OKDialog.show(this, "", MainApp.gs(R.string.alert_dialog_storage_permission_text));
break;
case AndroidPermission.CASE_LOCATION:
case AndroidPermission.CASE_SMS:
@ -327,9 +313,7 @@ public class MainActivity extends NoSplashAppCompatActivity {
return true;
case R.id.nav_exit:
log.debug("Exiting");
MainApp.instance().stopKeepAliveService();
RxBus.INSTANCE.send(new EventAppExit());
MainApp.closeDbHelper();
finish();
System.runFinalization();
System.exit(0);
@ -343,6 +327,14 @@ public class MainActivity extends NoSplashAppCompatActivity {
startActivity(i);
}, null);
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);
}

View file

@ -1,12 +1,14 @@
package info.nightscout.androidaps;
import android.app.Application;
import android.content.BroadcastReceiver;
import android.content.IntentFilter;
import android.content.res.Resources;
import android.os.SystemClock;
import androidx.annotation.ColorRes;
import androidx.annotation.PluralsRes;
import androidx.annotation.StringRes;
import androidx.core.content.ContextCompat;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import com.crashlytics.android.Crashlytics;
@ -15,6 +17,7 @@ import com.j256.ormlite.android.apptools.OpenHelperManager;
import net.danlew.android.joda.JodaTimeAndroid;
import org.json.JSONException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -22,6 +25,7 @@ import java.io.File;
import java.util.ArrayList;
import info.nightscout.androidaps.data.ConstraintChecker;
import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.db.DatabaseHelper;
import info.nightscout.androidaps.interfaces.PluginBase;
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.openAPSSMB.OpenAPSSMBPlugin;
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.objectives.ObjectivesPlugin;
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.nsclient.NSClientPlugin;
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.persistentNotification.PersistentNotificationPlugin;
import info.nightscout.androidaps.plugins.general.smsCommunicator.SmsCommunicatorPlugin;
@ -72,6 +75,7 @@ import info.nightscout.androidaps.plugins.sensitivity.SensitivityAAPSPlugin;
import info.nightscout.androidaps.plugins.sensitivity.SensitivityOref0Plugin;
import info.nightscout.androidaps.plugins.sensitivity.SensitivityOref1Plugin;
import info.nightscout.androidaps.plugins.sensitivity.SensitivityWeightedAveragePlugin;
import info.nightscout.androidaps.plugins.source.RandomBgPlugin;
import info.nightscout.androidaps.plugins.source.SourceDexcomPlugin;
import info.nightscout.androidaps.plugins.source.SourceEversensePlugin;
import info.nightscout.androidaps.plugins.source.SourceGlimpPlugin;
@ -86,8 +90,10 @@ import info.nightscout.androidaps.receivers.KeepAliveReceiver;
import info.nightscout.androidaps.receivers.NSAlarmReceiver;
import info.nightscout.androidaps.receivers.TimeDateOrTZChangeReceiver;
import info.nightscout.androidaps.services.Intents;
import info.nightscout.androidaps.utils.ActivityMonitor;
import info.nightscout.androidaps.utils.FabricPrivacy;
import info.nightscout.androidaps.utils.LocaleHelper;
import info.nightscout.androidaps.utils.SP;
import io.fabric.sdk.android.Fabric;
import static info.nightscout.androidaps.plugins.constraints.versionChecker.VersionCheckerUtilsKt.triggerCheckVersion;
@ -95,7 +101,6 @@ import static info.nightscout.androidaps.plugins.constraints.versionChecker.Vers
public class MainApp extends Application {
private static Logger log = LoggerFactory.getLogger(L.CORE);
private static KeepAliveReceiver keepAliveReceiver;
private static MainApp sInstance;
public static Resources sResources;
@ -108,11 +113,7 @@ public class MainApp extends Application {
private static ArrayList<PluginBase> pluginsList = null;
private static DataReceiver dataReceiver = new DataReceiver();
private static NSAlarmReceiver alarmReciever = new NSAlarmReceiver();
private static AckAlarmReceiver ackAlarmReciever = new AckAlarmReceiver();
private static DBAccessReceiver dbAccessReciever = new DBAccessReceiver();
private LocalBroadcastManager lbm;
BroadcastReceiver btReceiver;
private static NSAlarmReceiver alarmReceiver = new NSAlarmReceiver();
TimeDateOrTZChangeReceiver timeDateOrTZChangeReceiver;
public static boolean devBranch;
@ -145,6 +146,8 @@ public class MainApp extends Application {
log.error("Error with Fabric init! " + e);
}
registerActivityLifecycleCallbacks(ActivityMonitor.INSTANCE);
mFirebaseAnalytics = FirebaseAnalytics.getInstance(this);
mFirebaseAnalytics.setAnalyticsCollectionEnabled(!Boolean.getBoolean("disableFirebase"));
@ -164,7 +167,6 @@ public class MainApp extends Application {
//trigger here to see the new version on app start after an update
triggerCheckVersion();
//setBTReceiver();
if (pluginsList == null) {
pluginsList = new ArrayList<>();
@ -188,7 +190,7 @@ public class MainApp extends Application {
if (Config.PUMPDRIVERS) pluginsList.add(MedtronicPumpPlugin.getPlugin());
if (!Config.NSCLIENT) pluginsList.add(MDIPlugin.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(OpenAPSMAPlugin.getPlugin());
if (Config.APS) pluginsList.add(OpenAPSAMAPlugin.getPlugin());
@ -209,6 +211,7 @@ public class MainApp extends Application {
pluginsList.add(SourcePoctechPlugin.getPlugin());
pluginsList.add(SourceTomatoPlugin.getPlugin());
pluginsList.add(SourceEversensePlugin.getPlugin());
pluginsList.add(RandomBgPlugin.INSTANCE);
if (!Config.NSCLIENT) pluginsList.add(SmsCommunicatorPlugin.INSTANCE);
pluginsList.add(FoodPlugin.getPlugin());
@ -235,13 +238,40 @@ public class MainApp extends Application {
new Thread(() -> {
SystemClock.sleep(5000);
ConfigBuilderPlugin.getPlugin().getCommandQueue().readStatus("Initialization", null);
startKeepAliveService();
}).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() {
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_CHANGED_TREATMENT));
lbm.registerReceiver(dataReceiver, new IntentFilter(Intents.ACTION_REMOVED_TREATMENT));
@ -256,39 +286,21 @@ public class MainApp extends Application {
lbm.registerReceiver(dataReceiver, new IntentFilter(Intents.ACTION_NEW_CAL));
//register alarms
lbm.registerReceiver(alarmReciever, new IntentFilter(Intents.ACTION_ALARM));
lbm.registerReceiver(alarmReciever, new IntentFilter(Intents.ACTION_ANNOUNCEMENT));
lbm.registerReceiver(alarmReciever, new IntentFilter(Intents.ACTION_CLEAR_ALARM));
lbm.registerReceiver(alarmReciever, 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));
lbm.registerReceiver(alarmReceiver, new IntentFilter(Intents.ACTION_ALARM));
lbm.registerReceiver(alarmReceiver, new IntentFilter(Intents.ACTION_ANNOUNCEMENT));
lbm.registerReceiver(alarmReceiver, new IntentFilter(Intents.ACTION_CLEAR_ALARM));
lbm.registerReceiver(alarmReceiver, new IntentFilter(Intents.ACTION_URGENT_ALARM));
this.timeDateOrTZChangeReceiver = new TimeDateOrTZChangeReceiver();
this.timeDateOrTZChangeReceiver.registerBroadcasts(this);
}
private void startKeepAliveService() {
if (keepAliveReceiver == null) {
keepAliveReceiver = new KeepAliveReceiver();
keepAliveReceiver.setAlarm(this);
}
}
public void stopKeepAliveService() {
if (keepAliveReceiver != null)
KeepAliveReceiver.cancelAlarm(this);
}
public static String gs(int id) {
public static String gs(@StringRes int 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);
}
@ -296,8 +308,8 @@ public class MainApp extends Application {
return sResources.getQuantityString(id, quantity, args);
}
public static int gc(int id) {
return sResources.getColor(id);
public static int gc(@ColorRes int id) {
return ContextCompat.getColor(instance(), id);
}
public static MainApp instance() {
@ -308,13 +320,6 @@ public class MainApp extends Application {
return sDatabaseHelper;
}
public static void closeDbHelper() {
if (sDatabaseHelper != null) {
sDatabaseHelper.close();
sDatabaseHelper = null;
}
}
public static FirebaseAnalytics getFirebaseAnalytics() {
return mFirebaseAnalytics;
}
@ -417,20 +422,12 @@ public class MainApp extends Application {
public void onTerminate() {
if (L.isEnabled(L.CORE))
log.debug("onTerminate");
super.onTerminate();
if (sDatabaseHelper != null) {
sDatabaseHelper.close();
sDatabaseHelper = null;
}
if (btReceiver != null) {
unregisterReceiver(btReceiver);
}
if (timeDateOrTZChangeReceiver != null) {
if (timeDateOrTZChangeReceiver != null)
unregisterReceiver(timeDateOrTZChangeReceiver);
}
unregisterActivityLifecycleCallbacks(ActivityMonitor.INSTANCE);
KeepAliveReceiver.cancelAlarm(this);
super.onTerminate();
}
public static int dpToPx(int dp) {

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 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.utils.SP
class ErrorHelperActivity : NoSplashAppCompatActivity() {
class ErrorHelperActivity : DialogAppCompatActivity() {
@Override
override fun onCreate(savedInstanceState: Bundle?) {

View file

@ -89,7 +89,7 @@ public class PreferencesActivity extends PreferenceActivity implements SharedPre
return;
}
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));
}

View file

@ -3,7 +3,7 @@ package info.nightscout.androidaps.activities
import android.os.Bundle
import info.nightscout.androidaps.plugins.source.SourceDexcomPlugin
class RequestDexcomPermissionActivity : NoSplashAppCompatActivity() {
class RequestDexcomPermissionActivity : DialogAppCompatActivity() {
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

@ -397,7 +397,7 @@ public class Profile {
return toMgdl(getIsfTimeFromMidnight(secondsFromMidnight(time)), units);
}
double getIsfTimeFromMidnight(int timeAsSeconds) {
public double getIsfTimeFromMidnight(int timeAsSeconds) {
if (isf_v == null)
isf_v = convertToSparseArray(isf);
return getValueToTime(isf_v, timeAsSeconds);
@ -589,7 +589,7 @@ public class Profile {
public double getMaxDailyBasal() {
double max = 0d;
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;
}
return max;

View file

@ -1,6 +1,7 @@
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
@ -40,21 +41,19 @@ class ProfileStore(val data: JSONObject) {
fun getSpecificProfile(profileName: String): Profile? {
var profile: Profile? = null
try {
getStore()?.let { store ->
if (store.has(profileName)) {
profile = cachedObjects[profileName]
if (profile == null) {
val profileObject = store.getJSONObject(profileName)
if (profileObject != null && profileObject.has("units")) {
profile = Profile(profileObject, profileObject.getString("units"))
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
}
}
}
}
} catch (e: JSONException) {
log.error("Unhandled exception", e)
}
return profile
}

View file

@ -125,7 +125,8 @@ public class QuickWizardEntry {
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() {

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

@ -3,6 +3,7 @@ package info.nightscout.androidaps.db;
import android.content.Context;
import android.database.DatabaseUtils;
import android.database.sqlite.SQLiteDatabase;
import androidx.annotation.Nullable;
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.MainApp;
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.ProfileStore;
import info.nightscout.androidaps.events.EventCareportalEventChange;
@ -193,15 +194,6 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
return newVersion;
}
/**
* Close the database connections and clear any cached DAOs.
*/
@Override
public void close() {
super.close();
}
public long size(String database) {
return DatabaseUtils.queryNumEntries(getReadableDatabase(), database);
}
@ -558,12 +550,8 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
// ------------- DbRequests handling -------------------
public void create(DbRequest dbr) {
try {
public void create(DbRequest dbr) throws SQLException {
getDaoDbRequest().create(dbr);
} catch (SQLException e) {
log.error("Unhandled exception", e);
}
}
public int delete(DbRequest dbr) {
@ -772,8 +760,8 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
TempTarget tempTarget = new TempTarget()
.date(trJson.getLong("mills"))
.duration(JsonHelper.safeGetInt(trJson, "duration"))
.low(Profile.toMgdl(trJson.getDouble("targetBottom"), units))
.high(Profile.toMgdl(trJson.getDouble("targetTop"), units))
.low(Profile.toMgdl(JsonHelper.safeGetDouble(trJson, "targetBottom"), units))
.high(Profile.toMgdl(JsonHelper.safeGetDouble(trJson, "targetTop"), units))
.reason(JsonHelper.safeGetString(trJson, "reason", ""))
._id(trJson.getString("_id"))
.source(Source.NIGHTSCOUT);
@ -1425,7 +1413,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
QueryBuilder<CareportalEvent, Long> queryBuilder = getDaoCareportalEvents().queryBuilder();
queryBuilder.orderBy("date", false);
Where where = queryBuilder.where();
where.eq("eventType", event);
where.eq("eventType", event).and().isNotNull("json");
queryBuilder.limit(1L);
PreparedQuery<CareportalEvent> preparedQuery = queryBuilder.prepare();
careportalEvents = getDaoCareportalEvents().query(preparedQuery);
@ -1445,10 +1433,10 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
QueryBuilder<CareportalEvent, Long> queryBuilder = getDaoCareportalEvents().queryBuilder();
queryBuilder.orderBy("date", ascending);
Where where = queryBuilder.where();
where.ge("date", mills);
where.ge("date", mills).and().isNotNull("json").and().isNotNull("eventType");
PreparedQuery<CareportalEvent> preparedQuery = queryBuilder.prepare();
careportalEvents = getDaoCareportalEvents().query(preparedQuery);
preprocessOpenAPSOfflineEvents(careportalEvents);
careportalEvents = preprocessOpenAPSOfflineEvents(careportalEvents);
return careportalEvents;
} catch (SQLException e) {
log.error("Unhandled exception", e);
@ -1462,10 +1450,10 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
QueryBuilder<CareportalEvent, Long> queryBuilder = getDaoCareportalEvents().queryBuilder();
queryBuilder.orderBy("date", ascending);
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();
careportalEvents = getDaoCareportalEvents().query(preparedQuery);
preprocessOpenAPSOfflineEvents(careportalEvents);
careportalEvents = preprocessOpenAPSOfflineEvents(careportalEvents);
return careportalEvents;
} catch (SQLException e) {
log.error("Unhandled exception", e);
@ -1473,14 +1461,16 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
return new ArrayList<>();
}
public void preprocessOpenAPSOfflineEvents(List<CareportalEvent> list) {
OverlappingIntervals offlineEvents = new OverlappingIntervals();
public List<CareportalEvent> preprocessOpenAPSOfflineEvents(List<CareportalEvent> list) {
NonOverlappingIntervals offlineEvents = new NonOverlappingIntervals();
List<CareportalEvent> other = new ArrayList<>();
for (int i = 0; i < list.size(); i++) {
CareportalEvent event = list.get(i);
if (!event.eventType.equals(CareportalEvent.OPENAPSOFFLINE)) continue;
offlineEvents.add(event);
if (event.eventType.equals(CareportalEvent.OPENAPSOFFLINE)) offlineEvents.add(event);
else other.add(event);
}
other.addAll(offlineEvents.getList());
return other;
}
public List<CareportalEvent> getCareportalEventsFromTime(long mills, String type, boolean ascending) {
@ -1489,10 +1479,10 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
QueryBuilder<CareportalEvent, Long> queryBuilder = getDaoCareportalEvents().queryBuilder();
queryBuilder.orderBy("date", ascending);
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();
careportalEvents = getDaoCareportalEvents().query(preparedQuery);
preprocessOpenAPSOfflineEvents(careportalEvents);
careportalEvents = preprocessOpenAPSOfflineEvents(careportalEvents);
return careportalEvents;
} catch (SQLException e) {
log.error("Unhandled exception", e);
@ -1505,9 +1495,11 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
List<CareportalEvent> careportalEvents;
QueryBuilder<CareportalEvent, Long> queryBuilder = getDaoCareportalEvents().queryBuilder();
queryBuilder.orderBy("date", ascending);
Where where = queryBuilder.where();
where.isNotNull("json").and().isNotNull("eventType");
PreparedQuery<CareportalEvent> preparedQuery = queryBuilder.prepare();
careportalEvents = getDaoCareportalEvents().query(preparedQuery);
preprocessOpenAPSOfflineEvents(careportalEvents);
careportalEvents = preprocessOpenAPSOfflineEvents(careportalEvents);
return careportalEvents;
} catch (SQLException e) {
log.error("Unhandled exception", e);
@ -1592,15 +1584,23 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
// ---------------- ProfileSwitch handling ---------------
public List<ProfileSwitch> getProfileSwitchData(boolean ascending) {
public List<ProfileSwitch> getProfileSwitchData(long from, boolean ascending) {
try {
Dao<ProfileSwitch, Long> daoProfileSwitch = getDaoProfileSwitch();
List<ProfileSwitch> profileSwitches;
QueryBuilder<ProfileSwitch, Long> queryBuilder = daoProfileSwitch.queryBuilder();
queryBuilder.orderBy("date", ascending);
queryBuilder.limit(100L);
Where where = queryBuilder.where();
where.ge("date", from);
PreparedQuery<ProfileSwitch> preparedQuery = queryBuilder.prepare();
profileSwitches = daoProfileSwitch.query(preparedQuery);
//add last one without duration
ProfileSwitch last = getLastProfileSwitchWithoutDuration();
if (last != null) {
if (!profileSwitches.contains(last))
profileSwitches.add(last);
}
return profileSwitches;
} catch (SQLException e) {
log.error("Unhandled exception", e);
@ -1608,6 +1608,28 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
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) {
try {
Dao<ProfileSwitch, Long> daoProfileSwitch = getDaoProfileSwitch();

View file

@ -11,6 +11,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import info.nightscout.androidaps.logging.L;
import info.nightscout.androidaps.utils.DateUtil;
/**
* Created by mike on 27.02.2016.
@ -40,36 +41,49 @@ public class DbRequest {
}
// dbAdd
public DbRequest(String action, String collection, String nsClientID, JSONObject data) {
public DbRequest(String action, String collection, JSONObject data) {
this.action = action;
this.collection = collection;
this.nsClientID = "" + DateUtil.now();
try {
data.put("NSCLIENT_ID", nsClientID);
} catch (JSONException e) {
e.printStackTrace();
}
this.data = data.toString();
this.nsClientID = nsClientID;
this._id = "";
}
// dbUpdate, dbUpdateUnset
public DbRequest(String action, String collection, String nsClientID, String _id, JSONObject data) {
public DbRequest(String action, String collection, String _id, JSONObject data) {
this.action = action;
this.collection = collection;
this.nsClientID = "" + DateUtil.now();
try {
data.put("NSCLIENT_ID", nsClientID);
} catch (JSONException e) {
e.printStackTrace();
}
this.data = data.toString();
this.nsClientID = nsClientID;
this._id = _id;
}
// dbRemove
public DbRequest(String action, String collection, String nsClientID, String _id) {
public DbRequest(String action, String collection,
String _id) {
JSONObject data = new JSONObject();
this.action = action;
this.collection = collection;
this.data = new JSONObject().toString();
this.nsClientID = nsClientID;
this.nsClientID = "" + DateUtil.now();
try {
data.put("NSCLIENT_ID", nsClientID);
} catch (JSONException e) {
e.printStackTrace();
}
this.data = data.toString();
this._id = _id;
}
public String hash() {
return Hashing.sha1().hashString(action + collection + _id + data.toString(), Charsets.UTF_8).toString();
}
public JSONObject toJSON() {
JSONObject object = new JSONObject();
try {

View file

@ -325,8 +325,8 @@ public class ExtendedBolus implements Interval, DataPointWithLabelInterface {
}
public String toStringMedium() {
return "E " + DecimalFormatter.to2Decimal(absoluteRate()) + "U/h ("
+ getRealDuration() + "/" + durationInMinutes + ") ";
return DecimalFormatter.to2Decimal(absoluteRate()) + "U/h "
+ getRealDuration() + "/" + durationInMinutes + "'";
}
public String toStringTotal() {

View file

@ -6,8 +6,11 @@ import com.j256.ormlite.table.DatabaseTable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.logging.L;
import info.nightscout.androidaps.plugins.pump.common.utils.DateTimeUtil;
import info.nightscout.androidaps.utils.DateUtil;
/**
* Created by mike on 20.09.2017.
@ -56,4 +59,12 @@ public class TDD {
", 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

@ -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,68 @@
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 {
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,223 @@
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) {
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) {
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) {
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) {
CarbsGenerator.createCarb(carbsAfterConstraints, time, CareportalEvent.CARBCORRECTION, notes)
} else {
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,189 @@
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()
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() {
private 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.Intent
import android.os.Build
@ -7,11 +6,14 @@ import android.os.Bundle
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.ErrorHelperActivity
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
class ErrorDialog : DialogFragment() {
@ -24,20 +26,23 @@ class ErrorDialog : DialogFragment() {
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
dialog?.setTitle(title)
isCancelable = false
dialog?.window?.requestFeature(Window.FEATURE_NO_TITLE)
dialog?.window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN)
isCancelable = true
dialog?.setCanceledOnTouchOutside(false)
savedInstanceState?.let { bundle ->
bundle.getString("status")?.let { status = it }
bundle.getString("title")?.let { title = it }
sound = bundle.getInt("sound", R.raw.error)
}
return inflater.inflate(R.layout.overview_error_dialog, container, false)
return inflater.inflate(R.layout.dialog_error, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
error_title.text = title
overview_error_ok.setOnClickListener {
log.debug("Error dialog ok button pressed")
dismiss()
@ -56,9 +61,13 @@ class ErrorDialog : DialogFragment() {
bundle.putInt("sound", sound)
}
override fun onStart() {
super.onStart()
dialog?.window?.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
}
override fun onResume() {
super.onResume()
dialog?.window?.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
overview_error_status.text = status
}
@ -81,5 +90,5 @@ class ErrorDialog : DialogFragment() {
}
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,82 @@
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 {
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,169 @@
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) {
requestPrimeBolus(insulinAfterConstraints, notes)
}
if (siteChange) {
generateCareportalEvent(CareportalEvent.SITECHANGE, eventTime, notes)
}
if (insulinChange) {
// add a second for case of both checked
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,193 @@
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) {
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) {
detailedBolusInfo.date = time
TreatmentsPlugin.getPlugin().addToHistoryTreatment(detailedBolusInfo, false)
} else {
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,105 @@
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 {
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.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.Constants
import info.nightscout.androidaps.MainApp
import info.nightscout.androidaps.R
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.utils.DateUtil
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() {
private var time: Long = 0
enum class Mode(val i: Int) {
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?,
savedInstanceState: Bundle?): View? {
@ -31,19 +36,23 @@ class ProfileViewerDialog : DialogFragment() {
(savedInstanceState ?: arguments)?.let { bundle ->
time = bundle.getLong("time", 0)
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?) {
super.onViewCreated(view, savedInstanceState)
close.setOnClickListener { dismiss() }
profileview_reload.setOnClickListener {
ConfigBuilderPlugin.getPlugin().commandQueue.readStatus("ProfileViewDialog", null)
dismiss()
}
val profile: Profile?
val profileName: String?
@ -53,15 +62,14 @@ class ProfileViewerDialog : DialogFragment() {
profile = TreatmentsPlugin.getPlugin().getProfileSwitchFromHistory(time)?.profileObject
profileName = TreatmentsPlugin.getPlugin().getProfileSwitchFromHistory(time)?.customizedName
date = DateUtil.dateAndTimeString(TreatmentsPlugin.getPlugin().getProfileSwitchFromHistory(time)?.date
?: 0)
profileview_reload.visibility = View.GONE
?: 0)
profileview_datelayout.visibility = View.VISIBLE
}
Mode.PUMP_PROFILE -> {
profile = (ConfigBuilderPlugin.getPlugin().activePump as ProfileInterface?)?.profile?.getDefaultProfile()
profileName = (ConfigBuilderPlugin.getPlugin().activePump as ProfileInterface?)?.profileName
Mode.CUSTOM_PROFILE -> {
profile = Profile(JSONObject(customProfileJson), customProfileUnits)
profileName = customProfileName
date = ""
profileview_reload.visibility = View.VISIBLE
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)
super.onResume()
}
override fun onSaveInstanceState(bundle: Bundle) {
super.onSaveInstanceState(bundle)
bundle.putLong("time", time)
bundle.putInt("mode", mode.ordinal)
bundle.putString("customProfile", customProfileJson)
bundle.putString("customProfileName", customProfileName)
bundle.putString("customProfileUnits", customProfileUnits)
}
}

View file

@ -0,0 +1,115 @@
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) {
ConfigBuilderPlugin.getPlugin().commandQueue.tempBasalPercent(percent, durationInMinutes, true, profile, callback)
} else {
ConfigBuilderPlugin.getPlugin().commandQueue.tempBasalAbsolute(absolute, durationInMinutes, true, profile, callback)
}
})
}
return true
}
}

View file

@ -0,0 +1,152 @@
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
if (target != 0.0 && duration != 0.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_hours, 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 {
if (target == 0.0 || duration == 0.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.0) SP.putBoolean(R.string.key_objectiveusetemptarget, true)
})
}
return true
}
}

View file

@ -0,0 +1,132 @@
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 {
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.text.Editable
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.OnItemSelectedListener
import android.widget.ArrayAdapter
@ -26,7 +29,7 @@ import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin
import info.nightscout.androidaps.utils.*
import io.reactivex.android.schedulers.AndroidSchedulers
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 java.text.DecimalFormat
import java.util.*
@ -36,16 +39,13 @@ class WizardDialog : DialogFragment() {
private val log = LoggerFactory.getLogger(WizardDialog::class.java)
private var wizard: BolusWizard? = null
private var parentContext: Context? = null
//one shot guards
private var okClicked: Boolean = false
private val 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) {
calculateInsulin()
}
@ -53,21 +53,11 @@ class WizardDialog : DialogFragment() {
private var disposable: CompositeDisposable = CompositeDisposable()
override fun onAttach(context: Context) {
super.onAttach(context)
this.parentContext = context
}
override fun onStart() {
super.onStart()
dialog?.window?.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
}
override fun onDetach() {
super.onDetach()
this.parentContext = null
}
override fun onSaveInstanceState(savedInstanceState: Bundle) {
super.onSaveInstanceState(savedInstanceState)
savedInstanceState.putDouble("treatments_wizard_bg_input", treatments_wizard_bg_input.value)
@ -83,28 +73,28 @@ class WizardDialog : DialogFragment() {
isCancelable = true
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?) {
loadCheckedStates()
processCobCheckBox()
treatments_wizard_sbcheckbox.visibility = if (SP.getBoolean(R.string.key_usesuperbolus, false)) View.VISIBLE else View.GONE
treatments_wizard_notes_layout.visibility = if (SP.getBoolean(R.string.key_show_notes_entry_dialogs, false)) View.VISIBLE else View.GONE
treatments_wizard_sbcheckbox.visibility = SP.getBoolean(R.string.key_usesuperbolus, false).toVisibility()
treatments_wizard_notes_layout.visibility = SP.getBoolean(R.string.key_show_notes_entry_dialogs, false).toVisibility()
val maxCarbs = MainApp.getConstraintChecker().maxCarbsAllowed.value()
val maxCorrection = MainApp.getConstraintChecker().maxBolusAllowed.value()
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")
?: 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
?: 0.1
?: 0.1
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")
?: 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()
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 {
okClicked = true
calculateInsulin()
parentContext?.let { context ->
context?.let { context ->
wizard?.confirmAndExecute(context)
}
}
@ -124,23 +114,23 @@ class WizardDialog : DialogFragment() {
// cancel button
cancel.setOnClickListener { dismiss() }
// checkboxes
treatments_wizard_bgcheckbox.setOnCheckedChangeListener { buttonView, _ -> onCheckedChanged(buttonView) }
treatments_wizard_ttcheckbox.setOnCheckedChangeListener { buttonView, _ -> onCheckedChanged(buttonView) }
treatments_wizard_cobcheckbox.setOnCheckedChangeListener { buttonView, _ -> onCheckedChanged(buttonView) }
treatments_wizard_basaliobcheckbox.setOnCheckedChangeListener { buttonView, _ -> onCheckedChanged(buttonView) }
treatments_wizard_bolusiobcheckbox.setOnCheckedChangeListener { buttonView, _ -> onCheckedChanged(buttonView) }
treatments_wizard_bgtrendcheckbox.setOnCheckedChangeListener { buttonView, _ -> onCheckedChanged(buttonView) }
treatments_wizard_sbcheckbox.setOnCheckedChangeListener { buttonView, _ -> onCheckedChanged(buttonView) }
treatments_wizard_bgcheckbox.setOnCheckedChangeListener(::onCheckedChanged)
treatments_wizard_ttcheckbox.setOnCheckedChangeListener(::onCheckedChanged)
treatments_wizard_cobcheckbox.setOnCheckedChangeListener(::onCheckedChanged)
treatments_wizard_basaliobcheckbox.setOnCheckedChangeListener(::onCheckedChanged)
treatments_wizard_bolusiobcheckbox.setOnCheckedChangeListener(::onCheckedChanged)
treatments_wizard_bgtrendcheckbox.setOnCheckedChangeListener(::onCheckedChanged)
treatments_wizard_sbcheckbox.setOnCheckedChangeListener(::onCheckedChanged)
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_resulttable.visibility = if (showCalc) View.VISIBLE else View.GONE
treatments_wizard_delimiter.visibility = showCalc.toVisibility()
treatments_wizard_resulttable.visibility = showCalc.toVisibility()
treatments_wizard_calculationcheckbox.isChecked = showCalc
treatments_wizard_calculationcheckbox.setOnCheckedChangeListener { _, isChecked ->
run {
SP.putBoolean(MainApp.gs(R.string.key_wizard_calculation_visible), isChecked)
treatments_wizard_delimiter.visibility = if (isChecked) View.VISIBLE else View.GONE
treatments_wizard_resulttable.visibility = if (isChecked) View.VISIBLE else View.GONE
treatments_wizard_delimiter.visibility = isChecked.toVisibility()
treatments_wizard_resulttable.visibility = isChecked.toVisibility()
}
}
// profile spinner
@ -157,13 +147,13 @@ class WizardDialog : DialogFragment() {
}
// bus
disposable.add(RxBus
.toObservable(EventAutosensCalculationFinished::class.java)
.observeOn(AndroidSchedulers.mainThread())
.subscribe({
activity?.runOnUiThread { calculateInsulin() }
}, {
FabricPrivacy.logException(it)
})
.toObservable(EventAutosensCalculationFinished::class.java)
.observeOn(AndroidSchedulers.mainThread())
.subscribe({
activity?.runOnUiThread { calculateInsulin() }
}, {
FabricPrivacy.logException(it)
})
)
}
@ -173,7 +163,7 @@ class WizardDialog : DialogFragment() {
disposable.clear()
}
private fun onCheckedChanged(buttonView: CompoundButton) {
private fun onCheckedChanged(buttonView: CompoundButton, @Suppress("UNUSED_PARAMETER") state: Boolean) {
saveCheckedStates()
treatments_wizard_ttcheckbox.isEnabled = treatments_wizard_bgcheckbox.isChecked && TreatmentsPlugin.getPlugin().tempTargetFromHistory != null
if (buttonView.id == treatments_wizard_cobcheckbox.id)
@ -221,7 +211,6 @@ class WizardDialog : DialogFragment() {
treatments_wizard_profile.adapter = adapter
} ?: return
val units = ProfileFunctions.getSystemUnits()
treatments_wizard_bgunits.text = units
if (units == Constants.MGDL)
@ -250,7 +239,7 @@ class WizardDialog : DialogFragment() {
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() {
@ -291,15 +280,15 @@ class WizardDialog : DialogFragment() {
val carbTime = SafeParse.stringToInt(treatments_wizard_carb_time_input.text)
wizard = BolusWizard(specificProfile, profileName, tempTarget, carbsAfterConstraint, cob, bg, correction,
SP.getInt(R.string.key_boluswizard_percentage, 100).toDouble(),
treatments_wizard_bgcheckbox.isChecked,
treatments_wizard_cobcheckbox.isChecked,
treatments_wizard_bolusiobcheckbox.isChecked,
treatments_wizard_basaliobcheckbox.isChecked,
treatments_wizard_sbcheckbox.isChecked,
treatments_wizard_ttcheckbox.isChecked,
treatments_wizard_bgtrendcheckbox.isChecked,
treatment_wizard_notes.text.toString(), carbTime)
SP.getInt(R.string.key_boluswizard_percentage, 100).toDouble(),
treatments_wizard_bgcheckbox.isChecked,
treatments_wizard_cobcheckbox.isChecked,
treatments_wizard_bolusiobcheckbox.isChecked,
treatments_wizard_basaliobcheckbox.isChecked,
treatments_wizard_sbcheckbox.isChecked,
treatments_wizard_ttcheckbox.isChecked,
treatments_wizard_bgtrendcheckbox.isChecked,
treatment_wizard_notes.text.toString(), carbTime)
wizard?.let { wizard ->
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)
@ -320,8 +309,8 @@ class WizardDialog : DialogFragment() {
// Trend
if (treatments_wizard_bgtrendcheckbox.isChecked && wizard.glucoseStatus != null) {
treatments_wizard_bgtrend.text = ((if (wizard.trend > 0) "+" else "")
+ Profile.toUnitsString(wizard.trend * 3, wizard.trend * 3 / Constants.MMOLL_TO_MGDL, ProfileFunctions.getSystemUnits())
+ " " + ProfileFunctions.getSystemUnits())
+ Profile.toUnitsString(wizard.trend * 3, wizard.trend * 3 / Constants.MMOLL_TO_MGDL, ProfileFunctions.getSystemUnits())
+ " " + ProfileFunctions.getSystemUnits())
} else {
treatments_wizard_bgtrend.text = ""
}

View file

@ -4,7 +4,6 @@ import android.os.SystemClock;
import android.preference.Preference;
import android.preference.PreferenceFragment;
import androidx.appcompat.app.AlertDialog;
import androidx.fragment.app.FragmentActivity;
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.EventConfigBuilderUpdateGui;
import info.nightscout.androidaps.queue.CommandQueue;
import info.nightscout.androidaps.utils.OKDialog;
import info.nightscout.androidaps.utils.SP;
/**
@ -58,20 +58,16 @@ public abstract class PluginBase {
if (allowHardwarePump || activity == null) {
performPluginSwitch(newState, type);
} else {
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
builder.setMessage(R.string.allow_hardware_pump_text)
.setPositiveButton(R.string.yes, (dialog, id) -> {
performPluginSwitch(newState, type);
SP.putBoolean("allow_hardware_pump", true);
if (L.isEnabled(L.PUMP))
log.debug("First time HW pump allowed!");
})
.setNegativeButton(R.string.cancel, (dialog, id) -> {
RxBus.INSTANCE.send(new EventConfigBuilderUpdateGui());
if (L.isEnabled(L.PUMP))
log.debug("User does not allow switching to HW pump!");
});
builder.create().show();
OKDialog.showConfirmation(activity, MainApp.gs(R.string.allow_hardware_pump_text), () -> {
performPluginSwitch(newState, type);
SP.putBoolean("allow_hardware_pump", true);
if (L.isEnabled(L.PUMP))
log.debug("First time HW pump allowed!");
}, () -> {
RxBus.INSTANCE.send(new EventConfigBuilderUpdateGui());
if (L.isEnabled(L.PUMP))
log.debug("User does not allow switching to HW pump!");
});
}
} else {
performPluginSwitch(newState, type);

View file

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

View file

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

View file

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

View file

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

View file

@ -50,7 +50,7 @@ import info.nightscout.androidaps.plugins.bus.RxBus;
import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.configBuilder.ProfileFunctions;
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.iob.iobCobCalculator.events.EventAutosensCalculationFinished;
import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpPlugin;
@ -60,7 +60,6 @@ import info.nightscout.androidaps.queue.commands.Command;
import info.nightscout.androidaps.utils.FabricPrivacy;
import info.nightscout.androidaps.utils.SP;
import info.nightscout.androidaps.utils.T;
import info.nightscout.androidaps.utils.ToastUtils;
import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.schedulers.Schedulers;

View file

@ -2,7 +2,11 @@ package info.nightscout.androidaps.plugins.configBuilder
import android.content.Intent
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.activities.PreferencesActivity
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.plugins.bus.RxBus
import info.nightscout.androidaps.utils.PasswordProtection
import info.nightscout.androidaps.utils.toVisibility
class PluginViewHolder internal constructor(private val fragment: ConfigBuilderFragment,
private val pluginType: PluginType,
@ -56,8 +61,8 @@ class PluginViewHolder internal constructor(private val fragment: ConfigBuilderF
}
fun update() {
enabledExclusive.visibility = if (areMultipleSelectionsAllowed(pluginType)) View.GONE else View.VISIBLE
enabledInclusive.visibility = if (areMultipleSelectionsAllowed(pluginType)) View.VISIBLE else View.GONE
enabledExclusive.visibility = areMultipleSelectionsAllowed(pluginType).not().toVisibility()
enabledInclusive.visibility = areMultipleSelectionsAllowed(pluginType).toVisibility()
enabledExclusive.isChecked = plugin.isEnabled(pluginType)
enabledInclusive.isChecked = plugin.isEnabled(pluginType)
enabledInclusive.isEnabled = !plugin.pluginDescription.alwaysEnabled
@ -70,7 +75,7 @@ class PluginViewHolder internal constructor(private val fragment: ConfigBuilderF
pluginDescription.text = plugin.description
}
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.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.logging.L;
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.queue.Callback;
import info.nightscout.androidaps.utils.DateUtil;
@ -170,8 +170,8 @@ public class ProfileFunctions {
return profileSwitch;
}
public static void doProfileSwitch(final ProfileStore profileStore, final String profileName, final int duration, final int percentage, final int timeshift) {
ProfileSwitch profileSwitch = prepareProfileSwitch(profileStore, profileName, duration, percentage, timeshift, System.currentTimeMillis());
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, date);
TreatmentsPlugin.getPlugin().addToHistoryProfileSwitch(profileSwitch);
if (percentage == 90 && duration == 10)
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.objectives.Objective.ExamTask
import info.nightscout.androidaps.receivers.NetworkChangeReceiver
import info.nightscout.androidaps.setupwizard.events.EventSWUpdate
import info.nightscout.androidaps.utils.*
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable
@ -71,13 +72,13 @@ class ObjectivesFragment : Fragment() {
override fun onResume() {
super.onResume()
disposable.add(RxBus
.toObservable(EventObjectivesUpdateGui::class.java)
.observeOn(AndroidSchedulers.mainThread())
.subscribe({
objectives_recyclerview.adapter?.notifyDataSetChanged()
}, {
FabricPrivacy.logException(it)
})
.toObservable(EventObjectivesUpdateGui::class.java)
.observeOn(AndroidSchedulers.mainThread())
.subscribe({
objectives_recyclerview.adapter?.notifyDataSetChanged()
}, {
FabricPrivacy.logException(it)
})
)
}
@ -217,6 +218,7 @@ class ObjectivesFragment : Fragment() {
scrollToCurrentObjective()
startUpdateTimer()
RxBus.send(EventObjectivesUpdateGui())
RxBus.send(EventSWUpdate(false))
} else {
// move out of UI thread
Thread {
@ -234,6 +236,7 @@ class ObjectivesFragment : Fragment() {
RxBus.send(EventNtpStatus(MainApp.gs(R.string.success), 100))
SystemClock.sleep(1000)
RxBus.send(EventObjectivesUpdateGui())
RxBus.send(EventSWUpdate(false))
SystemClock.sleep(100)
scrollToCurrentObjective()
} else {
@ -254,6 +257,7 @@ class ObjectivesFragment : Fragment() {
scrollToCurrentObjective()
startUpdateTimer()
RxBus.send(EventObjectivesUpdateGui())
RxBus.send(EventSWUpdate(false))
} else
// move out of UI thread
Thread {
@ -270,6 +274,7 @@ class ObjectivesFragment : Fragment() {
RxBus.send(EventNtpStatus(MainApp.gs(R.string.success), 100))
SystemClock.sleep(1000)
RxBus.send(EventObjectivesUpdateGui())
RxBus.send(EventSWUpdate(false))
SystemClock.sleep(100)
scrollToCurrentObjective()
} else {
@ -280,16 +285,20 @@ class ObjectivesFragment : Fragment() {
}.start()
}
holder.unStart.setOnClickListener {
OKDialog.showConfirmation(activity, MainApp.gs(R.string.doyouwantresetstart)) {
objective.startedOn = 0
scrollToCurrentObjective()
RxBus.send(EventObjectivesUpdateGui())
activity?.let { activity ->
OKDialog.showConfirmation(activity, MainApp.gs(R.string.objectives), MainApp.gs(R.string.doyouwantresetstart), Runnable {
objective.startedOn = 0
scrollToCurrentObjective()
RxBus.send(EventObjectivesUpdateGui())
RxBus.send(EventSWUpdate(false))
})
}
}
holder.unFinish.setOnClickListener {
objective.accomplishedOn = 0
scrollToCurrentObjective()
RxBus.send(EventObjectivesUpdateGui())
RxBus.send(EventSWUpdate(false))
}
if (objective.hasSpecialInput && !objective.isAccomplished && objective.isStarted && objective.specialActionEnabled()) {
// generate random request code if none exists
@ -313,7 +322,6 @@ class ObjectivesFragment : Fragment() {
}
}
override fun getItemCount(): Int {
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" + "_accomplished", DateUtil.now())
setupObjectives()
OKDialog.show(activity, "", MainApp.gs(R.string.codeaccepted), null)
OKDialog.show(activity, MainApp.gs(R.string.objectives), MainApp.gs(R.string.codeaccepted))
} 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 io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable
import kotlinx.android.synthetic.main.overview_bolusprogress_dialog.*
import kotlinx.android.synthetic.main.dialog_bolusprogress.*
import org.slf4j.LoggerFactory
class NtpProgressDialog : DialogFragment() {
@ -33,16 +33,17 @@ class NtpProgressDialog : DialogFragment() {
state = savedInstanceState?.getString("state", DEFAULT_STATE) ?: DEFAULT_STATE
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?) {
super.onViewCreated(view, savedInstanceState)
overview_bolusprogress_stop.setOnClickListener { dismiss() }
overview_bolusprogress_status.setText(state)
overview_bolusprogress_progressbar.setMax(100)
overview_bolusprogress_progressbar.setProgress(percent)
overview_bolusprogress_status.text = state
overview_bolusprogress_progressbar.max = 100
overview_bolusprogress_progressbar.progress = percent
overview_bolusprogress_stop.text = MainApp.gs(R.string.close)
overview_bolusprogress_title.text = MainApp.gs(R.string.please_wait)
}
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.notifications.Notification;
import info.nightscout.androidaps.plugins.sensitivity.SensitivityOref1Plugin;
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin;
import info.nightscout.androidaps.utils.DecimalFormatter;
import info.nightscout.androidaps.utils.HardLimits;
import info.nightscout.androidaps.utils.Round;
@ -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);
}
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;
}

View file

@ -1,13 +1,19 @@
package info.nightscout.androidaps.plugins.constraints.versionChecker
import info.nightscout.androidaps.BuildConfig
import info.nightscout.androidaps.MainApp
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.general.overview.events.EventNewNotification
import info.nightscout.androidaps.plugins.general.overview.notifications.Notification
import info.nightscout.androidaps.utils.SP
import java.util.concurrent.TimeUnit
import kotlin.math.roundToInt
/**
* Usually we would have a class here.
@ -16,16 +22,23 @@ import java.util.concurrent.TimeUnit
* */
object VersionCheckerPlugin : PluginBase(PluginDescription()
.mainType(PluginType.CONSTRAINTS)
.neverVisible(true)
.alwaysEnabled(true)
.showInList(false)
.pluginName(R.string.versionChecker)), ConstraintsInterface {
.mainType(PluginType.CONSTRAINTS)
.neverVisible(true)
.alwaysEnabled(true)
.showInList(false)
.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> {
checkWarning()
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)
else
value
@ -33,41 +46,49 @@ object VersionCheckerPlugin : PluginBase(PluginDescription()
private fun checkWarning() {
val now = System.currentTimeMillis()
if (!SP.contains(R.string.key_last_versionchecker_plugin_warning)) {
SP.putLong(R.string.key_last_versionchecker_plugin_warning, now)
return
}
if (isOldVersion(GRACE_PERIOD_WARNING) && shouldWarnAgain(now)) {
if (isOldVersion(gracePeriod.warning.daysToMillis()) && shouldWarnAgain(now)) {
// store last notification time
SP.putLong(R.string.key_last_versionchecker_plugin_warning, now)
//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)
RxBus.send(EventNewNotification(notification))
}
}
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> =
if (isOldVersion(GRACE_PERIOD_OLD))
maxIob.set(0.toDouble(), MainApp.gs(R.string.old_version), this)
else
maxIob
if (isOldVersion(gracePeriod.old.daysToMillis()))
maxIob.set(0.toDouble(), MainApp.gs(R.string.old_version), this)
else
maxIob
private fun isOldVersion(gracePeriod: Long): Boolean {
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)
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)
private val WARN_EVERY = TimeUnit.DAYS.toMillis(1)
}
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.ViewGroup
import android.widget.LinearLayout
import androidx.core.content.ContextCompat
import androidx.fragment.app.Fragment
import info.nightscout.androidaps.Config
import info.nightscout.androidaps.MainApp
@ -18,17 +19,21 @@ import info.nightscout.androidaps.plugins.bus.RxBus
import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin
import info.nightscout.androidaps.plugins.configBuilder.ProfileFunctions
import info.nightscout.androidaps.plugins.general.actions.defs.CustomAction
import info.nightscout.androidaps.plugins.general.actions.dialogs.FillDialog
import info.nightscout.androidaps.plugins.general.actions.dialogs.NewExtendedBolusDialog
import info.nightscout.androidaps.plugins.general.actions.dialogs.NewTempBasalDialog
import info.nightscout.androidaps.dialogs.CareDialog
import info.nightscout.androidaps.dialogs.ExtendedBolusDialog
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.Dialogs.NewNSTreatmentDialog
import info.nightscout.androidaps.activities.ErrorHelperActivity
import info.nightscout.androidaps.dialogs.ProfileSwitchDialog
import info.nightscout.androidaps.dialogs.TempTargetDialog
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin
import info.nightscout.androidaps.queue.Callback
import info.nightscout.androidaps.utils.*
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable
import kotlinx.android.synthetic.main.actions_fragment.*
import kotlinx.android.synthetic.main.careportal_stats_fragment.*
import java.util.*
class ActionsFragment : Fragment() {
@ -47,39 +52,50 @@ class ActionsFragment : Fragment() {
super.onViewCreated(view, savedInstanceState)
actions_profileswitch.setOnClickListener {
val newDialog = NewNSTreatmentDialog()
val profileSwitch = CareportalFragment.PROFILESWITCH
profileSwitch.executeProfileSwitch = true
newDialog.setOptions(profileSwitch, R.string.careportal_profileswitch)
fragmentManager?.let { newDialog.show(it, "NewNSTreatmentDialog") }
fragmentManager?.let { ProfileSwitchDialog().show(it, "Actions") }
}
actions_temptarget.setOnClickListener {
val newTTDialog = NewNSTreatmentDialog()
val temptarget = CareportalFragment.TEMPTARGET
temptarget.executeTempTarget = true
newTTDialog.setOptions(temptarget, R.string.careportal_temporarytarget)
fragmentManager?.let { newTTDialog.show(it, "NewNSTreatmentDialog") }
fragmentManager?.let { TempTargetDialog().show(it, "Actions") }
}
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 {
if (TreatmentsPlugin.getPlugin().isInHistoryExtendedBoluslInProgress) {
ConfigBuilderPlugin.getPlugin().commandQueue.cancelExtended(object : Callback() {
override fun run() {
if (!result.success)
ToastUtils.showToastInUiThread(MainApp.instance().applicationContext, MainApp.gs(R.string.extendedbolusdeliveryerror))
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.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 {
if (TreatmentsPlugin.getPlugin().isTempBasalInProgress) {
ConfigBuilderPlugin.getPlugin().commandQueue.cancelTempBasal(true, object : Callback() {
override fun run() {
if (!result.success)
ToastUtils.showToastInUiThread(MainApp.instance().applicationContext, MainApp.gs(R.string.tempbasaldeliveryerror))
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)
}
}
})
}
@ -87,6 +103,21 @@ class ActionsFragment : Fragment() {
actions_fill.setOnClickListener { fragmentManager?.let { FillDialog().show(it, "FillDialog") } }
actions_historybrowser.setOnClickListener { startActivity(Intent(context, HistoryBrowseActivity::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)
}
@ -97,43 +128,27 @@ class ActionsFragment : Fragment() {
disposable += RxBus
.toObservable(EventInitializationChanged::class.java)
.observeOn(AndroidSchedulers.mainThread())
.subscribe({
updateGui()
}, {
FabricPrivacy.logException(it)
})
.subscribe({ updateGui() }, { FabricPrivacy.logException(it) })
disposable += RxBus
.toObservable(EventRefreshOverview::class.java)
.observeOn(AndroidSchedulers.mainThread())
.subscribe({
updateGui()
}, {
FabricPrivacy.logException(it)
})
.subscribe({ updateGui() }, { FabricPrivacy.logException(it) })
disposable += RxBus
.toObservable(EventExtendedBolusChange::class.java)
.observeOn(AndroidSchedulers.mainThread())
.subscribe({
updateGui()
}, {
FabricPrivacy.logException(it)
})
.subscribe({ updateGui() }, { FabricPrivacy.logException(it) })
disposable += RxBus
.toObservable(EventTempBasalChange::class.java)
.observeOn(AndroidSchedulers.mainThread())
.subscribe({
updateGui()
}, {
FabricPrivacy.logException(it)
})
.subscribe({ updateGui() }, { FabricPrivacy.logException(it) })
disposable += RxBus
.toObservable(EventCustomActionsChanged::class.java)
.observeOn(AndroidSchedulers.mainThread())
.subscribe({
updateGui()
}, {
FabricPrivacy.logException(it)
})
.subscribe({ updateGui() }, { FabricPrivacy.logException(it) })
disposable += RxBus
.toObservable(EventCareportalEventChange::class.java)
.observeOn(AndroidSchedulers.mainThread())
.subscribe({ updateGui() }, { FabricPrivacy.logException(it) })
updateGui()
}
@ -164,7 +179,7 @@ class ActionsFragment : Fragment() {
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_cancel?.visibility = View.GONE
} else {
@ -172,7 +187,7 @@ class ActionsFragment : Fragment() {
if (activeExtendedBolus != null) {
actions_extendedbolus?.visibility = View.GONE
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 {
actions_extendedbolus?.visibility = View.VISIBLE
actions_extendedbolus_cancel?.visibility = View.GONE
@ -198,8 +213,11 @@ class ActionsFragment : Fragment() {
if (!pump.pumpDescription.isRefillingCapable || !pump.isInitialized || pump.isSuspended) View.GONE
else View.VISIBLE
actions_temptarget?.visibility = if (!Config.APS) View.GONE else View.VISIBLE
actions_tddstats?.visibility = if (!pump.pumpDescription.supportsTDDs) View.GONE else View.VISIBLE
actions_temptarget?.visibility = Config.APS.toVisibility()
actions_tddstats?.visibility = pump.pumpDescription.supportsTDDs.toVisibility()
activity?.let { activity ->
CareportalFragment.updateAge(activity, careportal_sensorage, careportal_insulinage, careportal_canulaage, careportal_pbage)
}
checkPumpCustomActions()
}
@ -224,8 +242,7 @@ class ActionsFragment : Fragment() {
val action = this.pumpCustomActions[b.text.toString()]
ConfigBuilderPlugin.getPlugin().activePump!!.executeCustomAction(action!!.customActionType)
}
val top = resources.getDrawable(customAction.iconResourceId)
val top = activity?.let { ContextCompat.getDrawable(it, customAction.iconResourceId) }
btn.setCompoundDrawablesWithIntrinsicBounds(null, top, null, null)
action_buttons_layout?.addView(btn)

View file

@ -1,5 +1,6 @@
package info.nightscout.androidaps.plugins.general.actions
import info.nightscout.androidaps.Config
import info.nightscout.androidaps.R
import info.nightscout.androidaps.interfaces.PluginBase
import info.nightscout.androidaps.interfaces.PluginDescription
@ -8,6 +9,8 @@ import info.nightscout.androidaps.interfaces.PluginType
object ActionsPlugin : PluginBase(PluginDescription()
.mainType(PluginType.GENERAL)
.fragmentClass(ActionsFragment::class.qualifiedName)
.enableByDefault(Config.APS || Config.PUMPCONTROL)
.visibleByDefault(Config.APS || Config.PUMPCONTROL)
.pluginName(R.string.actions)
.shortName(R.string.actions_shortname)
.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,6 +1,7 @@
package info.nightscout.androidaps.plugins.general.automation
import android.os.Bundle
import android.text.method.ScrollingMovementMethod
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
@ -16,12 +17,12 @@ import info.nightscout.androidaps.plugins.general.automation.dragHelpers.SimpleI
import info.nightscout.androidaps.plugins.general.automation.events.EventAutomationDataChanged
import info.nightscout.androidaps.plugins.general.automation.events.EventAutomationUpdateGui
import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.HtmlHelper
import info.nightscout.androidaps.utils.plusAssign
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable
import kotlinx.android.synthetic.main.automation_fragment.*
class AutomationFragment : Fragment(), OnStartDragListener {
private var disposable: CompositeDisposable = CompositeDisposable()
@ -40,6 +41,8 @@ class AutomationFragment : Fragment(), OnStartDragListener {
automation_eventListView.layoutManager = LinearLayoutManager(context)
automation_eventListView.adapter = eventListAdapter
automation_logView.setMovementMethod(ScrollingMovementMethod())
automation_fabAddEvent.setOnClickListener {
val dialog = EditEventDialog()
val args = Bundle()
@ -88,8 +91,8 @@ class AutomationFragment : Fragment(), OnStartDragListener {
eventListAdapter?.notifyDataSetChanged()
val sb = StringBuilder()
for (l in AutomationPlugin.executionLog.reversed())
sb.append(l).append("\n")
automation_logView?.text = sb.toString()
sb.append(l).append("<br>")
automation_logView?.text = HtmlHelper.fromHtml(sb.toString())
}
override fun onStartDrag(viewHolder: RecyclerView.ViewHolder) {

View file

@ -178,10 +178,10 @@ object AutomationPlugin : PluginBase(PluginDescription()
val sb = StringBuilder()
sb.append(DateUtil.timeString(DateUtil.now()))
sb.append(" ")
sb.append(if (result.success) "" else "X")
sb.append(" ")
sb.append(if (result.success) "" else "")
sb.append(" <b>")
sb.append(event.title)
sb.append(": ")
sb.append(":</b> ")
sb.append(action.shortDescription())
sb.append(": ")
sb.append(result.comment)

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.LayoutBuilder;
import info.nightscout.androidaps.queue.Callback;
import info.nightscout.androidaps.utils.DateUtil;
import info.nightscout.androidaps.utils.JsonHelper;
public class ActionProfileSwitch extends Action {
private static Logger log = LoggerFactory.getLogger(L.AUTOMATION);
public InputProfileName inputProfileName = new InputProfileName(ProfileFunctions.getInstance().getProfileName());
InputProfileName inputProfileName;
String profileName = "";
public ActionProfileSwitch() {
// Prevent action if active profile is already active
// but we don't have a trigger IS_NOT_EQUAL
// 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
@ -50,23 +62,43 @@ public class ActionProfileSwitch extends Action {
String activeProfileName = ProfileFunctions.getInstance().getProfileName();
//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)) {
// 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;
}
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();
if (profileStore == null) return;
if(profileStore.getSpecificProfile(profileName) == null) {
if (L.isEnabled(L.AUTOMATION))
log.error("Selected profile does not exist! - "+ profileName);
if (callback != null)
callback.result(new PumpEnactResult().success(false).comment(R.string.notexists)).run();
return;
}
ProfileFunctions.doProfileSwitch(profileStore, profileName, 0, 100, 0);
ProfileFunctions.doProfileSwitch(profileStore, profileName, 0, 100, 0, DateUtil.now());
if (callback != null)
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;
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))
.build(root);
}

View file

@ -32,7 +32,7 @@ class ActionListAdapter(private val fragmentManager: FragmentManager, private va
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 {
if (action.hasDialog()) {
val args = Bundle()
@ -48,6 +48,7 @@ class ActionListAdapter(private val fragmentManager: FragmentManager, private va
recyclerView.notifyDataSetChanged()
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 file

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

View file

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

View file

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

View file

@ -4,9 +4,9 @@ import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.DialogFragment
import androidx.recyclerview.widget.LinearLayoutManager
import info.nightscout.androidaps.R
import info.nightscout.androidaps.dialogs.DialogFragmentWithDate
import info.nightscout.androidaps.plugins.bus.RxBus
import info.nightscout.androidaps.plugins.general.automation.AutomationEvent
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.disposables.CompositeDisposable
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 event: AutomationEvent = AutomationEvent()
@ -35,7 +34,7 @@ class EditEventDialog : DialogFragment() {
bundle.getString("event")?.let { event = AutomationEvent().fromJSON(it) }
}
dialog?.setCanceledOnTouchOutside(false)
onCreateViewGeneral()
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") } }
// OK button
ok.setOnClickListener {
// check for title
val title = automation_inputEventTitle.text.toString()
if (title.isEmpty()) {
ToastUtils.showToastInUiThread(context, R.string.automation_missing_task_name)
return@setOnClickListener
}
event.title = title
// check for at least one trigger
val con = event.trigger as TriggerConnector
if (con.size() == 0) {
ToastUtils.showToastInUiThread(context, R.string.automation_missing_trigger)
return@setOnClickListener
}
// check for at least one action
if (event.actions.isEmpty()) {
ToastUtils.showToastInUiThread(context, R.string.automation_missing_action)
return@setOnClickListener
}
// store
if (position == -1)
AutomationPlugin.automationEvents.add(event)
else
AutomationPlugin.automationEvents[position] = event
dismiss()
RxBus.send(EventAutomationDataChanged())
}
// Cancel button
cancel.setOnClickListener { dismiss() }
showPreconditions()
disposable.add(RxBus
@ -137,9 +103,33 @@ class EditEventDialog : DialogFragment() {
)
}
override fun onStart() {
super.onStart()
dialog?.window?.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
override fun submit() : Boolean{
// check for title
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() {
@ -147,10 +137,10 @@ class EditEventDialog : DialogFragment() {
disposable.clear()
}
override fun onSaveInstanceState(bundle: Bundle) {
super.onSaveInstanceState(bundle)
bundle.putString("event", event.toJSON())
bundle.putInt("position", position)
override fun onSaveInstanceState(savedInstanceState: Bundle) {
super.onSaveInstanceState(savedInstanceState)
savedInstanceState.putString("event", event.toJSON())
savedInstanceState.putInt("position", position)
}
private fun showPreconditions() {
@ -164,5 +154,4 @@ class EditEventDialog : DialogFragment() {
automation_forcedTriggerDescriptionLabel.visibility = View.GONE
}
}
}

View file

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

View file

@ -75,7 +75,7 @@ public class TriggerListAdapter {
private Spinner createSpinner() {
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);
spinner.setAdapter(spinnerArrayAdapter);
return spinner;

View file

@ -87,7 +87,7 @@ public class Comparator extends Element {
@Override
public void addToLayout(LinearLayout root) {
Spinner spinner = new Spinner(root.getContext());
ArrayAdapter<String> spinnerArrayAdapter = new ArrayAdapter<>(root.getContext(), android.R.layout.simple_spinner_item, Compare.labels());
ArrayAdapter<String> spinnerArrayAdapter = new ArrayAdapter<>(root.getContext(), R.layout.spinner_centered, Compare.labels());
spinnerArrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner.setAdapter(spinnerArrayAdapter);
LinearLayout.LayoutParams spinnerParams = new LinearLayout.LayoutParams(

View file

@ -54,7 +54,7 @@ public class ComparatorExists extends Element {
@Override
public void addToLayout(LinearLayout root) {
Spinner spinner = new Spinner(root.getContext());
ArrayAdapter<String> spinnerArrayAdapter = new ArrayAdapter<>(root.getContext(), android.R.layout.simple_spinner_item, Compare.labels());
ArrayAdapter<String> spinnerArrayAdapter = new ArrayAdapter<>(root.getContext(), R.layout.spinner_centered, Compare.labels());
spinnerArrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner.setAdapter(spinnerArrayAdapter);
LinearLayout.LayoutParams spinnerParams = new LinearLayout.LayoutParams(

View file

@ -87,7 +87,7 @@ public class InputDelta extends Element {
@Override
public void addToLayout(LinearLayout root) {
Spinner spinner = new Spinner(root.getContext());
ArrayAdapter<String> spinnerArrayAdapter = new ArrayAdapter<>(root.getContext(), android.R.layout.simple_spinner_item, DeltaType.labels());
ArrayAdapter<String> spinnerArrayAdapter = new ArrayAdapter<>(root.getContext(), R.layout.spinner_centered, DeltaType.labels());
spinnerArrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner.setAdapter(spinnerArrayAdapter);
LinearLayout.LayoutParams spinnerParams = new LinearLayout.LayoutParams(

View file

@ -0,0 +1,107 @@
package info.nightscout.androidaps.plugins.general.automation.elements;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.LinearLayout;
import android.widget.Spinner;
import androidx.annotation.StringRes;
import java.util.ArrayList;
import java.util.List;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
public class InputLocationMode extends Element {
public enum Mode {
INSIDE,
OUTSIDE,
GOING_IN,
GOING_OUT;
public @StringRes
int getStringRes() {
switch (this) {
case INSIDE:
return R.string.location_inside;
case OUTSIDE:
return R.string.location_outside;
case GOING_IN:
return R.string.location_going_in;
case GOING_OUT:
return R.string.location_going_out;
default:
return R.string.unknown;
}
}
public static List<String> labels() {
List<String> list = new ArrayList<>();
for (Mode c : Mode.values()) {
list.add(MainApp.gs(c.getStringRes()));
}
return list;
}
public Mode fromString(String wanted){
for (Mode c : Mode.values()) {
if(c.toString() == wanted)
return c;
}
return null;
}
}
private Mode mode;
public InputLocationMode() {
super();
mode = Mode.INSIDE;
}
public InputLocationMode(InputLocationMode another) {
super();
this.mode = another.mode;
}
@Override
public void addToLayout(LinearLayout root) {
ArrayAdapter<String> adapter = new ArrayAdapter<>(root.getContext(),
R.layout.spinner_centered, Mode.labels());
Spinner spinner = new Spinner(root.getContext());
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner.setAdapter(adapter);
LinearLayout.LayoutParams spinnerParams = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT
);
spinnerParams.setMargins(0, MainApp.dpToPx(4), 0, MainApp.dpToPx(4));
spinner.setLayoutParams(spinnerParams);
spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
setValue(Mode.values()[position]);
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
}
});
spinner.setSelection(this.getValue().ordinal());
root.addView(spinner);
}
public Mode getValue() {
return mode;
}
public InputLocationMode setValue(Mode mode) {
this.mode = mode;
return this;
}
}

View file

@ -19,6 +19,7 @@ import info.nightscout.androidaps.R;
import info.nightscout.androidaps.logging.L;
import info.nightscout.androidaps.plugins.general.automation.elements.InputButton;
import info.nightscout.androidaps.plugins.general.automation.elements.InputDouble;
import info.nightscout.androidaps.plugins.general.automation.elements.InputLocationMode;
import info.nightscout.androidaps.plugins.general.automation.elements.InputString;
import info.nightscout.androidaps.plugins.general.automation.elements.LabelWithElement;
import info.nightscout.androidaps.plugins.general.automation.elements.LayoutBuilder;
@ -28,12 +29,17 @@ import info.nightscout.androidaps.utils.DateUtil;
import info.nightscout.androidaps.utils.JsonHelper;
import info.nightscout.androidaps.utils.T;
import static info.nightscout.androidaps.plugins.general.automation.elements.InputLocationMode.Mode.*;
public class TriggerLocation extends Trigger {
private static Logger log = LoggerFactory.getLogger(L.AUTOMATION);
InputDouble latitude = new InputDouble(0d, -90d, +90d, 0.000001d, new DecimalFormat("0.000000"));
InputDouble longitude = new InputDouble(0d, -180d, +180d, 0.000001d, new DecimalFormat("0.000000"));
InputDouble distance = new InputDouble(200d, 0, 100000, 10d, new DecimalFormat("0"));
InputLocationMode modeSelected = new InputLocationMode();
InputLocationMode.Mode lastMode = INSIDE;
InputString name = new InputString();
private Runnable buttonAction = () -> {
@ -54,13 +60,16 @@ public class TriggerLocation extends Trigger {
latitude = new InputDouble(triggerLocation.latitude);
longitude = new InputDouble(triggerLocation.longitude);
distance = new InputDouble(triggerLocation.distance);
modeSelected = new InputLocationMode(triggerLocation.modeSelected);
if (modeSelected.getValue() == GOING_OUT)
lastMode = OUTSIDE;
lastRun = triggerLocation.lastRun;
name = triggerLocation.name;
}
@Override
public synchronized boolean shouldRun() {
Location location = LocationService.getLastLocation();
Location location = this.getCurrentLocation();
if (location == null)
return false;
@ -72,11 +81,20 @@ public class TriggerLocation extends Trigger {
a.setLongitude(longitude.getValue());
double calculatedDistance = location.distanceTo(a);
if (calculatedDistance < distance.getValue()) {
// log.debug("Moded(current/last/wanted): "+(currentMode(calculatedDistance))+"/"+lastMode+"/"+modeSelected.getValue());
// log.debug("Distance: "+calculatedDistance + "("+distance.getValue()+")");
if ((modeSelected.getValue() == INSIDE) && (calculatedDistance <= distance.getValue()) ||
((modeSelected.getValue() == OUTSIDE) && (calculatedDistance > distance.getValue())) ||
((modeSelected.getValue() == GOING_IN) && (calculatedDistance <= distance.getValue()) && (lastMode == OUTSIDE)) ||
((modeSelected.getValue() == GOING_OUT) && (calculatedDistance > distance.getValue()) && (lastMode == INSIDE))
) {
if (L.isEnabled(L.AUTOMATION))
log.debug("Ready for execution: " + friendlyDescription());
lastMode = currentMode(calculatedDistance);
return true;
}
lastMode = currentMode(calculatedDistance); // current mode will be last mode for the next check
return false;
}
@ -90,6 +108,7 @@ public class TriggerLocation extends Trigger {
data.put("longitude", longitude.getValue());
data.put("distance", distance.getValue());
data.put("name", name.getValue());
data.put("mode", modeSelected.getValue());
data.put("lastRun", lastRun);
o.put("data", data);
} catch (JSONException e) {
@ -106,7 +125,10 @@ public class TriggerLocation extends Trigger {
longitude.setValue(JsonHelper.safeGetDouble(d, "longitude"));
distance.setValue(JsonHelper.safeGetDouble(d, "distance"));
name.setValue(JsonHelper.safeGetString(d, "name"));
lastRun = JsonHelper.safeGetLong(d, "lastRun");
modeSelected.setValue(InputLocationMode.Mode.valueOf(JsonHelper.safeGetString(d, "mode")));
if (modeSelected.getValue() == GOING_OUT)
lastMode = OUTSIDE;
lastRun = DateUtil.now(); // set lastRun to now to give the service 5 mins to get the location properly
} catch (Exception e) {
log.error("Unhandled exception", e);
}
@ -120,7 +142,7 @@ public class TriggerLocation extends Trigger {
@Override
public String friendlyDescription() {
return MainApp.gs(R.string.locationis, name.getValue());
return MainApp.gs(R.string.locationis, MainApp.gs(modeSelected.getValue().getStringRes()), " " + name.getValue());
}
@Override
@ -154,6 +176,11 @@ public class TriggerLocation extends Trigger {
return this;
}
TriggerLocation setMode(InputLocationMode.Mode value) {
modeSelected.setValue(value);
return this;
}
@Override
public void generateDialog(LinearLayout root, FragmentManager fragmentManager) {
new LayoutBuilder()
@ -162,7 +189,21 @@ public class TriggerLocation extends Trigger {
.add(new LabelWithElement(MainApp.gs(R.string.latitude_short), "", latitude))
.add(new LabelWithElement(MainApp.gs(R.string.longitude_short), "", longitude))
.add(new LabelWithElement(MainApp.gs(R.string.distance_short), "", distance))
.add(new LabelWithElement(MainApp.gs(R.string.location_mode), "", modeSelected))
.add(new InputButton(MainApp.gs(R.string.currentlocation), buttonAction), LocationService.getLastLocation() != null)
.build(root);
}
// Method to return the actual mode based on the current distance
InputLocationMode.Mode currentMode(double currentDistance){
if ( currentDistance <= this.distance.getValue() )
return INSIDE;
else
return OUTSIDE;
}
static Location getCurrentLocation(){
return LocationService.getLastLocation();
}
}

View file

@ -93,7 +93,7 @@ public class TriggerTempTarget extends Trigger {
@Override
public int friendlyName() {
return R.string.temptarget;
return R.string.careportal_temporarytarget;
}
@Override
@ -124,7 +124,7 @@ public class TriggerTempTarget extends Trigger {
@Override
public void generateDialog(LinearLayout root, FragmentManager fragmentManager) {
new LayoutBuilder()
.add(new StaticLabel(R.string.temptarget))
.add(new StaticLabel(R.string.careportal_temporarytarget))
.add(comparator)
.build(root);
}

View file

@ -149,7 +149,7 @@ public class TriggerTimeRange extends Trigger {
public int getMinSinceMidnight(long time) {
// if passed argument is smaller than 1440 ( 24 h * 60 min ) that value is already converted
if (0 < time && time < 1441)
if (0 <= time && time < 1441)
return (int) time;
Calendar calendar = DateUtil.gregorianCalendar();
calendar.setTimeInMillis(time);

View file

@ -63,7 +63,6 @@ public class CareportalFragment extends Fragment implements View.OnClickListener
public static final OptionsToShow TEMPBASALSTART = new OptionsToShow(R.id.careportal_tempbasalstart, R.string.careportal_tempbasalstart).date().bg().duration().percent().absolute();
public static final OptionsToShow TEMPBASALEND = new OptionsToShow(R.id.careportal_tempbasalend, R.string.careportal_tempbasalend).date().bg();
public static final OptionsToShow PROFILESWITCH = new OptionsToShow(R.id.careportal_profileswitch, R.string.careportal_profileswitch).date().duration().profile();
public static final OptionsToShow PROFILESWITCHDIRECT = new OptionsToShow(R.id.careportal_profileswitch, R.string.careportal_profileswitch).duration().profile();
public static final OptionsToShow OPENAPSOFFLINE = new OptionsToShow(R.id.careportal_openapsoffline, R.string.careportal_openapsoffline).date().duration();
public static final OptionsToShow TEMPTARGET = new OptionsToShow(R.id.careportal_temporarytarget, R.string.careportal_temporarytarget).date().duration().tempTarget();
@ -180,7 +179,6 @@ public class CareportalFragment extends Fragment implements View.OnClickListener
newDialog.setOptions(NOTE, R.string.careportal_note);
break;
case R.id.careportal_profileswitch:
PROFILESWITCH.executeProfileSwitch = false;
newDialog.setOptions(PROFILESWITCH, R.string.careportal_profileswitch);
break;
case R.id.careportal_pumpsitechange:
@ -202,7 +200,6 @@ public class CareportalFragment extends Fragment implements View.OnClickListener
newDialog.setOptions(OPENAPSOFFLINE, R.string.careportal_openapsoffline);
break;
case R.id.careportal_temporarytarget:
TEMPTARGET.executeTempTarget = false;
newDialog.setOptions(TEMPTARGET, R.string.careportal_temporarytarget);
break;
default:
@ -222,7 +219,7 @@ public class CareportalFragment extends Fragment implements View.OnClickListener
activity.runOnUiThread(
() -> {
CareportalEvent careportalEvent;
NSSettingsStatus nsSettings = new NSSettingsStatus().getInstance();
NSSettingsStatus nsSettings = NSSettingsStatus.getInstance();
double iageUrgent = nsSettings.getExtendedWarnValue("iage", "urgent", 96);
double iageWarn = nsSettings.getExtendedWarnValue("iage", "warn", 72);

View file

@ -1,5 +1,6 @@
package info.nightscout.androidaps.plugins.general.careportal;
import info.nightscout.androidaps.Config;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.interfaces.PluginBase;
import info.nightscout.androidaps.interfaces.PluginDescription;
@ -22,10 +23,14 @@ public class CareportalPlugin extends PluginBase {
.fragmentClass(CareportalFragment.class.getName())
.pluginName(R.string.careportal)
.shortName(R.string.careportal_shortname)
.visibleByDefault(true)
.enableByDefault(true)
.visibleByDefault(Config.NSCLIENT)
.enableByDefault(Config.NSCLIENT)
.description(R.string.description_careportal)
);
}
@Override
public boolean specialEnableCondition() {
return Config.NSCLIENT;
}
}

View file

@ -1,7 +1,6 @@
package info.nightscout.androidaps.plugins.general.careportal.Dialogs;
import android.content.Context;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextWatcher;
@ -9,6 +8,8 @@ import android.text.format.DateFormat;
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.ArrayAdapter;
import android.widget.Button;
@ -18,7 +19,6 @@ import android.widget.RadioButton;
import android.widget.Spinner;
import android.widget.TextView;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatDialogFragment;
import androidx.fragment.app.DialogFragment;
@ -45,8 +45,6 @@ import info.nightscout.androidaps.data.ProfileStore;
import info.nightscout.androidaps.db.BgReading;
import info.nightscout.androidaps.db.CareportalEvent;
import info.nightscout.androidaps.db.ProfileSwitch;
import info.nightscout.androidaps.db.Source;
import info.nightscout.androidaps.db.TempTarget;
import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.configBuilder.ProfileFunctions;
import info.nightscout.androidaps.plugins.general.careportal.OptionsToShow;
@ -58,6 +56,7 @@ import info.nightscout.androidaps.utils.DefaultValueHelper;
import info.nightscout.androidaps.utils.HardLimits;
import info.nightscout.androidaps.utils.JsonHelper;
import info.nightscout.androidaps.utils.NumberPicker;
import info.nightscout.androidaps.utils.OKDialog;
import info.nightscout.androidaps.utils.SP;
import info.nightscout.androidaps.utils.SafeParse;
import info.nightscout.androidaps.utils.Translator;
@ -68,7 +67,7 @@ public class NewNSTreatmentDialog extends AppCompatDialogFragment implements Vie
private static OptionsToShow options;
private static String event;
Profile profile;
private Profile profile;
public ProfileStore profileStore;
TextView eventTypeText;
@ -105,9 +104,10 @@ public class NewNSTreatmentDialog extends AppCompatDialogFragment implements Vie
private static Integer seconds = null;
public void setOptions(OptionsToShow options, int event) {
public NewNSTreatmentDialog setOptions(OptionsToShow options, int event) {
this.options = options;
this.event = MainApp.gs(event);
return this;
}
public NewNSTreatmentDialog() {
@ -122,7 +122,10 @@ public class NewNSTreatmentDialog extends AppCompatDialogFragment implements Vie
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
if (options == null) return null;
getDialog().setTitle(MainApp.gs(options.eventName));
getDialog().getWindow().requestFeature(Window.FEATURE_NO_TITLE);
getDialog().getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN);
setCancelable(true);
getDialog().setCanceledOnTouchOutside(false);
setStyle(DialogFragment.STYLE_NORMAL, getTheme());
View view = inflater.inflate(R.layout.careportal_newnstreatment_dialog, container, false);
@ -200,16 +203,15 @@ public class NewNSTreatmentDialog extends AppCompatDialogFragment implements Vie
boolean erase = false;
String units = ProfileFunctions.getSystemUnits();
DefaultValueHelper helper = new DefaultValueHelper();
if (MainApp.gs(R.string.eatingsoon).equals(reasonList.get(position))) {
defaultDuration = helper.determineEatingSoonTTDuration();
defaultTarget = helper.determineEatingSoonTT();
defaultDuration = DefaultValueHelper.determineEatingSoonTTDuration();
defaultTarget = DefaultValueHelper.determineEatingSoonTT();
} else if (MainApp.gs(R.string.activity).equals(reasonList.get(position))) {
defaultDuration = helper.determineActivityTTDuration();
defaultTarget = helper.determineActivityTT();
defaultDuration = DefaultValueHelper.determineActivityTTDuration();
defaultTarget = DefaultValueHelper.determineActivityTT();
} else if (MainApp.gs(R.string.hypo).equals(reasonList.get(position))) {
defaultDuration = helper.determineHypoTTDuration();
defaultTarget = helper.determineHypoTT();
defaultDuration = DefaultValueHelper.determineHypoTTDuration();
defaultTarget = DefaultValueHelper.determineHypoTT();
} else if (editDuration.getValue() != 0) {
defaultDuration = editDuration.getValue();
} else {
@ -394,6 +396,13 @@ public class NewNSTreatmentDialog extends AppCompatDialogFragment implements Vie
return view;
}
@Override
public void onResume() {
super.onResume();
getDialog().getWindow().setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
}
@Override
public void onClick(View view) {
Calendar calendar = Calendar.getInstance();
@ -585,12 +594,12 @@ public class NewNSTreatmentDialog extends AppCompatDialogFragment implements Vie
String buildConfirmText(JSONObject data) {
String ret = "";
if (data.has("eventType")) {
ret += MainApp.gs(R.string.careportal_newnstreatment_eventtype);
ret += ": ";
ret += Translator.translate(JsonHelper.safeGetString(data, "eventType", ""));
ret += "\n";
}
// if (data.has("eventType")) {
// ret += MainApp.gs(R.string.careportal_newnstreatment_eventtype);
// ret += ": ";
// ret += Translator.translate(JsonHelper.safeGetString(data, "eventType", ""));
// ret += "\n";
// }
if (data.has("glucose")) {
ret += MainApp.gs(R.string.treatments_wizard_bg_label);
ret += ": ";
@ -672,7 +681,7 @@ public class NewNSTreatmentDialog extends AppCompatDialogFragment implements Vie
ret += "\n";
}
if (data.has("created_at")) {
ret += MainApp.gs(R.string.careportal_newnstreatment_eventtime_label);
ret += MainApp.gs(R.string.event_time_label);
ret += ": ";
ret += eventTime.toLocaleString();
ret += "\n";
@ -687,61 +696,25 @@ public class NewNSTreatmentDialog extends AppCompatDialogFragment implements Vie
return ret;
}
void confirmNSTreatmentCreation() {
Context context = getContext();
if (context != null) {
final JSONObject data = gatherData();
final String confirmText = buildConfirmText(data);
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setTitle(MainApp.gs(R.string.confirmation));
builder.setMessage(confirmText);
builder.setPositiveButton(MainApp.gs(R.string.ok), (dialog, id) -> createNSTreatment(data));
builder.setNegativeButton(MainApp.gs(R.string.cancel), null);
builder.show();
}
private void confirmNSTreatmentCreation() {
final JSONObject data = gatherData();
OKDialog.showConfirmation(getContext(), Translator.translate(JsonHelper.safeGetString(data, "eventType", MainApp.gs(R.string.overview_treatment_label))), buildConfirmText(data), () -> createNSTreatment(data));
}
void createNSTreatment(JSONObject data) {
if (options.executeProfileSwitch) {
if (data.has("profile")) {
ProfileFunctions.doProfileSwitch(profileStore, JsonHelper.safeGetString(data, "profile"), JsonHelper.safeGetInt(data, "duration"), JsonHelper.safeGetInt(data, "percentage"), JsonHelper.safeGetInt(data, "timeshift"));
}
} else if (options.executeTempTarget) {
final int duration = JsonHelper.safeGetInt(data, "duration");
final double targetBottom = JsonHelper.safeGetDouble(data, "targetBottom");
final double targetTop = JsonHelper.safeGetDouble(data, "targetTop");
final String reason = JsonHelper.safeGetString(data, "reason", "");
if ((targetBottom != 0d && targetTop != 0d) || duration == 0) {
TempTarget tempTarget = new TempTarget()
.date(eventTime.getTime())
.duration(duration)
.reason(reason)
.source(Source.USER);
if (tempTarget.durationInMinutes != 0) {
tempTarget.low(Profile.toMgdl(targetBottom, ProfileFunctions.getSystemUnits()))
.high(Profile.toMgdl(targetTop, ProfileFunctions.getSystemUnits()));
} else {
tempTarget.low(0).high(0);
}
TreatmentsPlugin.getPlugin().addToHistoryTempTarget(tempTarget);
}
if (duration == 10)
SP.putBoolean(R.string.key_objectiveusetemptarget, true);
if (JsonHelper.safeGetString(data, "eventType", "").equals(CareportalEvent.PROFILESWITCH)) {
ProfileSwitch profileSwitch = ProfileFunctions.prepareProfileSwitch(
profileStore,
JsonHelper.safeGetString(data, "profile"),
JsonHelper.safeGetInt(data, "duration"),
JsonHelper.safeGetInt(data, "percentage"),
JsonHelper.safeGetInt(data, "timeshift"),
eventTime.getTime()
);
NSUpload.uploadProfileSwitch(profileSwitch);
} else {
if (JsonHelper.safeGetString(data, "eventType").equals(CareportalEvent.PROFILESWITCH)) {
ProfileSwitch profileSwitch = ProfileFunctions.prepareProfileSwitch(
profileStore,
JsonHelper.safeGetString(data, "profile"),
JsonHelper.safeGetInt(data, "duration"),
JsonHelper.safeGetInt(data, "percentage"),
JsonHelper.safeGetInt(data, "timeshift"),
eventTime.getTime()
);
NSUpload.uploadProfileSwitch(profileSwitch);
} else {
NSUpload.uploadCareportalEntryToNS(data);
}
NSUpload.uploadCareportalEntryToNS(data);
}
}

View file

@ -19,10 +19,6 @@ public class OptionsToShow {
public boolean split;
public boolean tempTarget;
// perform direct actions
public boolean executeProfileSwitch = false;
public boolean executeTempTarget = false;
public OptionsToShow(int eventType, int eventName) {
this.eventType = eventType;
this.eventName = eventName;

View file

@ -1,6 +1,5 @@
package info.nightscout.androidaps.plugins.general.food;
import android.content.DialogInterface;
import android.graphics.Paint;
import android.os.Bundle;
import android.text.Editable;
@ -14,14 +13,11 @@ import android.widget.EditText;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.appcompat.app.AlertDialog;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
@ -33,6 +29,7 @@ import info.nightscout.androidaps.events.EventFoodDatabaseChanged;
import info.nightscout.androidaps.plugins.bus.RxBus;
import info.nightscout.androidaps.plugins.general.nsclient.NSUpload;
import info.nightscout.androidaps.utils.FabricPrivacy;
import info.nightscout.androidaps.utils.OKDialog;
import info.nightscout.androidaps.utils.SpinnerHelper;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.CompositeDisposable;
@ -42,43 +39,36 @@ import io.reactivex.disposables.CompositeDisposable;
*/
public class FoodFragment extends Fragment {
private static Logger log = LoggerFactory.getLogger(FoodFragment.class);
private CompositeDisposable disposable = new CompositeDisposable();
EditText filter;
ImageView clearFilter;
SpinnerHelper category;
SpinnerHelper subcategory;
RecyclerView recyclerView;
private EditText filter;
private SpinnerHelper category;
private SpinnerHelper subcategory;
private RecyclerView recyclerView;
List<Food> unfiltered;
List<Food> filtered;
ArrayList<CharSequence> categories;
ArrayList<CharSequence> subcategories;
private List<Food> unfiltered;
private List<Food> filtered;
final String EMPTY = MainApp.gs(R.string.none);
private final String EMPTY = MainApp.gs(R.string.none);
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.food_fragment, container, false);
filter = (EditText) view.findViewById(R.id.food_filter);
clearFilter = (ImageView) view.findViewById(R.id.food_clearfilter);
filter = view.findViewById(R.id.food_filter);
ImageView clearFilter = view.findViewById(R.id.food_clearfilter);
category = new SpinnerHelper(view.findViewById(R.id.food_category));
subcategory = new SpinnerHelper(view.findViewById(R.id.food_subcategory));
recyclerView = (RecyclerView) view.findViewById(R.id.food_recyclerview);
recyclerView = view.findViewById(R.id.food_recyclerview);
recyclerView.setHasFixedSize(true);
LinearLayoutManager llm = new LinearLayoutManager(view.getContext());
recyclerView.setLayoutManager(llm);
clearFilter.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
filter.setText("");
category.setSelection(0);
subcategory.setSelection(0);
filterData();
}
clearFilter.setOnClickListener(v -> {
filter.setText("");
category.setSelection(0);
subcategory.setSelection(0);
filterData();
});
category.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@ -149,11 +139,11 @@ public class FoodFragment extends Fragment {
disposable.clear();
}
void loadData() {
private void loadData() {
unfiltered = FoodPlugin.getPlugin().getService().getFoodData();
}
void fillCategories() {
private void fillCategories() {
Set<CharSequence> catSet = new HashSet<>();
for (Food f : unfiltered) {
@ -162,7 +152,7 @@ public class FoodFragment extends Fragment {
}
// make it unique
categories = new ArrayList<>(catSet);
ArrayList<CharSequence> categories = new ArrayList<>(catSet);
categories.add(0, MainApp.gs(R.string.none));
ArrayAdapter<CharSequence> adapterCategories = new ArrayAdapter<>(getContext(),
@ -170,7 +160,7 @@ public class FoodFragment extends Fragment {
category.setAdapter(adapterCategories);
}
void fillSubcategories() {
private void fillSubcategories() {
String categoryFilter = category.getSelectedItem().toString();
Set<CharSequence> subCatSet = new HashSet<>();
@ -184,7 +174,7 @@ public class FoodFragment extends Fragment {
}
// make it unique
subcategories = new ArrayList<>(subCatSet);
ArrayList<CharSequence> subcategories = new ArrayList<>(subCatSet);
subcategories.add(0, MainApp.gs(R.string.none));
ArrayAdapter<CharSequence> adapterSubcategories = new ArrayAdapter<>(getContext(),
@ -192,7 +182,7 @@ public class FoodFragment extends Fragment {
subcategory.setAdapter(adapterSubcategories);
}
void filterData() {
private void filterData() {
String textFilter = filter.getText().toString();
String categoryFilter = category.getSelectedItem().toString();
String subcategoryFilter = subcategory.getSelectedItem().toString();
@ -227,6 +217,7 @@ public class FoodFragment extends Fragment {
this.foodList = foodList;
}
@NonNull
@Override
public FoodsViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.food_item, viewGroup, false);
@ -257,7 +248,7 @@ public class FoodFragment extends Fragment {
return foodList.size();
}
class FoodsViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
class FoodsViewHolder extends RecyclerView.ViewHolder {
TextView name;
TextView portion;
TextView carbs;
@ -269,43 +260,26 @@ public class FoodFragment extends Fragment {
FoodsViewHolder(View itemView) {
super(itemView);
name = (TextView) itemView.findViewById(R.id.food_name);
portion = (TextView) itemView.findViewById(R.id.food_portion);
carbs = (TextView) itemView.findViewById(R.id.food_carbs);
fat = (TextView) itemView.findViewById(R.id.food_fat);
protein = (TextView) itemView.findViewById(R.id.food_protein);
energy = (TextView) itemView.findViewById(R.id.food_energy);
ns = (TextView) itemView.findViewById(R.id.ns_sign);
remove = (TextView) itemView.findViewById(R.id.food_remove);
remove.setOnClickListener(this);
name = itemView.findViewById(R.id.food_name);
portion = itemView.findViewById(R.id.food_portion);
carbs = itemView.findViewById(R.id.food_carbs);
fat = itemView.findViewById(R.id.food_fat);
protein = itemView.findViewById(R.id.food_protein);
energy = itemView.findViewById(R.id.food_energy);
ns = itemView.findViewById(R.id.ns_sign);
remove = itemView.findViewById(R.id.food_remove);
remove.setOnClickListener(v -> {
final Food food = (Food) v.getTag();
OKDialog.showConfirmation(getContext(), MainApp.gs(R.string.confirmation), MainApp.gs(R.string.removerecord) + "\n" + food.name, (dialog, id) -> {
final String _id = food._id;
if (_id != null && !_id.equals("")) {
NSUpload.removeFoodFromNS(_id);
}
FoodPlugin.getPlugin().getService().delete(food);
}, null);
});
remove.setPaintFlags(remove.getPaintFlags() | Paint.UNDERLINE_TEXT_FLAG);
}
@Override
public void onClick(View v) {
final Food food = (Food) v.getTag();
switch (v.getId()) {
case R.id.food_remove:
AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
builder.setTitle(MainApp.gs(R.string.confirmation));
builder.setMessage(MainApp.gs(R.string.removerecord) + "\n" + food.name);
builder.setPositiveButton(MainApp.gs(R.string.ok), new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
final String _id = food._id;
if (_id != null && !_id.equals("")) {
NSUpload.removeFoodFromNS(_id);
}
FoodPlugin.getPlugin().getService().delete(food);
}
});
builder.setNegativeButton(MainApp.gs(R.string.cancel), null);
builder.show();
break;
}
}
}
}
}

View file

@ -2,15 +2,14 @@ package info.nightscout.androidaps.plugins.general.maintenance;
import android.Manifest;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.os.Environment;
import android.preference.PreferenceManager;
import androidx.core.app.ActivityCompat;
import androidx.fragment.app.Fragment;
import androidx.core.content.ContextCompat;
import androidx.fragment.app.Fragment;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -39,7 +38,7 @@ import info.nightscout.androidaps.utils.ToastUtils;
public class ImportExportPrefs {
private static Logger log = LoggerFactory.getLogger(L.CORE);
static File path = new File(Environment.getExternalStorageDirectory().toString());
private static File path = new File(Environment.getExternalStorageDirectory().toString());
static public final File file = new File(path, MainApp.gs(R.string.app_name) + "Preferences");
private static final int REQUEST_EXTERNAL_STORAGE = 1;
@ -48,21 +47,7 @@ public class ImportExportPrefs {
Manifest.permission.WRITE_EXTERNAL_STORAGE
};
public static void verifyStoragePermissions(Activity activity) {
// Check if we have write permission
int permission = ActivityCompat.checkSelfPermission(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE);
if (permission != PackageManager.PERMISSION_GRANTED) {
// We don't have permission so prompt the user
ActivityCompat.requestPermissions(
activity,
PERMISSIONS_STORAGE,
REQUEST_EXTERNAL_STORAGE
);
}
}
public static void verifyStoragePermissions(Fragment fragment) {
static void verifyStoragePermissions(Fragment fragment) {
int permission = ContextCompat.checkSelfPermission(fragment.getContext(),
Manifest.permission.WRITE_EXTERNAL_STORAGE);
@ -73,85 +58,71 @@ public class ImportExportPrefs {
}
public static void exportSharedPreferences(final Fragment f) {
static void exportSharedPreferences(final Fragment f) {
exportSharedPreferences(f.getContext());
}
public static void exportSharedPreferences(final Context c) {
new AlertDialog.Builder(c)
.setMessage(MainApp.gs(R.string.export_to) + " " + file + " ?")
.setPositiveButton(android.R.string.yes, (dialog, which) -> {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(c);
try {
FileWriter fw = new FileWriter(file);
PrintWriter pw = new PrintWriter(fw);
Map<String, ?> prefsMap = prefs.getAll();
for (Map.Entry<String, ?> entry : prefsMap.entrySet()) {
pw.println(entry.getKey() + "::" + entry.getValue().toString());
}
pw.close();
fw.close();
ToastUtils.showToastInUiThread(c, MainApp.gs(R.string.exported));
} catch (FileNotFoundException e) {
ToastUtils.showToastInUiThread(c, MainApp.gs(R.string.filenotfound) + " " + file);
log.error("Unhandled exception", e);
} catch (IOException e) {
log.error("Unhandled exception", e);
}
})
.setNegativeButton(android.R.string.cancel, null)
.show();
private static void exportSharedPreferences(final Context context) {
OKDialog.showConfirmation(context, MainApp.gs(R.string.maintenance), MainApp.gs(R.string.export_to) + " " + file + " ?", () -> {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
try {
FileWriter fw = new FileWriter(file);
PrintWriter pw = new PrintWriter(fw);
Map<String, ?> prefsMap = prefs.getAll();
for (Map.Entry<String, ?> entry : prefsMap.entrySet()) {
pw.println(entry.getKey() + "::" + entry.getValue().toString());
}
pw.close();
fw.close();
ToastUtils.showToastInUiThread(context, MainApp.gs(R.string.exported));
} catch (FileNotFoundException e) {
ToastUtils.showToastInUiThread(context, MainApp.gs(R.string.filenotfound) + " " + file);
log.error("Unhandled exception", e);
} catch (IOException e) {
log.error("Unhandled exception", e);
}
});
}
public static void importSharedPreferences(final Fragment fragment) {
static void importSharedPreferences(final Fragment fragment) {
importSharedPreferences(fragment.getContext());
}
public static void importSharedPreferences(final Context context) {
new AlertDialog.Builder(context)
.setMessage(MainApp.gs(R.string.import_from) + " " + file + " ?")
.setPositiveButton(android.R.string.yes, (dialog, which) -> {
OKDialog.showConfirmation(context, MainApp.gs(R.string.maintenance), MainApp.gs(R.string.import_from) + " " + file + " ?", () -> {
String line;
String[] lineParts;
try {
SP.clear();
String line;
String[] lineParts;
try {
SP.clear();
BufferedReader reader = new BufferedReader(new FileReader(file));
while ((line = reader.readLine()) != null) {
lineParts = line.split("::");
if (lineParts.length == 2) {
if (lineParts[1].equals("true") || lineParts[1].equals("false")) {
SP.putBoolean(lineParts[0], Boolean.parseBoolean(lineParts[1]));
} else {
SP.putString(lineParts[0], lineParts[1]);
}
}
BufferedReader reader = new BufferedReader(new FileReader(file));
while ((line = reader.readLine()) != null) {
lineParts = line.split("::");
if (lineParts.length == 2) {
if (lineParts[1].equals("true") || lineParts[1].equals("false")) {
SP.putBoolean(lineParts[0], Boolean.parseBoolean(lineParts[1]));
} else {
SP.putString(lineParts[0], lineParts[1]);
}
reader.close();
SP.putBoolean(R.string.key_setupwizard_processed, true);
OKDialog.show(context, MainApp.gs(R.string.setting_imported), MainApp.gs(R.string.restartingapp), () -> {
log.debug("Exiting");
MainApp.instance().stopKeepAliveService();
RxBus.INSTANCE.send(new EventAppExit());
MainApp.closeDbHelper();
if (context instanceof Activity) {
((Activity)context).finish();
}
System.runFinalization();
System.exit(0);
});
} catch (FileNotFoundException e) {
ToastUtils.showToastInUiThread(context, MainApp.gs(R.string.filenotfound) + " " + file);
log.error("Unhandled exception", e);
} catch (IOException e) {
log.error("Unhandled exception", e);
}
})
.setNegativeButton(android.R.string.cancel, null)
.show();
}
reader.close();
SP.putBoolean(R.string.key_setupwizard_processed, true);
OKDialog.show(context, MainApp.gs(R.string.setting_imported), MainApp.gs(R.string.restartingapp), () -> {
log.debug("Exiting");
RxBus.INSTANCE.send(new EventAppExit());
if (context instanceof Activity) {
((Activity) context).finish();
}
System.runFinalization();
System.exit(0);
});
} catch (FileNotFoundException e) {
ToastUtils.showToastInUiThread(context, MainApp.gs(R.string.filenotfound) + " " + file);
log.error("Unhandled exception", e);
} catch (IOException e) {
log.error("Unhandled exception", e);
}
});
}
}

View file

@ -2,81 +2,58 @@ package info.nightscout.androidaps.plugins.general.maintenance;
import android.content.Intent;
import android.os.Bundle;
import androidx.fragment.app.Fragment;
import androidx.appcompat.app.AlertDialog;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.fragment.app.Fragment;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.plugins.general.food.FoodPlugin;
import info.nightscout.androidaps.plugins.general.maintenance.activities.LogSettingActivity;
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin;
import info.nightscout.androidaps.utils.OKDialog;
/**
*
*/
public class MaintenanceFragment extends Fragment {
private Fragment f;
@Override
public void onResume() {
super.onResume();
this.f = this;
}
@Override
public void onPause() {
super.onPause();
this.f = null;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.maintenance_fragment, container, false);
final Fragment f = this;
view.findViewById(R.id.log_send).setOnClickListener(view1 -> MaintenancePlugin.getPlugin().sendLogs());
view.findViewById(R.id.log_delete).setOnClickListener(view1 -> MaintenancePlugin.getPlugin().deleteLogs());
view.findViewById(R.id.nav_resetdb).setOnClickListener(view1 -> new AlertDialog.Builder(f.getContext())
.setTitle(R.string.nav_resetdb)
.setMessage(R.string.reset_db_confirm)
.setNegativeButton(android.R.string.cancel, null)
.setPositiveButton(android.R.string.ok, (dialog, which) -> {
view.findViewById(R.id.nav_resetdb).setOnClickListener(view1 ->
OKDialog.showConfirmation(getContext(), MainApp.gs(R.string.maintenance), MainApp.gs(R.string.reset_db_confirm), () -> {
MainApp.getDbHelper().resetDatabases();
// should be handled by Plugin-Interface and
// additional service interface and plugin registry
FoodPlugin.getPlugin().getService().resetFood();
TreatmentsPlugin.getPlugin().getService().resetTreatments();
})
.create()
.show());
);
view.findViewById(R.id.nav_export).setOnClickListener(view1 -> {
// start activity for checking permissions...
ImportExportPrefs.verifyStoragePermissions(f);
ImportExportPrefs.exportSharedPreferences(f);
ImportExportPrefs.verifyStoragePermissions(this);
ImportExportPrefs.exportSharedPreferences(this);
});
view.findViewById(R.id.nav_import).setOnClickListener(view1 -> {
// start activity for checking permissions...
ImportExportPrefs.verifyStoragePermissions(f);
ImportExportPrefs.importSharedPreferences(f);
ImportExportPrefs.verifyStoragePermissions(this);
ImportExportPrefs.importSharedPreferences(this);
});
view.findViewById(R.id.nav_logsettings).setOnClickListener(view1 -> {
startActivity(new Intent(getActivity(), LogSettingActivity.class));
});
return view;
}

View file

@ -1,9 +1,6 @@
package info.nightscout.androidaps.plugins.general.nsclient;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.graphics.Paint;
import android.os.Bundle;
import android.text.Html;
@ -25,6 +22,7 @@ import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientN
import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientRestart;
import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientUpdateGUI;
import info.nightscout.androidaps.utils.FabricPrivacy;
import info.nightscout.androidaps.utils.OKDialog;
import info.nightscout.androidaps.utils.SP;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.CompositeDisposable;
@ -113,20 +111,11 @@ public class NSClientFragment extends Fragment implements View.OnClickListener,
NSClientPlugin.getPlugin().clearLog();
break;
case R.id.nsclientinternal_clearqueue:
final Context context = getContext();
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setTitle(MainApp.gs(R.string.confirmation));
builder.setMessage("Clear queue? All data in queue will be lost!");
builder.setPositiveButton(MainApp.gs(R.string.ok), new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
UploadQueue.clearQueue();
updateGui();
FabricPrivacy.getInstance().logCustom("NSClientClearQueue");
}
OKDialog.showConfirmation(getContext(),MainApp.gs(R.string.nsclientinternal), MainApp.gs(R.string.clearqueueconfirm), () -> {
UploadQueue.clearQueue();
updateGui();
FabricPrivacy.getInstance().logCustom("NSClientClearQueue");
});
builder.setNegativeButton(MainApp.gs(R.string.cancel), null);
builder.show();
break;
case R.id.nsclientinternal_showqueue:
RxBus.INSTANCE.send(new EventNSClientNewLog("QUEUE", NSClientPlugin.getPlugin().queue().textList()));

View file

@ -32,6 +32,8 @@ import info.nightscout.androidaps.interfaces.PluginDescription;
import info.nightscout.androidaps.interfaces.PluginType;
import info.nightscout.androidaps.logging.L;
import info.nightscout.androidaps.plugins.bus.RxBus;
import info.nightscout.androidaps.plugins.general.nsclient.data.AlarmAck;
import info.nightscout.androidaps.plugins.general.nsclient.data.NSAlarm;
import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientNewLog;
import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientStatus;
import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientUpdateGUI;
@ -250,4 +252,25 @@ public class NSClientPlugin extends PluginBase {
public boolean hasWritePermission() {
return nsClientService.hasWriteAuth;
}
public void handleClearAlarm(NSAlarm originalAlarm, long silenceTimeInMsec) {
if (!isEnabled(PluginType.GENERAL)) {
return;
}
if (SP.getBoolean(R.string.key_ns_noupload, false)) {
if (L.isEnabled(L.NSCLIENT))
log.debug("Upload disabled. Message dropped");
return;
}
AlarmAck ack = new AlarmAck();
ack.level = originalAlarm.getLevel();
ack.group = originalAlarm.getGroup();
ack.silenceTime = silenceTimeInMsec;
if (nsClientService != null)
nsClientService.sendAlarmAck(ack);
}
}

View file

@ -1,14 +1,13 @@
package info.nightscout.androidaps.plugins.general.nsclient;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.ResolveInfo;
import android.os.Build;
import android.os.Bundle;
import android.preference.PreferenceManager;
import androidx.annotation.Nullable;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import org.apache.commons.lang3.StringUtils;
import org.json.JSONArray;
@ -24,22 +23,23 @@ import java.util.Locale;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.logging.L;
import info.nightscout.androidaps.plugins.configBuilder.ProfileFunctions;
import info.nightscout.androidaps.services.Intents;
import info.nightscout.androidaps.data.DetailedBolusInfo;
import info.nightscout.androidaps.data.IobTotal;
import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.db.BgReading;
import info.nightscout.androidaps.db.CareportalEvent;
import info.nightscout.androidaps.db.DbRequest;
import info.nightscout.androidaps.db.ExtendedBolus;
import info.nightscout.androidaps.db.ProfileSwitch;
import info.nightscout.androidaps.db.TempTarget;
import info.nightscout.androidaps.db.TemporaryBasal;
import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.logging.L;
import info.nightscout.androidaps.plugins.aps.loop.APSResult;
import info.nightscout.androidaps.plugins.aps.loop.DeviceStatus;
import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin;
import info.nightscout.androidaps.plugins.general.nsclient.data.DbLogger;
import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.configBuilder.ProfileFunctions;
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin;
import info.nightscout.androidaps.utils.BatteryLevel;
import info.nightscout.androidaps.utils.DateUtil;
import info.nightscout.androidaps.utils.SP;
@ -53,7 +53,6 @@ public class NSUpload {
public static void uploadTempBasalStartAbsolute(TemporaryBasal temporaryBasal, Double originalExtendedAmount) {
try {
Context context = MainApp.instance().getApplicationContext();
JSONObject data = new JSONObject();
data.put("eventType", CareportalEvent.TEMPBASAL);
data.put("duration", temporaryBasal.durationInMinutes);
@ -65,15 +64,7 @@ public class NSUpload {
data.put("enteredBy", "openaps://" + MainApp.gs(R.string.app_name));
if (originalExtendedAmount != null)
data.put("originalExtendedAmount", originalExtendedAmount); // for back synchronization
Bundle bundle = new Bundle();
bundle.putString("action", "dbAdd");
bundle.putString("collection", "treatments");
bundle.putString("data", data.toString());
Intent intent = new Intent(Intents.ACTION_DATABASE);
intent.putExtras(bundle);
intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
LocalBroadcastManager.getInstance(context).sendBroadcast(intent);
DbLogger.dbAdd(intent, data.toString());
UploadQueue.add(new DbRequest("dbAdd", "treatments", data));
} catch (JSONException e) {
log.error("Unhandled exception", e);
}
@ -96,7 +87,6 @@ public class NSUpload {
uploadTempBasalStartAbsolute(t, null);
}
} else {
Context context = MainApp.instance().getApplicationContext();
JSONObject data = new JSONObject();
data.put("eventType", CareportalEvent.TEMPBASAL);
data.put("duration", temporaryBasal.durationInMinutes);
@ -107,15 +97,7 @@ public class NSUpload {
data.put("pumpId", temporaryBasal.pumpId);
data.put("created_at", DateUtil.toISOString(temporaryBasal.date));
data.put("enteredBy", "openaps://" + MainApp.gs(R.string.app_name));
Bundle bundle = new Bundle();
bundle.putString("action", "dbAdd");
bundle.putString("collection", "treatments");
bundle.putString("data", data.toString());
Intent intent = new Intent(Intents.ACTION_DATABASE);
intent.putExtras(bundle);
intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
LocalBroadcastManager.getInstance(context).sendBroadcast(intent);
DbLogger.dbAdd(intent, data.toString());
UploadQueue.add(new DbRequest("dbAdd", "treatments", data));
}
} catch (JSONException e) {
log.error("Unhandled exception", e);
@ -124,7 +106,6 @@ public class NSUpload {
public static void uploadTempBasalEnd(long time, boolean isFakedTempBasal, long pumpId) {
try {
Context context = MainApp.instance().getApplicationContext();
JSONObject data = new JSONObject();
data.put("eventType", CareportalEvent.TEMPBASAL);
data.put("created_at", DateUtil.toISOString(time));
@ -133,15 +114,7 @@ public class NSUpload {
data.put("isFakedTempBasal", isFakedTempBasal);
if (pumpId != 0)
data.put("pumpId", pumpId);
Bundle bundle = new Bundle();
bundle.putString("action", "dbAdd");
bundle.putString("collection", "treatments");
bundle.putString("data", data.toString());
Intent intent = new Intent(Intents.ACTION_DATABASE);
intent.putExtras(bundle);
intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
LocalBroadcastManager.getInstance(context).sendBroadcast(intent);
DbLogger.dbAdd(intent, data.toString());
UploadQueue.add(new DbRequest("dbAdd", "treatments", data));
} catch (JSONException e) {
log.error("Unhandled exception", e);
}
@ -149,7 +122,6 @@ public class NSUpload {
public static void uploadExtendedBolus(ExtendedBolus extendedBolus) {
try {
Context context = MainApp.instance().getApplicationContext();
JSONObject data = new JSONObject();
data.put("eventType", CareportalEvent.COMBOBOLUS);
data.put("duration", extendedBolus.durationInMinutes);
@ -161,15 +133,7 @@ public class NSUpload {
data.put("pumpId", extendedBolus.pumpId);
data.put("created_at", DateUtil.toISOString(extendedBolus.date));
data.put("enteredBy", "openaps://" + MainApp.gs(R.string.app_name));
Bundle bundle = new Bundle();
bundle.putString("action", "dbAdd");
bundle.putString("collection", "treatments");
bundle.putString("data", data.toString());
Intent intent = new Intent(Intents.ACTION_DATABASE);
intent.putExtras(bundle);
intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
LocalBroadcastManager.getInstance(context).sendBroadcast(intent);
DbLogger.dbAdd(intent, data.toString());
UploadQueue.add(new DbRequest("dbAdd", "treatments", data));
} catch (JSONException e) {
log.error("Unhandled exception", e);
}
@ -177,7 +141,6 @@ public class NSUpload {
public static void uploadExtendedBolusEnd(long time, long pumpId) {
try {
Context context = MainApp.instance().getApplicationContext();
JSONObject data = new JSONObject();
data.put("eventType", CareportalEvent.COMBOBOLUS);
data.put("duration", 0);
@ -189,15 +152,7 @@ public class NSUpload {
data.put("enteredBy", "openaps://" + MainApp.gs(R.string.app_name));
if (pumpId != 0)
data.put("pumpId", pumpId);
Bundle bundle = new Bundle();
bundle.putString("action", "dbAdd");
bundle.putString("collection", "treatments");
bundle.putString("data", data.toString());
Intent intent = new Intent(Intents.ACTION_DATABASE);
intent.putExtras(bundle);
intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
LocalBroadcastManager.getInstance(context).sendBroadcast(intent);
DbLogger.dbAdd(intent, data.toString());
UploadQueue.add(new DbRequest("dbAdd", "treatments", data));
} catch (JSONException e) {
log.error("Unhandled exception", e);
}
@ -246,7 +201,12 @@ public class NSUpload {
}
} else {
if (L.isEnabled(L.NSCLIENT))
log.debug("OpenAPS data too old to upload");
log.debug("OpenAPS data too old to upload, sending iob only");
IobTotal[] iob = IobCobCalculatorPlugin.getPlugin().calculateIobArrayInDia(profile);
if (iob.length > 0) {
deviceStatus.iob = iob[0].json();
deviceStatus.iob.put("time", DateUtil.toISOString(DateUtil.now()));
}
}
deviceStatus.device = "openaps://" + Build.MANUFACTURER + " " + Build.MODEL;
JSONObject pumpstatus = ConfigBuilderPlugin.getPlugin().getActivePump().getJSONStatus(profile, profileName);
@ -258,16 +218,7 @@ public class NSUpload {
deviceStatus.uploaderBattery = batteryLevel;
deviceStatus.created_at = DateUtil.toISOString(new Date());
Context context = MainApp.instance().getApplicationContext();
Bundle bundle = new Bundle();
bundle.putString("action", "dbAdd");
bundle.putString("collection", "devicestatus");
bundle.putString("data", deviceStatus.mongoRecord().toString());
Intent intent = new Intent(Intents.ACTION_DATABASE);
intent.putExtras(bundle);
intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
LocalBroadcastManager.getInstance(context).sendBroadcast(intent);
DbLogger.dbAdd(intent, deviceStatus.mongoRecord().toString());
UploadQueue.add(new DbRequest("dbAdd", "devicestatus", deviceStatus.mongoRecord()));
} catch (JSONException e) {
log.error("Unhandled exception", e);
}
@ -315,11 +266,13 @@ public class NSUpload {
JSONObject data = new JSONObject();
data.put("eventType", CareportalEvent.TEMPORARYTARGET);
data.put("duration", tempTarget.durationInMinutes);
data.put("reason", tempTarget.reason);
data.put("targetBottom", Profile.fromMgdlToUnits(tempTarget.low, ProfileFunctions.getSystemUnits()));
data.put("targetTop", Profile.fromMgdlToUnits(tempTarget.high, ProfileFunctions.getSystemUnits()));
if (tempTarget.low > 0) {
data.put("reason", tempTarget.reason);
data.put("targetBottom", Profile.fromMgdlToUnits(tempTarget.low, ProfileFunctions.getSystemUnits()));
data.put("targetTop", Profile.fromMgdlToUnits(tempTarget.high, ProfileFunctions.getSystemUnits()));
data.put("units", ProfileFunctions.getSystemUnits());
}
data.put("created_at", DateUtil.toISOString(tempTarget.date));
data.put("units", ProfileFunctions.getSystemUnits());
data.put("enteredBy", MainApp.gs(R.string.app_name));
uploadCareportalEntryToNS(data);
} catch (JSONException e) {
@ -331,17 +284,7 @@ public class NSUpload {
try {
JSONObject data = getJson(profileSwitch);
if (profileSwitch._id != null) {
Context context = MainApp.instance().getApplicationContext();
Bundle bundle = new Bundle();
bundle.putString("action", "dbUpdate");
bundle.putString("collection", "treatments");
bundle.putString("data", data.toString());
bundle.putString("_id", profileSwitch._id);
Intent intent = new Intent(Intents.ACTION_DATABASE);
intent.putExtras(bundle);
intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
LocalBroadcastManager.getInstance(context).sendBroadcast(intent);
DbLogger.dbAdd(intent, data.toString());
UploadQueue.add(new DbRequest("dbUpdate", "treatments", profileSwitch._id, data));
}
} catch (JSONException e) {
log.error("Unhandled exception", e);
@ -380,16 +323,7 @@ public class NSUpload {
prebolus.put("created_at", DateUtil.toISOString(preBolusDate));
uploadCareportalEntryToNS(prebolus);
}
Context context = MainApp.instance().getApplicationContext();
Bundle bundle = new Bundle();
bundle.putString("action", "dbAdd");
bundle.putString("collection", "treatments");
bundle.putString("data", data.toString());
Intent intent = new Intent(Intents.ACTION_DATABASE);
intent.putExtras(bundle);
intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
LocalBroadcastManager.getInstance(context).sendBroadcast(intent);
DbLogger.dbAdd(intent, data.toString());
UploadQueue.add(new DbRequest("dbAdd", "treatments", data));
} catch (Exception e) {
log.error("Unhandled exception", e);
}
@ -397,40 +331,17 @@ public class NSUpload {
}
public static void removeCareportalEntryFromNS(String _id) {
try {
Context context = MainApp.instance().getApplicationContext();
Bundle bundle = new Bundle();
bundle.putString("action", "dbRemove");
bundle.putString("collection", "treatments");
bundle.putString("_id", _id);
Intent intent = new Intent(Intents.ACTION_DATABASE);
intent.putExtras(bundle);
intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
LocalBroadcastManager.getInstance(context).sendBroadcast(intent);
DbLogger.dbRemove(intent, _id);
} catch (Exception e) {
log.error("Unhandled exception", e);
}
UploadQueue.add(new DbRequest("dbRemove", "treatments", _id));
}
public static void uploadOpenAPSOffline(double durationInMinutes) {
try {
Context context = MainApp.instance().getApplicationContext();
JSONObject data = new JSONObject();
data.put("eventType", "OpenAPS Offline");
data.put("duration", durationInMinutes);
data.put("created_at", DateUtil.toISOString(new Date()));
data.put("enteredBy", "openaps://" + MainApp.gs(R.string.app_name));
Bundle bundle = new Bundle();
bundle.putString("action", "dbAdd");
bundle.putString("collection", "treatments");
bundle.putString("data", data.toString());
Intent intent = new Intent(Intents.ACTION_DATABASE);
intent.putExtras(bundle);
intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
LocalBroadcastManager.getInstance(context).sendBroadcast(intent);
DbLogger.dbAdd(intent, data.toString());
UploadQueue.add(new DbRequest("dbAdd", "treatments", data));
} catch (JSONException e) {
log.error("Unhandled exception", e);
}
@ -441,10 +352,6 @@ public class NSUpload {
}
public static void uploadError(String error, Date date) {
Context context = MainApp.instance().getApplicationContext();
Bundle bundle = new Bundle();
bundle.putString("action", "dbAdd");
bundle.putString("collection", "treatments");
JSONObject data = new JSONObject();
try {
data.put("eventType", "Announcement");
@ -455,19 +362,10 @@ public class NSUpload {
} catch (JSONException e) {
log.error("Unhandled exception", e);
}
bundle.putString("data", data.toString());
Intent intent = new Intent(Intents.ACTION_DATABASE);
intent.putExtras(bundle);
intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
LocalBroadcastManager.getInstance(context).sendBroadcast(intent);
DbLogger.dbAdd(intent, data.toString());
UploadQueue.add(new DbRequest("dbAdd", "treatments", data));
}
public static void uploadBg(BgReading reading, String source) {
Context context = MainApp.instance().getApplicationContext();
Bundle bundle = new Bundle();
bundle.putString("action", "dbAdd");
bundle.putString("collection", "entries");
JSONObject data = new JSONObject();
try {
data.put("device", source);
@ -479,20 +377,11 @@ public class NSUpload {
} catch (JSONException e) {
log.error("Unhandled exception", e);
}
bundle.putString("data", data.toString());
Intent intent = new Intent(Intents.ACTION_DATABASE);
intent.putExtras(bundle);
intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
LocalBroadcastManager.getInstance(context).sendBroadcast(intent);
DbLogger.dbAdd(intent, data.toString());
UploadQueue.add(new DbRequest("dbAdd", "entries", data));
}
public static void uploadAppStart() {
if (SP.getBoolean(R.string.key_ns_logappstartedevent, true)) {
Context context = MainApp.instance().getApplicationContext();
Bundle bundle = new Bundle();
bundle.putString("action", "dbAdd");
bundle.putString("collection", "treatments");
JSONObject data = new JSONObject();
try {
data.put("eventType", "Note");
@ -501,35 +390,17 @@ public class NSUpload {
} catch (JSONException e) {
log.error("Unhandled exception", e);
}
bundle.putString("data", data.toString());
Intent intent = new Intent(Intents.ACTION_DATABASE);
intent.putExtras(bundle);
intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
LocalBroadcastManager.getInstance(context).sendBroadcast(intent);
DbLogger.dbAdd(intent, data.toString());
UploadQueue.add(new DbRequest("dbAdd", "treatments", data));
}
}
public static void uploadProfileStore(JSONObject profileStore) {
if (SP.getBoolean(R.string.key_ns_uploadlocalprofile, false)) {
Context context = MainApp.instance().getApplicationContext();
Bundle bundle = new Bundle();
bundle.putString("action", "dbAdd");
bundle.putString("collection", "profile");
bundle.putString("data", String.valueOf(profileStore));
Intent intent = new Intent(Intents.ACTION_DATABASE);
intent.putExtras(bundle);
intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
LocalBroadcastManager.getInstance(context).sendBroadcast(intent);
DbLogger.dbAdd(intent, String.valueOf(profileStore));
UploadQueue.add(new DbRequest("dbAdd", "profile", String.valueOf(profileStore)));
}
}
public static void uploadEvent(String careportalEvent, long time, @Nullable String notes) {
Context context = MainApp.instance().getApplicationContext();
Bundle bundle = new Bundle();
bundle.putString("action", "dbAdd");
bundle.putString("collection", "treatments");
JSONObject data = new JSONObject();
try {
data.put("eventType", careportalEvent);
@ -541,26 +412,12 @@ public class NSUpload {
} catch (JSONException e) {
log.error("Unhandled exception", e);
}
bundle.putString("data", data.toString());
Intent intent = new Intent(Intents.ACTION_DATABASE);
intent.putExtras(bundle);
intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
LocalBroadcastManager.getInstance(context).sendBroadcast(intent);
DbLogger.dbAdd(intent, data.toString());
UploadQueue.add(new DbRequest("dbAdd", "treatments", data));
}
public static void removeFoodFromNS(String _id) {
try {
Context context = MainApp.instance().getApplicationContext();
Bundle bundle = new Bundle();
bundle.putString("action", "dbRemove");
bundle.putString("collection", "food");
bundle.putString("_id", _id);
Intent intent = new Intent(Intents.ACTION_DATABASE);
intent.putExtras(bundle);
intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
LocalBroadcastManager.getInstance(context).sendBroadcast(intent);
DbLogger.dbRemove(intent, _id);
UploadQueue.add(new DbRequest("dbRemove", "food", _id));
} catch (Exception e) {
log.error("Unhandled exception", e);
}

View file

@ -47,7 +47,17 @@ public class UploadQueue {
NSClientService.handler.post(() -> {
if (L.isEnabled(L.NSCLIENT))
log.debug("Adding to queue: " + dbr.data);
MainApp.getDbHelper().create(dbr);
try {
MainApp.getDbHelper().create(dbr);
} catch (Exception e) {
log.error("Unhandled exception", e);
dbr.nsClientID += "1";
try {
MainApp.getDbHelper().create(dbr);
} catch (Exception e1) {
log.error("Unhandled exception", e1);
}
}
NSClientPlugin plugin = NSClientPlugin.getPlugin();
if (plugin != null) {
plugin.resend("newdata");

View file

@ -1,43 +0,0 @@
package info.nightscout.androidaps.plugins.general.nsclient.broadcasts;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.services.Intents;
import info.nightscout.androidaps.plugins.general.nsclient.data.NSAlarm;
import info.nightscout.androidaps.utils.SP;
/**
* Created by mike on 11.06.2017.
*/
public class BroadcastAckAlarm {
public static void handleClearAlarm(NSAlarm originalAlarm, Context context, long silenceTimeInMsec) {
Bundle bundle = new Bundle();
bundle.putInt("level", originalAlarm.getLevel());
bundle.putString("group", originalAlarm.getGroup());
bundle.putLong("silenceTime", silenceTimeInMsec);
Intent intent = new Intent(Intents.ACTION_ACK_ALARM);
intent.putExtras(bundle);
intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
LocalBroadcastManager.getInstance(MainApp.instance()).sendBroadcast(intent);
if(SP.getBoolean(R.string.key_nsclient_localbroadcasts, false)) {
bundle = new Bundle();
bundle.putInt("level", originalAlarm.getLevel());
bundle.putString("group", originalAlarm.getGroup());
bundle.putLong("silenceTime", silenceTimeInMsec);
intent = new Intent(Intents.ACTION_ACK_ALARM);
intent.putExtras(bundle);
intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
context.sendBroadcast(intent);
}
}
}

View file

@ -25,12 +25,11 @@ import info.nightscout.androidaps.utils.SP;
public class BroadcastTreatment {
private static Logger log = LoggerFactory.getLogger(L.NSCLIENT);
public static void handleNewTreatment(JSONObject treatment, boolean isDelta, boolean isLocalBypass) {
public static void handleNewTreatment(JSONObject treatment, boolean isDelta) {
Bundle bundle = new Bundle();
bundle.putString("treatment", treatment.toString());
bundle.putBoolean("delta", isDelta);
bundle.putBoolean("islocal", isLocalBypass);
Intent intent = new Intent(Intents.ACTION_NEW_TREATMENT);
intent.putExtras(bundle);
intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);

View file

@ -1,43 +0,0 @@
package info.nightscout.androidaps.plugins.general.nsclient.data;
import android.content.Intent;
import android.content.pm.ResolveInfo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.logging.L;
import info.nightscout.androidaps.utils.ToastUtils;
/**
* Created by mike on 02.07.2016.
*/
public class DbLogger {
private static Logger log = LoggerFactory.getLogger(L.NSCLIENT);
public static void dbAdd(Intent intent, String data) {
List<ResolveInfo> q = MainApp.instance().getApplicationContext().getPackageManager().queryBroadcastReceivers(intent, 0);
if (q.size() < 1) {
ToastUtils.showToastInUiThread(MainApp.instance().getApplicationContext(), MainApp.gs(R.string.nsclientnotinstalled));
log.error("DBADD No receivers");
} else if (L.isEnabled(L.NSCLIENT)) {
if (L.isEnabled(L.NSCLIENT))
log.debug("DBADD dbAdd " + q.size() + " receivers " + data);
}
}
public static void dbRemove(Intent intent, String data) {
List<ResolveInfo> q = MainApp.instance().getApplicationContext().getPackageManager().queryBroadcastReceivers(intent, 0);
if (q.size() < 1) {
ToastUtils.showToastInUiThread(MainApp.instance().getApplicationContext(), MainApp.gs(R.string.nsclientnotinstalled));
log.error("DBREMOVE No receivers");
} else if (L.isEnabled(L.NSCLIENT)) {
if (L.isEnabled(L.NSCLIENT))
log.debug("DBREMOVE dbRemove " + q.size() + " receivers " + data);
}
}
}

View file

@ -407,7 +407,7 @@ public class NSDeviceStatus {
}
Uploader uploader = uploaders.get(device);
// check if this is new data
if (clock != 0 && (uploader != null && clock > uploader.clock || uploader == null)) {
if (clock != 0 && battery != null && (uploader != null && clock > uploader.clock || uploader == null)) {
if (uploader == null)
uploader = new Uploader();
uploader.battery = battery;

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