Merge pull request #147 from nightscout/2.8.0prep

2.8.0 release
This commit is contained in:
Milos Kozak 2021-01-02 11:05:02 +01:00 committed by GitHub
commit d40c5079d5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
981 changed files with 30541 additions and 15534 deletions

View file

@ -4,18 +4,9 @@
<JetCodeStyleSettings> <JetCodeStyleSettings>
<option name="PACKAGES_TO_USE_STAR_IMPORTS"> <option name="PACKAGES_TO_USE_STAR_IMPORTS">
<value> <value>
<package name="java.util" alias="false" withSubpackages="false" /> <package name="java.util" withSubpackages="false" static="false" />
<package name="kotlinx.android.synthetic" alias="false" withSubpackages="true" /> <package name="kotlinx.android.synthetic" withSubpackages="true" static="false" />
<package name="io.ktor" alias="false" withSubpackages="true" /> <package name="io.ktor" withSubpackages="true" static="false" />
</value>
</option>
<option name="PACKAGES_IMPORT_LAYOUT">
<value>
<package name="" alias="false" withSubpackages="true" />
<package name="java" alias="false" withSubpackages="true" />
<package name="javax" alias="false" withSubpackages="true" />
<package name="kotlin" alias="false" withSubpackages="true" />
<package name="" alias="true" withSubpackages="true" />
</value> </value>
</option> </option>
<option name="ALIGN_IN_COLUMNS_CASE_BRANCH" value="true" /> <option name="ALIGN_IN_COLUMNS_CASE_BRANCH" value="true" />

View file

@ -36,7 +36,7 @@ Translations
------------ ------------
* If possible, always use Android translation mechanism (with strings.xml and @strings/id) instead of hardcoded texts * If possible, always use Android translation mechanism (with strings.xml and @strings/id) instead of hardcoded texts
* Provide only English strings - all other languages will be crowd translated via Crowdn https://translations.androidaps.org/ * Provide only English strings - all other languages will be crowd translated via Crowdin (https://crowdin.com/project/androidaps and https://crowdin.com/project/androidapsdocs)
Hints Hints
----- -----

View file

@ -22,14 +22,6 @@ jacoco {
toolVersion = "0.8.3" toolVersion = "0.8.3"
} }
ext {
powermockVersion = "1.7.3"
dexmakerVersion = "1.2"
retrofit2Version = '2.9.0'
okhttp3Version = '4.7.2'
}
repositories { repositories {
jcenter { url "https://jcenter.bintray.com/" } jcenter { url "https://jcenter.bintray.com/" }
mavenCentral() mavenCentral()
@ -124,11 +116,11 @@ android {
ndkVersion "21.1.6352462" ndkVersion "21.1.6352462"
defaultConfig { defaultConfig {
minSdkVersion 24 minSdkVersion 26
targetSdkVersion 28 targetSdkVersion 28
multiDexEnabled true multiDexEnabled true
versionCode 1500 versionCode 1500
version "2.7.0" version "2.8.0"
buildConfigField "String", "VERSION", '"' + version + '"' buildConfigField "String", "VERSION", '"' + version + '"'
buildConfigField "String", "BUILDVERSION", '"' + generateGitBuild() + '-' + generateDate() + '"' buildConfigField "String", "BUILDVERSION", '"' + generateGitBuild() + '-' + generateDate() + '"'
buildConfigField "String", "REMOTE", '"' + generateGitRemote() + '"' buildConfigField "String", "REMOTE", '"' + generateGitRemote() + '"'
@ -143,6 +135,9 @@ android {
kotlinOptions { kotlinOptions {
jvmTarget = '1.8' jvmTarget = '1.8'
} }
buildFeatures {
viewBinding true
}
lintOptions { lintOptions {
checkReleaseBuilds false checkReleaseBuilds false
disable 'MissingTranslation' disable 'MissingTranslation'
@ -230,11 +225,9 @@ android {
allprojects { allprojects {
repositories { repositories {
jcenter()
flatDir { flatDir {
dirs 'libs' dirs 'libs'
} }
maven { url 'https://jitpack.io' }
} }
} }
@ -247,68 +240,13 @@ dependencies {
implementation project(':danar') implementation project(':danar')
implementation project(':rileylink') implementation project(':rileylink')
implementation project(':medtronic') implementation project(':medtronic')
implementation project(':omnipod')
implementation fileTree(include: ['*.jar'], dir: 'libs') implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation 'com.google.android.gms:play-services-wearable:17.0.0'
implementation "com.google.android.gms:play-services-location:17.0.0"
implementation 'com.google.firebase:firebase-core:17.4.3'
implementation 'com.google.firebase:firebase-auth:19.3.1'
implementation 'com.google.firebase:firebase-database:19.3.1'
implementation 'androidx.appcompat:appcompat:1.1.0' testImplementation "junit:junit:$junit_version"
implementation 'androidx.legacy:legacy-support-v13:1.0.0'
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
implementation 'androidx.cardview:cardview:1.0.0'
implementation 'androidx.biometric:biometric:1.0.1'
implementation 'androidx.recyclerview:recyclerview:1.1.0'
implementation 'androidx.gridlayout:gridlayout:1.0.0'
implementation 'androidx.percentlayout:percentlayout:1.0.0'
implementation "androidx.preference:preference-ktx:1.1.1"
implementation "androidx.activity:activity-ktx:${activityVersion}"
implementation "androidx.fragment:fragment:${fragmentVersion}"
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
implementation 'com.google.android.material:material:1.1.0'
implementation "io.reactivex.rxjava2:rxandroid:${rxandroid_version}"
implementation "com.j256.ormlite:ormlite-core:${ormLiteVersion}"
implementation "com.j256.ormlite:ormlite-android:${ormLiteVersion}"
implementation("com.github.tony19:logback-android-classic:1.1.1-6") {
exclude group: "com.google.android", module: "android"
}
implementation 'org.apache.commons:commons-lang3:3.10'
implementation 'org.slf4j:slf4j-api:1.7.30'
// Graphview cannot be upgraded
implementation "com.jjoe64:graphview:4.0.1"
implementation "com.joanzapata.iconify:android-iconify-fontawesome:2.2.2"
implementation 'com.madgag.spongycastle:core:1.58.0.0'
// Omnipod wizard
implementation(name: "com.atech-software.android.library.wizardpager-1.1.4", ext: "aar")
implementation("com.google.android:flexbox:0.3.0") {
exclude group: "com.android.support"
}
implementation("io.socket:socket.io-client:1.0.0") {
// excluding org.json which is provided by Android
exclude group: "org.json", module: "json"
}
implementation "com.google.code.gson:gson:2.8.6"
implementation('com.google.guava:guava:29.0-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.6'
implementation 'org.mozilla:rhino:1.7.12'
implementation 'com.github.DavidProdinger:weekdays-selector:1.1.0'
implementation 'com.github.kenglxn.QRGen:android:2.6.0'
implementation 'com.eatthepath:java-otp:0.2.0'
testImplementation "junit:junit:4.13"
testImplementation 'org.json:json:20200518' testImplementation 'org.json:json:20200518'
testImplementation "org.mockito:mockito-core:2.8.47" testImplementation "org.mockito:mockito-core:${mockitoVersion}"
testImplementation "org.powermock:powermock-api-mockito2:${powermockVersion}" testImplementation "org.powermock:powermock-api-mockito2:${powermockVersion}"
testImplementation "org.powermock:powermock-module-junit4-rule-agent:${powermockVersion}" testImplementation "org.powermock:powermock-module-junit4-rule-agent:${powermockVersion}"
testImplementation "org.powermock:powermock-module-junit4-rule:${powermockVersion}" testImplementation "org.powermock:powermock-module-junit4-rule:${powermockVersion}"
@ -321,31 +259,16 @@ dependencies {
testImplementation "org.skyscreamer:jsonassert:1.5.0" testImplementation "org.skyscreamer:jsonassert:1.5.0"
testImplementation "org.hamcrest:hamcrest-all:1.3" testImplementation "org.hamcrest:hamcrest-all:1.3"
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutinesVersion"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutinesVersion"
// new for tidepool
implementation "com.squareup.okhttp3:okhttp:$okhttp3Version"
implementation "com.squareup.okhttp3:logging-interceptor:$okhttp3Version"
implementation "com.squareup.retrofit2:retrofit:$retrofit2Version"
implementation "com.squareup.retrofit2:adapter-rxjava2:$retrofit2Version"
implementation "com.squareup.retrofit2:converter-gson:$retrofit2Version"
// Phone checker
implementation 'com.scottyab:rootbeer-lib:0.0.8'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0-alpha03' androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0-alpha03'
androidTestImplementation 'androidx.test.ext:junit:1.1.1' androidTestImplementation "androidx.test.ext:junit:$androidx_junit"
androidTestImplementation 'androidx.test:rules:1.3.0-beta01' androidTestImplementation "androidx.test:rules:$androidx_rules"
androidTestImplementation 'com.google.code.findbugs:jsr305:3.0.2' androidTestImplementation 'com.google.code.findbugs:jsr305:3.0.2'
/* Dagger2 - We are going to use dagger.android which includes /* Dagger2 - We are going to use dagger.android which includes
* support for Activity and fragment injection so we need to include * support for Activity and fragment injection so we need to include
* the following dependencies */ * the following dependencies */
implementation "com.google.dagger:dagger-android:$dagger_version"
implementation "com.google.dagger:dagger-android-support:$dagger_version"
annotationProcessor "com.google.dagger:dagger-compiler:$dagger_version" annotationProcessor "com.google.dagger:dagger-compiler:$dagger_version"
annotationProcessor "com.google.dagger:dagger-android-processor:$dagger_version" annotationProcessor "com.google.dagger:dagger-android-processor:$dagger_version"
kapt "com.google.dagger:dagger-android-processor:$dagger_version" kapt "com.google.dagger:dagger-android-processor:$dagger_version"
@ -354,15 +277,6 @@ dependencies {
kapt "com.google.dagger:dagger-compiler:$dagger_version" kapt "com.google.dagger:dagger-compiler:$dagger_version"
androidTestImplementation 'androidx.test.uiautomator:uiautomator:2.2.0' androidTestImplementation 'androidx.test.uiautomator:uiautomator:2.2.0'
//WorkManager
implementation 'androidx.work:work-runtime:2.3.4'
implementation 'androidx.work:work-runtime-ktx:2.3.4'
implementation 'androidx.work:work-rxjava2:2.3.4'
implementation 'com.google.androidbrowserhelper:androidbrowserhelper:1.1.0'
implementation 'com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava'
} }
/* /*

View file

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="info.nightscout.androidaps"> package="info.nightscout.androidaps">
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /> <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
@ -71,6 +72,10 @@
<activity android:name=".activities.ProfileHelperActivity" <activity android:name=".activities.ProfileHelperActivity"
android:theme="@style/ProfileHelperAppTheme" /> android:theme="@style/ProfileHelperAppTheme" />
<activity android:name=".activities.StatsActivity" /> <activity android:name=".activities.StatsActivity" />
<activity
android:name="com.google.firebase.auth.internal.FederatedSignInActivity"
tools:replace="android:launchMode"
android:launchMode="standard" />
<!-- Receive new BG readings from other local apps --> <!-- Receive new BG readings from other local apps -->
<receiver <receiver

View file

@ -110,7 +110,7 @@ function enable_smb(
return false; return false;
} }
var determine_basal = function determine_basal(glucose_status, currenttemp, iob_data, profile, autosens_data, meal_data, tempBasalFunctions, microBolusAllowed, reservoir_data, currentTime) { var determine_basal = function determine_basal(glucose_status, currenttemp, iob_data, profile, autosens_data, meal_data, tempBasalFunctions, microBolusAllowed, reservoir_data, currentTime, isSaveCgmSource) {
var rT = {}; //short for requestedTemp var rT = {}; //short for requestedTemp
var deliverAt = new Date(); var deliverAt = new Date();
@ -143,7 +143,7 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
rT.reason = "If current system time "+systemTime+" is correct, then BG data is too old. The last BG data was read "+minAgo+"m ago at "+bgTime; rT.reason = "If current system time "+systemTime+" is correct, then BG data is too old. The last BG data was read "+minAgo+"m ago at "+bgTime;
// if BG is too old/noisy, or is changing less than 1 mg/dL/5m for 45m, cancel any high temps and shorten any long zero temps // if BG is too old/noisy, or is changing less than 1 mg/dL/5m for 45m, cancel any high temps and shorten any long zero temps
//cherry pick from oref upstream dev cb8e94990301277fb1016c778b4e9efa55a6edbc //cherry pick from oref upstream dev cb8e94990301277fb1016c778b4e9efa55a6edbc
} else if ( bg > 60 && glucose_status.delta == 0 && glucose_status.short_avgdelta > -1 && glucose_status.short_avgdelta < 1 && glucose_status.long_avgdelta > -1 && glucose_status.long_avgdelta < 1 ) { } else if ( bg > 60 && glucose_status.delta == 0 && glucose_status.short_avgdelta > -1 && glucose_status.short_avgdelta < 1 && glucose_status.long_avgdelta > -1 && glucose_status.long_avgdelta < 1 && !isSaveCgmSource) {
if ( glucose_status.last_cal && glucose_status.last_cal < 3 ) { if ( glucose_status.last_cal && glucose_status.last_cal < 3 ) {
rT.reason = "CGM was just calibrated"; rT.reason = "CGM was just calibrated";
} else { } else {

View file

@ -2,3 +2,5 @@
51:6D:12:67:4C:27:F4:9B:9F:E5:42:9B:01:B3:98:E4:66:2B:85:B7:A8:DD:70:32:B7:6A:D7:97:9A:0D:97:10 51:6D:12:67:4C:27:F4:9B:9F:E5:42:9B:01:B3:98:E4:66:2B:85:B7:A8:DD:70:32:B7:6A:D7:97:9A:0D:97:10
#Leaked #Leaked
55:5D:70:C9:BE:10:41:7E:4B:01:A9:C4:C6:44:4A:F8:69:71:35:25:ED:95:23:16:C7:15:E8:EB:C6:08:FC:B1 55:5D:70:C9:BE:10:41:7E:4B:01:A9:C4:C6:44:4A:F8:69:71:35:25:ED:95:23:16:C7:15:E8:EB:C6:08:FC:B1
E0:71:A3:6E:96:60:5A:FC:B3:77:DB:2F:C4:E0:92:F3:39:A6:27:24:91:F5:7E:BB:55:9B:60:C6:CC:A3:03:41
32:99:61:C4:A0:92:E8:D2:C7:65:04:74:04:17:7E:2D:2A:16:2A:5A:63:48:69:6A:0A:C4:53:3C:7C:78:22:95

View file

@ -27,9 +27,10 @@ import androidx.viewpager2.widget.ViewPager2
import com.google.android.material.tabs.TabLayoutMediator import com.google.android.material.tabs.TabLayoutMediator
import com.joanzapata.iconify.Iconify import com.joanzapata.iconify.Iconify
import com.joanzapata.iconify.fonts.FontAwesomeModule import com.joanzapata.iconify.fonts.FontAwesomeModule
import info.nightscout.androidaps.activities.ProfileHelperActivity import dev.doubledot.doki.ui.DokiActivity
import info.nightscout.androidaps.activities.NoSplashAppCompatActivity import info.nightscout.androidaps.activities.NoSplashAppCompatActivity
import info.nightscout.androidaps.activities.PreferencesActivity import info.nightscout.androidaps.activities.PreferencesActivity
import info.nightscout.androidaps.activities.ProfileHelperActivity
import info.nightscout.androidaps.activities.SingleFragmentActivity import info.nightscout.androidaps.activities.SingleFragmentActivity
import info.nightscout.androidaps.activities.StatsActivity import info.nightscout.androidaps.activities.StatsActivity
import info.nightscout.androidaps.events.EventAppExit import info.nightscout.androidaps.events.EventAppExit
@ -45,6 +46,8 @@ import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
import info.nightscout.androidaps.plugins.constraints.signatureVerifier.SignatureVerifierPlugin import info.nightscout.androidaps.plugins.constraints.signatureVerifier.SignatureVerifierPlugin
import info.nightscout.androidaps.plugins.constraints.versionChecker.VersionCheckerUtils import info.nightscout.androidaps.plugins.constraints.versionChecker.VersionCheckerUtils
import info.nightscout.androidaps.plugins.general.maintenance.ImportExportPrefs
import info.nightscout.androidaps.plugins.general.maintenance.PrefsFileContract
import info.nightscout.androidaps.plugins.general.nsclient.data.NSSettingsStatus import info.nightscout.androidaps.plugins.general.nsclient.data.NSSettingsStatus
import info.nightscout.androidaps.plugins.general.smsCommunicator.SmsCommunicatorPlugin import info.nightscout.androidaps.plugins.general.smsCommunicator.SmsCommunicatorPlugin
import info.nightscout.androidaps.setupwizard.SetupWizardActivity import info.nightscout.androidaps.setupwizard.SetupWizardActivity
@ -68,6 +71,7 @@ import javax.inject.Inject
import kotlin.system.exitProcess import kotlin.system.exitProcess
class MainActivity : NoSplashAppCompatActivity() { class MainActivity : NoSplashAppCompatActivity() {
private val disposable = CompositeDisposable() private val disposable = CompositeDisposable()
@Inject lateinit var aapsLogger: AAPSLogger @Inject lateinit var aapsLogger: AAPSLogger
@ -87,9 +91,17 @@ class MainActivity : NoSplashAppCompatActivity() {
@Inject lateinit var constraintChecker: ConstraintChecker @Inject lateinit var constraintChecker: ConstraintChecker
@Inject lateinit var signatureVerifierPlugin: SignatureVerifierPlugin @Inject lateinit var signatureVerifierPlugin: SignatureVerifierPlugin
@Inject lateinit var config: Config @Inject lateinit var config: Config
@Inject lateinit var importExportPrefs: ImportExportPrefs
private lateinit var actionBarDrawerToggle: ActionBarDrawerToggle private lateinit var actionBarDrawerToggle: ActionBarDrawerToggle
private var pluginPreferencesMenuItem: MenuItem? = null private var pluginPreferencesMenuItem: MenuItem? = null
private var menu: Menu? = null
val callForPrefFile = registerForActivityResult(PrefsFileContract()) {
it?.let {
importExportPrefs.importSharedPreferences(this, it)
}
}
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
@ -111,6 +123,7 @@ class MainActivity : NoSplashAppCompatActivity() {
override fun onPageScrollStateChanged(state: Int) {} override fun onPageScrollStateChanged(state: Int) {}
override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {} override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {}
override fun onPageSelected(position: Int) { override fun onPageSelected(position: Int) {
setPluginPreferenceMenuName()
checkPluginPreferences(main_pager) checkPluginPreferences(main_pager)
} }
}) })
@ -126,16 +139,17 @@ class MainActivity : NoSplashAppCompatActivity() {
if (it.recreate) recreate() if (it.recreate) recreate()
else setupViews() else setupViews()
setWakeLock() setWakeLock()
}) { fabricPrivacy::logException } }, fabricPrivacy::logException)
) )
disposable.add(rxBus disposable.add(rxBus
.toObservable(EventPreferenceChange::class.java) .toObservable(EventPreferenceChange::class.java)
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
.subscribe({ processPreferenceChange(it) }) { fabricPrivacy::logException } .subscribe({ processPreferenceChange(it) }, fabricPrivacy::logException)
) )
if (!sp.getBoolean(R.string.key_setupwizard_processed, false) && !isRunningRealPumpTest()) { if (!sp.getBoolean(R.string.key_setupwizard_processed, false) && !isRunningRealPumpTest()) {
val intent = Intent(this, SetupWizardActivity::class.java) protectionCheck.queryProtection(this, ProtectionCheck.Protection.PREFERENCES, {
startActivity(intent) startActivity(Intent(this, SetupWizardActivity::class.java))
})
} }
androidPermission.notifyForStoragePermission(this) androidPermission.notifyForStoragePermission(this)
androidPermission.notifyForBatteryOptimizationPermission(this) androidPermission.notifyForBatteryOptimizationPermission(this)
@ -163,8 +177,8 @@ class MainActivity : NoSplashAppCompatActivity() {
override fun onResume() { override fun onResume() {
super.onResume() super.onResume()
protectionCheck.queryProtection(this, ProtectionCheck.Protection.APPLICATION, null, protectionCheck.queryProtection(this, ProtectionCheck.Protection.APPLICATION, null,
UIRunnable(Runnable { OKDialog.show(this, "", resourceHelper.gs(R.string.authorizationfailed), Runnable { finish() }) }), UIRunnable { OKDialog.show(this, "", resourceHelper.gs(R.string.authorizationfailed)) { finish() } },
UIRunnable(Runnable { OKDialog.show(this, "", resourceHelper.gs(R.string.authorizationfailed), Runnable { finish() }) }) UIRunnable { OKDialog.show(this, "", resourceHelper.gs(R.string.authorizationfailed)) { finish() } }
) )
} }
@ -183,14 +197,20 @@ class MainActivity : NoSplashAppCompatActivity() {
val pageAdapter = TabPageAdapter(this) val pageAdapter = TabPageAdapter(this)
main_navigation_view.setNavigationItemSelectedListener { true } main_navigation_view.setNavigationItemSelectedListener { true }
val menu = main_navigation_view.menu.also { it.clear() } val menu = main_navigation_view.menu.also { it.clear() }
for (p in activePlugin.pluginsList) { for (p in activePlugin.getPluginsList()) {
pageAdapter.registerNewFragment(p) pageAdapter.registerNewFragment(p)
if (p.isEnabled() && p.hasFragment() && !p.isFragmentVisible() && !p.pluginDescription.neverVisible) { if (p.isEnabled() && p.hasFragment() && !p.isFragmentVisible() && !p.pluginDescription.neverVisible) {
val menuItem = menu.add(p.name) val menuItem = menu.add(p.name)
menuItem.isCheckable = true menuItem.isCheckable = true
if(p.menuIcon != -1) {
menuItem.setIcon(p.menuIcon)
} else
{
menuItem.setIcon(R.drawable.ic_settings)
}
menuItem.setOnMenuItemClickListener { menuItem.setOnMenuItemClickListener {
val intent = Intent(this, SingleFragmentActivity::class.java) val intent = Intent(this, SingleFragmentActivity::class.java)
intent.putExtra("plugin", activePlugin.pluginsList.indexOf(p)) intent.putExtra("plugin", activePlugin.getPluginsList().indexOf(p))
startActivity(intent) startActivity(intent)
main_drawer_layout.closeDrawers() main_drawer_layout.closeDrawers()
true true
@ -228,7 +248,7 @@ class MainActivity : NoSplashAppCompatActivity() {
if (permissions.isNotEmpty()) { if (permissions.isNotEmpty()) {
if (ActivityCompat.checkSelfPermission(this, permissions[0]) == PackageManager.PERMISSION_GRANTED) { if (ActivityCompat.checkSelfPermission(this, permissions[0]) == PackageManager.PERMISSION_GRANTED) {
when (requestCode) { when (requestCode) {
AndroidPermission.CASE_STORAGE -> //show dialog after permission is granted AndroidPermission.CASE_STORAGE -> //show dialog after permission is granted
OKDialog.show(this, "", resourceHelper.gs(R.string.alert_dialog_storage_permission_text)) OKDialog.show(this, "", resourceHelper.gs(R.string.alert_dialog_storage_permission_text))
AndroidPermission.CASE_LOCATION, AndroidPermission.CASE_SMS, AndroidPermission.CASE_BATTERY, AndroidPermission.CASE_PHONE_STATE, AndroidPermission.CASE_SYSTEM_WINDOW -> { AndroidPermission.CASE_LOCATION, AndroidPermission.CASE_SMS, AndroidPermission.CASE_BATTERY, AndroidPermission.CASE_PHONE_STATE, AndroidPermission.CASE_SYSTEM_WINDOW -> {
@ -254,17 +274,24 @@ class MainActivity : NoSplashAppCompatActivity() {
return super.dispatchTouchEvent(event) return super.dispatchTouchEvent(event)
} }
private fun setPluginPreferenceMenuName() {
val plugin = (main_pager.adapter as TabPageAdapter).getPluginAt(main_pager.currentItem)
this.menu?.findItem(R.id.nav_plugin_preferences)?.title = resourceHelper.gs(R.string.nav_preferences_plugin, plugin.name)
}
override fun onCreateOptionsMenu(menu: Menu): Boolean { override fun onCreateOptionsMenu(menu: Menu): Boolean {
this.menu = menu
menuInflater.inflate(R.menu.menu_main, menu) menuInflater.inflate(R.menu.menu_main, menu)
pluginPreferencesMenuItem = menu.findItem(R.id.nav_plugin_preferences) pluginPreferencesMenuItem = menu.findItem(R.id.nav_plugin_preferences)
setPluginPreferenceMenuName()
checkPluginPreferences(main_pager) checkPluginPreferences(main_pager)
return true return true
} }
override fun onOptionsItemSelected(item: MenuItem): Boolean { override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) { when (item.itemId) {
R.id.nav_preferences -> { R.id.nav_preferences -> {
protectionCheck.queryProtection(this, ProtectionCheck.Protection.PREFERENCES, Runnable { protectionCheck.queryProtection(this, ProtectionCheck.Protection.PREFERENCES, {
val i = Intent(this, PreferencesActivity::class.java) val i = Intent(this, PreferencesActivity::class.java)
i.putExtra("id", -1) i.putExtra("id", -1)
startActivity(i) startActivity(i)
@ -272,17 +299,19 @@ class MainActivity : NoSplashAppCompatActivity() {
return true return true
} }
R.id.nav_historybrowser -> { R.id.nav_historybrowser -> {
startActivity(Intent(this, HistoryBrowseActivity::class.java)) startActivity(Intent(this, HistoryBrowseActivity::class.java))
return true return true
} }
R.id.nav_setupwizard -> { R.id.nav_setupwizard -> {
startActivity(Intent(this, SetupWizardActivity::class.java)) protectionCheck.queryProtection(this, ProtectionCheck.Protection.PREFERENCES, {
startActivity(Intent(this, SetupWizardActivity::class.java))
})
return true return true
} }
R.id.nav_about -> { R.id.nav_about -> {
var message = "Build: ${BuildConfig.BUILDVERSION}\n" var message = "Build: ${BuildConfig.BUILDVERSION}\n"
message += "Flavor: ${BuildConfig.FLAVOR}${BuildConfig.BUILD_TYPE}\n" message += "Flavor: ${BuildConfig.FLAVOR}${BuildConfig.BUILD_TYPE}\n"
message += "${resourceHelper.gs(R.string.configbuilder_nightscoutversion_label)} ${nsSettingsStatus.nightscoutVersionName}" message += "${resourceHelper.gs(R.string.configbuilder_nightscoutversion_label)} ${nsSettingsStatus.nightscoutVersionName}"
@ -295,14 +324,15 @@ class MainActivity : NoSplashAppCompatActivity() {
.setIcon(iconsProvider.getIcon()) .setIcon(iconsProvider.getIcon())
.setMessage(messageSpanned) .setMessage(messageSpanned)
.setPositiveButton(resourceHelper.gs(R.string.ok), null) .setPositiveButton(resourceHelper.gs(R.string.ok), null)
.create().also { .setNeutralButton(resourceHelper.gs(R.string.cta_dont_kill_my_app_info)) { _, _ -> DokiActivity.start(context = this@MainActivity) }
it.show() .create().apply {
(it.findViewById<View>(android.R.id.message) as TextView).movementMethod = LinkMovementMethod.getInstance() show()
findViewById<TextView>(android.R.id.message)?.movementMethod = LinkMovementMethod.getInstance()
} }
return true return true
} }
R.id.nav_exit -> { R.id.nav_exit -> {
aapsLogger.debug(LTag.CORE, "Exiting") aapsLogger.debug(LTag.CORE, "Exiting")
rxBus.send(EventAppExit()) rxBus.send(EventAppExit())
finish() finish()
@ -312,7 +342,7 @@ class MainActivity : NoSplashAppCompatActivity() {
R.id.nav_plugin_preferences -> { R.id.nav_plugin_preferences -> {
val plugin = (main_pager.adapter as TabPageAdapter).getPluginAt(main_pager.currentItem) val plugin = (main_pager.adapter as TabPageAdapter).getPluginAt(main_pager.currentItem)
protectionCheck.queryProtection(this, ProtectionCheck.Protection.PREFERENCES, Runnable { protectionCheck.queryProtection(this, ProtectionCheck.Protection.PREFERENCES, {
val i = Intent(this, PreferencesActivity::class.java) val i = Intent(this, PreferencesActivity::class.java)
i.putExtra("id", plugin.preferencesId) i.putExtra("id", plugin.preferencesId)
startActivity(i) startActivity(i)
@ -325,12 +355,12 @@ class MainActivity : NoSplashAppCompatActivity() {
return true return true
} }
*/ */
R.id.nav_defaultprofile -> { R.id.nav_defaultprofile -> {
startActivity(Intent(this, ProfileHelperActivity::class.java)) startActivity(Intent(this, ProfileHelperActivity::class.java))
return true return true
} }
R.id.nav_stats -> { R.id.nav_stats -> {
startActivity(Intent(this, StatsActivity::class.java)) startActivity(Intent(this, StatsActivity::class.java))
return true return true
} }

View file

@ -7,9 +7,6 @@ import android.content.SharedPreferences.OnSharedPreferenceChangeListener
import android.os.Bundle import android.os.Bundle
import androidx.annotation.XmlRes import androidx.annotation.XmlRes
import androidx.preference.* import androidx.preference.*
import dagger.android.AndroidInjector
import dagger.android.DispatchingAndroidInjector
import dagger.android.HasAndroidInjector
import dagger.android.support.AndroidSupportInjection import dagger.android.support.AndroidSupportInjection
import info.nightscout.androidaps.Config import info.nightscout.androidaps.Config
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
@ -58,9 +55,10 @@ import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.sharedPreferences.SP import info.nightscout.androidaps.utils.sharedPreferences.SP
import javax.inject.Inject import javax.inject.Inject
class MyPreferenceFragment : PreferenceFragmentCompat(), OnSharedPreferenceChangeListener, HasAndroidInjector { class MyPreferenceFragment : PreferenceFragmentCompat(), OnSharedPreferenceChangeListener {
private var pluginId = -1 private var pluginId = -1
private var filter = ""
@Inject lateinit var rxBus: RxBusWrapper @Inject lateinit var rxBus: RxBusWrapper
@Inject lateinit var resourceHelper: ResourceHelper @Inject lateinit var resourceHelper: ResourceHelper
@ -102,11 +100,6 @@ class MyPreferenceFragment : PreferenceFragmentCompat(), OnSharedPreferenceChang
@Inject lateinit var nsSettingStatus: NSSettingsStatus @Inject lateinit var nsSettingStatus: NSSettingsStatus
@Inject lateinit var openHumansUploader: OpenHumansUploader @Inject lateinit var openHumansUploader: OpenHumansUploader
// TODO why?
@Inject lateinit var androidInjector: DispatchingAndroidInjector<Any>
override fun androidInjector(): AndroidInjector<Any> = androidInjector
override fun onAttach(context: Context) { override fun onAttach(context: Context) {
AndroidSupportInjection.inject(this) AndroidSupportInjection.inject(this)
super.onAttach(context) super.onAttach(context)
@ -115,11 +108,13 @@ class MyPreferenceFragment : PreferenceFragmentCompat(), OnSharedPreferenceChang
override fun setArguments(args: Bundle?) { override fun setArguments(args: Bundle?) {
super.setArguments(args) super.setArguments(args)
pluginId = args?.getInt("id") ?: -1 pluginId = args?.getInt("id") ?: -1
filter = args?.getString("filter") ?: ""
} }
override fun onSaveInstanceState(outState: Bundle) { override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState) super.onSaveInstanceState(outState)
outState.putInt("id", pluginId) outState.putInt("id", pluginId)
outState.putString("filter", filter)
} }
override fun onDestroy() { override fun onDestroy() {
@ -150,6 +145,9 @@ class MyPreferenceFragment : PreferenceFragmentCompat(), OnSharedPreferenceChang
if (bundle.containsKey("id")) { if (bundle.containsKey("id")) {
pluginId = bundle.getInt("id") pluginId = bundle.getInt("id")
} }
if (bundle.containsKey("filter")) {
filter = bundle.getString("filter") ?: ""
}
} }
if (pluginId != -1) { if (pluginId != -1) {
addPreferencesFromResource(pluginId, rootKey) addPreferencesFromResource(pluginId, rootKey)
@ -175,7 +173,8 @@ class MyPreferenceFragment : PreferenceFragmentCompat(), OnSharedPreferenceChang
addPreferencesFromResourceIfEnabled(localInsightPlugin, rootKey, config.PUMPDRIVERS) addPreferencesFromResourceIfEnabled(localInsightPlugin, rootKey, config.PUMPDRIVERS)
addPreferencesFromResourceIfEnabled(comboPlugin, rootKey, config.PUMPDRIVERS) addPreferencesFromResourceIfEnabled(comboPlugin, rootKey, config.PUMPDRIVERS)
addPreferencesFromResourceIfEnabled(medtronicPumpPlugin, rootKey, config.PUMPDRIVERS) addPreferencesFromResourceIfEnabled(medtronicPumpPlugin, rootKey, config.PUMPDRIVERS)
addPreferencesFromResourceIfEnabled(virtualPumpPlugin, rootKey, !config.NSCLIENT) addPreferencesFromResource(R.xml.pref_pump, rootKey, config.PUMPDRIVERS)
addPreferencesFromResourceIfEnabled(virtualPumpPlugin, rootKey)
addPreferencesFromResourceIfEnabled(insulinOrefFreePeakPlugin, rootKey) addPreferencesFromResourceIfEnabled(insulinOrefFreePeakPlugin, rootKey)
addPreferencesFromResourceIfEnabled(nsClientPlugin, rootKey) addPreferencesFromResourceIfEnabled(nsClientPlugin, rootKey)
addPreferencesFromResourceIfEnabled(tidepoolPlugin, rootKey) addPreferencesFromResourceIfEnabled(tidepoolPlugin, rootKey)
@ -190,6 +189,7 @@ class MyPreferenceFragment : PreferenceFragmentCompat(), OnSharedPreferenceChang
} }
initSummary(preferenceScreen, pluginId != -1) initSummary(preferenceScreen, pluginId != -1)
preprocessPreferences() preprocessPreferences()
if (filter != "") updateFilterVisibility(filter, preferenceScreen)
} }
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String) { override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String) {
@ -251,6 +251,10 @@ class MyPreferenceFragment : PreferenceFragmentCompat(), OnSharedPreferenceChang
} }
} }
private fun addPreferencesFromResource(@Suppress("SameParameterValue") @XmlRes preferencesResId: Int, key: String?, enabled: Boolean) {
if (enabled) addPreferencesFromResource(preferencesResId, key)
}
@SuppressLint("RestrictedApi") @SuppressLint("RestrictedApi")
private fun addPreferencesFromResource(@XmlRes preferencesResId: Int, key: String?) { private fun addPreferencesFromResource(@XmlRes preferencesResId: Int, key: String?) {
val xmlRoot = preferenceManager.inflateFromResource(context, val xmlRoot = preferenceManager.inflateFromResource(context,
@ -283,6 +287,33 @@ class MyPreferenceFragment : PreferenceFragmentCompat(), OnSharedPreferenceChang
} }
} }
private fun updateFilterVisibility(filter: String, p: Preference): Boolean {
var visible = false
if (p is PreferenceGroup) {
for (i in 0 until p.preferenceCount) {
visible = updateFilterVisibility(filter, p.getPreference(i)) || visible
}
if (visible && p is PreferenceCategory) {
p.initialExpandedChildrenCount = Int.MAX_VALUE
}
} else {
if (p.key != null) {
visible = visible || p.key.contains(filter, true)
}
if (p.title != null) {
visible = visible || p.title.contains(filter, true)
}
if (p.summary != null) {
visible = visible || p.summary.contains(filter, true)
}
}
p.isVisible = visible
return visible
}
private fun updatePrefSummary(pref: Preference?) { private fun updatePrefSummary(pref: Preference?) {
if (pref is ListPreference) { if (pref is ListPreference) {
pref.setSummary(pref.entry) pref.setSummary(pref.entry)
@ -386,4 +417,9 @@ class MyPreferenceFragment : PreferenceFragmentCompat(), OnSharedPreferenceChang
} }
return super.onPreferenceTreeClick(preference) return super.onPreferenceTreeClick(preference)
} }
fun setFilter(filter: String) {
this.filter = filter
updateFilterVisibility(filter, preferenceScreen)
}
} }

View file

@ -2,11 +2,14 @@ package info.nightscout.androidaps.activities
import android.content.Context import android.content.Context
import android.os.Bundle import android.os.Bundle
import android.text.Editable
import android.text.TextWatcher
import androidx.preference.PreferenceFragmentCompat import androidx.preference.PreferenceFragmentCompat
import androidx.preference.PreferenceScreen import androidx.preference.PreferenceScreen
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.utils.locale.LocaleHelper import info.nightscout.androidaps.utils.locale.LocaleHelper
import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.resources.ResourceHelper
import kotlinx.android.synthetic.main.activity_preferences.*
import javax.inject.Inject import javax.inject.Inject
class PreferencesActivity : NoSplashAppCompatActivity(), PreferenceFragmentCompat.OnPreferenceStartScreenCallback { class PreferencesActivity : NoSplashAppCompatActivity(), PreferenceFragmentCompat.OnPreferenceStartScreenCallback {
@ -14,18 +17,31 @@ class PreferencesActivity : NoSplashAppCompatActivity(), PreferenceFragmentCompa
@Inject lateinit var resourceHelper: ResourceHelper @Inject lateinit var resourceHelper: ResourceHelper
var preferenceId = 0 var preferenceId = 0
var myPreferenceFragment: MyPreferenceFragment? = null
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setContentView(R.layout.activity_single_fragment) setContentView(R.layout.activity_preferences)
pref_filter.addTextChangedListener(object : TextWatcher {
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {}
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
filterPreferences()
}
override fun afterTextChanged(s: Editable) {}
})
title = resourceHelper.gs(R.string.nav_preferences) title = resourceHelper.gs(R.string.nav_preferences)
supportActionBar?.setDisplayHomeAsUpEnabled(true) supportActionBar?.setDisplayHomeAsUpEnabled(true)
supportActionBar?.setDisplayShowHomeEnabled(true) supportActionBar?.setDisplayShowHomeEnabled(true)
val myPreferenceFragment = MyPreferenceFragment() myPreferenceFragment = MyPreferenceFragment()
preferenceId = intent.getIntExtra("id", -1) preferenceId = intent.getIntExtra("id", -1)
val args = Bundle() val args = Bundle()
args.putInt("id", preferenceId) args.putInt("id", preferenceId)
myPreferenceFragment.arguments = args args.putString("filter", pref_filter.text.toString())
supportFragmentManager.beginTransaction().replace(R.id.frame_layout, myPreferenceFragment).commit() myPreferenceFragment?.arguments = args
supportFragmentManager.beginTransaction().replace(R.id.frame_layout, myPreferenceFragment!!).commit()
} }
override fun onPreferenceStartScreen(caller: PreferenceFragmentCompat, pref: PreferenceScreen): Boolean { override fun onPreferenceStartScreen(caller: PreferenceFragmentCompat, pref: PreferenceScreen): Boolean {
@ -44,4 +60,8 @@ class PreferencesActivity : NoSplashAppCompatActivity(), PreferenceFragmentCompa
override fun attachBaseContext(newBase: Context) { override fun attachBaseContext(newBase: Context) {
super.attachBaseContext(LocaleHelper.wrap(newBase)) super.attachBaseContext(LocaleHelper.wrap(newBase))
} }
private fun filterPreferences() {
myPreferenceFragment?.setFilter(pref_filter.text.toString())
}
} }

View file

@ -9,6 +9,8 @@ import dagger.android.support.DaggerAppCompatActivity
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.interfaces.PluginBase import info.nightscout.androidaps.interfaces.PluginBase
import info.nightscout.androidaps.plugins.configBuilder.PluginStore import info.nightscout.androidaps.plugins.configBuilder.PluginStore
import info.nightscout.androidaps.plugins.general.maintenance.ImportExportPrefs
import info.nightscout.androidaps.plugins.general.maintenance.PrefsFileContract
import info.nightscout.androidaps.utils.locale.LocaleHelper import info.nightscout.androidaps.utils.locale.LocaleHelper
import info.nightscout.androidaps.utils.protection.ProtectionCheck import info.nightscout.androidaps.utils.protection.ProtectionCheck
import javax.inject.Inject import javax.inject.Inject
@ -16,9 +18,16 @@ import javax.inject.Inject
class SingleFragmentActivity : DaggerAppCompatActivity() { class SingleFragmentActivity : DaggerAppCompatActivity() {
@Inject lateinit var pluginStore: PluginStore @Inject lateinit var pluginStore: PluginStore
@Inject lateinit var protectionCheck: ProtectionCheck @Inject lateinit var protectionCheck: ProtectionCheck
@Inject lateinit var importExportPrefs: ImportExportPrefs
private var plugin: PluginBase? = null private var plugin: PluginBase? = null
val callForPrefFile = registerForActivityResult(PrefsFileContract()) {
it?.let {
importExportPrefs.importSharedPreferences(this, it)
}
}
public override fun onCreate(savedInstanceState: Bundle?) { public override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setContentView(R.layout.activity_single_fragment) setContentView(R.layout.activity_single_fragment)

View file

@ -417,6 +417,8 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
try { try {
getDaoBgReadings().update(bgReading); getDaoBgReadings().update(bgReading);
openHumansUploader.enqueueBGReading(bgReading); openHumansUploader.enqueueBGReading(bgReading);
aapsLogger.debug(LTag.DATABASE, "BG: Updating record from: "+ bgReading.toString());
scheduleBgHistoryChange(bgReading.date); // trigger cache invalidation
} catch (SQLException e) { } catch (SQLException e) {
aapsLogger.error("Unhandled exception", e); aapsLogger.error("Unhandled exception", e);
} }

View file

@ -10,7 +10,7 @@ import info.nightscout.androidaps.plugins.general.maintenance.activities.PrefImp
import info.nightscout.androidaps.plugins.general.openhumans.OpenHumansLoginActivity import info.nightscout.androidaps.plugins.general.openhumans.OpenHumansLoginActivity
import info.nightscout.androidaps.plugins.general.overview.activities.QuickWizardListActivity import info.nightscout.androidaps.plugins.general.overview.activities.QuickWizardListActivity
import info.nightscout.androidaps.plugins.general.smsCommunicator.activities.SmsCommunicatorOtpActivity import info.nightscout.androidaps.plugins.general.smsCommunicator.activities.SmsCommunicatorOtpActivity
import info.nightscout.androidaps.plugins.pump.common.dialog.RileyLinkBLEScanActivity import info.nightscout.androidaps.plugins.pump.common.dialog.RileyLinkBLEConfigActivity
import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.dialog.RileyLinkStatusActivity import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.dialog.RileyLinkStatusActivity
import info.nightscout.androidaps.plugins.pump.insight.activities.InsightAlertActivity import info.nightscout.androidaps.plugins.pump.insight.activities.InsightAlertActivity
import info.nightscout.androidaps.plugins.pump.insight.activities.InsightPairingActivity import info.nightscout.androidaps.plugins.pump.insight.activities.InsightPairingActivity
@ -33,7 +33,7 @@ abstract class ActivitiesModule {
@ContributesAndroidInjector abstract fun contributesQuickWizardListActivity(): QuickWizardListActivity @ContributesAndroidInjector abstract fun contributesQuickWizardListActivity(): QuickWizardListActivity
@ContributesAndroidInjector abstract fun contributesRequestDexcomPermissionActivity(): RequestDexcomPermissionActivity @ContributesAndroidInjector abstract fun contributesRequestDexcomPermissionActivity(): RequestDexcomPermissionActivity
@ContributesAndroidInjector abstract fun contributesRileyLinkStatusActivity(): RileyLinkStatusActivity @ContributesAndroidInjector abstract fun contributesRileyLinkStatusActivity(): RileyLinkStatusActivity
@ContributesAndroidInjector abstract fun contributesRileyLinkBLEScanActivity(): RileyLinkBLEScanActivity @ContributesAndroidInjector abstract fun contributesRileyLinkBLEConfigActivity(): RileyLinkBLEConfigActivity
@ContributesAndroidInjector abstract fun contributesSetupWizardActivity(): SetupWizardActivity @ContributesAndroidInjector abstract fun contributesSetupWizardActivity(): SetupWizardActivity
@ContributesAndroidInjector abstract fun contributesSingleFragmentActivity(): SingleFragmentActivity @ContributesAndroidInjector abstract fun contributesSingleFragmentActivity(): SingleFragmentActivity
@ContributesAndroidInjector abstract fun contributesSmsCommunicatorOtpActivity(): SmsCommunicatorOtpActivity @ContributesAndroidInjector abstract fun contributesSmsCommunicatorOtpActivity(): SmsCommunicatorOtpActivity

View file

@ -10,6 +10,7 @@ import info.nightscout.androidaps.dana.di.DanaModule
import info.nightscout.androidaps.danar.di.DanaRModule import info.nightscout.androidaps.danar.di.DanaRModule
import info.nightscout.androidaps.danars.di.DanaRSModule import info.nightscout.androidaps.danars.di.DanaRSModule
import info.nightscout.androidaps.plugins.pump.common.dagger.RileyLinkModule import info.nightscout.androidaps.plugins.pump.common.dagger.RileyLinkModule
import info.nightscout.androidaps.plugins.pump.omnipod.dagger.OmnipodModule
import javax.inject.Singleton import javax.inject.Singleton
@Singleton @Singleton
@ -29,6 +30,7 @@ import javax.inject.Singleton
WizardModule::class, WizardModule::class,
RileyLinkModule::class, RileyLinkModule::class,
MedtronicModule::class, MedtronicModule::class,
OmnipodModule::class,
APSModule::class, APSModule::class,
PreferencesModule::class, PreferencesModule::class,
OverviewModule::class, OverviewModule::class,

View file

@ -39,6 +39,7 @@ abstract class AutomationModule {
@ContributesAndroidInjector abstract fun actionLoopResumeInjector(): ActionLoopResume @ContributesAndroidInjector abstract fun actionLoopResumeInjector(): ActionLoopResume
@ContributesAndroidInjector abstract fun actionLoopSuspendInjector(): ActionLoopSuspend @ContributesAndroidInjector abstract fun actionLoopSuspendInjector(): ActionLoopSuspend
@ContributesAndroidInjector abstract fun actionNotificationInjector(): ActionNotification @ContributesAndroidInjector abstract fun actionNotificationInjector(): ActionNotification
@ContributesAndroidInjector abstract fun actionAlarmInjector(): ActionAlarm
@ContributesAndroidInjector abstract fun actionProfileSwitchInjector(): ActionProfileSwitch @ContributesAndroidInjector abstract fun actionProfileSwitchInjector(): ActionProfileSwitch
@ContributesAndroidInjector abstract fun actionProfileSwitchPercentInjector(): ActionProfileSwitchPercent @ContributesAndroidInjector abstract fun actionProfileSwitchPercentInjector(): ActionProfileSwitchPercent
@ContributesAndroidInjector abstract fun actionSendSMSInjector(): ActionSendSMS @ContributesAndroidInjector abstract fun actionSendSMSInjector(): ActionSendSMS

View file

@ -26,4 +26,5 @@ abstract class CommandQueueModule {
@ContributesAndroidInjector abstract fun commandTempBasalAbsoluteInjector(): CommandTempBasalAbsolute @ContributesAndroidInjector abstract fun commandTempBasalAbsoluteInjector(): CommandTempBasalAbsolute
@ContributesAndroidInjector abstract fun commandTempBasalPercentInjector(): CommandTempBasalPercent @ContributesAndroidInjector abstract fun commandTempBasalPercentInjector(): CommandTempBasalPercent
@ContributesAndroidInjector abstract fun commandSetUserSettingsInjector(): CommandSetUserSettings @ContributesAndroidInjector abstract fun commandSetUserSettingsInjector(): CommandSetUserSettings
@ContributesAndroidInjector abstract fun commandCustomCommandInjector(): CommandCustomCommand
} }

View file

@ -36,6 +36,7 @@ import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.dialog.RileyL
import info.nightscout.androidaps.plugins.pump.insight.LocalInsightFragment import info.nightscout.androidaps.plugins.pump.insight.LocalInsightFragment
import info.nightscout.androidaps.plugins.pump.medtronic.MedtronicFragment import info.nightscout.androidaps.plugins.pump.medtronic.MedtronicFragment
import info.nightscout.androidaps.plugins.pump.medtronic.dialog.RileyLinkStatusDeviceMedtronic import info.nightscout.androidaps.plugins.pump.medtronic.dialog.RileyLinkStatusDeviceMedtronic
import info.nightscout.androidaps.plugins.pump.omnipod.ui.OmnipodOverviewFragment
import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpFragment import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpFragment
import info.nightscout.androidaps.plugins.source.BGSourceFragment import info.nightscout.androidaps.plugins.source.BGSourceFragment
import info.nightscout.androidaps.plugins.treatments.TreatmentsFragment import info.nightscout.androidaps.plugins.treatments.TreatmentsFragment
@ -67,6 +68,7 @@ abstract class FragmentsModule {
@ContributesAndroidInjector abstract fun contributesLoopFragment(): LoopFragment @ContributesAndroidInjector abstract fun contributesLoopFragment(): LoopFragment
@ContributesAndroidInjector abstract fun contributesMaintenanceFragment(): MaintenanceFragment @ContributesAndroidInjector abstract fun contributesMaintenanceFragment(): MaintenanceFragment
@ContributesAndroidInjector abstract fun contributesMedtronicFragment(): MedtronicFragment @ContributesAndroidInjector abstract fun contributesMedtronicFragment(): MedtronicFragment
@ContributesAndroidInjector abstract fun contributesOmnipodFragment(): OmnipodOverviewFragment
@ContributesAndroidInjector abstract fun contributesNSProfileFragment(): NSProfileFragment @ContributesAndroidInjector abstract fun contributesNSProfileFragment(): NSProfileFragment
@ContributesAndroidInjector abstract fun contributesNSClientFragment(): NSClientFragment @ContributesAndroidInjector abstract fun contributesNSClientFragment(): NSClientFragment
@ContributesAndroidInjector @ContributesAndroidInjector
@ -107,6 +109,7 @@ abstract class FragmentsModule {
@ContributesAndroidInjector abstract fun contributesChooseActionDialog(): ChooseActionDialog @ContributesAndroidInjector abstract fun contributesChooseActionDialog(): ChooseActionDialog
@ContributesAndroidInjector abstract fun contributesChooseTriggerDialog(): ChooseTriggerDialog @ContributesAndroidInjector abstract fun contributesChooseTriggerDialog(): ChooseTriggerDialog
@ContributesAndroidInjector abstract fun contributesInsulinDialog(): InsulinDialog @ContributesAndroidInjector abstract fun contributesInsulinDialog(): InsulinDialog
@ContributesAndroidInjector abstract fun contributesLoopDialog(): LoopDialog
@ContributesAndroidInjector abstract fun contributesObjectivesExamDialog(): ObjectivesExamDialog @ContributesAndroidInjector abstract fun contributesObjectivesExamDialog(): ObjectivesExamDialog
@ContributesAndroidInjector abstract fun contributesProfileSwitchDialog(): ProfileSwitchDialog @ContributesAndroidInjector abstract fun contributesProfileSwitchDialog(): ProfileSwitchDialog
@ContributesAndroidInjector abstract fun contributesTempBasalDialog(): TempBasalDialog @ContributesAndroidInjector abstract fun contributesTempBasalDialog(): TempBasalDialog

View file

@ -31,6 +31,7 @@ import info.nightscout.androidaps.plugins.general.persistentNotification.Persist
import info.nightscout.androidaps.plugins.general.smsCommunicator.SmsCommunicatorPlugin import info.nightscout.androidaps.plugins.general.smsCommunicator.SmsCommunicatorPlugin
import info.nightscout.androidaps.plugins.general.wear.WearPlugin import info.nightscout.androidaps.plugins.general.wear.WearPlugin
import info.nightscout.androidaps.plugins.general.xdripStatusline.StatusLinePlugin import info.nightscout.androidaps.plugins.general.xdripStatusline.StatusLinePlugin
import info.nightscout.androidaps.plugins.insulin.InsulinLyumjevPlugin
import info.nightscout.androidaps.plugins.insulin.InsulinOrefFreePeakPlugin import info.nightscout.androidaps.plugins.insulin.InsulinOrefFreePeakPlugin
import info.nightscout.androidaps.plugins.insulin.InsulinOrefRapidActingPlugin import info.nightscout.androidaps.plugins.insulin.InsulinOrefRapidActingPlugin
import info.nightscout.androidaps.plugins.insulin.InsulinOrefUltraRapidActingPlugin import info.nightscout.androidaps.plugins.insulin.InsulinOrefUltraRapidActingPlugin
@ -41,6 +42,7 @@ import info.nightscout.androidaps.plugins.pump.combo.ComboPlugin
import info.nightscout.androidaps.plugins.pump.insight.LocalInsightPlugin import info.nightscout.androidaps.plugins.pump.insight.LocalInsightPlugin
import info.nightscout.androidaps.plugins.pump.mdi.MDIPlugin import info.nightscout.androidaps.plugins.pump.mdi.MDIPlugin
import info.nightscout.androidaps.plugins.pump.medtronic.MedtronicPumpPlugin import info.nightscout.androidaps.plugins.pump.medtronic.MedtronicPumpPlugin
import info.nightscout.androidaps.plugins.pump.omnipod.OmnipodPumpPlugin
import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpPlugin import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpPlugin
import info.nightscout.androidaps.plugins.sensitivity.SensitivityAAPSPlugin import info.nightscout.androidaps.plugins.sensitivity.SensitivityAAPSPlugin
import info.nightscout.androidaps.plugins.sensitivity.SensitivityOref1Plugin import info.nightscout.androidaps.plugins.sensitivity.SensitivityOref1Plugin
@ -82,6 +84,12 @@ abstract class PluginsModule {
@IntKey(40) @IntKey(40)
abstract fun bindInsulinOrefUltraRapidActingPlugin(plugin: InsulinOrefUltraRapidActingPlugin): PluginBase abstract fun bindInsulinOrefUltraRapidActingPlugin(plugin: InsulinOrefUltraRapidActingPlugin): PluginBase
@Binds
@AllConfigs
@IntoMap
@IntKey(42)
abstract fun bindInsulinLyumjevPlugin(plugin: InsulinLyumjevPlugin): PluginBase
@Binds @Binds
@AllConfigs @AllConfigs
@IntoMap @IntoMap
@ -148,6 +156,12 @@ abstract class PluginsModule {
@IntKey(150) @IntKey(150)
abstract fun bindMedtronicPumpPlugin(plugin: MedtronicPumpPlugin): PluginBase abstract fun bindMedtronicPumpPlugin(plugin: MedtronicPumpPlugin): PluginBase
@Binds
@PumpDriver
@IntoMap
@IntKey(155)
abstract fun bindOmnipodPumpPlugin(plugin: OmnipodPumpPlugin): PluginBase
@Binds @Binds
@NotNSClient @NotNSClient
@IntoMap @IntoMap

View file

@ -10,6 +10,7 @@ import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.service.Riley
import info.nightscout.androidaps.plugins.pump.insight.InsightAlertService import info.nightscout.androidaps.plugins.pump.insight.InsightAlertService
import info.nightscout.androidaps.plugins.pump.insight.connection_service.InsightConnectionService import info.nightscout.androidaps.plugins.pump.insight.connection_service.InsightConnectionService
import info.nightscout.androidaps.plugins.pump.medtronic.service.RileyLinkMedtronicService import info.nightscout.androidaps.plugins.pump.medtronic.service.RileyLinkMedtronicService
import info.nightscout.androidaps.plugins.pump.omnipod.rileylink.service.RileyLinkOmnipodService
import info.nightscout.androidaps.services.AlarmSoundService import info.nightscout.androidaps.services.AlarmSoundService
import info.nightscout.androidaps.services.DataService import info.nightscout.androidaps.services.DataService
import info.nightscout.androidaps.services.LocationService import info.nightscout.androidaps.services.LocationService
@ -29,4 +30,5 @@ abstract class ServicesModule {
@ContributesAndroidInjector abstract fun contributesInsightConnectionService(): InsightConnectionService @ContributesAndroidInjector abstract fun contributesInsightConnectionService(): InsightConnectionService
@ContributesAndroidInjector abstract fun contributesRileyLinkService(): RileyLinkService @ContributesAndroidInjector abstract fun contributesRileyLinkService(): RileyLinkService
@ContributesAndroidInjector abstract fun contributesRileyLinkMedtronicService(): RileyLinkMedtronicService @ContributesAndroidInjector abstract fun contributesRileyLinkMedtronicService(): RileyLinkMedtronicService
@ContributesAndroidInjector abstract fun contributesRileyLinkOmnipodService(): RileyLinkOmnipodService
} }

View file

@ -9,6 +9,7 @@ import info.nightscout.androidaps.skins.SkinButtonsOn
import info.nightscout.androidaps.skins.SkinClassic import info.nightscout.androidaps.skins.SkinClassic
import info.nightscout.androidaps.skins.SkinInterface import info.nightscout.androidaps.skins.SkinInterface
import info.nightscout.androidaps.skins.SkinLargeDisplay import info.nightscout.androidaps.skins.SkinLargeDisplay
import info.nightscout.androidaps.skins.SkinLowRes
import javax.inject.Qualifier import javax.inject.Qualifier
@Module @Module
@ -32,6 +33,12 @@ open class SkinsModule {
@IntKey(20) @IntKey(20)
fun bindsSkinLargeDisplay(skinLargeDisplay: SkinLargeDisplay): SkinInterface = skinLargeDisplay fun bindsSkinLargeDisplay(skinLargeDisplay: SkinLargeDisplay): SkinInterface = skinLargeDisplay
@Provides
@Skin
@IntoMap
@IntKey(30)
fun bindsSkinLowRes(skinLowRes: SkinLowRes): SkinInterface = skinLowRes
@Qualifier @Qualifier
annotation class Skin annotation class Skin
} }

View file

@ -58,7 +58,7 @@ class CalibrationDialog : DialogFragmentWithDate() {
val units = profileFunction.getUnits() val units = profileFunction.getUnits()
val unitLabel = if (units == Constants.MMOL) resourceHelper.gs(R.string.mmol) else resourceHelper.gs(R.string.mgdl) val unitLabel = if (units == Constants.MMOL) resourceHelper.gs(R.string.mmol) else resourceHelper.gs(R.string.mgdl)
val actions: LinkedList<String?> = LinkedList() val actions: LinkedList<String?> = LinkedList()
val bg = overview_calibration_bg.value val bg = overview_calibration_bg?.value ?: return false
actions.add(resourceHelper.gs(R.string.treatments_wizard_bg_label) + ": " + Profile.toCurrentUnitsString(profileFunction, bg) + " " + unitLabel) actions.add(resourceHelper.gs(R.string.treatments_wizard_bg_label) + ": " + Profile.toCurrentUnitsString(profileFunction, bg) + " " + unitLabel)
if (bg > 0) { if (bg > 0) {
activity?.let { activity -> activity?.let { activity ->

View file

@ -150,7 +150,7 @@ class CarbsDialog : DialogFragmentWithDate() {
} }
override fun submit(): Boolean { override fun submit(): Boolean {
val carbs = overview_carbs_carbs.value.toInt() val carbs = overview_carbs_carbs?.value?.toInt() ?: return false
val carbsAfterConstraints = constraintChecker.applyCarbsConstraints(Constraint(carbs)).value() val carbsAfterConstraints = constraintChecker.applyCarbsConstraints(Constraint(carbs)).value()
val units = profileFunction.getUnits() val units = profileFunction.getUnits()
val activityTTDuration = defaultValueHelper.determineActivityTTDuration() val activityTTDuration = defaultValueHelper.determineActivityTTDuration()

View file

@ -122,7 +122,7 @@ class CareDialog : DialogFragmentWithDate() {
} }
} }
val bg = Profile.fromMgdlToUnits(GlucoseStatus(injector).getGlucoseStatusData()?.glucose val bg = Profile.fromMgdlToUnits(GlucoseStatus(injector).glucoseStatusData?.glucose
?: 0.0, profileFunction.getUnits()) ?: 0.0, profileFunction.getUnits())
val bgTextWatcher: TextWatcher = object : TextWatcher { val bgTextWatcher: TextWatcher = object : TextWatcher {
override fun afterTextChanged(s: Editable) {} override fun afterTextChanged(s: Editable) {}

View file

@ -1,12 +1,12 @@
package info.nightscout.androidaps.dialogs package info.nightscout.androidaps.dialogs
import android.content.Context
import android.content.Intent import android.content.Intent
import android.os.Bundle import android.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import com.google.common.base.Joiner import com.google.common.base.Joiner
import info.nightscout.androidaps.MainApp
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.activities.ErrorHelperActivity import info.nightscout.androidaps.activities.ErrorHelperActivity
import info.nightscout.androidaps.interfaces.ActivePluginProvider import info.nightscout.androidaps.interfaces.ActivePluginProvider
@ -15,8 +15,8 @@ import info.nightscout.androidaps.interfaces.Constraint
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
import info.nightscout.androidaps.queue.Callback import info.nightscout.androidaps.queue.Callback
import info.nightscout.androidaps.utils.HtmlHelper import info.nightscout.androidaps.utils.HtmlHelper
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
import info.nightscout.androidaps.utils.SafeParse import info.nightscout.androidaps.utils.SafeParse
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
import info.nightscout.androidaps.utils.extensions.formatColor import info.nightscout.androidaps.utils.extensions.formatColor
import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.resources.ResourceHelper
import kotlinx.android.synthetic.main.dialog_extendedbolus.* import kotlinx.android.synthetic.main.dialog_extendedbolus.*
@ -27,7 +27,8 @@ import javax.inject.Inject
import kotlin.math.abs import kotlin.math.abs
class ExtendedBolusDialog : DialogFragmentWithDate() { class ExtendedBolusDialog : DialogFragmentWithDate() {
@Inject lateinit var mainApp: MainApp
@Inject lateinit var ctx: Context
@Inject lateinit var resourceHelper: ResourceHelper @Inject lateinit var resourceHelper: ResourceHelper
@Inject lateinit var constraintChecker: ConstraintChecker @Inject lateinit var constraintChecker: ConstraintChecker
@Inject lateinit var commandQueue: CommandQueueProvider @Inject lateinit var commandQueue: CommandQueueProvider
@ -62,7 +63,7 @@ class ExtendedBolusDialog : DialogFragmentWithDate() {
} }
override fun submit(): Boolean { override fun submit(): Boolean {
val insulin = SafeParse.stringToDouble(actions_extendedbolus_insulin.text) val insulin = SafeParse.stringToDouble(actions_extendedbolus_insulin?.text ?: return false)
val durationInMinutes = actions_extendedbolus_duration.value.toInt() val durationInMinutes = actions_extendedbolus_duration.value.toInt()
val actions: LinkedList<String> = LinkedList() val actions: LinkedList<String> = LinkedList()
val insulinAfterConstraint = constraintChecker.applyExtendedBolusConstraints(Constraint(insulin)).value() val insulinAfterConstraint = constraintChecker.applyExtendedBolusConstraints(Constraint(insulin)).value()
@ -77,12 +78,12 @@ class ExtendedBolusDialog : DialogFragmentWithDate() {
commandQueue.extendedBolus(insulinAfterConstraint, durationInMinutes, object : Callback() { commandQueue.extendedBolus(insulinAfterConstraint, durationInMinutes, object : Callback() {
override fun run() { override fun run() {
if (!result.success) { if (!result.success) {
val i = Intent(mainApp, ErrorHelperActivity::class.java) val i = Intent(ctx, ErrorHelperActivity::class.java)
i.putExtra("soundid", R.raw.boluserror) i.putExtra("soundid", R.raw.boluserror)
i.putExtra("status", result.comment) i.putExtra("status", result.comment)
i.putExtra("title", resourceHelper.gs(R.string.treatmentdeliveryerror)) i.putExtra("title", resourceHelper.gs(R.string.treatmentdeliveryerror))
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
mainApp.startActivity(i) ctx.startActivity(i)
} }
} }
}) })

View file

@ -85,7 +85,7 @@ class FillDialog : DialogFragmentWithDate() {
} }
override fun submit(): Boolean { override fun submit(): Boolean {
val insulin = SafeParse.stringToDouble(fill_insulinamount.text) val insulin = SafeParse.stringToDouble(fill_insulinamount?.text ?: return false)
val actions: LinkedList<String?> = LinkedList() val actions: LinkedList<String?> = LinkedList()
val insulinAfterConstraints = constraintChecker.applyBolusConstraints(Constraint(insulin)).value() val insulinAfterConstraints = constraintChecker.applyBolusConstraints(Constraint(insulin)).value()

View file

@ -129,7 +129,7 @@ class InsulinDialog : DialogFragmentWithDate() {
override fun submit(): Boolean { override fun submit(): Boolean {
val pumpDescription = activePlugin.activePump.pumpDescription val pumpDescription = activePlugin.activePump.pumpDescription
val insulin = SafeParse.stringToDouble(overview_insulin_amount.text) val insulin = SafeParse.stringToDouble(overview_insulin_amount?.text ?: return false)
val insulinAfterConstraints = constraintChecker.applyBolusConstraints(Constraint(insulin)).value() val insulinAfterConstraints = constraintChecker.applyBolusConstraints(Constraint(insulin)).value()
val actions: LinkedList<String?> = LinkedList() val actions: LinkedList<String?> = LinkedList()
val units = profileFunction.getUnits() val units = profileFunction.getUnits()

View file

@ -0,0 +1,382 @@
package info.nightscout.androidaps.dialogs
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.os.Handler
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.Window
import android.view.WindowManager
import androidx.fragment.app.FragmentManager
import dagger.android.support.DaggerDialogFragment
import info.nightscout.androidaps.R
import info.nightscout.androidaps.activities.ErrorHelperActivity
import info.nightscout.androidaps.databinding.DialogLoopBinding
import info.nightscout.androidaps.events.*
import info.nightscout.androidaps.interfaces.*
import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
import info.nightscout.androidaps.plugins.constraints.objectives.ObjectivesPlugin
import info.nightscout.androidaps.queue.Callback
import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.ToastUtils
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
import info.nightscout.androidaps.utils.extensions.toVisibility
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.sharedPreferences.SP
import javax.inject.Inject
class LoopDialog : DaggerDialogFragment() {
@Inject lateinit var aapsLogger: AAPSLogger
@Inject lateinit var ctx: Context
@Inject lateinit var sp: SP
@Inject lateinit var rxBus: RxBusWrapper
@Inject lateinit var fabricPrivacy: FabricPrivacy
@Inject lateinit var resourceHelper: ResourceHelper
@Inject lateinit var profileFunction: ProfileFunction
@Inject lateinit var loopPlugin: LoopPlugin
@Inject lateinit var objectivesPlugin: ObjectivesPlugin
@Inject lateinit var activePlugin: ActivePluginProvider
@Inject lateinit var constraintChecker: ConstraintChecker
@Inject lateinit var commandQueue: CommandQueueProvider
@Inject lateinit var configBuilderPlugin: ConfigBuilderPlugin
private var showOkCancel: Boolean = true
private var _binding: DialogLoopBinding? = null
private var loopHandler = Handler()
private var refreshDialog: Runnable? = null
// This property is only valid between onCreateView and
// onDestroyView.
private val binding get() = _binding!!
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.putInt("showOkCancel", if (showOkCancel) 1 else 0)
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View {
// load data from bundle
(savedInstanceState ?: arguments)?.let { bundle ->
showOkCancel = bundle.getInt("showOkCancel", 1) == 1
}
dialog?.window?.requestFeature(Window.FEATURE_NO_TITLE)
dialog?.window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN)
isCancelable = true
dialog?.setCanceledOnTouchOutside(false)
_binding = DialogLoopBinding.inflate(inflater, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
updateGUI("LoopDialogOnViewCreated")
binding.overviewCloseloop.setOnClickListener { if (showOkCancel) onClickOkCancelEnabled(it) else onClick(it); dismiss() }
binding.overviewLgsloop.setOnClickListener { if (showOkCancel) onClickOkCancelEnabled(it) else onClick(it); dismiss() }
binding.overviewOpenloop.setOnClickListener { if (showOkCancel) onClickOkCancelEnabled(it) else onClick(it); dismiss() }
binding.overviewDisable.setOnClickListener { if (showOkCancel) onClickOkCancelEnabled(it) else onClick(it); dismiss() }
binding.overviewEnable.setOnClickListener { if (showOkCancel) onClickOkCancelEnabled(it) else onClick(it); dismiss() }
binding.overviewResume.setOnClickListener { if (showOkCancel) onClickOkCancelEnabled(it) else onClick(it); dismiss() }
binding.overviewReconnect.setOnClickListener { if (showOkCancel) onClickOkCancelEnabled(it) else onClick(it); dismiss() }
binding.overviewSuspend1h.setOnClickListener { if (showOkCancel) onClickOkCancelEnabled(it) else onClick(it); dismiss() }
binding.overviewSuspend2h.setOnClickListener { if (showOkCancel) onClickOkCancelEnabled(it) else onClick(it); dismiss() }
binding.overviewSuspend3h.setOnClickListener { if (showOkCancel) onClickOkCancelEnabled(it) else onClick(it); dismiss() }
binding.overviewSuspend10h.setOnClickListener { if (showOkCancel) onClickOkCancelEnabled(it) else onClick(it); dismiss() }
binding.overviewDisconnect15m.setOnClickListener { if (showOkCancel) onClickOkCancelEnabled(it) else onClick(it); dismiss() }
binding.overviewDisconnect30m.setOnClickListener { if (showOkCancel) onClickOkCancelEnabled(it) else onClick(it); dismiss() }
binding.overviewDisconnect1h.setOnClickListener { if (showOkCancel) onClickOkCancelEnabled(it) else onClick(it); dismiss() }
binding.overviewDisconnect2h.setOnClickListener { if (showOkCancel) onClickOkCancelEnabled(it) else onClick(it); dismiss() }
binding.overviewDisconnect3h.setOnClickListener { if (showOkCancel) onClickOkCancelEnabled(it) else onClick(it); dismiss() }
// cancel button
binding.cancel.setOnClickListener { dismiss() }
refreshDialog = Runnable {
scheduleUpdateGUI("refreshDialog")
loopHandler.postDelayed(refreshDialog, 15 * 1000L)
}
loopHandler.postDelayed(refreshDialog, 15 * 1000L)
}
@Synchronized
override fun onDestroyView() {
super.onDestroyView()
_binding = null
loopHandler.removeCallbacksAndMessages(null)
}
var task: Runnable? = null
private fun scheduleUpdateGUI(from: String) {
class UpdateRunnable : Runnable {
override fun run() {
updateGUI(from)
task = null
}
}
view?.removeCallbacks(task)
task = UpdateRunnable()
view?.postDelayed(task, 500)
}
@Synchronized
fun updateGUI(from: String) {
if (_binding == null) return
aapsLogger.debug("UpdateGUI from $from")
val pumpDescription: PumpDescription = activePlugin.activePump.pumpDescription
val closedLoopAllowed = objectivesPlugin.isClosedLoopAllowed(Constraint(true))
val lgsEnabled = objectivesPlugin.isLgsAllowed(Constraint(true))
val apsMode = sp.getString(R.string.key_aps_mode, "open")
if (profileFunction.isProfileValid("LoopDialogUpdateGUI")) {
if (loopPlugin.isEnabled(PluginType.LOOP)) {
when {
closedLoopAllowed.value() -> {
binding.overviewCloseloop.visibility = (apsMode != "closed").toVisibility()
binding.overviewLgsloop.visibility = (apsMode != "lgs").toVisibility()
binding.overviewOpenloop.visibility = (apsMode != "open").toVisibility()
}
lgsEnabled.value() -> {
binding.overviewCloseloop.visibility = View.GONE
binding.overviewLgsloop.visibility = (apsMode != "lgs").toVisibility()
binding.overviewOpenloop.visibility = (apsMode != "open").toVisibility()
}
else -> {
binding.overviewCloseloop.visibility = View.GONE
binding.overviewLgsloop.visibility = View.GONE
binding.overviewOpenloop.visibility = View.GONE
}
}
binding.overviewEnable.visibility = View.GONE
binding.overviewDisable.visibility = View.VISIBLE
if (!loopPlugin.isSuspended) {
binding.overviewSuspendHeader.text = resourceHelper.gs(R.string.suspendloop)
binding.overviewResume.visibility = View.GONE
binding.overviewSuspendButtons.visibility = View.VISIBLE
binding.overviewSuspend.visibility = View.VISIBLE
} else {
if (!loopPlugin.isDisconnected) {
binding.overviewSuspendHeader.text = resourceHelper.gs(R.string.resumeloop)
binding.overviewResume.visibility = View.VISIBLE
binding.overviewSuspendButtons.visibility = View.GONE
binding.overviewSuspend.visibility = View.VISIBLE
} else
binding.overviewSuspend.visibility = View.GONE
}
} else {
binding.overviewEnable.visibility = View.VISIBLE
binding.overviewDisable.visibility = View.GONE
binding.overviewSuspend.visibility = View.GONE
}
if (!loopPlugin.isDisconnected) {
binding.overviewPumpHeader.text = resourceHelper.gs(R.string.disconnectpump)
binding.overviewDisconnect15m.visibility = pumpDescription.tempDurationStep15mAllowed.toVisibility()
binding.overviewDisconnect30m.visibility = pumpDescription.tempDurationStep30mAllowed.toVisibility()
binding.overviewDisconnectButtons.visibility = View.VISIBLE
binding.overviewReconnect.visibility = View.GONE
} else {
binding.overviewPumpHeader.text = resourceHelper.gs(R.string.reconnect)
binding.overviewDisconnectButtons.visibility = View.GONE
binding.overviewReconnect.visibility = View.VISIBLE
}
}
val profile = profileFunction.getProfile()
val profileStore = activePlugin.activeProfileInterface.profile
if (profile == null || profileStore == null) {
ToastUtils.showToastInUiThread(ctx, resourceHelper.gs(R.string.noprofile))
dismiss()
return
}
}
private fun onClickOkCancelEnabled(v: View): Boolean {
var description = ""
when (v.id) {
R.id.overview_closeloop -> description = resourceHelper.gs(R.string.closedloop)
R.id.overview_lgsloop -> description = resourceHelper.gs(R.string.lowglucosesuspend)
R.id.overview_openloop -> description = resourceHelper.gs(R.string.openloop)
R.id.overview_disable -> description = resourceHelper.gs(R.string.disableloop)
R.id.overview_enable -> description = resourceHelper.gs(R.string.enableloop)
R.id.overview_resume -> description = resourceHelper.gs(R.string.resume)
R.id.overview_reconnect -> description = resourceHelper.gs(R.string.reconnect)
R.id.overview_suspend_1h -> description = resourceHelper.gs(R.string.suspendloopfor1h)
R.id.overview_suspend_2h -> description = resourceHelper.gs(R.string.suspendloopfor2h)
R.id.overview_suspend_3h -> description = resourceHelper.gs(R.string.suspendloopfor3h)
R.id.overview_suspend_10h -> description = resourceHelper.gs(R.string.suspendloopfor10h)
R.id.overview_disconnect_15m -> description = resourceHelper.gs(R.string.disconnectpumpfor15m)
R.id.overview_disconnect_30m -> description = resourceHelper.gs(R.string.disconnectpumpfor30m)
R.id.overview_disconnect_1h -> description = resourceHelper.gs(R.string.disconnectpumpfor1h)
R.id.overview_disconnect_2h -> description = resourceHelper.gs(R.string.disconnectpumpfor2h)
R.id.overview_disconnect_3h -> description = resourceHelper.gs(R.string.disconnectpumpfor3h)
}
activity?.let { activity ->
OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.confirm), description, Runnable {
onClick(v)
})
}
return true
}
fun onClick(v: View): Boolean {
val profile = profileFunction.getProfile() ?: return true
when (v.id) {
R.id.overview_closeloop -> {
sp.putString(R.string.key_aps_mode, "closed")
rxBus.send(EventPreferenceChange(resourceHelper.gs(R.string.closedloop)))
return true
}
R.id.overview_lgsloop -> {
sp.putString(R.string.key_aps_mode, "lgs")
rxBus.send(EventPreferenceChange(resourceHelper.gs(R.string.lowglucosesuspend)))
return true
}
R.id.overview_openloop -> {
sp.putString(R.string.key_aps_mode, "open")
rxBus.send(EventPreferenceChange(resourceHelper.gs(R.string.lowglucosesuspend)))
return true
}
R.id.overview_disable -> {
aapsLogger.debug("USER ENTRY: LOOP DISABLED")
loopPlugin.setPluginEnabled(PluginType.LOOP, false)
loopPlugin.setFragmentVisible(PluginType.LOOP, false)
configBuilderPlugin.storeSettings("DisablingLoop")
rxBus.send(EventRefreshOverview("suspendmenu"))
commandQueue.cancelTempBasal(true, object : Callback() {
override fun run() {
if (!result.success) {
ToastUtils.showToastInUiThread(ctx, resourceHelper.gs(R.string.tempbasaldeliveryerror))
}
}
})
loopPlugin.createOfflineEvent(24 * 60) // upload 24h, we don't know real duration
return true
}
R.id.overview_enable -> {
aapsLogger.debug("USER ENTRY: LOOP ENABLED")
loopPlugin.setPluginEnabled(PluginType.LOOP, true)
loopPlugin.setFragmentVisible(PluginType.LOOP, true)
configBuilderPlugin.storeSettings("EnablingLoop")
rxBus.send(EventRefreshOverview("suspendmenu"))
loopPlugin.createOfflineEvent(0)
return true
}
R.id.overview_resume, R.id.overview_reconnect -> {
aapsLogger.debug("USER ENTRY: RESUME")
loopPlugin.suspendTo(0L)
rxBus.send(EventRefreshOverview("suspendmenu"))
commandQueue.cancelTempBasal(true, object : Callback() {
override fun run() {
if (!result.success) {
val i = Intent(ctx, ErrorHelperActivity::class.java)
i.putExtra("soundid", R.raw.boluserror)
i.putExtra("status", result.comment)
i.putExtra("title", resourceHelper.gs(R.string.tempbasaldeliveryerror))
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
ctx.startActivity(i)
}
}
})
sp.putBoolean(R.string.key_objectiveusereconnect, true)
loopPlugin.createOfflineEvent(0)
return true
}
R.id.overview_suspend_1h -> {
aapsLogger.debug("USER ENTRY: SUSPEND 1h")
loopPlugin.suspendLoop(60)
rxBus.send(EventRefreshOverview("suspendmenu"))
return true
}
R.id.overview_suspend_2h -> {
aapsLogger.debug("USER ENTRY: SUSPEND 2h")
loopPlugin.suspendLoop(120)
rxBus.send(EventRefreshOverview("suspendmenu"))
return true
}
R.id.overview_suspend_3h -> {
aapsLogger.debug("USER ENTRY: SUSPEND 3h")
loopPlugin.suspendLoop(180)
rxBus.send(EventRefreshOverview("suspendmenu"))
return true
}
R.id.overview_suspend_10h -> {
aapsLogger.debug("USER ENTRY: SUSPEND 10h")
loopPlugin.suspendLoop(600)
rxBus.send(EventRefreshOverview("suspendmenu"))
return true
}
R.id.overview_disconnect_15m -> {
aapsLogger.debug("USER ENTRY: DISCONNECT 15m")
loopPlugin.disconnectPump(15, profile)
rxBus.send(EventRefreshOverview("suspendmenu"))
return true
}
R.id.overview_disconnect_30m -> {
aapsLogger.debug("USER ENTRY: DISCONNECT 30m")
loopPlugin.disconnectPump(30, profile)
rxBus.send(EventRefreshOverview("suspendmenu"))
return true
}
R.id.overview_disconnect_1h -> {
aapsLogger.debug("USER ENTRY: DISCONNECT 1h")
loopPlugin.disconnectPump(60, profile)
sp.putBoolean(R.string.key_objectiveusedisconnect, true)
rxBus.send(EventRefreshOverview("suspendmenu"))
return true
}
R.id.overview_disconnect_2h -> {
aapsLogger.debug("USER ENTRY: DISCONNECT 2h")
loopPlugin.disconnectPump(120, profile)
rxBus.send(EventRefreshOverview("suspendmenu"))
return true
}
R.id.overview_disconnect_3h -> {
aapsLogger.debug("USER ENTRY: DISCONNECT 3h")
loopPlugin.disconnectPump(180, profile)
rxBus.send(EventRefreshOverview("suspendmenu"))
return true
}
}
return false
}
override fun show(manager: FragmentManager, tag: String?) {
try {
manager.beginTransaction().let {
it.add(this, tag)
it.commitAllowingStateLoss()
}
} catch (e: IllegalStateException) {
aapsLogger.debug(e.localizedMessage)
}
}
}

View file

@ -52,7 +52,7 @@ class ProfileSwitchDialog : DialogFragmentWithDate() {
overview_profileswitch_duration.setParams(savedInstanceState?.getDouble("overview_profileswitch_duration") overview_profileswitch_duration.setParams(savedInstanceState?.getDouble("overview_profileswitch_duration")
?: 0.0, 0.0, Constants.MAX_PROFILE_SWITCH_DURATION, 10.0, DecimalFormat("0"), false, ok) ?: 0.0, 0.0, Constants.MAX_PROFILE_SWITCH_DURATION, 10.0, DecimalFormat("0"), false, ok)
overview_profileswitch_percentage.setParams(savedInstanceState?.getDouble("overview_profileswitch_percentage") 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) ?: 100.0, Constants.CPP_MIN_PERCENTAGE.toDouble(), Constants.CPP_MAX_PERCENTAGE.toDouble(), 5.0, DecimalFormat("0"), false, ok)
overview_profileswitch_timeshift.setParams(savedInstanceState?.getDouble("overview_profileswitch_timeshift") 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) ?: 0.0, Constants.CPP_MIN_TIMESHIFT.toDouble(), Constants.CPP_MAX_TIMESHIFT.toDouble(), 1.0, DecimalFormat("0"), false, ok)
@ -91,7 +91,7 @@ class ProfileSwitchDialog : DialogFragmentWithDate() {
?: return false ?: return false
val actions: LinkedList<String> = LinkedList() val actions: LinkedList<String> = LinkedList()
val duration = overview_profileswitch_duration.value.toInt() val duration = overview_profileswitch_duration?.value?.toInt() ?: return false
if (duration > 0) if (duration > 0)
actions.add(resourceHelper.gs(R.string.duration) + ": " + resourceHelper.gs(R.string.format_mins, duration)) actions.add(resourceHelper.gs(R.string.duration) + ": " + resourceHelper.gs(R.string.format_mins, duration))
val profile = overview_profileswitch_profile.selectedItem.toString() val profile = overview_profileswitch_profile.selectedItem.toString()

View file

@ -84,7 +84,7 @@ class TempBasalDialog : DialogFragmentWithDate() {
override fun submit(): Boolean { override fun submit(): Boolean {
var percent = 0 var percent = 0
var absolute = 0.0 var absolute = 0.0
val durationInMinutes = actions_tempbasal_duration.value.toInt() val durationInMinutes = actions_tempbasal_duration?.value?.toInt() ?: return false
val profile = profileFunction.getProfile() ?: return false val profile = profileFunction.getProfile() ?: return false
val actions: LinkedList<String> = LinkedList() val actions: LinkedList<String> = LinkedList()
if (isPercentPump) { if (isPercentPump) {

View file

@ -13,6 +13,7 @@ import info.nightscout.androidaps.R
import info.nightscout.androidaps.data.Profile import info.nightscout.androidaps.data.Profile
import info.nightscout.androidaps.db.Source import info.nightscout.androidaps.db.Source
import info.nightscout.androidaps.db.TempTarget import info.nightscout.androidaps.db.TempTarget
import info.nightscout.androidaps.interfaces.ActivePluginProvider
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
import info.nightscout.androidaps.interfaces.ProfileFunction import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin
@ -32,6 +33,9 @@ class TempTargetDialog : DialogFragmentWithDate() {
@Inject lateinit var profileFunction: ProfileFunction @Inject lateinit var profileFunction: ProfileFunction
@Inject lateinit var defaultValueHelper: DefaultValueHelper @Inject lateinit var defaultValueHelper: DefaultValueHelper
@Inject lateinit var treatmentsPlugin: TreatmentsPlugin @Inject lateinit var treatmentsPlugin: TreatmentsPlugin
@Inject lateinit var activePlugin: ActivePluginProvider
lateinit var reasonList: List<String>
override fun onSaveInstanceState(savedInstanceState: Bundle) { override fun onSaveInstanceState(savedInstanceState: Bundle) {
super.onSaveInstanceState(savedInstanceState) super.onSaveInstanceState(savedInstanceState)
@ -64,59 +68,71 @@ class TempTargetDialog : DialogFragmentWithDate() {
val units = profileFunction.getUnits() val units = profileFunction.getUnits()
overview_temptarget_units.text = if (units == Constants.MMOL) resourceHelper.gs(R.string.mmol) else resourceHelper.gs(R.string.mgdl) overview_temptarget_units.text = if (units == Constants.MMOL) resourceHelper.gs(R.string.mmol) else resourceHelper.gs(R.string.mgdl)
// temp target // temp target
context?.let { context -> context?.let { context ->
val reasonList: List<String> = Lists.newArrayList( if (activePlugin.activeTreatments.tempTargetFromHistory != null)
overview_temptarget_cancel?.visibility = View.VISIBLE
else
overview_temptarget_cancel?.visibility = View.GONE
reasonList = Lists.newArrayList(
resourceHelper.gs(R.string.manual), resourceHelper.gs(R.string.manual),
resourceHelper.gs(R.string.cancel),
resourceHelper.gs(R.string.eatingsoon), resourceHelper.gs(R.string.eatingsoon),
resourceHelper.gs(R.string.activity), resourceHelper.gs(R.string.activity),
resourceHelper.gs(R.string.hypo) resourceHelper.gs(R.string.hypo)
) )
val adapterReason = ArrayAdapter(context, R.layout.spinner_centered, reasonList) val adapterReason = ArrayAdapter(context, R.layout.spinner_centered, reasonList)
overview_temptarget_reason.adapter = adapterReason 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]) {
resourceHelper.gs(R.string.eatingsoon) -> {
defaultDuration = defaultValueHelper.determineEatingSoonTTDuration().toDouble()
defaultTarget = defaultValueHelper.determineEatingSoonTT()
}
resourceHelper.gs(R.string.activity) -> { overview_temptarget_cancel?.setOnClickListener { shortClick(it) }
defaultDuration = defaultValueHelper.determineActivityTTDuration().toDouble() overview_temptarget_eating_soon?.setOnClickListener { shortClick(it) }
defaultTarget = defaultValueHelper.determineActivityTT() overview_temptarget_activity?.setOnClickListener { shortClick(it) }
} overview_temptarget_hypo?.setOnClickListener { shortClick(it) }
resourceHelper.gs(R.string.hypo) -> { overview_temptarget_eating_soon?.setOnLongClickListener {
defaultDuration = defaultValueHelper.determineHypoTTDuration().toDouble() longClick(it)
defaultTarget = defaultValueHelper.determineHypoTT() return@setOnLongClickListener true
} }
overview_temptarget_activity?.setOnLongClickListener {
longClick(it)
return@setOnLongClickListener true
}
overview_temptarget_hypo?.setOnLongClickListener {
longClick(it)
return@setOnLongClickListener true
}
}
}
resourceHelper.gs(R.string.cancel) -> { private fun shortClick(v:View){
defaultDuration = 0.0 v.performLongClick()
defaultTarget = 0.0 if (submit()) dismiss()
} }
else -> { private fun longClick(v:View) {
defaultDuration = overview_temptarget_duration.value when (v.id) {
defaultTarget = overview_temptarget_temptarget.value R.id.overview_temptarget_eating_soon -> {
} overview_temptarget_temptarget.value = defaultValueHelper.determineEatingSoonTT()
} overview_temptarget_duration.value = defaultValueHelper.determineEatingSoonTTDuration().toDouble()
overview_temptarget_temptarget.value = defaultTarget overview_temptarget_reason.setSelection(reasonList.indexOf( resourceHelper.gs(R.string.eatingsoon)))
overview_temptarget_duration.value = defaultDuration }
} R.id.overview_temptarget_activity -> {
overview_temptarget_temptarget.value = defaultValueHelper.determineActivityTT()
override fun onNothingSelected(parent: AdapterView<*>?) {} overview_temptarget_duration.value = defaultValueHelper.determineActivityTTDuration().toDouble()
overview_temptarget_reason.setSelection(reasonList.indexOf(resourceHelper.gs(R.string.activity)))
}
R.id.overview_temptarget_hypo -> {
overview_temptarget_temptarget.value = defaultValueHelper.determineHypoTT()
overview_temptarget_duration.value = defaultValueHelper.determineHypoTTDuration().toDouble()
overview_temptarget_reason.setSelection(reasonList.indexOf(resourceHelper.gs(R.string.hypo)))
} }
} }
} }
override fun submit(): Boolean { override fun submit(): Boolean {
val actions: LinkedList<String> = LinkedList() val actions: LinkedList<String> = LinkedList()
val reason = overview_temptarget_reason.selectedItem.toString() val reason = overview_temptarget_reason?.selectedItem?.toString() ?: return false
val unitResId = if (profileFunction.getUnits() == Constants.MGDL) R.string.mgdl else R.string.mmol val unitResId = if (profileFunction.getUnits() == Constants.MGDL) R.string.mgdl else R.string.mmol
val target = overview_temptarget_temptarget.value val target = overview_temptarget_temptarget.value
val duration = overview_temptarget_duration.value.toInt() val duration = overview_temptarget_duration.value.toInt()

View file

@ -94,7 +94,7 @@ class TreatmentDialog : DialogFragmentWithDate() {
override fun submit(): Boolean { override fun submit(): Boolean {
val pumpDescription = activePlugin.activePump.pumpDescription val pumpDescription = activePlugin.activePump.pumpDescription
val insulin = SafeParse.stringToDouble(overview_treatment_insulin.text) val insulin = SafeParse.stringToDouble(overview_treatment_insulin?.text ?: return false)
val carbs = SafeParse.stringToInt(overview_treatment_carbs.text) val carbs = SafeParse.stringToInt(overview_treatment_carbs.text)
val recordOnlyChecked = overview_treatment_record_only.isChecked val recordOnlyChecked = overview_treatment_record_only.isChecked
val actions: LinkedList<String?> = LinkedList() val actions: LinkedList<String?> = LinkedList()

View file

@ -18,6 +18,7 @@ import info.nightscout.androidaps.Constants
import info.nightscout.androidaps.MainApp import info.nightscout.androidaps.MainApp
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.data.Profile import info.nightscout.androidaps.data.Profile
import info.nightscout.androidaps.databinding.DialogWizardBinding
import info.nightscout.androidaps.db.BgReading import info.nightscout.androidaps.db.BgReading
import info.nightscout.androidaps.interfaces.ActivePluginProvider import info.nightscout.androidaps.interfaces.ActivePluginProvider
import info.nightscout.androidaps.interfaces.Constraint import info.nightscout.androidaps.interfaces.Constraint
@ -39,7 +40,6 @@ import info.nightscout.androidaps.utils.sharedPreferences.SP
import info.nightscout.androidaps.utils.wizard.BolusWizard import info.nightscout.androidaps.utils.wizard.BolusWizard
import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable import io.reactivex.disposables.CompositeDisposable
import kotlinx.android.synthetic.main.dialog_wizard.*
import java.text.DecimalFormat import java.text.DecimalFormat
import java.util.* import java.util.*
import javax.inject.Inject import javax.inject.Inject
@ -72,8 +72,23 @@ class WizardDialog : DaggerDialogFragment() {
} }
} }
private val timeTextWatcher = 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()
binding.alarm.isChecked = binding.carbTimeInput.value > 0
}
}
private var disposable: CompositeDisposable = CompositeDisposable() private var disposable: CompositeDisposable = CompositeDisposable()
private var _binding: DialogWizardBinding? = null
// This property is only valid between onCreateView and
// onDestroyView.
private val binding get() = _binding!!
override fun onStart() { override fun onStart() {
super.onStart() super.onStart()
dialog?.window?.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT) dialog?.window?.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
@ -81,49 +96,50 @@ class WizardDialog : DaggerDialogFragment() {
override fun onSaveInstanceState(savedInstanceState: Bundle) { override fun onSaveInstanceState(savedInstanceState: Bundle) {
super.onSaveInstanceState(savedInstanceState) super.onSaveInstanceState(savedInstanceState)
savedInstanceState.putDouble("treatments_wizard_bg_input", treatments_wizard_bg_input.value) savedInstanceState.putDouble("bg_input", binding.bgInput.value)
savedInstanceState.putDouble("treatments_wizard_carbs_input", treatments_wizard_carbs_input.value) savedInstanceState.putDouble("carbs_input", binding.carbsInput.value)
savedInstanceState.putDouble("treatments_wizard_correction_input", treatments_wizard_correction_input.value) savedInstanceState.putDouble("correction_input", binding.correctionInput.value)
savedInstanceState.putDouble("treatments_wizard_carb_time_input", treatments_wizard_carb_time_input.value) savedInstanceState.putDouble("carb_time_input", binding.carbTimeInput.value)
} }
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? { savedInstanceState: Bundle?): View {
dialog?.window?.requestFeature(Window.FEATURE_NO_TITLE) dialog?.window?.requestFeature(Window.FEATURE_NO_TITLE)
dialog?.window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN) dialog?.window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN)
isCancelable = true isCancelable = true
dialog?.setCanceledOnTouchOutside(false) dialog?.setCanceledOnTouchOutside(false)
return inflater.inflate(R.layout.dialog_wizard, container, false) _binding = DialogWizardBinding.inflate(inflater, container, false)
return binding.root
} }
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
loadCheckedStates() loadCheckedStates()
processCobCheckBox() processCobCheckBox()
treatments_wizard_sbcheckbox.visibility = sp.getBoolean(R.string.key_usesuperbolus, false).toVisibility() binding.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() binding.notesLayout.visibility = sp.getBoolean(R.string.key_show_notes_entry_dialogs, false).toVisibility()
val maxCarbs = constraintChecker.getMaxCarbsAllowed().value() val maxCarbs = constraintChecker.getMaxCarbsAllowed().value()
val maxCorrection = constraintChecker.getMaxBolusAllowed().value() val maxCorrection = constraintChecker.getMaxBolusAllowed().value()
if (profileFunction.getUnits() == Constants.MGDL) if (profileFunction.getUnits() == Constants.MGDL)
treatments_wizard_bg_input.setParams(savedInstanceState?.getDouble("treatments_wizard_bg_input") binding.bgInput.setParams(savedInstanceState?.getDouble("bg_input")
?: 0.0, 0.0, 500.0, 1.0, DecimalFormat("0.0"), false, ok, textWatcher) ?: 0.0, 0.0, 500.0, 1.0, DecimalFormat("0"), false, binding.ok, timeTextWatcher)
else else
treatments_wizard_bg_input.setParams(savedInstanceState?.getDouble("treatments_wizard_bg_input") binding.bgInput.setParams(savedInstanceState?.getDouble("bg_input")
?: 0.0, 0.0, 30.0, 0.1, DecimalFormat("0.0"), false, ok, textWatcher) ?: 0.0, 0.0, 30.0, 0.1, DecimalFormat("0.0"), false, binding.ok, textWatcher)
treatments_wizard_carbs_input.setParams(savedInstanceState?.getDouble("treatments_wizard_carbs_input") binding.carbsInput.setParams(savedInstanceState?.getDouble("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, binding.ok, textWatcher)
val bolusStep = activePlugin.activePump.pumpDescription.bolusStep val bolusStep = activePlugin.activePump.pumpDescription.bolusStep
treatments_wizard_correction_input.setParams(savedInstanceState?.getDouble("treatments_wizard_correction_input") binding.correctionInput.setParams(savedInstanceState?.getDouble("correction_input")
?: 0.0, -maxCorrection, maxCorrection, bolusStep, DecimalFormatter.pumpSupportedBolusFormat(activePlugin.activePump), false, ok, textWatcher) ?: 0.0, -maxCorrection, maxCorrection, bolusStep, DecimalFormatter.pumpSupportedBolusFormat(activePlugin.activePump), false, binding.ok, textWatcher)
treatments_wizard_carb_time_input.setParams(savedInstanceState?.getDouble("treatments_wizard_carb_time_input") binding.carbTimeInput.setParams(savedInstanceState?.getDouble("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, binding.ok, timeTextWatcher)
initDialog() initDialog()
treatments_wizard_percent_used.text = resourceHelper.gs(R.string.format_percent, sp.getInt(R.string.key_boluswizard_percentage, 100)) binding.percentUsed.text = resourceHelper.gs(R.string.format_percent, sp.getInt(R.string.key_boluswizard_percentage, 100))
// ok button // ok button
ok.setOnClickListener { binding.ok.setOnClickListener {
if (okClicked) { if (okClicked) {
aapsLogger.debug(LTag.UI, "guarding: ok already clicked") aapsLogger.debug(LTag.UI, "guarding: ok already clicked")
} else { } else {
@ -136,37 +152,37 @@ class WizardDialog : DaggerDialogFragment() {
dismiss() dismiss()
} }
// cancel button // cancel button
cancel.setOnClickListener { dismiss() } binding.cancel.setOnClickListener { dismiss() }
// checkboxes // checkboxes
treatments_wizard_bgcheckbox.setOnCheckedChangeListener(::onCheckedChanged) binding.bgcheckbox.setOnCheckedChangeListener(::onCheckedChanged)
treatments_wizard_ttcheckbox.setOnCheckedChangeListener(::onCheckedChanged) binding.ttcheckbox.setOnCheckedChangeListener(::onCheckedChanged)
treatments_wizard_cobcheckbox.setOnCheckedChangeListener(::onCheckedChanged) binding.cobcheckbox.setOnCheckedChangeListener(::onCheckedChanged)
treatments_wizard_basaliobcheckbox.setOnCheckedChangeListener(::onCheckedChanged) binding.basaliobcheckbox.setOnCheckedChangeListener(::onCheckedChanged)
treatments_wizard_bolusiobcheckbox.setOnCheckedChangeListener(::onCheckedChanged) binding.bolusiobcheckbox.setOnCheckedChangeListener(::onCheckedChanged)
treatments_wizard_bgtrendcheckbox.setOnCheckedChangeListener(::onCheckedChanged) binding.bgtrendcheckbox.setOnCheckedChangeListener(::onCheckedChanged)
treatments_wizard_sbcheckbox.setOnCheckedChangeListener(::onCheckedChanged) binding.sbcheckbox.setOnCheckedChangeListener(::onCheckedChanged)
val showCalc = sp.getBoolean(resourceHelper.gs(R.string.key_wizard_calculation_visible), false) val showCalc = sp.getBoolean(R.string.key_wizard_calculation_visible, false)
treatments_wizard_delimiter.visibility = showCalc.toVisibility() binding.delimiter.visibility = showCalc.toVisibility()
treatments_wizard_resulttable.visibility = showCalc.toVisibility() binding.resulttable.visibility = showCalc.toVisibility()
treatments_wizard_calculationcheckbox.isChecked = showCalc binding.calculationcheckbox.isChecked = showCalc
treatments_wizard_calculationcheckbox.setOnCheckedChangeListener { _, isChecked -> binding.calculationcheckbox.setOnCheckedChangeListener { _, isChecked ->
run { run {
sp.putBoolean(resourceHelper.gs(R.string.key_wizard_calculation_visible), isChecked) sp.putBoolean(resourceHelper.gs(R.string.key_wizard_calculation_visible), isChecked)
treatments_wizard_delimiter.visibility = isChecked.toVisibility() binding.delimiter.visibility = isChecked.toVisibility()
treatments_wizard_resulttable.visibility = isChecked.toVisibility() binding.resulttable.visibility = isChecked.toVisibility()
} }
} }
// profile spinner // profile spinner
treatments_wizard_profile.onItemSelectedListener = object : OnItemSelectedListener { binding.profile.onItemSelectedListener = object : OnItemSelectedListener {
override fun onNothingSelected(parent: AdapterView<*>?) { override fun onNothingSelected(parent: AdapterView<*>?) {
ToastUtils.showToastInUiThread(mainApp, resourceHelper.gs(R.string.noprofileselected)) ToastUtils.showToastInUiThread(mainApp, resourceHelper.gs(R.string.noprofileselected))
ok.visibility = View.GONE binding.ok.visibility = View.GONE
} }
override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) { override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
calculateInsulin() calculateInsulin()
ok.visibility = View.VISIBLE binding.ok.visibility = View.VISIBLE
} }
} }
// bus // bus
@ -183,36 +199,37 @@ class WizardDialog : DaggerDialogFragment() {
override fun onDestroyView() { override fun onDestroyView() {
super.onDestroyView() super.onDestroyView()
disposable.clear() disposable.clear()
_binding = null
} }
private fun onCheckedChanged(buttonView: CompoundButton, @Suppress("UNUSED_PARAMETER") state: Boolean) { private fun onCheckedChanged(buttonView: CompoundButton, @Suppress("UNUSED_PARAMETER") state: Boolean) {
saveCheckedStates() saveCheckedStates()
treatments_wizard_ttcheckbox.isEnabled = treatments_wizard_bgcheckbox.isChecked && treatmentsPlugin.tempTargetFromHistory != null binding.ttcheckbox.isEnabled = binding.bgcheckbox.isChecked && treatmentsPlugin.tempTargetFromHistory != null
if (buttonView.id == treatments_wizard_cobcheckbox.id) if (buttonView.id == binding.cobcheckbox.id)
processCobCheckBox() processCobCheckBox()
calculateInsulin() calculateInsulin()
} }
private fun processCobCheckBox() { private fun processCobCheckBox() {
if (treatments_wizard_cobcheckbox.isChecked) { if (binding.cobcheckbox.isChecked) {
treatments_wizard_bolusiobcheckbox.isEnabled = false binding.bolusiobcheckbox.isEnabled = false
treatments_wizard_basaliobcheckbox.isEnabled = false binding.basaliobcheckbox.isEnabled = false
treatments_wizard_bolusiobcheckbox.isChecked = true binding.bolusiobcheckbox.isChecked = true
treatments_wizard_basaliobcheckbox.isChecked = true binding.basaliobcheckbox.isChecked = true
} else { } else {
treatments_wizard_bolusiobcheckbox.isEnabled = true binding.bolusiobcheckbox.isEnabled = true
treatments_wizard_basaliobcheckbox.isEnabled = true binding.basaliobcheckbox.isEnabled = true
} }
} }
private fun saveCheckedStates() { private fun saveCheckedStates() {
sp.putBoolean(resourceHelper.gs(R.string.key_wizard_include_cob), treatments_wizard_cobcheckbox.isChecked) sp.putBoolean(R.string.key_wizard_include_cob, binding.cobcheckbox.isChecked)
sp.putBoolean(resourceHelper.gs(R.string.key_wizard_include_trend_bg), treatments_wizard_bgtrendcheckbox.isChecked) sp.putBoolean(R.string.key_wizard_include_trend_bg, binding.bgtrendcheckbox.isChecked)
} }
private fun loadCheckedStates() { private fun loadCheckedStates() {
treatments_wizard_bgtrendcheckbox.isChecked = sp.getBoolean(resourceHelper.gs(R.string.key_wizard_include_trend_bg), false) binding.bgtrendcheckbox.isChecked = sp.getBoolean(R.string.key_wizard_include_trend_bg, false)
treatments_wizard_cobcheckbox.isChecked = sp.getBoolean(resourceHelper.gs(R.string.key_wizard_include_cob), false) binding.cobcheckbox.isChecked = sp.getBoolean(R.string.key_wizard_include_cob, false)
} }
private fun initDialog() { private fun initDialog() {
@ -230,25 +247,25 @@ class WizardDialog : DaggerDialogFragment() {
profileList.add(0, resourceHelper.gs(R.string.active)) profileList.add(0, resourceHelper.gs(R.string.active))
context?.let { context -> context?.let { context ->
val adapter = ArrayAdapter(context, R.layout.spinner_centered, profileList) val adapter = ArrayAdapter(context, R.layout.spinner_centered, profileList)
treatments_wizard_profile.adapter = adapter binding.profile.adapter = adapter
} ?: return } ?: return
val units = profileFunction.getUnits() val units = profileFunction.getUnits()
treatments_wizard_bgunits.text = units binding.bgunits.text = units
if (units == Constants.MGDL) if (units == Constants.MGDL)
treatments_wizard_bg_input.setStep(1.0) binding.bgInput.setStep(1.0)
else else
treatments_wizard_bg_input.setStep(0.1) binding.bgInput.setStep(0.1)
// Set BG if not old // Set BG if not old
val lastBg = iobCobCalculatorPlugin.actualBg() val lastBg = iobCobCalculatorPlugin.actualBg()
if (lastBg != null) { if (lastBg != null) {
treatments_wizard_bg_input.value = lastBg.valueToUnits(units) binding.bgInput.value = lastBg.valueToUnits(units)
} else { } else {
treatments_wizard_bg_input.value = 0.0 binding.bgInput.value = 0.0
} }
treatments_wizard_ttcheckbox.isEnabled = treatmentsPlugin.tempTargetFromHistory != null binding.ttcheckbox.isEnabled = treatmentsPlugin.tempTargetFromHistory != null
// IOB calculation // IOB calculation
treatmentsPlugin.updateTotalIOBTreatments() treatmentsPlugin.updateTotalIOBTreatments()
@ -256,19 +273,19 @@ class WizardDialog : DaggerDialogFragment() {
treatmentsPlugin.updateTotalIOBTempBasals() treatmentsPlugin.updateTotalIOBTempBasals()
val basalIob = treatmentsPlugin.lastCalculationTempBasals.round() val basalIob = treatmentsPlugin.lastCalculationTempBasals.round()
treatments_wizard_bolusiobinsulin.text = resourceHelper.gs(R.string.formatinsulinunits, -bolusIob.iob) binding.bolusiobinsulin.text = resourceHelper.gs(R.string.formatinsulinunits, -bolusIob.iob)
treatments_wizard_basaliobinsulin.text = resourceHelper.gs(R.string.formatinsulinunits, -basalIob.basaliob) binding.basaliobinsulin.text = resourceHelper.gs(R.string.formatinsulinunits, -basalIob.basaliob)
calculateInsulin() calculateInsulin()
treatments_wizard_percent_used.visibility = (sp.getInt(R.string.key_boluswizard_percentage, 100) != 100).toVisibility() binding.percentUsed.visibility = (sp.getInt(R.string.key_boluswizard_percentage, 100) != 100).toVisibility()
} }
private fun calculateInsulin() { private fun calculateInsulin() {
val profileStore = activePlugin.activeProfileInterface.profile val profileStore = activePlugin.activeProfileInterface.profile
if (treatments_wizard_profile?.selectedItem == null || profileStore == null) if (binding.profile.selectedItem == null || profileStore == null)
return // not initialized yet return // not initialized yet
var profileName = treatments_wizard_profile.selectedItem.toString() var profileName = binding.profile.selectedItem.toString()
val specificProfile: Profile? val specificProfile: Profile?
if (profileName == resourceHelper.gs(R.string.active)) { if (profileName == resourceHelper.gs(R.string.active)) {
specificProfile = profileFunction.getProfile() specificProfile = profileFunction.getProfile()
@ -279,82 +296,83 @@ class WizardDialog : DaggerDialogFragment() {
if (specificProfile == null) return if (specificProfile == null) return
// Entered values // Entered values
var bg = SafeParse.stringToDouble(treatments_wizard_bg_input.text) var bg = SafeParse.stringToDouble(binding.bgInput.text)
val carbs = SafeParse.stringToInt(treatments_wizard_carbs_input.text) val carbs = SafeParse.stringToInt(binding.carbsInput.text)
val correction = SafeParse.stringToDouble(treatments_wizard_correction_input.text) val correction = SafeParse.stringToDouble(binding.correctionInput.text)
val carbsAfterConstraint = constraintChecker.applyCarbsConstraints(Constraint(carbs)).value() val carbsAfterConstraint = constraintChecker.applyCarbsConstraints(Constraint(carbs)).value()
if (abs(carbs - carbsAfterConstraint) > 0.01) { if (abs(carbs - carbsAfterConstraint) > 0.01) {
treatments_wizard_carbs_input.value = 0.0 binding.carbsInput.value = 0.0
ToastUtils.showToastInUiThread(mainApp, resourceHelper.gs(R.string.carbsconstraintapplied)) ToastUtils.showToastInUiThread(mainApp, resourceHelper.gs(R.string.carbsconstraintapplied))
return return
} }
bg = if (treatments_wizard_bgcheckbox.isChecked) bg else 0.0 bg = if (binding.bgcheckbox.isChecked) bg else 0.0
val tempTarget = if (treatments_wizard_ttcheckbox.isChecked) treatmentsPlugin.tempTargetFromHistory else null val tempTarget = if (binding.ttcheckbox.isChecked) treatmentsPlugin.tempTargetFromHistory else null
// COB // COB
var cob = 0.0 var cob = 0.0
if (treatments_wizard_cobcheckbox.isChecked) { if (binding.cobcheckbox.isChecked) {
val cobInfo = iobCobCalculatorPlugin.getCobInfo(false, "Wizard COB") val cobInfo = iobCobCalculatorPlugin.getCobInfo(false, "Wizard COB")
cobInfo.displayCob?.let { cob = it } cobInfo.displayCob?.let { cob = it }
} }
val carbTime = SafeParse.stringToInt(treatments_wizard_carb_time_input.text) val carbTime = SafeParse.stringToInt(binding.carbTimeInput.text)
wizard = BolusWizard(mainApp).doCalc(specificProfile, profileName, tempTarget, carbsAfterConstraint, cob, bg, correction, wizard = BolusWizard(mainApp).doCalc(specificProfile, profileName, tempTarget, carbsAfterConstraint, cob, bg, correction,
sp.getInt(R.string.key_boluswizard_percentage, 100).toDouble(), sp.getInt(R.string.key_boluswizard_percentage, 100).toDouble(),
treatments_wizard_bgcheckbox.isChecked, binding.bgcheckbox.isChecked,
treatments_wizard_cobcheckbox.isChecked, binding.cobcheckbox.isChecked,
treatments_wizard_bolusiobcheckbox.isChecked, binding.bolusiobcheckbox.isChecked,
treatments_wizard_basaliobcheckbox.isChecked, binding.basaliobcheckbox.isChecked,
treatments_wizard_sbcheckbox.isChecked, binding.sbcheckbox.isChecked,
treatments_wizard_ttcheckbox.isChecked, binding.ttcheckbox.isChecked,
treatments_wizard_bgtrendcheckbox.isChecked, binding.bgtrendcheckbox.isChecked,
treatment_wizard_notes.text.toString(), carbTime) binding.alarm.isChecked,
binding.notes.text.toString(), carbTime)
wizard?.let { wizard -> wizard?.let { wizard ->
treatments_wizard_bg.text = String.format(resourceHelper.gs(R.string.format_bg_isf), BgReading().value(Profile.toMgdl(bg, profileFunction.getUnits())).valueToUnitsToString(profileFunction.getUnits()), wizard.sens) binding.bg.text = String.format(resourceHelper.gs(R.string.format_bg_isf), BgReading().value(Profile.toMgdl(bg, profileFunction.getUnits())).valueToUnitsToString(profileFunction.getUnits()), wizard.sens)
treatments_wizard_bginsulin.text = resourceHelper.gs(R.string.formatinsulinunits, wizard.insulinFromBG) binding.bginsulin.text = resourceHelper.gs(R.string.formatinsulinunits, wizard.insulinFromBG)
treatments_wizard_carbs.text = String.format(resourceHelper.gs(R.string.format_carbs_ic), carbs.toDouble(), wizard.ic) binding.carbs.text = String.format(resourceHelper.gs(R.string.format_carbs_ic), carbs.toDouble(), wizard.ic)
treatments_wizard_carbsinsulin.text = resourceHelper.gs(R.string.formatinsulinunits, wizard.insulinFromCarbs) binding.carbsinsulin.text = resourceHelper.gs(R.string.formatinsulinunits, wizard.insulinFromCarbs)
treatments_wizard_bolusiobinsulin.text = resourceHelper.gs(R.string.formatinsulinunits, wizard.insulinFromBolusIOB) binding.bolusiobinsulin.text = resourceHelper.gs(R.string.formatinsulinunits, wizard.insulinFromBolusIOB)
treatments_wizard_basaliobinsulin.text = resourceHelper.gs(R.string.formatinsulinunits, wizard.insulinFromBasalsIOB) binding.basaliobinsulin.text = resourceHelper.gs(R.string.formatinsulinunits, wizard.insulinFromBasalIOB)
treatments_wizard_correctioninsulin.text = resourceHelper.gs(R.string.formatinsulinunits, wizard.insulinFromCorrection) binding.correctioninsulin.text = resourceHelper.gs(R.string.formatinsulinunits, wizard.insulinFromCorrection)
// Superbolus // Superbolus
treatments_wizard_sb.text = if (treatments_wizard_sbcheckbox.isChecked) resourceHelper.gs(R.string.twohours) else "" binding.sb.text = if (binding.sbcheckbox.isChecked) resourceHelper.gs(R.string.twohours) else ""
treatments_wizard_sbinsulin.text = resourceHelper.gs(R.string.formatinsulinunits, wizard.insulinFromSuperBolus) binding.sbinsulin.text = resourceHelper.gs(R.string.formatinsulinunits, wizard.insulinFromSuperBolus)
// Trend // Trend
if (treatments_wizard_bgtrendcheckbox.isChecked && wizard.glucoseStatus != null) { if (binding.bgtrendcheckbox.isChecked && wizard.glucoseStatus != null) {
treatments_wizard_bgtrend.text = ((if (wizard.trend > 0) "+" else "") binding.bgtrend.text = ((if (wizard.trend > 0) "+" else "")
+ Profile.toUnitsString(wizard.trend * 3, wizard.trend * 3 / Constants.MMOLL_TO_MGDL, profileFunction.getUnits()) + Profile.toUnitsString(wizard.trend * 3, wizard.trend * 3 / Constants.MMOLL_TO_MGDL, profileFunction.getUnits())
+ " " + profileFunction.getUnits()) + " " + profileFunction.getUnits())
} else { } else {
treatments_wizard_bgtrend.text = "" binding.bgtrend.text = ""
} }
treatments_wizard_bgtrendinsulin.text = resourceHelper.gs(R.string.formatinsulinunits, wizard.insulinFromTrend) binding.bgtrendinsulin.text = resourceHelper.gs(R.string.formatinsulinunits, wizard.insulinFromTrend)
// COB // COB
if (treatments_wizard_cobcheckbox.isChecked) { if (binding.cobcheckbox.isChecked) {
treatments_wizard_cob.text = String.format(resourceHelper.gs(R.string.format_cob_ic), cob, wizard.ic) binding.cob.text = String.format(resourceHelper.gs(R.string.format_cob_ic), cob, wizard.ic)
treatments_wizard_cobinsulin.text = resourceHelper.gs(R.string.formatinsulinunits, wizard.insulinFromCOB) binding.cobinsulin.text = resourceHelper.gs(R.string.formatinsulinunits, wizard.insulinFromCOB)
} else { } else {
treatments_wizard_cob.text = "" binding.cob.text = ""
treatments_wizard_cobinsulin.text = "" binding.cobinsulin.text = ""
} }
if (wizard.calculatedTotalInsulin > 0.0 || carbsAfterConstraint > 0.0) { if (wizard.calculatedTotalInsulin > 0.0 || carbsAfterConstraint > 0.0) {
val insulinText = if (wizard.calculatedTotalInsulin > 0.0) resourceHelper.gs(R.string.formatinsulinunits, wizard.calculatedTotalInsulin) else "" val insulinText = if (wizard.calculatedTotalInsulin > 0.0) resourceHelper.gs(R.string.formatinsulinunits, wizard.calculatedTotalInsulin) else ""
val carbsText = if (carbsAfterConstraint > 0.0) resourceHelper.gs(R.string.format_carbs, carbsAfterConstraint) else "" val carbsText = if (carbsAfterConstraint > 0.0) resourceHelper.gs(R.string.format_carbs, carbsAfterConstraint) else ""
treatments_wizard_total.text = resourceHelper.gs(R.string.result_insulin_carbs, insulinText, carbsText) binding.total.text = resourceHelper.gs(R.string.result_insulin_carbs, insulinText, carbsText)
ok.visibility = View.VISIBLE binding.ok.visibility = View.VISIBLE
} else { } else {
treatments_wizard_total.text = resourceHelper.gs(R.string.missing_carbs, wizard.carbsEquivalent.toInt()) binding.total.text = resourceHelper.gs(R.string.missing_carbs, wizard.carbsEquivalent.toInt())
ok.visibility = View.INVISIBLE binding.ok.visibility = View.INVISIBLE
} }
} }

View file

@ -8,6 +8,7 @@ import android.view.ViewGroup
import android.widget.LinearLayout import android.widget.LinearLayout
import android.widget.RelativeLayout import android.widget.RelativeLayout
import android.widget.TextView import android.widget.TextView
import androidx.lifecycle.lifecycleScope
import com.jjoe64.graphview.GraphView import com.jjoe64.graphview.GraphView
import dagger.android.HasAndroidInjector import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
@ -37,13 +38,13 @@ import io.reactivex.disposables.CompositeDisposable
import io.reactivex.schedulers.Schedulers import io.reactivex.schedulers.Schedulers
import kotlinx.android.synthetic.main.activity_historybrowse.* import kotlinx.android.synthetic.main.activity_historybrowse.*
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import java.util.* import java.util.*
import javax.inject.Inject import javax.inject.Inject
class HistoryBrowseActivity : NoSplashAppCompatActivity() { class HistoryBrowseActivity : NoSplashAppCompatActivity() {
@Inject lateinit var injector: HasAndroidInjector @Inject lateinit var injector: HasAndroidInjector
@Inject lateinit var aapsLogger: AAPSLogger @Inject lateinit var aapsLogger: AAPSLogger
@Inject lateinit var rxBus: RxBusWrapper @Inject lateinit var rxBus: RxBusWrapper
@ -144,7 +145,7 @@ class HistoryBrowseActivity : NoSplashAppCompatActivity() {
historybrowse_bggraph?.gridLabelRenderer?.labelVerticalWidth = axisWidth historybrowse_bggraph?.gridLabelRenderer?.labelVerticalWidth = axisWidth
overviewMenus.setupChartMenu(overview_chartMenuButton) overviewMenus.setupChartMenu(overview_chartMenuButton)
prepareGraphs() prepareGraphsIfNeeded(overviewMenus.setting.size)
savedInstanceState?.let { bundle -> savedInstanceState?.let { bundle ->
rangeToDisplay = bundle.getInt("rangeToDisplay", 0) rangeToDisplay = bundle.getInt("rangeToDisplay", 0)
start = bundle.getLong("start", 0) start = bundle.getLong("start", 0)
@ -168,7 +169,7 @@ class HistoryBrowseActivity : NoSplashAppCompatActivity() {
if (it.cause is EventCustomCalculationFinished) { if (it.cause is EventCustomCalculationFinished) {
updateGUI("EventAutosensCalculationFinished", bgOnly = false) updateGUI("EventAutosensCalculationFinished", bgOnly = false)
} }
}) { fabricPrivacy::logException } }, fabricPrivacy::logException)
) )
disposable.add(rxBus disposable.add(rxBus
.toObservable(EventAutosensBgLoaded::class.java) .toObservable(EventAutosensBgLoaded::class.java)
@ -178,22 +179,21 @@ class HistoryBrowseActivity : NoSplashAppCompatActivity() {
if (it.cause is EventCustomCalculationFinished) { if (it.cause is EventCustomCalculationFinished) {
updateGUI("EventAutosensCalculationFinished", bgOnly = true) updateGUI("EventAutosensCalculationFinished", bgOnly = true)
} }
}) { fabricPrivacy::logException } }, fabricPrivacy::logException)
) )
disposable.add(rxBus disposable.add(rxBus
.toObservable(EventIobCalculationProgress::class.java) .toObservable(EventIobCalculationProgress::class.java)
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
.subscribe({ overview_iobcalculationprogess?.text = it.progress }) { fabricPrivacy::logException } .subscribe({ overview_iobcalculationprogess?.text = it.progress }, fabricPrivacy::logException)
) )
disposable.add(rxBus disposable.add(rxBus
.toObservable(EventRefreshOverview::class.java) .toObservable(EventRefreshOverview::class.java)
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
.subscribe({ .subscribe({
if (it.now) { if (it.now) {
prepareGraphs()
updateGUI("EventRefreshOverview", bgOnly = false) updateGUI("EventRefreshOverview", bgOnly = false)
} }
}) { fabricPrivacy::logException } }, fabricPrivacy::logException)
) )
if (start == 0L) { if (start == 0L) {
// set start of current day // set start of current day
@ -217,8 +217,7 @@ class HistoryBrowseActivity : NoSplashAppCompatActivity() {
} }
private fun prepareGraphs() { private fun prepareGraphsIfNeeded(numOfGraphs: Int) {
val numOfGraphs = overviewMenus.setting.size
if (numOfGraphs != secondaryGraphs.size - 1) { if (numOfGraphs != secondaryGraphs.size - 1) {
//aapsLogger.debug("New secondary graph count ${numOfGraphs-1}") //aapsLogger.debug("New secondary graph count ${numOfGraphs-1}")
@ -256,7 +255,7 @@ class HistoryBrowseActivity : NoSplashAppCompatActivity() {
} }
private fun runCalculation(from: String) { private fun runCalculation(from: String) {
GlobalScope.launch(Dispatchers.Default) { lifecycleScope.launch(Dispatchers.Default) {
treatmentsPluginHistory.initializeData(start - T.hours(8).msecs()) treatmentsPluginHistory.initializeData(start - T.hours(8).msecs())
val end = start + T.hours(rangeToDisplay.toLong()).msecs() val end = start + T.hours(rangeToDisplay.toLong()).msecs()
iobCobCalculatorPluginHistory.stopCalculation(from) iobCobCalculatorPluginHistory.stopCalculation(from)
@ -266,6 +265,8 @@ class HistoryBrowseActivity : NoSplashAppCompatActivity() {
} }
fun updateGUI(from: String, bgOnly: Boolean) { fun updateGUI(from: String, bgOnly: Boolean) {
val menuChartSettings = overviewMenus.setting
prepareGraphsIfNeeded(menuChartSettings.size)
aapsLogger.debug(LTag.UI, "updateGUI from: $from") aapsLogger.debug(LTag.UI, "updateGUI from: $from")
val pump = activePlugin.activePump val pump = activePlugin.activePump
val profile = profileFunction.getProfile() val profile = profileFunction.getProfile()
@ -273,7 +274,7 @@ class HistoryBrowseActivity : NoSplashAppCompatActivity() {
val lowLine = defaultValueHelper.determineLowLine() val lowLine = defaultValueHelper.determineLowLine()
val highLine = defaultValueHelper.determineHighLine() val highLine = defaultValueHelper.determineHighLine()
GlobalScope.launch(Dispatchers.Main) { lifecycleScope.launch(Dispatchers.Main) {
historybrowse_noprofile?.visibility = (profile == null).toVisibility() historybrowse_noprofile?.visibility = (profile == null).toVisibility()
profile ?: return@launch profile ?: return@launch
@ -308,11 +309,11 @@ class HistoryBrowseActivity : NoSplashAppCompatActivity() {
if (!bgOnly) { if (!bgOnly) {
// Treatments // Treatments
graphData.addTreatments(fromTime, toTime) graphData.addTreatments(fromTime, toTime)
if (overviewMenus.setting[0][OverviewMenus.CharType.ACT.ordinal]) if (menuChartSettings[0][OverviewMenus.CharType.ACT.ordinal])
graphData.addActivity(fromTime, toTime, false, 0.8) graphData.addActivity(fromTime, toTime, false, 0.8)
// add basal data // add basal data
if (pump.pumpDescription.isTempBasalCapable && overviewMenus.setting[0][OverviewMenus.CharType.BAS.ordinal]) { if (pump.pumpDescription.isTempBasalCapable && menuChartSettings[0][OverviewMenus.CharType.BAS.ordinal]) {
graphData.addBasals(fromTime, toTime, lowLine / graphData.maxY / 1.2) graphData.addBasals(fromTime, toTime, lowLine / graphData.maxY / 1.2)
} }
// ------------------ 2nd graph // ------------------ 2nd graph
@ -326,22 +327,22 @@ class HistoryBrowseActivity : NoSplashAppCompatActivity() {
var useIAForScale = false var useIAForScale = false
var useABSForScale = false var useABSForScale = false
when { when {
overviewMenus.setting[g + 1][OverviewMenus.CharType.IOB.ordinal] -> useIobForScale = true menuChartSettings[g + 1][OverviewMenus.CharType.IOB.ordinal] -> useIobForScale = true
overviewMenus.setting[g + 1][OverviewMenus.CharType.COB.ordinal] -> useCobForScale = true menuChartSettings[g + 1][OverviewMenus.CharType.COB.ordinal] -> useCobForScale = true
overviewMenus.setting[g + 1][OverviewMenus.CharType.DEV.ordinal] -> useDevForScale = true menuChartSettings[g + 1][OverviewMenus.CharType.DEV.ordinal] -> useDevForScale = true
overviewMenus.setting[g + 1][OverviewMenus.CharType.SEN.ordinal] -> useRatioForScale = true menuChartSettings[g + 1][OverviewMenus.CharType.SEN.ordinal] -> useRatioForScale = true
overviewMenus.setting[g + 1][OverviewMenus.CharType.ACT.ordinal] -> useIAForScale = true menuChartSettings[g + 1][OverviewMenus.CharType.ACT.ordinal] -> useIAForScale = true
overviewMenus.setting[g + 1][OverviewMenus.CharType.ABS.ordinal] -> useABSForScale = true menuChartSettings[g + 1][OverviewMenus.CharType.ABS.ordinal] -> useABSForScale = true
overviewMenus.setting[g + 1][OverviewMenus.CharType.DEVSLOPE.ordinal] -> useDSForScale = true menuChartSettings[g + 1][OverviewMenus.CharType.DEVSLOPE.ordinal] -> useDSForScale = true
} }
if (overviewMenus.setting[g + 1][OverviewMenus.CharType.IOB.ordinal]) secondGraphData.addIob(fromTime, toTime, useIobForScale, 1.0, overviewMenus.setting[g + 1][OverviewMenus.CharType.PRE.ordinal]) if (menuChartSettings[g + 1][OverviewMenus.CharType.IOB.ordinal]) secondGraphData.addIob(fromTime, toTime, useIobForScale, 1.0, menuChartSettings[g + 1][OverviewMenus.CharType.PRE.ordinal])
if (overviewMenus.setting[g + 1][OverviewMenus.CharType.COB.ordinal]) secondGraphData.addCob(fromTime, toTime, useCobForScale, if (useCobForScale) 1.0 else 0.5) if (menuChartSettings[g + 1][OverviewMenus.CharType.COB.ordinal]) secondGraphData.addCob(fromTime, toTime, useCobForScale, if (useCobForScale) 1.0 else 0.5)
if (overviewMenus.setting[g + 1][OverviewMenus.CharType.DEV.ordinal]) secondGraphData.addDeviations(fromTime, toTime, useDevForScale, 1.0) if (menuChartSettings[g + 1][OverviewMenus.CharType.DEV.ordinal]) secondGraphData.addDeviations(fromTime, toTime, useDevForScale, 1.0)
if (overviewMenus.setting[g + 1][OverviewMenus.CharType.SEN.ordinal]) secondGraphData.addRatio(fromTime, toTime, useRatioForScale, 1.0) if (menuChartSettings[g + 1][OverviewMenus.CharType.SEN.ordinal]) secondGraphData.addRatio(fromTime, toTime, useRatioForScale, 1.0)
if (overviewMenus.setting[g + 1][OverviewMenus.CharType.ACT.ordinal]) secondGraphData.addActivity(fromTime, toTime, useIAForScale, 0.8) if (menuChartSettings[g + 1][OverviewMenus.CharType.ACT.ordinal]) secondGraphData.addActivity(fromTime, toTime, useIAForScale, 0.8)
if (overviewMenus.setting[g + 1][OverviewMenus.CharType.ABS.ordinal]) secondGraphData.addAbsIob(fromTime, toTime, useABSForScale, 1.0) if (menuChartSettings[g + 1][OverviewMenus.CharType.ABS.ordinal]) secondGraphData.addAbsIob(fromTime, toTime, useABSForScale, 1.0)
if (overviewMenus.setting[g + 1][OverviewMenus.CharType.DEVSLOPE.ordinal] && buildHelper.isDev()) secondGraphData.addDeviationSlope(fromTime, toTime, useDSForScale, 1.0) if (menuChartSettings[g + 1][OverviewMenus.CharType.DEVSLOPE.ordinal] && buildHelper.isDev()) secondGraphData.addDeviationSlope(fromTime, toTime, useDSForScale, 1.0)
// set manual x bounds to have nice steps // set manual x bounds to have nice steps
secondGraphData.formatAxis(fromTime, toTime) secondGraphData.formatAxis(fromTime, toTime)
@ -356,13 +357,13 @@ class HistoryBrowseActivity : NoSplashAppCompatActivity() {
for (g in 0 until secondaryGraphs.size) { for (g in 0 until secondaryGraphs.size) {
secondaryGraphsLabel[g].text = overviewMenus.enabledTypes(g + 1) secondaryGraphsLabel[g].text = overviewMenus.enabledTypes(g + 1)
secondaryGraphs[g].visibility = (!bgOnly && ( secondaryGraphs[g].visibility = (!bgOnly && (
overviewMenus.setting[g + 1][OverviewMenus.CharType.IOB.ordinal] || menuChartSettings[g + 1][OverviewMenus.CharType.IOB.ordinal] ||
overviewMenus.setting[g + 1][OverviewMenus.CharType.COB.ordinal] || menuChartSettings[g + 1][OverviewMenus.CharType.COB.ordinal] ||
overviewMenus.setting[g + 1][OverviewMenus.CharType.DEV.ordinal] || menuChartSettings[g + 1][OverviewMenus.CharType.DEV.ordinal] ||
overviewMenus.setting[g + 1][OverviewMenus.CharType.SEN.ordinal] || menuChartSettings[g + 1][OverviewMenus.CharType.SEN.ordinal] ||
overviewMenus.setting[g + 1][OverviewMenus.CharType.ACT.ordinal] || menuChartSettings[g + 1][OverviewMenus.CharType.ACT.ordinal] ||
overviewMenus.setting[g + 1][OverviewMenus.CharType.ABS.ordinal] || menuChartSettings[g + 1][OverviewMenus.CharType.ABS.ordinal] ||
overviewMenus.setting[g + 1][OverviewMenus.CharType.DEVSLOPE.ordinal] menuChartSettings[g + 1][OverviewMenus.CharType.DEVSLOPE.ordinal]
)).toVisibility() )).toVisibility()
secondaryGraphsData[g].performUpdate() secondaryGraphsData[g].performUpdate()
} }

View file

@ -7,6 +7,7 @@ import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.plugins.general.nsclient.NSUpload import info.nightscout.androidaps.plugins.general.nsclient.NSUpload
import info.nightscout.androidaps.plugins.general.nsclient.UploadQueue
import info.nightscout.androidaps.plugins.treatments.TreatmentService import info.nightscout.androidaps.plugins.treatments.TreatmentService
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin
import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.DateUtil
@ -27,8 +28,10 @@ class TreatmentsPluginHistory @Inject constructor(
profileFunction: ProfileFunction, profileFunction: ProfileFunction,
activePlugin: ActivePluginProvider, activePlugin: ActivePluginProvider,
nsUpload: NSUpload, nsUpload: NSUpload,
fabricPrivacy: FabricPrivacy, dateUtil: DateUtil fabricPrivacy: FabricPrivacy,
) : TreatmentsPlugin(injector, aapsLogger, rxBus, resourceHelper, context, sp, profileFunction, activePlugin, nsUpload, fabricPrivacy, dateUtil) { dateUtil: DateUtil,
uploadQueue: UploadQueue
) : TreatmentsPlugin(injector, aapsLogger, rxBus, resourceHelper, context, sp, profileFunction, activePlugin, nsUpload, fabricPrivacy, dateUtil, uploadQueue) {
init { init {
onStart() onStart()

View file

@ -22,6 +22,7 @@ import javax.inject.Singleton;
import dagger.Lazy; import dagger.Lazy;
import dagger.android.HasAndroidInjector; import dagger.android.HasAndroidInjector;
import info.nightscout.androidaps.BuildConfig; import info.nightscout.androidaps.BuildConfig;
import info.nightscout.androidaps.Config;
import info.nightscout.androidaps.Constants; import info.nightscout.androidaps.Constants;
import info.nightscout.androidaps.MainActivity; import info.nightscout.androidaps.MainActivity;
import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.MainApp;
@ -55,10 +56,10 @@ import info.nightscout.androidaps.plugins.aps.loop.events.EventLoopUpdateGui;
import info.nightscout.androidaps.plugins.aps.loop.events.EventNewOpenLoopNotification; import info.nightscout.androidaps.plugins.aps.loop.events.EventNewOpenLoopNotification;
import info.nightscout.androidaps.plugins.bus.RxBusWrapper; import info.nightscout.androidaps.plugins.bus.RxBusWrapper;
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker; import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker;
import info.nightscout.androidaps.plugins.general.nsclient.NSUpload;
import info.nightscout.androidaps.plugins.general.overview.events.EventDismissNotification; import info.nightscout.androidaps.plugins.general.overview.events.EventDismissNotification;
import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification; import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification;
import info.nightscout.androidaps.plugins.general.overview.notifications.Notification; import info.nightscout.androidaps.plugins.general.overview.notifications.Notification;
import info.nightscout.androidaps.plugins.general.nsclient.NSUpload;
import info.nightscout.androidaps.plugins.general.wear.ActionStringHandler; import info.nightscout.androidaps.plugins.general.wear.ActionStringHandler;
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin; import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin;
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventAutosensCalculationFinished; import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventAutosensCalculationFinished;
@ -95,9 +96,8 @@ public class LoopPlugin extends PluginBase implements LoopInterface {
private final FabricPrivacy fabricPrivacy; private final FabricPrivacy fabricPrivacy;
private final NSUpload nsUpload; private final NSUpload nsUpload;
private final HardLimits hardLimits; private final HardLimits hardLimits;
private Notification notification;
private CompositeDisposable disposable = new CompositeDisposable(); private final CompositeDisposable disposable = new CompositeDisposable();
private static final String CHANNEL_ID = "AndroidAPS-Openloop"; private static final String CHANNEL_ID = "AndroidAPS-Openloop";
@ -126,6 +126,7 @@ public class LoopPlugin extends PluginBase implements LoopInterface {
AAPSLogger aapsLogger, AAPSLogger aapsLogger,
RxBusWrapper rxBus, RxBusWrapper rxBus,
SP sp, SP sp,
Config config,
ConstraintChecker constraintChecker, ConstraintChecker constraintChecker,
ResourceHelper resourceHelper, ResourceHelper resourceHelper,
ProfileFunction profileFunction, ProfileFunction profileFunction,
@ -144,9 +145,11 @@ public class LoopPlugin extends PluginBase implements LoopInterface {
super(new PluginDescription() super(new PluginDescription()
.mainType(PluginType.LOOP) .mainType(PluginType.LOOP)
.fragmentClass(LoopFragment.class.getName()) .fragmentClass(LoopFragment.class.getName())
.pluginIcon(R.drawable.ic_loop_closed_white)
.pluginName(R.string.loop) .pluginName(R.string.loop)
.shortName(R.string.loop_shortname) .shortName(R.string.loop_shortname)
.preferencesId(R.xml.pref_loop) .preferencesId(R.xml.pref_loop)
.enableByDefault(config.getAPS())
.description(R.string.description_loop), .description(R.string.description_loop),
aapsLogger, resourceHelper, injector aapsLogger, resourceHelper, injector
); );
@ -415,7 +418,7 @@ public class LoopPlugin extends PluginBase implements LoopInterface {
resultAfterConstraints.smb = 0; resultAfterConstraints.smb = 0;
} }
if (lastRun != null) { if (lastRun != null && lastRun.getConstraintsProcessed() != null) {
prevCarbsreq = lastRun.getConstraintsProcessed().carbsReq; prevCarbsreq = lastRun.getConstraintsProcessed().carbsReq;
} }
@ -551,6 +554,9 @@ public class LoopPlugin extends PluginBase implements LoopInterface {
rxBus.send(new EventLoopUpdateGui()); rxBus.send(new EventLoopUpdateGui());
} }
}); });
} else {
lastRun.setTbrSetByPump(result);
lastRun.setLastTBRRequest(lastRun.getLastAPSRun());
} }
rxBus.send(new EventLoopUpdateGui()); rxBus.send(new EventLoopUpdateGui());
} }

View file

@ -40,7 +40,7 @@ import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin;
import info.nightscout.androidaps.utils.sharedPreferences.SP; import info.nightscout.androidaps.utils.sharedPreferences.SP;
public class DetermineBasalAdapterAMAJS { public class DetermineBasalAdapterAMAJS {
private HasAndroidInjector injector; private final HasAndroidInjector injector;
@Inject AAPSLogger aapsLogger; @Inject AAPSLogger aapsLogger;
@Inject ConstraintChecker constraintChecker; @Inject ConstraintChecker constraintChecker;
@Inject SP sp; @Inject SP sp;
@ -48,7 +48,7 @@ public class DetermineBasalAdapterAMAJS {
@Inject TreatmentsPlugin treatmentsPlugin; @Inject TreatmentsPlugin treatmentsPlugin;
@Inject OpenHumansUploader openHumansUploader; @Inject OpenHumansUploader openHumansUploader;
private ScriptReader mScriptReader; private final ScriptReader mScriptReader;
private JSONObject mProfile; private JSONObject mProfile;
private JSONObject mGlucoseStatus; private JSONObject mGlucoseStatus;

View file

@ -80,6 +80,7 @@ public class OpenAPSAMAPlugin extends PluginBase implements APSInterface {
super(new PluginDescription() super(new PluginDescription()
.mainType(PluginType.APS) .mainType(PluginType.APS)
.fragmentClass(OpenAPSAMAFragment.class.getName()) .fragmentClass(OpenAPSAMAFragment.class.getName())
.pluginIcon(R.drawable.ic_generic_icon)
.pluginName(R.string.openapsama) .pluginName(R.string.openapsama)
.shortName(R.string.oaps_shortname) .shortName(R.string.oaps_shortname)
.preferencesId(R.xml.pref_openapsama) .preferencesId(R.xml.pref_openapsama)
@ -189,9 +190,9 @@ public class OpenAPSAMAPlugin extends PluginBase implements APSInterface {
} }
if (!hardLimits.checkOnlyHardLimits(profile.getDia(), "dia", hardLimits.getMINDIA(), hardLimits.getMAXDIA())) if (!hardLimits.checkOnlyHardLimits(profile.getDia(), "dia", hardLimits.minDia(), hardLimits.maxDia()))
return; return;
if (!hardLimits.checkOnlyHardLimits(profile.getIcTimeFromMidnight(Profile.secondsFromMidnight()), "carbratio", hardLimits.getMINIC(), hardLimits.getMAXIC())) if (!hardLimits.checkOnlyHardLimits(profile.getIcTimeFromMidnight(Profile.secondsFromMidnight()), "carbratio", hardLimits.minIC(), hardLimits.maxIC()))
return; return;
if (!hardLimits.checkOnlyHardLimits(profile.getIsfMgdl(), "sens", hardLimits.getMINISF(), hardLimits.getMAXISF())) if (!hardLimits.checkOnlyHardLimits(profile.getIsfMgdl(), "sens", hardLimits.getMINISF(), hardLimits.getMAXISF()))
return; return;

View file

@ -55,7 +55,7 @@ public class DetermineBasalAdapterSMBJS {
@Inject OpenHumansUploader openHumansUploader; @Inject OpenHumansUploader openHumansUploader;
private ScriptReader mScriptReader; private final ScriptReader mScriptReader;
private JSONObject mProfile; private JSONObject mProfile;
private JSONObject mGlucoseStatus; private JSONObject mGlucoseStatus;
private JSONArray mIobData; private JSONArray mIobData;
@ -65,6 +65,7 @@ public class DetermineBasalAdapterSMBJS {
private boolean mMicrobolusAllowed; private boolean mMicrobolusAllowed;
private boolean mSMBAlwaysAllowed; private boolean mSMBAlwaysAllowed;
private long mCurrentTime; private long mCurrentTime;
private boolean mIsSaveCgmSource;
private String storedCurrentTemp = null; private String storedCurrentTemp = null;
private String storedIobData = null; private String storedIobData = null;
@ -108,6 +109,7 @@ public class DetermineBasalAdapterSMBJS {
aapsLogger.debug(LTag.APS, "MicroBolusAllowed: " + (storedMicroBolusAllowed = "" + mMicrobolusAllowed)); aapsLogger.debug(LTag.APS, "MicroBolusAllowed: " + (storedMicroBolusAllowed = "" + mMicrobolusAllowed));
aapsLogger.debug(LTag.APS, "SMBAlwaysAllowed: " + (storedSMBAlwaysAllowed = "" + mSMBAlwaysAllowed)); aapsLogger.debug(LTag.APS, "SMBAlwaysAllowed: " + (storedSMBAlwaysAllowed = "" + mSMBAlwaysAllowed));
aapsLogger.debug(LTag.APS, "CurrentTime: " + (storedCurrentTime = "" + mCurrentTime)); aapsLogger.debug(LTag.APS, "CurrentTime: " + (storedCurrentTime = "" + mCurrentTime));
aapsLogger.debug(LTag.APS, "isSaveCgmSource: " + mIsSaveCgmSource);
DetermineBasalResultSMB determineBasalResultSMB = null; DetermineBasalResultSMB determineBasalResultSMB = null;
@ -237,7 +239,8 @@ public class DetermineBasalAdapterSMBJS {
boolean tempTargetSet, boolean tempTargetSet,
boolean microBolusAllowed, boolean microBolusAllowed,
boolean uamAllowed, boolean uamAllowed,
boolean advancedFiltering boolean advancedFiltering,
boolean isSaveCgmSource
) throws JSONException { ) throws JSONException {
String units = profile.getUnits(); String units = profile.getUnits();
@ -264,8 +267,8 @@ public class DetermineBasalAdapterSMBJS {
mProfile.put("low_temptarget_lowers_sensitivity", false); mProfile.put("low_temptarget_lowers_sensitivity", false);
mProfile.put("sensitivity_raises_target", sp.getBoolean(resourceHelper.gs(R.string.key_sensitivity_raises_target),SMBDefaults.sensitivity_raises_target)); mProfile.put("sensitivity_raises_target", sp.getBoolean(R.string.key_sensitivity_raises_target,SMBDefaults.sensitivity_raises_target));
mProfile.put("resistance_lowers_target", sp.getBoolean(resourceHelper.gs(R.string.key_resistance_lowers_target),SMBDefaults.resistance_lowers_target)); mProfile.put("resistance_lowers_target", sp.getBoolean(R.string.key_resistance_lowers_target,SMBDefaults.resistance_lowers_target));
mProfile.put("adv_target_adjustments", SMBDefaults.adv_target_adjustments); mProfile.put("adv_target_adjustments", SMBDefaults.adv_target_adjustments);
mProfile.put("exercise_mode", SMBDefaults.exercise_mode); mProfile.put("exercise_mode", SMBDefaults.exercise_mode);
mProfile.put("half_basal_exercise_target", SMBDefaults.half_basal_exercise_target); mProfile.put("half_basal_exercise_target", SMBDefaults.half_basal_exercise_target);
@ -281,8 +284,8 @@ public class DetermineBasalAdapterSMBJS {
mProfile.put("enableUAM", uamAllowed); mProfile.put("enableUAM", uamAllowed);
mProfile.put("A52_risk_enable", SMBDefaults.A52_risk_enable); mProfile.put("A52_risk_enable", SMBDefaults.A52_risk_enable);
boolean smbEnabled = sp.getBoolean(resourceHelper.gs(R.string.key_use_smb), false); boolean smbEnabled = sp.getBoolean(R.string.key_use_smb, false);
mProfile.put("SMBInterval", sp.getInt("key_smbinterval", SMBDefaults.SMBInterval)); mProfile.put("SMBInterval", sp.getInt(R.string.key_smbinterval, SMBDefaults.SMBInterval));
mProfile.put("enableSMB_with_COB", smbEnabled && sp.getBoolean(R.string.key_enableSMB_with_COB, false)); mProfile.put("enableSMB_with_COB", smbEnabled && sp.getBoolean(R.string.key_enableSMB_with_COB, false));
mProfile.put("enableSMB_with_temptarget", smbEnabled && sp.getBoolean(R.string.key_enableSMB_with_temptarget, false)); mProfile.put("enableSMB_with_temptarget", smbEnabled && sp.getBoolean(R.string.key_enableSMB_with_temptarget, false));
mProfile.put("allowSMB_with_high_temptarget", smbEnabled && sp.getBoolean(R.string.key_allowSMB_with_high_temptarget, false)); mProfile.put("allowSMB_with_high_temptarget", smbEnabled && sp.getBoolean(R.string.key_allowSMB_with_high_temptarget, false));
@ -354,6 +357,7 @@ public class DetermineBasalAdapterSMBJS {
mCurrentTime = now; mCurrentTime = now;
mIsSaveCgmSource = isSaveCgmSource;
} }
private Object makeParam(JSONObject jsonObject, Context rhino, Scriptable scope) { private Object makeParam(JSONObject jsonObject, Context rhino, Scriptable scope) {

View file

@ -88,6 +88,7 @@ public class OpenAPSSMBPlugin extends PluginBase implements APSInterface, Constr
super(new PluginDescription() super(new PluginDescription()
.mainType(PluginType.APS) .mainType(PluginType.APS)
.fragmentClass(OpenAPSSMBFragment.class.getName()) .fragmentClass(OpenAPSSMBFragment.class.getName())
.pluginIcon(R.drawable.ic_generic_icon)
.pluginName(R.string.openapssmb) .pluginName(R.string.openapssmb)
.shortName(R.string.smb_shortname) .shortName(R.string.smb_shortname)
.preferencesId(R.xml.pref_openapssmb) .preferencesId(R.xml.pref_openapssmb)
@ -220,9 +221,9 @@ public class OpenAPSSMBPlugin extends PluginBase implements APSInterface, Constr
} }
if (!hardLimits.checkOnlyHardLimits(profile.getDia(), "dia", hardLimits.getMINDIA(), hardLimits.getMAXDIA())) if (!hardLimits.checkOnlyHardLimits(profile.getDia(), "dia", hardLimits.minDia(), hardLimits.maxDia()))
return; return;
if (!hardLimits.checkOnlyHardLimits(profile.getIcTimeFromMidnight(Profile.secondsFromMidnight()), "carbratio", hardLimits.getMINIC(), hardLimits.getMAXIC())) if (!hardLimits.checkOnlyHardLimits(profile.getIcTimeFromMidnight(Profile.secondsFromMidnight()), "carbratio", hardLimits.minIC(), hardLimits.maxIC()))
return; return;
if (!hardLimits.checkOnlyHardLimits(profile.getIsfMgdl(), "sens", hardLimits.getMINISF(), hardLimits.getMAXISF())) if (!hardLimits.checkOnlyHardLimits(profile.getIsfMgdl(), "sens", hardLimits.getMINISF(), hardLimits.getMAXISF()))
return; return;
@ -270,7 +271,8 @@ public class OpenAPSSMBPlugin extends PluginBase implements APSInterface, Constr
isTempTarget, isTempTarget,
smbAllowed.value(), smbAllowed.value(),
uam.value(), uam.value(),
advancedFiltering.value() advancedFiltering.value(),
activePlugin.getActiveBgSource().getClass().getSimpleName().equals("DexcomPlugin")
); );
} catch (JSONException e) { } catch (JSONException e) {
fabricPrivacy.logException(e); fabricPrivacy.logException(e);

View file

@ -5,12 +5,9 @@ import android.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.CheckBox import android.widget.*
import android.widget.ImageButton
import android.widget.LinearLayout
import android.widget.RadioButton
import android.widget.TextView
import androidx.annotation.StringRes import androidx.annotation.StringRes
import androidx.core.content.ContextCompat
import dagger.android.support.DaggerFragment import dagger.android.support.DaggerFragment
import info.nightscout.androidaps.Config import info.nightscout.androidaps.Config
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
@ -129,6 +126,7 @@ class ConfigBuilderFragment : DaggerFragment() {
val baseView: LinearLayout = fragment.layoutInflater.inflate(R.layout.configbuilder_single_plugin, null) as LinearLayout val baseView: LinearLayout = fragment.layoutInflater.inflate(R.layout.configbuilder_single_plugin, null) as LinearLayout
private val enabledExclusive: RadioButton private val enabledExclusive: RadioButton
private val enabledInclusive: CheckBox private val enabledInclusive: CheckBox
private val pluginIcon: ImageView
private val pluginName: TextView private val pluginName: TextView
private val pluginDescription: TextView private val pluginDescription: TextView
private val pluginPreferences: ImageButton private val pluginPreferences: ImageButton
@ -137,6 +135,7 @@ class ConfigBuilderFragment : DaggerFragment() {
init { init {
enabledExclusive = baseView.findViewById(R.id.plugin_enabled_exclusive) enabledExclusive = baseView.findViewById(R.id.plugin_enabled_exclusive)
enabledInclusive = baseView.findViewById(R.id.plugin_enabled_inclusive) enabledInclusive = baseView.findViewById(R.id.plugin_enabled_inclusive)
pluginIcon = baseView.findViewById(R.id.plugin_icon)
pluginName = baseView.findViewById(R.id.plugin_name) pluginName = baseView.findViewById(R.id.plugin_name)
pluginDescription = baseView.findViewById(R.id.plugin_description) pluginDescription = baseView.findViewById(R.id.plugin_description)
pluginPreferences = baseView.findViewById(R.id.plugin_preferences) pluginPreferences = baseView.findViewById(R.id.plugin_preferences)
@ -175,6 +174,12 @@ class ConfigBuilderFragment : DaggerFragment() {
enabledInclusive.isChecked = plugin.isEnabled(pluginType) enabledInclusive.isChecked = plugin.isEnabled(pluginType)
enabledInclusive.isEnabled = !plugin.pluginDescription.alwaysEnabled enabledInclusive.isEnabled = !plugin.pluginDescription.alwaysEnabled
enabledExclusive.isEnabled = !plugin.pluginDescription.alwaysEnabled enabledExclusive.isEnabled = !plugin.pluginDescription.alwaysEnabled
if(plugin.menuIcon != -1) {
pluginIcon.visibility = View.VISIBLE
pluginIcon.setImageDrawable(context?.let { ContextCompat.getDrawable(it, plugin.menuIcon) })
} else {
pluginIcon.visibility = View.GONE
}
pluginName.text = plugin.name pluginName.text = plugin.name
if (plugin.description == null) if (plugin.description == null)
pluginDescription.visibility = View.GONE pluginDescription.visibility = View.GONE

View file

@ -32,6 +32,7 @@ class ConfigBuilderPlugin @Inject constructor(
.showInList(true) .showInList(true)
.alwaysEnabled(true) .alwaysEnabled(true)
.alwaysVisible(false) .alwaysVisible(false)
.pluginIcon(R.drawable.ic_cogs)
.pluginName(R.string.configbuilder) .pluginName(R.string.configbuilder)
.shortName(R.string.configbuilder_shortname) .shortName(R.string.configbuilder_shortname)
.description(R.string.description_config_builder), .description(R.string.description_config_builder),
@ -46,17 +47,17 @@ class ConfigBuilderPlugin @Inject constructor(
} }
private fun setAlwaysEnabledPluginsEnabled() { private fun setAlwaysEnabledPluginsEnabled() {
for (plugin in activePlugin.pluginsList) { for (plugin in activePlugin.getPluginsList()) {
if (plugin.pluginDescription.alwaysEnabled) plugin.setPluginEnabled(plugin.getType(), true) if (plugin.pluginDescription.alwaysEnabled) plugin.setPluginEnabled(plugin.getType(), true)
} }
storeSettings("setAlwaysEnabledPluginsEnabled") storeSettings("setAlwaysEnabledPluginsEnabled")
} }
override fun storeSettings(from: String) { override fun storeSettings(from: String) {
activePlugin.pluginsList activePlugin.getPluginsList()
aapsLogger.debug(LTag.CONFIGBUILDER, "Storing settings from: $from") aapsLogger.debug(LTag.CONFIGBUILDER, "Storing settings from: $from")
activePlugin.verifySelectionInCategories() activePlugin.verifySelectionInCategories()
for (p in activePlugin.pluginsList) { for (p in activePlugin.getPluginsList()) {
val type = p.getType() val type = p.getType()
if (p.pluginDescription.alwaysEnabled && p.pluginDescription.alwaysVisible) continue if (p.pluginDescription.alwaysEnabled && p.pluginDescription.alwaysVisible) continue
if (p.pluginDescription.alwaysEnabled && p.pluginDescription.neverVisible) continue if (p.pluginDescription.alwaysEnabled && p.pluginDescription.neverVisible) continue
@ -82,7 +83,7 @@ class ConfigBuilderPlugin @Inject constructor(
private fun loadSettings() { private fun loadSettings() {
aapsLogger.debug(LTag.CONFIGBUILDER, "Loading stored settings") aapsLogger.debug(LTag.CONFIGBUILDER, "Loading stored settings")
for (p in activePlugin.pluginsList) { for (p in activePlugin.getPluginsList()) {
val type = p.getType() val type = p.getType()
loadPref(p, type, true) loadPref(p, type, true)
if (p.getType() == PluginType.PUMP) { if (p.getType() == PluginType.PUMP) {
@ -110,7 +111,7 @@ class ConfigBuilderPlugin @Inject constructor(
} }
fun logPluginStatus() { fun logPluginStatus() {
for (p in activePlugin.pluginsList) { for (p in activePlugin.getPluginsList()) {
aapsLogger.debug(LTag.CONFIGBUILDER, p.name + ":" + aapsLogger.debug(LTag.CONFIGBUILDER, p.name + ":" +
(if (p.isEnabled(PluginType.GENERAL)) " GENERAL" else "") + (if (p.isEnabled(PluginType.GENERAL)) " GENERAL" else "") +
(if (p.isEnabled(PluginType.TREATMENT)) " TREATMENT" else "") + (if (p.isEnabled(PluginType.TREATMENT)) " TREATMENT" else "") +
@ -147,7 +148,7 @@ class ConfigBuilderPlugin @Inject constructor(
} }
} }
fun performPluginSwitch(changedPlugin: PluginBase, enabled: Boolean, type: PluginType) { override fun performPluginSwitch(changedPlugin: PluginBase, enabled: Boolean, type: PluginType) {
changedPlugin.setPluginEnabled(type, enabled) changedPlugin.setPluginEnabled(type, enabled)
changedPlugin.setFragmentVisible(type, enabled) changedPlugin.setFragmentVisible(type, enabled)
processOnEnabledCategoryChanged(changedPlugin, type) processOnEnabledCategoryChanged(changedPlugin, type)

View file

@ -15,13 +15,13 @@ class PluginStore @Inject constructor(
lateinit var plugins: List<@JvmSuppressWildcards PluginBase> lateinit var plugins: List<@JvmSuppressWildcards PluginBase>
private var activeBgSource: BgSourceInterface? = null private var activeBgSourceStore: BgSourceInterface? = null
private var activePump: PumpInterface? = null private var activePumpStore: PumpInterface? = null
private var activeProfile: ProfileInterface? = null private var activeProfile: ProfileInterface? = null
private var activeAPS: APSInterface? = null private var activeAPSStore: APSInterface? = null
private var activeInsulin: InsulinInterface? = null private var activeInsulinStore: InsulinInterface? = null
private var activeSensitivity: SensitivityInterface? = null private var activeSensitivityStore: SensitivityInterface? = null
private var activeTreatments: TreatmentsInterface? = null private var activeTreatmentsStore: TreatmentsInterface? = null
fun loadDefaults() { fun loadDefaults() {
verifySelectionInCategories() verifySelectionInCategories()
@ -71,34 +71,34 @@ class PluginStore @Inject constructor(
// PluginType.APS // PluginType.APS
if (!config.NSCLIENT && !config.PUMPCONTROL) { if (!config.NSCLIENT && !config.PUMPCONTROL) {
pluginsInCategory = getSpecificPluginsList(PluginType.APS) pluginsInCategory = getSpecificPluginsList(PluginType.APS)
activeAPS = getTheOneEnabledInArray(pluginsInCategory, PluginType.APS) as APSInterface? activeAPSStore = getTheOneEnabledInArray(pluginsInCategory, PluginType.APS) as APSInterface?
if (activeAPS == null) { if (activeAPSStore == null) {
activeAPS = getDefaultPlugin(PluginType.APS) as APSInterface activeAPSStore = getDefaultPlugin(PluginType.APS) as APSInterface
(activeAPS as PluginBase).setPluginEnabled(PluginType.APS, true) (activeAPSStore as PluginBase).setPluginEnabled(PluginType.APS, true)
aapsLogger.debug(LTag.CONFIGBUILDER, "Defaulting APSInterface") aapsLogger.debug(LTag.CONFIGBUILDER, "Defaulting APSInterface")
} }
setFragmentVisiblities((activeAPS as PluginBase).name, pluginsInCategory, PluginType.APS) setFragmentVisiblities((activeAPSStore as PluginBase).name, pluginsInCategory, PluginType.APS)
} }
// PluginType.INSULIN // PluginType.INSULIN
pluginsInCategory = getSpecificPluginsList(PluginType.INSULIN) pluginsInCategory = getSpecificPluginsList(PluginType.INSULIN)
activeInsulin = getTheOneEnabledInArray(pluginsInCategory, PluginType.INSULIN) as InsulinInterface? activeInsulinStore = getTheOneEnabledInArray(pluginsInCategory, PluginType.INSULIN) as InsulinInterface?
if (activeInsulin == null) { if (activeInsulinStore == null) {
activeInsulin = getDefaultPlugin(PluginType.INSULIN) as InsulinInterface activeInsulinStore = getDefaultPlugin(PluginType.INSULIN) as InsulinInterface
(activeInsulin as PluginBase).setPluginEnabled(PluginType.INSULIN, true) (activeInsulinStore as PluginBase).setPluginEnabled(PluginType.INSULIN, true)
aapsLogger.debug(LTag.CONFIGBUILDER, "Defaulting InsulinInterface") aapsLogger.debug(LTag.CONFIGBUILDER, "Defaulting InsulinInterface")
} }
setFragmentVisiblities((activeInsulin as PluginBase).name, pluginsInCategory, PluginType.INSULIN) setFragmentVisiblities((activeInsulinStore as PluginBase).name, pluginsInCategory, PluginType.INSULIN)
// PluginType.SENSITIVITY // PluginType.SENSITIVITY
pluginsInCategory = getSpecificPluginsList(PluginType.SENSITIVITY) pluginsInCategory = getSpecificPluginsList(PluginType.SENSITIVITY)
activeSensitivity = getTheOneEnabledInArray(pluginsInCategory, PluginType.SENSITIVITY) as SensitivityInterface? activeSensitivityStore = getTheOneEnabledInArray(pluginsInCategory, PluginType.SENSITIVITY) as SensitivityInterface?
if (activeSensitivity == null) { if (activeSensitivityStore == null) {
activeSensitivity = getDefaultPlugin(PluginType.SENSITIVITY) as SensitivityInterface activeSensitivityStore = getDefaultPlugin(PluginType.SENSITIVITY) as SensitivityInterface
(activeSensitivity as PluginBase).setPluginEnabled(PluginType.SENSITIVITY, true) (activeSensitivityStore as PluginBase).setPluginEnabled(PluginType.SENSITIVITY, true)
aapsLogger.debug(LTag.CONFIGBUILDER, "Defaulting SensitivityInterface") aapsLogger.debug(LTag.CONFIGBUILDER, "Defaulting SensitivityInterface")
} }
setFragmentVisiblities((activeSensitivity as PluginBase).name, pluginsInCategory, PluginType.SENSITIVITY) setFragmentVisiblities((activeSensitivityStore as PluginBase).name, pluginsInCategory, PluginType.SENSITIVITY)
// PluginType.PROFILE // PluginType.PROFILE
pluginsInCategory = getSpecificPluginsList(PluginType.PROFILE) pluginsInCategory = getSpecificPluginsList(PluginType.PROFILE)
@ -112,33 +112,33 @@ class PluginStore @Inject constructor(
// PluginType.BGSOURCE // PluginType.BGSOURCE
pluginsInCategory = getSpecificPluginsList(PluginType.BGSOURCE) pluginsInCategory = getSpecificPluginsList(PluginType.BGSOURCE)
activeBgSource = getTheOneEnabledInArray(pluginsInCategory, PluginType.BGSOURCE) as BgSourceInterface? activeBgSourceStore = getTheOneEnabledInArray(pluginsInCategory, PluginType.BGSOURCE) as BgSourceInterface?
if (activeBgSource == null) { if (activeBgSourceStore == null) {
activeBgSource = getDefaultPlugin(PluginType.BGSOURCE) as BgSourceInterface activeBgSourceStore = getDefaultPlugin(PluginType.BGSOURCE) as BgSourceInterface
(activeBgSource as PluginBase).setPluginEnabled(PluginType.BGSOURCE, true) (activeBgSourceStore as PluginBase).setPluginEnabled(PluginType.BGSOURCE, true)
aapsLogger.debug(LTag.CONFIGBUILDER, "Defaulting BgInterface") aapsLogger.debug(LTag.CONFIGBUILDER, "Defaulting BgInterface")
} }
setFragmentVisiblities((activeBgSource as PluginBase).name, pluginsInCategory, PluginType.PUMP) setFragmentVisiblities((activeBgSourceStore as PluginBase).name, pluginsInCategory, PluginType.PUMP)
// PluginType.PUMP // PluginType.PUMP
pluginsInCategory = getSpecificPluginsList(PluginType.PUMP) pluginsInCategory = getSpecificPluginsList(PluginType.PUMP)
activePump = getTheOneEnabledInArray(pluginsInCategory, PluginType.PUMP) as PumpInterface? activePumpStore = getTheOneEnabledInArray(pluginsInCategory, PluginType.PUMP) as PumpInterface?
if (activePump == null) { if (activePumpStore == null) {
activePump = getDefaultPlugin(PluginType.PUMP) as PumpInterface activePumpStore = getDefaultPlugin(PluginType.PUMP) as PumpInterface
(activePump as PluginBase).setPluginEnabled(PluginType.PUMP, true) (activePumpStore as PluginBase).setPluginEnabled(PluginType.PUMP, true)
aapsLogger.debug(LTag.CONFIGBUILDER, "Defaulting PumpInterface") aapsLogger.debug(LTag.CONFIGBUILDER, "Defaulting PumpInterface")
} }
setFragmentVisiblities((activePump as PluginBase).name, pluginsInCategory, PluginType.PUMP) setFragmentVisiblities((activePumpStore as PluginBase).name, pluginsInCategory, PluginType.PUMP)
// PluginType.TREATMENT // PluginType.TREATMENT
pluginsInCategory = getSpecificPluginsList(PluginType.TREATMENT) pluginsInCategory = getSpecificPluginsList(PluginType.TREATMENT)
activeTreatments = getTheOneEnabledInArray(pluginsInCategory, PluginType.TREATMENT) as TreatmentsInterface? activeTreatmentsStore = getTheOneEnabledInArray(pluginsInCategory, PluginType.TREATMENT) as TreatmentsInterface?
if (activeTreatments == null) { if (activeTreatmentsStore == null) {
activeTreatments = getDefaultPlugin(PluginType.TREATMENT) as TreatmentsInterface activeTreatmentsStore = getDefaultPlugin(PluginType.TREATMENT) as TreatmentsInterface
(activeTreatments as PluginBase).setPluginEnabled(PluginType.TREATMENT, true) (activeTreatmentsStore as PluginBase).setPluginEnabled(PluginType.TREATMENT, true)
aapsLogger.debug(LTag.CONFIGBUILDER, "Defaulting PumpInterface") aapsLogger.debug(LTag.CONFIGBUILDER, "Defaulting PumpInterface")
} }
setFragmentVisiblities((activeTreatments as PluginBase).name, pluginsInCategory, PluginType.TREATMENT) setFragmentVisiblities((activeTreatmentsStore as PluginBase).name, pluginsInCategory, PluginType.TREATMENT)
} }
/** /**
@ -203,27 +203,31 @@ class PluginStore @Inject constructor(
// ***** Interface ***** // ***** Interface *****
override fun getActiveBgSource(): BgSourceInterface { override val activeBgSource: BgSourceInterface
return activeBgSource ?: checkNotNull(activeBgSource) { "No bg source selected" } get() = activeBgSourceStore ?: checkNotNull(activeBgSourceStore) { "No bg source selected" }
}
override fun getActiveProfileInterface(): ProfileInterface = override val activeProfileInterface: ProfileInterface
activeProfile ?: checkNotNull(activeProfile) { "No profile selected" } get() = activeProfile ?: checkNotNull(activeProfile) { "No profile selected" }
override fun getActiveInsulin(): InsulinInterface = override val activeInsulin: InsulinInterface
activeInsulin ?: checkNotNull(activeInsulin) { "No insulin selected" } get() = activeInsulinStore ?: checkNotNull(activeInsulinStore) { "No insulin selected" }
override fun getActiveAPS(): APSInterface = override val activeAPS: APSInterface
activeAPS ?: checkNotNull(activeAPS) { "No APS selected" } get() = activeAPSStore ?: checkNotNull(activeAPSStore) { "No APS selected" }
override fun getActivePump(): PumpInterface = override val activePump: PumpInterface
activePump ?: checkNotNull(activePump) { "No pump selected" } get() = activePumpStore ?: checkNotNull(activePumpStore) { "No pump selected" }
override fun getActiveSensitivity(): SensitivityInterface = override val activeSensitivity: SensitivityInterface
activeSensitivity ?: checkNotNull(activeSensitivity) { "No sensitivity selected" } get() = activeSensitivityStore
?: checkNotNull(activeSensitivityStore) { "No sensitivity selected" }
override fun getActiveTreatments(): TreatmentsInterface = override val activeTreatments: TreatmentsInterface
activeTreatments ?: checkNotNull(activeTreatments) { "No treatments selected" } get() = activeTreatmentsStore
?: checkNotNull(activeTreatmentsStore) { "No treatments selected" }
override val activeOverview: OverviewInterface
get() = getSpecificPluginsListByInterface(OverviewInterface::class.java).first() as OverviewInterface
override fun getPluginsList(): ArrayList<PluginBase> = ArrayList(plugins) override fun getPluginsList(): ArrayList<PluginBase> = ArrayList(plugins)

View file

@ -2,5 +2,4 @@ package info.nightscout.androidaps.plugins.configBuilder.events
import info.nightscout.androidaps.events.EventUpdateGui import info.nightscout.androidaps.events.EventUpdateGui
class EventConfigBuilderUpdateGui : EventUpdateGui() { class EventConfigBuilderUpdateGui : EventUpdateGui()
}

View file

@ -1,6 +1,6 @@
package info.nightscout.androidaps.plugins.constraints.objectives package info.nightscout.androidaps.plugins.constraints.objectives
import android.app.Activity import androidx.fragment.app.FragmentActivity
import com.google.common.base.Charsets import com.google.common.base.Charsets
import com.google.common.hash.Hashing import com.google.common.hash.Hashing
import dagger.android.HasAndroidInjector import dagger.android.HasAndroidInjector
@ -32,6 +32,7 @@ class ObjectivesPlugin @Inject constructor(
.fragmentClass(ObjectivesFragment::class.qualifiedName) .fragmentClass(ObjectivesFragment::class.qualifiedName)
.alwaysEnabled(config.APS) .alwaysEnabled(config.APS)
.showInList(config.APS) .showInList(config.APS)
.pluginIcon(R.drawable.ic_graduation)
.pluginName(R.string.objectives) .pluginName(R.string.objectives)
.shortName(R.string.objectives_shortname) .shortName(R.string.objectives_shortname)
.description(R.string.description_objectives), .description(R.string.description_objectives),
@ -116,7 +117,7 @@ class ObjectivesPlugin @Inject constructor(
sp.putBoolean(R.string.key_objectiveusescale, false) sp.putBoolean(R.string.key_objectiveusescale, false)
} }
fun completeObjectives(activity: Activity, request: String) { fun completeObjectives(activity: FragmentActivity, request: String) {
val requestCode = sp.getString(R.string.key_objectives_request_code, "") val requestCode = sp.getString(R.string.key_objectives_request_code, "")
var url = sp.getString(R.string.key_nsclientinternal_url, "").toLowerCase(Locale.getDefault()) var url = sp.getString(R.string.key_nsclientinternal_url, "").toLowerCase(Locale.getDefault())
if (!url.endsWith("/")) url = "$url/" if (!url.endsWith("/")) url = "$url/"
@ -145,7 +146,7 @@ class ObjectivesPlugin @Inject constructor(
} }
} }
fun allPriorAccomplished(position: Int) : Boolean { fun allPriorAccomplished(position: Int): Boolean {
var accomplished = true var accomplished = true
for (i in 0 until position) { for (i in 0 until position) {
accomplished = accomplished && objectives[i].isAccomplished accomplished = accomplished && objectives[i].isAccomplished
@ -162,6 +163,12 @@ class ObjectivesPlugin @Inject constructor(
return value return value
} }
fun isLgsAllowed(value: Constraint<Boolean>): Constraint<Boolean> {
if (!objectives[MAXBASAL_OBJECTIVE].isStarted)
value.set(aapsLogger, false, String.format(resourceHelper.gs(R.string.objectivenotstarted), MAXBASAL_OBJECTIVE + 1), this)
return value
}
override fun isClosedLoopAllowed(value: Constraint<Boolean>): Constraint<Boolean> { override fun isClosedLoopAllowed(value: Constraint<Boolean>): Constraint<Boolean> {
if (!objectives[MAXIOB_ZERO_CL_OBJECTIVE].isStarted) if (!objectives[MAXIOB_ZERO_CL_OBJECTIVE].isStarted)
value.set(aapsLogger, false, String.format(resourceHelper.gs(R.string.objectivenotstarted), MAXIOB_ZERO_CL_OBJECTIVE + 1), this) value.set(aapsLogger, false, String.format(resourceHelper.gs(R.string.objectivenotstarted), MAXIOB_ZERO_CL_OBJECTIVE + 1), this)

View file

@ -8,6 +8,7 @@ import android.widget.CheckBox;
import android.widget.TextView; import android.widget.TextView;
import androidx.annotation.StringRes; import androidx.annotation.StringRes;
import androidx.fragment.app.FragmentActivity;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -25,9 +26,9 @@ public abstract class Objective {
@Inject public SP sp; @Inject public SP sp;
@Inject public ResourceHelper resourceHelper; @Inject public ResourceHelper resourceHelper;
private String spName; private final String spName;
@StringRes private int objective; @StringRes private final int objective;
@StringRes private int gate; @StringRes private final int gate;
private long startedOn; private long startedOn;
private long accomplishedOn; private long accomplishedOn;
List<Task> tasks = new ArrayList<>(); List<Task> tasks = new ArrayList<>();
@ -110,12 +111,12 @@ public abstract class Objective {
return true; return true;
} }
public void specialAction(Activity activity, String input) { public void specialAction(FragmentActivity activity, String input) {
} }
public abstract class Task { public abstract class Task {
@StringRes @StringRes
private int task; private final int task;
private Objective objective; private Objective objective;
ArrayList<Hint> hints = new ArrayList<>(); ArrayList<Hint> hints = new ArrayList<>();
@ -137,8 +138,6 @@ public abstract class Objective {
return isCompleted(); return isCompleted();
} }
;
public String getProgress() { public String getProgress() {
return resourceHelper.gs(isCompleted() ? R.string.completed_well_done : R.string.not_completed_yet); return resourceHelper.gs(isCompleted() ? R.string.completed_well_done : R.string.not_completed_yet);
} }
@ -159,7 +158,7 @@ public abstract class Objective {
public class MinimumDurationTask extends Task { public class MinimumDurationTask extends Task {
private long minimumDuration; private final long minimumDuration;
MinimumDurationTask(long minimumDuration) { MinimumDurationTask(long minimumDuration) {
super(R.string.time_elapsed); super(R.string.time_elapsed);
@ -196,7 +195,7 @@ public abstract class Objective {
@StringRes @StringRes
int question; int question;
ArrayList<Option> options = new ArrayList<>(); ArrayList<Option> options = new ArrayList<>();
private String spIdentifier; private final String spIdentifier;
private boolean answered; private boolean answered;
private long disabledTo; private long disabledTo;
@ -273,8 +272,7 @@ public abstract class Objective {
public boolean evaluate() { public boolean evaluate() {
boolean selection = cb.isChecked(); boolean selection = cb.isChecked();
if (selection && isCorrect) return true; if (selection && isCorrect) return true;
if (!selection && !isCorrect) return true; return !selection && !isCorrect;
return false;
} }
} }

View file

@ -48,7 +48,7 @@ public class Objective0 extends Objective {
tasks.add(new Task(R.string.virtualpump_uploadstatus_title) { tasks.add(new Task(R.string.virtualpump_uploadstatus_title) {
@Override @Override
public boolean isCompleted() { public boolean isCompleted() {
return sp.getBoolean("virtualpump_uploadstatus", false); return sp.getBoolean(R.string.key_virtualpump_uploadstatus, false);
} }
@Override @Override
@ -78,9 +78,7 @@ public class Objective0 extends Objective {
@Override @Override
public boolean isCompleted() { public boolean isCompleted() {
APSInterface usedAPS = activePlugin.getActiveAPS(); APSInterface usedAPS = activePlugin.getActiveAPS();
if (((PluginBase) usedAPS).isEnabled(PluginType.APS)) return ((PluginBase) usedAPS).isEnabled(PluginType.APS);
return true;
return false;
} }
}); });
tasks.add(new Task(R.string.activate_profile) { tasks.add(new Task(R.string.activate_profile) {

View file

@ -19,186 +19,197 @@ public class Objective2 extends Objective {
@Override @Override
protected void setupTasks(List<Task> tasks) { protected void setupTasks(List<Task> tasks) {
tasks.add(new ExamTask(R.string.prerequisites_label, R.string.prerequisites_what, "prerequisites")
.option(new Option(R.string.prerequisites_nightscout, true))
.option(new Option(R.string.prerequisites_computer, true))
.option(new Option(R.string.prerequisites_pump, true))
.option(new Option(R.string.prerequisites_beanandroiddeveloper, false))
.hint(new Hint(R.string.prerequisites_hint1))
);
tasks.add(new ExamTask(R.string.prerequisites2_label, R.string.prerequisites2_what, "prerequisites2")
.option(new Option(R.string.prerequisites2_profile, true))
.option(new Option(R.string.prerequisites2_device, true))
.option(new Option(R.string.prerequisites2_internet, false))
.option(new Option(R.string.prerequisites2_supportedcgm, true))
.hint(new Hint(R.string.prerequisites2_hint1))
);
tasks.add(new ExamTask(R.string.basaltest_label, R.string.basaltest_when,"basaltest")
.option(new Option(R.string.basaltest_fixed, false))
.option(new Option(R.string.basaltest_havingregularhighlow, true))
.option(new Option(R.string.basaltest_weekly, false))
.option(new Option(R.string.basaltest_beforeloop, true))
.hint(new Hint(R.string.basaltest_hint1))
);
tasks.add(new ExamTask(R.string.dia_label_exam, R.string.dia_whatmeansdia,"dia") tasks.add(new ExamTask(R.string.dia_label_exam, R.string.dia_whatmeansdia,"dia")
.option(new Option(R.string.dia_minimumis3h, false)) .option(new Option(R.string.dia_profile, true))
.option(new Option(R.string.dia_minimumis5h, true)) .option(new Option(R.string.dia_minimumis5h, true))
.option(new Option(R.string.dia_meaningisequaltodiapump, false)) .option(new Option(R.string.dia_meaningisequaltodiapump, false))
.option(new Option(R.string.dia_valuemustbedetermined, true)) .option(new Option(R.string.dia_valuemustbedetermined, true))
.hint(new Hint(R.string.dia_hint1)) .hint(new Hint(R.string.dia_hint1))
); );
tasks.add(new ExamTask(R.string.isf_label_exam, R.string.blank,"isf")
.option(new Option(R.string.isf_decreasingvalue, true))
.option(new Option(R.string.isf_preferences, false))
.option(new Option(R.string.isf_increasingvalue, false))
.option(new Option(R.string.isf_noeffect, false))
.hint(new Hint(R.string.isf_hint1))
.hint(new Hint(R.string.isf_hint2))
);
tasks.add(new ExamTask(R.string.ic_label_exam, R.string.blank,"ic")
.option(new Option(R.string.ic_increasingvalue, true))
.option(new Option(R.string.ic_decreasingvalue, false))
.option(new Option(R.string.ic_multiple, true))
.option(new Option(R.string.ic_isf, false))
.hint(new Hint(R.string.ic_hint1))
);
tasks.add(new ExamTask(R.string.hypott_label, R.string.hypott_whenhypott,"hypott") tasks.add(new ExamTask(R.string.hypott_label, R.string.hypott_whenhypott,"hypott")
.option(new Option(R.string.hypott_goinglow, false))
.option(new Option(R.string.hypott_preventoversmb, true)) .option(new Option(R.string.hypott_preventoversmb, true))
.option(new Option(R.string.hypott_exercise, false))
.option(new Option(R.string.hypott_wrongbasal, false))
.option(new Option(R.string.hypott_0basal, false))
.hint(new Hint(R.string.hypott_hint1)) .hint(new Hint(R.string.hypott_hint1))
); );
tasks.add(new ExamTask(R.string.offlineprofile_label, R.string.offlineprofile_whatprofile,"offlineprofile") tasks.add(new ExamTask(R.string.profileswitch_label, R.string.profileswitch_pctwillchange,"profileswitch")
.option(new Option(R.string.localprofile, true)) .option(new Option(R.string.profileswitch_basallower, true))
.option(new Option(R.string.nsprofile, false)) .option(new Option(R.string.profileswitch_isfhigher, true))
.option(new Option(R.string.offlineprofile_nsprofile, true)) .option(new Option(R.string.profileswitch_iclower, false))
.hint(new Hint(R.string.offlineprofile_hint1)) .option(new Option(R.string.profileswitch_unchanged, false))
.hint(new Hint(R.string.profileswitch_hint1))
); );
tasks.add(new ExamTask(R.string.pumpdisconnect_label, R.string.pumpdisconnect_label,"pumpdisconnect") tasks.add(new ExamTask(R.string.profileswitch2_label, R.string.profileswitch2_pctwillchange,"profileswitch2")
.option(new Option(R.string.pumpdisconnect_letknow, true)) .option(new Option(R.string.profileswitch2_bghigher, false))
.option(new Option(R.string.pumpdisconnect_suspend, false)) .option(new Option(R.string.profileswitch2_basalhigher, true))
.option(new Option(R.string.pumpdisconnect_dontchnage, false)) .option(new Option(R.string.profileswitch2_bgunchanged, true))
.hint(new Hint(R.string.pumpdisconnect_hint1)) .option(new Option(R.string.profileswitch2_isfhigher, false))
.hint(new Hint(R.string.profileswitch_hint1))
); );
tasks.add(new ExamTask(R.string.objectives_label, R.string.objectives_howtosave,"objectives") tasks.add(new ExamTask(R.string.profileswitchtime_label, R.string.profileswitchtime_iwant,"profileswitchtime")
.option(new Option(R.string.objectives_exportsettings, true)) .option(new Option(R.string.profileswitchtime_2, false))
.option(new Option(R.string.objectives_storeelsewhere, true)) .option(new Option(R.string.profileswitchtime__2, true))
.option(new Option(R.string.objectives_doexportonstart, false)) .option(new Option(R.string.profileswitchtime_tt, false))
.option(new Option(R.string.objectives_doexportafterchange, true)) .option(new Option(R.string.profileswitchtime_100, false))
.option(new Option(R.string.objectives_doexportafterobjective, true)) .hint(new Hint(R.string.profileswitchtime_hint1))
.option(new Option(R.string.objectives_doexportafterfirtssettings, true)) );
.hint(new Hint(R.string.objectives_hint1)) tasks.add(new ExamTask(R.string.profileswitch4_label, R.string.blank,"profileswitch4")
.hint(new Hint(R.string.objectives_hint2)) .option(new Option(R.string.profileswitch4_rates, true))
.option(new Option(R.string.profileswitch4_internet, true))
.option(new Option(R.string.profileswitch4_sufficient, false))
.option(new Option(R.string.profileswitch4_multi, true))
.hint(new Hint(R.string.profileswitch_hint1))
);
tasks.add(new ExamTask(R.string.exerciseprofile_label, R.string.exerciseprofile_whattodo,"exercise")
.option(new Option(R.string.exerciseprofile_switchprofileabove100, false))
.option(new Option(R.string.exerciseprofile_switchprofilebelow100, true))
.option(new Option(R.string.exerciseprofile_suspendloop, false))
.option(new Option(R.string.exerciseprofile_leaveat100, false))
.hint(new Hint(R.string.exerciseprofile_hint1))
);
tasks.add(new ExamTask(R.string.exercise_label, R.string.exercise_whattodo,"exercise2")
.option(new Option(R.string.exercise_settt, true))
.option(new Option(R.string.exercise_setfinished, false))
.option(new Option(R.string.exercise_setunchanged, false))
.option(new Option(R.string.exercise_15g, false))
.hint(new Hint(R.string.exercise_hint1))
); );
tasks.add(new ExamTask(R.string.noisycgm_label, R.string.noisycgm_whattodo,"noisycgm") tasks.add(new ExamTask(R.string.noisycgm_label, R.string.noisycgm_whattodo,"noisycgm")
.option(new Option(R.string.nothing, false)) .option(new Option(R.string.noisycgm_nothing, false))
.option(new Option(R.string.disconnectpumpfor1h, false))
.option(new Option(R.string.noisycgm_pause, true)) .option(new Option(R.string.noisycgm_pause, true))
.option(new Option(R.string.noisycgm_replacesensor, true)) .option(new Option(R.string.noisycgm_replacesensor, true))
.option(new Option(R.string.noisycgm_turnoffphone, false))
.option(new Option(R.string.noisycgm_checksmoothing, true)) .option(new Option(R.string.noisycgm_checksmoothing, true))
.hint(new Hint(R.string.noisycgm_hint1)) .hint(new Hint(R.string.noisycgm_hint1))
); );
tasks.add(new ExamTask(R.string.exercise_label, R.string.exercise_whattodo,"exercise") tasks.add(new ExamTask(R.string.pumpdisconnect_label, R.string.blank,"pumpdisconnect")
.option(new Option(R.string.nothing, false)) .option(new Option(R.string.pumpdisconnect_unnecessary, false))
.option(new Option(R.string.exercise_setactivitytt, true)) .option(new Option(R.string.pumpdisconnect_missinginsulin, true))
.option(new Option(R.string.exercise_switchprofilebelow100, true)) .option(new Option(R.string.pumpdisconnect_notstop, false))
.option(new Option(R.string.exercise_switchprofileabove100, false)) .option(new Option(R.string.pumpdisconnect_openloop, false))
.option(new Option(R.string.exercise_stoploop, false)) .hint(new Hint(R.string.pumpdisconnect_hint1))
.option(new Option(R.string.exercise_doitbeforestart, true))
.option(new Option(R.string.exercise_afterstart, true))
.hint(new Hint(R.string.exercise_hint1))
); );
tasks.add(new ExamTask(R.string.suspendloop_label, R.string.suspendloop_doigetinsulin,"suspendloop") tasks.add(new ExamTask(R.string.insulin_label, R.string.insulin_ultrarapid,"insulin")
.option(new Option(R.string.suspendloop_yes, true)) .option(new Option(R.string.insulin_novorapid, false))
.option(new Option(R.string.suspendloop_no, false)) .option(new Option(R.string.insulin_humalog, false))
.option(new Option(R.string.insulin_actrapid, false))
.option(new Option(R.string.insulin_fiasp, true))
.hint(new Hint(R.string.insulin_hint1))
); );
tasks.add(new ExamTask(R.string.basaltest_label, R.string.basaltest_when,"basaltest") tasks.add(new ExamTask(R.string.sensitivity_label, R.string.blank,"sensitivity")
.option(new Option(R.string.basaltest_beforeloop, true)) .option(new Option(R.string.sensitivity_adjust, true))
.option(new Option(R.string.basaltest_havingregularhypo, true)) .option(new Option(R.string.sensitivity_edit, false))
.option(new Option(R.string.basaltest_havingregularhyper, true)) .option(new Option(R.string.sensitivity_cannula, true))
.hint(new Hint(R.string.basaltest_hint1)) .option(new Option(R.string.sensitivity_time, true))
.hint(new Hint(R.string.sensitivity_hint1))
); );
tasks.add(new ExamTask(R.string.basalhelp_label, R.string.basalhelp_where,"basalhelp") tasks.add(new ExamTask(R.string.objectives_label, R.string.objectives_howtosave,"objectives")
.option(new Option(R.string.basalhelp_diabetesteam, true)) .option(new Option(R.string.objectives_notesettings, false))
.option(new Option(R.string.basalhelp_google, false)) .option(new Option(R.string.objectives_afterobjective, true))
.option(new Option(R.string.basalhelp_facebook, false)) .option(new Option(R.string.objectives_afterchange, true))
.hint(new Hint(R.string.basalhelp_hint1)) .option(new Option(R.string.objectives_afterinitialsetup, true))
.hint(new Hint(R.string.objectives_hint1))
.hint(new Hint(R.string.objectives_hint2))
); );
tasks.add(new ExamTask(R.string.prerequisites_label, R.string.prerequisites_what, "prerequisites") tasks.add(new ExamTask(R.string.objectives2_label, R.string.objectives_howtosave,"objectives2")
.option(new Option(R.string.prerequisites_determinedcorrectprofile, true)) .option(new Option(R.string.objectives2_maintenance, true))
.option(new Option(R.string.prerequisites_computer, true)) .option(new Option(R.string.objectives2_internalstorage, true))
.option(new Option(R.string.prerequisites_phone, true)) .option(new Option(R.string.objectives2_cloud, true))
.option(new Option(R.string.prerequisites_car, false)) .option(new Option(R.string.objectives2_easyrestore, false))
.option(new Option(R.string.prerequisites_nightscout, true)) .hint(new Hint(R.string.objectives_hint1))
.option(new Option(R.string.prerequisites_tidepoolaccount, false)) .hint(new Hint(R.string.objectives_hint2))
.option(new Option(R.string.prerequisites_googleaccount, false))
.option(new Option(R.string.prerequisites_githubaccount, false))
.option(new Option(R.string.prerequisites_beanandroiddeveloper, false))
.option(new Option(R.string.prerequisites_own670g, false))
.option(new Option(R.string.prerequisites_smartwatch, false))
.option(new Option(R.string.prerequisites_supportedcgm, true))
.hint(new Hint(R.string.prerequisites_hint1))
); );
tasks.add(new ExamTask(R.string.update_label, R.string.whatistrue,"update") tasks.add(new ExamTask(R.string.update_label, R.string.blank,"update")
.option(new Option(R.string.update_git, true)) .option(new Option(R.string.update_git, true))
.option(new Option(R.string.update_asap, true))
.option(new Option(R.string.update_keys, true))
.option(new Option(R.string.update_neverupdate, false))
.option(new Option(R.string.update_askfriend, false)) .option(new Option(R.string.update_askfriend, false))
.option(new Option(R.string.update_keys, true))
.option(new Option(R.string.update_asap, true))
.hint(new Hint(R.string.update_hint1)) .hint(new Hint(R.string.update_hint1))
); );
tasks.add(new ExamTask(R.string.troubleshooting_label, R.string.troubleshooting_wheretoask,"troubleshooting") tasks.add(new ExamTask(R.string.troubleshooting_label, R.string.troubleshooting_wheretoask,"troubleshooting")
.option(new Option(R.string.troubleshooting_fb, true)) .option(new Option(R.string.troubleshooting_fb, true))
.option(new Option(R.string.troubleshooting_wiki, true)) .option(new Option(R.string.troubleshooting_wiki, true))
.option(new Option(R.string.troubleshooting_gitter, true)) .option(new Option(R.string.troubleshooting_gitter, true))
.option(new Option(R.string.troubleshooting_googlesupport, false))
.option(new Option(R.string.troubleshooting_yourendo, false)) .option(new Option(R.string.troubleshooting_yourendo, false))
.hint(new Hint(R.string.troubleshooting_hint1)) .hint(new Hint(R.string.troubleshooting_hint1))
.hint(new Hint(R.string.troubleshooting_hint2)) .hint(new Hint(R.string.troubleshooting_hint2))
.hint(new Hint(R.string.troubleshooting_hint3)) .hint(new Hint(R.string.troubleshooting_hint3))
); );
tasks.add(new ExamTask(R.string.insulin_label, R.string.insulin_ultrarapid,"insulin")
.option(new Option(R.string.insulin_fiasp, true))
.option(new Option(R.string.insulin_novorapid, false))
.option(new Option(R.string.insulin_humalog, false))
.option(new Option(R.string.insulin_actrapid, false))
.hint(new Hint(R.string.insulin_hint1))
);
tasks.add(new ExamTask(R.string.sensitivity_label, R.string.sensitivity_which,"sensitivity")
.option(new Option(R.string.sensitivityweightedaverage, true))
.option(new Option(R.string.sensitivityoref1, false))
.option(new Option(R.string.sensitivityaaps, true))
.hint(new Hint(R.string.sensitivity_hint1))
);
tasks.add(new ExamTask(R.string.sensitivity_label, R.string.sensitivityuam_which,"sensitivityuam")
.option(new Option(R.string.sensitivityweightedaverage, false))
.option(new Option(R.string.sensitivityoref1, true))
.option(new Option(R.string.sensitivityaaps, false))
.hint(new Hint(R.string.sensitivity_hint1))
);
tasks.add(new ExamTask(R.string.wrongcarbs_label, R.string.wrongcarbs_whattodo,"wrongcarbs") tasks.add(new ExamTask(R.string.wrongcarbs_label, R.string.wrongcarbs_whattodo,"wrongcarbs")
.option(new Option(R.string.wrongcarbs_addfakeinsulin, false)) .option(new Option(R.string.wrongcarbs_addinsulin, false))
.option(new Option(R.string.wrongcarbs_treatmentstab, true)) .option(new Option(R.string.wrongcarbs_treatmentstab, true))
.option(new Option(R.string.wrongcarbs_donothing, false))
.option(new Option(R.string.wrongcarbs_bolus, false))
);
tasks.add(new ExamTask(R.string.wronginsulin_label, R.string.wronginsulin_whattodo,"wronginsulin")
.option(new Option(R.string.wronginsulin_careportal, false))
.option(new Option(R.string.wronginsulin_compare, true))
.option(new Option(R.string.wronginsulin_prime, true))
.option(new Option(R.string.wrongcarbs_donothing, false))
);
tasks.add(new ExamTask(R.string.iob_label, R.string.blank,"iob")
.option(new Option(R.string.iob_value, true))
.option(new Option(R.string.iob_hightemp, false))
.option(new Option(R.string.iob_negiob, true))
.option(new Option(R.string.iob_posiob, true))
);
tasks.add(new ExamTask(R.string.breadgrams_label, R.string.blank,"breadgrams")
.option(new Option(R.string.breadgrams_grams, true))
.option(new Option(R.string.breadgrams_exchange, false))
.option(new Option(R.string.breadgrams_decay, true))
.option(new Option(R.string.breadgrams_calc, true))
.hint(new Hint(R.string.breadgrams_hint1))
); );
tasks.add(new ExamTask(R.string.extendedcarbs_label, R.string.extendedcarbs_handling,"extendedcarbs") tasks.add(new ExamTask(R.string.extendedcarbs_label, R.string.extendedcarbs_handling,"extendedcarbs")
.option(new Option(R.string.extendedcarbs_useextendedcarbs, true)) .option(new Option(R.string.extendedcarbs_future, true))
.option(new Option(R.string.extendedcarbs_add, false)) .option(new Option(R.string.extendedcarbs_free, false))
.option(new Option(R.string.extendedcarbs_useextendedbolus, false)) .option(new Option(R.string.extendedcarbs_fat, true))
.option(new Option(R.string.extendedcarbs_rescue, false))
.hint(new Hint(R.string.extendedcarbs_hint1)) .hint(new Hint(R.string.extendedcarbs_hint1))
); );
tasks.add(new ExamTask(R.string.nsclient_label, R.string.nsclient_howcanyou,"nsclient") tasks.add(new ExamTask(R.string.nsclient_label, R.string.nsclient_howcanyou,"nsclient")
.option(new Option(R.string.nsclient_nightscout, true)) .option(new Option(R.string.nsclient_nightscout, true))
.option(new Option(R.string.nsclientinternal, true))
.option(new Option(R.string.nsclient_dexcomfollow, true)) .option(new Option(R.string.nsclient_dexcomfollow, true))
.option(new Option(R.string.nsclient_dexcomfollowxdrip, false)) .option(new Option(R.string.nsclient_data, true))
.option(new Option(R.string.nsclient_xdripfollower, true)) .option(new Option(R.string.nsclient_fullcontrol, false))
.option(new Option(R.string.nsclient_looponiphone, false))
.option(new Option(R.string.nsclient_spikeiphone, true))
.hint(new Hint(R.string.nsclient_hint1)) .hint(new Hint(R.string.nsclient_hint1))
); );
tasks.add(new ExamTask(R.string.isf_label_exam, R.string.whatistrue,"isf")
.option(new Option(R.string.isf_increasingvalue, true))
.option(new Option(R.string.isf_decreasingvalue, false))
.option(new Option(R.string.isf_noeffect, false))
.option(new Option(R.string.isf_preferences, false))
.option(new Option(R.string.isf_profile, false))
.hint(new Hint(R.string.isf_hint1))
.hint(new Hint(R.string.isf_hint2))
);
tasks.add(new ExamTask(R.string.ic_label_exam, R.string.whatistrue,"ic")
.option(new Option(R.string.ic_increasingvalue, true))
.option(new Option(R.string.ic_decreasingvalue, false))
.option(new Option(R.string.ic_noeffect, false))
.option(new Option(R.string.ic_different, false))
.option(new Option(R.string.ic_meaning, false))
.hint(new Hint(R.string.ic_hint1))
);
tasks.add(new ExamTask(R.string.profileswitch_label, R.string.profileswitch_pctwillchange,"profileswitch")
.option(new Option(R.string.profileswitch_basalhigher, false))
.option(new Option(R.string.profileswitch_basallower, true))
.option(new Option(R.string.profileswitch_ichigher, true))
.option(new Option(R.string.profileswitch_iclower, false))
.option(new Option(R.string.profileswitch_isfhigher, true))
.option(new Option(R.string.profileswitch_isflower, false))
.option(new Option(R.string.profileswitch_overall, true))
.option(new Option(R.string.profileswitch_targethigher, false))
.option(new Option(R.string.profileswitch_targetlower, false))
.option(new Option(R.string.profileswitch_targetbottom, false))
.hint(new Hint(R.string.profileswitch_hint1))
);
tasks.add(new ExamTask(R.string.profileswitch_label, R.string.profileswitchtime_iwant,"profileswitchtime")
.option(new Option(R.string.profileswitchtime_1, false))
.option(new Option(R.string.profileswitchtime__1, true))
.option(new Option(R.string.profileswitchtime_60, false))
.option(new Option(R.string.profileswitchtime__60, false))
.hint(new Hint(R.string.profileswitchtime_hint1))
);
tasks.add(new ExamTask(R.string.other_medication_label, R.string.other_medication_text,"otherMedicationWarning") tasks.add(new ExamTask(R.string.other_medication_label, R.string.other_medication_text,"otherMedicationWarning")
.option(new Option(R.string.yes, true)) .option(new Option(R.string.yes, true))
.option(new Option(R.string.no, false)) .option(new Option(R.string.no, false))

View file

@ -1,6 +1,6 @@
package info.nightscout.androidaps.plugins.constraints.objectives.objectives; package info.nightscout.androidaps.plugins.constraints.objectives.objectives;
import android.app.Activity; import androidx.fragment.app.FragmentActivity;
import java.util.List; import java.util.List;
@ -10,6 +10,7 @@ import dagger.android.HasAndroidInjector;
import info.nightscout.androidaps.R; import info.nightscout.androidaps.R;
import info.nightscout.androidaps.plugins.constraints.objectives.ObjectivesPlugin; import info.nightscout.androidaps.plugins.constraints.objectives.ObjectivesPlugin;
import info.nightscout.androidaps.plugins.general.nsclient.NSClientPlugin; import info.nightscout.androidaps.plugins.general.nsclient.NSClientPlugin;
import info.nightscout.androidaps.plugins.general.nsclient.services.NSClientService;
import info.nightscout.androidaps.utils.T; import info.nightscout.androidaps.utils.T;
import info.nightscout.androidaps.utils.resources.ResourceHelper; import info.nightscout.androidaps.utils.resources.ResourceHelper;
import info.nightscout.androidaps.utils.sharedPreferences.SP; import info.nightscout.androidaps.utils.sharedPreferences.SP;
@ -50,11 +51,11 @@ public class Objective3 extends Objective {
@Override @Override
public boolean specialActionEnabled() { public boolean specialActionEnabled() {
return nsClientPlugin.nsClientService.isConnected && nsClientPlugin.nsClientService.hasWriteAuth; return NSClientService.isConnected && NSClientService.hasWriteAuth;
} }
@Override @Override
public void specialAction(Activity activity, String input) { public void specialAction(FragmentActivity activity, String input) {
objectivesPlugin.completeObjectives(activity, input); objectivesPlugin.completeObjectives(activity, input);
} }
} }

View file

@ -36,12 +36,12 @@ class PhoneCheckerPlugin @Inject constructor(
private fun isDevModeEnabled(): Boolean { private fun isDevModeEnabled(): Boolean {
return android.provider.Settings.Secure.getInt(context.contentResolver, return android.provider.Settings.Secure.getInt(context.contentResolver,
android.provider.Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 0) != 0; android.provider.Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 0) != 0
} }
override fun onStart() { override fun onStart() {
super.onStart() super.onStart()
phoneRooted = RootBeer(context).isRooted() phoneRooted = RootBeer(context).isRooted
devMode = isDevModeEnabled() devMode = isDevModeEnabled()
} }
} }

View file

@ -37,17 +37,17 @@ import info.nightscout.androidaps.utils.sharedPreferences.SP;
@Singleton @Singleton
public class SafetyPlugin extends PluginBase implements ConstraintsInterface { public class SafetyPlugin extends PluginBase implements ConstraintsInterface {
private SP sp; private final SP sp;
private RxBusWrapper rxBus; private final RxBusWrapper rxBus;
private ConstraintChecker constraintChecker; private final ConstraintChecker constraintChecker;
private OpenAPSAMAPlugin openAPSAMAPlugin; private final OpenAPSAMAPlugin openAPSAMAPlugin;
private OpenAPSSMBPlugin openAPSSMBPlugin; private final OpenAPSSMBPlugin openAPSSMBPlugin;
private SensitivityOref1Plugin sensitivityOref1Plugin; private final SensitivityOref1Plugin sensitivityOref1Plugin;
private ActivePluginProvider activePlugin; private final ActivePluginProvider activePlugin;
private HardLimits hardLimits; private final HardLimits hardLimits;
private BuildHelper buildHelper; private final BuildHelper buildHelper;
private TreatmentsPlugin treatmentsPlugin; private final TreatmentsPlugin treatmentsPlugin;
private Config config; private final Config config;
@Inject @Inject
public SafetyPlugin( public SafetyPlugin(

View file

@ -1,7 +1,9 @@
package info.nightscout.androidaps.plugins.general.actions package info.nightscout.androidaps.plugins.general.actions
import android.content.Context
import android.content.Intent import android.content.Intent
import android.os.Bundle import android.os.Bundle
import android.util.DisplayMetrics
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
@ -9,7 +11,7 @@ import android.widget.LinearLayout
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import dagger.android.support.DaggerFragment import dagger.android.support.DaggerFragment
import info.nightscout.androidaps.Config import info.nightscout.androidaps.Config
import info.nightscout.androidaps.MainApp import info.nightscout.androidaps.Constants
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.activities.ErrorHelperActivity import info.nightscout.androidaps.activities.ErrorHelperActivity
import info.nightscout.androidaps.activities.TDDStatsActivity import info.nightscout.androidaps.activities.TDDStatsActivity
@ -24,6 +26,7 @@ import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.plugins.general.actions.defs.CustomAction import info.nightscout.androidaps.plugins.general.actions.defs.CustomAction
import info.nightscout.androidaps.plugins.general.overview.StatusLightHandler import info.nightscout.androidaps.plugins.general.overview.StatusLightHandler
import info.nightscout.androidaps.queue.Callback import info.nightscout.androidaps.queue.Callback
import info.nightscout.androidaps.skins.SkinProvider
import info.nightscout.androidaps.utils.FabricPrivacy import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.alertDialogs.OKDialog import info.nightscout.androidaps.utils.alertDialogs.OKDialog
import info.nightscout.androidaps.utils.buildHelper.BuildHelper import info.nightscout.androidaps.utils.buildHelper.BuildHelper
@ -42,11 +45,12 @@ import java.util.*
import javax.inject.Inject import javax.inject.Inject
class ActionsFragment : DaggerFragment() { class ActionsFragment : DaggerFragment() {
@Inject lateinit var aapsLogger: AAPSLogger @Inject lateinit var aapsLogger: AAPSLogger
@Inject lateinit var rxBus: RxBusWrapper @Inject lateinit var rxBus: RxBusWrapper
@Inject lateinit var sp: SP @Inject lateinit var sp: SP
@Inject lateinit var profileFunction: ProfileFunction @Inject lateinit var profileFunction: ProfileFunction
@Inject lateinit var mainApp: MainApp @Inject lateinit var ctx: Context
@Inject lateinit var resourceHelper: ResourceHelper @Inject lateinit var resourceHelper: ResourceHelper
@Inject lateinit var statusLightHandler: StatusLightHandler @Inject lateinit var statusLightHandler: StatusLightHandler
@Inject lateinit var fabricPrivacy: FabricPrivacy @Inject lateinit var fabricPrivacy: FabricPrivacy
@ -54,16 +58,30 @@ class ActionsFragment : DaggerFragment() {
@Inject lateinit var commandQueue: CommandQueueProvider @Inject lateinit var commandQueue: CommandQueueProvider
@Inject lateinit var buildHelper: BuildHelper @Inject lateinit var buildHelper: BuildHelper
@Inject lateinit var protectionCheck: ProtectionCheck @Inject lateinit var protectionCheck: ProtectionCheck
@Inject lateinit var skinProvider: SkinProvider
@Inject lateinit var config: Config @Inject lateinit var config: Config
private var disposable: CompositeDisposable = CompositeDisposable() private var disposable: CompositeDisposable = CompositeDisposable()
private val pumpCustomActions = HashMap<String, CustomAction>() private val pumpCustomActions = HashMap<String, CustomAction>()
private val pumpCustomButtons = ArrayList<SingleClickButton>() private val pumpCustomButtons = ArrayList<SingleClickButton>()
private var smallWidth = false
private var smallHeight = false
private lateinit var dm: DisplayMetrics
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? { savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.actions_fragment, container, false) //check screen width
dm = DisplayMetrics()
activity?.windowManager?.defaultDisplay?.getMetrics(dm)
val screenWidth = dm.widthPixels
val screenHeight = dm.heightPixels
smallWidth = screenWidth <= Constants.SMALL_WIDTH
smallHeight = screenHeight <= Constants.SMALL_HEIGHT
val landscape = screenHeight < screenWidth
return inflater.inflate(skinProvider.activeSkin().actionsLayout(landscape, smallWidth), container, false)
} }
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
@ -77,12 +95,12 @@ class ActionsFragment : DaggerFragment() {
} }
actions_extendedbolus.setOnClickListener { actions_extendedbolus.setOnClickListener {
activity?.let { activity -> activity?.let { activity ->
protectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, UIRunnable(Runnable { protectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, UIRunnable {
OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.extended_bolus), resourceHelper.gs(R.string.ebstopsloop), OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.extended_bolus), resourceHelper.gs(R.string.ebstopsloop),
Runnable { Runnable {
ExtendedBolusDialog().show(childFragmentManager, "Actions") ExtendedBolusDialog().show(childFragmentManager, "Actions")
}, null) }, null)
})) })
} }
} }
actions_extendedbolus_cancel.setOnClickListener { actions_extendedbolus_cancel.setOnClickListener {
@ -91,12 +109,12 @@ class ActionsFragment : DaggerFragment() {
commandQueue.cancelExtended(object : Callback() { commandQueue.cancelExtended(object : Callback() {
override fun run() { override fun run() {
if (!result.success) { if (!result.success) {
val i = Intent(mainApp, ErrorHelperActivity::class.java) val i = Intent(ctx, ErrorHelperActivity::class.java)
i.putExtra("soundid", R.raw.boluserror) i.putExtra("soundid", R.raw.boluserror)
i.putExtra("status", result.comment) i.putExtra("status", result.comment)
i.putExtra("title", resourceHelper.gs(R.string.extendedbolusdeliveryerror)) i.putExtra("title", resourceHelper.gs(R.string.extendedbolusdeliveryerror))
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
mainApp.startActivity(i) ctx.startActivity(i)
} }
} }
}) })
@ -111,12 +129,12 @@ class ActionsFragment : DaggerFragment() {
commandQueue.cancelTempBasal(true, object : Callback() { commandQueue.cancelTempBasal(true, object : Callback() {
override fun run() { override fun run() {
if (!result.success) { if (!result.success) {
val i = Intent(mainApp, ErrorHelperActivity::class.java) val i = Intent(ctx, ErrorHelperActivity::class.java)
i.putExtra("soundid", R.raw.boluserror) i.putExtra("soundid", R.raw.boluserror)
i.putExtra("status", result.comment) i.putExtra("status", result.comment)
i.putExtra("title", resourceHelper.gs(R.string.tempbasaldeliveryerror)) i.putExtra("title", resourceHelper.gs(R.string.tempbasaldeliveryerror))
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
mainApp.startActivity(i) ctx.startActivity(i)
} }
} }
}) })
@ -124,7 +142,7 @@ class ActionsFragment : DaggerFragment() {
} }
actions_fill.setOnClickListener { actions_fill.setOnClickListener {
activity?.let { activity -> activity?.let { activity ->
protectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, UIRunnable(Runnable { FillDialog().show(childFragmentManager, "FillDialog") })) protectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, UIRunnable { FillDialog().show(childFragmentManager, "FillDialog") })
} }
} }
actions_historybrowser.setOnClickListener { startActivity(Intent(context, HistoryBrowseActivity::class.java)) } actions_historybrowser.setOnClickListener { startActivity(Intent(context, HistoryBrowseActivity::class.java)) }
@ -233,26 +251,36 @@ class ActionsFragment : DaggerFragment() {
actions_canceltempbasal?.visibility = View.GONE actions_canceltempbasal?.visibility = View.GONE
} }
} }
val activeBgSource = activePlugin.activeBgSource
actions_historybrowser.visibility = (profile != null).toVisibility() actions_historybrowser.visibility = (profile != null).toVisibility()
actions_fill?.visibility = (pump.pumpDescription.isRefillingCapable && pump.isInitialized && !pump.isSuspended).toVisibility() actions_fill?.visibility = (pump.pumpDescription.isRefillingCapable && pump.isInitialized && !pump.isSuspended).toVisibility()
actions_pumpbatterychange?.visibility = pump.pumpDescription.isBatteryReplaceable.toVisibility() actions_pumpbatterychange?.visibility = pump.pumpDescription.isBatteryReplaceable.toVisibility()
actions_temptarget?.visibility = (profile != null && config.APS).toVisibility() actions_temptarget?.visibility = (profile != null && config.APS).toVisibility()
actions_tddstats?.visibility = pump.pumpDescription.supportsTDDs.toVisibility() actions_tddstats?.visibility = pump.pumpDescription.supportsTDDs.toVisibility()
statusLightHandler.updateStatusLights(careportal_canulaage, careportal_insulinage, null, careportal_sensorage, careportal_pbage, null) if (!config.NSCLIENT) {
statusLightHandler.updateStatusLights(careportal_canulaage, careportal_insulinage, careportal_reservoirlevel, careportal_sensorage, careportal_sensorlevel, careportal_pbage, careportal_batterylevel)
careportal_senslevellabel?.text = if (activeBgSource.sensorBatteryLevel == -1) "" else resourceHelper.gs(R.string.careportal_level_label)
} else {
statusLightHandler.updateStatusLights(careportal_canulaage, careportal_insulinage, null, careportal_sensorage, null, careportal_pbage, null)
careportal_senslevellabel?.text = ""
careportal_inslevellabel?.text = ""
careportal_pblevellabel?.text = ""
}
checkPumpCustomActions() checkPumpCustomActions()
} }
private fun checkPumpCustomActions() { private fun checkPumpCustomActions() {
val activePump = activePlugin.activePump val activePump = activePlugin.activePump
val customActions = activePump.customActions ?: return val customActions = activePump.customActions ?: return
val currentContext = context ?: return
removePumpCustomActions() removePumpCustomActions()
for (customAction in customActions) { for (customAction in customActions) {
if (!customAction.isEnabled) continue if (!customAction.isEnabled) continue
val btn = SingleClickButton(context, null, android.R.attr.buttonStyle) val btn = SingleClickButton(currentContext, null, android.R.attr.buttonStyle)
btn.text = resourceHelper.gs(customAction.name) btn.text = resourceHelper.gs(customAction.name)
val layoutParams = LinearLayout.LayoutParams( val layoutParams = LinearLayout.LayoutParams(

View file

@ -22,6 +22,7 @@ class ActionsPlugin @Inject constructor(
.fragmentClass(ActionsFragment::class.qualifiedName) .fragmentClass(ActionsFragment::class.qualifiedName)
.enableByDefault(config.APS || config.PUMPCONTROL) .enableByDefault(config.APS || config.PUMPCONTROL)
.visibleByDefault(config.APS || config.PUMPCONTROL) .visibleByDefault(config.APS || config.PUMPCONTROL)
.pluginIcon(R.drawable.ic_action)
.pluginName(R.string.actions) .pluginName(R.string.actions)
.shortName(R.string.actions_shortname) .shortName(R.string.actions_shortname)
.description(R.string.description_actions), .description(R.string.description_actions),

View file

@ -15,12 +15,18 @@ import java.util.*
import javax.inject.Inject import javax.inject.Inject
class AutomationEvent(private val injector: HasAndroidInjector) { class AutomationEvent(private val injector: HasAndroidInjector) {
@Inject lateinit var aapsLogger: AAPSLogger @Inject lateinit var aapsLogger: AAPSLogger
var title: String? = null
var isEnabled = true
var systemAction: Boolean = false // true = generated by AAPS, false = entered by user
var readOnly: Boolean = false // removing, editing disabled
var autoRemove: Boolean = false // auto-remove once used
var trigger: Trigger = TriggerConnector(injector) var trigger: Trigger = TriggerConnector(injector)
val actions: MutableList<Action> = ArrayList() val actions: MutableList<Action> = ArrayList()
var title: String? = null
var isEnabled = true
var lastRun: Long = 0 var lastRun: Long = 0
init { init {
@ -43,6 +49,9 @@ class AutomationEvent(private val injector: HasAndroidInjector) {
return JSONObject() return JSONObject()
.put("title", title) .put("title", title)
.put("enabled", isEnabled) .put("enabled", isEnabled)
.put("systemAction", systemAction)
.put("readOnly", readOnly)
.put("autoRemove", autoRemove)
.put("trigger", trigger.toJSON()) .put("trigger", trigger.toJSON())
.put("actions", array) .put("actions", array)
.toString() .toString()
@ -52,6 +61,9 @@ class AutomationEvent(private val injector: HasAndroidInjector) {
val d = JSONObject(data) val d = JSONObject(data)
title = d.optString("title", "") title = d.optString("title", "")
isEnabled = d.optBoolean("enabled", true) isEnabled = d.optBoolean("enabled", true)
systemAction = d.optBoolean("systemAction", false)
readOnly = d.optBoolean("readOnly", false)
autoRemove = d.optBoolean("autoRemove", false)
trigger = TriggerDummy(injector).instantiate(JSONObject(d.getString("trigger"))) trigger = TriggerDummy(injector).instantiate(JSONObject(d.getString("trigger")))
?: TriggerConnector(injector) ?: TriggerConnector(injector)
val array = d.getJSONArray("actions") val array = d.getJSONArray("actions")

View file

@ -9,18 +9,17 @@ import android.view.LayoutInflater
import android.view.MotionEvent import android.view.MotionEvent
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.CheckBox
import android.widget.ImageView import android.widget.ImageView
import android.widget.LinearLayout import android.widget.LinearLayout
import android.widget.RelativeLayout
import android.widget.TextView
import androidx.annotation.DrawableRes import androidx.annotation.DrawableRes
import androidx.recyclerview.widget.ItemTouchHelper import androidx.recyclerview.widget.ItemTouchHelper
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import dagger.android.HasAndroidInjector
import dagger.android.support.DaggerFragment import dagger.android.support.DaggerFragment
import info.nightscout.androidaps.MainApp
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.databinding.AutomationEventItemBinding
import info.nightscout.androidaps.databinding.AutomationFragmentBinding
import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.plugins.general.automation.dialogs.EditEventDialog import info.nightscout.androidaps.plugins.general.automation.dialogs.EditEventDialog
import info.nightscout.androidaps.plugins.general.automation.dragHelpers.ItemTouchHelperAdapter import info.nightscout.androidaps.plugins.general.automation.dragHelpers.ItemTouchHelperAdapter
@ -34,42 +33,50 @@ import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.HtmlHelper import info.nightscout.androidaps.utils.HtmlHelper
import info.nightscout.androidaps.utils.alertDialogs.OKDialog.showConfirmation import info.nightscout.androidaps.utils.alertDialogs.OKDialog.showConfirmation
import info.nightscout.androidaps.utils.extensions.plusAssign import info.nightscout.androidaps.utils.extensions.plusAssign
import info.nightscout.androidaps.utils.extensions.toVisibility
import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.resources.ResourceHelper
import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable import io.reactivex.disposables.CompositeDisposable
import kotlinx.android.synthetic.main.automation_fragment.*
import java.util.* import java.util.*
import javax.inject.Inject import javax.inject.Inject
class AutomationFragment : DaggerFragment(), OnStartDragListener { class AutomationFragment : DaggerFragment(), OnStartDragListener {
@Inject lateinit var resourceHelper: ResourceHelper @Inject lateinit var resourceHelper: ResourceHelper
@Inject lateinit var rxBus: RxBusWrapper @Inject lateinit var rxBus: RxBusWrapper
@Inject lateinit var fabricPrivacy: FabricPrivacy @Inject lateinit var fabricPrivacy: FabricPrivacy
@Inject lateinit var automationPlugin: AutomationPlugin @Inject lateinit var automationPlugin: AutomationPlugin
@Inject lateinit var mainApp : MainApp @Inject lateinit var injector: HasAndroidInjector
private var disposable: CompositeDisposable = CompositeDisposable() private var disposable: CompositeDisposable = CompositeDisposable()
private lateinit var eventListAdapter: EventListAdapter private lateinit var eventListAdapter: EventListAdapter
private var itemTouchHelper: ItemTouchHelper? = null private var itemTouchHelper: ItemTouchHelper? = null
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { private var _binding: AutomationFragmentBinding? = null
return inflater.inflate(R.layout.automation_fragment, container, false)
// This property is only valid between onCreateView and
// onDestroyView.
private val binding get() = _binding!!
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
_binding = AutomationFragmentBinding.inflate(inflater, container, false)
return binding.root
} }
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
eventListAdapter = EventListAdapter() eventListAdapter = EventListAdapter()
automation_eventListView.layoutManager = LinearLayoutManager(context) binding.eventListView.layoutManager = LinearLayoutManager(context)
automation_eventListView.adapter = eventListAdapter binding.eventListView.adapter = eventListAdapter
automation_logView.movementMethod = ScrollingMovementMethod() binding.logView.movementMethod = ScrollingMovementMethod()
automation_fabAddEvent.setOnClickListener { binding.fabAddEvent.setOnClickListener {
val dialog = EditEventDialog() val dialog = EditEventDialog()
val args = Bundle() val args = Bundle()
args.putString("event", AutomationEvent(mainApp).toJSON()) args.putString("event", AutomationEvent(injector).toJSON())
args.putInt("position", -1) // New event args.putInt("position", -1) // New event
dialog.arguments = args dialog.arguments = args
dialog.show(childFragmentManager, "EditEventDialog") dialog.show(childFragmentManager, "EditEventDialog")
@ -77,7 +84,7 @@ class AutomationFragment : DaggerFragment(), OnStartDragListener {
val callback: ItemTouchHelper.Callback = SimpleItemTouchHelperCallback(eventListAdapter) val callback: ItemTouchHelper.Callback = SimpleItemTouchHelperCallback(eventListAdapter)
itemTouchHelper = ItemTouchHelper(callback) itemTouchHelper = ItemTouchHelper(callback)
itemTouchHelper?.attachToRecyclerView(automation_eventListView) itemTouchHelper?.attachToRecyclerView(binding.eventListView)
} }
@ -105,13 +112,20 @@ class AutomationFragment : DaggerFragment(), OnStartDragListener {
disposable.clear() disposable.clear()
} }
@Synchronized
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
@Synchronized @Synchronized
private fun updateGui() { private fun updateGui() {
if (_binding == null) return
eventListAdapter.notifyDataSetChanged() eventListAdapter.notifyDataSetChanged()
val sb = StringBuilder() val sb = StringBuilder()
for (l in automationPlugin.executionLog.reversed()) for (l in automationPlugin.executionLog.reversed())
sb.append(l).append("<br>") sb.append(l).append("<br>")
automation_logView?.text = HtmlHelper.fromHtml(sb.toString()) binding.logView.text = HtmlHelper.fromHtml(sb.toString())
} }
override fun onStartDrag(viewHolder: RecyclerView.ViewHolder) { override fun onStartDrag(viewHolder: RecyclerView.ViewHolder) {
@ -132,6 +146,7 @@ class AutomationFragment : DaggerFragment(), OnStartDragListener {
} }
inner class EventListAdapter : RecyclerView.Adapter<EventListAdapter.ViewHolder>(), ItemTouchHelperAdapter { inner class EventListAdapter : RecyclerView.Adapter<EventListAdapter.ViewHolder>(), ItemTouchHelperAdapter {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val v = LayoutInflater.from(parent.context).inflate(R.layout.automation_event_item, parent, false) val v = LayoutInflater.from(parent.context).inflate(R.layout.automation_event_item, parent, false)
return ViewHolder(v, parent.context) return ViewHolder(v, parent.context)
@ -146,37 +161,38 @@ class AutomationFragment : DaggerFragment(), OnStartDragListener {
@SuppressLint("ClickableViewAccessibility") @SuppressLint("ClickableViewAccessibility")
override fun onBindViewHolder(holder: ViewHolder, position: Int) { override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val event = automationPlugin.automationEvents[position] val event = automationPlugin.at(position)
holder.eventTitle.text = event.title holder.binding.eventTitle.text = event.title
holder.enabled.isChecked = event.isEnabled holder.binding.enabled.isChecked = event.isEnabled
holder.iconLayout.removeAllViews() holder.binding.enabled.isEnabled = !event.readOnly
holder.binding.iconLayout.removeAllViews()
// trigger icons // trigger icons
val triggerIcons = HashSet<Int>() val triggerIcons = HashSet<Int>()
fillIconSet(event.trigger as TriggerConnector, triggerIcons) fillIconSet(event.trigger as TriggerConnector, triggerIcons)
for (res in triggerIcons) { for (res in triggerIcons) {
addImage(res, holder.context, holder.iconLayout) addImage(res, holder.context, holder.binding.iconLayout)
} }
// arrow icon // arrow icon
val iv = ImageView(holder.context) val iv = ImageView(holder.context)
iv.setImageResource(R.drawable.ic_arrow_forward_white_24dp) iv.setImageResource(R.drawable.ic_arrow_forward_white_24dp)
iv.layoutParams = LinearLayout.LayoutParams(resourceHelper.dpToPx(24), resourceHelper.dpToPx(24)) iv.layoutParams = LinearLayout.LayoutParams(resourceHelper.dpToPx(24), resourceHelper.dpToPx(24))
iv.setPadding(resourceHelper.dpToPx(4), 0, resourceHelper.dpToPx(4), 0) iv.setPadding(resourceHelper.dpToPx(4), 0, resourceHelper.dpToPx(4), 0)
holder.iconLayout.addView(iv) holder.binding.iconLayout.addView(iv)
// action icons // action icons
val actionIcons = HashSet<Int>() val actionIcons = HashSet<Int>()
for (action in event.actions) { for (action in event.actions) {
actionIcons.add(action.icon()) actionIcons.add(action.icon())
} }
for (res in actionIcons) { for (res in actionIcons) {
addImage(res, holder.context, holder.iconLayout) addImage(res, holder.context, holder.binding.iconLayout)
} }
// enabled event // enabled event
holder.enabled.setOnClickListener { holder.binding.enabled.setOnClickListener {
event.isEnabled = holder.enabled.isChecked event.isEnabled = holder.binding.enabled.isChecked
rxBus.send(EventAutomationDataChanged()) rxBus.send(EventAutomationDataChanged())
} }
// edit event // edit event
holder.rootLayout.setOnClickListener { holder.binding.rootLayout.setOnClickListener {
val dialog = EditEventDialog() val dialog = EditEventDialog()
val args = Bundle() val args = Bundle()
args.putString("event", event.toJSON()) args.putString("event", event.toJSON())
@ -185,42 +201,49 @@ class AutomationFragment : DaggerFragment(), OnStartDragListener {
dialog.show(childFragmentManager, "EditEventDialog") dialog.show(childFragmentManager, "EditEventDialog")
} }
// Start a drag whenever the handle view it touched // Start a drag whenever the handle view it touched
holder.iconSort.setOnTouchListener { v: View, motionEvent: MotionEvent -> holder.binding.iconSort.setOnTouchListener { v: View, motionEvent: MotionEvent ->
if (motionEvent.action == MotionEvent.ACTION_DOWN) { if (motionEvent.action == MotionEvent.ACTION_DOWN) {
this@AutomationFragment.onStartDrag(holder) this@AutomationFragment.onStartDrag(holder)
return@setOnTouchListener true return@setOnTouchListener true
} }
v.onTouchEvent(motionEvent) v.onTouchEvent(motionEvent)
} }
// remove event
holder.binding.iconTrash.setOnClickListener {
showConfirmation(requireContext(), resourceHelper.gs(R.string.removerecord) + " " + automationPlugin.at(position).title,
Runnable {
automationPlugin.removeAt(position)
notifyItemRemoved(position)
}, Runnable {
rxBus.send(EventAutomationUpdateGui())
})
}
holder.binding.iconTrash.visibility = (!event.readOnly).toVisibility()
holder.binding.aapsLogo.visibility = (event.systemAction).toVisibility()
} }
override fun getItemCount(): Int = automationPlugin.automationEvents.size override fun getItemCount(): Int = automationPlugin.size()
override fun onItemMove(fromPosition: Int, toPosition: Int): Boolean { override fun onItemMove(fromPosition: Int, toPosition: Int): Boolean {
Collections.swap(automationPlugin.automationEvents, fromPosition, toPosition) automationPlugin.swap(fromPosition, toPosition)
notifyItemMoved(fromPosition, toPosition) notifyItemMoved(fromPosition, toPosition)
rxBus.send(EventAutomationDataChanged())
return true return true
} }
override fun onItemDismiss(position: Int) { override fun onItemDismiss(position: Int) {
activity?.let { activity -> activity?.let { activity ->
showConfirmation(activity, resourceHelper.gs(R.string.removerecord) + " " + automationPlugin.automationEvents[position].title, showConfirmation(activity, resourceHelper.gs(R.string.removerecord) + " " + automationPlugin.at(position).title,
Runnable { Runnable {
automationPlugin.automationEvents.removeAt(position) automationPlugin.removeAt(position)
notifyItemRemoved(position) notifyItemRemoved(position)
rxBus.send(EventAutomationDataChanged()) rxBus.send(EventAutomationDataChanged())
rxBus.send(EventAutomationUpdateGui())
}, Runnable { rxBus.send(EventAutomationUpdateGui()) }) }, Runnable { rxBus.send(EventAutomationUpdateGui()) })
} }
} }
inner class ViewHolder(view: View, val context: Context) : RecyclerView.ViewHolder(view), ItemTouchHelperViewHolder { inner class ViewHolder(view: View, val context: Context) : RecyclerView.ViewHolder(view), ItemTouchHelperViewHolder {
val rootLayout: RelativeLayout = view.findViewById(R.id.rootLayout)
val iconLayout: LinearLayout = view.findViewById(R.id.iconLayout) val binding = AutomationEventItemBinding.bind(view)
val eventTitle: TextView = view.findViewById(R.id.viewEventTitle)
val iconSort: ImageView = view.findViewById(R.id.iconSort)
val enabled: CheckBox = view.findViewById(R.id.automation_enabled)
override fun onItemSelected() = itemView.setBackgroundColor(Color.LTGRAY) override fun onItemSelected() = itemView.setBackgroundColor(Color.LTGRAY)

View file

@ -39,8 +39,10 @@ import io.reactivex.schedulers.Schedulers
import org.json.JSONArray import org.json.JSONArray
import org.json.JSONException import org.json.JSONException
import org.json.JSONObject import org.json.JSONObject
import java.util.*
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
import kotlin.collections.ArrayList
@Singleton @Singleton
class AutomationPlugin @Inject constructor( class AutomationPlugin @Inject constructor(
@ -57,6 +59,7 @@ class AutomationPlugin @Inject constructor(
) : PluginBase(PluginDescription() ) : PluginBase(PluginDescription()
.mainType(PluginType.GENERAL) .mainType(PluginType.GENERAL)
.fragmentClass(AutomationFragment::class.qualifiedName) .fragmentClass(AutomationFragment::class.qualifiedName)
.pluginIcon(R.drawable.ic_automation)
.pluginName(R.string.automation) .pluginName(R.string.automation)
.shortName(R.string.automation_short) .shortName(R.string.automation_short)
.preferencesId(R.xml.pref_automation) .preferencesId(R.xml.pref_automation)
@ -68,7 +71,7 @@ class AutomationPlugin @Inject constructor(
private val keyAutomationEvents = "AUTOMATION_EVENTS" private val keyAutomationEvents = "AUTOMATION_EVENTS"
val automationEvents = ArrayList<AutomationEvent>() private val automationEvents = ArrayList<AutomationEvent>()
var executionLog: MutableList<String> = ArrayList() var executionLog: MutableList<String> = ArrayList()
var btConnects: MutableList<EventBTChange> = ArrayList() var btConnects: MutableList<EventBTChange> = ArrayList()
@ -76,6 +79,7 @@ class AutomationPlugin @Inject constructor(
private lateinit var refreshLoop: Runnable private lateinit var refreshLoop: Runnable
companion object { companion object {
const val event = "{\"title\":\"Low\",\"enabled\":true,\"trigger\":\"{\\\"type\\\":\\\"info.nightscout.androidaps.plugins.general.automation.triggers.TriggerConnector\\\",\\\"data\\\":{\\\"connectorType\\\":\\\"AND\\\",\\\"triggerList\\\":[\\\"{\\\\\\\"type\\\\\\\":\\\\\\\"info.nightscout.androidaps.plugins.general.automation.triggers.TriggerBg\\\\\\\",\\\\\\\"data\\\\\\\":{\\\\\\\"bg\\\\\\\":4,\\\\\\\"comparator\\\\\\\":\\\\\\\"IS_LESSER\\\\\\\",\\\\\\\"units\\\\\\\":\\\\\\\"mmol\\\\\\\"}}\\\",\\\"{\\\\\\\"type\\\\\\\":\\\\\\\"info.nightscout.androidaps.plugins.general.automation.triggers.TriggerDelta\\\\\\\",\\\\\\\"data\\\\\\\":{\\\\\\\"value\\\\\\\":-0.1,\\\\\\\"units\\\\\\\":\\\\\\\"mmol\\\\\\\",\\\\\\\"deltaType\\\\\\\":\\\\\\\"DELTA\\\\\\\",\\\\\\\"comparator\\\\\\\":\\\\\\\"IS_LESSER\\\\\\\"}}\\\"]}}\",\"actions\":[\"{\\\"type\\\":\\\"info.nightscout.androidaps.plugins.general.automation.actions.ActionStartTempTarget\\\",\\\"data\\\":{\\\"value\\\":8,\\\"units\\\":\\\"mmol\\\",\\\"durationInMinutes\\\":60}}\"]}" const val event = "{\"title\":\"Low\",\"enabled\":true,\"trigger\":\"{\\\"type\\\":\\\"info.nightscout.androidaps.plugins.general.automation.triggers.TriggerConnector\\\",\\\"data\\\":{\\\"connectorType\\\":\\\"AND\\\",\\\"triggerList\\\":[\\\"{\\\\\\\"type\\\\\\\":\\\\\\\"info.nightscout.androidaps.plugins.general.automation.triggers.TriggerBg\\\\\\\",\\\\\\\"data\\\\\\\":{\\\\\\\"bg\\\\\\\":4,\\\\\\\"comparator\\\\\\\":\\\\\\\"IS_LESSER\\\\\\\",\\\\\\\"units\\\\\\\":\\\\\\\"mmol\\\\\\\"}}\\\",\\\"{\\\\\\\"type\\\\\\\":\\\\\\\"info.nightscout.androidaps.plugins.general.automation.triggers.TriggerDelta\\\\\\\",\\\\\\\"data\\\\\\\":{\\\\\\\"value\\\\\\\":-0.1,\\\\\\\"units\\\\\\\":\\\\\\\"mmol\\\\\\\",\\\\\\\"deltaType\\\\\\\":\\\\\\\"DELTA\\\\\\\",\\\\\\\"comparator\\\\\\\":\\\\\\\"IS_LESSER\\\\\\\"}}\\\"]}}\",\"actions\":[\"{\\\"type\\\":\\\"info.nightscout.androidaps.plugins.general.automation.actions.ActionStartTempTarget\\\",\\\"data\\\":{\\\"value\\\":8,\\\"units\\\":\\\"mmol\\\",\\\"durationInMinutes\\\":60}}\"]}"
} }
@ -183,42 +187,46 @@ class AutomationPlugin @Inject constructor(
@Synchronized @Synchronized
private fun processActions() { private fun processActions() {
var userEventsEnabled = true
if (loopPlugin.isSuspended || !loopPlugin.isEnabled()) { if (loopPlugin.isSuspended || !loopPlugin.isEnabled()) {
aapsLogger.debug(LTag.AUTOMATION, "Loop deactivated") aapsLogger.debug(LTag.AUTOMATION, "Loop deactivated")
executionLog.add(resourceHelper.gs(R.string.smscommunicator_loopisdisabled)) executionLog.add(resourceHelper.gs(R.string.smscommunicator_loopisdisabled))
return userEventsEnabled = false
} }
val enabled = constraintChecker.isAutomationEnabled() val enabled = constraintChecker.isAutomationEnabled()
if (!enabled.value()) { if (!enabled.value()) {
executionLog.add(enabled.getMostLimitedReasons(aapsLogger)) executionLog.add(enabled.getMostLimitedReasons(aapsLogger))
return userEventsEnabled = false
} }
aapsLogger.debug(LTag.AUTOMATION, "processActions") aapsLogger.debug(LTag.AUTOMATION, "processActions")
for (event in automationEvents) { for (event in automationEvents) {
if (event.isEnabled && event.shouldRun() && event.trigger.shouldRun() && event.getPreconditions().shouldRun()) { if (event.isEnabled && event.shouldRun() && event.trigger.shouldRun() && event.getPreconditions().shouldRun()) {
val actions = event.actions if (event.systemAction || userEventsEnabled) {
for (action in actions) { val actions = event.actions
action.doAction(object : Callback() { for (action in actions) {
override fun run() { action.doAction(object : Callback() {
val sb = StringBuilder() override fun run() {
sb.append(dateUtil.timeString(DateUtil.now())) val sb = StringBuilder()
sb.append(" ") sb.append(dateUtil.timeString(DateUtil.now()))
sb.append(if (result.success) "" else "") sb.append(" ")
sb.append(" <b>") sb.append(if (result.success) "" else "")
sb.append(event.title) sb.append(" <b>")
sb.append(":</b> ") sb.append(event.title)
sb.append(action.shortDescription()) sb.append(":</b> ")
sb.append(": ") sb.append(action.shortDescription())
sb.append(result.comment) sb.append(": ")
executionLog.add(sb.toString()) sb.append(result.comment)
aapsLogger.debug(LTag.AUTOMATION, "Executed: $sb") executionLog.add(sb.toString())
rxBus.send(EventAutomationUpdateGui()) aapsLogger.debug(LTag.AUTOMATION, "Executed: $sb")
} rxBus.send(EventAutomationUpdateGui())
}) }
})
}
SystemClock.sleep(1100)
event.lastRun = DateUtil.now()
if (event.autoRemove) automationEvents.remove(event)
} }
SystemClock.sleep(1100)
event.lastRun = DateUtil.now()
} }
} }
// we cannot detect connected BT devices // we cannot detect connected BT devices
@ -230,6 +238,38 @@ class AutomationPlugin @Inject constructor(
storeToSP() // save last run time storeToSP() // save last run time
} }
fun add(event: AutomationEvent) {
automationEvents.add(event)
rxBus.send(EventAutomationDataChanged())
}
fun addIfNotExists(event: AutomationEvent) {
for (e in automationEvents) {
if (event.title == e.title) return
}
automationEvents.add(event)
rxBus.send(EventAutomationDataChanged())
}
fun set(event: AutomationEvent, index: Int) {
automationEvents[index] = event
rxBus.send(EventAutomationDataChanged())
}
fun removeAt(index: Int) {
automationEvents.removeAt(index)
rxBus.send(EventAutomationDataChanged())
}
fun at(index: Int) = automationEvents[index]
fun size() = automationEvents.size
fun swap(fromPosition: Int, toPosition: Int) {
Collections.swap(automationEvents, fromPosition, toPosition)
rxBus.send(EventAutomationDataChanged())
}
fun getActionDummyObjects(): List<Action> { fun getActionDummyObjects(): List<Action> {
return listOf( return listOf(
//ActionLoopDisable(injector), //ActionLoopDisable(injector),
@ -239,6 +279,7 @@ class AutomationPlugin @Inject constructor(
ActionStartTempTarget(injector), ActionStartTempTarget(injector),
ActionStopTempTarget(injector), ActionStopTempTarget(injector),
ActionNotification(injector), ActionNotification(injector),
ActionAlarm(injector),
ActionProfileSwitchPercent(injector), ActionProfileSwitchPercent(injector),
ActionProfileSwitch(injector), ActionProfileSwitch(injector),
ActionSendSMS(injector) ActionSendSMS(injector)

View file

@ -0,0 +1,75 @@
package info.nightscout.androidaps.plugins.general.automation.actions
import android.content.Context
import android.content.Intent
import android.widget.LinearLayout
import androidx.annotation.DrawableRes
import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.R
import info.nightscout.androidaps.activities.ErrorHelperActivity
import info.nightscout.androidaps.activities.PreferencesActivity
import info.nightscout.androidaps.data.PumpEnactResult
import info.nightscout.androidaps.events.EventRefreshOverview
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.plugins.general.automation.elements.InputString
import info.nightscout.androidaps.plugins.general.automation.elements.LabelWithElement
import info.nightscout.androidaps.plugins.general.automation.elements.LayoutBuilder
import info.nightscout.androidaps.plugins.general.nsclient.NSUpload
import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification
import info.nightscout.androidaps.plugins.general.overview.notifications.NotificationUserMessage
import info.nightscout.androidaps.queue.Callback
import info.nightscout.androidaps.utils.JsonHelper
import info.nightscout.androidaps.utils.alertDialogs.WarningDialog
import info.nightscout.androidaps.utils.resources.ResourceHelper
import org.json.JSONObject
import javax.inject.Inject
class ActionAlarm(injector: HasAndroidInjector) : Action(injector) {
@Inject lateinit var resourceHelper: ResourceHelper
@Inject lateinit var rxBus: RxBusWrapper
@Inject lateinit var nsUpload: NSUpload
@Inject lateinit var context: Context
var text = InputString(injector)
constructor(injector: HasAndroidInjector, text: String) : this(injector) {
this.text = InputString(injector, text)
}
override fun friendlyName(): Int = R.string.alarm
override fun shortDescription(): String = resourceHelper.gs(R.string.alarm_message, text.value)
@DrawableRes override fun icon(): Int = R.drawable.ic_access_alarm_24dp
override fun doAction(callback: Callback) {
val i = Intent(context, ErrorHelperActivity::class.java)
i.putExtra("soundid", R.raw.modern_alarm)
i.putExtra("status", text.value)
i.putExtra("title", resourceHelper.gs(R.string.alarm))
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
context.startActivity(i)
callback.result(PumpEnactResult(injector).success(true).comment(R.string.ok))?.run()
}
override fun toJSON(): String {
val data = JSONObject().put("text", text.value)
return JSONObject()
.put("type", this.javaClass.name)
.put("data", data)
.toString()
}
override fun fromJSON(data: String): Action {
val o = JSONObject(data)
text.value = JsonHelper.safeGetString(o, "text", "")
return this
}
override fun hasDialog(): Boolean = true
override fun generateDialog(root: LinearLayout) {
LayoutBuilder()
.add(LabelWithElement(injector, resourceHelper.gs(R.string.alarm_short), "", text))
.build(root)
}
}

View file

@ -37,7 +37,7 @@ class ActionStartTempTarget(injector: HasAndroidInjector) : Action(injector) {
override fun friendlyName(): Int = R.string.starttemptarget override fun friendlyName(): Int = R.string.starttemptarget
override fun shortDescription(): String = resourceHelper.gs(R.string.starttemptarget) + ": " + tt().friendlyDescription(value.units, resourceHelper) override fun shortDescription(): String = resourceHelper.gs(R.string.starttemptarget) + ": " + tt().friendlyDescription(value.units, resourceHelper)
@DrawableRes override fun icon(): Int = R.drawable.ic_cp_cgm_target @DrawableRes override fun icon(): Int = R.drawable.ic_temptarget_high
override fun doAction(callback: Callback) { override fun doAction(callback: Callback) {
activePlugin.activeTreatments.addToHistoryTempTarget(tt()) activePlugin.activeTreatments.addToHistoryTempTarget(tt())

View file

@ -6,24 +6,30 @@ import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.RadioButton import android.widget.RadioButton
import info.nightscout.androidaps.MainApp import info.nightscout.androidaps.MainApp
import info.nightscout.androidaps.R import info.nightscout.androidaps.databinding.AutomationDialogChooseActionBinding
import info.nightscout.androidaps.dialogs.DialogFragmentWithDate import info.nightscout.androidaps.dialogs.DialogFragmentWithDate
import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.plugins.general.automation.AutomationPlugin import info.nightscout.androidaps.plugins.general.automation.AutomationPlugin
import info.nightscout.androidaps.plugins.general.automation.actions.Action import info.nightscout.androidaps.plugins.general.automation.actions.Action
import info.nightscout.androidaps.plugins.general.automation.events.EventAutomationAddAction import info.nightscout.androidaps.plugins.general.automation.events.EventAutomationAddAction
import info.nightscout.androidaps.plugins.general.automation.events.EventAutomationUpdateGui import info.nightscout.androidaps.plugins.general.automation.events.EventAutomationUpdateGui
import kotlinx.android.synthetic.main.automation_dialog_choose_action.*
import javax.inject.Inject import javax.inject.Inject
import kotlin.reflect.full.primaryConstructor import kotlin.reflect.full.primaryConstructor
class ChooseActionDialog : DialogFragmentWithDate() { class ChooseActionDialog : DialogFragmentWithDate() {
@Inject lateinit var automationPlugin: AutomationPlugin @Inject lateinit var automationPlugin: AutomationPlugin
@Inject lateinit var rxBus: RxBusWrapper @Inject lateinit var rxBus: RxBusWrapper
@Inject lateinit var mainApp : MainApp @Inject lateinit var mainApp: MainApp
private var checkedIndex = -1 private var checkedIndex = -1
private var _binding: AutomationDialogChooseActionBinding? = null
// This property is only valid between onCreateView and
// onDestroyView.
private val binding get() = _binding!!
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? { savedInstanceState: Bundle?): View? {
// restore checked radio button // restore checked radio button
@ -32,7 +38,8 @@ class ChooseActionDialog : DialogFragmentWithDate() {
} }
onCreateViewGeneral() onCreateViewGeneral()
return inflater.inflate(R.layout.automation_dialog_choose_action, container, false) _binding = AutomationDialogChooseActionBinding.inflate(inflater, container, false)
return binding.root
} }
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
@ -42,11 +49,16 @@ class ChooseActionDialog : DialogFragmentWithDate() {
val radioButton = RadioButton(context) val radioButton = RadioButton(context)
radioButton.setText(a.friendlyName()) radioButton.setText(a.friendlyName())
radioButton.tag = a.javaClass.name radioButton.tag = a.javaClass.name
automation_radioGroup.addView(radioButton) binding.radioGroup.addView(radioButton)
} }
if (checkedIndex != -1) if (checkedIndex != -1)
(automation_radioGroup.getChildAt(checkedIndex) as RadioButton).isChecked = true (binding.radioGroup.getChildAt(checkedIndex) as RadioButton).isChecked = true
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
} }
override fun submit(): Boolean { override fun submit(): Boolean {
@ -70,16 +82,16 @@ class ChooseActionDialog : DialogFragmentWithDate() {
} }
private fun getActionClass(): String? { private fun getActionClass(): String? {
val radioButtonID = automation_radioGroup.checkedRadioButtonId val radioButtonID = binding.radioGroup.checkedRadioButtonId
val radioButton = automation_radioGroup.findViewById<RadioButton>(radioButtonID) val radioButton = binding.radioGroup.findViewById<RadioButton>(radioButtonID)
return radioButton?.let { return radioButton?.let {
it.tag as String it.tag as String
} }
} }
private fun determineCheckedIndex(): Int { private fun determineCheckedIndex(): Int {
for (i in 0 until automation_radioGroup.childCount) { for (i in 0 until binding.radioGroup.childCount) {
if ((automation_radioGroup.getChildAt(i) as RadioButton).isChecked) if ((binding.radioGroup.getChildAt(i) as RadioButton).isChecked)
return i return i
} }
return -1 return -1

View file

@ -6,34 +6,42 @@ import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.RadioButton import android.widget.RadioButton
import info.nightscout.androidaps.MainApp import info.nightscout.androidaps.MainApp
import info.nightscout.androidaps.R import info.nightscout.androidaps.databinding.AutomationDialogChooseTriggerBinding
import info.nightscout.androidaps.dialogs.DialogFragmentWithDate import info.nightscout.androidaps.dialogs.DialogFragmentWithDate
import info.nightscout.androidaps.plugins.general.automation.AutomationPlugin import info.nightscout.androidaps.plugins.general.automation.AutomationPlugin
import info.nightscout.androidaps.plugins.general.automation.triggers.Trigger import info.nightscout.androidaps.plugins.general.automation.triggers.Trigger
import kotlinx.android.synthetic.main.automation_dialog_choose_trigger.*
import javax.inject.Inject import javax.inject.Inject
import kotlin.reflect.full.primaryConstructor import kotlin.reflect.full.primaryConstructor
class ChooseTriggerDialog : DialogFragmentWithDate() { class ChooseTriggerDialog : DialogFragmentWithDate() {
@Inject lateinit var automationPlugin: AutomationPlugin @Inject lateinit var automationPlugin: AutomationPlugin
@Inject lateinit var mainApp : MainApp @Inject lateinit var mainApp: MainApp
private var checkedIndex = -1 private var checkedIndex = -1
private var clickListener: OnClickListener? = null private var clickListener: OnClickListener? = null
private var _binding: AutomationDialogChooseTriggerBinding? = null
// This property is only valid between onCreateView and
// onDestroyView.
private val binding get() = _binding!!
interface OnClickListener { interface OnClickListener {
fun onClick(newTriggerObject: Trigger) fun onClick(newTriggerObject: Trigger)
} }
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? { savedInstanceState: Bundle?): View {
// restore checked radio button // restore checked radio button
savedInstanceState?.let { bundle -> savedInstanceState?.let { bundle ->
checkedIndex = bundle.getInt("checkedIndex") checkedIndex = bundle.getInt("checkedIndex")
} }
onCreateViewGeneral() onCreateViewGeneral()
return inflater.inflate(R.layout.automation_dialog_choose_trigger, container, false) _binding = AutomationDialogChooseTriggerBinding.inflate(inflater, container, false)
return binding.root
} }
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
@ -43,11 +51,16 @@ class ChooseTriggerDialog : DialogFragmentWithDate() {
val radioButton = RadioButton(context) val radioButton = RadioButton(context)
radioButton.setText(t.friendlyName()) radioButton.setText(t.friendlyName())
radioButton.tag = t.javaClass.name radioButton.tag = t.javaClass.name
automation_chooseTriggerRadioGroup.addView(radioButton) binding.chooseTriggerRadioGroup.addView(radioButton)
} }
if (checkedIndex != -1) if (checkedIndex != -1)
(automation_chooseTriggerRadioGroup.getChildAt(checkedIndex) as RadioButton).isChecked = true (binding.chooseTriggerRadioGroup.getChildAt(checkedIndex) as RadioButton).isChecked = true
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
} }
override fun submit(): Boolean { override fun submit(): Boolean {
@ -74,16 +87,16 @@ class ChooseTriggerDialog : DialogFragmentWithDate() {
} }
private fun getTriggerClass(): String? { private fun getTriggerClass(): String? {
val radioButtonID = automation_chooseTriggerRadioGroup.checkedRadioButtonId val radioButtonID = binding.chooseTriggerRadioGroup.checkedRadioButtonId
val radioButton = automation_chooseTriggerRadioGroup.findViewById<RadioButton>(radioButtonID) val radioButton = binding.chooseTriggerRadioGroup.findViewById<RadioButton>(radioButtonID)
return radioButton?.let { return radioButton?.let {
it.tag as String it.tag as String
} }
} }
private fun determineCheckedIndex(): Int { private fun determineCheckedIndex(): Int {
for (i in 0 until automation_chooseTriggerRadioGroup.childCount) { for (i in 0 until binding.chooseTriggerRadioGroup.childCount) {
if ((automation_chooseTriggerRadioGroup.getChildAt(i) as RadioButton).isChecked) if ((binding.chooseTriggerRadioGroup.getChildAt(i) as RadioButton).isChecked)
return i return i
} }
return -1 return -1

View file

@ -5,41 +5,48 @@ import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import info.nightscout.androidaps.MainApp import info.nightscout.androidaps.MainApp
import info.nightscout.androidaps.R import info.nightscout.androidaps.databinding.AutomationDialogActionBinding
import info.nightscout.androidaps.dialogs.DialogFragmentWithDate import info.nightscout.androidaps.dialogs.DialogFragmentWithDate
import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.plugins.general.automation.actions.Action import info.nightscout.androidaps.plugins.general.automation.actions.Action
import info.nightscout.androidaps.plugins.general.automation.actions.ActionDummy import info.nightscout.androidaps.plugins.general.automation.actions.ActionDummy
import info.nightscout.androidaps.plugins.general.automation.events.EventAutomationUpdateAction import info.nightscout.androidaps.plugins.general.automation.events.EventAutomationUpdateAction
import kotlinx.android.synthetic.main.automation_dialog_action.*
import org.json.JSONObject import org.json.JSONObject
import javax.inject.Inject import javax.inject.Inject
class EditActionDialog : DialogFragmentWithDate() { class EditActionDialog : DialogFragmentWithDate() {
@Inject lateinit var rxBus: RxBusWrapper @Inject lateinit var rxBus: RxBusWrapper
@Inject lateinit var mainApp: MainApp @Inject lateinit var mainApp: MainApp
private var action: Action? = null private var action: Action? = null
private var actionPosition: Int = -1 private var actionPosition: Int = -1
private var _binding: AutomationDialogActionBinding? = null
// This property is only valid between onCreateView and
// onDestroyView.
private val binding get() = _binding!!
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? { savedInstanceState: Bundle?): View {
// load data from bundle // load data from bundle
(savedInstanceState ?: arguments)?.let { bundle -> (savedInstanceState ?: arguments)?.let { bundle ->
actionPosition = bundle.getInt("actionPosition", -1) actionPosition = bundle.getInt("actionPosition", -1)
bundle.getString("action")?.let { action = ActionDummy(mainApp).instantiate(JSONObject(it)) } bundle.getString("action")?.let { action = ActionDummy(mainApp).instantiate(JSONObject(it)) }
} }
onCreateViewGeneral() onCreateViewGeneral()
return inflater.inflate(R.layout.automation_dialog_action, container, false) _binding = AutomationDialogActionBinding.inflate(inflater, container, false)
return binding.root
} }
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
action?.let { action?.let {
automation_actionTitle.setText(it.friendlyName()) binding.actionTitle.setText(it.friendlyName())
automation_editActionLayout.removeAllViews() binding.editActionLayout.removeAllViews()
it.generateDialog(automation_editActionLayout) it.generateDialog(binding.editActionLayout)
} }
} }

View file

@ -11,6 +11,7 @@ import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import info.nightscout.androidaps.MainApp import info.nightscout.androidaps.MainApp
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.databinding.AutomationDialogEventBinding
import info.nightscout.androidaps.dialogs.DialogFragmentWithDate import info.nightscout.androidaps.dialogs.DialogFragmentWithDate
import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.plugins.general.automation.AutomationEvent import info.nightscout.androidaps.plugins.general.automation.AutomationEvent
@ -25,12 +26,13 @@ import info.nightscout.androidaps.plugins.general.automation.triggers.TriggerCon
import info.nightscout.androidaps.utils.FabricPrivacy import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.ToastUtils import info.nightscout.androidaps.utils.ToastUtils
import info.nightscout.androidaps.utils.extensions.plusAssign import info.nightscout.androidaps.utils.extensions.plusAssign
import info.nightscout.androidaps.utils.extensions.toVisibility
import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable import io.reactivex.disposables.CompositeDisposable
import kotlinx.android.synthetic.main.automation_dialog_event.*
import javax.inject.Inject import javax.inject.Inject
class EditEventDialog : DialogFragmentWithDate() { class EditEventDialog : DialogFragmentWithDate() {
@Inject lateinit var rxBus: RxBusWrapper @Inject lateinit var rxBus: RxBusWrapper
@Inject lateinit var mainApp: MainApp @Inject lateinit var mainApp: MainApp
@Inject lateinit var fabricPrivacy: FabricPrivacy @Inject lateinit var fabricPrivacy: FabricPrivacy
@ -42,8 +44,14 @@ class EditEventDialog : DialogFragmentWithDate() {
private var disposable: CompositeDisposable = CompositeDisposable() private var disposable: CompositeDisposable = CompositeDisposable()
private var _binding: AutomationDialogEventBinding? = null
// This property is only valid between onCreateView and
// onDestroyView.
private val binding get() = _binding!!
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? { savedInstanceState: Bundle?): View {
event = AutomationEvent(mainApp) event = AutomationEvent(mainApp)
// load data from bundle // load data from bundle
(savedInstanceState ?: arguments)?.let { bundle -> (savedInstanceState ?: arguments)?.let { bundle ->
@ -52,16 +60,21 @@ class EditEventDialog : DialogFragmentWithDate() {
} }
onCreateViewGeneral() onCreateViewGeneral()
return inflater.inflate(R.layout.automation_dialog_event, container, false) _binding = AutomationDialogEventBinding.inflate(inflater, container, false)
return binding.root
} }
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
automation_inputEventTitle.setText(event.title) binding.okcancel.ok.visibility = (!event.readOnly).toVisibility()
automation_triggerDescription.text = event.trigger.friendlyDescription()
automation_editTrigger.setOnClickListener { binding.inputEventTitle.setText(event.title)
binding.inputEventTitle.isFocusable = false
binding.triggerDescription.text = event.trigger.friendlyDescription()
binding.editTrigger.visibility = (!event.readOnly).toVisibility()
binding.editTrigger.setOnClickListener {
val args = Bundle() val args = Bundle()
args.putString("trigger", event.trigger.toJSON()) args.putString("trigger", event.trigger.toJSON())
val dialog = EditTriggerDialog() val dialog = EditTriggerDialog()
@ -71,10 +84,11 @@ class EditEventDialog : DialogFragmentWithDate() {
// setup action list view // setup action list view
actionListAdapter = ActionListAdapter() actionListAdapter = ActionListAdapter()
automation_actionListView.layoutManager = LinearLayoutManager(context) binding.actionListView.layoutManager = LinearLayoutManager(context)
automation_actionListView.adapter = actionListAdapter binding.actionListView.adapter = actionListAdapter
automation_addAction.setOnClickListener { ChooseActionDialog().show(childFragmentManager, "ChooseActionDialog") } binding.addAction.visibility = (!event.readOnly).toVisibility()
binding.addAction.setOnClickListener { ChooseActionDialog().show(childFragmentManager, "ChooseActionDialog") }
showPreconditions() showPreconditions()
@ -84,36 +98,33 @@ class EditEventDialog : DialogFragmentWithDate() {
.subscribe({ .subscribe({
actionListAdapter?.notifyDataSetChanged() actionListAdapter?.notifyDataSetChanged()
showPreconditions() showPreconditions()
}, { fabricPrivacy.logException(it) } }, fabricPrivacy::logException)
)
disposable += rxBus disposable += rxBus
.toObservable(EventAutomationAddAction::class.java) .toObservable(EventAutomationAddAction::class.java)
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
.subscribe({ .subscribe({
event.addAction(it.action) event.addAction(it.action)
actionListAdapter?.notifyDataSetChanged() actionListAdapter?.notifyDataSetChanged()
}, { fabricPrivacy.logException(it) } }, fabricPrivacy::logException)
)
disposable += rxBus disposable += rxBus
.toObservable(EventAutomationUpdateTrigger::class.java) .toObservable(EventAutomationUpdateTrigger::class.java)
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
.subscribe({ .subscribe({
event.trigger = it.trigger event.trigger = it.trigger
automation_triggerDescription.text = event.trigger.friendlyDescription() binding.triggerDescription.text = event.trigger.friendlyDescription()
}, { fabricPrivacy.logException(it) } }, fabricPrivacy::logException)
)
disposable += rxBus disposable += rxBus
.toObservable(EventAutomationUpdateAction::class.java) .toObservable(EventAutomationUpdateAction::class.java)
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
.subscribe({ .subscribe({
event.actions[it.position] = it.action event.actions[it.position] = it.action
actionListAdapter?.notifyDataSetChanged() actionListAdapter?.notifyDataSetChanged()
}, { fabricPrivacy.logException(it) }) }, fabricPrivacy::logException)
} }
override fun submit(): Boolean { override fun submit(): Boolean {
// check for title // check for title
val title = automation_inputEventTitle.text.toString() val title = binding.inputEventTitle.text?.toString() ?: return false
if (title.isEmpty()) { if (title.isEmpty()) {
ToastUtils.showToastInUiThread(context, R.string.automation_missing_task_name) ToastUtils.showToastInUiThread(context, R.string.automation_missing_task_name)
return false return false
@ -132,9 +143,9 @@ class EditEventDialog : DialogFragmentWithDate() {
} }
// store // store
if (position == -1) if (position == -1)
automationPlugin.automationEvents.add(event) automationPlugin.add(event)
else else
automationPlugin.automationEvents[position] = event automationPlugin.set(event, position)
rxBus.send(EventAutomationDataChanged()) rxBus.send(EventAutomationDataChanged())
return true return true
@ -143,6 +154,7 @@ class EditEventDialog : DialogFragmentWithDate() {
override fun onDestroyView() { override fun onDestroyView() {
super.onDestroyView() super.onDestroyView()
disposable.clear() disposable.clear()
_binding = null
} }
override fun onSaveInstanceState(savedInstanceState: Bundle) { override fun onSaveInstanceState(savedInstanceState: Bundle) {
@ -154,12 +166,12 @@ class EditEventDialog : DialogFragmentWithDate() {
private fun showPreconditions() { private fun showPreconditions() {
val forcedTriggers = event.getPreconditions() val forcedTriggers = event.getPreconditions()
if (forcedTriggers.size() > 0) { if (forcedTriggers.size() > 0) {
automation_forcedTriggerDescription.visibility = View.VISIBLE binding.forcedTriggerDescription.visibility = View.VISIBLE
automation_forcedTriggerDescriptionLabel.visibility = View.VISIBLE binding.forcedTriggerDescriptionLabel.visibility = View.VISIBLE
automation_forcedTriggerDescription.text = forcedTriggers.friendlyDescription() binding.forcedTriggerDescription.text = forcedTriggers.friendlyDescription()
} else { } else {
automation_forcedTriggerDescription.visibility = View.GONE binding.forcedTriggerDescription.visibility = View.GONE
automation_forcedTriggerDescriptionLabel.visibility = View.GONE binding.forcedTriggerDescriptionLabel.visibility = View.GONE
} }
} }
@ -180,20 +192,24 @@ class EditEventDialog : DialogFragmentWithDate() {
inner class ViewHolder(val view: View) : RecyclerView.ViewHolder(view) { inner class ViewHolder(val view: View) : RecyclerView.ViewHolder(view) {
fun bind(action: Action, recyclerView: RecyclerView.Adapter<ViewHolder>, position: Int) { fun bind(action: Action, recyclerView: RecyclerView.Adapter<ViewHolder>, position: Int) {
view.findViewById<LinearLayout>(R.id.automation_layoutText).setOnClickListener { if (!event.readOnly)
if (action.hasDialog()) { view.findViewById<LinearLayout>(R.id.automation_layoutText).setOnClickListener {
val args = Bundle() if (action.hasDialog()) {
args.putInt("actionPosition", position) val args = Bundle()
args.putString("action", action.toJSON()) args.putInt("actionPosition", position)
val dialog = EditActionDialog() args.putString("action", action.toJSON())
dialog.arguments = args val dialog = EditActionDialog()
dialog.show(childFragmentManager, "EditActionDialog") dialog.arguments = args
dialog.show(childFragmentManager, "EditActionDialog")
}
}
view.findViewById<ImageView>(R.id.automation_iconTrash).run {
visibility = (!event.readOnly).toVisibility()
setOnClickListener {
event.actions.remove(action)
recyclerView.notifyDataSetChanged()
rxBus.send(EventAutomationUpdateGui())
} }
}
view.findViewById<ImageView>(R.id.automation_iconTrash).setOnClickListener {
event.actions.remove(action)
recyclerView.notifyDataSetChanged()
rxBus.send(EventAutomationUpdateGui())
} }
view.findViewById<ImageView>(R.id.automation_action_image).setImageResource(action.icon()) view.findViewById<ImageView>(R.id.automation_action_image).setImageResource(action.icon())
view.findViewById<TextView>(R.id.automation_viewActionTitle).text = action.shortDescription() view.findViewById<TextView>(R.id.automation_viewActionTitle).text = action.shortDescription()

View file

@ -5,7 +5,7 @@ import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import info.nightscout.androidaps.MainApp import info.nightscout.androidaps.MainApp
import info.nightscout.androidaps.R import info.nightscout.androidaps.databinding.AutomationDialogEditTriggerBinding
import info.nightscout.androidaps.dialogs.DialogFragmentWithDate import info.nightscout.androidaps.dialogs.DialogFragmentWithDate
import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.plugins.general.automation.events.EventAutomationUpdateTrigger import info.nightscout.androidaps.plugins.general.automation.events.EventAutomationUpdateTrigger
@ -19,11 +19,11 @@ import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.extensions.plusAssign import info.nightscout.androidaps.utils.extensions.plusAssign
import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable import io.reactivex.disposables.CompositeDisposable
import kotlinx.android.synthetic.main.automation_dialog_edit_trigger.*
import org.json.JSONObject import org.json.JSONObject
import javax.inject.Inject import javax.inject.Inject
class EditTriggerDialog : DialogFragmentWithDate() { class EditTriggerDialog : DialogFragmentWithDate() {
@Inject lateinit var rxBus: RxBusWrapper @Inject lateinit var rxBus: RxBusWrapper
@Inject lateinit var mainApp: MainApp @Inject lateinit var mainApp: MainApp
@Inject lateinit var fabricPrivacy: FabricPrivacy @Inject lateinit var fabricPrivacy: FabricPrivacy
@ -32,15 +32,22 @@ class EditTriggerDialog : DialogFragmentWithDate() {
private var triggers: Trigger? = null private var triggers: Trigger? = null
private var _binding: AutomationDialogEditTriggerBinding? = null
// This property is only valid between onCreateView and
// onDestroyView.
private val binding get() = _binding!!
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? { savedInstanceState: Bundle?): View {
// load data from bundle // load data from bundle
(savedInstanceState ?: arguments)?.let { bundle -> (savedInstanceState ?: arguments)?.let { bundle ->
bundle.getString("trigger")?.let { triggers = TriggerDummy(mainApp).instantiate(JSONObject(it)) } bundle.getString("trigger")?.let { triggers = TriggerDummy(mainApp).instantiate(JSONObject(it)) }
} }
onCreateViewGeneral() onCreateViewGeneral()
return inflater.inflate(R.layout.automation_dialog_edit_trigger, container, false) _binding = AutomationDialogEditTriggerBinding.inflate(inflater, container, false)
return binding.root
} }
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
@ -50,16 +57,16 @@ class EditTriggerDialog : DialogFragmentWithDate() {
.toObservable(EventTriggerChanged::class.java) .toObservable(EventTriggerChanged::class.java)
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
.subscribe({ .subscribe({
automation_layoutTrigger.removeAllViews() binding.layoutTrigger.removeAllViews()
triggers?.generateDialog(automation_layoutTrigger) triggers?.generateDialog(binding.layoutTrigger)
}, { fabricPrivacy.logException(it) }) }, { fabricPrivacy.logException(it) })
disposable += rxBus disposable += rxBus
.toObservable(EventTriggerRemove::class.java) .toObservable(EventTriggerRemove::class.java)
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
.subscribe({ .subscribe({
findParent(triggers, it.trigger)?.list?.remove(it.trigger) findParent(triggers, it.trigger)?.list?.remove(it.trigger)
automation_layoutTrigger.removeAllViews() binding.layoutTrigger.removeAllViews()
triggers?.generateDialog(automation_layoutTrigger) triggers?.generateDialog(binding.layoutTrigger)
}, { fabricPrivacy.logException(it) }) }, { fabricPrivacy.logException(it) })
disposable += rxBus disposable += rxBus
@ -67,17 +74,18 @@ class EditTriggerDialog : DialogFragmentWithDate() {
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
.subscribe({ .subscribe({
findParent(triggers, it.trigger)?.list?.add(it.trigger.duplicate()) findParent(triggers, it.trigger)?.list?.add(it.trigger.duplicate())
automation_layoutTrigger.removeAllViews() binding.layoutTrigger.removeAllViews()
triggers?.generateDialog(automation_layoutTrigger) triggers?.generateDialog(binding.layoutTrigger)
}, { fabricPrivacy.logException(it) }) }, { fabricPrivacy.logException(it) })
// display root trigger // display root trigger
triggers?.generateDialog(automation_layoutTrigger) triggers?.generateDialog(binding.layoutTrigger)
} }
override fun onDestroyView() { override fun onDestroyView() {
super.onDestroyView() super.onDestroyView()
disposable.clear() disposable.clear()
_binding = null
} }
override fun submit(): Boolean { override fun submit(): Boolean {

View file

@ -21,7 +21,7 @@ class SimpleItemTouchHelperCallback(private val mAdapter: ItemTouchHelperAdapter
} }
override fun isItemViewSwipeEnabled(): Boolean { override fun isItemViewSwipeEnabled(): Boolean {
return true return false
} }
override fun getMovementFlags(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder): Int { // Set movement flags based on the layout manager override fun getMovementFlags(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder): Int { // Set movement flags based on the layout manager

View file

@ -46,7 +46,7 @@ class TriggerBg(injector: HasAndroidInjector) : Trigger(injector) {
} }
override fun shouldRun(): Boolean { override fun shouldRun(): Boolean {
val glucoseStatus = GlucoseStatus(injector).getGlucoseStatusData() val glucoseStatus = GlucoseStatus(injector).glucoseStatusData
if (glucoseStatus == null && comparator.value == Comparator.Compare.IS_NOT_AVAILABLE) { if (glucoseStatus == null && comparator.value == Comparator.Compare.IS_NOT_AVAILABLE) {
aapsLogger.debug(LTag.AUTOMATION, "Ready for execution: " + friendlyDescription()) aapsLogger.debug(LTag.AUTOMATION, "Ready for execution: " + friendlyDescription())
return true return true

View file

@ -35,6 +35,12 @@ class TriggerDelta(injector: HasAndroidInjector) : Trigger(injector) {
else InputDelta(injector, 0.0, (-MGDL_MAX), MGDL_MAX, 1.0, DecimalFormat("1"), DeltaType.DELTA) else InputDelta(injector, 0.0, (-MGDL_MAX), MGDL_MAX, 1.0, DecimalFormat("1"), DeltaType.DELTA)
} }
constructor(injector: HasAndroidInjector, inputDelta: InputDelta, units: String, comparator: Comparator.Compare) : this(injector) {
this.units = units
this.delta = inputDelta
this.comparator.value = comparator
}
private constructor(injector: HasAndroidInjector, triggerDelta: TriggerDelta) : this(injector) { private constructor(injector: HasAndroidInjector, triggerDelta: TriggerDelta) : this(injector) {
units = triggerDelta.units units = triggerDelta.units
delta = InputDelta(injector, triggerDelta.delta) delta = InputDelta(injector, triggerDelta.delta)
@ -58,7 +64,7 @@ class TriggerDelta(injector: HasAndroidInjector) : Trigger(injector) {
} }
override fun shouldRun(): Boolean { override fun shouldRun(): Boolean {
val glucoseStatus = GlucoseStatus(injector).getGlucoseStatusData() val glucoseStatus = GlucoseStatus(injector).glucoseStatusData
?: return if (comparator.value == Comparator.Compare.IS_NOT_AVAILABLE) { ?: return if (comparator.value == Comparator.Compare.IS_NOT_AVAILABLE) {
aapsLogger.debug(LTag.AUTOMATION, "Ready for execution: " + friendlyDescription()) aapsLogger.debug(LTag.AUTOMATION, "Ready for execution: " + friendlyDescription())
true true

View file

@ -105,9 +105,7 @@ public class Food {
return false; return false;
if (!Objects.equals(subcategory, other.subcategory)) if (!Objects.equals(subcategory, other.subcategory))
return false; return false;
if (!Objects.equals(units, other.units)) return Objects.equals(units, other.units);
return false;
return true;
} }
public void copyFrom(Food other) { public void copyFrom(Food other) {

View file

@ -49,7 +49,7 @@ class FoodFragment : DaggerFragment() {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
food_recyclerview.setHasFixedSize(true) food_recyclerview.setHasFixedSize(true)
food_recyclerview.setLayoutManager(LinearLayoutManager(view.context)) food_recyclerview.layoutManager = LinearLayoutManager(view.context)
food_recyclerview.adapter = RecyclerViewAdapter(foodPlugin.service?.foodData ?: ArrayList()) food_recyclerview.adapter = RecyclerViewAdapter(foodPlugin.service?.foodData ?: ArrayList())
food_clearfilter.setOnClickListener { food_clearfilter.setOnClickListener {
@ -69,7 +69,7 @@ class FoodFragment : DaggerFragment() {
filterData() filterData()
} }
} }
food_subcategory.setOnItemSelectedListener(object : AdapterView.OnItemSelectedListener { food_subcategory.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) { override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
filterData() filterData()
} }
@ -77,7 +77,7 @@ class FoodFragment : DaggerFragment() {
override fun onNothingSelected(parent: AdapterView<*>?) { override fun onNothingSelected(parent: AdapterView<*>?) {
filterData() filterData()
} }
}) }
food_filter.addTextChangedListener(object : TextWatcher { food_filter.addTextChangedListener(object : TextWatcher {
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {} override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {}
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) { override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {

View file

@ -18,6 +18,7 @@ class FoodPlugin @Inject constructor(
) : PluginBase(PluginDescription() ) : PluginBase(PluginDescription()
.mainType(PluginType.GENERAL) .mainType(PluginType.GENERAL)
.fragmentClass(FoodFragment::class.java.name) .fragmentClass(FoodFragment::class.java.name)
.pluginIcon(R.drawable.ic_food)
.pluginName(R.string.food) .pluginName(R.string.food)
.shortName(R.string.food_short) .shortName(R.string.food_short)
.description(R.string.description_food), .description(R.string.description_food),

View file

@ -48,7 +48,7 @@ public class FoodService extends OrmLiteBaseService<DatabaseHelper> {
@Inject RxBusWrapper rxBus; @Inject RxBusWrapper rxBus;
@Inject FabricPrivacy fabricPrivacy; @Inject FabricPrivacy fabricPrivacy;
private CompositeDisposable disposable = new CompositeDisposable(); private final CompositeDisposable disposable = new CompositeDisposable();
private static final ScheduledExecutorService foodEventWorker = Executors.newSingleThreadScheduledExecutor(); private static final ScheduledExecutorService foodEventWorker = Executors.newSingleThreadScheduledExecutor();
private static ScheduledFuture<?> scheduledFoodEventPost = null; private static ScheduledFuture<?> scheduledFoodEventPost = null;

View file

@ -1,24 +1,27 @@
package info.nightscout.androidaps.plugins.general.maintenance package info.nightscout.androidaps.plugins.general.maintenance
import android.Manifest import android.Manifest
import android.app.Activity
import android.bluetooth.BluetoothAdapter import android.bluetooth.BluetoothAdapter
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.pm.PackageManager import android.content.pm.PackageManager
import android.provider.Settings import android.provider.Settings
import androidx.annotation.StringRes import androidx.annotation.StringRes
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity import androidx.fragment.app.FragmentActivity
import info.nightscout.androidaps.BuildConfig import info.nightscout.androidaps.BuildConfig
import info.nightscout.androidaps.MainActivity
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.activities.PreferencesActivity import info.nightscout.androidaps.activities.PreferencesActivity
import info.nightscout.androidaps.activities.SingleFragmentActivity
import info.nightscout.androidaps.events.EventAppExit import info.nightscout.androidaps.events.EventAppExit
import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.logging.LTag
import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.plugins.general.maintenance.formats.* import info.nightscout.androidaps.plugins.general.maintenance.formats.*
import info.nightscout.androidaps.utils.AndroidPermission
import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.ToastUtils import info.nightscout.androidaps.utils.ToastUtils
import info.nightscout.androidaps.utils.alertDialogs.OKDialog import info.nightscout.androidaps.utils.alertDialogs.OKDialog
@ -41,12 +44,6 @@ import javax.inject.Singleton
* Created by mike on 03.07.2016. * Created by mike on 03.07.2016.
*/ */
private const val REQUEST_EXTERNAL_STORAGE = 1
private val PERMISSIONS_STORAGE = arrayOf(
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE
)
@Singleton @Singleton
class ImportExportPrefs @Inject constructor( class ImportExportPrefs @Inject constructor(
private var log: AAPSLogger, private var log: AAPSLogger,
@ -55,6 +52,7 @@ class ImportExportPrefs @Inject constructor(
private val buildHelper: BuildHelper, private val buildHelper: BuildHelper,
private val rxBus: RxBusWrapper, private val rxBus: RxBusWrapper,
private val passwordCheck: PasswordCheck, private val passwordCheck: PasswordCheck,
private val androidPermission: AndroidPermission,
private val classicPrefsFormat: ClassicPrefsFormat, private val classicPrefsFormat: ClassicPrefsFormat,
private val encryptedPrefsFormat: EncryptedPrefsFormat, private val encryptedPrefsFormat: EncryptedPrefsFormat,
private val prefFileList: PrefFileListProvider private val prefFileList: PrefFileListProvider
@ -70,13 +68,18 @@ class ImportExportPrefs @Inject constructor(
f.activity?.let { exportSharedPreferences(it) } f.activity?.let { exportSharedPreferences(it) }
} }
fun verifyStoragePermissions(fragment: Fragment) { fun verifyStoragePermissions(fragment: Fragment, onGranted: Runnable) {
fragment.context?.let { fragment.context?.let { ctx ->
val permission = ContextCompat.checkSelfPermission(it, val permission = ContextCompat.checkSelfPermission(ctx,
Manifest.permission.WRITE_EXTERNAL_STORAGE) Manifest.permission.WRITE_EXTERNAL_STORAGE)
if (permission != PackageManager.PERMISSION_GRANTED) { if (permission != PackageManager.PERMISSION_GRANTED) {
// We don't have permission so prompt the user // We don't have permission so prompt the user
fragment.requestPermissions(PERMISSIONS_STORAGE, REQUEST_EXTERNAL_STORAGE) fragment.activity?.let {
androidPermission.askForPermission(it, arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE), AndroidPermission.CASE_STORAGE)
}
} else {
onGranted.run()
} }
} }
} }
@ -120,9 +123,9 @@ class ImportExportPrefs @Inject constructor(
} }
private fun prefsEncryptionIsDisabled() = private fun prefsEncryptionIsDisabled() =
buildHelper.isEngineeringMode() && !sp.getBoolean(resourceHelper.gs(R.string.key_maintenance_encrypt_exported_prefs), true) buildHelper.isEngineeringMode() && !sp.getBoolean(R.string.key_maintenance_encrypt_exported_prefs, true)
private fun askForMasterPass(activity: Activity, @StringRes canceledMsg: Int, then: ((password: String) -> Unit)) { private fun askForMasterPass(activity: FragmentActivity, @StringRes canceledMsg: Int, then: ((password: String) -> Unit)) {
passwordCheck.queryPassword(activity, R.string.master_password, R.string.key_master_password, { password -> passwordCheck.queryPassword(activity, R.string.master_password, R.string.key_master_password, { password ->
then(password) then(password)
}, { }, {
@ -130,7 +133,7 @@ class ImportExportPrefs @Inject constructor(
}) })
} }
private fun askForEncryptionPass(activity: Activity, @StringRes canceledMsg: Int, @StringRes passwordName: Int, @StringRes passwordExplanation: Int?, private fun askForEncryptionPass(activity: FragmentActivity, @StringRes canceledMsg: Int, @StringRes passwordName: Int, @StringRes passwordExplanation: Int?,
@StringRes passwordWarning: Int?, then: ((password: String) -> Unit)) { @StringRes passwordWarning: Int?, then: ((password: String) -> Unit)) {
passwordCheck.queryAnyPassword(activity, passwordName, R.string.key_master_password, passwordExplanation, passwordWarning, { password -> passwordCheck.queryAnyPassword(activity, passwordName, R.string.key_master_password, passwordExplanation, passwordWarning, { password ->
then(password) then(password)
@ -139,7 +142,7 @@ class ImportExportPrefs @Inject constructor(
}) })
} }
private fun askForMasterPassIfNeeded(activity: Activity, @StringRes canceledMsg: Int, then: ((password: String) -> Unit)) { private fun askForMasterPassIfNeeded(activity: FragmentActivity, @StringRes canceledMsg: Int, then: ((password: String) -> Unit)) {
if (prefsEncryptionIsDisabled()) { if (prefsEncryptionIsDisabled()) {
then("") then("")
} else { } else {
@ -147,7 +150,7 @@ class ImportExportPrefs @Inject constructor(
} }
} }
private fun assureMasterPasswordSet(activity: Activity, @StringRes wrongPwdTitle: Int): Boolean { private fun assureMasterPasswordSet(activity: FragmentActivity, @StringRes wrongPwdTitle: Int): Boolean {
if (!sp.contains(R.string.key_master_password) || (sp.getString(R.string.key_master_password, "") == "")) { if (!sp.contains(R.string.key_master_password) || (sp.getString(R.string.key_master_password, "") == "")) {
WarningDialog.showWarning(activity, WarningDialog.showWarning(activity,
resourceHelper.gs(wrongPwdTitle), resourceHelper.gs(wrongPwdTitle),
@ -163,23 +166,22 @@ class ImportExportPrefs @Inject constructor(
return true return true
} }
private fun askToConfirmExport(activity: Activity, fileToExport: File, then: ((password: String) -> Unit)) { private fun askToConfirmExport(activity: FragmentActivity, fileToExport: File, then: ((password: String) -> Unit)) {
if (!prefsEncryptionIsDisabled() && !assureMasterPasswordSet(activity, R.string.nav_export)) return if (!prefsEncryptionIsDisabled() && !assureMasterPasswordSet(activity, R.string.nav_export)) return
TwoMessagesAlertDialog.showAlert(activity, resourceHelper.gs(R.string.nav_export), TwoMessagesAlertDialog.showAlert(activity, resourceHelper.gs(R.string.nav_export),
resourceHelper.gs(R.string.export_to) + " " + fileToExport + " ?", resourceHelper.gs(R.string.export_to) + " " + fileToExport.name + " ?",
resourceHelper.gs(R.string.password_preferences_encrypt_prompt), { resourceHelper.gs(R.string.password_preferences_encrypt_prompt), {
askForMasterPassIfNeeded(activity, R.string.preferences_export_canceled, then) askForMasterPassIfNeeded(activity, R.string.preferences_export_canceled, then)
}, null, R.drawable.ic_header_export) }, null, R.drawable.ic_header_export)
} }
private fun askToConfirmImport(activity: Activity, fileToImport: PrefsFile, then: ((password: String) -> Unit)) { private fun askToConfirmImport(activity: FragmentActivity, fileToImport: PrefsFile, then: ((password: String) -> Unit)) {
if (fileToImport.handler == PrefsFormatsHandler.ENCRYPTED) { if (fileToImport.handler == PrefsFormatsHandler.ENCRYPTED) {
if (!assureMasterPasswordSet(activity, R.string.nav_import)) return if (!assureMasterPasswordSet(activity, R.string.nav_import)) return
TwoMessagesAlertDialog.showAlert(activity, resourceHelper.gs(R.string.nav_import), TwoMessagesAlertDialog.showAlert(activity, resourceHelper.gs(R.string.nav_import),
resourceHelper.gs(R.string.import_from) + " " + fileToImport.file + " ?", resourceHelper.gs(R.string.import_from) + " " + fileToImport.name + " ?",
resourceHelper.gs(R.string.password_preferences_decrypt_prompt), { resourceHelper.gs(R.string.password_preferences_decrypt_prompt), {
askForMasterPass(activity, R.string.preferences_import_canceled, then) askForMasterPass(activity, R.string.preferences_import_canceled, then)
}, null, R.drawable.ic_header_import) }, null, R.drawable.ic_header_import)
@ -191,7 +193,7 @@ class ImportExportPrefs @Inject constructor(
} }
} }
private fun promptForDecryptionPasswordIfNeeded(activity: Activity, prefs: Prefs, importOk: Boolean, private fun promptForDecryptionPasswordIfNeeded(activity: FragmentActivity, prefs: Prefs, importOk: Boolean,
format: PrefsFormat, importFile: PrefsFile, then: ((prefs: Prefs, importOk: Boolean) -> Unit)) { format: PrefsFormat, importFile: PrefsFile, then: ((prefs: Prefs, importOk: Boolean) -> Unit)) {
// current master password was not the one used for decryption, so we prompt for old password... // current master password was not the one used for decryption, so we prompt for old password...
@ -206,14 +208,14 @@ class ImportExportPrefs @Inject constructor(
// import is OK when we do not have errors (warnings are allowed) // import is OK when we do not have errors (warnings are allowed)
val importOkCheckedAgain = checkIfImportIsOk(prefsReloaded) val importOkCheckedAgain = checkIfImportIsOk(prefsReloaded)
then(prefsReloaded, importOkCheckedAgain); then(prefsReloaded, importOkCheckedAgain)
} }
} else { } else {
then(prefs, importOk); then(prefs, importOk)
} }
} }
private fun exportSharedPreferences(activity: Activity) { private fun exportSharedPreferences(activity: FragmentActivity) {
prefFileList.ensureExportDirExists() prefFileList.ensureExportDirExists()
val legacyFile = prefFileList.legacyFile() val legacyFile = prefFileList.legacyFile()
@ -262,14 +264,12 @@ class ImportExportPrefs @Inject constructor(
} }
fun importSharedPreferences(activity: FragmentActivity) { fun importSharedPreferences(activity: FragmentActivity) {
val callForPrefFile = activity.registerForActivityResult(PrefsFileContract()) {
it?.let {
importSharedPreferences(activity, it)
}
}
try { try {
callForPrefFile.launch(null) if (activity is SingleFragmentActivity)
activity.callForPrefFile.launch(null)
if (activity is MainActivity)
activity.callForPrefFile.launch(null)
} catch (e: IllegalArgumentException) { } catch (e: IllegalArgumentException) {
// this exception happens on some early implementations of ActivityResult contracts // this exception happens on some early implementations of ActivityResult contracts
// when registered and called for the second time // when registered and called for the second time
@ -278,12 +278,12 @@ class ImportExportPrefs @Inject constructor(
} }
} }
private fun importSharedPreferences(activity: Activity, importFile: PrefsFile) { fun importSharedPreferences(activity: FragmentActivity, importFile: PrefsFile) {
askToConfirmImport(activity, importFile) { password -> askToConfirmImport(activity, importFile) { password ->
val format: PrefsFormat = when (importFile.handler) { val format: PrefsFormat = when (importFile.handler) {
PrefsFormatsHandler.CLASSIC -> classicPrefsFormat PrefsFormatsHandler.CLASSIC -> classicPrefsFormat
PrefsFormatsHandler.ENCRYPTED -> encryptedPrefsFormat PrefsFormatsHandler.ENCRYPTED -> encryptedPrefsFormat
} }
@ -335,7 +335,7 @@ class ImportExportPrefs @Inject constructor(
for ((_, value) in prefs.metadata) { for ((_, value) in prefs.metadata) {
if (value.status == PrefsStatus.ERROR) if (value.status == PrefsStatus.ERROR)
importOk = false; importOk = false
} }
return importOk return importOk
} }
@ -345,7 +345,7 @@ class ImportExportPrefs @Inject constructor(
show(context, resourceHelper.gs(R.string.setting_imported), resourceHelper.gs(R.string.restartingapp), Runnable { show(context, resourceHelper.gs(R.string.setting_imported), resourceHelper.gs(R.string.restartingapp), Runnable {
log.debug(TAG, "Exiting") log.debug(TAG, "Exiting")
rxBus.send(EventAppExit()) rxBus.send(EventAppExit())
if (context is Activity) { if (context is AppCompatActivity) {
context.finish() context.finish()
} }
System.runFinalization() System.runFinalization()

View file

@ -46,13 +46,15 @@ class MaintenanceFragment : DaggerFragment() {
} }
nav_export.setOnClickListener { nav_export.setOnClickListener {
// start activity for checking permissions... // start activity for checking permissions...
importExportPrefs.verifyStoragePermissions(this) importExportPrefs.verifyStoragePermissions(this) {
importExportPrefs.exportSharedPreferences(this) importExportPrefs.exportSharedPreferences(this)
}
} }
nav_import.setOnClickListener { nav_import.setOnClickListener {
// start activity for checking permissions... // start activity for checking permissions...
importExportPrefs.verifyStoragePermissions(this) importExportPrefs.verifyStoragePermissions(this) {
importExportPrefs.importSharedPreferences(this) importExportPrefs.importSharedPreferences(this)
}
} }
nav_logsettings.setOnClickListener { startActivity(Intent(activity, LogSettingActivity::class.java)) } nav_logsettings.setOnClickListener { startActivity(Intent(activity, LogSettingActivity::class.java)) }
} }

View file

@ -40,6 +40,7 @@ class MaintenancePlugin @Inject constructor(
.fragmentClass(MaintenanceFragment::class.java.name) .fragmentClass(MaintenanceFragment::class.java.name)
.alwaysVisible(false) .alwaysVisible(false)
.alwaysEnabled(true) .alwaysEnabled(true)
.pluginIcon(R.drawable.ic_maintenance)
.pluginName(R.string.maintenance) .pluginName(R.string.maintenance)
.shortName(R.string.maintenance_shortname) .shortName(R.string.maintenance_shortname)
.preferencesId(R.xml.pref_maintenance) .preferencesId(R.xml.pref_maintenance)

View file

@ -1,20 +1,18 @@
package info.nightscout.androidaps.plugins.general.maintenance package info.nightscout.androidaps.plugins.general.maintenance
import android.app.Activity
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.os.Build import android.os.Build
import android.os.Environment import android.os.Environment
import android.os.Parcelable import android.os.Parcelable
import androidx.activity.result.contract.ActivityResultContract import androidx.activity.result.contract.ActivityResultContract
import androidx.fragment.app.FragmentActivity
import info.nightscout.androidaps.BuildConfig import info.nightscout.androidaps.BuildConfig
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.plugins.constraints.versionChecker.VersionCheckerUtils import info.nightscout.androidaps.plugins.constraints.versionChecker.VersionCheckerUtils
import info.nightscout.androidaps.plugins.general.maintenance.activities.PrefImportListActivity import info.nightscout.androidaps.plugins.general.maintenance.activities.PrefImportListActivity
import info.nightscout.androidaps.plugins.general.maintenance.formats.* import info.nightscout.androidaps.plugins.general.maintenance.formats.*
import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.sharedPreferences.SP
import info.nightscout.androidaps.utils.storage.Storage import info.nightscout.androidaps.utils.storage.Storage
import kotlinx.android.parcel.Parcelize import kotlinx.android.parcel.Parcelize
import kotlinx.android.parcel.RawValue import kotlinx.android.parcel.RawValue
@ -34,6 +32,7 @@ enum class PrefsImportDir {
@Parcelize @Parcelize
data class PrefsFile( data class PrefsFile(
val name: String,
val file: File, val file: File,
val baseDir: File, val baseDir: File,
val dirKind: PrefsImportDir, val dirKind: PrefsImportDir,
@ -46,13 +45,14 @@ data class PrefsFile(
class PrefsFileContract : ActivityResultContract<Void, PrefsFile>() { class PrefsFileContract : ActivityResultContract<Void, PrefsFile>() {
companion object { companion object {
const val OUTPUT_PARAM = "prefs_file" const val OUTPUT_PARAM = "prefs_file"
} }
override fun parseResult(resultCode: Int, intent: Intent?): PrefsFile? { override fun parseResult(resultCode: Int, intent: Intent?): PrefsFile? {
return when (resultCode) { return when (resultCode) {
Activity.RESULT_OK -> intent?.getParcelableExtra(OUTPUT_PARAM) FragmentActivity.RESULT_OK -> intent?.getParcelableExtra(OUTPUT_PARAM)
else -> null else -> null
} }
} }
@ -74,6 +74,7 @@ class PrefFileListProvider @Inject constructor(
) { ) {
companion object { companion object {
private val path = File(Environment.getExternalStorageDirectory().toString()) private val path = File(Environment.getExternalStorageDirectory().toString())
private val aapsPath = File(path, "AAPS" + File.separator + "preferences") private val aapsPath = File(path, "AAPS" + File.separator + "preferences")
private const val IMPORT_AGE_NOT_YET_OLD_DAYS = 60 private const val IMPORT_AGE_NOT_YET_OLD_DAYS = 60
@ -96,7 +97,7 @@ class PrefFileListProvider @Inject constructor(
val detectedOld = !detectedNew && classicPrefsFormat.isPreferencesFile(it, contents) val detectedOld = !detectedNew && classicPrefsFormat.isPreferencesFile(it, contents)
if (detectedNew || detectedOld) { if (detectedNew || detectedOld) {
val formatHandler = if (detectedNew) PrefsFormatsHandler.ENCRYPTED else PrefsFormatsHandler.CLASSIC val formatHandler = if (detectedNew) PrefsFormatsHandler.ENCRYPTED else PrefsFormatsHandler.CLASSIC
prefFiles.add(PrefsFile(it, path, PrefsImportDir.ROOT_DIR, formatHandler, metadataFor(loadMetadata, formatHandler, contents))) prefFiles.add(PrefsFile(it.name, it, path, PrefsImportDir.ROOT_DIR, formatHandler, metadataFor(loadMetadata, formatHandler, contents)))
} }
} }
@ -104,7 +105,7 @@ class PrefFileListProvider @Inject constructor(
aapsPath.walk().filter { it.isFile && it.name.endsWith(".json") }.forEach { aapsPath.walk().filter { it.isFile && it.name.endsWith(".json") }.forEach {
val contents = storage.getFileContents(it) val contents = storage.getFileContents(it)
if (encryptedPrefsFormat.isPreferencesFile(it, contents)) { if (encryptedPrefsFormat.isPreferencesFile(it, contents)) {
prefFiles.add(PrefsFile(it, aapsPath, PrefsImportDir.AAPS_DIR, PrefsFormatsHandler.ENCRYPTED, metadataFor(loadMetadata, PrefsFormatsHandler.ENCRYPTED, contents))) prefFiles.add(PrefsFile(it.name, it, aapsPath, PrefsImportDir.AAPS_DIR, PrefsFormatsHandler.ENCRYPTED, metadataFor(loadMetadata, PrefsFormatsHandler.ENCRYPTED, contents)))
} }
} }
@ -166,10 +167,10 @@ class PrefFileListProvider @Inject constructor(
meta[PrefsMetadataKey.CREATED_AT]?.let { createdAt -> meta[PrefsMetadataKey.CREATED_AT]?.let { createdAt ->
try { try {
val date1 = DateTime.parse(createdAt.value); val date1 = DateTime.parse(createdAt.value)
val date2 = DateTime.now() val date2 = DateTime.now()
val daysOld = Days.daysBetween(date1.toLocalDate(), date2.toLocalDate()).getDays() val daysOld = Days.daysBetween(date1.toLocalDate(), date2.toLocalDate()).days
if (daysOld > IMPORT_AGE_NOT_YET_OLD_DAYS) { if (daysOld > IMPORT_AGE_NOT_YET_OLD_DAYS) {
createdAt.status = PrefsStatus.WARN createdAt.status = PrefsStatus.WARN

View file

@ -1,6 +1,5 @@
package info.nightscout.androidaps.plugins.general.maintenance.activities package info.nightscout.androidaps.plugins.general.maintenance.activities
import android.app.Activity
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.os.Bundle import android.os.Bundle
@ -9,6 +8,7 @@ import android.view.MenuItem
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.TextView import android.widget.TextView
import androidx.fragment.app.FragmentActivity
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import dagger.android.support.DaggerAppCompatActivity import dagger.android.support.DaggerAppCompatActivity
@ -63,7 +63,7 @@ class PrefImportListActivity : DaggerAppCompatActivity() {
val i = Intent() val i = Intent()
i.putExtra(PrefsFileContract.OUTPUT_PARAM, prefFile) i.putExtra(PrefsFileContract.OUTPUT_PARAM, prefFile)
setResult(Activity.RESULT_OK, i) setResult(FragmentActivity.RESULT_OK, i)
finish() finish()
} }
} }

View file

@ -22,7 +22,7 @@ class ClassicPrefsFormat @Inject constructor(
override fun isPreferencesFile(file: File, preloadedContents: String?): Boolean { override fun isPreferencesFile(file: File, preloadedContents: String?): Boolean {
val contents = preloadedContents ?: storage.getFileContents(file) val contents = preloadedContents ?: storage.getFileContents(file)
return contents.contains("units::" + Constants.MGDL) || contents.contains("units::" + Constants.MMOL) return contents.contains("units::" + Constants.MGDL) || contents.contains("units::" + Constants.MMOL) || contents.contains("language::") || contents.contains("I_understand::")
} }
override fun savePreferences(file: File, prefs: Prefs, masterPassword: String?) { override fun savePreferences(file: File, prefs: Prefs, masterPassword: String?) {

View file

@ -244,7 +244,7 @@ class EncryptedPrefsFormat @Inject constructor(
metadata[PrefsMetadataKey.FILE_FORMAT] = PrefMetadata(resourceHelper.gs(R.string.prefdecrypt_wrong_json), PrefsStatus.ERROR) metadata[PrefsMetadataKey.FILE_FORMAT] = PrefMetadata(resourceHelper.gs(R.string.prefdecrypt_wrong_json), PrefsStatus.ERROR)
} }
return metadata; return metadata
} }
} }

View file

@ -37,7 +37,7 @@ public class NSClientFragment extends DaggerFragment implements View.OnClickList
@Inject UploadQueue uploadQueue; @Inject UploadQueue uploadQueue;
@Inject FabricPrivacy fabricPrivacy; @Inject FabricPrivacy fabricPrivacy;
private CompositeDisposable disposable = new CompositeDisposable(); private final CompositeDisposable disposable = new CompositeDisposable();
private TextView logTextView; private TextView logTextView;
private TextView queueTextView; private TextView queueTextView;

View file

@ -10,6 +10,7 @@ import android.os.IBinder;
import android.text.Spanned; import android.text.Spanned;
import androidx.preference.PreferenceFragmentCompat; import androidx.preference.PreferenceFragmentCompat;
import androidx.preference.SwitchPreference;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@ -50,7 +51,7 @@ import io.reactivex.schedulers.Schedulers;
@Singleton @Singleton
public class NSClientPlugin extends PluginBase { public class NSClientPlugin extends PluginBase {
private CompositeDisposable disposable = new CompositeDisposable(); private final CompositeDisposable disposable = new CompositeDisposable();
private final AAPSLogger aapsLogger; private final AAPSLogger aapsLogger;
private final RxBusWrapper rxBus; private final RxBusWrapper rxBus;
@ -72,7 +73,7 @@ public class NSClientPlugin extends PluginBase {
public NSClientService nsClientService = null; public NSClientService nsClientService = null;
private NsClientReceiverDelegate nsClientReceiverDelegate; private final NsClientReceiverDelegate nsClientReceiverDelegate;
@Inject @Inject
public NSClientPlugin( public NSClientPlugin(
@ -89,6 +90,7 @@ public class NSClientPlugin extends PluginBase {
super(new PluginDescription() super(new PluginDescription()
.mainType(PluginType.GENERAL) .mainType(PluginType.GENERAL)
.fragmentClass(NSClientFragment.class.getName()) .fragmentClass(NSClientFragment.class.getName())
.pluginIcon(R.drawable.ic_nightscout_syncs)
.pluginName(R.string.nsclientinternal) .pluginName(R.string.nsclientinternal)
.shortName(R.string.nsclientinternal_shortname) .shortName(R.string.nsclientinternal_shortname)
.preferencesId(R.xml.pref_nsclientinternal) .preferencesId(R.xml.pref_nsclientinternal)
@ -190,11 +192,25 @@ public class NSClientPlugin extends PluginBase {
super.preprocessPreferences(preferenceFragment); super.preprocessPreferences(preferenceFragment);
if (config.getNSCLIENT()) { if (config.getNSCLIENT()) {
preferenceFragment.findPreference(resourceHelper.gs(R.string.key_statuslights_overview_advanced)); SwitchPreference key_ns_uploadlocalprofile = preferenceFragment.findPreference(resourceHelper.gs(R.string.key_ns_uploadlocalprofile));
if (key_ns_uploadlocalprofile != null) key_ns_uploadlocalprofile.setVisible(false);
SwitchPreference key_ns_autobackfill = preferenceFragment.findPreference(resourceHelper.gs(R.string.key_ns_autobackfill));
if (key_ns_autobackfill != null) key_ns_autobackfill.setVisible(false);
SwitchPreference key_ns_create_announcements_from_errors = preferenceFragment.findPreference(resourceHelper.gs(R.string.key_ns_create_announcements_from_errors));
if (key_ns_create_announcements_from_errors != null) key_ns_create_announcements_from_errors.setVisible(false);
SwitchPreference key_ns_create_announcements_from_carbs_req = preferenceFragment.findPreference(resourceHelper.gs(R.string.key_ns_create_announcements_from_carbs_req));
if (key_ns_create_announcements_from_carbs_req != null) key_ns_create_announcements_from_carbs_req.setVisible(false);
SwitchPreference key_ns_upload_only = preferenceFragment.findPreference(resourceHelper.gs(R.string.key_ns_upload_only));
if (key_ns_upload_only != null) {
key_ns_upload_only.setVisible(false);
key_ns_upload_only.setEnabled(false);
}
SwitchPreference key_ns_sync_use_absolute = preferenceFragment.findPreference(resourceHelper.gs(R.string.key_ns_sync_use_absolute));
if (key_ns_sync_use_absolute != null) key_ns_sync_use_absolute.setVisible(false);
} }
} }
private ServiceConnection mConnection = new ServiceConnection() { private final ServiceConnection mConnection = new ServiceConnection() {
public void onServiceDisconnected(ComponentName name) { public void onServiceDisconnected(ComponentName name) {
aapsLogger.debug(LTag.NSCLIENT, "Service is disconnected"); aapsLogger.debug(LTag.NSCLIENT, "Service is disconnected");
@ -261,7 +277,7 @@ public class NSClientPlugin extends PluginBase {
} }
public boolean hasWritePermission() { public boolean hasWritePermission() {
return nsClientService.hasWriteAuth; return NSClientService.hasWriteAuth;
} }
public void handleClearAlarm(NSAlarm originalAlarm, long silenceTimeInMsec) { public void handleClearAlarm(NSAlarm originalAlarm, long silenceTimeInMsec) {

View file

@ -15,10 +15,13 @@ import javax.inject.Inject;
import javax.inject.Singleton; import javax.inject.Singleton;
import dagger.android.HasAndroidInjector; import dagger.android.HasAndroidInjector;
import info.nightscout.androidaps.Config;
import info.nightscout.androidaps.R; import info.nightscout.androidaps.R;
import info.nightscout.androidaps.interfaces.ConfigInterface;
import info.nightscout.androidaps.logging.AAPSLogger; import info.nightscout.androidaps.logging.AAPSLogger;
import info.nightscout.androidaps.logging.LTag; import info.nightscout.androidaps.logging.LTag;
import info.nightscout.androidaps.plugins.aps.loop.APSResult; import info.nightscout.androidaps.plugins.aps.loop.APSResult;
import info.nightscout.androidaps.plugins.configBuilder.RunningConfiguration;
import info.nightscout.androidaps.utils.DateUtil; import info.nightscout.androidaps.utils.DateUtil;
import info.nightscout.androidaps.utils.HtmlHelper; import info.nightscout.androidaps.utils.HtmlHelper;
import info.nightscout.androidaps.utils.Round; import info.nightscout.androidaps.utils.Round;
@ -85,6 +88,8 @@ public class NSDeviceStatus {
private final SP sp; private final SP sp;
private final ResourceHelper resourceHelper; private final ResourceHelper resourceHelper;
private final NSSettingsStatus nsSettingsStatus; private final NSSettingsStatus nsSettingsStatus;
private final ConfigInterface config;
private final RunningConfiguration runningConfiguration;
private JSONObject data = null; private JSONObject data = null;
@ -93,12 +98,16 @@ public class NSDeviceStatus {
AAPSLogger aapsLogger, AAPSLogger aapsLogger,
SP sp, SP sp,
ResourceHelper resourceHelper, ResourceHelper resourceHelper,
NSSettingsStatus nsSettingsStatus NSSettingsStatus nsSettingsStatus,
ConfigInterface config,
RunningConfiguration runningConfiguration
) { ) {
this.aapsLogger = aapsLogger; this.aapsLogger = aapsLogger;
this.sp = sp; this.sp = sp;
this.resourceHelper = resourceHelper; this.resourceHelper = resourceHelper;
this.nsSettingsStatus = nsSettingsStatus; this.nsSettingsStatus = nsSettingsStatus;
this.config = config;
this.runningConfiguration = runningConfiguration;
} }
public void handleNewData(JSONArray devicestatuses) { public void handleNewData(JSONArray devicestatuses) {
@ -114,8 +123,13 @@ public class NSDeviceStatus {
// Objectives 0 // Objectives 0
sp.putBoolean(R.string.key_ObjectivespumpStatusIsAvailableInNS, true); sp.putBoolean(R.string.key_ObjectivespumpStatusIsAvailableInNS, true);
} }
if (devicestatusJson.has("configuration") && config.getNSCLIENT()) {
// copy configuration of Insulin and Sensitivity from main AAPS
runningConfiguration.apply(devicestatusJson.getJSONObject("configuration"));
}
} }
} catch (JSONException ignored) { } catch (JSONException jsonException) {
jsonException.printStackTrace();
} }
} }
} }
@ -375,7 +389,7 @@ public class NSDeviceStatus {
// ********* Uploader data *********** // ********* Uploader data ***********
private static HashMap<String, Uploader> uploaders = new HashMap<>(); private static final HashMap<String, Uploader> uploaders = new HashMap<>();
static class Uploader { static class Uploader {
long clock = 0L; long clock = 0L;

View file

@ -10,9 +10,9 @@ import info.nightscout.androidaps.logging.LTag;
import info.nightscout.androidaps.logging.StacktraceLoggerWrapper; import info.nightscout.androidaps.logging.StacktraceLoggerWrapper;
public class NSTreatment { public class NSTreatment {
private static Logger log = StacktraceLoggerWrapper.getLogger(LTag.NSCLIENT); private static final Logger log = StacktraceLoggerWrapper.getLogger(LTag.NSCLIENT);
private JSONObject data; private final JSONObject data;
private String action = null; // "update", "remove" or null (add) private String action = null; // "update", "remove" or null (add)
public NSTreatment(JSONObject obj) { public NSTreatment(JSONObject obj) {

View file

@ -91,10 +91,10 @@ public class NSClientService extends DaggerService {
@Inject DateUtil dateUtil; @Inject DateUtil dateUtil;
@Inject UploadQueue uploadQueue; @Inject UploadQueue uploadQueue;
private CompositeDisposable disposable = new CompositeDisposable(); private final CompositeDisposable disposable = new CompositeDisposable();
static public PowerManager.WakeLock mWakeLock; static public PowerManager.WakeLock mWakeLock;
private IBinder mBinder = new NSClientService.LocalBinder(); private final IBinder mBinder = new NSClientService.LocalBinder();
static ProfileStore profileStore; static ProfileStore profileStore;
@ -123,9 +123,9 @@ public class NSClientService extends DaggerService {
private String nsAPIhashCode = ""; private String nsAPIhashCode = "";
private final ArrayList<Long> reconnections = new ArrayList<>(); private final ArrayList<Long> reconnections = new ArrayList<>();
private int WATCHDOG_INTERVAL_MINUTES = 2; private final int WATCHDOG_INTERVAL_MINUTES = 2;
private int WATCHDOG_RECONNECT_IN = 15; private final int WATCHDOG_RECONNECT_IN = 15;
private int WATCHDOG_MAXCONNECTIONS = 5; private final int WATCHDOG_MAXCONNECTIONS = 5;
public NSClientService() { public NSClientService() {
super(); super();
@ -322,7 +322,7 @@ public class NSClientService extends DaggerService {
} }
} }
private Emitter.Listener onConnect = new Emitter.Listener() { private final Emitter.Listener onConnect = new Emitter.Listener() {
@Override @Override
public void call(Object... args) { public void call(Object... args) {
connectCounter++; connectCounter++;
@ -360,7 +360,7 @@ public class NSClientService extends DaggerService {
} }
} }
private Emitter.Listener onDisconnect = new Emitter.Listener() { private final Emitter.Listener onDisconnect = new Emitter.Listener() {
@Override @Override
public void call(Object... args) { public void call(Object... args) {
aapsLogger.debug(LTag.NSCLIENT, "disconnect reason: {}", args); aapsLogger.debug(LTag.NSCLIENT, "disconnect reason: {}", args);
@ -412,7 +412,7 @@ public class NSClientService extends DaggerService {
nsDevice = sp.getString("careportal_enteredby", ""); nsDevice = sp.getString("careportal_enteredby", "");
} }
private Emitter.Listener onError = new Emitter.Listener() { private final Emitter.Listener onError = new Emitter.Listener() {
@Override @Override
public void call(final Object... args) { public void call(final Object... args) {
String msg = "Unknown Error"; String msg = "Unknown Error";
@ -423,7 +423,7 @@ public class NSClientService extends DaggerService {
} }
}; };
private Emitter.Listener onPing = new Emitter.Listener() { private final Emitter.Listener onPing = new Emitter.Listener() {
@Override @Override
public void call(final Object... args) { public void call(final Object... args) {
rxBus.send(new EventNSClientNewLog("PING", "received")); rxBus.send(new EventNSClientNewLog("PING", "received"));
@ -432,7 +432,7 @@ public class NSClientService extends DaggerService {
} }
}; };
private Emitter.Listener onAnnouncement = new Emitter.Listener() { private final Emitter.Listener onAnnouncement = new Emitter.Listener() {
/* /*
{ {
"level":0, "level":0,
@ -456,7 +456,7 @@ public class NSClientService extends DaggerService {
} }
}; };
private Emitter.Listener onAlarm = new Emitter.Listener() { private final Emitter.Listener onAlarm = new Emitter.Listener() {
/* /*
{ {
"level":1, "level":1,
@ -482,7 +482,7 @@ public class NSClientService extends DaggerService {
} }
}; };
private Emitter.Listener onUrgentAlarm = args -> { private final Emitter.Listener onUrgentAlarm = args -> {
JSONObject data; JSONObject data;
try { try {
data = (JSONObject) args[0]; data = (JSONObject) args[0];
@ -492,7 +492,7 @@ public class NSClientService extends DaggerService {
} }
}; };
private Emitter.Listener onClearAlarm = new Emitter.Listener() { private final Emitter.Listener onClearAlarm = new Emitter.Listener() {
/* /*
{ {
"clear":true, "clear":true,
@ -516,7 +516,7 @@ public class NSClientService extends DaggerService {
} }
}; };
private Emitter.Listener onDataUpdate = new Emitter.Listener() { private final Emitter.Listener onDataUpdate = new Emitter.Listener() {
@Override @Override
public void call(final Object... args) { public void call(final Object... args) {
NSClientService.handler.post(() -> { NSClientService.handler.post(() -> {

View file

@ -185,7 +185,7 @@ private val allowedKeys = """
tidepool_only_while_charging tidepool_only_while_charging
tidepool_only_while_unmetered tidepool_only_while_unmetered
virtualpump virtualpump
virtualpump_uploadstatus key_virtualpump_uploadstatus
virtualpump_type virtualpump_type
wearplugin wearplugin
wearcontrol wearcontrol

View file

@ -43,8 +43,8 @@ class OpenHumansAPI(
.toSingle() .toSingle()
.map { response -> .map { response ->
response.use { _ -> response.use { _ ->
val body = response.body val responseBody = response.body
val jsonObject = body?.let { JSONObject(it.string()) } val jsonObject = responseBody?.let { JSONObject(it.string()) }
if (!response.isSuccessful) throw OHHttpException(response.code, response.message, jsonObject?.getString("error")) if (!response.isSuccessful) throw OHHttpException(response.code, response.message, jsonObject?.getString("error"))
if (jsonObject == null) throw OHHttpException(response.code, response.message, "No body") if (jsonObject == null) throw OHHttpException(response.code, response.message, "No body")
if (!jsonObject.has("expires_in")) throw OHMissingFieldException("expires_in") if (!jsonObject.has("expires_in")) throw OHMissingFieldException("expires_in")

View file

@ -1,6 +1,5 @@
package info.nightscout.androidaps.plugins.general.openhumans package info.nightscout.androidaps.plugins.general.openhumans
import android.app.Activity
import android.app.Dialog import android.app.Dialog
import android.content.Intent import android.content.Intent
import android.net.Uri import android.net.Uri
@ -11,6 +10,7 @@ import android.widget.Toast
import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AlertDialog
import androidx.browser.customtabs.CustomTabsIntent import androidx.browser.customtabs.CustomTabsIntent
import androidx.fragment.app.DialogFragment import androidx.fragment.app.DialogFragment
import androidx.fragment.app.FragmentActivity
import dagger.android.support.DaggerDialogFragment import dagger.android.support.DaggerDialogFragment
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.activities.NoSplashAppCompatActivity import info.nightscout.androidaps.activities.NoSplashAppCompatActivity
@ -26,7 +26,7 @@ class OpenHumansLoginActivity : NoSplashAppCompatActivity() {
val button = findViewById<Button>(R.id.button) val button = findViewById<Button>(R.id.button)
val checkbox = findViewById<CheckBox>(R.id.checkbox) val checkbox = findViewById<CheckBox>(R.id.checkbox)
button.setOnClickListener { _ -> button.setOnClickListener {
if (checkbox.isChecked) { if (checkbox.isChecked) {
CustomTabsIntent.Builder().build().launchUrl(this, Uri.parse(OpenHumansUploader.AUTH_URL)) CustomTabsIntent.Builder().build().launchUrl(this, Uri.parse(OpenHumansUploader.AUTH_URL))
} else { } else {
@ -55,7 +55,7 @@ class OpenHumansLoginActivity : NoSplashAppCompatActivity() {
} }
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
return AlertDialog.Builder(activity!!) return AlertDialog.Builder(requireActivity())
.setTitle(R.string.completing_login) .setTitle(R.string.completing_login)
.setMessage(R.string.please_wait) .setMessage(R.string.please_wait)
.create() .create()
@ -65,10 +65,10 @@ class OpenHumansLoginActivity : NoSplashAppCompatActivity() {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
disposable = openHumansUploader.login(arguments?.getString("authToken")!!).subscribeOn(Schedulers.io()).subscribe({ disposable = openHumansUploader.login(arguments?.getString("authToken")!!).subscribeOn(Schedulers.io()).subscribe({
dismiss() dismiss()
SetupDoneDialog().show(fragmentManager!!, "SetupDoneDialog") SetupDoneDialog().show(parentFragmentManager, "SetupDoneDialog")
}, { }, {
dismiss() dismiss()
ErrorDialog(it.message).show(fragmentManager!!, "ErrorDialog") ErrorDialog(it.message).show(parentFragmentManager, "ErrorDialog")
}) })
} }
@ -96,7 +96,7 @@ class OpenHumansLoginActivity : NoSplashAppCompatActivity() {
val message = arguments?.getString("message") val message = arguments?.getString("message")
val shownMessage = if (message == null) getString(R.string.there_was_an_error) val shownMessage = if (message == null) getString(R.string.there_was_an_error)
else "${getString(R.string.there_was_an_error)}\n\n$message" else "${getString(R.string.there_was_an_error)}\n\n$message"
return AlertDialog.Builder(activity!!) return AlertDialog.Builder(requireActivity())
.setTitle(R.string.error) .setTitle(R.string.error)
.setMessage(shownMessage) .setMessage(shownMessage)
.setPositiveButton(R.string.close, null) .setPositiveButton(R.string.close, null)
@ -122,14 +122,14 @@ class OpenHumansLoginActivity : NoSplashAppCompatActivity() {
} }
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
return AlertDialog.Builder(activity!!) return AlertDialog.Builder(requireActivity())
.setTitle(R.string.successfully_logged_in) .setTitle(R.string.successfully_logged_in)
.setMessage(R.string.setup_will_continue_in_background) .setMessage(R.string.setup_will_continue_in_background)
.setCancelable(false) .setCancelable(false)
.setPositiveButton(R.string.close) { _, _ -> .setPositiveButton(R.string.close) { _, _ ->
activity!!.run { requireActivity().run {
setResult(Activity.RESULT_OK) setResult(FragmentActivity.RESULT_OK)
activity!!.finish() requireActivity().finish()
} }
} }
.create() .create()

View file

@ -59,6 +59,7 @@ class OpenHumansUploader @Inject constructor(
) : PluginBase( ) : PluginBase(
PluginDescription() PluginDescription()
.mainType(PluginType.GENERAL) .mainType(PluginType.GENERAL)
.pluginIcon(R.drawable.open_humans_white)
.pluginName(R.string.open_humans) .pluginName(R.string.open_humans)
.shortName(R.string.open_humans_short) .shortName(R.string.open_humans_short)
.description(R.string.donate_your_data_to_science) .description(R.string.donate_your_data_to_science)
@ -564,7 +565,7 @@ class OpenHumansUploader @Inject constructor(
creationDate = uploadDate.time creationDate = uploadDate.time
), ),
content = bytes, content = bytes,
highestQueueId = items.map { it.id }.max() highestQueueId = items.map { it.id }.maxOrNull()
)) ))
} }

View file

@ -11,10 +11,7 @@ import android.graphics.drawable.AnimationDrawable
import android.os.Bundle import android.os.Bundle
import android.os.Handler import android.os.Handler
import android.util.DisplayMetrics import android.util.DisplayMetrics
import android.view.ContextMenu
import android.view.ContextMenu.ContextMenuInfo
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.MenuItem
import android.view.View import android.view.View
import android.view.View.OnLongClickListener import android.view.View.OnLongClickListener
import android.view.ViewGroup import android.view.ViewGroup
@ -22,6 +19,7 @@ import android.widget.LinearLayout
import android.widget.RelativeLayout import android.widget.RelativeLayout
import android.widget.TextView import android.widget.TextView
import androidx.core.text.toSpanned import androidx.core.text.toSpanned
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import com.jjoe64.graphview.GraphView import com.jjoe64.graphview.GraphView
import dagger.android.HasAndroidInjector import dagger.android.HasAndroidInjector
@ -30,17 +28,9 @@ import info.nightscout.androidaps.Config
import info.nightscout.androidaps.Constants import info.nightscout.androidaps.Constants
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.data.Profile import info.nightscout.androidaps.data.Profile
import info.nightscout.androidaps.dialogs.CalibrationDialog import info.nightscout.androidaps.dialogs.*
import info.nightscout.androidaps.dialogs.CarbsDialog
import info.nightscout.androidaps.dialogs.InsulinDialog
import info.nightscout.androidaps.dialogs.TreatmentDialog
import info.nightscout.androidaps.dialogs.WizardDialog
import info.nightscout.androidaps.events.* import info.nightscout.androidaps.events.*
import info.nightscout.androidaps.interfaces.ActivePluginProvider import info.nightscout.androidaps.interfaces.*
import info.nightscout.androidaps.interfaces.Constraint
import info.nightscout.androidaps.interfaces.DatabaseHelperInterface
import info.nightscout.androidaps.interfaces.PluginType
import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin
import info.nightscout.androidaps.plugins.aps.loop.events.EventNewOpenLoopNotification import info.nightscout.androidaps.plugins.aps.loop.events.EventNewOpenLoopNotification
@ -56,6 +46,7 @@ import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventAutosensCalculationFinished import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventAutosensCalculationFinished
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventIobCalculationProgress import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventIobCalculationProgress
import info.nightscout.androidaps.plugins.pump.common.defs.PumpType
import info.nightscout.androidaps.plugins.source.DexcomPlugin import info.nightscout.androidaps.plugins.source.DexcomPlugin
import info.nightscout.androidaps.plugins.source.XdripPlugin import info.nightscout.androidaps.plugins.source.XdripPlugin
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin
@ -74,35 +65,16 @@ import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable import io.reactivex.disposables.CompositeDisposable
import io.reactivex.schedulers.Schedulers import io.reactivex.schedulers.Schedulers
import kotlinx.android.synthetic.main.overview_buttons_layout.* import kotlinx.android.synthetic.main.overview_buttons_layout.*
import kotlinx.android.synthetic.main.overview_buttons_layout.overview_carbsbutton
import kotlinx.android.synthetic.main.overview_buttons_layout.overview_insulinbutton
import kotlinx.android.synthetic.main.overview_buttons_layout.overview_quickwizardbutton
import kotlinx.android.synthetic.main.overview_buttons_layout.overview_treatmentbutton
import kotlinx.android.synthetic.main.overview_buttons_layout.overview_wizardbutton
import kotlinx.android.synthetic.main.overview_fragment.overview_notifications import kotlinx.android.synthetic.main.overview_fragment.overview_notifications
import kotlinx.android.synthetic.main.overview_fragment_nsclient_tablet.* import kotlinx.android.synthetic.main.overview_fragment_nsclient.*
import kotlinx.android.synthetic.main.overview_graphs_layout.overview_bggraph import kotlinx.android.synthetic.main.overview_graphs_layout.*
import kotlinx.android.synthetic.main.overview_graphs_layout.overview_chartMenuButton
import kotlinx.android.synthetic.main.overview_graphs_layout.overview_iobcalculationprogess
import kotlinx.android.synthetic.main.overview_graphs_layout.overview_iobgraph
import kotlinx.android.synthetic.main.overview_info_layout.* import kotlinx.android.synthetic.main.overview_info_layout.*
import kotlinx.android.synthetic.main.overview_info_layout.overview_arrow
import kotlinx.android.synthetic.main.overview_info_layout.overview_basebasal
import kotlinx.android.synthetic.main.overview_info_layout.overview_bg
import kotlinx.android.synthetic.main.overview_info_layout.overview_cob
import kotlinx.android.synthetic.main.overview_info_layout.overview_extendedbolus
import kotlinx.android.synthetic.main.overview_info_layout.overview_iob
import kotlinx.android.synthetic.main.overview_info_layout.overview_sensitivity
import kotlinx.android.synthetic.main.overview_loop_pumpstatus_layout.* import kotlinx.android.synthetic.main.overview_loop_pumpstatus_layout.*
import kotlinx.android.synthetic.main.overview_statuslights_layout.* import kotlinx.android.synthetic.main.overview_statuslights_layout.*
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import java.util.* import java.util.*
import java.util.concurrent.Executors
import java.util.concurrent.ScheduledFuture
import java.util.concurrent.TimeUnit
import javax.inject.Inject import javax.inject.Inject
import kotlin.collections.ArrayList import kotlin.collections.ArrayList
import kotlin.math.abs import kotlin.math.abs
@ -152,9 +124,6 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
private var loopHandler = Handler() private var loopHandler = Handler()
private var refreshLoop: Runnable? = null private var refreshLoop: Runnable? = null
private val worker = Executors.newSingleThreadScheduledExecutor()
private var scheduledUpdate: ScheduledFuture<*>? = null
private val secondaryGraphs = ArrayList<GraphView>() private val secondaryGraphs = ArrayList<GraphView>()
private val secondaryGraphsLabel = ArrayList<TextView>() private val secondaryGraphsLabel = ArrayList<TextView>()
@ -181,6 +150,9 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
// pre-process landscape mode
skinProvider.activeSkin().preProcessLandscapeOverviewLayout(dm, view, resourceHelper.gb(R.bool.isTablet))
overview_pumpstatus?.setBackgroundColor(resourceHelper.gc(R.color.colorInitializingBorder)) overview_pumpstatus?.setBackgroundColor(resourceHelper.gc(R.color.colorInitializingBorder))
overview_notifications?.setHasFixedSize(false) overview_notifications?.setHasFixedSize(false)
@ -205,9 +177,13 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
sp.putBoolean(R.string.key_objectiveusescale, true) sp.putBoolean(R.string.key_objectiveusescale, true)
false false
} }
prepareGraphsIfNeeded(overviewMenus.setting.size)
overviewMenus.setupChartMenu(overview_chartMenuButton) overviewMenus.setupChartMenu(overview_chartMenuButton)
prepareGraphs()
overview_activeprofile?.setOnClickListener(this)
overview_activeprofile?.setOnLongClickListener(this)
overview_temptarget?.setOnClickListener(this)
overview_temptarget?.setOnLongClickListener(this)
overview_accepttempbutton?.setOnClickListener(this) overview_accepttempbutton?.setOnClickListener(this)
overview_treatmentbutton?.setOnClickListener(this) overview_treatmentbutton?.setOnClickListener(this)
overview_wizardbutton?.setOnClickListener(this) overview_wizardbutton?.setOnClickListener(this)
@ -217,15 +193,15 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
overview_carbsbutton?.setOnClickListener(this) overview_carbsbutton?.setOnClickListener(this)
overview_quickwizardbutton?.setOnClickListener(this) overview_quickwizardbutton?.setOnClickListener(this)
overview_quickwizardbutton?.setOnLongClickListener(this) overview_quickwizardbutton?.setOnLongClickListener(this)
overview_apsmode?.setOnClickListener(this)
overview_apsmode?.setOnLongClickListener(this)
overview_activeprofile?.setOnLongClickListener(this)
} }
override fun onPause() { override fun onPause() {
super.onPause() super.onPause()
disposable.clear() disposable.clear()
loopHandler.removeCallbacksAndMessages(null) loopHandler.removeCallbacksAndMessages(null)
overview_apsmode_llayout?.let { unregisterForContextMenu(it) }
overview_activeprofile?.let { unregisterForContextMenu(it) }
overview_temptarget?.let { unregisterForContextMenu(it) }
} }
override fun onResume() { override fun onResume() {
@ -234,7 +210,6 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
.toObservable(EventRefreshOverview::class.java) .toObservable(EventRefreshOverview::class.java)
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
.subscribe({ .subscribe({
prepareGraphs()
if (it.now) updateGUI(it.from) if (it.now) updateGUI(it.from)
else scheduleUpdateGUI(it.from) else scheduleUpdateGUI(it.from)
}) { fabricPrivacy.logException(it) }) }) { fabricPrivacy.logException(it) })
@ -297,32 +272,30 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
} }
loopHandler.postDelayed(refreshLoop, 60 * 1000L) loopHandler.postDelayed(refreshLoop, 60 * 1000L)
overview_apsmode_llayout?.let { registerForContextMenu(overview_apsmode) }
overview_activeprofile?.let { registerForContextMenu(it) }
overview_temptarget?.let { registerForContextMenu(it) }
updateGUI("onResume") updateGUI("onResume")
} }
override fun onCreateContextMenu(menu: ContextMenu, v: View, menuInfo: ContextMenuInfo?) {
super.onCreateContextMenu(menu, v, menuInfo)
overviewMenus.createContextMenu(menu, v)
}
override fun onContextItemSelected(item: MenuItem): Boolean {
return if (overviewMenus.onContextItemSelected(item, childFragmentManager)) true else super.onContextItemSelected(item)
}
override fun onClick(v: View) { override fun onClick(v: View) {
// try to fix https://fabric.io/nightscout3/android/apps/info.nightscout.androidaps/issues/5aca7a1536c7b23527eb4be7?time=last-seven-days // try to fix https://fabric.io/nightscout3/android/apps/info.nightscout.androidaps/issues/5aca7a1536c7b23527eb4be7?time=last-seven-days
// https://stackoverflow.com/questions/14860239/checking-if-state-is-saved-before-committing-a-fragmenttransaction // https://stackoverflow.com/questions/14860239/checking-if-state-is-saved-before-committing-a-fragmenttransaction
if (childFragmentManager.isStateSaved) return if (childFragmentManager.isStateSaved) return
activity?.let { activity -> activity?.let { activity ->
when (v.id) { when (v.id) {
R.id.overview_treatmentbutton -> protectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, UIRunnable(Runnable { TreatmentDialog().show(childFragmentManager, "Overview") })) R.id.overview_treatmentbutton -> protectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, UIRunnable { TreatmentDialog().show(childFragmentManager, "Overview") })
R.id.overview_wizardbutton -> protectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, UIRunnable(Runnable { WizardDialog().show(childFragmentManager, "Overview") })) R.id.overview_wizardbutton -> protectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, UIRunnable { WizardDialog().show(childFragmentManager, "Overview") })
R.id.overview_insulinbutton -> protectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, UIRunnable(Runnable { InsulinDialog().show(childFragmentManager, "Overview") })) R.id.overview_insulinbutton -> protectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, UIRunnable { InsulinDialog().show(childFragmentManager, "Overview") })
R.id.overview_quickwizardbutton -> protectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, UIRunnable(Runnable { onClickQuickWizard() })) R.id.overview_quickwizardbutton -> protectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, UIRunnable { onClickQuickWizard() })
R.id.overview_carbsbutton -> protectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, UIRunnable(Runnable { CarbsDialog().show(childFragmentManager, "Overview") })) R.id.overview_carbsbutton -> protectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, UIRunnable { CarbsDialog().show(childFragmentManager, "Overview") })
R.id.overview_temptarget -> protectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, UIRunnable { TempTargetDialog().show(childFragmentManager, "Overview") })
R.id.overview_activeprofile -> {
val args = Bundle()
args.putLong("time", DateUtil.now())
args.putInt("mode", ProfileViewerDialog.Mode.RUNNING_PROFILE.ordinal)
val pvd = ProfileViewerDialog()
pvd.arguments = args
pvd.show(childFragmentManager, "ProfileViewDialog")
}
R.id.overview_cgmbutton -> { R.id.overview_cgmbutton -> {
if (xdripPlugin.isEnabled(PluginType.BGSOURCE)) if (xdripPlugin.isEnabled(PluginType.BGSOURCE))
@ -357,7 +330,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
loopPlugin.invoke("Accept temp button", false) loopPlugin.invoke("Accept temp button", false)
if (lastRun?.lastAPSRun != null && lastRun.constraintsProcessed?.isChangeRequested == true) { if (lastRun?.lastAPSRun != null && lastRun.constraintsProcessed?.isChangeRequested == true) {
OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.tempbasal_label), lastRun.constraintsProcessed?.toSpanned() OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.tempbasal_label), lastRun.constraintsProcessed?.toSpanned()
?: "".toSpanned(), Runnable { ?: "".toSpanned(), {
aapsLogger.debug("USER ENTRY: ACCEPT TEMP BASAL") aapsLogger.debug("USER ENTRY: ACCEPT TEMP BASAL")
overview_accepttempbutton?.visibility = View.GONE overview_accepttempbutton?.visibility = View.GONE
(context?.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager).cancel(Constants.notificationID) (context?.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager).cancel(Constants.notificationID)
@ -367,6 +340,14 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
} }
} }
} }
R.id.overview_apsmode -> {
val args = Bundle()
args.putInt("showOkCancel", 1) // 1-> true
val pvd = LoopDialog()
pvd.arguments = args
pvd.show(childFragmentManager, "Overview")
}
} }
} }
} }
@ -391,6 +372,18 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
startActivity(Intent(v.context, QuickWizardListActivity::class.java)) startActivity(Intent(v.context, QuickWizardListActivity::class.java))
return true return true
} }
R.id.overview_apsmode -> {
val args = Bundle()
args.putInt("showOkCancel", 0) // 0-> false
val pvd = LoopDialog()
pvd.arguments = args
pvd.show(childFragmentManager, "Overview")
}
R.id.overview_temptarget -> v.performClick()
R.id.overview_activeprofile -> activity?.let { activity -> protectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, UIRunnable { ProfileSwitchDialog().show(childFragmentManager, "Overview") }) }
} }
return false return false
} }
@ -477,10 +470,8 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
} }
private fun prepareGraphs() { private fun prepareGraphsIfNeeded(numOfGraphs: Int) {
synchronized(graphLock) { synchronized(graphLock) {
val numOfGraphs = overviewMenus.setting.size
if (numOfGraphs != secondaryGraphs.size - 1) { if (numOfGraphs != secondaryGraphs.size - 1) {
//aapsLogger.debug("New secondary graph count ${numOfGraphs-1}") //aapsLogger.debug("New secondary graph count ${numOfGraphs-1}")
// rebuild needed // rebuild needed
@ -516,21 +507,19 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
} }
} }
var task: Runnable? = null
private fun scheduleUpdateGUI(from: String) { private fun scheduleUpdateGUI(from: String) {
class UpdateRunnable : Runnable { class UpdateRunnable : Runnable {
override fun run() { override fun run() {
activity?.runOnUiThread { updateGUI(from)
updateGUI(from) task = null
scheduledUpdate = null
}
} }
} }
// prepare task for execution in 500 milliseconds view?.removeCallbacks(task)
// cancel waiting task to prevent multiple updates task = UpdateRunnable()
scheduledUpdate?.cancel(false) view?.postDelayed(task, 500)
val task: Runnable = UpdateRunnable()
scheduledUpdate = worker.schedule(task, 500, TimeUnit.MILLISECONDS)
} }
@SuppressLint("SetTextI18n") @SuppressLint("SetTextI18n")
@ -556,6 +545,14 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
val units = profileFunction.getUnits() val units = profileFunction.getUnits()
val lowLine = defaultValueHelper.determineLowLine() val lowLine = defaultValueHelper.determineLowLine()
val highLine = defaultValueHelper.determineHighLine() val highLine = defaultValueHelper.determineHighLine()
val lastRun = loopPlugin.lastRun
val predictionsAvailable = if (config.APS) lastRun?.request?.hasPredictions == true else config.NSCLIENT
try {
updateGraph(lastRun, predictionsAvailable, lowLine, highLine, pump, profile)
} catch (e: IllegalStateException) {
return // view no longer exists
}
//Start with updating the BG as it is unaffected by loop. //Start with updating the BG as it is unaffected by loop.
// **** BG value **** // **** BG value ****
@ -573,13 +570,15 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
val glucoseStatus = GlucoseStatus(injector).glucoseStatusData val glucoseStatus = GlucoseStatus(injector).glucoseStatusData
if (glucoseStatus != null) { if (glucoseStatus != null) {
overview_delta_large?.text = Profile.toSignedUnitsString(glucoseStatus.delta, glucoseStatus.delta * Constants.MGDL_TO_MMOLL, units)
overview_delta_large?.setTextColor(color)
overview_delta?.text = Profile.toSignedUnitsString(glucoseStatus.delta, glucoseStatus.delta * Constants.MGDL_TO_MMOLL, units) overview_delta?.text = Profile.toSignedUnitsString(glucoseStatus.delta, glucoseStatus.delta * Constants.MGDL_TO_MMOLL, units)
overview_deltashort?.text = Profile.toSignedUnitsString(glucoseStatus.delta, glucoseStatus.delta * Constants.MGDL_TO_MMOLL, units) overview_avgdelta?.text = "${Profile.toSignedUnitsString(glucoseStatus.short_avgdelta, glucoseStatus.short_avgdelta * Constants.MGDL_TO_MMOLL, units)}"
overview_avgdelta?.text = "${Profile.toSignedUnitsString(glucoseStatus.short_avgdelta, glucoseStatus.short_avgdelta * Constants.MGDL_TO_MMOLL, units)}\n${Profile.toSignedUnitsString(glucoseStatus.long_avgdelta, glucoseStatus.long_avgdelta * Constants.MGDL_TO_MMOLL, units)}" overview_long_avgdelta?.text = "${Profile.toSignedUnitsString(glucoseStatus.long_avgdelta, glucoseStatus.long_avgdelta * Constants.MGDL_TO_MMOLL, units)}"
} else { } else {
overview_delta?.text = "Δ " + resourceHelper.gs(R.string.notavailable) overview_delta?.text = "Δ " + resourceHelper.gs(R.string.notavailable)
overview_deltashort?.text = "---"
overview_avgdelta?.text = "" overview_avgdelta?.text = ""
overview_long_avgdelta?.text = ""
} }
// strike through if BG is old // strike through if BG is old
@ -596,56 +595,66 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
} }
val closedLoopEnabled = constraintChecker.isClosedLoopAllowed() val closedLoopEnabled = constraintChecker.isClosedLoopAllowed()
// open loop mode // aps mode
if (config.APS && pump.pumpDescription.isTempBasalCapable) { if (config.APS && pump.pumpDescription.isTempBasalCapable) {
overview_apsmode?.visibility = View.VISIBLE overview_apsmode?.visibility = View.VISIBLE
overview_time_llayout?.visibility = View.GONE
when { when {
loopPlugin.isEnabled() && loopPlugin.isSuperBolus -> { loopPlugin.isEnabled() && loopPlugin.isSuperBolus -> {
overview_apsmode?.setImageResource(R.drawable.ic_loop_superbolus) overview_apsmode?.setImageResource(R.drawable.ic_loop_superbolus)
overview_apsmode_text?.text = DateUtil.age(loopPlugin.minutesToEndOfSuspend() * 60000L, true, resourceHelper) overview_apsmode_text?.text = DateUtil.age(loopPlugin.minutesToEndOfSuspend() * 60000L, true, resourceHelper)
overview_apsmode_text?.visibility = View.VISIBLE
} }
loopPlugin.isDisconnected -> { loopPlugin.isDisconnected -> {
overview_apsmode?.setImageResource(R.drawable.ic_loop_disconnected) overview_apsmode?.setImageResource(R.drawable.ic_loop_disconnected)
overview_apsmode_text?.text = DateUtil.age(loopPlugin.minutesToEndOfSuspend() * 60000L, true, resourceHelper) overview_apsmode_text?.text = DateUtil.age(loopPlugin.minutesToEndOfSuspend() * 60000L, true, resourceHelper)
overview_apsmode_text?.visibility = View.VISIBLE
} }
loopPlugin.isEnabled() && loopPlugin.isSuspended -> { loopPlugin.isEnabled() && loopPlugin.isSuspended -> {
overview_apsmode?.setImageResource(R.drawable.ic_loop_paused) overview_apsmode?.setImageResource(R.drawable.ic_loop_paused)
overview_apsmode_text?.text = DateUtil.age(loopPlugin.minutesToEndOfSuspend() * 60000L, true, resourceHelper) overview_apsmode_text?.text = DateUtil.age(loopPlugin.minutesToEndOfSuspend() * 60000L, true, resourceHelper)
overview_apsmode_text?.visibility = View.VISIBLE
} }
pump.isSuspended -> { pump.isSuspended -> {
overview_apsmode?.setImageResource(R.drawable.ic_loop_paused) overview_apsmode?.setImageResource(if (pump.pumpDescription.pumpType == PumpType.Insulet_Omnipod) {
overview_apsmode_text?.text = "" // For Omnipod, indicate the pump as disconnected when it's suspended.
// The only way to 'reconnect' it, is through the Omnipod tab
R.drawable.ic_loop_disconnected
} else {
R.drawable.ic_loop_paused
})
overview_apsmode_text?.visibility = View.GONE
} }
loopPlugin.isEnabled() && closedLoopEnabled.value() && loopPlugin.isLGS -> { loopPlugin.isEnabled() && closedLoopEnabled.value() && loopPlugin.isLGS -> {
overview_apsmode?.setImageResource(R.drawable.ic_loop_lgs) overview_apsmode?.setImageResource(R.drawable.ic_loop_lgs)
overview_apsmode_text?.text = "" overview_apsmode_text?.visibility = View.GONE
} }
loopPlugin.isEnabled() && closedLoopEnabled.value() -> { loopPlugin.isEnabled() && closedLoopEnabled.value() -> {
overview_apsmode?.setImageResource(R.drawable.ic_loop_closed) overview_apsmode?.setImageResource(R.drawable.ic_loop_closed)
overview_apsmode_text?.text = "" overview_apsmode_text?.visibility = View.GONE
} }
loopPlugin.isEnabled() && !closedLoopEnabled.value() -> { loopPlugin.isEnabled() && !closedLoopEnabled.value() -> {
overview_apsmode?.setImageResource(R.drawable.ic_loop_open) overview_apsmode?.setImageResource(R.drawable.ic_loop_open)
overview_apsmode_text?.text = "" overview_apsmode_text?.visibility = View.GONE
} }
else -> { else -> {
overview_apsmode?.setImageResource(R.drawable.ic_loop_disabled) overview_apsmode?.setImageResource(R.drawable.ic_loop_disabled)
overview_apsmode_text?.text = "" overview_apsmode_text?.visibility = View.GONE
} }
} }
} else { } else {
//nsclient
overview_apsmode?.visibility = View.GONE overview_apsmode?.visibility = View.GONE
overview_apsmode_text?.visibility = View.GONE overview_apsmode_text?.visibility = View.GONE
overview_time_llayout?.visibility = View.VISIBLE
} }
val lastRun = loopPlugin.lastRun
val predictionsAvailable = if (config.APS) lastRun?.request?.hasPredictions == true else config.NSCLIENT
// temp target // temp target
val tempTarget = treatmentsPlugin.tempTargetFromHistory val tempTarget = treatmentsPlugin.tempTargetFromHistory
@ -671,7 +680,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
// Basal, TBR // Basal, TBR
val activeTemp = treatmentsPlugin.getTempBasalFromHistory(System.currentTimeMillis()) val activeTemp = treatmentsPlugin.getTempBasalFromHistory(System.currentTimeMillis())
overview_basebasal?.text = activeTemp?.let { if (resourceHelper.shortTextMode()) "T:" + activeTemp.toStringVeryShort() else activeTemp.toStringFull() } overview_basebasal?.text = activeTemp?.let { "T:" + activeTemp.toStringVeryShort() }
?: resourceHelper.gs(R.string.pump_basebasalrate, profile.basal) ?: resourceHelper.gs(R.string.pump_basebasalrate, profile.basal)
overview_basal_llayout?.setOnClickListener { overview_basal_llayout?.setOnClickListener {
var fullText = "${resourceHelper.gs(R.string.basebasalrate_label)}: ${resourceHelper.gs(R.string.pump_basebasalrate, profile.basal)}" var fullText = "${resourceHelper.gs(R.string.basebasalrate_label)}: ${resourceHelper.gs(R.string.pump_basebasalrate, profile.basal)}"
@ -692,10 +701,10 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
// Extended bolus // Extended bolus
val extendedBolus = treatmentsPlugin.getExtendedBolusFromHistory(System.currentTimeMillis()) val extendedBolus = treatmentsPlugin.getExtendedBolusFromHistory(System.currentTimeMillis())
overview_extendedbolus?.text = if (extendedBolus != null && !pump.isFakingTempsByExtendedBoluses) { overview_extendedbolus?.text =
if (resourceHelper.shortTextMode()) resourceHelper.gs(R.string.pump_basebasalrate, extendedBolus.absoluteRate()) if (extendedBolus != null && !pump.isFakingTempsByExtendedBoluses)
else extendedBolus.toStringMedium() resourceHelper.gs(R.string.pump_basebasalrate, extendedBolus.absoluteRate())
} else "" else ""
overview_extendedbolus?.setOnClickListener { overview_extendedbolus?.setOnClickListener {
if (extendedBolus != null) activity?.let { if (extendedBolus != null) activity?.let {
OKDialog.show(it, resourceHelper.gs(R.string.extended_bolus), extendedBolus.toString()) OKDialog.show(it, resourceHelper.gs(R.string.extended_bolus), extendedBolus.toString())
@ -720,15 +729,8 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
treatmentsPlugin.updateTotalIOBTempBasals() treatmentsPlugin.updateTotalIOBTempBasals()
val bolusIob = treatmentsPlugin.lastCalculationTreatments.round() val bolusIob = treatmentsPlugin.lastCalculationTreatments.round()
val basalIob = treatmentsPlugin.lastCalculationTempBasals.round() val basalIob = treatmentsPlugin.lastCalculationTempBasals.round()
overview_iob?.text = when { overview_iob?.text = resourceHelper.gs(R.string.formatinsulinunits, bolusIob.iob + basalIob.basaliob)
resourceHelper.shortTextMode() ->
resourceHelper.gs(R.string.formatinsulinunits, bolusIob.iob + basalIob.basaliob)
else ->
resourceHelper.gs(R.string.formatinsulinunits, bolusIob.iob + basalIob.basaliob) + " (" +
resourceHelper.gs(R.string.formatinsulinunits, bolusIob.iob) + "/" +
resourceHelper.gs(R.string.formatinsulinunits, basalIob.basaliob) + ")"
}
overview_iob_llayout?.setOnClickListener { overview_iob_llayout?.setOnClickListener {
activity?.let { activity?.let {
OKDialog.show(it, resourceHelper.gs(R.string.iob), OKDialog.show(it, resourceHelper.gs(R.string.iob),
@ -741,7 +743,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
// Status lights // Status lights
overview_statuslights?.visibility = (sp.getBoolean(R.string.key_show_statuslights, true) || config.NSCLIENT).toVisibility() overview_statuslights?.visibility = (sp.getBoolean(R.string.key_show_statuslights, true) || config.NSCLIENT).toVisibility()
statusLightHandler.updateStatusLights(careportal_canulaage, careportal_insulinage, careportal_reservoirlevel, careportal_sensorage, careportal_pbage, careportal_batterylevel) statusLightHandler.updateStatusLights(careportal_canulaage, careportal_insulinage, careportal_reservoirlevel, careportal_sensorage, null, careportal_pbage, careportal_batterylevel)
// cob // cob
var cobText: String = resourceHelper.gs(R.string.value_unavailable_short) var cobText: String = resourceHelper.gs(R.string.value_unavailable_short)
@ -790,10 +792,13 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
iobCobCalculatorPlugin.getLastAutosensData("Overview")?.let { autosensData -> iobCobCalculatorPlugin.getLastAutosensData("Overview")?.let { autosensData ->
String.format(Locale.ENGLISH, "%.0f%%", autosensData.autosensResult.ratio * 100) String.format(Locale.ENGLISH, "%.0f%%", autosensData.autosensResult.ratio * 100)
} ?: "" } ?: ""
}
// ****** GRAPH ******* private fun updateGraph(lastRun: LoopInterface.LastRun?, predictionsAvailable: Boolean, lowLine: Double, highLine: Double, pump: PumpInterface, profile: Profile) {
GlobalScope.launch(Dispatchers.Main) { viewLifecycleOwner.lifecycleScope.launch(Dispatchers.Main) {
overview_bggraph ?: return@launch overview_bggraph ?: return@launch
val menuChartSettings = overviewMenus.setting
prepareGraphsIfNeeded(menuChartSettings.size)
val graphData = GraphData(injector, overview_bggraph, iobCobCalculatorPlugin, treatmentsPlugin) val graphData = GraphData(injector, overview_bggraph, iobCobCalculatorPlugin, treatmentsPlugin)
val secondaryGraphsData: ArrayList<GraphData> = ArrayList() val secondaryGraphsData: ArrayList<GraphData> = ArrayList()
@ -811,7 +816,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
val fromTime: Long val fromTime: Long
val endTime: Long val endTime: Long
val apsResult = if (config.APS) lastRun?.constraintsProcessed else NSDeviceStatus.getAPSResult(injector) val apsResult = if (config.APS) lastRun?.constraintsProcessed else NSDeviceStatus.getAPSResult(injector)
if (predictionsAvailable && apsResult != null && overviewMenus.setting[0][OverviewMenus.CharType.PRE.ordinal]) { if (predictionsAvailable && apsResult != null && menuChartSettings[0][OverviewMenus.CharType.PRE.ordinal]) {
var predictionHours = (ceil(apsResult.latestPredictionsTime - System.currentTimeMillis().toDouble()) / (60 * 60 * 1000)).toInt() var predictionHours = (ceil(apsResult.latestPredictionsTime - System.currentTimeMillis().toDouble()) / (60 * 60 * 1000)).toInt()
predictionHours = min(2, predictionHours) predictionHours = min(2, predictionHours)
predictionHours = max(0, predictionHours) predictionHours = max(0, predictionHours)
@ -833,7 +838,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
graphData.addInRangeArea(fromTime, endTime, lowLine, highLine) graphData.addInRangeArea(fromTime, endTime, lowLine, highLine)
// **** BG **** // **** BG ****
if (predictionsAvailable && overviewMenus.setting[0][OverviewMenus.CharType.PRE.ordinal]) if (predictionsAvailable && menuChartSettings[0][OverviewMenus.CharType.PRE.ordinal])
graphData.addBgReadings(fromTime, toTime, lowLine, highLine, apsResult?.predictions) graphData.addBgReadings(fromTime, toTime, lowLine, highLine, apsResult?.predictions)
else graphData.addBgReadings(fromTime, toTime, lowLine, highLine, null) else graphData.addBgReadings(fromTime, toTime, lowLine, highLine, null)
@ -842,11 +847,11 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
// Treatments // Treatments
graphData.addTreatments(fromTime, endTime) graphData.addTreatments(fromTime, endTime)
if (overviewMenus.setting[0][OverviewMenus.CharType.ACT.ordinal]) if (menuChartSettings[0][OverviewMenus.CharType.ACT.ordinal])
graphData.addActivity(fromTime, endTime, false, 0.8) graphData.addActivity(fromTime, endTime, false, 0.8)
// add basal data // add basal data
if (pump.pumpDescription.isTempBasalCapable && overviewMenus.setting[0][OverviewMenus.CharType.BAS.ordinal]) if (pump.pumpDescription.isTempBasalCapable && menuChartSettings[0][OverviewMenus.CharType.BAS.ordinal])
graphData.addBasals(fromTime, now, lowLine / graphData.maxY / 1.2) graphData.addBasals(fromTime, now, lowLine / graphData.maxY / 1.2)
// add target line // add target line
@ -857,7 +862,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
// ------------------ 2nd graph // ------------------ 2nd graph
synchronized(graphLock) { synchronized(graphLock) {
for (g in 0 until min(secondaryGraphs.size, overviewMenus.setting.size + 1)) { for (g in 0 until min(secondaryGraphs.size, menuChartSettings.size + 1)) {
val secondGraphData = GraphData(injector, secondaryGraphs[g], iobCobCalculatorPlugin, treatmentsPlugin) val secondGraphData = GraphData(injector, secondaryGraphs[g], iobCobCalculatorPlugin, treatmentsPlugin)
var useABSForScale = false var useABSForScale = false
var useIobForScale = false var useIobForScale = false
@ -867,22 +872,22 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
var useDSForScale = false var useDSForScale = false
var useIAForScale = false var useIAForScale = false
when { when {
overviewMenus.setting[g + 1][OverviewMenus.CharType.ABS.ordinal] -> useABSForScale = true menuChartSettings[g + 1][OverviewMenus.CharType.ABS.ordinal] -> useABSForScale = true
overviewMenus.setting[g + 1][OverviewMenus.CharType.IOB.ordinal] -> useIobForScale = true menuChartSettings[g + 1][OverviewMenus.CharType.IOB.ordinal] -> useIobForScale = true
overviewMenus.setting[g + 1][OverviewMenus.CharType.COB.ordinal] -> useCobForScale = true menuChartSettings[g + 1][OverviewMenus.CharType.COB.ordinal] -> useCobForScale = true
overviewMenus.setting[g + 1][OverviewMenus.CharType.DEV.ordinal] -> useDevForScale = true menuChartSettings[g + 1][OverviewMenus.CharType.DEV.ordinal] -> useDevForScale = true
overviewMenus.setting[g + 1][OverviewMenus.CharType.SEN.ordinal] -> useRatioForScale = true menuChartSettings[g + 1][OverviewMenus.CharType.SEN.ordinal] -> useRatioForScale = true
overviewMenus.setting[g + 1][OverviewMenus.CharType.ACT.ordinal] -> useIAForScale = true menuChartSettings[g + 1][OverviewMenus.CharType.ACT.ordinal] -> useIAForScale = true
overviewMenus.setting[g + 1][OverviewMenus.CharType.DEVSLOPE.ordinal] -> useDSForScale = true menuChartSettings[g + 1][OverviewMenus.CharType.DEVSLOPE.ordinal] -> useDSForScale = true
} }
if (overviewMenus.setting[g + 1][OverviewMenus.CharType.ABS.ordinal]) secondGraphData.addAbsIob(fromTime, now, useABSForScale, 1.0) if (menuChartSettings[g + 1][OverviewMenus.CharType.ABS.ordinal]) secondGraphData.addAbsIob(fromTime, now, useABSForScale, 1.0)
if (overviewMenus.setting[g + 1][OverviewMenus.CharType.IOB.ordinal]) secondGraphData.addIob(fromTime, now, useIobForScale, 1.0, overviewMenus.setting[g + 1][OverviewMenus.CharType.PRE.ordinal]) if (menuChartSettings[g + 1][OverviewMenus.CharType.IOB.ordinal]) secondGraphData.addIob(fromTime, now, useIobForScale, 1.0, menuChartSettings[g + 1][OverviewMenus.CharType.PRE.ordinal])
if (overviewMenus.setting[g + 1][OverviewMenus.CharType.COB.ordinal]) secondGraphData.addCob(fromTime, now, useCobForScale, if (useCobForScale) 1.0 else 0.5) if (menuChartSettings[g + 1][OverviewMenus.CharType.COB.ordinal]) secondGraphData.addCob(fromTime, now, useCobForScale, if (useCobForScale) 1.0 else 0.5)
if (overviewMenus.setting[g + 1][OverviewMenus.CharType.DEV.ordinal]) secondGraphData.addDeviations(fromTime, now, useDevForScale, 1.0) if (menuChartSettings[g + 1][OverviewMenus.CharType.DEV.ordinal]) secondGraphData.addDeviations(fromTime, now, useDevForScale, 1.0)
if (overviewMenus.setting[g + 1][OverviewMenus.CharType.SEN.ordinal]) secondGraphData.addRatio(fromTime, now, useRatioForScale, 1.0) if (menuChartSettings[g + 1][OverviewMenus.CharType.SEN.ordinal]) secondGraphData.addRatio(fromTime, now, useRatioForScale, 1.0)
if (overviewMenus.setting[g + 1][OverviewMenus.CharType.ACT.ordinal]) secondGraphData.addActivity(fromTime, endTime, useIAForScale, 0.8) if (menuChartSettings[g + 1][OverviewMenus.CharType.ACT.ordinal]) secondGraphData.addActivity(fromTime, endTime, useIAForScale, 0.8)
if (overviewMenus.setting[g + 1][OverviewMenus.CharType.DEVSLOPE.ordinal] && buildHelper.isDev()) secondGraphData.addDeviationSlope(fromTime, now, useDSForScale, 1.0) if (menuChartSettings[g + 1][OverviewMenus.CharType.DEVSLOPE.ordinal] && buildHelper.isDev()) secondGraphData.addDeviationSlope(fromTime, now, useDSForScale, 1.0)
// set manual x bounds to have nice steps // set manual x bounds to have nice steps
secondGraphData.formatAxis(fromTime, endTime) secondGraphData.formatAxis(fromTime, endTime)
@ -894,16 +899,16 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
// finally enforce drawing of graphs in UI thread // finally enforce drawing of graphs in UI thread
graphData.performUpdate() graphData.performUpdate()
synchronized(graphLock) { synchronized(graphLock) {
for (g in 0 until min(secondaryGraphs.size, overviewMenus.setting.size + 1)) { for (g in 0 until min(secondaryGraphs.size, menuChartSettings.size + 1)) {
secondaryGraphsLabel[g].text = overviewMenus.enabledTypes(g + 1) secondaryGraphsLabel[g].text = overviewMenus.enabledTypes(g + 1)
secondaryGraphs[g].visibility = ( secondaryGraphs[g].visibility = (
overviewMenus.setting[g + 1][OverviewMenus.CharType.ABS.ordinal] || menuChartSettings[g + 1][OverviewMenus.CharType.ABS.ordinal] ||
overviewMenus.setting[g + 1][OverviewMenus.CharType.IOB.ordinal] || menuChartSettings[g + 1][OverviewMenus.CharType.IOB.ordinal] ||
overviewMenus.setting[g + 1][OverviewMenus.CharType.COB.ordinal] || menuChartSettings[g + 1][OverviewMenus.CharType.COB.ordinal] ||
overviewMenus.setting[g + 1][OverviewMenus.CharType.DEV.ordinal] || menuChartSettings[g + 1][OverviewMenus.CharType.DEV.ordinal] ||
overviewMenus.setting[g + 1][OverviewMenus.CharType.SEN.ordinal] || menuChartSettings[g + 1][OverviewMenus.CharType.SEN.ordinal] ||
overviewMenus.setting[g + 1][OverviewMenus.CharType.ACT.ordinal] || menuChartSettings[g + 1][OverviewMenus.CharType.ACT.ordinal] ||
overviewMenus.setting[g + 1][OverviewMenus.CharType.DEVSLOPE.ordinal] menuChartSettings[g + 1][OverviewMenus.CharType.DEVSLOPE.ordinal]
).toVisibility() ).toVisibility()
secondaryGraphsData[g].performUpdate() secondaryGraphsData[g].performUpdate()
} }

View file

@ -1,43 +1,20 @@
package info.nightscout.androidaps.plugins.general.overview package info.nightscout.androidaps.plugins.general.overview
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.text.SpannableString import android.text.SpannableString
import android.text.style.ForegroundColorSpan import android.text.style.ForegroundColorSpan
import android.view.ContextMenu
import android.view.Menu import android.view.Menu
import android.view.MenuItem
import android.view.View import android.view.View
import android.widget.ImageButton import android.widget.ImageButton
import androidx.annotation.ColorRes import androidx.annotation.ColorRes
import androidx.annotation.StringRes import androidx.annotation.StringRes
import androidx.appcompat.widget.PopupMenu import androidx.appcompat.widget.PopupMenu
import androidx.fragment.app.FragmentManager
import com.google.gson.Gson import com.google.gson.Gson
import info.nightscout.androidaps.Config import info.nightscout.androidaps.Config
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.activities.ErrorHelperActivity
import info.nightscout.androidaps.data.Profile
import info.nightscout.androidaps.db.Source
import info.nightscout.androidaps.db.TempTarget
import info.nightscout.androidaps.dialogs.ProfileSwitchDialog
import info.nightscout.androidaps.dialogs.ProfileViewerDialog
import info.nightscout.androidaps.dialogs.TempTargetDialog
import info.nightscout.androidaps.events.EventRefreshOverview import info.nightscout.androidaps.events.EventRefreshOverview
import info.nightscout.androidaps.interfaces.ActivePluginProvider
import info.nightscout.androidaps.interfaces.CommandQueueProvider
import info.nightscout.androidaps.interfaces.PluginType
import info.nightscout.androidaps.interfaces.PumpDescription
import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin
import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin
import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.androidaps.queue.Callback
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.DefaultValueHelper
import info.nightscout.androidaps.utils.ToastUtils
import info.nightscout.androidaps.utils.buildHelper.BuildHelper import info.nightscout.androidaps.utils.buildHelper.BuildHelper
import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.sharedPreferences.SP import info.nightscout.androidaps.utils.sharedPreferences.SP
@ -50,13 +27,7 @@ class OverviewMenus @Inject constructor(
private val resourceHelper: ResourceHelper, private val resourceHelper: ResourceHelper,
private val sp: SP, private val sp: SP,
private val rxBus: RxBusWrapper, private val rxBus: RxBusWrapper,
private val context: Context,
private val buildHelper: BuildHelper, private val buildHelper: BuildHelper,
private val defaultValueHelper: DefaultValueHelper,
private val activePlugin: ActivePluginProvider,
private val profileFunction: ProfileFunction,
private val commandQueue: CommandQueueProvider,
private val configBuilderPlugin: ConfigBuilderPlugin,
private val loopPlugin: LoopPlugin, private val loopPlugin: LoopPlugin,
private val config: Config private val config: Config
) { ) {
@ -79,17 +50,22 @@ class OverviewMenus @Inject constructor(
fun enabledTypes(graph: Int): String { fun enabledTypes(graph: Int): String {
val r = StringBuilder() val r = StringBuilder()
for (type in CharType.values()) if (setting[graph][type.ordinal]) { for (type in CharType.values()) if (_setting[graph][type.ordinal]) {
r.append(resourceHelper.gs(type.shortnameId)) r.append(resourceHelper.gs(type.shortnameId))
r.append(" ") r.append(" ")
} }
return r.toString() return r.toString()
} }
var setting: MutableList<Array<Boolean>> = ArrayList()
private var _setting: MutableList<Array<Boolean>> = ArrayList()
val setting: List<Array<Boolean>>
get() = _setting.toMutableList() // implicitly does a list copy
private fun storeGraphConfig() { private fun storeGraphConfig() {
val sts = Gson().toJson(setting) val sts = Gson().toJson(_setting)
sp.putString(R.string.key_graphconfig, sts) sp.putString(R.string.key_graphconfig, sts)
aapsLogger.debug(sts) aapsLogger.debug(sts)
} }
@ -97,22 +73,22 @@ class OverviewMenus @Inject constructor(
private fun loadGraphConfig() { private fun loadGraphConfig() {
val sts = sp.getString(R.string.key_graphconfig, "") val sts = sp.getString(R.string.key_graphconfig, "")
if (sts.isNotEmpty()) { if (sts.isNotEmpty()) {
setting = Gson().fromJson(sts, Array<Array<Boolean>>::class.java).toMutableList() _setting = Gson().fromJson(sts, Array<Array<Boolean>>::class.java).toMutableList()
// reset when new CharType added // reset when new CharType added
for (s in setting) for (s in _setting)
if (s.size != CharType.values().size) { if (s.size != CharType.values().size) {
setting = ArrayList() _setting = ArrayList()
setting.add(Array(CharType.values().size) { true }) _setting.add(Array(CharType.values().size) { true })
} }
} else { } else {
setting = ArrayList() _setting = ArrayList()
setting.add(Array(CharType.values().size) { true }) _setting.add(Array(CharType.values().size) { true })
} }
} }
fun setupChartMenu(chartButton: ImageButton) { fun setupChartMenu(chartButton: ImageButton) {
loadGraphConfig() loadGraphConfig()
val numOfGraphs = setting.size // 1 main + x secondary val numOfGraphs = _setting.size // 1 main + x secondary
chartButton.setOnClickListener { v: View -> chartButton.setOnClickListener { v: View ->
val predictionsAvailable: Boolean = when { val predictionsAvailable: Boolean = when {
@ -141,7 +117,7 @@ class OverviewMenus @Inject constructor(
s.setSpan(ForegroundColorSpan(resourceHelper.gc(m.colorId)), 0, s.length, 0) s.setSpan(ForegroundColorSpan(resourceHelper.gc(m.colorId)), 0, s.length, 0)
item.title = s item.title = s
item.isCheckable = true item.isCheckable = true
item.isChecked = setting[g][m.ordinal] item.isChecked = _setting[g][m.ordinal]
} }
} }
} }
@ -155,14 +131,14 @@ class OverviewMenus @Inject constructor(
// id < 100 graph header - divider 1, 2, 3 ..... // id < 100 graph header - divider 1, 2, 3 .....
if (it.itemId == numOfGraphs) { if (it.itemId == numOfGraphs) {
// add new empty // add new empty
setting.add(Array(CharType.values().size) { false }) _setting.add(Array(CharType.values().size) { false })
} else if (it.itemId < 100) { } else if (it.itemId < 100) {
// remove graph // remove graph
setting.removeAt(it.itemId) _setting.removeAt(it.itemId)
} else { } else {
val graphNumber = it.itemId / 100 - 1 val graphNumber = it.itemId / 100 - 1
val item = it.itemId % 100 val item = it.itemId % 100
setting[graphNumber][item] = !it.isChecked _setting[graphNumber][item] = !it.isChecked
} }
storeGraphConfig() storeGraphConfig()
setupChartMenu(chartButton) setupChartMenu(chartButton)
@ -175,247 +151,4 @@ class OverviewMenus @Inject constructor(
} }
} }
fun createContextMenu(menu: ContextMenu, v: View) {
when (v.id) {
R.id.overview_apsmode -> {
val pumpDescription: PumpDescription = activePlugin.activePump.pumpDescription
if (!profileFunction.isProfileValid("ContextMenuCreation")) return
menu.setHeaderTitle(resourceHelper.gs(R.string.loop))
if (loopPlugin.isEnabled(PluginType.LOOP)) {
menu.add(resourceHelper.gs(R.string.disableloop))
if (!loopPlugin.isSuspended) {
menu.add(resourceHelper.gs(R.string.suspendloopfor1h))
menu.add(resourceHelper.gs(R.string.suspendloopfor2h))
menu.add(resourceHelper.gs(R.string.suspendloopfor3h))
menu.add(resourceHelper.gs(R.string.suspendloopfor10h))
} else {
if (!loopPlugin.isDisconnected) {
menu.add(resourceHelper.gs(R.string.resume))
}
}
}
if (!loopPlugin.isEnabled(PluginType.LOOP)) {
menu.add(resourceHelper.gs(R.string.enableloop))
}
if (!loopPlugin.isDisconnected) {
showSuspendPump(menu, pumpDescription)
} else {
menu.add(resourceHelper.gs(R.string.reconnect))
}
}
R.id.overview_activeprofile -> {
menu.setHeaderTitle(resourceHelper.gs(R.string.profile))
menu.add(resourceHelper.gs(R.string.viewprofile))
if (activePlugin.activeProfileInterface.profile != null) {
menu.add(resourceHelper.gs(R.string.careportal_profileswitch))
}
}
R.id.overview_temptarget -> {
menu.setHeaderTitle(resourceHelper.gs(R.string.careportal_temporarytarget))
menu.add(resourceHelper.gs(R.string.custom))
menu.add(resourceHelper.gs(R.string.eatingsoon))
menu.add(resourceHelper.gs(R.string.activity))
menu.add(resourceHelper.gs(R.string.hypo))
if (activePlugin.activeTreatments.tempTargetFromHistory != null) {
menu.add(resourceHelper.gs(R.string.cancel))
}
}
}
}
private fun showSuspendPump(menu: ContextMenu, pumpDescription: PumpDescription) {
if (pumpDescription.tempDurationStep15mAllowed) menu.add(resourceHelper.gs(R.string.disconnectpumpfor15m))
if (pumpDescription.tempDurationStep30mAllowed) menu.add(resourceHelper.gs(R.string.disconnectpumpfor30m))
menu.add(resourceHelper.gs(R.string.disconnectpumpfor1h))
menu.add(resourceHelper.gs(R.string.disconnectpumpfor2h))
menu.add(resourceHelper.gs(R.string.disconnectpumpfor3h))
}
fun onContextItemSelected(item: MenuItem, manager: FragmentManager): Boolean {
val profile = profileFunction.getProfile() ?: return true
when (item.title) {
resourceHelper.gs(R.string.disableloop) -> {
aapsLogger.debug("USER ENTRY: LOOP DISABLED")
loopPlugin.setPluginEnabled(PluginType.LOOP, false)
loopPlugin.setFragmentVisible(PluginType.LOOP, false)
configBuilderPlugin.storeSettings("DisablingLoop")
rxBus.send(EventRefreshOverview("suspendmenu"))
commandQueue.cancelTempBasal(true, object : Callback() {
override fun run() {
if (!result.success) {
ToastUtils.showToastInUiThread(context, resourceHelper.gs(R.string.tempbasaldeliveryerror))
}
}
})
loopPlugin.createOfflineEvent(24 * 60) // upload 24h, we don't know real duration
return true
}
resourceHelper.gs(R.string.enableloop) -> {
aapsLogger.debug("USER ENTRY: LOOP ENABLED")
loopPlugin.setPluginEnabled(PluginType.LOOP, true)
loopPlugin.setFragmentVisible(PluginType.LOOP, true)
configBuilderPlugin.storeSettings("EnablingLoop")
rxBus.send(EventRefreshOverview("suspendmenu"))
loopPlugin.createOfflineEvent(0)
return true
}
resourceHelper.gs(R.string.resume), resourceHelper.gs(R.string.reconnect) -> {
aapsLogger.debug("USER ENTRY: RESUME")
loopPlugin.suspendTo(0L)
rxBus.send(EventRefreshOverview("suspendmenu"))
commandQueue.cancelTempBasal(true, object : Callback() {
override fun run() {
if (!result.success) {
val i = Intent(context, ErrorHelperActivity::class.java)
i.putExtra("soundid", R.raw.boluserror)
i.putExtra("status", result.comment)
i.putExtra("title", resourceHelper.gs(R.string.tempbasaldeliveryerror))
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
context.startActivity(i)
}
}
})
sp.putBoolean(R.string.key_objectiveusereconnect, true)
loopPlugin.createOfflineEvent(0)
return true
}
resourceHelper.gs(R.string.suspendloopfor1h) -> {
aapsLogger.debug("USER ENTRY: SUSPEND 1h")
loopPlugin.suspendLoop(60)
rxBus.send(EventRefreshOverview("suspendmenu"))
return true
}
resourceHelper.gs(R.string.suspendloopfor2h) -> {
aapsLogger.debug("USER ENTRY: SUSPEND 2h")
loopPlugin.suspendLoop(120)
rxBus.send(EventRefreshOverview("suspendmenu"))
return true
}
resourceHelper.gs(R.string.suspendloopfor3h) -> {
aapsLogger.debug("USER ENTRY: SUSPEND 3h")
loopPlugin.suspendLoop(180)
rxBus.send(EventRefreshOverview("suspendmenu"))
return true
}
resourceHelper.gs(R.string.suspendloopfor10h) -> {
aapsLogger.debug("USER ENTRY: SUSPEND 10h")
loopPlugin.suspendLoop(600)
rxBus.send(EventRefreshOverview("suspendmenu"))
return true
}
resourceHelper.gs(R.string.disconnectpumpfor15m) -> {
aapsLogger.debug("USER ENTRY: DISCONNECT 15m")
loopPlugin.disconnectPump(15, profile)
rxBus.send(EventRefreshOverview("suspendmenu"))
return true
}
resourceHelper.gs(R.string.disconnectpumpfor30m) -> {
aapsLogger.debug("USER ENTRY: DISCONNECT 30m")
loopPlugin.disconnectPump(30, profile)
rxBus.send(EventRefreshOverview("suspendmenu"))
return true
}
resourceHelper.gs(R.string.disconnectpumpfor1h) -> {
aapsLogger.debug("USER ENTRY: DISCONNECT 1h")
loopPlugin.disconnectPump(60, profile)
sp.putBoolean(R.string.key_objectiveusedisconnect, true)
rxBus.send(EventRefreshOverview("suspendmenu"))
return true
}
resourceHelper.gs(R.string.disconnectpumpfor2h) -> {
aapsLogger.debug("USER ENTRY: DISCONNECT 2h")
loopPlugin.disconnectPump(120, profile)
rxBus.send(EventRefreshOverview("suspendmenu"))
return true
}
resourceHelper.gs(R.string.disconnectpumpfor3h) -> {
aapsLogger.debug("USER ENTRY: DISCONNECT 3h")
loopPlugin.disconnectPump(180, profile)
rxBus.send(EventRefreshOverview("suspendmenu"))
return true
}
resourceHelper.gs(R.string.careportal_profileswitch) -> {
ProfileSwitchDialog().show(manager, "Overview")
}
resourceHelper.gs(R.string.viewprofile) -> {
val args = Bundle()
args.putLong("time", DateUtil.now())
args.putInt("mode", ProfileViewerDialog.Mode.RUNNING_PROFILE.ordinal)
val pvd = ProfileViewerDialog()
pvd.arguments = args
pvd.show(manager, "ProfileViewDialog")
}
resourceHelper.gs(R.string.eatingsoon) -> {
aapsLogger.debug("USER ENTRY: TEMP TARGET EATING SOON")
val target = Profile.toMgdl(defaultValueHelper.determineEatingSoonTT(), profileFunction.getUnits())
val tempTarget = TempTarget()
.date(System.currentTimeMillis())
.duration(defaultValueHelper.determineEatingSoonTTDuration())
.reason(resourceHelper.gs(R.string.eatingsoon))
.source(Source.USER)
.low(target)
.high(target)
activePlugin.activeTreatments.addToHistoryTempTarget(tempTarget)
}
resourceHelper.gs(R.string.activity) -> {
aapsLogger.debug("USER ENTRY: TEMP TARGET ACTIVITY")
val target = Profile.toMgdl(defaultValueHelper.determineActivityTT(), profileFunction.getUnits())
val tempTarget = TempTarget()
.date(DateUtil.now())
.duration(defaultValueHelper.determineActivityTTDuration())
.reason(resourceHelper.gs(R.string.activity))
.source(Source.USER)
.low(target)
.high(target)
activePlugin.activeTreatments.addToHistoryTempTarget(tempTarget)
}
resourceHelper.gs(R.string.hypo) -> {
aapsLogger.debug("USER ENTRY: TEMP TARGET HYPO")
val target = Profile.toMgdl(defaultValueHelper.determineHypoTT(), profileFunction.getUnits())
val tempTarget = TempTarget()
.date(DateUtil.now())
.duration(defaultValueHelper.determineHypoTTDuration())
.reason(resourceHelper.gs(R.string.hypo))
.source(Source.USER)
.low(target)
.high(target)
activePlugin.activeTreatments.addToHistoryTempTarget(tempTarget)
}
resourceHelper.gs(R.string.custom) -> {
TempTargetDialog().show(manager, "Overview")
}
resourceHelper.gs(R.string.cancel) -> {
aapsLogger.debug("USER ENTRY: TEMP TARGET CANCEL")
val tempTarget = TempTarget()
.source(Source.USER)
.date(DateUtil.now())
.duration(0)
.low(0.0)
.high(0.0)
activePlugin.activeTreatments.addToHistoryTempTarget(tempTarget)
}
}
return false
}
} }

View file

@ -6,6 +6,7 @@ import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.Config import info.nightscout.androidaps.Config
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.events.EventRefreshOverview import info.nightscout.androidaps.events.EventRefreshOverview
import info.nightscout.androidaps.interfaces.OverviewInterface
import info.nightscout.androidaps.interfaces.PluginBase import info.nightscout.androidaps.interfaces.PluginBase
import info.nightscout.androidaps.interfaces.PluginDescription import info.nightscout.androidaps.interfaces.PluginDescription
import info.nightscout.androidaps.interfaces.PluginType import info.nightscout.androidaps.interfaces.PluginType
@ -16,9 +17,12 @@ import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotifi
import info.nightscout.androidaps.plugins.general.overview.notifications.NotificationStore import info.nightscout.androidaps.plugins.general.overview.notifications.NotificationStore
import info.nightscout.androidaps.utils.FabricPrivacy import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.extensions.plusAssign import info.nightscout.androidaps.utils.extensions.plusAssign
import info.nightscout.androidaps.utils.extensions.*
import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.sharedPreferences.SP
import io.reactivex.disposables.CompositeDisposable import io.reactivex.disposables.CompositeDisposable
import io.reactivex.schedulers.Schedulers import io.reactivex.schedulers.Schedulers
import org.json.JSONObject
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
@ -28,6 +32,7 @@ class OverviewPlugin @Inject constructor(
private val notificationStore: NotificationStore, private val notificationStore: NotificationStore,
private val fabricPrivacy: FabricPrivacy, private val fabricPrivacy: FabricPrivacy,
private val rxBus: RxBusWrapper, private val rxBus: RxBusWrapper,
private val sp: SP,
aapsLogger: AAPSLogger, aapsLogger: AAPSLogger,
resourceHelper: ResourceHelper, resourceHelper: ResourceHelper,
private val config: Config private val config: Config
@ -36,12 +41,13 @@ class OverviewPlugin @Inject constructor(
.fragmentClass(OverviewFragment::class.qualifiedName) .fragmentClass(OverviewFragment::class.qualifiedName)
.alwaysVisible(true) .alwaysVisible(true)
.alwaysEnabled(true) .alwaysEnabled(true)
.pluginIcon(R.drawable.ic_home)
.pluginName(R.string.overview) .pluginName(R.string.overview)
.shortName(R.string.overview_shortname) .shortName(R.string.overview_shortname)
.preferencesId(R.xml.pref_overview) .preferencesId(R.xml.pref_overview)
.description(R.string.description_overview), .description(R.string.description_overview),
aapsLogger, resourceHelper, injector aapsLogger, resourceHelper, injector
) { ), OverviewInterface {
private var disposable: CompositeDisposable = CompositeDisposable() private var disposable: CompositeDisposable = CompositeDisposable()
@ -82,4 +88,57 @@ class OverviewPlugin @Inject constructor(
} }
} }
} }
override fun configuration(): JSONObject =
JSONObject()
.putString(R.string.key_quickwizard, sp, resourceHelper)
.putInt(R.string.key_eatingsoon_duration, sp, resourceHelper)
.putDouble(R.string.key_eatingsoon_target, sp, resourceHelper)
.putInt(R.string.key_activity_duration, sp, resourceHelper)
.putDouble(R.string.key_activity_target, sp, resourceHelper)
.putInt(R.string.key_hypo_duration, sp, resourceHelper)
.putDouble(R.string.key_hypo_target, sp, resourceHelper)
.putDouble(R.string.key_low_mark, sp, resourceHelper)
.putDouble(R.string.key_high_mark, sp, resourceHelper)
.putDouble(R.string.key_statuslights_cage_warning, sp, resourceHelper)
.putDouble(R.string.key_statuslights_cage_critical, sp, resourceHelper)
.putDouble(R.string.key_statuslights_iage_warning, sp, resourceHelper)
.putDouble(R.string.key_statuslights_iage_critical, sp, resourceHelper)
.putDouble(R.string.key_statuslights_sage_warning, sp, resourceHelper)
.putDouble(R.string.key_statuslights_sage_critical, sp, resourceHelper)
.putDouble(R.string.key_statuslights_sbat_warning, sp, resourceHelper)
.putDouble(R.string.key_statuslights_sbat_critical, sp, resourceHelper)
.putDouble(R.string.key_statuslights_bage_warning, sp, resourceHelper)
.putDouble(R.string.key_statuslights_bage_critical, sp, resourceHelper)
.putDouble(R.string.key_statuslights_res_warning, sp, resourceHelper)
.putDouble(R.string.key_statuslights_res_critical, sp, resourceHelper)
.putDouble(R.string.key_statuslights_bat_warning, sp, resourceHelper)
.putDouble(R.string.key_statuslights_bat_critical, sp, resourceHelper)
override fun applyConfiguration(configuration: JSONObject) {
configuration
.storeString(R.string.key_quickwizard, sp, resourceHelper)
.storeInt(R.string.key_eatingsoon_duration, sp, resourceHelper)
.storeDouble(R.string.key_eatingsoon_target, sp, resourceHelper)
.storeInt(R.string.key_activity_duration, sp, resourceHelper)
.storeDouble(R.string.key_activity_target, sp, resourceHelper)
.storeInt(R.string.key_hypo_duration, sp, resourceHelper)
.storeDouble(R.string.key_hypo_target, sp, resourceHelper)
.storeDouble(R.string.key_low_mark, sp, resourceHelper)
.storeDouble(R.string.key_high_mark, sp, resourceHelper)
.storeDouble(R.string.key_statuslights_cage_warning, sp, resourceHelper)
.storeDouble(R.string.key_statuslights_cage_critical, sp, resourceHelper)
.storeDouble(R.string.key_statuslights_iage_warning, sp, resourceHelper)
.storeDouble(R.string.key_statuslights_iage_critical, sp, resourceHelper)
.storeDouble(R.string.key_statuslights_sage_warning, sp, resourceHelper)
.storeDouble(R.string.key_statuslights_sage_critical, sp, resourceHelper)
.storeDouble(R.string.key_statuslights_sbat_warning, sp, resourceHelper)
.storeDouble(R.string.key_statuslights_sbat_critical, sp, resourceHelper)
.storeDouble(R.string.key_statuslights_bage_warning, sp, resourceHelper)
.storeDouble(R.string.key_statuslights_bage_critical, sp, resourceHelper)
.storeDouble(R.string.key_statuslights_res_warning, sp, resourceHelper)
.storeDouble(R.string.key_statuslights_res_critical, sp, resourceHelper)
.storeDouble(R.string.key_statuslights_bat_warning, sp, resourceHelper)
.storeDouble(R.string.key_statuslights_bat_critical, sp, resourceHelper)
}
} }

View file

@ -1,5 +1,6 @@
package info.nightscout.androidaps.plugins.general.overview package info.nightscout.androidaps.plugins.general.overview
import android.graphics.Color
import android.widget.TextView import android.widget.TextView
import androidx.annotation.StringRes import androidx.annotation.StringRes
import info.nightscout.androidaps.Config import info.nightscout.androidaps.Config
@ -8,6 +9,8 @@ import info.nightscout.androidaps.R
import info.nightscout.androidaps.db.CareportalEvent import info.nightscout.androidaps.db.CareportalEvent
import info.nightscout.androidaps.interfaces.ActivePluginProvider import info.nightscout.androidaps.interfaces.ActivePluginProvider
import info.nightscout.androidaps.plugins.pump.common.defs.PumpType import info.nightscout.androidaps.plugins.pump.common.defs.PumpType
import info.nightscout.androidaps.plugins.pump.omnipod.OmnipodPumpPlugin
import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.OmnipodConstants
import info.nightscout.androidaps.utils.DecimalFormatter import info.nightscout.androidaps.utils.DecimalFormatter
import info.nightscout.androidaps.utils.WarnColors import info.nightscout.androidaps.utils.WarnColors
import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.resources.ResourceHelper
@ -27,16 +30,34 @@ class StatusLightHandler @Inject constructor(
/** /**
* applies the extended statusLight subview on the overview fragment * applies the extended statusLight subview on the overview fragment
*/ */
fun updateStatusLights(careportal_canulaage: TextView?, careportal_insulinage: TextView?, careportal_reservoirlevel: TextView?, careportal_sensorage: TextView?, careportal_pbage: TextView?, careportal_batterylevel: TextView?) { fun updateStatusLights(careportal_canulaage: TextView?, careportal_insulinage: TextView?, careportal_reservoirlevel: TextView?, careportal_sensorage: TextView?, careportal_sensorbatterylevel: TextView?, careportal_pbage: TextView?, careportal_batterylevel: TextView?) {
val pump = activePlugin.activePump val pump = activePlugin.activePump
val bgSource = activePlugin.activeBgSource
handleAge(careportal_canulaage, CareportalEvent.SITECHANGE, R.string.key_statuslights_cage_warning, 48.0, R.string.key_statuslights_cage_critical, 72.0) handleAge(careportal_canulaage, CareportalEvent.SITECHANGE, R.string.key_statuslights_cage_warning, 48.0, R.string.key_statuslights_cage_critical, 72.0)
handleAge(careportal_insulinage, CareportalEvent.INSULINCHANGE, R.string.key_statuslights_iage_warning, 72.0, R.string.key_statuslights_iage_critical, 144.0) handleAge(careportal_insulinage, CareportalEvent.INSULINCHANGE, R.string.key_statuslights_iage_warning, 72.0, R.string.key_statuslights_iage_critical, 144.0)
handleAge(careportal_sensorage, CareportalEvent.SENSORCHANGE, R.string.key_statuslights_sage_warning, 216.0, R.string.key_statuslights_sage_critical, 240.0) handleAge(careportal_sensorage, CareportalEvent.SENSORCHANGE, R.string.key_statuslights_sage_warning, 216.0, R.string.key_statuslights_sage_critical, 240.0)
handleAge(careportal_pbage, CareportalEvent.PUMPBATTERYCHANGE, R.string.key_statuslights_bage_warning, 216.0, R.string.key_statuslights_bage_critical, 240.0) if (pump.pumpDescription.isBatteryReplaceable) {
if (!config.NSCLIENT) handleAge(careportal_pbage, CareportalEvent.PUMPBATTERYCHANGE, R.string.key_statuslights_bage_warning, 216.0, R.string.key_statuslights_bage_critical, 240.0)
handleLevel(careportal_reservoirlevel, R.string.key_statuslights_res_critical, 10.0, R.string.key_statuslights_res_warning, 80.0, pump.reservoirLevel, "U") }
if (!config.NSCLIENT && pump.model() != PumpType.AccuChekCombo) if (!config.NSCLIENT) {
handleLevel(careportal_batterylevel, R.string.key_statuslights_bat_critical, 26.0, R.string.key_statuslights_bat_warning, 51.0, pump.batteryLevel.toDouble(), "%") if (pump.model() == PumpType.Insulet_Omnipod) {
handleOmnipodReservoirLevel(careportal_reservoirlevel, R.string.key_statuslights_res_critical, 10.0, R.string.key_statuslights_res_warning, 80.0, pump.reservoirLevel, "U")
} else {
handleLevel(careportal_reservoirlevel, R.string.key_statuslights_res_critical, 10.0, R.string.key_statuslights_res_warning, 80.0, pump.reservoirLevel, "U")
}
if (bgSource.sensorBatteryLevel != -1)
handleLevel(careportal_sensorbatterylevel, R.string.key_statuslights_sbat_critical, 5.0, R.string.key_statuslights_sbat_warning, 20.0, bgSource.sensorBatteryLevel.toDouble(), "%")
else
careportal_sensorbatterylevel?.text = ""
}
if (!config.NSCLIENT) {
if (pump.model() == PumpType.Insulet_Omnipod && pump is OmnipodPumpPlugin) { // instanceof check is needed because at startup, pump can still be VirtualPumpPlugin and that will cause a crash because of the class cast below
handleOmnipodBatteryLevel(careportal_batterylevel, R.string.key_statuslights_bat_critical, 26.0, R.string.key_statuslights_bat_warning, 51.0, pump.batteryLevel.toDouble(), "%", (pump as OmnipodPumpPlugin).isUseRileyLinkBatteryLevel)
} else if (pump.model() != PumpType.AccuChekCombo) {
handleLevel(careportal_batterylevel, R.string.key_statuslights_bat_critical, 26.0, R.string.key_statuslights_bat_warning, 51.0, pump.batteryLevel.toDouble(), "%")
}
}
} }
private fun handleAge(view: TextView?, eventName: String, @StringRes warnSettings: Int, defaultWarnThreshold: Double, @StringRes urgentSettings: Int, defaultUrgentThreshold: Double) { private fun handleAge(view: TextView?, eventName: String, @StringRes warnSettings: Int, defaultWarnThreshold: Double, @StringRes urgentSettings: Int, defaultUrgentThreshold: Double) {
@ -58,4 +79,24 @@ class StatusLightHandler @Inject constructor(
view?.text = " " + DecimalFormatter.to0Decimal(level) + units view?.text = " " + DecimalFormatter.to0Decimal(level) + units
warnColors.setColorInverse(view, level, resWarn, resUrgent) warnColors.setColorInverse(view, level, resWarn, resUrgent)
} }
// Omnipod only reports reservoir level when it's 50 units or less, so we display "50+U" for any value > 50
private fun handleOmnipodReservoirLevel(view: TextView?, criticalSetting: Int, criticalDefaultValue: Double, warnSetting: Int, warnDefaultValue: Double, level: Double, units: String) {
if (level > OmnipodConstants.MAX_RESERVOIR_READING) {
@Suppress("SetTextI18n")
view?.text = " 50+$units"
view?.setTextColor(Color.WHITE)
} else {
handleLevel(view, criticalSetting, criticalDefaultValue, warnSetting, warnDefaultValue, level, units)
}
}
private fun handleOmnipodBatteryLevel(view: TextView?, criticalSetting: Int, criticalDefaultValue: Double, warnSetting: Int, warnDefaultValue: Double, level: Double, units: String, useRileyLinkBatteryLevel: Boolean) {
if (useRileyLinkBatteryLevel) {
handleLevel(view, criticalSetting, criticalDefaultValue, warnSetting, warnDefaultValue, level, units)
} else {
view?.text = resourceHelper.gs(R.string.notavailable)
view?.setTextColor(Color.WHITE)
}
}
} }

View file

@ -33,7 +33,7 @@ class QuickWizardListActivity : NoSplashAppCompatActivity() {
private var disposable: CompositeDisposable = CompositeDisposable() private var disposable: CompositeDisposable = CompositeDisposable()
private inner class RecyclerViewAdapter internal constructor(internal var fragmentManager: FragmentManager) : RecyclerView.Adapter<RecyclerViewAdapter.QuickWizardEntryViewHolder>() { private inner class RecyclerViewAdapter(var fragmentManager: FragmentManager) : RecyclerView.Adapter<RecyclerViewAdapter.QuickWizardEntryViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): QuickWizardEntryViewHolder { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): QuickWizardEntryViewHolder {
return QuickWizardEntryViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.overview_quickwizardlist_item, parent, false), fragmentManager) return QuickWizardEntryViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.overview_quickwizardlist_item, parent, false), fragmentManager)
@ -48,7 +48,7 @@ class QuickWizardListActivity : NoSplashAppCompatActivity() {
override fun getItemCount(): Int = quickWizard.size() override fun getItemCount(): Int = quickWizard.size()
private inner class QuickWizardEntryViewHolder internal constructor(itemView: View, internal var fragmentManager: FragmentManager) : RecyclerView.ViewHolder(itemView) { private inner class QuickWizardEntryViewHolder(itemView: View, var fragmentManager: FragmentManager) : RecyclerView.ViewHolder(itemView) {
val buttonText: TextView = itemView.findViewById(R.id.overview_quickwizard_item_buttonText) val buttonText: TextView = itemView.findViewById(R.id.overview_quickwizard_item_buttonText)
val carbs: TextView = itemView.findViewById(R.id.overview_quickwizard_item_carbs) val carbs: TextView = itemView.findViewById(R.id.overview_quickwizard_item_carbs)
val from: TextView = itemView.findViewById(R.id.overview_quickwizard_item_from) val from: TextView = itemView.findViewById(R.id.overview_quickwizard_item_from)

View file

@ -315,7 +315,7 @@ public class AreaGraphSeries<E extends DoubleDataPoint> extends BaseSeries<E> {
canvas.drawPath(mPath, paint); canvas.drawPath(mPath, paint);
canvas.drawPath(mSecondPath, paint); canvas.drawPath(mSecondPath, paint);
if (mStyles.drawBackground) { if (mStyles.drawBackground) {
canvas.drawRect((float)startX, (float)startY2, endX, endY1, mPaintBackground); canvas.drawRect(startX, startY2, endX, endY1, mPaintBackground);
} }
} else if (mStyles.drawDataPoints) { } else if (mStyles.drawDataPoints) {
//fix: last value not drawn as datapoint. Draw first point here, and then on every step the end values (above) //fix: last value not drawn as datapoint. Draw first point here, and then on every step the end values (above)

View file

@ -11,9 +11,9 @@ import java.io.Serializable;
public class DoubleDataPoint implements DataPointInterface, Serializable { public class DoubleDataPoint implements DataPointInterface, Serializable {
private static final long serialVersionUID=1428267322645L; private static final long serialVersionUID=1428267322645L;
private double x; private final double x;
private double y1; private final double y1;
private double y2; private final double y2;
public DoubleDataPoint(double x, double y1, double y2) { public DoubleDataPoint(double x, double y1, double y2) {
this.x=x; this.x=x;

View file

@ -12,10 +12,10 @@ import java.util.Date;
public class ScaledDataPoint implements DataPointInterface, Serializable { public class ScaledDataPoint implements DataPointInterface, Serializable {
private static final long serialVersionUID=1428263342645L; private static final long serialVersionUID=1428263342645L;
private double x; private final double x;
private double y; private final double y;
private Scale scale; private final Scale scale;
public ScaledDataPoint(double x, double y, Scale scale) { public ScaledDataPoint(double x, double y, Scale scale) {
this.x=x; this.x=x;

View file

@ -4,6 +4,7 @@ import com.jjoe64.graphview.DefaultLabelFormatter;
import java.text.DateFormat; import java.text.DateFormat;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.Locale;
/** /**
* Created by mike on 09.06.2016. * Created by mike on 09.06.2016.
@ -20,10 +21,22 @@ public class TimeAsXAxisLabelFormatter extends DefaultLabelFormatter {
public String formatLabel(double value, boolean isValueX) { public String formatLabel(double value, boolean isValueX) {
if (isValueX) { if (isValueX) {
// format as date // format as date
DateFormat dateFormat = new SimpleDateFormat(mFormat); DateFormat dateFormat = new SimpleDateFormat(mFormat, Locale.getDefault());
return dateFormat.format((long) value); return dateFormat.format((long) value);
} else { } else {
return super.formatLabel(value, isValueX); try {
// unknown reason for crashing on this
// Fatal Exception: java.lang.NullPointerException
// Attempt to invoke virtual method 'double com.jjoe64.graphview.Viewport.getMaxY(boolean)' on a null object reference
// com.jjoe64.graphview.DefaultLabelFormatter.formatLabel (DefaultLabelFormatter.java:89)
// info.nightscout.androidaps.plugins.general.overview.graphExtensions.TimeAsXAxisLabelFormatter.formatLabel (TimeAsXAxisLabelFormatter.java:26)
// com.jjoe64.graphview.GridLabelRenderer.drawVerticalSteps (GridLabelRenderer.java:1057)
// com.jjoe64.graphview.GridLabelRenderer.draw (GridLabelRenderer.java:866)
// com.jjoe64.graphview.GraphView.onDraw (GraphView.java:296)
return super.formatLabel(value, isValueX);
} catch (Exception ignored) {
return "";
}
} }
} }
} }

View file

@ -22,7 +22,7 @@ import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.logging.LTag
import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.plugins.general.overview.events.EventDismissNotification import info.nightscout.androidaps.plugins.general.overview.events.EventDismissNotification
import info.nightscout.androidaps.services.AlarmSoundService import info.nightscout.androidaps.services.AlarmSoundServiceHelper
import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.resources.IconsProvider import info.nightscout.androidaps.utils.resources.IconsProvider
import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.resources.ResourceHelper
@ -39,6 +39,7 @@ class NotificationStore @Inject constructor(
private val resourceHelper: ResourceHelper, private val resourceHelper: ResourceHelper,
private val context: Context, private val context: Context,
private val iconsProvider: IconsProvider, private val iconsProvider: IconsProvider,
private val alarmSoundServiceHelper: AlarmSoundServiceHelper,
private val dateUtil: DateUtil private val dateUtil: DateUtil
) { ) {
@ -46,10 +47,12 @@ class NotificationStore @Inject constructor(
private var usesChannels = false private var usesChannels = false
companion object { companion object {
private const val CHANNEL_ID = "AndroidAPS-Overview" private const val CHANNEL_ID = "AndroidAPS-Overview"
} }
inner class NotificationComparator : Comparator<Notification> { inner class NotificationComparator : Comparator<Notification> {
override fun compare(o1: Notification, o2: Notification): Int { override fun compare(o1: Notification, o2: Notification): Int {
return o1.level - o2.level return o1.level - o2.level
} }
@ -68,17 +71,9 @@ class NotificationStore @Inject constructor(
store.add(n) store.add(n)
if (sp.getBoolean(R.string.key_raise_notifications_as_android_notifications, false) && n !is NotificationWithAction) { if (sp.getBoolean(R.string.key_raise_notifications_as_android_notifications, false) && n !is NotificationWithAction) {
raiseSystemNotification(n) raiseSystemNotification(n)
if (usesChannels && n.soundId != null && n.soundId != 0) { if (usesChannels && n.soundId != null && n.soundId != 0) alarmSoundServiceHelper.startAlarm(context, n.soundId)
val alarm = Intent(context, AlarmSoundService::class.java)
alarm.putExtra("soundid", n.soundId)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) context.startForegroundService(alarm) else context.startService(alarm)
}
} else { } else {
if (n.soundId != null && n.soundId != 0) { if (n.soundId != null && n.soundId != 0) alarmSoundServiceHelper.startAlarm(context, n.soundId)
val alarm = Intent(context, AlarmSoundService::class.java)
alarm.putExtra("soundid", n.soundId)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) context.startForegroundService(alarm) else context.startService(alarm)
}
} }
Collections.sort(store, NotificationComparator()) Collections.sort(store, NotificationComparator())
return true return true
@ -87,10 +82,7 @@ class NotificationStore @Inject constructor(
@Synchronized fun remove(id: Int): Boolean { @Synchronized fun remove(id: Int): Boolean {
for (i in store.indices) { for (i in store.indices) {
if (store[i].id == id) { if (store[i].id == id) {
if (store[i].soundId != null) { if (store[i].soundId != null) alarmSoundServiceHelper.stopService(context)
val alarm = Intent(context, AlarmSoundService::class.java)
context.stopService(alarm)
}
store.removeAt(i) store.removeAt(i)
return true return true
} }
@ -195,10 +187,10 @@ class NotificationStore @Inject constructor(
@Suppress("SetTextI18n") @Suppress("SetTextI18n")
holder.text.text = dateUtil.timeString(notification.date) + " " + notification.text holder.text.text = dateUtil.timeString(notification.date) + " " + notification.text
when (notification.level) { when (notification.level) {
Notification.URGENT -> holder.cv.setBackgroundColor(resourceHelper.gc(R.color.notificationUrgent)) Notification.URGENT -> holder.cv.setBackgroundColor(resourceHelper.gc(R.color.notificationUrgent))
Notification.NORMAL -> holder.cv.setBackgroundColor(resourceHelper.gc(R.color.notificationNormal)) Notification.NORMAL -> holder.cv.setBackgroundColor(resourceHelper.gc(R.color.notificationNormal))
Notification.LOW -> holder.cv.setBackgroundColor(resourceHelper.gc(R.color.notificationLow)) Notification.LOW -> holder.cv.setBackgroundColor(resourceHelper.gc(R.color.notificationLow))
Notification.INFO -> holder.cv.setBackgroundColor(resourceHelper.gc(R.color.notificationInfo)) Notification.INFO -> holder.cv.setBackgroundColor(resourceHelper.gc(R.color.notificationInfo))
Notification.ANNOUNCEMENT -> holder.cv.setBackgroundColor(resourceHelper.gc(R.color.notificationAnnouncement)) Notification.ANNOUNCEMENT -> holder.cv.setBackgroundColor(resourceHelper.gc(R.color.notificationAnnouncement))
} }
} }
@ -208,6 +200,7 @@ class NotificationStore @Inject constructor(
} }
inner class NotificationsViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { inner class NotificationsViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
var cv: CardView = itemView.findViewById(R.id.notification_cardview) var cv: CardView = itemView.findViewById(R.id.notification_cardview)
var text: TextView = itemView.findViewById(R.id.notification_text) var text: TextView = itemView.findViewById(R.id.notification_text)
var dismiss: Button = itemView.findViewById(R.id.notification_dismiss) var dismiss: Button = itemView.findViewById(R.id.notification_dismiss)

View file

@ -44,7 +44,7 @@ class DummyService : DaggerService() {
.subscribe({ .subscribe({
aapsLogger.debug(LTag.CORE, "EventAppExit received") aapsLogger.debug(LTag.CORE, "EventAppExit received")
stopSelf() stopSelf()
}) { fabricPrivacy::logException } }, fabricPrivacy::logException )
) )
} }

View file

@ -137,7 +137,7 @@ class PersistentNotificationPlugin @Inject constructor(
var line1_aa: String var line1_aa: String
val units = profileFunction.getUnits() val units = profileFunction.getUnits()
val lastBG = iobCobCalculatorPlugin.lastBg() val lastBG = iobCobCalculatorPlugin.lastBg()
val glucoseStatus = GlucoseStatus(injector).getGlucoseStatusData() val glucoseStatus = GlucoseStatus(injector).glucoseStatusData
if (lastBG != null) { if (lastBG != null) {
line1_aa = lastBG.valueToUnitsToString(units) line1_aa = lastBG.valueToUnitsToString(units)
line1 = line1_aa line1 = line1_aa

View file

@ -23,7 +23,6 @@ import info.nightscout.androidaps.logging.LTag
import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin
import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientRestart import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientRestart
import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification
import info.nightscout.androidaps.plugins.general.overview.notifications.Notification import info.nightscout.androidaps.plugins.general.overview.notifications.Notification
@ -67,6 +66,7 @@ class SmsCommunicatorPlugin @Inject constructor(
) : PluginBase(PluginDescription() ) : PluginBase(PluginDescription()
.mainType(PluginType.GENERAL) .mainType(PluginType.GENERAL)
.fragmentClass(SmsCommunicatorFragment::class.java.name) .fragmentClass(SmsCommunicatorFragment::class.java.name)
.pluginIcon(R.drawable.ic_sms)
.pluginName(R.string.smscommunicator) .pluginName(R.string.smscommunicator)
.shortName(R.string.smscommunicator_shortname) .shortName(R.string.smscommunicator_shortname)
.preferencesId(R.xml.pref_smscommunicator) .preferencesId(R.xml.pref_smscommunicator)
@ -290,7 +290,7 @@ class SmsCommunicatorPlugin @Inject constructor(
val agoMin = (agoMsec / 60.0 / 1000.0).toInt() val agoMin = (agoMsec / 60.0 / 1000.0).toInt()
reply = resourceHelper.gs(R.string.sms_lastbg) + " " + lastBG.valueToUnitsToString(units) + " " + String.format(resourceHelper.gs(R.string.sms_minago), agoMin) + ", " reply = resourceHelper.gs(R.string.sms_lastbg) + " " + lastBG.valueToUnitsToString(units) + " " + String.format(resourceHelper.gs(R.string.sms_minago), agoMin) + ", "
} }
val glucoseStatus = GlucoseStatus(injector).getGlucoseStatusData() val glucoseStatus = GlucoseStatus(injector).glucoseStatusData
if (glucoseStatus != null) reply += resourceHelper.gs(R.string.sms_delta) + " " + Profile.toUnitsString(glucoseStatus.delta, glucoseStatus.delta * Constants.MGDL_TO_MMOLL, units) + " " + units + ", " if (glucoseStatus != null) reply += resourceHelper.gs(R.string.sms_delta) + " " + Profile.toUnitsString(glucoseStatus.delta, glucoseStatus.delta * Constants.MGDL_TO_MMOLL, units) + " " + units + ", "
activePlugin.activeTreatments.updateTotalIOBTreatments() activePlugin.activeTreatments.updateTotalIOBTreatments()
val bolusIob = activePlugin.activeTreatments.lastCalculationTreatments.round() val bolusIob = activePlugin.activeTreatments.lastCalculationTreatments.round()
@ -314,6 +314,7 @@ class SmsCommunicatorPlugin @Inject constructor(
receivedSms.processed = true receivedSms.processed = true
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction() { messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction() {
override fun run() { override fun run() {
aapsLogger.debug("USER ENTRY: SMS LOOP DISABLE")
loopPlugin.setPluginEnabled(PluginType.LOOP, false) loopPlugin.setPluginEnabled(PluginType.LOOP, false)
commandQueue.cancelTempBasal(true, object : Callback() { commandQueue.cancelTempBasal(true, object : Callback() {
override fun run() { override fun run() {
@ -337,6 +338,7 @@ class SmsCommunicatorPlugin @Inject constructor(
receivedSms.processed = true receivedSms.processed = true
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction() { messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction() {
override fun run() { override fun run() {
aapsLogger.debug("USER ENTRY: SMS LOOP ENABLE")
loopPlugin.setPluginEnabled(PluginType.LOOP, true) loopPlugin.setPluginEnabled(PluginType.LOOP, true)
sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.smscommunicator_loophasbeenenabled))) sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.smscommunicator_loophasbeenenabled)))
rxBus.send(EventRefreshOverview("SMS_LOOP_START")) rxBus.send(EventRefreshOverview("SMS_LOOP_START"))
@ -349,7 +351,7 @@ class SmsCommunicatorPlugin @Inject constructor(
"STATUS" -> { "STATUS" -> {
val reply = if (loopPlugin.isEnabled(PluginType.LOOP)) { val reply = if (loopPlugin.isEnabled(PluginType.LOOP)) {
if (loopPlugin.isSuspended()) String.format(resourceHelper.gs(R.string.loopsuspendedfor), loopPlugin.minutesToEndOfSuspend()) if (loopPlugin.isSuspended) String.format(resourceHelper.gs(R.string.loopsuspendedfor), loopPlugin.minutesToEndOfSuspend())
else resourceHelper.gs(R.string.smscommunicator_loopisenabled) else resourceHelper.gs(R.string.smscommunicator_loopisenabled)
} else } else
resourceHelper.gs(R.string.smscommunicator_loopisdisabled) resourceHelper.gs(R.string.smscommunicator_loopisdisabled)
@ -363,7 +365,18 @@ class SmsCommunicatorPlugin @Inject constructor(
receivedSms.processed = true receivedSms.processed = true
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction() { messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction() {
override fun run() { override fun run() {
aapsLogger.debug("USER ENTRY: SMS LOOP RESUME")
loopPlugin.suspendTo(0L)
rxBus.send(EventRefreshOverview("SMS_LOOP_RESUME")) rxBus.send(EventRefreshOverview("SMS_LOOP_RESUME"))
commandQueue.cancelTempBasal(true, object : Callback() {
override fun run() {
if (!result.success) {
var replyText = resourceHelper.gs(R.string.smscommunicator_tempbasalfailed)
replyText += "\n" + activePlugin.activePump.shortStatus(true)
sendSMS(Sms(receivedSms.phoneNumber, replyText))
}
}
})
loopPlugin.createOfflineEvent(0) loopPlugin.createOfflineEvent(0)
sendSMSToAllNumbers(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.smscommunicator_loopresumed))) sendSMSToAllNumbers(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.smscommunicator_loopresumed)))
} }
@ -385,6 +398,7 @@ class SmsCommunicatorPlugin @Inject constructor(
receivedSms.processed = true receivedSms.processed = true
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction(duration) { messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction(duration) {
override fun run() { override fun run() {
aapsLogger.debug("USER ENTRY: SMS LOOP SUSPEND")
commandQueue.cancelTempBasal(true, object : Callback() { commandQueue.cancelTempBasal(true, object : Callback() {
override fun run() { override fun run() {
if (result.success) { if (result.success) {
@ -463,6 +477,7 @@ class SmsCommunicatorPlugin @Inject constructor(
receivedSms.processed = true receivedSms.processed = true
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction() { messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction() {
override fun run() { override fun run() {
aapsLogger.debug("USER ENTRY: SMS PUMP CONNECT")
commandQueue.cancelTempBasal(true, object : Callback() { commandQueue.cancelTempBasal(true, object : Callback() {
override fun run() { override fun run() {
if (!result.success) { if (!result.success) {
@ -491,6 +506,7 @@ class SmsCommunicatorPlugin @Inject constructor(
receivedSms.processed = true receivedSms.processed = true
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction() { messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction() {
override fun run() { override fun run() {
aapsLogger.debug("USER ENTRY: SMS PUMP DISCONNECT")
val profile = profileFunction.getProfile() val profile = profileFunction.getProfile()
loopPlugin.disconnectPump(duration, profile) loopPlugin.disconnectPump(duration, profile)
rxBus.send(EventRefreshOverview("SMS_PUMP_DISCONNECT")) rxBus.send(EventRefreshOverview("SMS_PUMP_DISCONNECT"))
@ -544,6 +560,7 @@ class SmsCommunicatorPlugin @Inject constructor(
val finalPercentage = percentage val finalPercentage = percentage
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction(list[pindex - 1] as String, finalPercentage) { messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction(list[pindex - 1] as String, finalPercentage) {
override fun run() { override fun run() {
aapsLogger.debug("USER ENTRY: SMS PROFILE $reply")
activePlugin.activeTreatments.doProfileSwitch(store, list[pindex - 1] as String, 0, finalPercentage, 0, DateUtil.now()) activePlugin.activeTreatments.doProfileSwitch(store, list[pindex - 1] as String, 0, finalPercentage, 0, DateUtil.now())
sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.profileswitchcreated))) sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.profileswitchcreated)))
} }
@ -561,6 +578,7 @@ class SmsCommunicatorPlugin @Inject constructor(
receivedSms.processed = true receivedSms.processed = true
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction() { messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction() {
override fun run() { override fun run() {
aapsLogger.debug("USER ENTRY: SMS BASAL $reply")
commandQueue.cancelTempBasal(true, object : Callback() { commandQueue.cancelTempBasal(true, object : Callback() {
override fun run() { override fun run() {
if (result.success) { if (result.success) {
@ -578,12 +596,13 @@ class SmsCommunicatorPlugin @Inject constructor(
}) })
} else if (splitted[1].endsWith("%")) { } else if (splitted[1].endsWith("%")) {
var tempBasalPct = SafeParse.stringToInt(StringUtils.removeEnd(splitted[1], "%")) var tempBasalPct = SafeParse.stringToInt(StringUtils.removeEnd(splitted[1], "%"))
val durationStep = activePlugin.activePump.model().tbrSettings.durationStep
var duration = 30 var duration = 30
if (splitted.size > 2) duration = SafeParse.stringToInt(splitted[2]) if (splitted.size > 2) duration = SafeParse.stringToInt(splitted[2])
val profile = profileFunction.getProfile() val profile = profileFunction.getProfile()
if (profile == null) sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.noprofile))) if (profile == null) sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.noprofile)))
else if (tempBasalPct == 0 && splitted[1] != "0%") sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.wrongformat))) else if (tempBasalPct == 0 && splitted[1] != "0%") sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.wrongformat)))
else if (duration == 0) sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.wrongformat))) else if (duration <= 0 || duration % durationStep != 0) sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.wrongTbrDuration, durationStep)))
else { else {
tempBasalPct = constraintChecker.applyBasalPercentConstraints(Constraint(tempBasalPct), profile).value() tempBasalPct = constraintChecker.applyBasalPercentConstraints(Constraint(tempBasalPct), profile).value()
val passCode = generatePasscode() val passCode = generatePasscode()
@ -591,6 +610,7 @@ class SmsCommunicatorPlugin @Inject constructor(
receivedSms.processed = true receivedSms.processed = true
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction(tempBasalPct, duration) { messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction(tempBasalPct, duration) {
override fun run() { override fun run() {
aapsLogger.debug("USER ENTRY: SMS BASAL $reply")
commandQueue.tempBasalPercent(anInteger(), secondInteger(), true, profile, object : Callback() { commandQueue.tempBasalPercent(anInteger(), secondInteger(), true, profile, object : Callback() {
override fun run() { override fun run() {
if (result.success) { if (result.success) {
@ -610,12 +630,13 @@ class SmsCommunicatorPlugin @Inject constructor(
} }
} else { } else {
var tempBasal = SafeParse.stringToDouble(splitted[1]) var tempBasal = SafeParse.stringToDouble(splitted[1])
val durationStep = activePlugin.activePump.model().tbrSettings.durationStep
var duration = 30 var duration = 30
if (splitted.size > 2) duration = SafeParse.stringToInt(splitted[2]) if (splitted.size > 2) duration = SafeParse.stringToInt(splitted[2])
val profile = profileFunction.getProfile() val profile = profileFunction.getProfile()
if (profile == null) sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.noprofile))) if (profile == null) sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.noprofile)))
else if (tempBasal == 0.0 && splitted[1] != "0") sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.wrongformat))) else if (tempBasal == 0.0 && splitted[1] != "0") sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.wrongformat)))
else if (duration == 0) sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.wrongformat))) else if (duration <= 0 || duration % durationStep != 0) sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.wrongTbrDuration, durationStep)))
else { else {
tempBasal = constraintChecker.applyBasalConstraints(Constraint(tempBasal), profile).value() tempBasal = constraintChecker.applyBasalConstraints(Constraint(tempBasal), profile).value()
val passCode = generatePasscode() val passCode = generatePasscode()
@ -623,6 +644,7 @@ class SmsCommunicatorPlugin @Inject constructor(
receivedSms.processed = true receivedSms.processed = true
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction(tempBasal, duration) { messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction(tempBasal, duration) {
override fun run() { override fun run() {
aapsLogger.debug("USER ENTRY: SMS BASAL $reply")
commandQueue.tempBasalAbsolute(aDouble(), secondInteger(), true, profile, object : Callback() { commandQueue.tempBasalAbsolute(aDouble(), secondInteger(), true, profile, object : Callback() {
override fun run() { override fun run() {
if (result.success) { if (result.success) {
@ -650,6 +672,7 @@ class SmsCommunicatorPlugin @Inject constructor(
receivedSms.processed = true receivedSms.processed = true
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction() { messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction() {
override fun run() { override fun run() {
aapsLogger.debug("USER ENTRY: SMS EXTENDED $reply")
commandQueue.cancelExtended(object : Callback() { commandQueue.cancelExtended(object : Callback() {
override fun run() { override fun run() {
if (result.success) { if (result.success) {
@ -678,6 +701,7 @@ class SmsCommunicatorPlugin @Inject constructor(
receivedSms.processed = true receivedSms.processed = true
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction(extended, duration) { messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction(extended, duration) {
override fun run() { override fun run() {
aapsLogger.debug("USER ENTRY: SMS EXTENDED $reply")
commandQueue.extendedBolus(aDouble(), secondInteger(), object : Callback() { commandQueue.extendedBolus(aDouble(), secondInteger(), object : Callback() {
override fun run() { override fun run() {
if (result.success) { if (result.success) {
@ -713,6 +737,7 @@ class SmsCommunicatorPlugin @Inject constructor(
receivedSms.processed = true receivedSms.processed = true
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction(bolus) { messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction(bolus) {
override fun run() { override fun run() {
aapsLogger.debug("USER ENTRY: SMS BOLUS $reply")
val detailedBolusInfo = DetailedBolusInfo() val detailedBolusInfo = DetailedBolusInfo()
detailedBolusInfo.insulin = aDouble() detailedBolusInfo.insulin = aDouble()
detailedBolusInfo.source = Source.USER detailedBolusInfo.source = Source.USER
@ -787,6 +812,7 @@ class SmsCommunicatorPlugin @Inject constructor(
receivedSms.processed = true receivedSms.processed = true
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction(grams, time) { messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction(grams, time) {
override fun run() { override fun run() {
aapsLogger.debug("USER ENTRY: SMS CARBS $reply")
val detailedBolusInfo = DetailedBolusInfo() val detailedBolusInfo = DetailedBolusInfo()
detailedBolusInfo.carbs = anInteger().toDouble() detailedBolusInfo.carbs = anInteger().toDouble()
detailedBolusInfo.source = Source.USER detailedBolusInfo.source = Source.USER
@ -827,6 +853,7 @@ class SmsCommunicatorPlugin @Inject constructor(
receivedSms.processed = true receivedSms.processed = true
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction() { messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction() {
override fun run() { override fun run() {
aapsLogger.debug("USER ENTRY: SMS TARGET $reply")
val units = profileFunction.getUnits() val units = profileFunction.getUnits()
var keyDuration = 0 var keyDuration = 0
var defaultTargetDuration = 0 var defaultTargetDuration = 0
@ -882,6 +909,7 @@ class SmsCommunicatorPlugin @Inject constructor(
receivedSms.processed = true receivedSms.processed = true
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction() { messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction() {
override fun run() { override fun run() {
aapsLogger.debug("USER ENTRY: SMS TARGET $reply")
val tempTarget = TempTarget() val tempTarget = TempTarget()
.source(Source.USER) .source(Source.USER)
.date(DateUtil.now()) .date(DateUtil.now())
@ -906,6 +934,7 @@ class SmsCommunicatorPlugin @Inject constructor(
receivedSms.processed = true receivedSms.processed = true
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction() { messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction() {
override fun run() { override fun run() {
aapsLogger.debug("USER ENTRY: SMS SMS $reply")
sp.putBoolean(R.string.key_smscommunicator_remotecommandsallowed, false) sp.putBoolean(R.string.key_smscommunicator_remotecommandsallowed, false)
val replyText = String.format(resourceHelper.gs(R.string.smscommunicator_stoppedsms)) val replyText = String.format(resourceHelper.gs(R.string.smscommunicator_stoppedsms))
sendSMSToAllNumbers(Sms(receivedSms.phoneNumber, replyText)) sendSMSToAllNumbers(Sms(receivedSms.phoneNumber, replyText))
@ -922,6 +951,7 @@ class SmsCommunicatorPlugin @Inject constructor(
receivedSms.processed = true receivedSms.processed = true
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction(cal) { messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction(cal) {
override fun run() { override fun run() {
aapsLogger.debug("USER ENTRY: SMS CAL $reply")
val result = xdripCalibrations.sendIntent(aDouble!!) val result = xdripCalibrations.sendIntent(aDouble!!)
if (result) sendSMSToAllNumbers(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.smscommunicator_calibrationsent))) else sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.smscommunicator_calibrationfailed))) if (result) sendSMSToAllNumbers(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.smscommunicator_calibrationsent))) else sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.smscommunicator_calibrationfailed)))
} }
@ -1002,7 +1032,7 @@ class SmsCommunicatorPlugin @Inject constructor(
private fun areMoreNumbers(allowednumbers: String?): Boolean { private fun areMoreNumbers(allowednumbers: String?): Boolean {
return allowednumbers?.let { return allowednumbers?.let {
var countNumbers = 0 val knownNumbers = HashSet<String>()
val substrings = it.split(";").toTypedArray() val substrings = it.split(";").toTypedArray()
for (number in substrings) { for (number in substrings) {
var cleaned = number.replace(Regex("\\s+"), "") var cleaned = number.replace(Regex("\\s+"), "")
@ -1010,9 +1040,9 @@ class SmsCommunicatorPlugin @Inject constructor(
cleaned = cleaned.replace("+", "") cleaned = cleaned.replace("+", "")
cleaned = cleaned.replace("-", "") cleaned = cleaned.replace("-", "")
if (!cleaned.matches(Regex("[0-9]+"))) continue if (!cleaned.matches(Regex("[0-9]+"))) continue
countNumbers++ knownNumbers.add(cleaned)
} }
countNumbers > 1 knownNumbers.size > 1
} ?: false } ?: false
} }
} }

View file

@ -1,11 +1,15 @@
package info.nightscout.androidaps.plugins.general.smsCommunicator.activities package info.nightscout.androidaps.plugins.general.smsCommunicator.activities
import android.content.ClipData
import android.content.ClipboardManager
import android.content.Context
import android.content.res.Resources import android.content.res.Resources
import android.graphics.Color import android.graphics.Color
import android.os.Bundle import android.os.Bundle
import android.text.Editable import android.text.Editable
import android.text.TextWatcher import android.text.TextWatcher
import android.view.View import android.view.View
import android.view.WindowManager
import com.google.common.primitives.Ints.min import com.google.common.primitives.Ints.min
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
@ -15,8 +19,8 @@ import info.nightscout.androidaps.plugins.general.smsCommunicator.SmsCommunicato
import info.nightscout.androidaps.plugins.general.smsCommunicator.otp.OneTimePassword import info.nightscout.androidaps.plugins.general.smsCommunicator.otp.OneTimePassword
import info.nightscout.androidaps.plugins.general.smsCommunicator.otp.OneTimePasswordValidationResult import info.nightscout.androidaps.plugins.general.smsCommunicator.otp.OneTimePasswordValidationResult
import info.nightscout.androidaps.utils.FabricPrivacy import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
import info.nightscout.androidaps.utils.ToastUtils import info.nightscout.androidaps.utils.ToastUtils
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.resources.ResourceHelper
import kotlinx.android.synthetic.main.activity_smscommunicator_otp.* import kotlinx.android.synthetic.main.activity_smscommunicator_otp.*
import net.glxn.qrgen.android.QRCode import net.glxn.qrgen.android.QRCode
@ -31,6 +35,7 @@ class SmsCommunicatorOtpActivity : NoSplashAppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
window.setFlags(WindowManager.LayoutParams.FLAG_SECURE, WindowManager.LayoutParams.FLAG_SECURE)
setContentView(R.layout.activity_smscommunicator_otp) setContentView(R.layout.activity_smscommunicator_otp)
smscommunicator_otp_verify_edit.addTextChangedListener(object : TextWatcher { smscommunicator_otp_verify_edit.addTextChangedListener(object : TextWatcher {
@ -64,9 +69,23 @@ class SmsCommunicatorOtpActivity : NoSplashAppCompatActivity() {
Runnable { Runnable {
otp.ensureKey(true) otp.ensureKey(true)
updateGui() updateGui()
ToastUtils.showToastInUiThread(this, R.string.smscommunicator_otp_reset_successful) ToastUtils.Long.infoToast(this, resourceHelper.gs(R.string.smscommunicator_otp_reset_successful))
}) })
} }
smscommunicator_otp_provisioning.setOnLongClickListener {
OKDialog.showConfirmation(this,
resourceHelper.gs(R.string.smscommunicator_otp_export_title),
resourceHelper.gs(R.string.smscommunicator_otp_export_prompt),
Runnable {
val clipboard = getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
val clip = ClipData.newPlainText("OTP Secret", otp.provisioningSecret())
clipboard.primaryClip = clip
ToastUtils.Long.infoToast(this, resourceHelper.gs(R.string.smscommunicator_otp_export_successful))
})
true
}
} }
@Synchronized @Synchronized

View file

@ -121,4 +121,10 @@ class OneTimePassword @Inject constructor(
fun provisioningURI(): String? = fun provisioningURI(): String? =
key?.let { "otpauth://totp/AndroidAPS:" + URLEncoder.encode(name(), "utf-8").replace("+", "%20") + "?secret=" + BaseEncoding.base32().encode(it.encoded).replace("=", "") + "&issuer=AndroidAPS" } key?.let { "otpauth://totp/AndroidAPS:" + URLEncoder.encode(name(), "utf-8").replace("+", "%20") + "?secret=" + BaseEncoding.base32().encode(it.encoded).replace("=", "") + "&issuer=AndroidAPS" }
/**
* Return secret used to provision Authenticator apps, in Base32 format
*/
fun provisioningSecret(): String? =
key?.let { BaseEncoding.base32().encode(it.encoded).replace("=", "") }
} }

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