Merge pull request #5 from nightscout/dev

Dev
This commit is contained in:
Andreas 2021-01-26 16:00:31 +01:00 committed by GitHub
commit 321dd74595
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
622 changed files with 19556 additions and 11230 deletions

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

@ -87,7 +87,7 @@ def gitAvailable = { ->
} }
def allCommited = { -> def allCommitted = { ->
StringBuilder stringBuilder = new StringBuilder() StringBuilder stringBuilder = new StringBuilder()
try { try {
def stdout = new ByteArrayOutputStream() def stdout = new ByteArrayOutputStream()
@ -116,15 +116,16 @@ 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.2-dev" version "2.8.2.1-dev"
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() + '"'
buildConfigField "String", "HEAD", '"' + generateGitBuild() + '"' buildConfigField "String", "HEAD", '"' + generateGitBuild() + '"'
buildConfigField "String", "COMMITTED", '"' + allCommitted() + '"'
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
// if you change minSdkVersion to less than 11, you need to change executeTask for wear // if you change minSdkVersion to less than 11, you need to change executeTask for wear
@ -246,7 +247,7 @@ dependencies {
testImplementation "junit:junit:$junit_version" testImplementation "junit:junit:$junit_version"
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}"
@ -314,12 +315,12 @@ tasks.whenTaskAdded { task ->
printf('--------------\n') printf('--------------\n')
printf('isMaster: %s\n', isMaster().toString()) printf('isMaster: %s\n', isMaster().toString())
printf('gitAvailable: %s\n', gitAvailable().toString()) printf('gitAvailable: %s\n', gitAvailable().toString())
printf('allCommited: %s\n', allCommited().toString()) printf('allCommitted: %s\n', allCommitted().toString())
printf('--------------\n') printf('--------------\n')
if (isMaster() && !gitAvailable()) { if (isMaster() && !gitAvailable()) {
throw new GradleException('GIT system is not available. On Windows try to run Android Studio as an Administrator. Check if GIT is installed and Studio have permissions to use it') throw new GradleException('GIT system is not available. On Windows try to run Android Studio as an Administrator. Check if GIT is installed and Studio have permissions to use it')
} }
if (isMaster() && !allCommited()) { if (isMaster() && !allCommitted()) {
throw new GradleException('There are uncommitted changes. Clone sources again as described in wiki and do not allow gradle update') throw new GradleException('There are uncommitted changes. Clone sources again as described in wiki and do not allow gradle update')
} }

BIN
app/jacoco.exec Normal file

Binary file not shown.

View file

@ -3,6 +3,7 @@
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
package="info.nightscout.androidaps"> package="info.nightscout.androidaps">
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /> <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.BLUETOOTH" /> <uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" /> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />

View file

@ -151,7 +151,7 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
} }
} }
//cherry pick from oref upstream dev cb8e94990301277fb1016c778b4e9efa55a6edbc //cherry pick from oref upstream dev cb8e94990301277fb1016c778b4e9efa55a6edbc
if (bg <= 10 || bg === 38 || noise >= 3 || minAgo > 12 || minAgo < -5 || ( 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 ) ) { if (bg <= 10 || bg === 38 || noise >= 3 || minAgo > 12 || minAgo < -5 || ( 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 (currenttemp.rate > basal) { // high temp is running if (currenttemp.rate > basal) { // high temp is running
rT.reason += ". Replacing high temp basal of "+currenttemp.rate+" with neutral temp of "+basal; rT.reason += ". Replacing high temp basal of "+currenttemp.rate+" with neutral temp of "+basal;
rT.deliverAt = deliverAt; rT.deliverAt = deliverAt;

View file

@ -2,5 +2,6 @@
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
# àqΣnΖ`ZϼγwÛ/τàΒϳ9Φ'$ΑϵžλUΛ`ÆÌΣЃA
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 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 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

@ -1,15 +1,21 @@
package info.nightscout.androidaps package info.nightscout.androidaps
import android.os.Build
import info.nightscout.androidaps.interfaces.ConfigInterface import info.nightscout.androidaps.interfaces.ConfigInterface
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
@Singleton @Singleton
class Config @Inject constructor(): ConfigInterface{ class Config @Inject constructor() : ConfigInterface {
override val SUPPORTEDNSVERSION = 1002 // 0.10.00 override val SUPPORTEDNSVERSION = 1002 // 0.10.00
override val APS = BuildConfig.FLAVOR == "full" override val APS = BuildConfig.FLAVOR == "full"
override val NSCLIENT = BuildConfig.FLAVOR == "nsclient" || BuildConfig.FLAVOR == "nsclient2" override val NSCLIENT = BuildConfig.FLAVOR == "nsclient" || BuildConfig.FLAVOR == "nsclient2"
override val PUMPCONTROL = BuildConfig.FLAVOR == "pumpcontrol" override val PUMPCONTROL = BuildConfig.FLAVOR == "pumpcontrol"
override val PUMPDRIVERS = BuildConfig.FLAVOR == "full" || BuildConfig.FLAVOR == "pumpcontrol" override val PUMPDRIVERS = BuildConfig.FLAVOR == "full" || BuildConfig.FLAVOR == "pumpcontrol"
override val FLAVOR = BuildConfig.FLAVOR
override val VERSION_NAME = BuildConfig.VERSION_NAME
override val currentDeviceModelString =
Build.MANUFACTURER + " " + Build.MODEL + " (" + Build.DEVICE + ")"
} }

View file

@ -2,7 +2,6 @@ package info.nightscout.androidaps
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.pm.PackageManager
import android.graphics.Rect import android.graphics.Rect
import android.os.Bundle import android.os.Bundle
import android.os.PersistableBundle import android.os.PersistableBundle
@ -22,9 +21,9 @@ import android.widget.TextView
import androidx.appcompat.app.ActionBarDrawerToggle import androidx.appcompat.app.ActionBarDrawerToggle
import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AlertDialog
import androidx.appcompat.widget.Toolbar import androidx.appcompat.widget.Toolbar
import androidx.core.app.ActivityCompat
import androidx.viewpager2.widget.ViewPager2 import androidx.viewpager2.widget.ViewPager2
import com.google.android.material.tabs.TabLayoutMediator import com.google.android.material.tabs.TabLayoutMediator
import com.google.firebase.crashlytics.FirebaseCrashlytics
import com.joanzapata.iconify.Iconify import com.joanzapata.iconify.Iconify
import com.joanzapata.iconify.fonts.FontAwesomeModule import com.joanzapata.iconify.fonts.FontAwesomeModule
import dev.doubledot.doki.ui.DokiActivity import dev.doubledot.doki.ui.DokiActivity
@ -33,6 +32,7 @@ import info.nightscout.androidaps.activities.PreferencesActivity
import info.nightscout.androidaps.activities.ProfileHelperActivity 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.databinding.ActivityMainBinding
import info.nightscout.androidaps.events.EventAppExit import info.nightscout.androidaps.events.EventAppExit
import info.nightscout.androidaps.events.EventPreferenceChange import info.nightscout.androidaps.events.EventPreferenceChange
import info.nightscout.androidaps.events.EventRebuildTabs import info.nightscout.androidaps.events.EventRebuildTabs
@ -46,8 +46,6 @@ 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
@ -59,13 +57,11 @@ import info.nightscout.androidaps.utils.extensions.isRunningRealPumpTest
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 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.sharedPreferences.SP import info.nightscout.androidaps.utils.sharedPreferences.SP
import info.nightscout.androidaps.utils.tabs.TabPageAdapter import info.nightscout.androidaps.utils.tabs.TabPageAdapter
import info.nightscout.androidaps.utils.ui.UIRunnable import info.nightscout.androidaps.utils.ui.UIRunnable
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.activity_main.*
import java.util.* import java.util.*
import javax.inject.Inject import javax.inject.Inject
import kotlin.system.exitProcess import kotlin.system.exitProcess
@ -78,7 +74,6 @@ class MainActivity : NoSplashAppCompatActivity() {
@Inject lateinit var rxBus: RxBusWrapper @Inject lateinit var rxBus: RxBusWrapper
@Inject lateinit var androidPermission: AndroidPermission @Inject lateinit var androidPermission: AndroidPermission
@Inject lateinit var sp: SP @Inject lateinit var sp: SP
@Inject lateinit var resourceHelper: ResourceHelper
@Inject lateinit var versionCheckerUtils: VersionCheckerUtils @Inject lateinit var versionCheckerUtils: VersionCheckerUtils
@Inject lateinit var smsCommunicatorPlugin: SmsCommunicatorPlugin @Inject lateinit var smsCommunicatorPlugin: SmsCommunicatorPlugin
@Inject lateinit var loopPlugin: LoopPlugin @Inject lateinit var loopPlugin: LoopPlugin
@ -91,38 +86,36 @@ 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()) { private lateinit var binding: ActivityMainBinding
it?.let {
importExportPrefs.importSharedPreferences(this, it)
}
}
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
Iconify.with(FontAwesomeModule()) Iconify.with(FontAwesomeModule())
LocaleHelper.update(applicationContext) LocaleHelper.update(applicationContext)
setContentView(R.layout.activity_main) binding = ActivityMainBinding.inflate(layoutInflater)
setSupportActionBar(toolbar) setContentView(binding.root)
setSupportActionBar(binding.toolbar)
supportActionBar?.setDisplayShowTitleEnabled(false) supportActionBar?.setDisplayShowTitleEnabled(false)
supportActionBar?.setDisplayHomeAsUpEnabled(true) supportActionBar?.setDisplayHomeAsUpEnabled(true)
supportActionBar?.setHomeButtonEnabled(true) supportActionBar?.setHomeButtonEnabled(true)
actionBarDrawerToggle = ActionBarDrawerToggle(this, main_drawer_layout, R.string.open_navigation, R.string.close_navigation).also { actionBarDrawerToggle = ActionBarDrawerToggle(this, binding.mainDrawerLayout, R.string.open_navigation, R.string.close_navigation).also {
main_drawer_layout.addDrawerListener(it) binding.mainDrawerLayout.addDrawerListener(it)
it.syncState() it.syncState()
} }
// initialize screen wake lock // initialize screen wake lock
processPreferenceChange(EventPreferenceChange(resourceHelper.gs(R.string.key_keep_screen_on))) processPreferenceChange(EventPreferenceChange(resourceHelper.gs(R.string.key_keep_screen_on)))
main_pager.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() { binding.mainPager.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() {
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) {
checkPluginPreferences(main_pager) setPluginPreferenceMenuName()
checkPluginPreferences(binding.mainPager)
} }
}) })
@ -193,63 +186,53 @@ class MainActivity : NoSplashAppCompatActivity() {
private fun setupViews() { private fun setupViews() {
// Menu // Menu
val pageAdapter = TabPageAdapter(this) val pageAdapter = TabPageAdapter(this)
main_navigation_view.setNavigationItemSelectedListener { true } binding.mainNavigationView.setNavigationItemSelectedListener { true }
val menu = main_navigation_view.menu.also { it.clear() } val menu = binding.mainNavigationView.menu.also { it.clear() }
for (p in activePlugin.getPluginsList()) { 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.getPluginsList().indexOf(p)) intent.putExtra("plugin", activePlugin.getPluginsList().indexOf(p))
startActivity(intent) startActivity(intent)
main_drawer_layout.closeDrawers() binding.mainDrawerLayout.closeDrawers()
true true
} }
} }
} }
main_pager.adapter = pageAdapter binding.mainPager.adapter = pageAdapter
main_pager.offscreenPageLimit = 8 // This may cause more memory consumption binding.mainPager.offscreenPageLimit = 8 // This may cause more memory consumption
checkPluginPreferences(main_pager) checkPluginPreferences(binding.mainPager)
// Tabs // Tabs
if (sp.getBoolean(R.string.key_short_tabtitles, false)) { if (sp.getBoolean(R.string.key_short_tabtitles, false)) {
tabs_normal.visibility = View.GONE binding.tabsNormal.visibility = View.GONE
tabs_compact.visibility = View.VISIBLE binding.tabsCompact.visibility = View.VISIBLE
toolbar.layoutParams = LinearLayout.LayoutParams(Toolbar.LayoutParams.MATCH_PARENT, resources.getDimension(R.dimen.compact_height).toInt()) binding.toolbar.layoutParams = LinearLayout.LayoutParams(Toolbar.LayoutParams.MATCH_PARENT, resources.getDimension(R.dimen.compact_height).toInt())
TabLayoutMediator(tabs_compact, main_pager) { tab, position -> TabLayoutMediator(binding.tabsCompact, binding.mainPager) { tab, position ->
tab.text = (main_pager.adapter as TabPageAdapter).getPluginAt(position).nameShort tab.text = (binding.mainPager.adapter as TabPageAdapter).getPluginAt(position).nameShort
}.attach() }.attach()
} else { } else {
tabs_normal.visibility = View.VISIBLE binding.tabsNormal.visibility = View.VISIBLE
tabs_compact.visibility = View.GONE binding.tabsCompact.visibility = View.GONE
val typedValue = TypedValue() val typedValue = TypedValue()
if (theme.resolveAttribute(R.attr.actionBarSize, typedValue, true)) { if (theme.resolveAttribute(R.attr.actionBarSize, typedValue, true)) {
toolbar.layoutParams = LinearLayout.LayoutParams(Toolbar.LayoutParams.MATCH_PARENT, binding.toolbar.layoutParams = LinearLayout.LayoutParams(Toolbar.LayoutParams.MATCH_PARENT,
TypedValue.complexToDimensionPixelSize(typedValue.data, resources.displayMetrics)) TypedValue.complexToDimensionPixelSize(typedValue.data, resources.displayMetrics))
} }
TabLayoutMediator(tabs_normal, main_pager) { tab, position -> TabLayoutMediator(binding.tabsNormal, binding.mainPager) { tab, position ->
tab.text = (main_pager.adapter as TabPageAdapter).getPluginAt(position).name tab.text = (binding.mainPager.adapter as TabPageAdapter).getPluginAt(position).name
}.attach() }.attach()
} }
} }
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
if (permissions.isNotEmpty()) {
if (ActivityCompat.checkSelfPermission(this, permissions[0]) == PackageManager.PERMISSION_GRANTED) {
when (requestCode) {
AndroidPermission.CASE_STORAGE -> //show dialog after permission is granted
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 -> {
}
}
}
}
}
override fun dispatchTouchEvent(event: MotionEvent): Boolean { override fun dispatchTouchEvent(event: MotionEvent): Boolean {
if (event.action == MotionEvent.ACTION_DOWN) { if (event.action == MotionEvent.ACTION_DOWN) {
val v = currentFocus val v = currentFocus
@ -266,10 +249,19 @@ class MainActivity : NoSplashAppCompatActivity() {
return super.dispatchTouchEvent(event) return super.dispatchTouchEvent(event)
} }
private fun setPluginPreferenceMenuName() {
if (binding.mainPager.currentItem >= 0) {
val plugin = (binding.mainPager.adapter as TabPageAdapter).getPluginAt(binding.mainPager.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)
checkPluginPreferences(main_pager) setPluginPreferenceMenuName()
checkPluginPreferences(binding.mainPager)
return true return true
} }
@ -301,6 +293,7 @@ class MainActivity : NoSplashAppCompatActivity() {
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}"
if (buildHelper.isEngineeringMode()) message += "\n${resourceHelper.gs(R.string.engineering_mode_enabled)}" if (buildHelper.isEngineeringMode()) message += "\n${resourceHelper.gs(R.string.engineering_mode_enabled)}"
if (!fabricPrivacy.fabricEnabled()) message += "\n${resourceHelper.gs(R.string.fabric_upload_disabled)}"
message += resourceHelper.gs(R.string.about_link_urls) message += resourceHelper.gs(R.string.about_link_urls)
val messageSpanned = SpannableString(message) val messageSpanned = SpannableString(message)
Linkify.addLinks(messageSpanned, Linkify.WEB_URLS) Linkify.addLinks(messageSpanned, Linkify.WEB_URLS)
@ -326,7 +319,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 = (binding.mainPager.adapter as TabPageAdapter).getPluginAt(binding.mainPager.currentItem)
protectionCheck.queryProtection(this, ProtectionCheck.Protection.PREFERENCES, { 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)
@ -381,6 +374,12 @@ class MainActivity : NoSplashAppCompatActivity() {
fabricPrivacy.firebaseAnalytics.setUserProperty("Profile", activePlugin.activeProfileInterface.javaClass.simpleName) fabricPrivacy.firebaseAnalytics.setUserProperty("Profile", activePlugin.activeProfileInterface.javaClass.simpleName)
activePlugin.activeSensitivity.let { fabricPrivacy.firebaseAnalytics.setUserProperty("Sensitivity", it::class.java.simpleName) } activePlugin.activeSensitivity.let { fabricPrivacy.firebaseAnalytics.setUserProperty("Sensitivity", it::class.java.simpleName) }
activePlugin.activeInsulin.let { fabricPrivacy.firebaseAnalytics.setUserProperty("Insulin", it::class.java.simpleName) } activePlugin.activeInsulin.let { fabricPrivacy.firebaseAnalytics.setUserProperty("Insulin", it::class.java.simpleName) }
// Add to crash log too
FirebaseCrashlytics.getInstance().setCustomKey("HEAD", BuildConfig.HEAD)
FirebaseCrashlytics.getInstance().setCustomKey("Version", BuildConfig.VERSION)
FirebaseCrashlytics.getInstance().setCustomKey("Remote", remote)
FirebaseCrashlytics.getInstance().setCustomKey("Committed", BuildConfig.COMMITTED)
FirebaseCrashlytics.getInstance().setCustomKey("Hash", hashes[0])
} }
} }

View file

@ -420,6 +420,6 @@ class MyPreferenceFragment : PreferenceFragmentCompat(), OnSharedPreferenceChang
fun setFilter(filter: String) { fun setFilter(filter: String) {
this.filter = filter this.filter = filter
updateFilterVisibility(filter, preferenceScreen) preferenceManager?.preferenceScreen?.let { updateFilterVisibility(filter, it) }
} }
} }

View file

@ -7,23 +7,22 @@ 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.databinding.ActivityPreferencesBinding
import info.nightscout.androidaps.utils.locale.LocaleHelper import info.nightscout.androidaps.utils.locale.LocaleHelper
import info.nightscout.androidaps.utils.resources.ResourceHelper
import kotlinx.android.synthetic.main.activity_preferences.*
import javax.inject.Inject
class PreferencesActivity : NoSplashAppCompatActivity(), PreferenceFragmentCompat.OnPreferenceStartScreenCallback { class PreferencesActivity : NoSplashAppCompatActivity(), PreferenceFragmentCompat.OnPreferenceStartScreenCallback {
@Inject lateinit var resourceHelper: ResourceHelper private var preferenceId = 0
private var myPreferenceFragment: MyPreferenceFragment? = null
var preferenceId = 0 private lateinit var binding: ActivityPreferencesBinding
var myPreferenceFragment: MyPreferenceFragment? = null
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setContentView(R.layout.activity_preferences) binding = ActivityPreferencesBinding.inflate(layoutInflater)
setContentView(binding.root)
pref_filter.addTextChangedListener(object : TextWatcher { binding.prefFilter.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) {
filterPreferences() filterPreferences()
@ -37,23 +36,21 @@ class PreferencesActivity : NoSplashAppCompatActivity(), PreferenceFragmentCompa
supportActionBar?.setDisplayShowHomeEnabled(true) supportActionBar?.setDisplayShowHomeEnabled(true)
myPreferenceFragment = MyPreferenceFragment() myPreferenceFragment = MyPreferenceFragment()
preferenceId = intent.getIntExtra("id", -1) preferenceId = intent.getIntExtra("id", -1)
val args = Bundle() myPreferenceFragment?.arguments = Bundle().also {
args.putInt("id", preferenceId) it.putInt("id", preferenceId)
args.putString("filter", pref_filter.text.toString()) it.putString("filter", binding.prefFilter.text.toString())
myPreferenceFragment?.arguments = args }
if (savedInstanceState == null)
supportFragmentManager.beginTransaction().replace(R.id.frame_layout, myPreferenceFragment!!).commit() 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 {
val fragment = MyPreferenceFragment() val fragment = MyPreferenceFragment()
val args = Bundle() fragment.arguments = Bundle().also {
args.putString(PreferenceFragmentCompat.ARG_PREFERENCE_ROOT, pref.key) it.putString(PreferenceFragmentCompat.ARG_PREFERENCE_ROOT, pref.key)
args.putInt("id", preferenceId) it.putInt("id", preferenceId)
fragment.arguments = args }
supportFragmentManager.beginTransaction() supportFragmentManager.beginTransaction().replace(R.id.frame_layout, fragment, pref.key).addToBackStack(pref.key).commit()
.replace(R.id.frame_layout, fragment, pref.key)
.addToBackStack(pref.key)
.commit()
return true return true
} }
@ -62,6 +59,6 @@ class PreferencesActivity : NoSplashAppCompatActivity(), PreferenceFragmentCompa
} }
private fun filterPreferences() { private fun filterPreferences() {
myPreferenceFragment?.setFilter(pref_filter.text.toString()) myPreferenceFragment?.setFilter(binding.prefFilter.text.toString())
} }
} }

View file

@ -10,6 +10,7 @@ import info.nightscout.androidaps.R
import info.nightscout.androidaps.data.Profile import info.nightscout.androidaps.data.Profile
import info.nightscout.androidaps.data.defaultProfile.DefaultProfile import info.nightscout.androidaps.data.defaultProfile.DefaultProfile
import info.nightscout.androidaps.data.defaultProfile.DefaultProfileDPV import info.nightscout.androidaps.data.defaultProfile.DefaultProfileDPV
import info.nightscout.androidaps.databinding.ActivityProfilehelperBinding
import info.nightscout.androidaps.db.ProfileSwitch import info.nightscout.androidaps.db.ProfileSwitch
import info.nightscout.androidaps.dialogs.ProfileViewerDialog import info.nightscout.androidaps.dialogs.ProfileViewerDialog
import info.nightscout.androidaps.interfaces.ActivePluginProvider import info.nightscout.androidaps.interfaces.ActivePluginProvider
@ -24,15 +25,13 @@ import info.nightscout.androidaps.utils.T
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
import info.nightscout.androidaps.utils.extensions.toVisibility import info.nightscout.androidaps.utils.extensions.toVisibility
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.stats.TddCalculator import info.nightscout.androidaps.utils.stats.TddCalculator
import kotlinx.android.synthetic.main.activity_profilehelper.*
import java.text.DecimalFormat import java.text.DecimalFormat
import javax.inject.Inject import javax.inject.Inject
class ProfileHelperActivity : NoSplashAppCompatActivity() { class ProfileHelperActivity : NoSplashAppCompatActivity() {
@Inject lateinit var aapsLogger: AAPSLogger @Inject lateinit var aapsLogger: AAPSLogger
@Inject lateinit var resourceHelper: ResourceHelper
@Inject lateinit var tddCalculator: TddCalculator @Inject lateinit var tddCalculator: TddCalculator
@Inject lateinit var profileFunction: ProfileFunction @Inject lateinit var profileFunction: ProfileFunction
@Inject lateinit var defaultProfile: DefaultProfile @Inject lateinit var defaultProfile: DefaultProfile
@ -65,22 +64,26 @@ class ProfileHelperActivity : NoSplashAppCompatActivity() {
private lateinit var profileSwitch: List<ProfileSwitch> private lateinit var profileSwitch: List<ProfileSwitch>
private val profileSwitchUsed = arrayOf(0, 0) private val profileSwitchUsed = arrayOf(0, 0)
private lateinit var binding: ActivityProfilehelperBinding
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setContentView(R.layout.activity_profilehelper)
profilehelper_menu1.setOnClickListener { binding = ActivityProfilehelperBinding.inflate(layoutInflater)
setContentView(binding.root)
binding.menu1.setOnClickListener {
switchTab(0, typeSelected[0]) switchTab(0, typeSelected[0])
} }
profilehelper_menu2.setOnClickListener { binding.menu2.setOnClickListener {
switchTab(1, typeSelected[1]) switchTab(1, typeSelected[1])
} }
profilehelper_profiletype.setOnClickListener { binding.profiletype.setOnClickListener {
PopupMenu(this, profilehelper_profiletype).apply { PopupMenu(this, binding.profiletype).apply {
menuInflater.inflate(R.menu.menu_profilehelper, menu) menuInflater.inflate(R.menu.menu_profilehelper, menu)
setOnMenuItemClickListener { item -> setOnMenuItemClickListener { item ->
profilehelper_profiletype.setText(item.title) binding.profiletype.setText(item.title)
when (item.itemId) { when (item.itemId) {
R.id.menu_default -> switchTab(tabSelected, ProfileType.MOTOL_DEFAULT) R.id.menu_default -> switchTab(tabSelected, ProfileType.MOTOL_DEFAULT)
R.id.menu_default_dpv -> switchTab(tabSelected, ProfileType.DPV_DEFAULT) R.id.menu_default_dpv -> switchTab(tabSelected, ProfileType.DPV_DEFAULT)
@ -97,12 +100,12 @@ class ProfileHelperActivity : NoSplashAppCompatActivity() {
// Active profile // Active profile
profileList = activePlugin.activeProfileInterface.profile?.getProfileList() ?: ArrayList() profileList = activePlugin.activeProfileInterface.profile?.getProfileList() ?: ArrayList()
profilehelper_available_profile_list.setOnClickListener { binding.availableProfileList.setOnClickListener {
PopupMenu(this, profilehelper_available_profile_list).apply { PopupMenu(this, binding.availableProfileList).apply {
var order = 0 var order = 0
for (name in profileList) menu.add(Menu.NONE, order, order++, name) for (name in profileList) menu.add(Menu.NONE, order, order++, name)
setOnMenuItemClickListener { item -> setOnMenuItemClickListener { item ->
profilehelper_available_profile_list.setText(item.title) binding.availableProfileList.setText(item.title)
profileUsed[tabSelected] = item.itemId profileUsed[tabSelected] = item.itemId
true true
} }
@ -113,12 +116,12 @@ class ProfileHelperActivity : NoSplashAppCompatActivity() {
// Profile switch // Profile switch
profileSwitch = databaseHelper.getProfileSwitchData(dateUtil._now() - T.months(2).msecs(), true) profileSwitch = databaseHelper.getProfileSwitchData(dateUtil._now() - T.months(2).msecs(), true)
profilehelper_profileswitch_list.setOnClickListener { binding.profileswitchList.setOnClickListener {
PopupMenu(this, profilehelper_profileswitch_list).apply { PopupMenu(this, binding.profileswitchList).apply {
var order = 0 var order = 0
for (name in profileSwitch) menu.add(Menu.NONE, order, order++, name.customizedName) for (name in profileSwitch) menu.add(Menu.NONE, order, order++, name.customizedName)
setOnMenuItemClickListener { item -> setOnMenuItemClickListener { item ->
profilehelper_profileswitch_list.setText(item.title) binding.profileswitchList.setText(item.title)
profileSwitchUsed[tabSelected] = item.itemId profileSwitchUsed[tabSelected] = item.itemId
true true
} }
@ -127,7 +130,7 @@ class ProfileHelperActivity : NoSplashAppCompatActivity() {
} }
// Default profile // Default profile
profilehelper_copytolocalprofile.setOnClickListener { binding.copytolocalprofile.setOnClickListener {
val age = ageUsed[tabSelected] val age = ageUsed[tabSelected]
val weight = weightUsed[tabSelected] val weight = weightUsed[tabSelected]
val tdd = tddUsed[tabSelected] val tdd = tddUsed[tabSelected]
@ -142,31 +145,31 @@ class ProfileHelperActivity : NoSplashAppCompatActivity() {
} }
} }
profilehelper_age.setParams(0.0, 1.0, 18.0, 1.0, DecimalFormat("0"), false, null) binding.age.setParams(0.0, 1.0, 18.0, 1.0, DecimalFormat("0"), false, null)
profilehelper_weight.setParams(0.0, 0.0, 150.0, 1.0, DecimalFormat("0"), false, null, object : TextWatcher { binding.weight.setParams(0.0, 0.0, 150.0, 1.0, DecimalFormat("0"), false, null, object : TextWatcher {
override fun afterTextChanged(s: Editable) {} override fun afterTextChanged(s: Editable) {}
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {} override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {}
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) { override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
profilehelper_tdd_row.visibility = (profilehelper_weight.value == 0.0).toVisibility() binding.tddRow.visibility = (binding.weight.value == 0.0).toVisibility()
} }
}) })
profilehelper_tdd.setParams(0.0, 0.0, 200.0, 1.0, DecimalFormat("0"), false, null, object : TextWatcher { binding.tdd.setParams(0.0, 0.0, 200.0, 1.0, DecimalFormat("0"), false, null, object : TextWatcher {
override fun afterTextChanged(s: Editable) {} override fun afterTextChanged(s: Editable) {}
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {} override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {}
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) { override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
profilehelper_weight_row.visibility = (profilehelper_tdd.value == 0.0).toVisibility() binding.weightRow.visibility = (binding.tdd.value == 0.0).toVisibility()
} }
}) })
profilehelper_basalpctfromtdd.setParams(32.0, 32.0, 37.0, 1.0, DecimalFormat("0"), false, null) binding.basalpctfromtdd.setParams(32.0, 32.0, 37.0, 1.0, DecimalFormat("0"), false, null)
profilehelper_tdds.text = tddCalculator.stats() binding.tdds.text = tddCalculator.stats()
// Current profile // Current profile
profilehelper_current_profile_text.text = profileFunction.getProfileName() binding.currentProfileText.text = profileFunction.getProfileName()
// General // General
profilehelper_compareprofile.setOnClickListener { binding.compareprofile.setOnClickListener {
storeValues() storeValues()
for (i in 0..1) { for (i in 0..1) {
if (typeSelected[i] == ProfileType.MOTOL_DEFAULT) { if (typeSelected[i] == ProfileType.MOTOL_DEFAULT) {
@ -221,6 +224,7 @@ class ProfileHelperActivity : NoSplashAppCompatActivity() {
} }
private fun getProfile(age: Double, tdd: Double, weight: Double, basalPct: Double, tab: Int): Profile? = private fun getProfile(age: Double, tdd: Double, weight: Double, basalPct: Double, tab: Int): Profile? =
try { // profile must not exist
when (typeSelected[tab]) { when (typeSelected[tab]) {
ProfileType.MOTOL_DEFAULT -> defaultProfile.profile(age, tdd, weight, profileFunction.getUnits()) ProfileType.MOTOL_DEFAULT -> defaultProfile.profile(age, tdd, weight, profileFunction.getUnits())
ProfileType.DPV_DEFAULT -> defaultProfileDPV.profile(age, tdd, basalPct, profileFunction.getUnits()) ProfileType.DPV_DEFAULT -> defaultProfileDPV.profile(age, tdd, basalPct, profileFunction.getUnits())
@ -228,6 +232,9 @@ class ProfileHelperActivity : NoSplashAppCompatActivity() {
ProfileType.AVAILABLE_PROFILE -> activePlugin.activeProfileInterface.profile?.getSpecificProfile(profileList[profileUsed[tab]].toString()) ProfileType.AVAILABLE_PROFILE -> activePlugin.activeProfileInterface.profile?.getSpecificProfile(profileList[profileUsed[tab]].toString())
ProfileType.PROFILE_SWITCH -> profileSwitch[profileSwitchUsed[tab]].profileObject?.convertToNonCustomizedProfile() ProfileType.PROFILE_SWITCH -> profileSwitch[profileSwitchUsed[tab]].profileObject?.convertToNonCustomizedProfile()
} }
} catch (e: Exception) {
null
}
private fun getProfileName(age: Double, tdd: Double, weight: Double, basalSumPct: Double, tab: Int): String = private fun getProfileName(age: Double, tdd: Double, weight: Double, basalSumPct: Double, tab: Int): String =
when (typeSelected[tab]) { when (typeSelected[tab]) {
@ -239,10 +246,10 @@ class ProfileHelperActivity : NoSplashAppCompatActivity() {
} }
private fun storeValues() { private fun storeValues() {
ageUsed[tabSelected] = profilehelper_age.value ageUsed[tabSelected] = binding.age.value
weightUsed[tabSelected] = profilehelper_weight.value weightUsed[tabSelected] = binding.weight.value
tddUsed[tabSelected] = profilehelper_tdd.value tddUsed[tabSelected] = binding.tdd.value
pctUsed[tabSelected] = profilehelper_basalpctfromtdd.value pctUsed[tabSelected] = binding.basalpctfromtdd.value
} }
private fun switchTab(tab: Int, newContent: ProfileType, storeOld: Boolean = true) { private fun switchTab(tab: Int, newContent: ProfileType, storeOld: Boolean = true) {
@ -252,10 +259,10 @@ class ProfileHelperActivity : NoSplashAppCompatActivity() {
tabSelected = tab tabSelected = tab
typeSelected[tabSelected] = newContent typeSelected[tabSelected] = newContent
profilehelper_profiletype_title.defaultHintTextColor = ColorStateList.valueOf(resourceHelper.gc(if (tab == 0) R.color.tabBgColorSelected else R.color.examinedProfile)) binding.profiletypeTitle.defaultHintTextColor = ColorStateList.valueOf(resourceHelper.gc(if (tab == 0) R.color.tabBgColorSelected else R.color.examinedProfile))
// show new content // show new content
profilehelper_profiletype.setText( binding.profiletype.setText(
when (typeSelected[tabSelected]) { when (typeSelected[tabSelected]) {
ProfileType.MOTOL_DEFAULT -> resourceHelper.gs(R.string.motoldefaultprofile) ProfileType.MOTOL_DEFAULT -> resourceHelper.gs(R.string.motoldefaultprofile)
ProfileType.DPV_DEFAULT -> resourceHelper.gs(R.string.dpvdefaultprofile) ProfileType.DPV_DEFAULT -> resourceHelper.gs(R.string.dpvdefaultprofile)
@ -263,26 +270,26 @@ class ProfileHelperActivity : NoSplashAppCompatActivity() {
ProfileType.AVAILABLE_PROFILE -> resourceHelper.gs(R.string.availableprofile) ProfileType.AVAILABLE_PROFILE -> resourceHelper.gs(R.string.availableprofile)
ProfileType.PROFILE_SWITCH -> resourceHelper.gs(R.string.careportal_profileswitch) ProfileType.PROFILE_SWITCH -> resourceHelper.gs(R.string.careportal_profileswitch)
}) })
profilehelper_default_profile.visibility = (newContent == ProfileType.MOTOL_DEFAULT || newContent == ProfileType.DPV_DEFAULT).toVisibility() binding.defaultProfile.visibility = (newContent == ProfileType.MOTOL_DEFAULT || newContent == ProfileType.DPV_DEFAULT).toVisibility()
profilehelper_current_profile.visibility = (newContent == ProfileType.CURRENT).toVisibility() binding.currentProfile.visibility = (newContent == ProfileType.CURRENT).toVisibility()
profilehelper_available_profile.visibility = (newContent == ProfileType.AVAILABLE_PROFILE).toVisibility() binding.availableProfile.visibility = (newContent == ProfileType.AVAILABLE_PROFILE).toVisibility()
profilehelper_profile_switch.visibility = (newContent == ProfileType.PROFILE_SWITCH).toVisibility() binding.profileSwitch.visibility = (newContent == ProfileType.PROFILE_SWITCH).toVisibility()
// restore selected values // restore selected values
profilehelper_age.value = ageUsed[tabSelected] binding.age.value = ageUsed[tabSelected]
profilehelper_weight.value = weightUsed[tabSelected] binding.weight.value = weightUsed[tabSelected]
profilehelper_tdd.value = tddUsed[tabSelected] binding.tdd.value = tddUsed[tabSelected]
profilehelper_basalpctfromtdd.value = pctUsed[tabSelected] binding.basalpctfromtdd.value = pctUsed[tabSelected]
profilehelper_basalpctfromtdd_row.visibility = (newContent == ProfileType.DPV_DEFAULT).toVisibility() binding.basalpctfromtddRow.visibility = (newContent == ProfileType.DPV_DEFAULT).toVisibility()
if (profileList.isNotEmpty()) if (profileList.isNotEmpty())
profilehelper_available_profile_list.setText(profileList[profileUsed[tabSelected]].toString()) binding.availableProfileList.setText(profileList[profileUsed[tabSelected]].toString())
if (profileSwitch.isNotEmpty()) if (profileSwitch.isNotEmpty())
profilehelper_profileswitch_list.setText(profileSwitch[profileSwitchUsed[tabSelected]].customizedName) binding.profileswitchList.setText(profileSwitch[profileSwitchUsed[tabSelected]].customizedName)
} }
private fun setBackgroundColorOnSelected(tab: Int) { private fun setBackgroundColorOnSelected(tab: Int) {
profilehelper_menu1.setBackgroundColor(resourceHelper.gc(if (tab == 1) R.color.defaultbackground else R.color.tabBgColorSelected)) binding.menu1.setBackgroundColor(resourceHelper.gc(if (tab == 1) R.color.defaultbackground else R.color.tabBgColorSelected))
profilehelper_menu2.setBackgroundColor(resourceHelper.gc(if (tab == 0) R.color.defaultbackground else R.color.examinedProfile)) binding.menu2.setBackgroundColor(resourceHelper.gc(if (tab == 0) R.color.defaultbackground else R.color.examinedProfile))
} }
} }

View file

@ -15,6 +15,7 @@ class RequestDexcomPermissionActivity : DialogAppCompatActivity() {
} }
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) { override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
finish() finish()
} }

View file

@ -5,29 +5,20 @@ import android.content.Intent
import android.os.Bundle import android.os.Bundle
import android.view.Menu import android.view.Menu
import android.view.MenuItem import android.view.MenuItem
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
class SingleFragmentActivity : DaggerAppCompatActivity() { class SingleFragmentActivity : DaggerAppCompatActivityWithResult() {
@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

@ -2,35 +2,36 @@ package info.nightscout.androidaps.activities
import android.os.Bundle import android.os.Bundle
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.databinding.ActivityStatsBinding
import info.nightscout.androidaps.utils.ActivityMonitor import info.nightscout.androidaps.utils.ActivityMonitor
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.alertDialogs.OKDialog import info.nightscout.androidaps.utils.alertDialogs.OKDialog
import info.nightscout.androidaps.utils.stats.TddCalculator import info.nightscout.androidaps.utils.stats.TddCalculator
import info.nightscout.androidaps.utils.stats.TirCalculator import info.nightscout.androidaps.utils.stats.TirCalculator
import info.nightscout.androidaps.utils.resources.ResourceHelper
import kotlinx.android.synthetic.main.activity_stats.*
import javax.inject.Inject import javax.inject.Inject
class StatsActivity : NoSplashAppCompatActivity() { class StatsActivity : NoSplashAppCompatActivity() {
@Inject lateinit var tddCalculator: TddCalculator @Inject lateinit var tddCalculator: TddCalculator
@Inject lateinit var tirCalculator: TirCalculator @Inject lateinit var tirCalculator: TirCalculator
@Inject lateinit var resourceHelper: ResourceHelper
@Inject lateinit var activityMonitor: ActivityMonitor @Inject lateinit var activityMonitor: ActivityMonitor
private lateinit var binding: ActivityStatsBinding
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setContentView(R.layout.activity_stats) binding = ActivityStatsBinding.inflate(layoutInflater)
setContentView(binding.root)
stats_tdds.text = tddCalculator.stats() binding.tdds.text = tddCalculator.stats()
stats_tir.text = tirCalculator.stats() binding.tir.text = tirCalculator.stats()
stats_activity.text = activityMonitor.stats() binding.activity.text = activityMonitor.stats()
ok.setOnClickListener { finish() } binding.ok.setOnClickListener { finish() }
stats_reset.setOnClickListener { binding.reset.setOnClickListener {
OKDialog.showConfirmation(this, resourceHelper.gs(R.string.doyouwantresetstats), Runnable { OKDialog.showConfirmation(this, resourceHelper.gs(R.string.doyouwantresetstats)) {
activityMonitor.reset() activityMonitor.reset()
recreate() recreate()
}) }
} }
} }
} }

View file

@ -6,6 +6,7 @@ import com.google.firebase.auth.FirebaseAuth
import com.google.firebase.database.FirebaseDatabase import com.google.firebase.database.FirebaseDatabase
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.data.defaultProfile.DefaultProfile import info.nightscout.androidaps.data.defaultProfile.DefaultProfile
import info.nightscout.androidaps.databinding.ActivitySurveyBinding
import info.nightscout.androidaps.dialogs.ProfileViewerDialog import info.nightscout.androidaps.dialogs.ProfileViewerDialog
import info.nightscout.androidaps.interfaces.ActivePluginProvider import info.nightscout.androidaps.interfaces.ActivePluginProvider
import info.nightscout.androidaps.interfaces.ProfileFunction import info.nightscout.androidaps.interfaces.ProfileFunction
@ -16,15 +17,13 @@ import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.InstanceId import info.nightscout.androidaps.utils.InstanceId
import info.nightscout.androidaps.utils.SafeParse import info.nightscout.androidaps.utils.SafeParse
import info.nightscout.androidaps.utils.ToastUtils import info.nightscout.androidaps.utils.ToastUtils
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.stats.TddCalculator import info.nightscout.androidaps.utils.stats.TddCalculator
import info.nightscout.androidaps.utils.stats.TirCalculator import info.nightscout.androidaps.utils.stats.TirCalculator
import kotlinx.android.synthetic.main.activity_survey.*
import javax.inject.Inject import javax.inject.Inject
class SurveyActivity : NoSplashAppCompatActivity() { class SurveyActivity : NoSplashAppCompatActivity() {
@Inject lateinit var aapsLogger: AAPSLogger @Inject lateinit var aapsLogger: AAPSLogger
@Inject lateinit var resourceHelper: ResourceHelper
@Inject lateinit var activePlugin: ActivePluginProvider @Inject lateinit var activePlugin: ActivePluginProvider
@Inject lateinit var tddCalculator: TddCalculator @Inject lateinit var tddCalculator: TddCalculator
@Inject lateinit var tirCalculator: TirCalculator @Inject lateinit var tirCalculator: TirCalculator
@ -32,24 +31,27 @@ class SurveyActivity : NoSplashAppCompatActivity() {
@Inject lateinit var activityMonitor: ActivityMonitor @Inject lateinit var activityMonitor: ActivityMonitor
@Inject lateinit var defaultProfile: DefaultProfile @Inject lateinit var defaultProfile: DefaultProfile
private lateinit var binding: ActivitySurveyBinding
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setContentView(R.layout.activity_survey) binding = ActivitySurveyBinding.inflate(layoutInflater)
setContentView(binding.root)
survey_id.text = InstanceId.instanceId() binding.id.text = InstanceId.instanceId()
val profileStore = activePlugin.activeProfileInterface.profile val profileStore = activePlugin.activeProfileInterface.profile
val profileList = profileStore?.getProfileList() ?: return val profileList = profileStore?.getProfileList() ?: return
survey_spinner.adapter = ArrayAdapter(this, R.layout.spinner_centered, profileList) binding.spinner.adapter = ArrayAdapter(this, R.layout.spinner_centered, profileList)
survey_tdds.text = tddCalculator.stats() binding.tdds.text = tddCalculator.stats()
survey_tir.text = tirCalculator.stats() binding.tir.text = tirCalculator.stats()
survey_activity.text = activityMonitor.stats() binding.activity.text = activityMonitor.stats()
survey_profile.setOnClickListener { binding.profile.setOnClickListener {
val age = SafeParse.stringToDouble(survey_age.text.toString()) val age = SafeParse.stringToDouble(binding.age.text.toString())
val weight = SafeParse.stringToDouble(survey_weight.text.toString()) val weight = SafeParse.stringToDouble(binding.weight.text.toString())
val tdd = SafeParse.stringToDouble(survey_tdd.text.toString()) val tdd = SafeParse.stringToDouble(binding.tdd.text.toString())
if (age < 1 || age > 120) { if (age < 1 || age > 120) {
ToastUtils.showToastInUiThread(this, R.string.invalidage) ToastUtils.showToastInUiThread(this, R.string.invalidage)
return@setOnClickListener return@setOnClickListener
@ -78,11 +80,11 @@ class SurveyActivity : NoSplashAppCompatActivity() {
} }
} }
survey_submit.setOnClickListener { binding.submit.setOnClickListener {
val r = FirebaseRecord() val r = FirebaseRecord()
r.id = InstanceId.instanceId() r.id = InstanceId.instanceId()
r.age = SafeParse.stringToInt(survey_age.text.toString()) r.age = SafeParse.stringToInt(binding.age.text.toString())
r.weight = SafeParse.stringToInt(survey_weight.text.toString()) r.weight = SafeParse.stringToInt(binding.weight.text.toString())
if (r.age < 1 || r.age > 120) { if (r.age < 1 || r.age > 120) {
ToastUtils.showToastInUiThread(this, R.string.invalidage) ToastUtils.showToastInUiThread(this, R.string.invalidage)
return@setOnClickListener return@setOnClickListener
@ -92,9 +94,9 @@ class SurveyActivity : NoSplashAppCompatActivity() {
return@setOnClickListener return@setOnClickListener
} }
if (survey_spinner.selectedItem == null) if (binding.spinner.selectedItem == null)
return@setOnClickListener return@setOnClickListener
val profileName = survey_spinner.selectedItem.toString() val profileName = binding.spinner.selectedItem.toString()
val specificProfile = profileStore.getSpecificProfile(profileName) val specificProfile = profileStore.getSpecificProfile(profileName)
r.profileJson = specificProfile.toString() r.profileJson = specificProfile.toString()
@ -121,6 +123,7 @@ class SurveyActivity : NoSplashAppCompatActivity() {
} }
inner class FirebaseRecord { inner class FirebaseRecord {
var id = "" var id = ""
var age: Int = 0 var age: Int = 0
var weight: Int = 0 var weight: Int = 0

View file

@ -6,11 +6,10 @@ import info.nightscout.androidaps.MainActivity
import info.nightscout.androidaps.activities.* import info.nightscout.androidaps.activities.*
import info.nightscout.androidaps.historyBrowser.HistoryBrowseActivity import info.nightscout.androidaps.historyBrowser.HistoryBrowseActivity
import info.nightscout.androidaps.plugins.general.maintenance.activities.LogSettingActivity import info.nightscout.androidaps.plugins.general.maintenance.activities.LogSettingActivity
import info.nightscout.androidaps.plugins.general.maintenance.activities.PrefImportListActivity
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,14 +32,13 @@ 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
@ContributesAndroidInjector abstract fun contributesStatsActivity(): StatsActivity @ContributesAndroidInjector abstract fun contributesStatsActivity(): StatsActivity
@ContributesAndroidInjector abstract fun contributesSurveyActivity(): SurveyActivity @ContributesAndroidInjector abstract fun contributesSurveyActivity(): SurveyActivity
@ContributesAndroidInjector abstract fun contributesDefaultProfileActivity(): ProfileHelperActivity @ContributesAndroidInjector abstract fun contributesDefaultProfileActivity(): ProfileHelperActivity
@ContributesAndroidInjector abstract fun contributesPrefImportListActivity(): PrefImportListActivity
@ContributesAndroidInjector abstract fun contributesOpenHumansLoginActivity(): OpenHumansLoginActivity @ContributesAndroidInjector abstract fun contributesOpenHumansLoginActivity(): OpenHumansLoginActivity
} }

View file

@ -12,6 +12,7 @@ import info.nightscout.androidaps.db.DatabaseHelperProvider
import info.nightscout.androidaps.interfaces.* import info.nightscout.androidaps.interfaces.*
import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin
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.nsclient.UploadQueue import info.nightscout.androidaps.plugins.general.nsclient.UploadQueue
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin
import info.nightscout.androidaps.queue.CommandQueue import info.nightscout.androidaps.queue.CommandQueue
@ -58,5 +59,6 @@ open class AppModule {
@Binds fun bindDatabaseHelperInterface(databaseHelperProvider: DatabaseHelperProvider): DatabaseHelperInterface @Binds fun bindDatabaseHelperInterface(databaseHelperProvider: DatabaseHelperProvider): DatabaseHelperInterface
@Binds fun bindUploadQueueInterface(uploadQueue: UploadQueue): UploadQueueInterface @Binds fun bindUploadQueueInterface(uploadQueue: UploadQueue): UploadQueueInterface
@Binds fun bindNotificationHolderInterface(notificationHolder: NotificationHolder): NotificationHolderInterface @Binds fun bindNotificationHolderInterface(notificationHolder: NotificationHolder): NotificationHolderInterface
@Binds fun bindImportExportPrefsInterface(importExportPrefs: ImportExportPrefs): ImportExportPrefsInterface
} }
} }

View file

@ -109,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

@ -205,7 +205,7 @@ abstract class PluginsModule {
abstract fun bindLocalProfilePlugin(plugin: LocalProfilePlugin): PluginBase abstract fun bindLocalProfilePlugin(plugin: LocalProfilePlugin): PluginBase
@Binds @Binds
@APS @AllConfigs
@IntoMap @IntoMap
@IntKey(250) @IntKey(250)
abstract fun bindAutomationPlugin(plugin: AutomationPlugin): PluginBase abstract fun bindAutomationPlugin(plugin: AutomationPlugin): PluginBase

View file

@ -2,7 +2,6 @@ package info.nightscout.androidaps.dependencyInjection
import dagger.Module import dagger.Module
import dagger.android.ContributesAndroidInjector import dagger.android.ContributesAndroidInjector
import info.nightscout.androidaps.plugins.general.maintenance.ImportExportPrefs
import info.nightscout.androidaps.plugins.general.maintenance.PrefFileListProvider import info.nightscout.androidaps.plugins.general.maintenance.PrefFileListProvider
import info.nightscout.androidaps.plugins.general.maintenance.formats.ClassicPrefsFormat import info.nightscout.androidaps.plugins.general.maintenance.formats.ClassicPrefsFormat
import info.nightscout.androidaps.plugins.general.maintenance.formats.EncryptedPrefsFormat import info.nightscout.androidaps.plugins.general.maintenance.formats.EncryptedPrefsFormat
@ -13,7 +12,6 @@ import info.nightscout.androidaps.utils.CryptoUtil
abstract class PreferencesModule { abstract class PreferencesModule {
@ContributesAndroidInjector abstract fun cryptoUtilInjector(): CryptoUtil @ContributesAndroidInjector abstract fun cryptoUtilInjector(): CryptoUtil
@ContributesAndroidInjector abstract fun importExportPrefsInjector(): ImportExportPrefs
@ContributesAndroidInjector abstract fun encryptedPrefsFormatInjector(): EncryptedPrefsFormat @ContributesAndroidInjector abstract fun encryptedPrefsFormatInjector(): EncryptedPrefsFormat
@ContributesAndroidInjector abstract fun classicPrefsFormatInjector(): ClassicPrefsFormat @ContributesAndroidInjector abstract fun classicPrefsFormatInjector(): ClassicPrefsFormat
@ContributesAndroidInjector abstract fun prefImportListProviderInjector(): PrefFileListProvider @ContributesAndroidInjector abstract fun prefImportListProviderInjector(): PrefFileListProvider

View file

@ -12,6 +12,7 @@ import info.nightscout.androidaps.receivers.*
@Suppress("unused") @Suppress("unused")
abstract class ReceiversModule { abstract class ReceiversModule {
@ContributesAndroidInjector abstract fun contributesAutoStartReceiver(): AutoStartReceiver
@ContributesAndroidInjector abstract fun contributesBTReceiver(): BTReceiver @ContributesAndroidInjector abstract fun contributesBTReceiver(): BTReceiver
@ContributesAndroidInjector abstract fun contributesChargingStateReceiver(): ChargingStateReceiver @ContributesAndroidInjector abstract fun contributesChargingStateReceiver(): ChargingStateReceiver
@ContributesAndroidInjector abstract fun contributesDataReceiver(): DataReceiver @ContributesAndroidInjector abstract fun contributesDataReceiver(): DataReceiver

View file

@ -9,14 +9,13 @@ import dagger.android.HasAndroidInjector
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.databinding.DialogCalibrationBinding
import info.nightscout.androidaps.interfaces.ProfileFunction import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus
import info.nightscout.androidaps.utils.HtmlHelper import info.nightscout.androidaps.utils.HtmlHelper
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
import info.nightscout.androidaps.utils.XdripCalibrations import info.nightscout.androidaps.utils.XdripCalibrations
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.dialog_calibration.*
import kotlinx.android.synthetic.main.okcancel.*
import java.text.DecimalFormat import java.text.DecimalFormat
import java.util.* import java.util.*
import javax.inject.Inject import javax.inject.Inject
@ -28,15 +27,22 @@ class CalibrationDialog : DialogFragmentWithDate() {
@Inject lateinit var profileFunction: ProfileFunction @Inject lateinit var profileFunction: ProfileFunction
@Inject lateinit var xdripCalibrations: XdripCalibrations @Inject lateinit var xdripCalibrations: XdripCalibrations
private var _binding: DialogCalibrationBinding? = null
// This property is only valid between onCreateView and
// onDestroyView.
private val binding get() = _binding!!
override fun onSaveInstanceState(savedInstanceState: Bundle) { override fun onSaveInstanceState(savedInstanceState: Bundle) {
super.onSaveInstanceState(savedInstanceState) super.onSaveInstanceState(savedInstanceState)
savedInstanceState.putDouble("overview_calibration_bg", overview_calibration_bg.value) savedInstanceState.putDouble("bg", binding.bg.value)
} }
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? { savedInstanceState: Bundle?): View {
onCreateViewGeneral() onCreateViewGeneral()
return inflater.inflate(R.layout.dialog_calibration, container, false) _binding = DialogCalibrationBinding.inflate(inflater, container, false)
return binding.root
} }
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
@ -46,23 +52,29 @@ class CalibrationDialog : DialogFragmentWithDate() {
val bg = Profile.fromMgdlToUnits(GlucoseStatus(injector).glucoseStatusData?.glucose val bg = Profile.fromMgdlToUnits(GlucoseStatus(injector).glucoseStatusData?.glucose
?: 0.0, units) ?: 0.0, units)
if (units == Constants.MMOL) if (units == Constants.MMOL)
overview_calibration_bg.setParams(savedInstanceState?.getDouble("overview_calibration_bg") binding.bg.setParams(savedInstanceState?.getDouble("bg")
?: bg, 2.0, 30.0, 0.1, DecimalFormat("0.0"), false, ok) ?: bg, 2.0, 30.0, 0.1, DecimalFormat("0.0"), false, binding.okcancel.ok)
else else
overview_calibration_bg.setParams(savedInstanceState?.getDouble("overview_calibration_bg") binding.bg.setParams(savedInstanceState?.getDouble("bg")
?: bg, 36.0, 500.0, 1.0, DecimalFormat("0"), false, ok) ?: bg, 36.0, 500.0, 1.0, DecimalFormat("0"), false, binding.okcancel.ok)
overview_calibration_units.text = if (units == Constants.MMOL) resourceHelper.gs(R.string.mmol) else resourceHelper.gs(R.string.mgdl) binding.units.text = if (units == Constants.MMOL) resourceHelper.gs(R.string.mmol) else resourceHelper.gs(R.string.mgdl)
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
} }
override fun submit(): Boolean { override fun submit(): Boolean {
if (_binding == null) return false
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 ?: return false val bg = binding.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 ->
OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.overview_calibration), HtmlHelper.fromHtml(Joiner.on("<br/>").join(actions)), Runnable { OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.overview_calibration), HtmlHelper.fromHtml(Joiner.on("<br/>").join(actions)), {
aapsLogger.debug("USER ENTRY: CALIBRATION $bg") aapsLogger.debug("USER ENTRY: CALIBRATION $bg")
xdripCalibrations.sendIntent(bg) xdripCalibrations.sendIntent(bg)
}) })

View file

@ -11,6 +11,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.DialogCarbsBinding
import info.nightscout.androidaps.db.CareportalEvent import info.nightscout.androidaps.db.CareportalEvent
import info.nightscout.androidaps.db.Source import info.nightscout.androidaps.db.Source
import info.nightscout.androidaps.db.TempTarget import info.nightscout.androidaps.db.TempTarget
@ -29,15 +30,13 @@ import info.nightscout.androidaps.utils.ToastUtils
import info.nightscout.androidaps.utils.alertDialogs.OKDialog 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_carbs.*
import kotlinx.android.synthetic.main.notes.*
import kotlinx.android.synthetic.main.okcancel.*
import java.text.DecimalFormat import java.text.DecimalFormat
import java.util.* import java.util.*
import javax.inject.Inject import javax.inject.Inject
import kotlin.math.max import kotlin.math.max
class CarbsDialog : DialogFragmentWithDate() { class CarbsDialog : DialogFragmentWithDate() {
@Inject lateinit var mainApp: MainApp @Inject lateinit var mainApp: MainApp
@Inject lateinit var resourceHelper: ResourceHelper @Inject lateinit var resourceHelper: ResourceHelper
@Inject lateinit var constraintChecker: ConstraintChecker @Inject lateinit var constraintChecker: ConstraintChecker
@ -49,6 +48,7 @@ class CarbsDialog : DialogFragmentWithDate() {
@Inject lateinit var carbsGenerator: CarbsGenerator @Inject lateinit var carbsGenerator: CarbsGenerator
companion object { companion object {
private const val FAV1_DEFAULT = 5 private const val FAV1_DEFAULT = 5
private const val FAV2_DEFAULT = 10 private const val FAV2_DEFAULT = 10
private const val FAV3_DEFAULT = 20 private const val FAV3_DEFAULT = 20
@ -65,92 +65,105 @@ class CarbsDialog : DialogFragmentWithDate() {
private fun validateInputs() { private fun validateInputs() {
val maxCarbs = constraintChecker.getMaxCarbsAllowed().value().toDouble() val maxCarbs = constraintChecker.getMaxCarbsAllowed().value().toDouble()
val time = overview_carbs_time.value.toInt() val time = binding.time.value.toInt()
if (time > 12 * 60 || time < -12 * 60) { if (time > 12 * 60 || time < -12 * 60) {
overview_carbs_time.value = 0.0 binding.time.value = 0.0
ToastUtils.showToastInUiThread(mainApp, resourceHelper.gs(R.string.constraintapllied)) ToastUtils.showToastInUiThread(mainApp, resourceHelper.gs(R.string.constraintapllied))
} }
if (overview_carbs_duration.value > 10) { if (binding.duration.value > 10) {
overview_carbs_duration.value = 0.0 binding.duration.value = 0.0
ToastUtils.showToastInUiThread(mainApp, resourceHelper.gs(R.string.constraintapllied)) ToastUtils.showToastInUiThread(mainApp, resourceHelper.gs(R.string.constraintapllied))
} }
if (overview_carbs_carbs.value.toInt() > maxCarbs) { if (binding.carbs.value.toInt() > maxCarbs) {
overview_carbs_carbs.value = 0.0 binding.carbs.value = 0.0
ToastUtils.showToastInUiThread(mainApp, resourceHelper.gs(R.string.carbsconstraintapplied)) ToastUtils.showToastInUiThread(mainApp, resourceHelper.gs(R.string.carbsconstraintapplied))
} }
} }
private var _binding: DialogCarbsBinding? = null
// This property is only valid between onCreateView and
// onDestroyView.
private val binding get() = _binding!!
override fun onSaveInstanceState(savedInstanceState: Bundle) { override fun onSaveInstanceState(savedInstanceState: Bundle) {
super.onSaveInstanceState(savedInstanceState) super.onSaveInstanceState(savedInstanceState)
savedInstanceState.putDouble("overview_carbs_time", overview_carbs_time.value) savedInstanceState.putDouble("time", binding.time.value)
savedInstanceState.putDouble("overview_carbs_duration", overview_carbs_duration.value) savedInstanceState.putDouble("duration", binding.duration.value)
savedInstanceState.putDouble("overview_carbs_carbs", overview_carbs_carbs.value) savedInstanceState.putDouble("carbs", binding.carbs.value)
} }
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? { savedInstanceState: Bundle?): View {
onCreateViewGeneral() onCreateViewGeneral()
return inflater.inflate(R.layout.dialog_carbs, container, false) _binding = DialogCarbsBinding.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)
val maxCarbs = constraintChecker.getMaxCarbsAllowed().value().toDouble() val maxCarbs = constraintChecker.getMaxCarbsAllowed().value().toDouble()
overview_carbs_time.setParams(savedInstanceState?.getDouble("overview_carbs_time") binding.time.setParams(savedInstanceState?.getDouble("time")
?: 0.0, -12 * 60.0, 12 * 60.0, 5.0, DecimalFormat("0"), false, ok, textWatcher) ?: 0.0, -12 * 60.0, 12 * 60.0, 5.0, DecimalFormat("0"), false, binding.okcancel.ok, textWatcher)
overview_carbs_duration.setParams(savedInstanceState?.getDouble("overview_carbs_duration") binding.duration.setParams(savedInstanceState?.getDouble("duration")
?: 0.0, 0.0, 10.0, 1.0, DecimalFormat("0"), false, ok, textWatcher) ?: 0.0, 0.0, 10.0, 1.0, DecimalFormat("0"), false, binding.okcancel.ok, textWatcher)
overview_carbs_carbs.setParams(savedInstanceState?.getDouble("overview_carbs_carbs") binding.carbs.setParams(savedInstanceState?.getDouble("carbs")
?: 0.0, 0.0, maxCarbs, 1.0, DecimalFormat("0"), false, ok, textWatcher) ?: 0.0, 0.0, maxCarbs, 1.0, DecimalFormat("0"), false, binding.okcancel.ok, textWatcher)
overview_carbs_plus1.text = toSignedString(sp.getInt(R.string.key_carbs_button_increment_1, FAV1_DEFAULT)) binding.plus1.text = toSignedString(sp.getInt(R.string.key_carbs_button_increment_1, FAV1_DEFAULT))
overview_carbs_plus1.setOnClickListener { binding.plus1.setOnClickListener {
overview_carbs_carbs.value = max(0.0, overview_carbs_carbs.value binding.carbs.value = max(0.0, binding.carbs.value
+ sp.getInt(R.string.key_carbs_button_increment_1, FAV1_DEFAULT)) + sp.getInt(R.string.key_carbs_button_increment_1, FAV1_DEFAULT))
validateInputs() validateInputs()
} }
overview_carbs_plus2.text = toSignedString(sp.getInt(R.string.key_carbs_button_increment_2, FAV2_DEFAULT)) binding.plus2.text = toSignedString(sp.getInt(R.string.key_carbs_button_increment_2, FAV2_DEFAULT))
overview_carbs_plus2.setOnClickListener { binding.plus2.setOnClickListener {
overview_carbs_carbs.value = max(0.0, overview_carbs_carbs.value binding.carbs.value = max(0.0, binding.carbs.value
+ sp.getInt(R.string.key_carbs_button_increment_2, FAV2_DEFAULT)) + sp.getInt(R.string.key_carbs_button_increment_2, FAV2_DEFAULT))
validateInputs() validateInputs()
} }
overview_carbs_plus3.text = toSignedString(sp.getInt(R.string.key_carbs_button_increment_3, FAV3_DEFAULT)) binding.plus3.text = toSignedString(sp.getInt(R.string.key_carbs_button_increment_3, FAV3_DEFAULT))
overview_carbs_plus3.setOnClickListener { binding.plus3.setOnClickListener {
overview_carbs_carbs.value = max(0.0, overview_carbs_carbs.value binding.carbs.value = max(0.0, binding.carbs.value
+ sp.getInt(R.string.key_carbs_button_increment_3, FAV3_DEFAULT)) + sp.getInt(R.string.key_carbs_button_increment_3, FAV3_DEFAULT))
validateInputs() validateInputs()
} }
iobCobCalculatorPlugin.actualBg()?.let { bgReading -> iobCobCalculatorPlugin.actualBg()?.let { bgReading ->
if (bgReading.value < 72) if (bgReading.value < 72)
overview_carbs_hypo_tt.isChecked = true binding.hypoTt.isChecked = true
} }
overview_carbs_hypo_tt.setOnClickListener { binding.hypoTt.setOnClickListener {
overview_carbs_activity_tt.isChecked = false binding.activityTt.isChecked = false
overview_carbs_eating_soon_tt.isChecked = false binding.eatingSoonTt.isChecked = false
} }
overview_carbs_activity_tt.setOnClickListener { binding.activityTt.setOnClickListener {
overview_carbs_hypo_tt.isChecked = false binding.hypoTt.isChecked = false
overview_carbs_eating_soon_tt.isChecked = false binding.eatingSoonTt.isChecked = false
} }
overview_carbs_eating_soon_tt.setOnClickListener { binding.eatingSoonTt.setOnClickListener {
overview_carbs_hypo_tt.isChecked = false binding.hypoTt.isChecked = false
overview_carbs_activity_tt.isChecked = false binding.activityTt.isChecked = false
} }
} }
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
private fun toSignedString(value: Int): String { private fun toSignedString(value: Int): String {
return if (value > 0) "+$value" else value.toString() return if (value > 0) "+$value" else value.toString()
} }
override fun submit(): Boolean { override fun submit(): Boolean {
val carbs = overview_carbs_carbs?.value?.toInt() ?: return false if (_binding == null) return false
val carbs = binding.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()
@ -162,22 +175,22 @@ class CarbsDialog : DialogFragmentWithDate() {
val actions: LinkedList<String?> = LinkedList() val actions: LinkedList<String?> = LinkedList()
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 activitySelected = overview_carbs_activity_tt.isChecked val activitySelected = binding.activityTt.isChecked
if (activitySelected) if (activitySelected)
actions.add(resourceHelper.gs(R.string.temptargetshort) + ": " + (DecimalFormatter.to1Decimal(activityTT) + " " + unitLabel + " (" + resourceHelper.gs(R.string.format_mins, activityTTDuration) + ")").formatColor(resourceHelper, R.color.tempTargetConfirmation)) actions.add(resourceHelper.gs(R.string.temptargetshort) + ": " + (DecimalFormatter.to1Decimal(activityTT) + " " + unitLabel + " (" + resourceHelper.gs(R.string.format_mins, activityTTDuration) + ")").formatColor(resourceHelper, R.color.tempTargetConfirmation))
val eatingSoonSelected = overview_carbs_eating_soon_tt.isChecked val eatingSoonSelected = binding.eatingSoonTt.isChecked
if (eatingSoonSelected) if (eatingSoonSelected)
actions.add(resourceHelper.gs(R.string.temptargetshort) + ": " + (DecimalFormatter.to1Decimal(eatingSoonTT) + " " + unitLabel + " (" + resourceHelper.gs(R.string.format_mins, eatingSoonTTDuration) + ")").formatColor(resourceHelper, R.color.tempTargetConfirmation)) actions.add(resourceHelper.gs(R.string.temptargetshort) + ": " + (DecimalFormatter.to1Decimal(eatingSoonTT) + " " + unitLabel + " (" + resourceHelper.gs(R.string.format_mins, eatingSoonTTDuration) + ")").formatColor(resourceHelper, R.color.tempTargetConfirmation))
val hypoSelected = overview_carbs_hypo_tt.isChecked val hypoSelected = binding.hypoTt.isChecked
if (hypoSelected) if (hypoSelected)
actions.add(resourceHelper.gs(R.string.temptargetshort) + ": " + (DecimalFormatter.to1Decimal(hypoTT) + " " + unitLabel + " (" + resourceHelper.gs(R.string.format_mins, hypoTTDuration) + ")").formatColor(resourceHelper, R.color.tempTargetConfirmation)) actions.add(resourceHelper.gs(R.string.temptargetshort) + ": " + (DecimalFormatter.to1Decimal(hypoTT) + " " + unitLabel + " (" + resourceHelper.gs(R.string.format_mins, hypoTTDuration) + ")").formatColor(resourceHelper, R.color.tempTargetConfirmation))
val timeOffset = overview_carbs_time.value.toInt() val timeOffset = binding.time.value.toInt()
eventTime -= eventTime % 1000 eventTime -= eventTime % 1000
val time = eventTime + timeOffset * 1000 * 60 val time = eventTime + timeOffset * 1000 * 60
if (timeOffset != 0) if (timeOffset != 0)
actions.add(resourceHelper.gs(R.string.time) + ": " + dateUtil.dateAndTimeString(time)) actions.add(resourceHelper.gs(R.string.time) + ": " + dateUtil.dateAndTimeString(time))
val duration = overview_carbs_duration.value.toInt() val duration = binding.duration.value.toInt()
if (duration > 0) if (duration > 0)
actions.add(resourceHelper.gs(R.string.duration) + ": " + duration + resourceHelper.gs(R.string.shorthour)) actions.add(resourceHelper.gs(R.string.duration) + ": " + duration + resourceHelper.gs(R.string.shorthour))
if (carbsAfterConstraints > 0) { if (carbsAfterConstraints > 0) {
@ -185,7 +198,7 @@ class CarbsDialog : DialogFragmentWithDate() {
if (carbsAfterConstraints != carbs) if (carbsAfterConstraints != carbs)
actions.add("<font color='" + resourceHelper.gc(R.color.warning) + "'>" + resourceHelper.gs(R.string.carbsconstraintapplied) + "</font>") actions.add("<font color='" + resourceHelper.gc(R.color.warning) + "'>" + resourceHelper.gs(R.string.carbsconstraintapplied) + "</font>")
} }
val notes = notes.text.toString() val notes = binding.notesLayout.notes.text.toString()
if (notes.isNotEmpty()) if (notes.isNotEmpty())
actions.add(resourceHelper.gs(R.string.careportal_newnstreatment_notes_label) + ": " + notes) actions.add(resourceHelper.gs(R.string.careportal_newnstreatment_notes_label) + ": " + notes)
@ -194,7 +207,7 @@ class CarbsDialog : DialogFragmentWithDate() {
if (carbsAfterConstraints > 0 || activitySelected || eatingSoonSelected || hypoSelected) { if (carbsAfterConstraints > 0 || activitySelected || eatingSoonSelected || hypoSelected) {
activity?.let { activity -> activity?.let { activity ->
OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.carbs), HtmlHelper.fromHtml(Joiner.on("<br/>").join(actions)), Runnable { OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.carbs), HtmlHelper.fromHtml(Joiner.on("<br/>").join(actions)), {
when { when {
activitySelected -> { activitySelected -> {
aapsLogger.debug("USER ENTRY: TEMPTARGET ACTIVITY $activityTT duration: $activityTTDuration") aapsLogger.debug("USER ENTRY: TEMPTARGET ACTIVITY $activityTT duration: $activityTTDuration")

View file

@ -13,6 +13,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.DialogCareBinding
import info.nightscout.androidaps.db.CareportalEvent import info.nightscout.androidaps.db.CareportalEvent
import info.nightscout.androidaps.db.Source import info.nightscout.androidaps.db.Source
import info.nightscout.androidaps.interfaces.ProfileFunction import info.nightscout.androidaps.interfaces.ProfileFunction
@ -23,15 +24,13 @@ import info.nightscout.androidaps.utils.HtmlHelper
import info.nightscout.androidaps.utils.Translator import info.nightscout.androidaps.utils.Translator
import info.nightscout.androidaps.utils.alertDialogs.OKDialog 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.dialog_care.*
import kotlinx.android.synthetic.main.notes.*
import kotlinx.android.synthetic.main.okcancel.*
import org.json.JSONObject import org.json.JSONObject
import java.text.DecimalFormat import java.text.DecimalFormat
import java.util.* import java.util.*
import javax.inject.Inject import javax.inject.Inject
class CareDialog : DialogFragmentWithDate() { class CareDialog : DialogFragmentWithDate() {
@Inject lateinit var injector: HasAndroidInjector @Inject lateinit var injector: HasAndroidInjector
@Inject lateinit var mainApp: MainApp @Inject lateinit var mainApp: MainApp
@Inject lateinit var resourceHelper: ResourceHelper @Inject lateinit var resourceHelper: ResourceHelper
@ -60,18 +59,25 @@ class CareDialog : DialogFragmentWithDate() {
return this return this
} }
private var _binding: DialogCareBinding? = null
// This property is only valid between onCreateView and
// onDestroyView.
private val binding get() = _binding!!
override fun onSaveInstanceState(savedInstanceState: Bundle) { override fun onSaveInstanceState(savedInstanceState: Bundle) {
super.onSaveInstanceState(savedInstanceState) super.onSaveInstanceState(savedInstanceState)
savedInstanceState.putDouble("actions_care_bg", actions_care_bg.value) savedInstanceState.putDouble("bg", binding.bg.value)
savedInstanceState.putDouble("actions_care_duration", actions_care_duration.value) savedInstanceState.putDouble("duration", binding.duration.value)
savedInstanceState.putInt("event", event) savedInstanceState.putInt("event", event)
savedInstanceState.putInt("options", options.ordinal) savedInstanceState.putInt("options", options.ordinal)
} }
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? { savedInstanceState: Bundle?): View {
onCreateViewGeneral() onCreateViewGeneral()
return inflater.inflate(R.layout.dialog_care, container, false) _binding = DialogCareBinding.inflate(inflater, container, false)
return binding.root
} }
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
@ -82,7 +88,7 @@ class CareDialog : DialogFragmentWithDate() {
options = EventType.values()[savedInstanceState.getInt("options", 0)] options = EventType.values()[savedInstanceState.getInt("options", 0)]
} }
actions_care_icon.setImageResource(when (options) { binding.icon.setImageResource(when (options) {
EventType.BGCHECK -> R.drawable.ic_cp_bgcheck EventType.BGCHECK -> R.drawable.ic_cp_bgcheck
EventType.SENSOR_INSERT -> R.drawable.ic_cp_cgm_insert EventType.SENSOR_INSERT -> R.drawable.ic_cp_cgm_insert
EventType.BATTERY_CHANGE -> R.drawable.ic_cp_pump_battery EventType.BATTERY_CHANGE -> R.drawable.ic_cp_pump_battery
@ -91,7 +97,7 @@ class CareDialog : DialogFragmentWithDate() {
EventType.QUESTION -> R.drawable.ic_cp_question EventType.QUESTION -> R.drawable.ic_cp_question
EventType.ANNOUNCEMENT -> R.drawable.ic_cp_announcement EventType.ANNOUNCEMENT -> R.drawable.ic_cp_announcement
}) })
actions_care_title.text = resourceHelper.gs(when (options) { binding.title.text = resourceHelper.gs(when (options) {
EventType.BGCHECK -> R.string.careportal_bgcheck EventType.BGCHECK -> R.string.careportal_bgcheck
EventType.SENSOR_INSERT -> R.string.careportal_cgmsensorinsert EventType.SENSOR_INSERT -> R.string.careportal_cgmsensorinsert
EventType.BATTERY_CHANGE -> R.string.careportal_pumpbatterychange EventType.BATTERY_CHANGE -> R.string.careportal_pumpbatterychange
@ -105,20 +111,20 @@ class CareDialog : DialogFragmentWithDate() {
EventType.QUESTION, EventType.QUESTION,
EventType.ANNOUNCEMENT, EventType.ANNOUNCEMENT,
EventType.BGCHECK -> { EventType.BGCHECK -> {
action_care_duration_layout.visibility = View.GONE binding.durationLayout.visibility = View.GONE
} }
EventType.SENSOR_INSERT, EventType.SENSOR_INSERT,
EventType.BATTERY_CHANGE -> { EventType.BATTERY_CHANGE -> {
action_care_bg_layout.visibility = View.GONE binding.bgLayout.visibility = View.GONE
actions_care_bgsource.visibility = View.GONE binding.bgsource.visibility = View.GONE
action_care_duration_layout.visibility = View.GONE binding.durationLayout.visibility = View.GONE
} }
EventType.NOTE, EventType.NOTE,
EventType.EXERCISE -> { EventType.EXERCISE -> {
action_care_bg_layout.visibility = View.GONE binding.bgLayout.visibility = View.GONE
actions_care_bgsource.visibility = View.GONE binding.bgsource.visibility = View.GONE
} }
} }
@ -128,23 +134,28 @@ class CareDialog : DialogFragmentWithDate() {
override fun afterTextChanged(s: Editable) {} override fun afterTextChanged(s: Editable) {}
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {} override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {}
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) { override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
if (actions_care_sensor.isChecked) actions_care_meter.isChecked = true if (binding.sensor.isChecked) binding.meter.isChecked = true
} }
} }
if (profileFunction.getUnits() == Constants.MMOL) { if (profileFunction.getUnits() == Constants.MMOL) {
actions_care_bgunits.text = resourceHelper.gs(R.string.mmol) binding.bgunits.text = resourceHelper.gs(R.string.mmol)
actions_care_bg.setParams(savedInstanceState?.getDouble("actions_care_bg") binding.bg.setParams(savedInstanceState?.getDouble("bg")
?: bg, 2.0, 30.0, 0.1, DecimalFormat("0.0"), false, ok, bgTextWatcher) ?: bg, 2.0, 30.0, 0.1, DecimalFormat("0.0"), false, binding.okcancel.ok, bgTextWatcher)
} else { } else {
actions_care_bgunits.text = resourceHelper.gs(R.string.mgdl) binding.bgunits.text = resourceHelper.gs(R.string.mgdl)
actions_care_bg.setParams(savedInstanceState?.getDouble("actions_care_bg") binding.bg.setParams(savedInstanceState?.getDouble("bg")
?: bg, 36.0, 500.0, 1.0, DecimalFormat("0"), false, ok, bgTextWatcher) ?: bg, 36.0, 500.0, 1.0, DecimalFormat("0"), false, binding.okcancel.ok, bgTextWatcher)
} }
actions_care_duration.setParams(savedInstanceState?.getDouble("actions_care_duration") binding.duration.setParams(savedInstanceState?.getDouble("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, binding.okcancel.ok)
if (options == EventType.NOTE || options == EventType.QUESTION || options == EventType.ANNOUNCEMENT) if (options == EventType.NOTE || options == EventType.QUESTION || options == EventType.ANNOUNCEMENT || options == EventType.EXERCISE)
notes_layout?.visibility = View.VISIBLE // independent to preferences binding.notesLayout.root.visibility = View.VISIBLE // independent to preferences
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
} }
override fun submit(): Boolean { override fun submit(): Boolean {
@ -156,20 +167,20 @@ class CareDialog : DialogFragmentWithDate() {
if (options == EventType.BGCHECK || options == EventType.QUESTION || options == EventType.ANNOUNCEMENT) { if (options == EventType.BGCHECK || options == EventType.QUESTION || options == EventType.ANNOUNCEMENT) {
val type = val type =
when { when {
actions_care_meter.isChecked -> CareportalEvent.FINGER binding.meter.isChecked -> CareportalEvent.FINGER
actions_care_sensor.isChecked -> CareportalEvent.SENSOR binding.sensor.isChecked -> CareportalEvent.SENSOR
else -> CareportalEvent.MANUAL else -> CareportalEvent.MANUAL
} }
actions.add(resourceHelper.gs(R.string.careportal_newnstreatment_glucosetype) + ": " + translator.translate(type)) actions.add(resourceHelper.gs(R.string.careportal_newnstreatment_glucosetype) + ": " + translator.translate(type))
actions.add(resourceHelper.gs(R.string.treatments_wizard_bg_label) + ": " + Profile.toCurrentUnitsString(profileFunction, actions_care_bg.value) + " " + resourceHelper.gs(unitResId)) actions.add(resourceHelper.gs(R.string.treatments_wizard_bg_label) + ": " + Profile.toCurrentUnitsString(profileFunction, binding.bg.value) + " " + resourceHelper.gs(unitResId))
json.put("glucose", actions_care_bg.value) json.put("glucose", binding.bg.value)
json.put("glucoseType", type) json.put("glucoseType", type)
} }
if (options == EventType.NOTE || options == EventType.EXERCISE) { if (options == EventType.NOTE || options == EventType.EXERCISE) {
actions.add(resourceHelper.gs(R.string.careportal_newnstreatment_duration_label) + ": " + resourceHelper.gs(R.string.format_mins, actions_care_duration.value.toInt())) actions.add(resourceHelper.gs(R.string.careportal_newnstreatment_duration_label) + ": " + resourceHelper.gs(R.string.format_mins, binding.duration.value.toInt()))
json.put("duration", actions_care_duration.value.toInt()) json.put("duration", binding.duration.value.toInt())
} }
val notes = notes.text.toString() val notes = binding.notesLayout.notes.text.toString()
if (notes.isNotEmpty()) { if (notes.isNotEmpty()) {
actions.add(resourceHelper.gs(R.string.careportal_newnstreatment_notes_label) + ": " + notes) actions.add(resourceHelper.gs(R.string.careportal_newnstreatment_notes_label) + ": " + notes)
json.put("notes", notes) json.put("notes", notes)
@ -195,7 +206,7 @@ class CareDialog : DialogFragmentWithDate() {
json.put("enteredBy", enteredBy) json.put("enteredBy", enteredBy)
activity?.let { activity -> activity?.let { activity ->
OKDialog.showConfirmation(activity, resourceHelper.gs(event), HtmlHelper.fromHtml(Joiner.on("<br/>").join(actions)), Runnable { OKDialog.showConfirmation(activity, resourceHelper.gs(event), HtmlHelper.fromHtml(Joiner.on("<br/>").join(actions)), {
val careportalEvent = CareportalEvent(injector) val careportalEvent = CareportalEvent(injector)
careportalEvent.date = eventTime careportalEvent.date = eventTime
careportalEvent.source = Source.USER careportalEvent.source = Source.USER

View file

@ -8,6 +8,8 @@ import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.view.Window import android.view.Window
import android.view.WindowManager import android.view.WindowManager
import android.widget.Button
import android.widget.TextView
import androidx.fragment.app.FragmentManager import androidx.fragment.app.FragmentManager
import dagger.android.support.DaggerDialogFragment import dagger.android.support.DaggerDialogFragment
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
@ -16,9 +18,6 @@ import info.nightscout.androidaps.logging.LTag
import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.extensions.toVisibility import info.nightscout.androidaps.utils.extensions.toVisibility
import info.nightscout.androidaps.utils.sharedPreferences.SP import info.nightscout.androidaps.utils.sharedPreferences.SP
import kotlinx.android.synthetic.main.datetime.*
import kotlinx.android.synthetic.main.notes.*
import kotlinx.android.synthetic.main.okcancel.*
import java.util.* import java.util.*
import javax.inject.Inject import javax.inject.Inject
@ -58,10 +57,14 @@ abstract class DialogFragmentWithDate : DaggerDialogFragment() {
} }
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
val eventDateView = view.findViewById(R.id.eventdate) as TextView?
val eventTimeView = view.findViewById(R.id.eventtime) as TextView?
eventTime = savedInstanceState?.getLong("eventTime") ?: DateUtil.now() eventTime = savedInstanceState?.getLong("eventTime") ?: DateUtil.now()
eventTimeChanged = savedInstanceState?.getBoolean("eventTimeChanged") ?: false eventTimeChanged = savedInstanceState?.getBoolean("eventTimeChanged") ?: false
overview_eventdate?.text = DateUtil.dateString(eventTime)
overview_eventtime?.text = dateUtil.timeString(eventTime) eventDateView?.text = DateUtil.dateString(eventTime)
eventTimeView?.text = dateUtil.timeString(eventTime)
// create an OnDateSetListener // create an OnDateSetListener
val dateSetListener = DatePickerDialog.OnDateSetListener { _, year, monthOfYear, dayOfMonth -> val dateSetListener = DatePickerDialog.OnDateSetListener { _, year, monthOfYear, dayOfMonth ->
@ -72,10 +75,10 @@ abstract class DialogFragmentWithDate : DaggerDialogFragment() {
cal.set(Calendar.DAY_OF_MONTH, dayOfMonth) cal.set(Calendar.DAY_OF_MONTH, dayOfMonth)
eventTime = cal.timeInMillis eventTime = cal.timeInMillis
eventTimeChanged = true eventTimeChanged = true
overview_eventdate?.text = DateUtil.dateString(eventTime) eventDateView?.text = DateUtil.dateString(eventTime)
} }
overview_eventdate?.setOnClickListener { eventDateView?.setOnClickListener {
context?.let { context?.let {
val cal = Calendar.getInstance() val cal = Calendar.getInstance()
cal.timeInMillis = eventTime cal.timeInMillis = eventTime
@ -96,10 +99,10 @@ abstract class DialogFragmentWithDate : DaggerDialogFragment() {
cal.set(Calendar.SECOND, seconds++) // randomize seconds to prevent creating record of the same time, if user choose time manually cal.set(Calendar.SECOND, seconds++) // randomize seconds to prevent creating record of the same time, if user choose time manually
eventTime = cal.timeInMillis eventTime = cal.timeInMillis
eventTimeChanged = true eventTimeChanged = true
overview_eventtime?.text = dateUtil.timeString(eventTime) eventTimeView?.text = dateUtil.timeString(eventTime)
} }
overview_eventtime?.setOnClickListener { eventTimeView?.setOnClickListener {
context?.let { context?.let {
val cal = Calendar.getInstance() val cal = Calendar.getInstance()
cal.timeInMillis = eventTime cal.timeInMillis = eventTime
@ -111,9 +114,9 @@ abstract class DialogFragmentWithDate : DaggerDialogFragment() {
} }
} }
notes_layout?.visibility = sp.getBoolean(R.string.key_show_notes_entry_dialogs, false).toVisibility() (view.findViewById(R.id.notes_layout) as View?)?.visibility = sp.getBoolean(R.string.key_show_notes_entry_dialogs, false).toVisibility()
ok.setOnClickListener { (view.findViewById(R.id.ok) as Button?)?.setOnClickListener {
synchronized(okClicked) { synchronized(okClicked) {
if (okClicked) { if (okClicked) {
aapsLogger.warn(LTag.UI, "guarding: ok already clicked") aapsLogger.warn(LTag.UI, "guarding: ok already clicked")
@ -124,7 +127,7 @@ abstract class DialogFragmentWithDate : DaggerDialogFragment() {
} }
} }
} }
cancel.setOnClickListener { dismiss() } (view.findViewById(R.id.cancel) as Button?)?.setOnClickListener { dismiss() }
} }
override fun show(manager: FragmentManager, tag: String?) { override fun show(manager: FragmentManager, tag: String?) {

View file

@ -1,48 +1,55 @@
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.databinding.DialogExtendedbolusBinding
import info.nightscout.androidaps.interfaces.ActivePluginProvider import info.nightscout.androidaps.interfaces.ActivePluginProvider
import info.nightscout.androidaps.interfaces.CommandQueueProvider import info.nightscout.androidaps.interfaces.CommandQueueProvider
import info.nightscout.androidaps.interfaces.Constraint 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.okcancel.*
import java.text.DecimalFormat import java.text.DecimalFormat
import java.util.* import java.util.*
import javax.inject.Inject 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
@Inject lateinit var activePlugin: ActivePluginProvider @Inject lateinit var activePlugin: ActivePluginProvider
private var _binding: DialogExtendedbolusBinding? = null
// This property is only valid between onCreateView and
// onDestroyView.
private val binding get() = _binding!!
override fun onSaveInstanceState(savedInstanceState: Bundle) { override fun onSaveInstanceState(savedInstanceState: Bundle) {
super.onSaveInstanceState(savedInstanceState) super.onSaveInstanceState(savedInstanceState)
savedInstanceState.putDouble("actions_extendedbolus_insulin", actions_extendedbolus_insulin.value) savedInstanceState.putDouble("insulin", binding.insulin.value)
savedInstanceState.putDouble("actions_extendedbolus_duration", actions_extendedbolus_duration.value) savedInstanceState.putDouble("duration", binding.duration.value)
} }
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? { savedInstanceState: Bundle?): View {
onCreateViewGeneral() onCreateViewGeneral()
return inflater.inflate(R.layout.dialog_extendedbolus, container, false) _binding = DialogExtendedbolusBinding.inflate(inflater, container, false)
return binding.root
} }
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
@ -52,18 +59,24 @@ class ExtendedBolusDialog : DialogFragmentWithDate() {
val maxInsulin = constraintChecker.getMaxExtendedBolusAllowed().value() val maxInsulin = constraintChecker.getMaxExtendedBolusAllowed().value()
val extendedStep = pumpDescription.extendedBolusStep val extendedStep = pumpDescription.extendedBolusStep
actions_extendedbolus_insulin.setParams(savedInstanceState?.getDouble("actions_extendedbolus_insulin") binding.insulin.setParams(savedInstanceState?.getDouble("insulin")
?: extendedStep, extendedStep, maxInsulin, extendedStep, DecimalFormat("0.00"), false, ok) ?: extendedStep, extendedStep, maxInsulin, extendedStep, DecimalFormat("0.00"), false, binding.okcancel.ok)
val extendedDurationStep = pumpDescription.extendedBolusDurationStep val extendedDurationStep = pumpDescription.extendedBolusDurationStep
val extendedMaxDuration = pumpDescription.extendedBolusMaxDuration val extendedMaxDuration = pumpDescription.extendedBolusMaxDuration
actions_extendedbolus_duration.setParams(savedInstanceState?.getDouble("actions_extendedbolus_duration") binding.duration.setParams(savedInstanceState?.getDouble("duration")
?: extendedDurationStep, extendedDurationStep, extendedMaxDuration, extendedDurationStep, DecimalFormat("0"), false, ok) ?: extendedDurationStep, extendedDurationStep, extendedMaxDuration, extendedDurationStep, DecimalFormat("0"), false, binding.okcancel.ok)
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
} }
override fun submit(): Boolean { override fun submit(): Boolean {
val insulin = SafeParse.stringToDouble(actions_extendedbolus_insulin?.text ?: return false) if (_binding == null) return false
val durationInMinutes = actions_extendedbolus_duration.value.toInt() val insulin = SafeParse.stringToDouble(binding.insulin.text ?: return false)
val durationInMinutes = binding.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()
actions.add(resourceHelper.gs(R.string.formatinsulinunits, insulinAfterConstraint)) actions.add(resourceHelper.gs(R.string.formatinsulinunits, insulinAfterConstraint))
@ -72,17 +85,17 @@ class ExtendedBolusDialog : DialogFragmentWithDate() {
actions.add(resourceHelper.gs(R.string.constraintapllied).formatColor(resourceHelper, R.color.warning)) actions.add(resourceHelper.gs(R.string.constraintapllied).formatColor(resourceHelper, R.color.warning))
activity?.let { activity -> activity?.let { activity ->
OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.extended_bolus), HtmlHelper.fromHtml(Joiner.on("<br/>").join(actions)), Runnable { OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.extended_bolus), HtmlHelper.fromHtml(Joiner.on("<br/>").join(actions)), {
aapsLogger.debug("USER ENTRY: EXTENDED BOLUS $insulinAfterConstraint duration: $durationInMinutes") aapsLogger.debug("USER ENTRY: EXTENDED BOLUS $insulinAfterConstraint duration: $durationInMinutes")
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

@ -10,6 +10,7 @@ import com.google.common.base.Joiner
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.activities.ErrorHelperActivity import info.nightscout.androidaps.activities.ErrorHelperActivity
import info.nightscout.androidaps.data.DetailedBolusInfo import info.nightscout.androidaps.data.DetailedBolusInfo
import info.nightscout.androidaps.databinding.DialogFillBinding
import info.nightscout.androidaps.db.CareportalEvent import info.nightscout.androidaps.db.CareportalEvent
import info.nightscout.androidaps.db.Source import info.nightscout.androidaps.db.Source
import info.nightscout.androidaps.interfaces.ActivePluginProvider import info.nightscout.androidaps.interfaces.ActivePluginProvider
@ -24,14 +25,12 @@ import info.nightscout.androidaps.utils.SafeParse
import info.nightscout.androidaps.utils.alertDialogs.OKDialog 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_fill.*
import kotlinx.android.synthetic.main.notes.*
import kotlinx.android.synthetic.main.okcancel.*
import java.util.* import java.util.*
import javax.inject.Inject import javax.inject.Inject
import kotlin.math.abs import kotlin.math.abs
class FillDialog : DialogFragmentWithDate() { class FillDialog : DialogFragmentWithDate() {
@Inject lateinit var constraintChecker: ConstraintChecker @Inject lateinit var constraintChecker: ConstraintChecker
@Inject lateinit var resourceHelper: ResourceHelper @Inject lateinit var resourceHelper: ResourceHelper
@Inject lateinit var ctx: Context @Inject lateinit var ctx: Context
@ -39,15 +38,22 @@ class FillDialog : DialogFragmentWithDate() {
@Inject lateinit var commandQueue: CommandQueueProvider @Inject lateinit var commandQueue: CommandQueueProvider
@Inject lateinit var activePlugin: ActivePluginProvider @Inject lateinit var activePlugin: ActivePluginProvider
private var _binding: DialogFillBinding? = null
// This property is only valid between onCreateView and
// onDestroyView.
private val binding get() = _binding!!
override fun onSaveInstanceState(savedInstanceState: Bundle) { override fun onSaveInstanceState(savedInstanceState: Bundle) {
super.onSaveInstanceState(savedInstanceState) super.onSaveInstanceState(savedInstanceState)
savedInstanceState.putDouble("fill_insulin_amount", fill_insulinamount.value) savedInstanceState.putDouble("fill_insulin_amount", binding.fillInsulinamount.value)
} }
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? { savedInstanceState: Bundle?): View {
onCreateViewGeneral() onCreateViewGeneral()
return inflater.inflate(R.layout.dialog_fill, container, false) _binding = DialogFillBinding.inflate(inflater, container, false)
return binding.root
} }
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
@ -55,37 +61,43 @@ class FillDialog : DialogFragmentWithDate() {
val maxInsulin = constraintChecker.getMaxBolusAllowed().value() val maxInsulin = constraintChecker.getMaxBolusAllowed().value()
val bolusStep = activePlugin.activePump.pumpDescription.bolusStep val bolusStep = activePlugin.activePump.pumpDescription.bolusStep
fill_insulinamount.setParams(savedInstanceState?.getDouble("fill_insulin_amount") binding.fillInsulinamount.setParams(savedInstanceState?.getDouble("fill_insulin_amount")
?: 0.0, 0.0, maxInsulin, bolusStep, DecimalFormatter.pumpSupportedBolusFormat(activePlugin.activePump), true, ok) ?: 0.0, 0.0, maxInsulin, bolusStep, DecimalFormatter.pumpSupportedBolusFormat(activePlugin.activePump), true, binding.okcancel.ok)
val amount1 = sp.getDouble("fill_button1", 0.3) val amount1 = sp.getDouble("fill_button1", 0.3)
if (amount1 > 0) { if (amount1 > 0) {
fill_preset_button1.visibility = View.VISIBLE binding.fillPresetButton1.visibility = View.VISIBLE
fill_preset_button1.text = DecimalFormatter.toPumpSupportedBolus(amount1, activePlugin.activePump) // + "U"); binding.fillPresetButton1.text = DecimalFormatter.toPumpSupportedBolus(amount1, activePlugin.activePump) // + "U");
fill_preset_button1.setOnClickListener { fill_insulinamount.value = amount1 } binding.fillPresetButton1.setOnClickListener { binding.fillInsulinamount.value = amount1 }
} else { } else {
fill_preset_button1.visibility = View.GONE binding.fillPresetButton1.visibility = View.GONE
} }
val amount2 = sp.getDouble("fill_button2", 0.0) val amount2 = sp.getDouble("fill_button2", 0.0)
if (amount2 > 0) { if (amount2 > 0) {
fill_preset_button2.visibility = View.VISIBLE binding.fillPresetButton2.visibility = View.VISIBLE
fill_preset_button2.text = DecimalFormatter.toPumpSupportedBolus(amount2, activePlugin.activePump) // + "U"); binding.fillPresetButton2.text = DecimalFormatter.toPumpSupportedBolus(amount2, activePlugin.activePump) // + "U");
fill_preset_button2.setOnClickListener { fill_insulinamount.value = amount2 } binding.fillPresetButton2.setOnClickListener { binding.fillInsulinamount.value = amount2 }
} else { } else {
fill_preset_button2.visibility = View.GONE binding.fillPresetButton2.visibility = View.GONE
} }
val amount3 = sp.getDouble("fill_button3", 0.0) val amount3 = sp.getDouble("fill_button3", 0.0)
if (amount3 > 0) { if (amount3 > 0) {
fill_preset_button3.visibility = View.VISIBLE binding.fillPresetButton3.visibility = View.VISIBLE
fill_preset_button3.text = DecimalFormatter.toPumpSupportedBolus(amount3, activePlugin.activePump) // + "U"); binding.fillPresetButton3.text = DecimalFormatter.toPumpSupportedBolus(amount3, activePlugin.activePump) // + "U");
fill_preset_button3.setOnClickListener { fill_insulinamount.value = amount3 } binding.fillPresetButton3.setOnClickListener { binding.fillInsulinamount.value = amount3 }
} else { } else {
fill_preset_button3.visibility = View.GONE binding.fillPresetButton3.visibility = View.GONE
} }
} }
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
override fun submit(): Boolean { override fun submit(): Boolean {
val insulin = SafeParse.stringToDouble(fill_insulinamount?.text ?: return false) if (_binding == null) return false
val insulin = SafeParse.stringToDouble(binding.fillInsulinamount.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()
@ -96,13 +108,13 @@ class FillDialog : DialogFragmentWithDate() {
if (abs(insulinAfterConstraints - insulin) > 0.01) if (abs(insulinAfterConstraints - insulin) > 0.01)
actions.add(resourceHelper.gs(R.string.bolusconstraintappliedwarn, insulin, insulinAfterConstraints).formatColor(resourceHelper, R.color.warning)) actions.add(resourceHelper.gs(R.string.bolusconstraintappliedwarn, insulin, insulinAfterConstraints).formatColor(resourceHelper, R.color.warning))
} }
val siteChange = fill_catheter_change.isChecked val siteChange = binding.fillCatheterChange.isChecked
if (siteChange) if (siteChange)
actions.add(resourceHelper.gs(R.string.record_pump_site_change).formatColor(resourceHelper, R.color.actionsConfirm)) actions.add(resourceHelper.gs(R.string.record_pump_site_change).formatColor(resourceHelper, R.color.actionsConfirm))
val insulinChange = fill_cartridge_change.isChecked val insulinChange = binding.fillCartridgeChange.isChecked
if (insulinChange) if (insulinChange)
actions.add(resourceHelper.gs(R.string.record_insulin_cartridge_change).formatColor(resourceHelper, R.color.actionsConfirm)) actions.add(resourceHelper.gs(R.string.record_insulin_cartridge_change).formatColor(resourceHelper, R.color.actionsConfirm))
val notes = notes.text.toString() val notes = binding.notesLayout.notes.text.toString()
if (notes.isNotEmpty()) if (notes.isNotEmpty())
actions.add(resourceHelper.gs(R.string.careportal_newnstreatment_notes_label) + ": " + notes) actions.add(resourceHelper.gs(R.string.careportal_newnstreatment_notes_label) + ": " + notes)
eventTime -= eventTime % 1000 eventTime -= eventTime % 1000
@ -110,9 +122,9 @@ class FillDialog : DialogFragmentWithDate() {
if (eventTimeChanged) if (eventTimeChanged)
actions.add(resourceHelper.gs(R.string.time) + ": " + dateUtil.dateAndTimeString(eventTime)) actions.add(resourceHelper.gs(R.string.time) + ": " + dateUtil.dateAndTimeString(eventTime))
if (insulinAfterConstraints > 0 || fill_catheter_change.isChecked || fill_cartridge_change.isChecked) { if (insulinAfterConstraints > 0 || binding.fillCatheterChange.isChecked || binding.fillCartridgeChange.isChecked) {
activity?.let { activity -> activity?.let { activity ->
OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.primefill), HtmlHelper.fromHtml(Joiner.on("<br/>").join(actions)), Runnable { OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.primefill), HtmlHelper.fromHtml(Joiner.on("<br/>").join(actions)), {
if (insulinAfterConstraints > 0) { if (insulinAfterConstraints > 0) {
aapsLogger.debug("USER ENTRY: PRIME BOLUS $insulinAfterConstraints") aapsLogger.debug("USER ENTRY: PRIME BOLUS $insulinAfterConstraints")
requestPrimeBolus(insulinAfterConstraints, notes) requestPrimeBolus(insulinAfterConstraints, notes)

View file

@ -15,14 +15,15 @@ import info.nightscout.androidaps.R
import info.nightscout.androidaps.activities.ErrorHelperActivity import info.nightscout.androidaps.activities.ErrorHelperActivity
import info.nightscout.androidaps.data.DetailedBolusInfo import info.nightscout.androidaps.data.DetailedBolusInfo
import info.nightscout.androidaps.data.Profile import info.nightscout.androidaps.data.Profile
import info.nightscout.androidaps.databinding.DialogInsulinBinding
import info.nightscout.androidaps.db.CareportalEvent import info.nightscout.androidaps.db.CareportalEvent
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.interfaces.ActivePluginProvider
import info.nightscout.androidaps.interfaces.CommandQueueProvider import info.nightscout.androidaps.interfaces.CommandQueueProvider
import info.nightscout.androidaps.interfaces.Constraint import info.nightscout.androidaps.interfaces.Constraint
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
import info.nightscout.androidaps.interfaces.ProfileFunction import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
import info.nightscout.androidaps.queue.Callback import info.nightscout.androidaps.queue.Callback
import info.nightscout.androidaps.utils.* import info.nightscout.androidaps.utils.*
import info.nightscout.androidaps.utils.alertDialogs.OKDialog import info.nightscout.androidaps.utils.alertDialogs.OKDialog
@ -30,9 +31,6 @@ import info.nightscout.androidaps.utils.extensions.formatColor
import info.nightscout.androidaps.utils.extensions.toSignedString import info.nightscout.androidaps.utils.extensions.toSignedString
import info.nightscout.androidaps.utils.extensions.toVisibility import info.nightscout.androidaps.utils.extensions.toVisibility
import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.resources.ResourceHelper
import kotlinx.android.synthetic.main.dialog_insulin.*
import kotlinx.android.synthetic.main.notes.*
import kotlinx.android.synthetic.main.okcancel.*
import java.text.DecimalFormat import java.text.DecimalFormat
import java.util.* import java.util.*
import javax.inject.Inject import javax.inject.Inject
@ -40,6 +38,7 @@ import kotlin.math.abs
import kotlin.math.max import kotlin.math.max
class InsulinDialog : DialogFragmentWithDate() { class InsulinDialog : DialogFragmentWithDate() {
@Inject lateinit var constraintChecker: ConstraintChecker @Inject lateinit var constraintChecker: ConstraintChecker
@Inject lateinit var resourceHelper: ResourceHelper @Inject lateinit var resourceHelper: ResourceHelper
@Inject lateinit var defaultValueHelper: DefaultValueHelper @Inject lateinit var defaultValueHelper: DefaultValueHelper
@ -50,6 +49,7 @@ class InsulinDialog : DialogFragmentWithDate() {
@Inject lateinit var config: Config @Inject lateinit var config: Config
companion object { companion object {
private const val PLUS1_DEFAULT = 0.5 private const val PLUS1_DEFAULT = 0.5
private const val PLUS2_DEFAULT = 1.0 private const val PLUS2_DEFAULT = 1.0
private const val PLUS3_DEFAULT = 2.0 private const val PLUS3_DEFAULT = 2.0
@ -64,78 +64,91 @@ class InsulinDialog : DialogFragmentWithDate() {
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {} override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {}
} }
private var _binding: DialogInsulinBinding? = null
// This property is only valid between onCreateView and
// onDestroyView.
private val binding get() = _binding!!
private fun validateInputs() { private fun validateInputs() {
val maxInsulin = constraintChecker.getMaxBolusAllowed().value() val maxInsulin = constraintChecker.getMaxBolusAllowed().value()
if (abs(overview_insulin_time.value.toInt()) > 12 * 60) { if (abs(binding.time.value.toInt()) > 12 * 60) {
overview_insulin_time.value = 0.0 binding.time.value = 0.0
ToastUtils.showToastInUiThread(context, resourceHelper.gs(R.string.constraintapllied)) ToastUtils.showToastInUiThread(context, resourceHelper.gs(R.string.constraintapllied))
} }
if (overview_insulin_amount.value > maxInsulin) { if (binding.amount.value > maxInsulin) {
overview_insulin_amount.value = 0.0 binding.amount.value = 0.0
ToastUtils.showToastInUiThread(context, resourceHelper.gs(R.string.bolusconstraintapplied)) ToastUtils.showToastInUiThread(context, resourceHelper.gs(R.string.bolusconstraintapplied))
} }
} }
override fun onSaveInstanceState(savedInstanceState: Bundle) { override fun onSaveInstanceState(savedInstanceState: Bundle) {
super.onSaveInstanceState(savedInstanceState) super.onSaveInstanceState(savedInstanceState)
savedInstanceState.putDouble("overview_insulin_time", overview_insulin_time.value) savedInstanceState.putDouble("time", binding.time.value)
savedInstanceState.putDouble("overview_insulin_amount", overview_insulin_amount.value) savedInstanceState.putDouble("amount", binding.amount.value)
} }
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? { savedInstanceState: Bundle?): View {
onCreateViewGeneral() onCreateViewGeneral()
return inflater.inflate(R.layout.dialog_insulin, container, false) _binding = DialogInsulinBinding.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)
if (config.NSCLIENT) { if (config.NSCLIENT) {
overview_insulin_record_only.isChecked = true binding.recordOnly.isChecked = true
overview_insulin_record_only.isEnabled = false binding.recordOnly.isEnabled = false
} }
val maxInsulin = constraintChecker.getMaxBolusAllowed().value() val maxInsulin = constraintChecker.getMaxBolusAllowed().value()
overview_insulin_time.setParams(savedInstanceState?.getDouble("overview_insulin_time") binding.time.setParams(savedInstanceState?.getDouble("time")
?: 0.0, -12 * 60.0, 12 * 60.0, 5.0, DecimalFormat("0"), false, ok, textWatcher) ?: 0.0, -12 * 60.0, 12 * 60.0, 5.0, DecimalFormat("0"), false, binding.okcancel.ok, textWatcher)
overview_insulin_amount.setParams(savedInstanceState?.getDouble("overview_insulin_amount") binding.amount.setParams(savedInstanceState?.getDouble("amount")
?: 0.0, 0.0, maxInsulin, activePlugin.activePump.pumpDescription.bolusStep, DecimalFormatter.pumpSupportedBolusFormat(activePlugin.activePump), false, ok, textWatcher) ?: 0.0, 0.0, maxInsulin, activePlugin.activePump.pumpDescription.bolusStep, DecimalFormatter.pumpSupportedBolusFormat(activePlugin.activePump), false, binding.okcancel.ok, textWatcher)
overview_insulin_plus05.text = sp.getDouble(resourceHelper.gs(R.string.key_insulin_button_increment_1), PLUS1_DEFAULT).toSignedString(activePlugin.activePump) binding.plus05.text = sp.getDouble(resourceHelper.gs(R.string.key_insulin_button_increment_1), PLUS1_DEFAULT).toSignedString(activePlugin.activePump)
overview_insulin_plus05.setOnClickListener { binding.plus05.setOnClickListener {
overview_insulin_amount.value = max(0.0, overview_insulin_amount.value binding.amount.value = max(0.0, binding.amount.value
+ sp.getDouble(resourceHelper.gs(R.string.key_insulin_button_increment_1), PLUS1_DEFAULT)) + sp.getDouble(resourceHelper.gs(R.string.key_insulin_button_increment_1), PLUS1_DEFAULT))
validateInputs() validateInputs()
} }
overview_insulin_plus10.text = sp.getDouble(resourceHelper.gs(R.string.key_insulin_button_increment_2), PLUS2_DEFAULT).toSignedString(activePlugin.activePump) binding.plus10.text = sp.getDouble(resourceHelper.gs(R.string.key_insulin_button_increment_2), PLUS2_DEFAULT).toSignedString(activePlugin.activePump)
overview_insulin_plus10.setOnClickListener { binding.plus10.setOnClickListener {
overview_insulin_amount.value = max(0.0, overview_insulin_amount.value binding.amount.value = max(0.0, binding.amount.value
+ sp.getDouble(resourceHelper.gs(R.string.key_insulin_button_increment_2), PLUS2_DEFAULT)) + sp.getDouble(resourceHelper.gs(R.string.key_insulin_button_increment_2), PLUS2_DEFAULT))
validateInputs() validateInputs()
} }
overview_insulin_plus20.text = sp.getDouble(resourceHelper.gs(R.string.key_insulin_button_increment_3), PLUS3_DEFAULT).toSignedString(activePlugin.activePump) binding.plus20.text = sp.getDouble(resourceHelper.gs(R.string.key_insulin_button_increment_3), PLUS3_DEFAULT).toSignedString(activePlugin.activePump)
overview_insulin_plus20.setOnClickListener { binding.plus20.setOnClickListener {
overview_insulin_amount.value = max(0.0, overview_insulin_amount.value binding.amount.value = max(0.0, binding.amount.value
+ sp.getDouble(resourceHelper.gs(R.string.key_insulin_button_increment_3), PLUS3_DEFAULT)) + sp.getDouble(resourceHelper.gs(R.string.key_insulin_button_increment_3), PLUS3_DEFAULT))
validateInputs() validateInputs()
} }
overview_insulin_time_layout.visibility = View.GONE binding.timeLayout.visibility = View.GONE
overview_insulin_record_only.setOnCheckedChangeListener { _, isChecked: Boolean -> binding.recordOnly.setOnCheckedChangeListener { _, isChecked: Boolean ->
overview_insulin_time_layout.visibility = isChecked.toVisibility() binding.timeLayout.visibility = isChecked.toVisibility()
} }
} }
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
override fun submit(): Boolean { override fun submit(): Boolean {
if (_binding == null) return false
val pumpDescription = activePlugin.activePump.pumpDescription val pumpDescription = activePlugin.activePump.pumpDescription
val insulin = SafeParse.stringToDouble(overview_insulin_amount?.text ?: return false) val insulin = SafeParse.stringToDouble(binding.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()
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 recordOnlyChecked = overview_insulin_record_only.isChecked val recordOnlyChecked = binding.recordOnly.isChecked
val eatingSoonChecked = overview_insulin_start_eating_soon_tt.isChecked val eatingSoonChecked = binding.startEatingSoonTt.isChecked
if (insulinAfterConstraints > 0) { if (insulinAfterConstraints > 0) {
actions.add(resourceHelper.gs(R.string.bolus) + ": " + DecimalFormatter.toPumpSupportedBolus(insulinAfterConstraints, activePlugin.activePump, resourceHelper).formatColor(resourceHelper, R.color.bolus)) actions.add(resourceHelper.gs(R.string.bolus) + ": " + DecimalFormatter.toPumpSupportedBolus(insulinAfterConstraints, activePlugin.activePump, resourceHelper).formatColor(resourceHelper, R.color.bolus))
@ -149,18 +162,18 @@ class InsulinDialog : DialogFragmentWithDate() {
if (eatingSoonChecked) if (eatingSoonChecked)
actions.add(resourceHelper.gs(R.string.temptargetshort) + ": " + (DecimalFormatter.to1Decimal(eatingSoonTT) + " " + unitLabel + " (" + resourceHelper.gs(R.string.format_mins, eatingSoonTTDuration) + ")").formatColor(resourceHelper, R.color.tempTargetConfirmation)) actions.add(resourceHelper.gs(R.string.temptargetshort) + ": " + (DecimalFormatter.to1Decimal(eatingSoonTT) + " " + unitLabel + " (" + resourceHelper.gs(R.string.format_mins, eatingSoonTTDuration) + ")").formatColor(resourceHelper, R.color.tempTargetConfirmation))
val timeOffset = overview_insulin_time.value.toInt() val timeOffset = binding.time.value.toInt()
val time = DateUtil.now() + T.mins(timeOffset.toLong()).msecs() val time = DateUtil.now() + T.mins(timeOffset.toLong()).msecs()
if (timeOffset != 0) if (timeOffset != 0)
actions.add(resourceHelper.gs(R.string.time) + ": " + dateUtil.dateAndTimeString(time)) actions.add(resourceHelper.gs(R.string.time) + ": " + dateUtil.dateAndTimeString(time))
val notes = notes.text.toString() val notes = binding.notesLayout.notes.text.toString()
if (notes.isNotEmpty()) if (notes.isNotEmpty())
actions.add(resourceHelper.gs(R.string.careportal_newnstreatment_notes_label) + ": " + notes) actions.add(resourceHelper.gs(R.string.careportal_newnstreatment_notes_label) + ": " + notes)
if (insulinAfterConstraints > 0 || eatingSoonChecked) { if (insulinAfterConstraints > 0 || eatingSoonChecked) {
activity?.let { activity -> activity?.let { activity ->
OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.bolus), HtmlHelper.fromHtml(Joiner.on("<br/>").join(actions)), Runnable { OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.bolus), HtmlHelper.fromHtml(Joiner.on("<br/>").join(actions)), {
if (eatingSoonChecked) { if (eatingSoonChecked) {
aapsLogger.debug("USER ENTRY: TEMPTARGET EATING SOON $eatingSoonTT duration: $eatingSoonTTDuration") aapsLogger.debug("USER ENTRY: TEMPTARGET EATING SOON $eatingSoonTT duration: $eatingSoonTTDuration")
val tempTarget = TempTarget() val tempTarget = TempTarget()

View file

@ -0,0 +1,385 @@
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 -> {
aapsLogger.debug("USER ENTRY: CLOSED LOOP MODE")
sp.putString(R.string.key_aps_mode, "closed")
rxBus.send(EventPreferenceChange(resourceHelper.gs(R.string.closedloop)))
return true
}
R.id.overview_lgsloop -> {
aapsLogger.debug("USER ENTRY: LGS LOOP MODE")
sp.putString(R.string.key_aps_mode, "lgs")
rxBus.send(EventPreferenceChange(resourceHelper.gs(R.string.lowglucosesuspend)))
return true
}
R.id.overview_openloop -> {
aapsLogger.debug("USER ENTRY: OPEN LOOP MODE")
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

@ -8,6 +8,7 @@ import android.widget.ArrayAdapter
import com.google.common.base.Joiner import com.google.common.base.Joiner
import info.nightscout.androidaps.Constants import info.nightscout.androidaps.Constants
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.databinding.DialogProfileswitchBinding
import info.nightscout.androidaps.interfaces.ActivePluginProvider import info.nightscout.androidaps.interfaces.ActivePluginProvider
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
@ -15,46 +16,51 @@ import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.HtmlHelper import info.nightscout.androidaps.utils.HtmlHelper
import info.nightscout.androidaps.utils.alertDialogs.OKDialog 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.dialog_profileswitch.*
import kotlinx.android.synthetic.main.notes.*
import kotlinx.android.synthetic.main.okcancel.*
import java.text.DecimalFormat import java.text.DecimalFormat
import java.util.* import java.util.*
import javax.inject.Inject import javax.inject.Inject
class ProfileSwitchDialog : DialogFragmentWithDate() { class ProfileSwitchDialog : DialogFragmentWithDate() {
@Inject lateinit var resourceHelper: ResourceHelper @Inject lateinit var resourceHelper: ResourceHelper
@Inject lateinit var profileFunction: ProfileFunction @Inject lateinit var profileFunction: ProfileFunction
@Inject lateinit var treatmentsPlugin: TreatmentsPlugin @Inject lateinit var treatmentsPlugin: TreatmentsPlugin
@Inject lateinit var activePlugin: ActivePluginProvider @Inject lateinit var activePlugin: ActivePluginProvider
var profileIndex: Int? = null private var profileIndex: Int? = null
private var _binding: DialogProfileswitchBinding? = null
// This property is only valid between onCreateView and
// onDestroyView.
private val binding get() = _binding!!
override fun onSaveInstanceState(savedInstanceState: Bundle) { override fun onSaveInstanceState(savedInstanceState: Bundle) {
super.onSaveInstanceState(savedInstanceState) super.onSaveInstanceState(savedInstanceState)
savedInstanceState.putDouble("overview_profileswitch_duration", overview_profileswitch_duration.value) savedInstanceState.putDouble("duration", binding.duration.value)
savedInstanceState.putDouble("overview_profileswitch_percentage", overview_profileswitch_percentage.value) savedInstanceState.putDouble("percentage", binding.percentage.value)
savedInstanceState.putDouble("overview_profileswitch_timeshift", overview_profileswitch_timeshift.value) savedInstanceState.putDouble("timeshift", binding.timeshift.value)
} }
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? { savedInstanceState: Bundle?): View {
onCreateViewGeneral() onCreateViewGeneral()
arguments?.let { bundle -> arguments?.let { bundle ->
profileIndex = bundle.getInt("profileIndex", 0) profileIndex = bundle.getInt("profileIndex", 0)
} }
return inflater.inflate(R.layout.dialog_profileswitch, container, false) _binding = DialogProfileswitchBinding.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)
overview_profileswitch_duration.setParams(savedInstanceState?.getDouble("overview_profileswitch_duration") binding.duration.setParams(savedInstanceState?.getDouble("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, binding.okcancel.ok)
overview_profileswitch_percentage.setParams(savedInstanceState?.getDouble("overview_profileswitch_percentage") binding.percentage.setParams(savedInstanceState?.getDouble("percentage")
?: 100.0, Constants.CPP_MIN_PERCENTAGE.toDouble(), Constants.CPP_MAX_PERCENTAGE.toDouble(), 5.0, DecimalFormat("0"), false, ok) ?: 100.0, Constants.CPP_MIN_PERCENTAGE.toDouble(), Constants.CPP_MAX_PERCENTAGE.toDouble(), 5.0, DecimalFormat("0"), false, binding.okcancel.ok)
overview_profileswitch_timeshift.setParams(savedInstanceState?.getDouble("overview_profileswitch_timeshift") binding.timeshift.setParams(savedInstanceState?.getDouble("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, binding.okcancel.ok)
// profile // profile
context?.let { context -> context?.let { context ->
@ -62,54 +68,60 @@ class ProfileSwitchDialog : DialogFragmentWithDate() {
?: return ?: return
val profileList = profileStore.getProfileList() val profileList = profileStore.getProfileList()
val adapter = ArrayAdapter(context, R.layout.spinner_centered, profileList) val adapter = ArrayAdapter(context, R.layout.spinner_centered, profileList)
overview_profileswitch_profile.adapter = adapter binding.profile.adapter = adapter
// set selected to actual profile // set selected to actual profile
if (profileIndex != null) if (profileIndex != null)
overview_profileswitch_profile.setSelection(profileIndex as Int) binding.profile.setSelection(profileIndex as Int)
else else
for (p in profileList.indices) for (p in profileList.indices)
if (profileList[p] == profileFunction.getProfileName(false)) if (profileList[p] == profileFunction.getProfileName(false))
overview_profileswitch_profile.setSelection(p) binding.profile.setSelection(p)
} ?: return } ?: return
treatmentsPlugin.getProfileSwitchFromHistory(DateUtil.now())?.let { ps -> treatmentsPlugin.getProfileSwitchFromHistory(DateUtil.now())?.let { ps ->
if (ps.isCPP) { if (ps.isCPP) {
overview_profileswitch_reuselayout.visibility = View.VISIBLE binding.reuselayout.visibility = View.VISIBLE
overview_profileswitch_reusebutton.text = resourceHelper.gs(R.string.reuse) + " " + ps.percentage + "% " + ps.timeshift + "h" binding.reusebutton.text = resourceHelper.gs(R.string.reuse_profile_pct_hours, ps.percentage, ps.timeshift)
overview_profileswitch_reusebutton.setOnClickListener { binding.reusebutton.setOnClickListener {
overview_profileswitch_percentage.value = ps.percentage.toDouble() binding.percentage.value = ps.percentage.toDouble()
overview_profileswitch_timeshift.value = ps.timeshift.toDouble() binding.timeshift.value = ps.timeshift.toDouble()
} }
} else { } else {
overview_profileswitch_reuselayout.visibility = View.GONE binding.reuselayout.visibility = View.GONE
} }
} }
} }
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
override fun submit(): Boolean { override fun submit(): Boolean {
if (_binding == null) return false
val profileStore = activePlugin.activeProfileInterface.profile val profileStore = activePlugin.activeProfileInterface.profile
?: return false ?: return false
val actions: LinkedList<String> = LinkedList() val actions: LinkedList<String> = LinkedList()
val duration = overview_profileswitch_duration?.value?.toInt() ?: return false val duration = binding.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 = binding.profile.selectedItem.toString()
actions.add(resourceHelper.gs(R.string.profile) + ": " + profile) actions.add(resourceHelper.gs(R.string.profile) + ": " + profile)
val percent = overview_profileswitch_percentage.value.toInt() val percent = binding.percentage.value.toInt()
if (percent != 100) if (percent != 100)
actions.add(resourceHelper.gs(R.string.percent) + ": " + percent + "%") actions.add(resourceHelper.gs(R.string.percent) + ": " + percent + "%")
val timeShift = overview_profileswitch_timeshift.value.toInt() val timeShift = binding.timeshift.value.toInt()
if (timeShift != 0) if (timeShift != 0)
actions.add(resourceHelper.gs(R.string.careportal_newnstreatment_timeshift_label) + ": " + resourceHelper.gs(R.string.format_hours, timeShift.toDouble())) actions.add(resourceHelper.gs(R.string.careportal_newnstreatment_timeshift_label) + ": " + resourceHelper.gs(R.string.format_hours, timeShift.toDouble()))
val notes = notes.text.toString() val notes = binding.notesLayout.notes.text.toString()
if (notes.isNotEmpty()) if (notes.isNotEmpty())
actions.add(resourceHelper.gs(R.string.careportal_newnstreatment_notes_label) + ": " + notes) actions.add(resourceHelper.gs(R.string.careportal_newnstreatment_notes_label) + ": " + notes)
if (eventTimeChanged) if (eventTimeChanged)
actions.add(resourceHelper.gs(R.string.time) + ": " + dateUtil.dateAndTimeString(eventTime)) actions.add(resourceHelper.gs(R.string.time) + ": " + dateUtil.dateAndTimeString(eventTime))
activity?.let { activity -> activity?.let { activity ->
OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.careportal_profileswitch), HtmlHelper.fromHtml(Joiner.on("<br/>").join(actions)), Runnable { OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.careportal_profileswitch), HtmlHelper.fromHtml(Joiner.on("<br/>").join(actions)), {
aapsLogger.debug("USER ENTRY: PROFILE SWITCH $profile percent: $percent timeshift: $timeShift duration: $duration") aapsLogger.debug("USER ENTRY: PROFILE SWITCH $profile percent: $percent timeshift: $timeShift duration: $duration")
treatmentsPlugin.doProfileSwitch(profileStore, profile, duration, percent, timeShift, eventTime) treatmentsPlugin.doProfileSwitch(profileStore, profile, duration, percent, timeShift, eventTime)
}) })

View file

@ -9,26 +9,26 @@ import android.view.ViewGroup
import com.google.common.base.Joiner import com.google.common.base.Joiner
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.activities.ErrorHelperActivity import info.nightscout.androidaps.activities.ErrorHelperActivity
import info.nightscout.androidaps.databinding.DialogTempbasalBinding
import info.nightscout.androidaps.interfaces.ActivePluginProvider import info.nightscout.androidaps.interfaces.ActivePluginProvider
import info.nightscout.androidaps.interfaces.CommandQueueProvider import info.nightscout.androidaps.interfaces.CommandQueueProvider
import info.nightscout.androidaps.interfaces.Constraint import info.nightscout.androidaps.interfaces.Constraint
import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.androidaps.interfaces.PumpDescription import info.nightscout.androidaps.interfaces.PumpDescription
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
import info.nightscout.androidaps.interfaces.ProfileFunction
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_tempbasal.*
import kotlinx.android.synthetic.main.okcancel.*
import java.text.DecimalFormat import java.text.DecimalFormat
import java.util.* import java.util.*
import javax.inject.Inject import javax.inject.Inject
import kotlin.math.abs import kotlin.math.abs
class TempBasalDialog : DialogFragmentWithDate() { class TempBasalDialog : DialogFragmentWithDate() {
@Inject lateinit var constraintChecker: ConstraintChecker @Inject lateinit var constraintChecker: ConstraintChecker
@Inject lateinit var resourceHelper: ResourceHelper @Inject lateinit var resourceHelper: ResourceHelper
@Inject lateinit var profileFunction: ProfileFunction @Inject lateinit var profileFunction: ProfileFunction
@ -38,17 +38,24 @@ class TempBasalDialog : DialogFragmentWithDate() {
private var isPercentPump = true private var isPercentPump = true
private var _binding: DialogTempbasalBinding? = null
// This property is only valid between onCreateView and
// onDestroyView.
private val binding get() = _binding!!
override fun onSaveInstanceState(savedInstanceState: Bundle) { override fun onSaveInstanceState(savedInstanceState: Bundle) {
super.onSaveInstanceState(savedInstanceState) super.onSaveInstanceState(savedInstanceState)
savedInstanceState.putDouble("actions_tempbasal_duration", actions_tempbasal_duration.value) savedInstanceState.putDouble("duration", binding.duration.value)
savedInstanceState.putDouble("actions_tempbasal_basalpercentinput", actions_tempbasal_basalpercentinput.value) savedInstanceState.putDouble("basalpercentinput", binding.basalpercentinput.value)
savedInstanceState.putDouble("actions_tempbasal_basalabsoluteinput", actions_tempbasal_basalabsoluteinput.value) savedInstanceState.putDouble("basalabsoluteinput", binding.basalabsoluteinput.value)
} }
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? { savedInstanceState: Bundle?): View {
onCreateViewGeneral() onCreateViewGeneral()
return inflater.inflate(R.layout.dialog_tempbasal, container, false) _binding = DialogTempbasalBinding.inflate(inflater, container, false)
return binding.root
} }
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
@ -60,41 +67,47 @@ class TempBasalDialog : DialogFragmentWithDate() {
val maxTempPercent = pumpDescription.maxTempPercent.toDouble() val maxTempPercent = pumpDescription.maxTempPercent.toDouble()
val tempPercentStep = pumpDescription.tempPercentStep.toDouble() val tempPercentStep = pumpDescription.tempPercentStep.toDouble()
actions_tempbasal_basalpercentinput.setParams(savedInstanceState?.getDouble("actions_tempbasal_basalpercentinput") binding.basalpercentinput.setParams(savedInstanceState?.getDouble("basalpercentinput")
?: 100.0, 0.0, maxTempPercent, tempPercentStep, DecimalFormat("0"), true, ok) ?: 100.0, 0.0, maxTempPercent, tempPercentStep, DecimalFormat("0"), true, binding.okcancel.ok)
actions_tempbasal_basalabsoluteinput.setParams(savedInstanceState?.getDouble("actions_tempbasal_basalabsoluteinput") binding.basalabsoluteinput.setParams(savedInstanceState?.getDouble("basalabsoluteinput")
?: profile.basal, 0.0, pumpDescription.maxTempAbsolute, pumpDescription.tempAbsoluteStep, DecimalFormat("0.00"), true, ok) ?: profile.basal, 0.0, pumpDescription.maxTempAbsolute, pumpDescription.tempAbsoluteStep, DecimalFormat("0.00"), true, binding.okcancel.ok)
val tempDurationStep = pumpDescription.tempDurationStep.toDouble() val tempDurationStep = pumpDescription.tempDurationStep.toDouble()
val tempMaxDuration = pumpDescription.tempMaxDuration.toDouble() val tempMaxDuration = pumpDescription.tempMaxDuration.toDouble()
actions_tempbasal_duration.setParams(savedInstanceState?.getDouble("actions_tempbasal_duration") binding.duration.setParams(savedInstanceState?.getDouble("duration")
?: tempDurationStep, tempDurationStep, tempMaxDuration, tempDurationStep, DecimalFormat("0"), false, ok) ?: tempDurationStep, tempDurationStep, tempMaxDuration, tempDurationStep, DecimalFormat("0"), false, binding.okcancel.ok)
isPercentPump = pumpDescription.tempBasalStyle and PumpDescription.PERCENT == PumpDescription.PERCENT isPercentPump = pumpDescription.tempBasalStyle and PumpDescription.PERCENT == PumpDescription.PERCENT
if (isPercentPump) { if (isPercentPump) {
actions_tempbasal_percent_layout.visibility = View.VISIBLE binding.percentLayout.visibility = View.VISIBLE
actions_tempbasal_absolute_layout.visibility = View.GONE binding.absoluteLayout.visibility = View.GONE
} else { } else {
actions_tempbasal_percent_layout.visibility = View.GONE binding.percentLayout.visibility = View.GONE
actions_tempbasal_absolute_layout.visibility = View.VISIBLE binding.absoluteLayout.visibility = View.VISIBLE
} }
} }
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
override fun submit(): Boolean { override fun submit(): Boolean {
if (_binding == null) return false
var percent = 0 var percent = 0
var absolute = 0.0 var absolute = 0.0
val durationInMinutes = actions_tempbasal_duration?.value?.toInt() ?: return false val durationInMinutes = binding.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) {
val basalPercentInput = SafeParse.stringToInt(actions_tempbasal_basalpercentinput.text) val basalPercentInput = SafeParse.stringToInt(binding.basalpercentinput.text)
percent = constraintChecker.applyBasalPercentConstraints(Constraint(basalPercentInput), profile).value() percent = constraintChecker.applyBasalPercentConstraints(Constraint(basalPercentInput), profile).value()
actions.add(resourceHelper.gs(R.string.tempbasal_label) + ": $percent%") actions.add(resourceHelper.gs(R.string.tempbasal_label) + ": $percent%")
actions.add(resourceHelper.gs(R.string.duration) + ": " + resourceHelper.gs(R.string.format_mins, durationInMinutes)) actions.add(resourceHelper.gs(R.string.duration) + ": " + resourceHelper.gs(R.string.format_mins, durationInMinutes))
if (percent != basalPercentInput) actions.add(resourceHelper.gs(R.string.constraintapllied)) if (percent != basalPercentInput) actions.add(resourceHelper.gs(R.string.constraintapllied))
} else { } else {
val basalAbsoluteInput = SafeParse.stringToDouble(actions_tempbasal_basalabsoluteinput.text) val basalAbsoluteInput = SafeParse.stringToDouble(binding.basalabsoluteinput.text)
absolute = constraintChecker.applyBasalConstraints(Constraint(basalAbsoluteInput), profile).value() absolute = constraintChecker.applyBasalConstraints(Constraint(basalAbsoluteInput), profile).value()
actions.add(resourceHelper.gs(R.string.tempbasal_label) + ": " + resourceHelper.gs(R.string.pump_basebasalrate, absolute)) actions.add(resourceHelper.gs(R.string.tempbasal_label) + ": " + resourceHelper.gs(R.string.pump_basebasalrate, absolute))
actions.add(resourceHelper.gs(R.string.duration) + ": " + resourceHelper.gs(R.string.format_mins, durationInMinutes)) actions.add(resourceHelper.gs(R.string.duration) + ": " + resourceHelper.gs(R.string.format_mins, durationInMinutes))
@ -102,7 +115,7 @@ class TempBasalDialog : DialogFragmentWithDate() {
actions.add(resourceHelper.gs(R.string.constraintapllied).formatColor(resourceHelper, R.color.warning)) actions.add(resourceHelper.gs(R.string.constraintapllied).formatColor(resourceHelper, R.color.warning))
} }
activity?.let { activity -> activity?.let { activity ->
OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.tempbasal_label), HtmlHelper.fromHtml(Joiner.on("<br/>").join(actions)), Runnable { OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.tempbasal_label), HtmlHelper.fromHtml(Joiner.on("<br/>").join(actions)), {
val callback: Callback = object : Callback() { val callback: Callback = object : Callback() {
override fun run() { override fun run() {
if (!result.success) { if (!result.success) {

View file

@ -4,122 +4,152 @@ 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.AdapterView
import android.widget.ArrayAdapter import android.widget.ArrayAdapter
import com.google.common.base.Joiner import com.google.common.base.Joiner
import com.google.common.collect.Lists import com.google.common.collect.Lists
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.databinding.DialogTemptargetBinding
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.plugins.configBuilder.ConstraintChecker import info.nightscout.androidaps.interfaces.ActivePluginProvider
import info.nightscout.androidaps.interfaces.ProfileFunction import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin
import info.nightscout.androidaps.utils.DefaultValueHelper import info.nightscout.androidaps.utils.DefaultValueHelper
import info.nightscout.androidaps.utils.HtmlHelper import info.nightscout.androidaps.utils.HtmlHelper
import info.nightscout.androidaps.utils.alertDialogs.OKDialog 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.dialog_temptarget.*
import kotlinx.android.synthetic.main.okcancel.*
import java.text.DecimalFormat import java.text.DecimalFormat
import java.util.* import java.util.*
import javax.inject.Inject import javax.inject.Inject
class TempTargetDialog : DialogFragmentWithDate() { class TempTargetDialog : DialogFragmentWithDate() {
@Inject lateinit var constraintChecker: ConstraintChecker @Inject lateinit var constraintChecker: ConstraintChecker
@Inject lateinit var resourceHelper: ResourceHelper @Inject lateinit var resourceHelper: ResourceHelper
@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>
private var _binding: DialogTemptargetBinding? = null
// This property is only valid between onCreateView and
// onDestroyView.
private val binding get() = _binding!!
override fun onSaveInstanceState(savedInstanceState: Bundle) { override fun onSaveInstanceState(savedInstanceState: Bundle) {
super.onSaveInstanceState(savedInstanceState) super.onSaveInstanceState(savedInstanceState)
savedInstanceState.putDouble("overview_temptarget_duration", overview_temptarget_duration.value) savedInstanceState.putDouble("duration", binding.duration.value)
savedInstanceState.putDouble("overview_temptarget_temptarget", overview_temptarget_temptarget.value) savedInstanceState.putDouble("temptarget", binding.temptarget.value)
} }
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? { savedInstanceState: Bundle?): View {
onCreateViewGeneral() onCreateViewGeneral()
return inflater.inflate(R.layout.dialog_temptarget, container, false) _binding = DialogTemptargetBinding.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)
overview_temptarget_duration.setParams(savedInstanceState?.getDouble("overview_temptarget_duration") binding.duration.setParams(savedInstanceState?.getDouble("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, binding.okcancel.ok)
if (profileFunction.getUnits() == Constants.MMOL) if (profileFunction.getUnits() == Constants.MMOL)
overview_temptarget_temptarget.setParams( binding.temptarget.setParams(
savedInstanceState?.getDouble("overview_temptarget_temptarget") savedInstanceState?.getDouble("temptarget")
?: Constants.MIN_TT_MMOL, ?: 8.0,
Constants.MIN_TT_MMOL, Constants.MAX_TT_MMOL, 0.1, DecimalFormat("0.0"), false, ok) Constants.MIN_TT_MMOL, Constants.MAX_TT_MMOL, 0.1, DecimalFormat("0.0"), false, binding.okcancel.ok)
else else
overview_temptarget_temptarget.setParams( binding.temptarget.setParams(
savedInstanceState?.getDouble("overview_temptarget_temptarget") savedInstanceState?.getDouble("temptarget")
?: Constants.MIN_TT_MGDL, ?: 144.0,
Constants.MIN_TT_MGDL, Constants.MAX_TT_MGDL, 1.0, DecimalFormat("0"), false, ok) Constants.MIN_TT_MGDL, Constants.MAX_TT_MGDL, 1.0, DecimalFormat("0"), false, binding.okcancel.ok)
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) binding.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)
binding.targetCancel.visibility = View.VISIBLE
else
binding.targetCancel.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 binding.reason.adapter = adapterReason
overview_temptarget_reason.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) { binding.targetCancel.setOnClickListener { shortClick(it) }
val defaultDuration: Double binding.eatingSoon.setOnClickListener { shortClick(it) }
val defaultTarget: Double binding.activity.setOnClickListener { shortClick(it) }
when (reasonList[position]) { binding.hypo.setOnClickListener { shortClick(it) }
resourceHelper.gs(R.string.eatingsoon) -> {
defaultDuration = defaultValueHelper.determineEatingSoonTTDuration().toDouble() binding.eatingSoon.setOnLongClickListener {
defaultTarget = defaultValueHelper.determineEatingSoonTT() longClick(it)
return@setOnLongClickListener true
}
binding.activity.setOnLongClickListener {
longClick(it)
return@setOnLongClickListener true
}
binding.hypo.setOnLongClickListener {
longClick(it)
return@setOnLongClickListener true
}
}
} }
resourceHelper.gs(R.string.activity) -> { private fun shortClick(v: View) {
defaultDuration = defaultValueHelper.determineActivityTTDuration().toDouble() v.performLongClick()
defaultTarget = defaultValueHelper.determineActivityTT() if (submit()) dismiss()
} }
resourceHelper.gs(R.string.hypo) -> { private fun longClick(v: View) {
defaultDuration = defaultValueHelper.determineHypoTTDuration().toDouble() when (v.id) {
defaultTarget = defaultValueHelper.determineHypoTT() R.id.eating_soon -> {
binding.temptarget.value = defaultValueHelper.determineEatingSoonTT()
binding.duration.value = defaultValueHelper.determineEatingSoonTTDuration().toDouble()
binding.reason.setSelection(reasonList.indexOf(resourceHelper.gs(R.string.eatingsoon)))
} }
resourceHelper.gs(R.string.cancel) -> { R.id.activity -> {
defaultDuration = 0.0 binding.temptarget.value = defaultValueHelper.determineActivityTT()
defaultTarget = 0.0 binding.duration.value = defaultValueHelper.determineActivityTTDuration().toDouble()
binding.reason.setSelection(reasonList.indexOf(resourceHelper.gs(R.string.activity)))
} }
else -> { R.id.hypo -> {
defaultDuration = overview_temptarget_duration.value binding.temptarget.value = defaultValueHelper.determineHypoTT()
defaultTarget = overview_temptarget_temptarget.value binding.duration.value = defaultValueHelper.determineHypoTTDuration().toDouble()
binding.reason.setSelection(reasonList.indexOf(resourceHelper.gs(R.string.hypo)))
} }
} }
overview_temptarget_temptarget.value = defaultTarget
overview_temptarget_duration.value = defaultDuration
} }
override fun onNothingSelected(parent: AdapterView<*>?) {} override fun onDestroyView() {
} super.onDestroyView()
} _binding = null
} }
override fun submit(): Boolean { override fun submit(): Boolean {
if (_binding == null) return false
val actions: LinkedList<String> = LinkedList() val actions: LinkedList<String> = LinkedList()
val reason = overview_temptarget_reason?.selectedItem?.toString() ?: return false val reason = binding.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 = binding.temptarget.value
val duration = overview_temptarget_duration.value.toInt() val duration = binding.duration.value.toInt()
if (target != 0.0 && duration != 0) { if (target != 0.0 && duration != 0) {
actions.add(resourceHelper.gs(R.string.reason) + ": " + reason) actions.add(resourceHelper.gs(R.string.reason) + ": " + reason)
actions.add(resourceHelper.gs(R.string.target_label) + ": " + Profile.toCurrentUnitsString(profileFunction, target) + " " + resourceHelper.gs(unitResId)) actions.add(resourceHelper.gs(R.string.target_label) + ": " + Profile.toCurrentUnitsString(profileFunction, target) + " " + resourceHelper.gs(unitResId))
@ -131,7 +161,7 @@ class TempTargetDialog : DialogFragmentWithDate() {
actions.add(resourceHelper.gs(R.string.time) + ": " + dateUtil.dateAndTimeString(eventTime)) actions.add(resourceHelper.gs(R.string.time) + ": " + dateUtil.dateAndTimeString(eventTime))
activity?.let { activity -> activity?.let { activity ->
OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.careportal_temporarytarget), HtmlHelper.fromHtml(Joiner.on("<br/>").join(actions)), Runnable { OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.careportal_temporarytarget), HtmlHelper.fromHtml(Joiner.on("<br/>").join(actions)), {
aapsLogger.debug("USER ENTRY: TEMP TARGET $target duration: $duration") aapsLogger.debug("USER ENTRY: TEMP TARGET $target duration: $duration")
if (target == 0.0 || duration == 0) { if (target == 0.0 || duration == 0) {
val tempTarget = TempTarget() val tempTarget = TempTarget()

View file

@ -13,6 +13,7 @@ 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.activities.ErrorHelperActivity
import info.nightscout.androidaps.data.DetailedBolusInfo import info.nightscout.androidaps.data.DetailedBolusInfo
import info.nightscout.androidaps.databinding.DialogTreatmentBinding
import info.nightscout.androidaps.db.CareportalEvent import info.nightscout.androidaps.db.CareportalEvent
import info.nightscout.androidaps.db.Source import info.nightscout.androidaps.db.Source
import info.nightscout.androidaps.interfaces.ActivePluginProvider import info.nightscout.androidaps.interfaces.ActivePluginProvider
@ -22,20 +23,18 @@ import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
import info.nightscout.androidaps.queue.Callback import info.nightscout.androidaps.queue.Callback
import info.nightscout.androidaps.utils.DecimalFormatter import info.nightscout.androidaps.utils.DecimalFormatter
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.ToastUtils import info.nightscout.androidaps.utils.ToastUtils
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_insulin.*
import kotlinx.android.synthetic.main.dialog_treatment.*
import kotlinx.android.synthetic.main.okcancel.*
import java.text.DecimalFormat import java.text.DecimalFormat
import java.util.* import java.util.*
import javax.inject.Inject import javax.inject.Inject
import kotlin.math.abs import kotlin.math.abs
class TreatmentDialog : DialogFragmentWithDate() { class TreatmentDialog : DialogFragmentWithDate() {
@Inject lateinit var constraintChecker: ConstraintChecker @Inject lateinit var constraintChecker: ConstraintChecker
@Inject lateinit var resourceHelper: ResourceHelper @Inject lateinit var resourceHelper: ResourceHelper
@Inject lateinit var activePlugin: ActivePluginProvider @Inject lateinit var activePlugin: ActivePluginProvider
@ -54,49 +53,62 @@ class TreatmentDialog : DialogFragmentWithDate() {
private fun validateInputs() { private fun validateInputs() {
val maxCarbs = constraintChecker.getMaxCarbsAllowed().value().toDouble() val maxCarbs = constraintChecker.getMaxCarbsAllowed().value().toDouble()
val maxInsulin = constraintChecker.getMaxBolusAllowed().value() val maxInsulin = constraintChecker.getMaxBolusAllowed().value()
if (SafeParse.stringToInt(overview_treatment_carbs.text) > maxCarbs) { if (SafeParse.stringToInt(binding.carbs.text) > maxCarbs) {
overview_treatment_carbs.value = 0.0 binding.carbs.value = 0.0
ToastUtils.showToastInUiThread(context, resourceHelper.gs(R.string.carbsconstraintapplied)) ToastUtils.showToastInUiThread(context, resourceHelper.gs(R.string.carbsconstraintapplied))
} }
if (SafeParse.stringToDouble(overview_treatment_insulin.text) > maxInsulin) { if (SafeParse.stringToDouble(binding.insulin.text) > maxInsulin) {
overview_treatment_insulin.value = 0.0 binding.insulin.value = 0.0
ToastUtils.showToastInUiThread(context, resourceHelper.gs(R.string.bolusconstraintapplied)) ToastUtils.showToastInUiThread(context, resourceHelper.gs(R.string.bolusconstraintapplied))
} }
} }
private var _binding: DialogTreatmentBinding? = null
// This property is only valid between onCreateView and
// onDestroyView.
private val binding get() = _binding!!
override fun onSaveInstanceState(savedInstanceState: Bundle) { override fun onSaveInstanceState(savedInstanceState: Bundle) {
super.onSaveInstanceState(savedInstanceState) super.onSaveInstanceState(savedInstanceState)
savedInstanceState.putDouble("overview_treatment_carbs", overview_treatment_carbs.value) savedInstanceState.putDouble("carbs", binding.carbs.value)
savedInstanceState.putDouble("overview_treatment_insulin", overview_treatment_insulin.value) savedInstanceState.putDouble("insulin", binding.insulin.value)
} }
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? { savedInstanceState: Bundle?): View {
onCreateViewGeneral() onCreateViewGeneral()
return inflater.inflate(R.layout.dialog_treatment, container, false) _binding = DialogTreatmentBinding.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)
if (config.NSCLIENT) { if (config.NSCLIENT) {
overview_treatment_record_only.isChecked = true binding.recordOnly.isChecked = true
overview_treatment_record_only.isEnabled = false binding.recordOnly.isEnabled = false
} }
val maxCarbs = constraintChecker.getMaxCarbsAllowed().value().toDouble() val maxCarbs = constraintChecker.getMaxCarbsAllowed().value().toDouble()
val maxInsulin = constraintChecker.getMaxBolusAllowed().value() val maxInsulin = constraintChecker.getMaxBolusAllowed().value()
val pumpDescription = activePlugin.activePump.pumpDescription val pumpDescription = activePlugin.activePump.pumpDescription
overview_treatment_carbs.setParams(savedInstanceState?.getDouble("overview_treatment_carbs") binding.carbs.setParams(savedInstanceState?.getDouble("carbs")
?: 0.0, 0.0, maxCarbs, 1.0, DecimalFormat("0"), false, ok, textWatcher) ?: 0.0, 0.0, maxCarbs, 1.0, DecimalFormat("0"), false, binding.okcancel.ok, textWatcher)
overview_treatment_insulin.setParams(savedInstanceState?.getDouble("overview_treatment_insulin") binding.insulin.setParams(savedInstanceState?.getDouble("insulin")
?: 0.0, 0.0, maxInsulin, pumpDescription.bolusStep, DecimalFormatter.pumpSupportedBolusFormat(activePlugin.activePump), false, ok, textWatcher) ?: 0.0, 0.0, maxInsulin, pumpDescription.bolusStep, DecimalFormatter.pumpSupportedBolusFormat(activePlugin.activePump), false, binding.okcancel.ok, textWatcher)
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
} }
override fun submit(): Boolean { override fun submit(): Boolean {
if (_binding == null) return false
val pumpDescription = activePlugin.activePump.pumpDescription val pumpDescription = activePlugin.activePump.pumpDescription
val insulin = SafeParse.stringToDouble(overview_treatment_insulin?.text ?: return false) val insulin = SafeParse.stringToDouble(binding.insulin.text ?: return false)
val carbs = SafeParse.stringToInt(overview_treatment_carbs.text) val carbs = SafeParse.stringToInt(binding.carbs.text)
val recordOnlyChecked = overview_treatment_record_only.isChecked val recordOnlyChecked = binding.recordOnly.isChecked
val actions: LinkedList<String?> = LinkedList() val actions: LinkedList<String?> = LinkedList()
val insulinAfterConstraints = constraintChecker.applyBolusConstraints(Constraint(insulin)).value() val insulinAfterConstraints = constraintChecker.applyBolusConstraints(Constraint(insulin)).value()
val carbsAfterConstraints = constraintChecker.applyCarbsConstraints(Constraint(carbs)).value() val carbsAfterConstraints = constraintChecker.applyCarbsConstraints(Constraint(carbs)).value()
@ -115,7 +127,7 @@ class TreatmentDialog : DialogFragmentWithDate() {
} }
if (insulinAfterConstraints > 0 || carbsAfterConstraints > 0) { if (insulinAfterConstraints > 0 || carbsAfterConstraints > 0) {
activity?.let { activity -> activity?.let { activity ->
OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.overview_treatment_label), HtmlHelper.fromHtml(Joiner.on("<br/>").join(actions)), Runnable { OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.overview_treatment_label), HtmlHelper.fromHtml(Joiner.on("<br/>").join(actions)), {
aapsLogger.debug("USER ENTRY: BOLUS insulin $insulin carbs: $carbs") aapsLogger.debug("USER ENTRY: BOLUS insulin $insulin carbs: $carbs")
val detailedBolusInfo = DetailedBolusInfo() val detailedBolusInfo = DetailedBolusInfo()
if (insulinAfterConstraints == 0.0) detailedBolusInfo.eventType = CareportalEvent.CARBCORRECTION if (insulinAfterConstraints == 0.0) detailedBolusInfo.eventType = CareportalEvent.CARBCORRECTION

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"), 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

@ -9,15 +9,16 @@ import android.view.WindowManager
import dagger.android.support.DaggerDialogFragment import dagger.android.support.DaggerDialogFragment
import info.nightscout.androidaps.Constants import info.nightscout.androidaps.Constants
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.databinding.DialogWizardinfoBinding
import info.nightscout.androidaps.interfaces.ProfileFunction import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.androidaps.utils.DecimalFormatter import info.nightscout.androidaps.utils.DecimalFormatter
import info.nightscout.androidaps.utils.JsonHelper import info.nightscout.androidaps.utils.JsonHelper
import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.resources.ResourceHelper
import kotlinx.android.synthetic.main.dialog_wizardinfo.*
import org.json.JSONObject import org.json.JSONObject
import javax.inject.Inject import javax.inject.Inject
class WizardInfoDialog : DaggerDialogFragment() { class WizardInfoDialog : DaggerDialogFragment() {
@Inject lateinit var resourceHelper: ResourceHelper @Inject lateinit var resourceHelper: ResourceHelper
@Inject lateinit var profileFunction: ProfileFunction @Inject lateinit var profileFunction: ProfileFunction
@ -27,62 +28,74 @@ class WizardInfoDialog : DaggerDialogFragment() {
this.json = json this.json = json
} }
private var _binding: DialogWizardinfoBinding? = 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 {
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_wizardinfo, container, false) _binding = DialogWizardinfoBinding.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)
close.setOnClickListener { dismiss() } binding.close.setOnClickListener { dismiss() }
val units = profileFunction.getUnits() val units = profileFunction.getUnits()
val bgString = val bgString =
if (units == Constants.MGDL) DecimalFormatter.to0Decimal(JsonHelper.safeGetDouble(json, "bg")) if (units == Constants.MGDL) DecimalFormatter.to0Decimal(JsonHelper.safeGetDouble(json, "bg"))
else DecimalFormatter.to1Decimal(JsonHelper.safeGetDouble(json, "bg")) else DecimalFormatter.to1Decimal(JsonHelper.safeGetDouble(json, "bg"))
// BG // BG
treatments_wizard_bg.text = resourceHelper.gs(R.string.format_bg_isf, bgString, JsonHelper.safeGetDouble(json, "isf")) binding.bg.text = resourceHelper.gs(R.string.format_bg_isf, bgString, JsonHelper.safeGetDouble(json, "isf"))
treatments_wizard_bginsulin.text = resourceHelper.gs(R.string.formatinsulinunits, JsonHelper.safeGetDouble(json, "insulinbg")) binding.bginsulin.text = resourceHelper.gs(R.string.formatinsulinunits, JsonHelper.safeGetDouble(json, "insulinbg"))
treatments_wizard_bgcheckbox.isChecked = JsonHelper.safeGetBoolean(json, "insulinbgused") binding.bgcheckbox.isChecked = JsonHelper.safeGetBoolean(json, "insulinbgused")
treatments_wizard_ttcheckbox.isChecked = JsonHelper.safeGetBoolean(json, "ttused") binding.ttcheckbox.isChecked = JsonHelper.safeGetBoolean(json, "ttused")
// Trend // Trend
treatments_wizard_bgtrend.text = JsonHelper.safeGetString(json, "trend") binding.bgtrend.text = JsonHelper.safeGetString(json, "trend")
treatments_wizard_bgtrendinsulin.text = resourceHelper.gs(R.string.formatinsulinunits, JsonHelper.safeGetDouble(json, "insulintrend")) binding.bgtrendinsulin.text = resourceHelper.gs(R.string.formatinsulinunits, JsonHelper.safeGetDouble(json, "insulintrend"))
treatments_wizard_bgtrendcheckbox.isChecked = JsonHelper.safeGetBoolean(json, "trendused") binding.bgtrendcheckbox.isChecked = JsonHelper.safeGetBoolean(json, "trendused")
// COB // COB
treatments_wizard_cob.text = resourceHelper.gs(R.string.format_cob_ic, JsonHelper.safeGetDouble(json, "cob"), JsonHelper.safeGetDouble(json, "ic")) binding.cob.text = resourceHelper.gs(R.string.format_cob_ic, JsonHelper.safeGetDouble(json, "cob"), JsonHelper.safeGetDouble(json, "ic"))
treatments_wizard_cobinsulin.text = resourceHelper.gs(R.string.formatinsulinunits, JsonHelper.safeGetDouble(json, "insulincob")) binding.cobinsulin.text = resourceHelper.gs(R.string.formatinsulinunits, JsonHelper.safeGetDouble(json, "insulincob"))
treatments_wizard_cobcheckbox.isChecked = JsonHelper.safeGetBoolean(json, "cobused") binding.cobcheckbox.isChecked = JsonHelper.safeGetBoolean(json, "cobused")
// Bolus IOB // Bolus IOB
treatments_wizard_bolusiobinsulin.text = resourceHelper.gs(R.string.formatinsulinunits, JsonHelper.safeGetDouble(json, "bolusiob")) binding.bolusiobinsulin.text = resourceHelper.gs(R.string.formatinsulinunits, JsonHelper.safeGetDouble(json, "bolusiob"))
treatments_wizard_bolusiobcheckbox.isChecked = JsonHelper.safeGetBoolean(json, "bolusiobused") binding.bolusiobcheckbox.isChecked = JsonHelper.safeGetBoolean(json, "bolusiobused")
// Basal IOB // Basal IOB
treatments_wizard_basaliobinsulin.text = resourceHelper.gs(R.string.formatinsulinunits, JsonHelper.safeGetDouble(json, "basaliob")) binding.basaliobinsulin.text = resourceHelper.gs(R.string.formatinsulinunits, JsonHelper.safeGetDouble(json, "basaliob"))
treatments_wizard_basaliobcheckbox.isChecked = JsonHelper.safeGetBoolean(json, "basaliobused") binding.basaliobcheckbox.isChecked = JsonHelper.safeGetBoolean(json, "basaliobused")
// Superbolus // Superbolus
treatments_wizard_sbinsulin.text = resourceHelper.gs(R.string.formatinsulinunits, JsonHelper.safeGetDouble(json, "insulinsuperbolus")) binding.sbinsulin.text = resourceHelper.gs(R.string.formatinsulinunits, JsonHelper.safeGetDouble(json, "insulinsuperbolus"))
treatments_wizard_sbcheckbox.isChecked = JsonHelper.safeGetBoolean(json, "superbolusused") binding.sbcheckbox.isChecked = JsonHelper.safeGetBoolean(json, "superbolusused")
// Carbs // Carbs
treatments_wizard_carbs.text = resourceHelper.gs(R.string.format_carbs_ic, JsonHelper.safeGetDouble(json, "carbs"), JsonHelper.safeGetDouble(json, "ic")) binding.carbs.text = resourceHelper.gs(R.string.format_carbs_ic, JsonHelper.safeGetDouble(json, "carbs"), JsonHelper.safeGetDouble(json, "ic"))
treatments_wizard_carbsinsulin.text = resourceHelper.gs(R.string.formatinsulinunits, JsonHelper.safeGetDouble(json, "insulincarbs")) binding.carbsinsulin.text = resourceHelper.gs(R.string.formatinsulinunits, JsonHelper.safeGetDouble(json, "insulincarbs"))
// Correction // Correction
treatments_wizard_correctioninsulin.text = resourceHelper.gs(R.string.formatinsulinunits, JsonHelper.safeGetDouble(json, "othercorrection")) binding.correctioninsulin.text = resourceHelper.gs(R.string.formatinsulinunits, JsonHelper.safeGetDouble(json, "othercorrection"))
// Profile // Profile
treatments_wizard_profile.text = JsonHelper.safeGetString(json, "profile") binding.profile.text = JsonHelper.safeGetString(json, "profile")
// Notes // Notes
treatments_wizard_notes.text = JsonHelper.safeGetString(json, "notes") binding.notes.text = JsonHelper.safeGetString(json, "notes")
// Percentage // Percentage
treatments_wizard_percent_used.text = DecimalFormatter.to0Decimal(JsonHelper.safeGetDouble(json, "percentageCorrection", 100.0)) + "%" binding.percentUsed.text = resourceHelper.gs(R.string.format_percent, (JsonHelper.safeGetInt(json, "percentageCorrection", 100)))
// Total // Total
treatments_wizard_totalinsulin.text = resourceHelper.gs(R.string.formatinsulinunits, JsonHelper.safeGetDouble(json, "insulin")) binding.totalinsulin.text = resourceHelper.gs(R.string.formatinsulinunits, JsonHelper.safeGetDouble(json, "insulin"))
} }
override fun onStart() { override fun onStart() {
super.onStart() super.onStart()
dialog?.window?.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT) dialog?.window?.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
} }
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
} }

View file

@ -13,6 +13,7 @@ import com.jjoe64.graphview.GraphView
import dagger.android.HasAndroidInjector import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.activities.NoSplashAppCompatActivity import info.nightscout.androidaps.activities.NoSplashAppCompatActivity
import info.nightscout.androidaps.databinding.ActivityHistorybrowseBinding
import info.nightscout.androidaps.events.EventCustomCalculationFinished import info.nightscout.androidaps.events.EventCustomCalculationFinished
import info.nightscout.androidaps.events.EventRefreshOverview import info.nightscout.androidaps.events.EventRefreshOverview
import info.nightscout.androidaps.interfaces.ActivePluginProvider import info.nightscout.androidaps.interfaces.ActivePluginProvider
@ -31,12 +32,10 @@ import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.T import info.nightscout.androidaps.utils.T
import info.nightscout.androidaps.utils.buildHelper.BuildHelper import info.nightscout.androidaps.utils.buildHelper.BuildHelper
import info.nightscout.androidaps.utils.extensions.toVisibility import info.nightscout.androidaps.utils.extensions.toVisibility
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.sharedPreferences.SP import info.nightscout.androidaps.utils.sharedPreferences.SP
import io.reactivex.android.schedulers.AndroidSchedulers 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.activity_historybrowse.*
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
@ -44,11 +43,11 @@ 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
@Inject lateinit var sp: SP @Inject lateinit var sp: SP
@Inject lateinit var resourceHelper: ResourceHelper
@Inject lateinit var profileFunction: ProfileFunction @Inject lateinit var profileFunction: ProfileFunction
@Inject lateinit var defaultValueHelper: DefaultValueHelper @Inject lateinit var defaultValueHelper: DefaultValueHelper
@Inject lateinit var iobCobCalculatorPluginHistory: IobCobCalculatorPluginHistory @Inject lateinit var iobCobCalculatorPluginHistory: IobCobCalculatorPluginHistory
@ -68,21 +67,27 @@ class HistoryBrowseActivity : NoSplashAppCompatActivity() {
private var rangeToDisplay = 24 // for graph private var rangeToDisplay = 24 // for graph
private var start: Long = 0 private var start: Long = 0
private val graphLock = Object()
private var eventCustomCalculationFinished = EventCustomCalculationFinished() private var eventCustomCalculationFinished = EventCustomCalculationFinished()
private lateinit var binding: ActivityHistorybrowseBinding
private var destroyed = false
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setContentView(R.layout.activity_historybrowse) binding = ActivityHistorybrowseBinding.inflate(layoutInflater)
setContentView(binding.root)
historybrowse_left.setOnClickListener { binding.left.setOnClickListener {
start -= T.hours(rangeToDisplay.toLong()).msecs() start -= T.hours(rangeToDisplay.toLong()).msecs()
runCalculation("onClickLeft") runCalculation("onClickLeft")
} }
historybrowse_right.setOnClickListener { binding.right.setOnClickListener {
start += T.hours(rangeToDisplay.toLong()).msecs() start += T.hours(rangeToDisplay.toLong()).msecs()
runCalculation("onClickRight") runCalculation("onClickRight")
} }
historybrowse_end.setOnClickListener { binding.end.setOnClickListener {
val calendar = Calendar.getInstance() val calendar = Calendar.getInstance()
calendar.timeInMillis = System.currentTimeMillis() calendar.timeInMillis = System.currentTimeMillis()
calendar[Calendar.MILLISECOND] = 0 calendar[Calendar.MILLISECOND] = 0
@ -92,12 +97,12 @@ class HistoryBrowseActivity : NoSplashAppCompatActivity() {
start = calendar.timeInMillis start = calendar.timeInMillis
runCalculation("onClickEnd") runCalculation("onClickEnd")
} }
historybrowse_zoom.setOnClickListener { binding.zoom.setOnClickListener {
rangeToDisplay += 6 rangeToDisplay += 6
rangeToDisplay = if (rangeToDisplay > 24) 6 else rangeToDisplay rangeToDisplay = if (rangeToDisplay > 24) 6 else rangeToDisplay
updateGUI("rangeChange", false) updateGUI("rangeChange", false)
} }
historybrowse_zoom.setOnLongClickListener { binding.zoom.setOnLongClickListener {
val calendar = Calendar.getInstance() val calendar = Calendar.getInstance()
calendar.timeInMillis = start calendar.timeInMillis = start
calendar[Calendar.MILLISECOND] = 0 calendar[Calendar.MILLISECOND] = 0
@ -121,11 +126,11 @@ class HistoryBrowseActivity : NoSplashAppCompatActivity() {
cal[Calendar.MINUTE] = 0 cal[Calendar.MINUTE] = 0
cal[Calendar.HOUR_OF_DAY] = 0 cal[Calendar.HOUR_OF_DAY] = 0
start = cal.timeInMillis start = cal.timeInMillis
historybrowse_date?.text = dateUtil.dateAndTimeString(start) binding.date.text = dateUtil.dateAndTimeString(start)
runCalculation("onClickDate") runCalculation("onClickDate")
} }
historybrowse_date.setOnClickListener { binding.date.setOnClickListener {
val cal = Calendar.getInstance() val cal = Calendar.getInstance()
cal.timeInMillis = start cal.timeInMillis = start
DatePickerDialog(this, dateSetListener, DatePickerDialog(this, dateSetListener,
@ -139,12 +144,12 @@ class HistoryBrowseActivity : NoSplashAppCompatActivity() {
windowManager?.defaultDisplay?.getMetrics(dm) windowManager?.defaultDisplay?.getMetrics(dm)
axisWidth = if (dm.densityDpi <= 120) 3 else if (dm.densityDpi <= 160) 10 else if (dm.densityDpi <= 320) 35 else if (dm.densityDpi <= 420) 50 else if (dm.densityDpi <= 560) 70 else 80 axisWidth = if (dm.densityDpi <= 120) 3 else if (dm.densityDpi <= 160) 10 else if (dm.densityDpi <= 320) 35 else if (dm.densityDpi <= 420) 50 else if (dm.densityDpi <= 560) 70 else 80
historybrowse_bggraph?.gridLabelRenderer?.gridColor = resourceHelper.gc(R.color.graphgrid) binding.bggraph.gridLabelRenderer?.gridColor = resourceHelper.gc(R.color.graphgrid)
historybrowse_bggraph?.gridLabelRenderer?.reloadStyles() binding.bggraph.gridLabelRenderer?.reloadStyles()
historybrowse_bggraph?.gridLabelRenderer?.labelVerticalWidth = axisWidth binding.bggraph.gridLabelRenderer?.labelVerticalWidth = axisWidth
overviewMenus.setupChartMenu(overview_chartMenuButton) overviewMenus.setupChartMenu(binding.overviewChartMenuButton)
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)
@ -158,6 +163,12 @@ class HistoryBrowseActivity : NoSplashAppCompatActivity() {
iobCobCalculatorPluginHistory.stopCalculation("onPause") iobCobCalculatorPluginHistory.stopCalculation("onPause")
} }
@Synchronized
override fun onDestroy() {
destroyed = true
super.onDestroy()
}
public override fun onResume() { public override fun onResume() {
super.onResume() super.onResume()
disposable.add(rxBus disposable.add(rxBus
@ -168,7 +179,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 +189,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({ binding.overviewIobcalculationprogess.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,15 +227,14 @@ class HistoryBrowseActivity : NoSplashAppCompatActivity() {
} }
private fun prepareGraphs() { private fun prepareGraphsIfNeeded(numOfGraphs: Int) {
val numOfGraphs = overviewMenus.setting.size synchronized(graphLock) {
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
secondaryGraphs.clear() secondaryGraphs.clear()
secondaryGraphsLabel.clear() secondaryGraphsLabel.clear()
history_iobgraph.removeAllViews() binding.iobGraph.removeAllViews()
for (i in 1 until numOfGraphs) { for (i in 1 until numOfGraphs) {
val relativeLayout = RelativeLayout(this) val relativeLayout = RelativeLayout(this)
relativeLayout.layoutParams = RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT) relativeLayout.layoutParams = RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
@ -248,11 +257,11 @@ class HistoryBrowseActivity : NoSplashAppCompatActivity() {
relativeLayout.addView(label) relativeLayout.addView(label)
secondaryGraphsLabel.add(label) secondaryGraphsLabel.add(label)
history_iobgraph.addView(relativeLayout) binding.iobGraph.addView(relativeLayout)
secondaryGraphs.add(graph) secondaryGraphs.add(graph)
} }
} }
}
} }
private fun runCalculation(from: String) { private fun runCalculation(from: String) {
@ -265,7 +274,10 @@ class HistoryBrowseActivity : NoSplashAppCompatActivity() {
} }
} }
@Synchronized
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()
@ -274,13 +286,13 @@ class HistoryBrowseActivity : NoSplashAppCompatActivity() {
val highLine = defaultValueHelper.determineHighLine() val highLine = defaultValueHelper.determineHighLine()
lifecycleScope.launch(Dispatchers.Main) { lifecycleScope.launch(Dispatchers.Main) {
historybrowse_noprofile?.visibility = (profile == null).toVisibility() binding.noprofile.visibility = (profile == null).toVisibility()
profile ?: return@launch profile ?: return@launch
historybrowse_bggraph ?: return@launch if (destroyed) return@launch
historybrowse_date?.text = dateUtil.dateAndTimeString(start) binding.date.text = dateUtil.dateAndTimeString(start)
historybrowse_zoom?.text = rangeToDisplay.toString() binding.zoom.text = rangeToDisplay.toString()
val graphData = GraphData(injector, historybrowse_bggraph, iobCobCalculatorPluginHistory, treatmentsPluginHistory) val graphData = GraphData(injector, binding.bggraph, iobCobCalculatorPluginHistory, treatmentsPluginHistory)
val secondaryGraphsData: ArrayList<GraphData> = ArrayList() val secondaryGraphsData: ArrayList<GraphData> = ArrayList()
// do preparation in different thread // do preparation in different thread
@ -296,8 +308,6 @@ class HistoryBrowseActivity : NoSplashAppCompatActivity() {
// **** BG **** // **** BG ****
graphData.addBgReadings(fromTime, toTime, lowLine, highLine, null) graphData.addBgReadings(fromTime, toTime, lowLine, highLine, null)
// set manual x bounds to have nice steps
graphData.formatAxis(fromTime, toTime)
// add target line // add target line
graphData.addTargetLine(fromTime, toTime, profile, null) graphData.addTargetLine(fromTime, toTime, profile, null)
@ -308,14 +318,15 @@ 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
synchronized(graphLock) {
for (g in 0 until secondaryGraphs.size) { for (g in 0 until secondaryGraphs.size) {
val secondGraphData = GraphData(injector, secondaryGraphs[g], iobCobCalculatorPluginHistory, treatmentsPluginHistory) val secondGraphData = GraphData(injector, secondaryGraphs[g], iobCobCalculatorPluginHistory, treatmentsPluginHistory)
var useIobForScale = false var useIobForScale = false
@ -326,22 +337,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)
@ -350,22 +361,29 @@ class HistoryBrowseActivity : NoSplashAppCompatActivity() {
} }
} }
} }
// set manual x bounds to have nice steps
graphData.setNumVerticalLables()
graphData.formatAxis(fromTime, toTime)
}
// finally enforce drawing of graphs in UI thread // finally enforce drawing of graphs in UI thread
graphData.performUpdate() graphData.performUpdate()
if (!bgOnly) if (!bgOnly)
synchronized(graphLock) {
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

@ -6,6 +6,7 @@ import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import dagger.android.support.DaggerFragment import dagger.android.support.DaggerFragment
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.databinding.LoopFragmentBinding
import info.nightscout.androidaps.interfaces.Constraint import info.nightscout.androidaps.interfaces.Constraint
import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.plugins.aps.loop.events.EventLoopSetLastRunGui import info.nightscout.androidaps.plugins.aps.loop.events.EventLoopSetLastRunGui
@ -19,7 +20,6 @@ import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.sharedPreferences.SP import info.nightscout.androidaps.utils.sharedPreferences.SP
import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable import io.reactivex.disposables.CompositeDisposable
import kotlinx.android.synthetic.main.loop_fragment.*
import javax.inject.Inject import javax.inject.Inject
class LoopFragment : DaggerFragment() { class LoopFragment : DaggerFragment() {
@ -33,16 +33,23 @@ class LoopFragment : DaggerFragment() {
private var disposable: CompositeDisposable = CompositeDisposable() private var disposable: CompositeDisposable = CompositeDisposable()
private var _binding: LoopFragmentBinding? = 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 {
return inflater.inflate(R.layout.loop_fragment, container, false) _binding = LoopFragmentBinding.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)
loop_run.setOnClickListener { binding.run.setOnClickListener {
loop_lastrun.text = resourceHelper.gs(R.string.executing) binding.lastrun.text = resourceHelper.gs(R.string.executing)
Thread { loopPlugin.invoke("Loop button", true) }.start() Thread { loopPlugin.invoke("Loop button", true) }.start()
} }
} }
@ -62,7 +69,7 @@ class LoopFragment : DaggerFragment() {
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
.subscribe({ .subscribe({
clearGUI() clearGUI()
loop_lastrun?.text = it.text binding.lastrun.text = it.text
}, { fabricPrivacy.logException(it) }) }, { fabricPrivacy.logException(it) })
updateGUI() updateGUI()
@ -76,22 +83,28 @@ class LoopFragment : DaggerFragment() {
} }
@Synchronized @Synchronized
fun updateGUI() { override fun onDestroyView() {
if (loop_request == null) return super.onDestroyView()
loopPlugin.lastRun?.let { _binding = null
loop_request?.text = it.request?.toSpanned() ?: "" }
loop_constraintsprocessed?.text = it.constraintsProcessed?.toSpanned() ?: ""
loop_source?.text = it.source ?: ""
loop_lastrun?.text = dateUtil.dateAndTimeString(it.lastAPSRun)
?: ""
loop_smbrequest_time?.text = dateUtil.dateAndTimeAndSecondsString(it.lastSMBRequest)
loop_smbexecution_time?.text = dateUtil.dateAndTimeAndSecondsString(it.lastSMBEnact)
loop_tbrrequest_time?.text = dateUtil.dateAndTimeAndSecondsString(it.lastTBRRequest)
loop_tbrexecution_time?.text = dateUtil.dateAndTimeAndSecondsString(it.lastTBREnact)
loop_tbrsetbypump?.text = it.tbrSetByPump?.let { tbrSetByPump -> HtmlHelper.fromHtml(tbrSetByPump.toHtml()) } @Synchronized
fun updateGUI() {
if (_binding == null) return
loopPlugin.lastRun?.let {
binding.request.text = it.request?.toSpanned() ?: ""
binding.constraintsprocessed.text = it.constraintsProcessed?.toSpanned() ?: ""
binding.source.text = it.source ?: ""
binding.lastrun.text = dateUtil.dateAndTimeString(it.lastAPSRun)
?: "" ?: ""
loop_smbsetbypump?.text = it.smbSetByPump?.let { smbSetByPump -> HtmlHelper.fromHtml(smbSetByPump.toHtml()) } binding.smbrequestTime.text = dateUtil.dateAndTimeAndSecondsString(it.lastSMBRequest)
binding.smbexecutionTime.text = dateUtil.dateAndTimeAndSecondsString(it.lastSMBEnact)
binding.tbrrequestTime.text = dateUtil.dateAndTimeAndSecondsString(it.lastTBRRequest)
binding.tbrexecutionTime.text = dateUtil.dateAndTimeAndSecondsString(it.lastTBREnact)
binding.tbrsetbypump.text = it.tbrSetByPump?.let { tbrSetByPump -> HtmlHelper.fromHtml(tbrSetByPump.toHtml()) }
?: ""
binding.smbsetbypump.text = it.smbSetByPump?.let { smbSetByPump -> HtmlHelper.fromHtml(smbSetByPump.toHtml()) }
?: "" ?: ""
val constraints = val constraints =
@ -101,22 +114,22 @@ class LoopFragment : DaggerFragment() {
constraintsProcessed.smbConstraint?.let { smbConstraint -> allConstraints.copyReasons(smbConstraint) } constraintsProcessed.smbConstraint?.let { smbConstraint -> allConstraints.copyReasons(smbConstraint) }
allConstraints.getMostLimitedReasons(aapsLogger) allConstraints.getMostLimitedReasons(aapsLogger)
} ?: "" } ?: ""
loop_constraints?.text = constraints binding.constraints.text = constraints
} }
} }
@Synchronized @Synchronized
private fun clearGUI() { private fun clearGUI() {
loop_request?.text = "" binding.request.text = ""
loop_constraints?.text = "" binding.constraints.text = ""
loop_constraintsprocessed?.text = "" binding.constraintsprocessed.text = ""
loop_source?.text = "" binding.source.text = ""
loop_lastrun?.text = "" binding.lastrun.text = ""
loop_smbrequest_time?.text = "" binding.smbrequestTime.text = ""
loop_smbexecution_time?.text = "" binding.smbexecutionTime.text = ""
loop_tbrrequest_time?.text = "" binding.tbrrequestTime.text = ""
loop_tbrexecution_time?.text = "" binding.tbrexecutionTime.text = ""
loop_tbrsetbypump?.text = "" binding.tbrsetbypump.text = ""
loop_smbsetbypump?.text = "" binding.smbsetbypump.text = ""
} }
} }

View file

@ -7,7 +7,6 @@ import android.app.PendingIntent;
import android.app.TaskStackBuilder; import android.app.TaskStackBuilder;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.os.Build;
import android.os.SystemClock; import android.os.SystemClock;
import androidx.core.app.NotificationCompat; import androidx.core.app.NotificationCompat;
@ -145,6 +144,7 @@ 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)
@ -184,12 +184,12 @@ public class LoopPlugin extends PluginBase implements LoopInterface {
.observeOn(Schedulers.io()) .observeOn(Schedulers.io())
.subscribe(event -> invoke("EventTempTargetChange", true), fabricPrivacy::logException) .subscribe(event -> invoke("EventTempTargetChange", true), fabricPrivacy::logException)
); );
/** /*
* This method is triggered once autosens calculation has completed, so the LoopPlugin This method is triggered once autosens calculation has completed, so the LoopPlugin
* has current data to work with. However, autosens calculation can be triggered by multiple has current data to work with. However, autosens calculation can be triggered by multiple
* sources and currently only a new BG should trigger a loop run. Hence we return early if sources and currently only a new BG should trigger a loop run. Hence we return early if
* the event causing the calculation is not EventNewBg. the event causing the calculation is not EventNewBg.
* <p> <p>
*/ */
disposable.add(rxBus disposable.add(rxBus
.toObservable(EventAutosensCalculationFinished.class) .toObservable(EventAutosensCalculationFinished.class)
@ -211,8 +211,6 @@ public class LoopPlugin extends PluginBase implements LoopInterface {
} }
private void createNotificationChannel() { private void createNotificationChannel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationManager mNotificationManager = NotificationManager mNotificationManager =
(NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
@SuppressLint("WrongConstant") NotificationChannel channel = new NotificationChannel(CHANNEL_ID, @SuppressLint("WrongConstant") NotificationChannel channel = new NotificationChannel(CHANNEL_ID,
@ -220,7 +218,6 @@ public class LoopPlugin extends PluginBase implements LoopInterface {
NotificationManager.IMPORTANCE_HIGH); NotificationManager.IMPORTANCE_HIGH);
mNotificationManager.createNotificationChannel(channel); mNotificationManager.createNotificationChannel(channel);
} }
}
@Override @Override
protected void onStop() { protected void onStop() {
@ -239,10 +236,6 @@ public class LoopPlugin extends PluginBase implements LoopInterface {
} }
} }
public long suspendedTo() {
return loopSuspendedTill;
}
public void suspendTo(long endTime) { public void suspendTo(long endTime) {
loopSuspendedTill = endTime; loopSuspendedTill = endTime;
isSuperBolus = false; isSuperBolus = false;
@ -340,8 +333,9 @@ public class LoopPlugin extends PluginBase implements LoopInterface {
} }
return isDisconnected; return isDisconnected;
} }
public boolean treatmentTimethreshold(int duartionMinutes) { public boolean treatmentTimethreshold(int duartionMinutes) {
long threshold = System.currentTimeMillis() + (duartionMinutes*60*1000); long threshold = System.currentTimeMillis() + (duartionMinutes * 60 * 1000);
boolean bool = false; boolean bool = false;
if (treatmentsPlugin.getLastBolusTime() > threshold || treatmentsPlugin.getLastCarbTime() > threshold) if (treatmentsPlugin.getLastBolusTime() > threshold || treatmentsPlugin.getLastCarbTime() > threshold)
bool = true; bool = true;
@ -413,7 +407,7 @@ public class LoopPlugin extends PluginBase implements LoopInterface {
// safety check for multiple SMBs // safety check for multiple SMBs
long lastBolusTime = treatmentsPlugin.getLastBolusTime(); long lastBolusTime = treatmentsPlugin.getLastBolusTime();
if (lastBolusTime != 0 && lastBolusTime + T.mins(3).msecs() > System.currentTimeMillis()) { if (lastBolusTime != 0 && lastBolusTime + T.mins(3).msecs() > System.currentTimeMillis()) {
getAapsLogger().debug(LTag.APS, "SMB requsted but still in 3 min interval"); getAapsLogger().debug(LTag.APS, "SMB requested but still in 3 min interval");
resultAfterConstraints.smb = 0; resultAfterConstraints.smb = 0;
} }
@ -455,31 +449,31 @@ public class LoopPlugin extends PluginBase implements LoopInterface {
&& resultAfterConstraints.carbsReq >= sp.getInt(R.string.key_smb_enable_carbs_suggestions_threshold, 0) && resultAfterConstraints.carbsReq >= sp.getInt(R.string.key_smb_enable_carbs_suggestions_threshold, 0)
&& carbsSuggestionsSuspendedUntil < System.currentTimeMillis() && !treatmentTimethreshold(-15)) { && carbsSuggestionsSuspendedUntil < System.currentTimeMillis() && !treatmentTimethreshold(-15)) {
if (sp.getBoolean(R.string.key_enable_carbs_required_alert_local,true) && !sp.getBoolean(R.string.key_raise_notifications_as_android_notifications, false)) { if (sp.getBoolean(R.string.key_enable_carbs_required_alert_local, true) && !sp.getBoolean(R.string.key_raise_notifications_as_android_notifications, true)) {
Notification carbreqlocal = new Notification(Notification.CARBS_REQUIRED, resultAfterConstraints.getCarbsRequiredText(), Notification.NORMAL); Notification carbreqlocal = new Notification(Notification.CARBS_REQUIRED, resultAfterConstraints.getCarbsRequiredText(), Notification.NORMAL);
rxBus.send(new EventNewNotification(carbreqlocal)); rxBus.send(new EventNewNotification(carbreqlocal));
} }
if (sp.getBoolean(R.string.key_ns_create_announcements_from_carbs_req, false)) { if (sp.getBoolean(R.string.key_ns_create_announcements_from_carbs_req, false)) {
nsUpload.uploadError(resultAfterConstraints.getCarbsRequiredText()); nsUpload.uploadError(resultAfterConstraints.getCarbsRequiredText());
} }
if (sp.getBoolean(R.string.key_enable_carbs_required_alert_local,true) && sp.getBoolean(R.string.key_raise_notifications_as_android_notifications, false)){ if (sp.getBoolean(R.string.key_enable_carbs_required_alert_local, true) && sp.getBoolean(R.string.key_raise_notifications_as_android_notifications, true)) {
Intent intentAction5m = new Intent(context, CarbSuggestionReceiver.class); Intent intentAction5m = new Intent(context, CarbSuggestionReceiver.class);
intentAction5m.putExtra("ignoreDuration", 5); intentAction5m.putExtra("ignoreDuration", 5);
PendingIntent pendingIntent5m = PendingIntent.getBroadcast(context, 1, intentAction5m, PendingIntent.FLAG_UPDATE_CURRENT); PendingIntent pendingIntent5m = PendingIntent.getBroadcast(context, 1, intentAction5m, PendingIntent.FLAG_UPDATE_CURRENT);
NotificationCompat.Action actionIgnore5m = new NotificationCompat.Action actionIgnore5m = new
NotificationCompat.Action(R.drawable.ic_notif_aaps, resourceHelper.gs(R.string.ignore5m,"Ignore 5m"), pendingIntent5m); NotificationCompat.Action(R.drawable.ic_notif_aaps, resourceHelper.gs(R.string.ignore5m, "Ignore 5m"), pendingIntent5m);
Intent intentAction15m = new Intent(context, CarbSuggestionReceiver.class); Intent intentAction15m = new Intent(context, CarbSuggestionReceiver.class);
intentAction15m.putExtra("ignoreDuration", 15); intentAction15m.putExtra("ignoreDuration", 15);
PendingIntent pendingIntent15m = PendingIntent.getBroadcast(context, 1, intentAction15m, PendingIntent.FLAG_UPDATE_CURRENT); PendingIntent pendingIntent15m = PendingIntent.getBroadcast(context, 1, intentAction15m, PendingIntent.FLAG_UPDATE_CURRENT);
NotificationCompat.Action actionIgnore15m = new NotificationCompat.Action actionIgnore15m = new
NotificationCompat.Action(R.drawable.ic_notif_aaps, resourceHelper.gs(R.string.ignore15m,"Ignore 15m"), pendingIntent15m); NotificationCompat.Action(R.drawable.ic_notif_aaps, resourceHelper.gs(R.string.ignore15m, "Ignore 15m"), pendingIntent15m);
Intent intentAction30m = new Intent(context, CarbSuggestionReceiver.class); Intent intentAction30m = new Intent(context, CarbSuggestionReceiver.class);
intentAction30m.putExtra("ignoreDuration", 30); intentAction30m.putExtra("ignoreDuration", 30);
PendingIntent pendingIntent30m = PendingIntent.getBroadcast(context, 1, intentAction30m, PendingIntent.FLAG_UPDATE_CURRENT); PendingIntent pendingIntent30m = PendingIntent.getBroadcast(context, 1, intentAction30m, PendingIntent.FLAG_UPDATE_CURRENT);
NotificationCompat.Action actionIgnore30m = new NotificationCompat.Action actionIgnore30m = new
NotificationCompat.Action(R.drawable.ic_notif_aaps, resourceHelper.gs(R.string.ignore30m,"Ignore 30m"), pendingIntent30m); NotificationCompat.Action(R.drawable.ic_notif_aaps, resourceHelper.gs(R.string.ignore30m, "Ignore 30m"), pendingIntent30m);
NotificationCompat.Builder builder = new NotificationCompat.Builder(context, CHANNEL_ID); NotificationCompat.Builder builder = new NotificationCompat.Builder(context, CHANNEL_ID);
builder.setSmallIcon(R.drawable.notif_icon) builder.setSmallIcon(R.drawable.notif_icon)
@ -502,7 +496,7 @@ public class LoopPlugin extends PluginBase implements LoopInterface {
rxBus.send(new EventNewOpenLoopNotification()); rxBus.send(new EventNewOpenLoopNotification());
//only send to wear if Native notifications are turned off //only send to wear if Native notifications are turned off
if (!sp.getBoolean(R.string.key_raise_notifications_as_android_notifications, false)) { if (!sp.getBoolean(R.string.key_raise_notifications_as_android_notifications, true)) {
// Send to Wear // Send to Wear
actionStringHandler.get().handleInitiate("changeRequest"); actionStringHandler.get().handleInitiate("changeRequest");
} }
@ -510,7 +504,7 @@ public class LoopPlugin extends PluginBase implements LoopInterface {
} else { } else {
//If carbs were required previously, but are no longer needed, dismiss notifications //If carbs were required previously, but are no longer needed, dismiss notifications
if ( prevCarbsreq > 0 ) { if (prevCarbsreq > 0) {
dismissSuggestion(); dismissSuggestion();
rxBus.send(new EventDismissNotification(Notification.CARBS_REQUIRED)); rxBus.send(new EventDismissNotification(Notification.CARBS_REQUIRED));
} }
@ -590,8 +584,8 @@ public class LoopPlugin extends PluginBase implements LoopInterface {
} }
} }
public void disableCarbSuggestions(int duartionMinutes) { public void disableCarbSuggestions(int durationMinutes) {
carbsSuggestionsSuspendedUntil = System.currentTimeMillis() + (duartionMinutes*60*1000); carbsSuggestionsSuspendedUntil = System.currentTimeMillis() + (durationMinutes * 60 * 1000);
dismissSuggestion(); dismissSuggestion();
} }

View file

@ -7,6 +7,7 @@ import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import dagger.android.support.DaggerFragment import dagger.android.support.DaggerFragment
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.databinding.OpenapsamaFragmentBinding
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.events.EventOpenAPSUpdateGui import info.nightscout.androidaps.plugins.aps.events.EventOpenAPSUpdateGui
@ -19,12 +20,12 @@ import info.nightscout.androidaps.utils.extensions.plusAssign
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.openapsama_fragment.*
import org.json.JSONArray import org.json.JSONArray
import org.json.JSONException import org.json.JSONException
import javax.inject.Inject import javax.inject.Inject
class OpenAPSAMAFragment : DaggerFragment() { class OpenAPSAMAFragment : DaggerFragment() {
private var disposable: CompositeDisposable = CompositeDisposable() private var disposable: CompositeDisposable = CompositeDisposable()
@Inject lateinit var aapsLogger: AAPSLogger @Inject lateinit var aapsLogger: AAPSLogger
@ -34,15 +35,22 @@ class OpenAPSAMAFragment : DaggerFragment() {
@Inject lateinit var openAPSAMAPlugin: OpenAPSAMAPlugin @Inject lateinit var openAPSAMAPlugin: OpenAPSAMAPlugin
@Inject lateinit var dateUtil: DateUtil @Inject lateinit var dateUtil: DateUtil
private var _binding: OpenapsamaFragmentBinding? = 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 {
return inflater.inflate(R.layout.openapsama_fragment, container, false) _binding = OpenapsamaFragmentBinding.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)
openapsma_run.setOnClickListener { binding.run.setOnClickListener {
openAPSAMAPlugin.invoke("OpenAPSAMA button", false) openAPSAMAPlugin.invoke("OpenAPSAMA button", false)
} }
} }
@ -73,47 +81,53 @@ class OpenAPSAMAFragment : DaggerFragment() {
disposable.clear() disposable.clear()
} }
@Synchronized
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
@Synchronized @Synchronized
private fun updateGUI() { private fun updateGUI() {
if (openapsma_result == null) return if (_binding == null) return
openAPSAMAPlugin.lastAPSResult?.let { lastAPSResult -> openAPSAMAPlugin.lastAPSResult?.let { lastAPSResult ->
openapsma_result.text = JSONFormatter.format(lastAPSResult.json) binding.result.text = JSONFormatter.format(lastAPSResult.json)
openapsma_request.text = lastAPSResult.toSpanned() binding.request.text = lastAPSResult.toSpanned()
} }
openAPSAMAPlugin.lastDetermineBasalAdapterAMAJS?.let { determineBasalAdapterAMAJS -> openAPSAMAPlugin.lastDetermineBasalAdapterAMAJS?.let { determineBasalAdapterAMAJS ->
openapsma_glucosestatus.text = JSONFormatter.format(determineBasalAdapterAMAJS.glucoseStatusParam) binding.glucosestatus.text = JSONFormatter.format(determineBasalAdapterAMAJS.glucoseStatusParam)
openapsma_currenttemp.text = JSONFormatter.format(determineBasalAdapterAMAJS.currentTempParam) binding.currenttemp.text = JSONFormatter.format(determineBasalAdapterAMAJS.currentTempParam)
try { try {
val iobArray = JSONArray(determineBasalAdapterAMAJS.iobDataParam) val iobArray = JSONArray(determineBasalAdapterAMAJS.iobDataParam)
openapsma_iobdata.text = TextUtils.concat(resourceHelper.gs(R.string.array_of_elements, iobArray.length()) + "\n", JSONFormatter.format(iobArray.getString(0))) binding.iobdata.text = TextUtils.concat(resourceHelper.gs(R.string.array_of_elements, iobArray.length()) + "\n", JSONFormatter.format(iobArray.getString(0)))
} catch (e: JSONException) { } catch (e: JSONException) {
aapsLogger.error(LTag.APS, "Unhandled exception", e) aapsLogger.error(LTag.APS, "Unhandled exception", e)
@Suppress("SetTextI18n") @Suppress("SetTextI18n")
openapsma_iobdata.text = "JSONException see log for details" binding.iobdata.text = "JSONException see log for details"
} }
openapsma_profile.text = JSONFormatter.format(determineBasalAdapterAMAJS.profileParam) binding.profile.text = JSONFormatter.format(determineBasalAdapterAMAJS.profileParam)
openapsma_mealdata.text = JSONFormatter.format(determineBasalAdapterAMAJS.mealDataParam) binding.mealdata.text = JSONFormatter.format(determineBasalAdapterAMAJS.mealDataParam)
openapsma_scriptdebugdata.text = determineBasalAdapterAMAJS.scriptDebug binding.scriptdebugdata.text = determineBasalAdapterAMAJS.scriptDebug
} }
if (openAPSAMAPlugin.lastAPSRun != 0L) { if (openAPSAMAPlugin.lastAPSRun != 0L) {
openapsma_lastrun.text = dateUtil.dateAndTimeString(openAPSAMAPlugin.lastAPSRun) binding.lastrun.text = dateUtil.dateAndTimeString(openAPSAMAPlugin.lastAPSRun)
} }
openAPSAMAPlugin.lastAutosensResult?.let { openAPSAMAPlugin.lastAutosensResult?.let {
openapsma_autosensdata.text = JSONFormatter.format(it.json()) binding.autosensdata.text = JSONFormatter.format(it.json())
} }
} }
private fun updateResultGUI(text: String) { private fun updateResultGUI(text: String) {
openapsma_result.text = text binding.result.text = text
openapsma_glucosestatus.text = "" binding.glucosestatus.text = ""
openapsma_currenttemp.text = "" binding.currenttemp.text = ""
openapsma_iobdata.text = "" binding.iobdata.text = ""
openapsma_profile.text = "" binding.profile.text = ""
openapsma_mealdata.text = "" binding.mealdata.text = ""
openapsma_autosensdata.text = "" binding.autosensdata.text = ""
openapsma_scriptdebugdata.text = "" binding.scriptdebugdata.text = ""
openapsma_request.text = "" binding.request.text = ""
openapsma_lastrun.text = "" binding.lastrun.text = ""
} }
} }

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)

View file

@ -19,7 +19,6 @@ import java.nio.charset.StandardCharsets;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import javax.inject.Inject; import javax.inject.Inject;
import info.nightscout.androidaps.plugins.general.openhumans.OpenHumansUploader;
import dagger.android.HasAndroidInjector; import dagger.android.HasAndroidInjector;
import info.nightscout.androidaps.Constants; import info.nightscout.androidaps.Constants;
import info.nightscout.androidaps.R; import info.nightscout.androidaps.R;
@ -28,13 +27,14 @@ import info.nightscout.androidaps.data.MealData;
import info.nightscout.androidaps.data.Profile; import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.db.TemporaryBasal; import info.nightscout.androidaps.db.TemporaryBasal;
import info.nightscout.androidaps.interfaces.ActivePluginProvider; import info.nightscout.androidaps.interfaces.ActivePluginProvider;
import info.nightscout.androidaps.interfaces.ProfileFunction;
import info.nightscout.androidaps.interfaces.PumpInterface; import info.nightscout.androidaps.interfaces.PumpInterface;
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.logger.LoggerCallback; import info.nightscout.androidaps.plugins.aps.logger.LoggerCallback;
import info.nightscout.androidaps.plugins.aps.loop.ScriptReader; import info.nightscout.androidaps.plugins.aps.loop.ScriptReader;
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.openhumans.OpenHumansUploader;
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus; import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus;
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin; import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin;
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin; import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin;
@ -73,10 +73,6 @@ public class DetermineBasalAdapterSMBJS {
private String storedGlucoseStatus = null; private String storedGlucoseStatus = null;
private String storedProfile = null; private String storedProfile = null;
private String storedMeal_data = null; private String storedMeal_data = null;
private String storedAutosens_data = null;
private String storedMicroBolusAllowed = null;
private String storedSMBAlwaysAllowed = null;
private String storedCurrentTime = null;
private String scriptDebug = ""; private String scriptDebug = "";
@ -102,13 +98,13 @@ public class DetermineBasalAdapterSMBJS {
aapsLogger.debug(LTag.APS, "Profile: " + (storedProfile = mProfile.toString())); aapsLogger.debug(LTag.APS, "Profile: " + (storedProfile = mProfile.toString()));
aapsLogger.debug(LTag.APS, "Meal data: " + (storedMeal_data = mMealData.toString())); aapsLogger.debug(LTag.APS, "Meal data: " + (storedMeal_data = mMealData.toString()));
if (mAutosensData != null) if (mAutosensData != null)
aapsLogger.debug(LTag.APS, "Autosens data: " + (storedAutosens_data = mAutosensData.toString())); aapsLogger.debug(LTag.APS, "Autosens data: " + mAutosensData.toString());
else else
aapsLogger.debug(LTag.APS, "Autosens data: " + (storedAutosens_data = "undefined")); aapsLogger.debug(LTag.APS, "Autosens data: " + "undefined");
aapsLogger.debug(LTag.APS, "Reservoir data: " + "undefined"); aapsLogger.debug(LTag.APS, "Reservoir data: " + "undefined");
aapsLogger.debug(LTag.APS, "MicroBolusAllowed: " + (storedMicroBolusAllowed = "" + mMicrobolusAllowed)); aapsLogger.debug(LTag.APS, "MicroBolusAllowed: " + mMicrobolusAllowed);
aapsLogger.debug(LTag.APS, "SMBAlwaysAllowed: " + (storedSMBAlwaysAllowed = "" + mSMBAlwaysAllowed)); aapsLogger.debug(LTag.APS, "SMBAlwaysAllowed: " + mSMBAlwaysAllowed);
aapsLogger.debug(LTag.APS, "CurrentTime: " + (storedCurrentTime = "" + mCurrentTime)); aapsLogger.debug(LTag.APS, "CurrentTime: " + mCurrentTime);
aapsLogger.debug(LTag.APS, "isSaveCgmSource: " + mIsSaveCgmSource); aapsLogger.debug(LTag.APS, "isSaveCgmSource: " + mIsSaveCgmSource);
@ -151,9 +147,10 @@ public class DetermineBasalAdapterSMBJS {
makeParam(mAutosensData, rhino, scope), makeParam(mAutosensData, rhino, scope),
makeParam(mMealData, rhino, scope), makeParam(mMealData, rhino, scope),
setTempBasalFunctionsObj, setTempBasalFunctionsObj,
new Boolean(mMicrobolusAllowed), Boolean.valueOf(mMicrobolusAllowed),
makeParam(null, rhino, scope), // reservoir data as undefined makeParam(null, rhino, scope), // reservoir data as undefined
new Long(mCurrentTime) Long.valueOf(mCurrentTime),
Boolean.valueOf(mIsSaveCgmSource)
}; };
@ -213,14 +210,6 @@ public class DetermineBasalAdapterSMBJS {
return storedMeal_data; return storedMeal_data;
} }
String getAutosensDataParam() {
return storedAutosens_data;
}
String getMicroBolusAllowedParam() {
return storedMicroBolusAllowed;
}
String getScriptDebug() { String getScriptDebug() {
return scriptDebug; return scriptDebug;
} }
@ -243,7 +232,6 @@ public class DetermineBasalAdapterSMBJS {
boolean isSaveCgmSource boolean isSaveCgmSource
) throws JSONException { ) throws JSONException {
String units = profile.getUnits();
PumpInterface pump = activePluginProvider.getActivePump(); PumpInterface pump = activePluginProvider.getActivePump();
Double pumpbolusstep = pump.getPumpDescription().bolusStep; Double pumpbolusstep = pump.getPumpDescription().bolusStep;
mProfile = new JSONObject(); mProfile = new JSONObject();
@ -267,8 +255,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);
@ -284,7 +272,7 @@ 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(R.string.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));
@ -364,14 +352,12 @@ public class DetermineBasalAdapterSMBJS {
if (jsonObject == null) return Undefined.instance; if (jsonObject == null) return Undefined.instance;
Object param = NativeJSON.parse(rhino, scope, jsonObject.toString(), (context, scriptable, scriptable1, objects) -> objects[1]); return NativeJSON.parse(rhino, scope, jsonObject.toString(), (context, scriptable, scriptable1, objects) -> objects[1]);
return param;
} }
private Object makeParamArray(JSONArray jsonArray, Context rhino, Scriptable scope) { private Object makeParamArray(JSONArray jsonArray, Context rhino, Scriptable scope) {
//Object param = NativeJSON.parse(rhino, scope, "{myarray: " + jsonArray.toString() + " }", new Callable() { //Object param = NativeJSON.parse(rhino, scope, "{myarray: " + jsonArray.toString() + " }", new Callable() {
Object param = NativeJSON.parse(rhino, scope, jsonArray.toString(), (context, scriptable, scriptable1, objects) -> objects[1]); return NativeJSON.parse(rhino, scope, jsonArray.toString(), (context, scriptable, scriptable1, objects) -> objects[1]);
return param;
} }
private String readFile(String filename) throws IOException { private String readFile(String filename) throws IOException {

View file

@ -8,6 +8,7 @@ import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import dagger.android.support.DaggerFragment import dagger.android.support.DaggerFragment
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.databinding.OpenapsamaFragmentBinding
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.events.EventOpenAPSUpdateGui import info.nightscout.androidaps.plugins.aps.events.EventOpenAPSUpdateGui
@ -20,7 +21,6 @@ import info.nightscout.androidaps.utils.extensions.plusAssign
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.openapsama_fragment.*
import org.json.JSONArray import org.json.JSONArray
import org.json.JSONException import org.json.JSONException
import javax.inject.Inject import javax.inject.Inject
@ -35,15 +35,22 @@ class OpenAPSSMBFragment : DaggerFragment() {
@Inject lateinit var openAPSSMBPlugin: OpenAPSSMBPlugin @Inject lateinit var openAPSSMBPlugin: OpenAPSSMBPlugin
@Inject lateinit var dateUtil: DateUtil @Inject lateinit var dateUtil: DateUtil
private var _binding: OpenapsamaFragmentBinding? = 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 {
return inflater.inflate(R.layout.openapsama_fragment, container, false) _binding = OpenapsamaFragmentBinding.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)
openapsma_run.setOnClickListener { binding.run.setOnClickListener {
openAPSSMBPlugin.invoke("OpenAPSSMB button", false) openAPSSMBPlugin.invoke("OpenAPSSMB button", false)
} }
} }
@ -73,52 +80,58 @@ class OpenAPSSMBFragment : DaggerFragment() {
disposable.clear() disposable.clear()
} }
@Synchronized
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
@Synchronized @Synchronized
fun updateGUI() { fun updateGUI() {
if (openapsma_result == null) return if (_binding == null) return
openAPSSMBPlugin.lastAPSResult?.let { lastAPSResult -> openAPSSMBPlugin.lastAPSResult?.let { lastAPSResult ->
openapsma_result.text = JSONFormatter.format(lastAPSResult.json) binding.result.text = JSONFormatter.format(lastAPSResult.json)
openapsma_request.text = lastAPSResult.toSpanned() binding.request.text = lastAPSResult.toSpanned()
} }
openAPSSMBPlugin.lastDetermineBasalAdapterSMBJS?.let { determineBasalAdapterSMBJS -> openAPSSMBPlugin.lastDetermineBasalAdapterSMBJS?.let { determineBasalAdapterSMBJS ->
openapsma_glucosestatus.text = JSONFormatter.format(determineBasalAdapterSMBJS.glucoseStatusParam) binding.glucosestatus.text = JSONFormatter.format(determineBasalAdapterSMBJS.glucoseStatusParam)
openapsma_currenttemp.text = JSONFormatter.format(determineBasalAdapterSMBJS.currentTempParam) binding.currenttemp.text = JSONFormatter.format(determineBasalAdapterSMBJS.currentTempParam)
try { try {
val iobArray = JSONArray(determineBasalAdapterSMBJS.iobDataParam) val iobArray = JSONArray(determineBasalAdapterSMBJS.iobDataParam)
openapsma_iobdata.text = TextUtils.concat(resourceHelper.gs(R.string.array_of_elements, iobArray.length()) + "\n", JSONFormatter.format(iobArray.getString(0))) binding.iobdata.text = TextUtils.concat(resourceHelper.gs(R.string.array_of_elements, iobArray.length()) + "\n", JSONFormatter.format(iobArray.getString(0)))
} catch (e: JSONException) { } catch (e: JSONException) {
aapsLogger.error(LTag.APS, "Unhandled exception", e) aapsLogger.error(LTag.APS, "Unhandled exception", e)
@SuppressLint("SetTextI18n") @SuppressLint("SetTextI18n")
openapsma_iobdata.text = "JSONException see log for details" binding.iobdata.text = "JSONException see log for details"
} }
openapsma_profile.text = JSONFormatter.format(determineBasalAdapterSMBJS.profileParam) binding.profile.text = JSONFormatter.format(determineBasalAdapterSMBJS.profileParam)
openapsma_mealdata.text = JSONFormatter.format(determineBasalAdapterSMBJS.mealDataParam) binding.mealdata.text = JSONFormatter.format(determineBasalAdapterSMBJS.mealDataParam)
openapsma_scriptdebugdata.text = determineBasalAdapterSMBJS.scriptDebug binding.scriptdebugdata.text = determineBasalAdapterSMBJS.scriptDebug
openAPSSMBPlugin.lastAPSResult?.inputConstraints?.let { openAPSSMBPlugin.lastAPSResult?.inputConstraints?.let {
openapsma_constraints.text = it.getReasons(aapsLogger) binding.constraints.text = it.getReasons(aapsLogger)
} }
} }
if (openAPSSMBPlugin.lastAPSRun != 0L) { if (openAPSSMBPlugin.lastAPSRun != 0L) {
openapsma_lastrun.text = dateUtil.dateAndTimeString(openAPSSMBPlugin.lastAPSRun) binding.lastrun.text = dateUtil.dateAndTimeString(openAPSSMBPlugin.lastAPSRun)
} }
openAPSSMBPlugin.lastAutosensResult?.let { openAPSSMBPlugin.lastAutosensResult?.let {
openapsma_autosensdata.text = JSONFormatter.format(it.json()) binding.autosensdata.text = JSONFormatter.format(it.json())
} }
} }
@Synchronized @Synchronized
private fun updateResultGUI(text: String) { private fun updateResultGUI(text: String) {
if (openapsma_result == null) return if (_binding == null) return
openapsma_result.text = text binding.result.text = text
openapsma_glucosestatus.text = "" binding.glucosestatus.text = ""
openapsma_currenttemp.text = "" binding.currenttemp.text = ""
openapsma_iobdata.text = "" binding.iobdata.text = ""
openapsma_profile.text = "" binding.profile.text = ""
openapsma_mealdata.text = "" binding.mealdata.text = ""
openapsma_autosensdata.text = "" binding.autosensdata.text = ""
openapsma_scriptdebugdata.text = "" binding.scriptdebugdata.text = ""
openapsma_request.text = "" binding.request.text = ""
openapsma_lastrun.text = "" binding.lastrun.text = ""
} }
} }

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)

View file

@ -12,6 +12,7 @@ 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
import info.nightscout.androidaps.activities.PreferencesActivity import info.nightscout.androidaps.activities.PreferencesActivity
import info.nightscout.androidaps.databinding.ConfigbuilderFragmentBinding
import info.nightscout.androidaps.events.EventRebuildTabs import info.nightscout.androidaps.events.EventRebuildTabs
import info.nightscout.androidaps.interfaces.* import info.nightscout.androidaps.interfaces.*
import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.plugins.bus.RxBusWrapper
@ -23,11 +24,11 @@ import info.nightscout.androidaps.utils.protection.ProtectionCheck
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.configbuilder_fragment.*
import java.util.* import java.util.*
import javax.inject.Inject import javax.inject.Inject
class ConfigBuilderFragment : DaggerFragment() { class ConfigBuilderFragment : DaggerFragment() {
@Inject lateinit var rxBus: RxBusWrapper @Inject lateinit var rxBus: RxBusWrapper
@Inject lateinit var resourceHelper: ResourceHelper @Inject lateinit var resourceHelper: ResourceHelper
@Inject lateinit var configBuilderPlugin: ConfigBuilderPlugin @Inject lateinit var configBuilderPlugin: ConfigBuilderPlugin
@ -39,25 +40,32 @@ class ConfigBuilderFragment : DaggerFragment() {
private var disposable: CompositeDisposable = CompositeDisposable() private var disposable: CompositeDisposable = CompositeDisposable()
private val pluginViewHolders = ArrayList<PluginViewHolder>() private val pluginViewHolders = ArrayList<PluginViewHolder>()
private var _binding: ConfigbuilderFragmentBinding? = 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 {
return inflater.inflate(R.layout.configbuilder_fragment, container, false) _binding = ConfigbuilderFragmentBinding.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)
if (protectionCheck.isLocked(ProtectionCheck.Protection.PREFERENCES)) if (protectionCheck.isLocked(ProtectionCheck.Protection.PREFERENCES))
configbuilder_main_layout.visibility = View.GONE binding.mainLayout.visibility = View.GONE
else else
unlock.visibility = View.GONE binding.unlock.visibility = View.GONE
unlock.setOnClickListener { binding.unlock.setOnClickListener {
activity?.let { activity -> activity?.let { activity ->
protectionCheck.queryProtection(activity, ProtectionCheck.Protection.PREFERENCES, Runnable { protectionCheck.queryProtection(activity, ProtectionCheck.Protection.PREFERENCES, {
activity.runOnUiThread { activity.runOnUiThread {
configbuilder_main_layout.visibility = View.VISIBLE binding.mainLayout.visibility = View.VISIBLE
unlock.visibility = View.GONE binding.unlock.visibility = View.GONE
} }
}) })
} }
@ -82,9 +90,15 @@ class ConfigBuilderFragment : DaggerFragment() {
disposable.clear() disposable.clear()
} }
@Synchronized
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
@Synchronized @Synchronized
private fun updateGUI() { private fun updateGUI() {
configbuilder_categories.removeAllViews() binding.categories.removeAllViews()
if (!config.NSCLIENT) { if (!config.NSCLIENT) {
createViewsForPlugins(R.string.configbuilder_profile, R.string.configbuilder_profile_description, PluginType.PROFILE, activePlugin.getSpecificPluginsVisibleInListByInterface(ProfileInterface::class.java, PluginType.PROFILE)) createViewsForPlugins(R.string.configbuilder_profile, R.string.configbuilder_profile_description, PluginType.PROFILE, activePlugin.getSpecificPluginsVisibleInListByInterface(ProfileInterface::class.java, PluginType.PROFILE))
} }
@ -115,7 +129,7 @@ class ConfigBuilderFragment : DaggerFragment() {
pluginContainer.addView(pluginViewHolder.baseView) pluginContainer.addView(pluginViewHolder.baseView)
pluginViewHolders.add(pluginViewHolder) pluginViewHolders.add(pluginViewHolder)
} }
configbuilder_categories.addView(parent) binding.categories.addView(parent)
} }
inner class PluginViewHolder internal constructor(private val fragment: ConfigBuilderFragment, inner class PluginViewHolder internal constructor(private val fragment: ConfigBuilderFragment,
@ -157,7 +171,7 @@ class ConfigBuilderFragment : DaggerFragment() {
pluginPreferences.setOnClickListener { pluginPreferences.setOnClickListener {
fragment.activity?.let { activity -> fragment.activity?.let { activity ->
protectionCheck.queryProtection(activity, ProtectionCheck.Protection.PREFERENCES, Runnable { protectionCheck.queryProtection(activity, ProtectionCheck.Protection.PREFERENCES, {
val i = Intent(fragment.context, PreferencesActivity::class.java) val i = Intent(fragment.context, PreferencesActivity::class.java)
i.putExtra("id", plugin.preferencesId) i.putExtra("id", plugin.preferencesId)
fragment.startActivity(i) fragment.startActivity(i)
@ -174,7 +188,7 @@ 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) { if (plugin.menuIcon != -1) {
pluginIcon.visibility = View.VISIBLE pluginIcon.visibility = View.VISIBLE
pluginIcon.setImageDrawable(context?.let { ContextCompat.getDrawable(it, plugin.menuIcon) }) pluginIcon.setImageDrawable(context?.let { ContextCompat.getDrawable(it, plugin.menuIcon) })
} else { } else {
@ -196,7 +210,5 @@ class ConfigBuilderFragment : DaggerFragment() {
private fun areMultipleSelectionsAllowed(type: PluginType): Boolean { private fun areMultipleSelectionsAllowed(type: PluginType): Boolean {
return type == PluginType.GENERAL || type == PluginType.CONSTRAINTS || type == PluginType.LOOP return type == PluginType.GENERAL || type == PluginType.CONSTRAINTS || type == PluginType.LOOP
} }
} }
} }

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),

View file

@ -9,8 +9,6 @@ import android.view.Gravity
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.Button
import android.widget.EditText
import android.widget.LinearLayout import android.widget.LinearLayout
import android.widget.TextView import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
@ -19,11 +17,13 @@ import androidx.recyclerview.widget.LinearSmoothScroller
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import dagger.android.support.DaggerFragment import dagger.android.support.DaggerFragment
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.databinding.ObjectivesFragmentBinding
import info.nightscout.androidaps.databinding.ObjectivesItemBinding
import info.nightscout.androidaps.dialogs.NtpProgressDialog
import info.nightscout.androidaps.events.EventNtpStatus
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.constraints.objectives.activities.ObjectivesExamDialog import info.nightscout.androidaps.plugins.constraints.objectives.activities.ObjectivesExamDialog
import info.nightscout.androidaps.dialogs.NtpProgressDialog
import info.nightscout.androidaps.events.EventNtpStatus
import info.nightscout.androidaps.plugins.constraints.objectives.events.EventObjectivesUpdateGui import info.nightscout.androidaps.plugins.constraints.objectives.events.EventObjectivesUpdateGui
import info.nightscout.androidaps.plugins.constraints.objectives.objectives.Objective.ExamTask import info.nightscout.androidaps.plugins.constraints.objectives.objectives.Objective.ExamTask
import info.nightscout.androidaps.receivers.ReceiverStatusStore import info.nightscout.androidaps.receivers.ReceiverStatusStore
@ -31,17 +31,17 @@ import info.nightscout.androidaps.setupwizard.events.EventSWUpdate
import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.FabricPrivacy 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
import info.nightscout.androidaps.utils.SntpClient import info.nightscout.androidaps.utils.SntpClient
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
import info.nightscout.androidaps.utils.extensions.plusAssign import info.nightscout.androidaps.utils.extensions.plusAssign
import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.sharedPreferences.SP import info.nightscout.androidaps.utils.sharedPreferences.SP
import 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.objectives_fragment.*
import javax.inject.Inject import javax.inject.Inject
class ObjectivesFragment : DaggerFragment() { class ObjectivesFragment : DaggerFragment() {
@Inject lateinit var rxBus: RxBusWrapper @Inject lateinit var rxBus: RxBusWrapper
@Inject lateinit var aapsLogger: AAPSLogger @Inject lateinit var aapsLogger: AAPSLogger
@Inject lateinit var sp: SP @Inject lateinit var sp: SP
@ -64,19 +64,26 @@ class ObjectivesFragment : DaggerFragment() {
} }
} }
private var _binding: ObjectivesFragmentBinding? = 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 {
return inflater.inflate(R.layout.objectives_fragment, container, false) _binding = ObjectivesFragmentBinding.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)
objectives_recyclerview.layoutManager = LinearLayoutManager(view.context) binding.recyclerview.layoutManager = LinearLayoutManager(view.context)
objectives_recyclerview.adapter = objectivesAdapter binding.recyclerview.adapter = objectivesAdapter
objectives_fake.setOnClickListener { updateGUI() } binding.fake.setOnClickListener { updateGUI() }
objectives_reset.setOnClickListener { binding.reset.setOnClickListener {
objectivesPlugin.reset() objectivesPlugin.reset()
objectives_recyclerview.adapter?.notifyDataSetChanged() binding.recyclerview.adapter?.notifyDataSetChanged()
scrollToCurrentObjective() scrollToCurrentObjective()
} }
scrollToCurrentObjective() scrollToCurrentObjective()
@ -90,7 +97,7 @@ class ObjectivesFragment : DaggerFragment() {
.toObservable(EventObjectivesUpdateGui::class.java) .toObservable(EventObjectivesUpdateGui::class.java)
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
.subscribe({ .subscribe({
objectives_recyclerview.adapter?.notifyDataSetChanged() binding.recyclerview.adapter?.notifyDataSetChanged()
}, { fabricPrivacy.logException(it) } }, { fabricPrivacy.logException(it) }
) )
} }
@ -105,6 +112,7 @@ class ObjectivesFragment : DaggerFragment() {
override fun onDestroyView() { override fun onDestroyView() {
super.onDestroyView() super.onDestroyView()
handler.removeCallbacks(objectiveUpdater) handler.removeCallbacks(objectiveUpdater)
_binding = null
} }
private fun startUpdateTimer() { private fun startUpdateTimer() {
@ -129,7 +137,7 @@ class ObjectivesFragment : DaggerFragment() {
override fun calculateTimeForScrolling(dx: Int): Int = super.calculateTimeForScrolling(dx) * 4 override fun calculateTimeForScrolling(dx: Int): Int = super.calculateTimeForScrolling(dx) * 4
} }
smoothScroller.targetPosition = i smoothScroller.targetPosition = i
objectives_recyclerview.layoutManager?.startSmoothScroll(smoothScroller) binding.recyclerview.layoutManager?.startSmoothScroll(smoothScroller)
} }
break break
} }
@ -145,67 +153,66 @@ class ObjectivesFragment : DaggerFragment() {
override fun onBindViewHolder(holder: ViewHolder, position: Int) { override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val objective = objectivesPlugin.objectives[position] val objective = objectivesPlugin.objectives[position]
holder.title.text = resourceHelper.gs(R.string.nth_objective, position + 1) holder.binding.title.text = resourceHelper.gs(R.string.nth_objective, position + 1)
if (objective.objective != 0) { if (objective.objective != 0) {
holder.objective.visibility = View.VISIBLE holder.binding.objective.visibility = View.VISIBLE
holder.objective.text = resourceHelper.gs(objective.objective) holder.binding.objective.text = resourceHelper.gs(objective.objective)
} else } else
holder.objective.visibility = View.GONE holder.binding.objective.visibility = View.GONE
if (objective.gate != 0) { if (objective.gate != 0) {
holder.gate.visibility = View.VISIBLE holder.binding.gate.visibility = View.VISIBLE
holder.gate.text = resourceHelper.gs(objective.gate) holder.binding.gate.text = resourceHelper.gs(objective.gate)
} else } else
holder.gate.visibility = View.GONE holder.binding.gate.visibility = View.GONE
if (!objective.isStarted) { if (!objective.isStarted) {
holder.gate.setTextColor(-0x1) holder.binding.gate.setTextColor(-0x1)
holder.verify.visibility = View.GONE holder.binding.verify.visibility = View.GONE
holder.progress.visibility = View.GONE holder.binding.progress.visibility = View.GONE
holder.accomplished.visibility = View.GONE holder.binding.accomplished.visibility = View.GONE
holder.unFinish.visibility = View.GONE holder.binding.unfinish.visibility = View.GONE
holder.unStart.visibility = View.GONE holder.binding.unstart.visibility = View.GONE
if (position == 0 || objectivesPlugin.allPriorAccomplished(position)) if (position == 0 || objectivesPlugin.allPriorAccomplished(position))
holder.start.visibility = View.VISIBLE holder.binding.start.visibility = View.VISIBLE
else else
holder.start.visibility = View.GONE holder.binding.start.visibility = View.GONE
} else if (objective.isAccomplished) { } else if (objective.isAccomplished) {
holder.gate.setTextColor(-0xb350b0) holder.binding.gate.setTextColor(-0xb350b0)
holder.verify.visibility = View.GONE holder.binding.verify.visibility = View.GONE
holder.progress.visibility = View.GONE holder.binding.progress.visibility = View.GONE
holder.start.visibility = View.GONE holder.binding.start.visibility = View.GONE
holder.accomplished.visibility = View.VISIBLE holder.binding.accomplished.visibility = View.VISIBLE
holder.unFinish.visibility = View.VISIBLE holder.binding.unfinish.visibility = View.VISIBLE
holder.unStart.visibility = View.GONE holder.binding.unstart.visibility = View.GONE
} else if (objective.isStarted) { } else if (objective.isStarted) {
holder.gate.setTextColor(-0x1) holder.binding.gate.setTextColor(-0x1)
holder.verify.visibility = View.VISIBLE holder.binding.verify.visibility = View.VISIBLE
holder.verify.isEnabled = objective.isCompleted || objectives_fake.isChecked holder.binding.verify.isEnabled = objective.isCompleted || binding.fake.isChecked
holder.start.visibility = View.GONE holder.binding.start.visibility = View.GONE
holder.accomplished.visibility = View.GONE holder.binding.accomplished.visibility = View.GONE
holder.unFinish.visibility = View.GONE holder.binding.unfinish.visibility = View.GONE
holder.unStart.visibility = View.VISIBLE holder.binding.unstart.visibility = View.VISIBLE
holder.progress.visibility = View.VISIBLE holder.binding.progress.visibility = View.VISIBLE
holder.progress.removeAllViews() holder.binding.progress.removeAllViews()
for (task in objective.tasks) { for (task in objective.tasks) {
if (task.shouldBeIgnored()) continue if (task.shouldBeIgnored()) continue
// name // name
val name = TextView(holder.progress.context) val name = TextView(holder.binding.progress.context)
@Suppress("SetTextlI8n")
name.text = resourceHelper.gs(task.task) + ":" name.text = resourceHelper.gs(task.task) + ":"
name.setTextColor(-0x1) name.setTextColor(-0x1)
holder.progress.addView(name, LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT) holder.binding.progress.addView(name, LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT)
// hint // hint
task.hints.forEach { h -> task.hints.forEach { h ->
if (!task.isCompleted) if (!task.isCompleted)
holder.progress.addView(h.generate(context)) holder.binding.progress.addView(h.generate(context))
} }
// state // state
val state = TextView(holder.progress.context) val state = TextView(holder.binding.progress.context)
state.setTextColor(-0x1) state.setTextColor(-0x1)
val basicHTML = "<font color=\"%1\$s\"><b>%2\$s</b></font>" val basicHTML = "<font color=\"%1\$s\"><b>%2\$s</b></font>"
val formattedHTML = String.format(basicHTML, if (task.isCompleted) "#4CAF50" else "#FF9800", task.progress) val formattedHTML = String.format(basicHTML, if (task.isCompleted) "#4CAF50" else "#FF9800", task.progress)
state.text = HtmlHelper.fromHtml(formattedHTML) state.text = HtmlHelper.fromHtml(formattedHTML)
state.gravity = Gravity.END state.gravity = Gravity.END
holder.progress.addView(state, LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT) holder.binding.progress.addView(state, LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT)
if (task is ExamTask) { if (task is ExamTask) {
state.setOnClickListener { state.setOnClickListener {
val dialog = ObjectivesExamDialog() val dialog = ObjectivesExamDialog()
@ -218,16 +225,16 @@ class ObjectivesFragment : DaggerFragment() {
} }
} }
// horizontal line // horizontal line
val separator = View(holder.progress.context) val separator = View(holder.binding.progress.context)
separator.setBackgroundColor(Color.DKGRAY) separator.setBackgroundColor(Color.DKGRAY)
holder.progress.addView(separator, LinearLayout.LayoutParams.MATCH_PARENT, 2) holder.binding.progress.addView(separator, LinearLayout.LayoutParams.MATCH_PARENT, 2)
} }
} }
holder.accomplished.text = resourceHelper.gs(R.string.accomplished, dateUtil.dateAndTimeString(objective.accomplishedOn)) holder.binding.accomplished.text = resourceHelper.gs(R.string.accomplished, dateUtil.dateAndTimeString(objective.accomplishedOn))
holder.accomplished.setTextColor(-0x3e3e3f) holder.binding.accomplished.setTextColor(-0x3e3e3f)
holder.verify.setOnClickListener { holder.binding.verify.setOnClickListener {
receiverStatusStore.updateNetworkStatus() receiverStatusStore.updateNetworkStatus()
if (objectives_fake.isChecked) { if (binding.fake.isChecked) {
objective.accomplishedOn = DateUtil.now() objective.accomplishedOn = DateUtil.now()
scrollToCurrentObjective() scrollToCurrentObjective()
startUpdateTimer() startUpdateTimer()
@ -264,9 +271,9 @@ class ObjectivesFragment : DaggerFragment() {
}.start() }.start()
} }
} }
holder.start.setOnClickListener { holder.binding.start.setOnClickListener {
receiverStatusStore.updateNetworkStatus() receiverStatusStore.updateNetworkStatus()
if (objectives_fake.isChecked) { if (binding.fake.isChecked) {
objective.startedOn = DateUtil.now() objective.startedOn = DateUtil.now()
scrollToCurrentObjective() scrollToCurrentObjective()
startUpdateTimer() startUpdateTimer()
@ -298,7 +305,7 @@ class ObjectivesFragment : DaggerFragment() {
}, receiverStatusStore.isConnected) }, receiverStatusStore.isConnected)
}.start() }.start()
} }
holder.unStart.setOnClickListener { holder.binding.unstart.setOnClickListener {
activity?.let { activity -> activity?.let { activity ->
OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.objectives), resourceHelper.gs(R.string.doyouwantresetstart), Runnable { OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.objectives), resourceHelper.gs(R.string.doyouwantresetstart), Runnable {
objective.startedOn = 0 objective.startedOn = 0
@ -308,7 +315,7 @@ class ObjectivesFragment : DaggerFragment() {
}) })
} }
} }
holder.unFinish.setOnClickListener { holder.binding.unfinish.setOnClickListener {
objective.accomplishedOn = 0 objective.accomplishedOn = 0
scrollToCurrentObjective() scrollToCurrentObjective()
rxBus.send(EventObjectivesUpdateGui()) rxBus.send(EventObjectivesUpdateGui())
@ -318,21 +325,21 @@ class ObjectivesFragment : DaggerFragment() {
// generate random request code if none exists // generate random request code if none exists
val request = sp.getString(R.string.key_objectives_request_code, String.format("%1$05d", (Math.random() * 99999).toInt())) val request = sp.getString(R.string.key_objectives_request_code, String.format("%1$05d", (Math.random() * 99999).toInt()))
sp.putString(R.string.key_objectives_request_code, request) sp.putString(R.string.key_objectives_request_code, request)
holder.requestCode.text = resourceHelper.gs(R.string.requestcode, request) holder.binding.requestcode.text = resourceHelper.gs(R.string.requestcode, request)
holder.requestCode.visibility = View.VISIBLE holder.binding.requestcode.visibility = View.VISIBLE
holder.enterButton.visibility = View.VISIBLE holder.binding.enterbutton.visibility = View.VISIBLE
holder.input.visibility = View.VISIBLE holder.binding.input.visibility = View.VISIBLE
holder.inputHint.visibility = View.VISIBLE holder.binding.inputhint.visibility = View.VISIBLE
holder.enterButton.setOnClickListener { holder.binding.enterbutton.setOnClickListener {
val input = holder.input.text.toString() val input = holder.binding.input.text.toString()
objective.specialAction(activity, input) objective.specialAction(activity, input)
rxBus.send(EventObjectivesUpdateGui()) rxBus.send(EventObjectivesUpdateGui())
} }
} else { } else {
holder.enterButton.visibility = View.GONE holder.binding.enterbutton.visibility = View.GONE
holder.input.visibility = View.GONE holder.binding.input.visibility = View.GONE
holder.inputHint.visibility = View.GONE holder.binding.inputhint.visibility = View.GONE
holder.requestCode.visibility = View.GONE holder.binding.requestcode.visibility = View.GONE
} }
} }
@ -340,20 +347,9 @@ class ObjectivesFragment : DaggerFragment() {
return objectivesPlugin.objectives.size return objectivesPlugin.objectives.size
} }
inner class ViewHolder internal constructor(itemView: View) : RecyclerView.ViewHolder(itemView) { inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val title: TextView = itemView.findViewById(R.id.objective_title)
val objective: TextView = itemView.findViewById(R.id.objective_objective) val binding = ObjectivesItemBinding.bind(itemView)
val gate: TextView = itemView.findViewById(R.id.objective_gate)
val accomplished: TextView = itemView.findViewById(R.id.objective_accomplished)
val progress: LinearLayout = itemView.findViewById(R.id.objective_progress)
val verify: Button = itemView.findViewById(R.id.objective_verify)
val start: Button = itemView.findViewById(R.id.objective_start)
val unFinish: Button = itemView.findViewById(R.id.objective_unfinish)
val unStart: Button = itemView.findViewById(R.id.objective_unstart)
val inputHint: TextView = itemView.findViewById(R.id.objective_inputhint)
val input: EditText = itemView.findViewById(R.id.objective_input)
val enterButton: Button = itemView.findViewById(R.id.objective_enterbutton)
val requestCode: TextView = itemView.findViewById(R.id.objective_requestcode)
} }
} }

View file

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

@ -6,6 +6,7 @@ import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import dagger.android.support.DaggerDialogFragment import dagger.android.support.DaggerDialogFragment
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.databinding.ObjectivesExamFragmentBinding
import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.plugins.constraints.objectives.events.EventObjectivesUpdateGui import info.nightscout.androidaps.plugins.constraints.objectives.events.EventObjectivesUpdateGui
import info.nightscout.androidaps.plugins.constraints.objectives.objectives.Objective import info.nightscout.androidaps.plugins.constraints.objectives.objectives.Objective
@ -15,28 +16,36 @@ import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.T import info.nightscout.androidaps.utils.T
import info.nightscout.androidaps.utils.ToastUtils import info.nightscout.androidaps.utils.ToastUtils
import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.resources.ResourceHelper
import kotlinx.android.synthetic.main.objectives_exam_fragment.*
import javax.inject.Inject import javax.inject.Inject
class ObjectivesExamDialog : DaggerDialogFragment() { class ObjectivesExamDialog : DaggerDialogFragment() {
@Inject lateinit var rxBus: RxBusWrapper @Inject lateinit var rxBus: RxBusWrapper
@Inject lateinit var resourceHelper: ResourceHelper @Inject lateinit var resourceHelper: ResourceHelper
@Inject lateinit var dateUtil: DateUtil @Inject lateinit var dateUtil: DateUtil
companion object { companion object {
var objective: Objective? = null var objective: Objective? = null
} }
private var currentTask = 0 private var currentTask = 0
private var _binding: ObjectivesExamFragmentBinding? = 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 ->
currentTask = bundle.getInt("currentTask", 0) currentTask = bundle.getInt("currentTask", 0)
} }
return inflater.inflate(R.layout.objectives_exam_fragment, container, false) _binding = ObjectivesExamFragmentBinding.inflate(inflater, container, false)
return binding.root
} }
override fun onStart() { override fun onStart() {
@ -55,13 +64,21 @@ class ObjectivesExamDialog : DaggerDialogFragment() {
bundle.putInt("currentTask", currentTask) bundle.putInt("currentTask", currentTask)
} }
@Synchronized
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
@Synchronized
fun updateGui() { fun updateGui() {
if (_binding == null) return
objective?.let { objective -> objective?.let { objective ->
val task: ExamTask = objective.tasks[currentTask] as ExamTask val task: ExamTask = objective.tasks[currentTask] as ExamTask
objectives_exam_name.setText(task.task) binding.examName.setText(task.task)
objectives_exam_question.setText(task.question) binding.examQuestion.setText(task.question)
// Options // Options
objectives_exam_options.removeAllViews() binding.examOptions.removeAllViews()
task.options.forEach { task.options.forEach {
val cb = it.generate(context) val cb = it.generate(context)
if (task.answered) { if (task.answered) {
@ -69,19 +86,19 @@ class ObjectivesExamDialog : DaggerDialogFragment() {
if (it.isCorrect) if (it.isCorrect)
cb.isChecked = true cb.isChecked = true
} }
objectives_exam_options.addView(cb) binding.examOptions.addView(cb)
} }
// Hints // Hints
objectives_exam_hints.removeAllViews() binding.examHints.removeAllViews()
for (h in task.hints) { for (h in task.hints) {
objectives_exam_hints.addView(h.generate(context)) binding.examHints.addView(h.generate(context))
} }
// Disabled to // Disabled to
objectives_exam_disabledto.text = resourceHelper.gs(R.string.answerdisabledto, dateUtil.timeString(task.disabledTo)) binding.examDisabledto.text = resourceHelper.gs(R.string.answerdisabledto, dateUtil.timeString(task.disabledTo))
objectives_exam_disabledto.visibility = if (task.isEnabledAnswer) View.GONE else View.VISIBLE binding.examDisabledto.visibility = if (task.isEnabledAnswer) View.GONE else View.VISIBLE
// Buttons // Buttons
objectives_exam_verify.isEnabled = !task.answered && task.isEnabledAnswer binding.examVerify.isEnabled = !task.answered && task.isEnabledAnswer
objectives_exam_verify.setOnClickListener { binding.examVerify.setOnClickListener {
var result = true var result = true
for (o in task.options) { for (o in task.options) {
val option: Option = o as Option val option: Option = o as Option
@ -95,26 +112,26 @@ class ObjectivesExamDialog : DaggerDialogFragment() {
updateGui() updateGui()
rxBus.send(EventObjectivesUpdateGui()) rxBus.send(EventObjectivesUpdateGui())
} }
close.setOnClickListener { dismiss() } binding.close.setOnClickListener { dismiss() }
objectives_exam_reset.setOnClickListener { binding.examReset.setOnClickListener {
task.answered = false task.answered = false
//task.disabledTo = 0 //task.disabledTo = 0
updateGui() updateGui()
rxBus.send(EventObjectivesUpdateGui()) rxBus.send(EventObjectivesUpdateGui())
} }
objectives_back_button.isEnabled = currentTask != 0 binding.backButton.isEnabled = currentTask != 0
objectives_back_button.setOnClickListener { binding.backButton.setOnClickListener {
currentTask-- currentTask--
updateGui() updateGui()
} }
objectives_next_button.isEnabled = currentTask != objective.tasks.size - 1 binding.nextButton.isEnabled = currentTask != objective.tasks.size - 1
objectives_next_button.setOnClickListener { binding.nextButton.setOnClickListener {
currentTask++ currentTask++
updateGui() updateGui()
} }
objectives_next_unanswered_button.isEnabled = !objective.isCompleted binding.nextUnansweredButton.isEnabled = !objective.isCompleted
objectives_next_unanswered_button.setOnClickListener { binding.nextUnansweredButton.setOnClickListener {
for (i in (currentTask + 1) until objective.tasks.size) { for (i in (currentTask + 1) until objective.tasks.size) {
if (!objective.tasks[i].isCompleted) { if (!objective.tasks[i].isCompleted) {
currentTask = i currentTask = i

View file

@ -1,6 +1,5 @@
package info.nightscout.androidaps.plugins.constraints.objectives.objectives; package info.nightscout.androidaps.plugins.constraints.objectives.objectives;
import android.app.Activity;
import android.content.Context; import android.content.Context;
import android.graphics.Color; import android.graphics.Color;
import android.text.util.Linkify; import android.text.util.Linkify;
@ -185,9 +184,9 @@ public abstract class Objective {
int days = (int) Math.floor((double) duration / T.days(1).msecs()); int days = (int) Math.floor((double) duration / T.days(1).msecs());
int hours = (int) Math.floor((double) duration / T.hours(1).msecs()); int hours = (int) Math.floor((double) duration / T.hours(1).msecs());
int minutes = (int) Math.floor((double) duration / T.mins(1).msecs()); int minutes = (int) Math.floor((double) duration / T.mins(1).msecs());
if (days > 0) return resourceHelper.gq(R.plurals.objective_days, days, days); if (days > 0) return resourceHelper.gq(R.plurals.days, days, days);
else if (hours > 0) return resourceHelper.gq(R.plurals.objective_hours, hours, hours); else if (hours > 0) return resourceHelper.gq(R.plurals.hours, hours, hours);
else return resourceHelper.gq(R.plurals.objective_minutes, minutes, minutes); else return resourceHelper.gq(R.plurals.minutes, minutes, minutes);
} }
} }

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,5 +1,6 @@
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.util.DisplayMetrics
@ -11,7 +12,6 @@ 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.Constants import info.nightscout.androidaps.Constants
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.activities.TDDStatsActivity import info.nightscout.androidaps.activities.TDDStatsActivity
@ -25,6 +25,7 @@ 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.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.plugins.pump.omnipod.OmnipodPumpPlugin
import info.nightscout.androidaps.queue.Callback import info.nightscout.androidaps.queue.Callback
import info.nightscout.androidaps.skins.SkinProvider import info.nightscout.androidaps.skins.SkinProvider
import info.nightscout.androidaps.utils.FabricPrivacy import info.nightscout.androidaps.utils.FabricPrivacy
@ -45,11 +46,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
@ -94,12 +96,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 {
@ -108,12 +110,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)
} }
} }
}) })
@ -128,12 +130,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)
} }
} }
}) })
@ -141,7 +143,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)) }
@ -253,7 +255,7 @@ class ActionsFragment : DaggerFragment() {
val activeBgSource = activePlugin.activeBgSource 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 || (pump is OmnipodPumpPlugin && pump.isUseRileyLinkBatteryLevel && pump.isBatteryChangeLoggingEnabled)).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()

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,8 +15,8 @@ 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.AutomationEventItemBinding
import info.nightscout.androidaps.databinding.AutomationFragmentBinding import info.nightscout.androidaps.databinding.AutomationFragmentBinding
@ -46,7 +46,7 @@ class AutomationFragment : DaggerFragment(), OnStartDragListener {
@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
@ -76,7 +76,7 @@ class AutomationFragment : DaggerFragment(), OnStartDragListener {
binding.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")
@ -112,6 +112,7 @@ class AutomationFragment : DaggerFragment(), OnStartDragListener {
disposable.clear() disposable.clear()
} }
@Synchronized
override fun onDestroyView() { override fun onDestroyView() {
super.onDestroyView() super.onDestroyView()
_binding = null _binding = null
@ -119,6 +120,7 @@ class AutomationFragment : DaggerFragment(), OnStartDragListener {
@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())
@ -159,7 +161,7 @@ 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.binding.eventTitle.text = event.title holder.binding.eventTitle.text = event.title
holder.binding.enabled.isChecked = event.isEnabled holder.binding.enabled.isChecked = event.isEnabled
holder.binding.enabled.isEnabled = !event.readOnly holder.binding.enabled.isEnabled = !event.readOnly
@ -190,7 +192,6 @@ class AutomationFragment : DaggerFragment(), OnStartDragListener {
rxBus.send(EventAutomationDataChanged()) rxBus.send(EventAutomationDataChanged())
} }
// edit event // edit event
if (!event.readOnly)
holder.binding.rootLayout.setOnClickListener { holder.binding.rootLayout.setOnClickListener {
val dialog = EditEventDialog() val dialog = EditEventDialog()
val args = Bundle() val args = Bundle()
@ -209,36 +210,33 @@ class AutomationFragment : DaggerFragment(), OnStartDragListener {
} }
// remove event // remove event
holder.binding.iconTrash.setOnClickListener { holder.binding.iconTrash.setOnClickListener {
showConfirmation(requireContext(), resourceHelper.gs(R.string.removerecord) + " " + automationPlugin.automationEvents[position].title, showConfirmation(requireContext(), 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(EventAutomationUpdateGui())
}, Runnable { }, Runnable {
rxBus.send(EventAutomationUpdateGui()) rxBus.send(EventAutomationUpdateGui())
}) })
} }
holder.binding.iconTrash.visibility = (!event.readOnly).toVisibility() 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()) })
} }
} }

View file

@ -1,12 +1,11 @@
package info.nightscout.androidaps.plugins.general.automation package info.nightscout.androidaps.plugins.general.automation
import android.content.Context import android.content.Context
import android.content.Intent
import android.os.Build
import android.os.Handler import android.os.Handler
import android.os.HandlerThread import android.os.HandlerThread
import android.os.SystemClock import android.os.SystemClock
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.events.EventBTChange import info.nightscout.androidaps.events.EventBTChange
import info.nightscout.androidaps.events.EventChargingState import info.nightscout.androidaps.events.EventChargingState
@ -27,7 +26,7 @@ import info.nightscout.androidaps.plugins.general.automation.events.EventAutomat
import info.nightscout.androidaps.plugins.general.automation.triggers.* import info.nightscout.androidaps.plugins.general.automation.triggers.*
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventAutosensCalculationFinished import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventAutosensCalculationFinished
import info.nightscout.androidaps.queue.Callback import info.nightscout.androidaps.queue.Callback
import info.nightscout.androidaps.services.LocationService import info.nightscout.androidaps.services.LocationServiceHelper
import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.FabricPrivacy import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.T import info.nightscout.androidaps.utils.T
@ -39,8 +38,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(
@ -53,12 +54,18 @@ class AutomationPlugin @Inject constructor(
private val rxBus: RxBusWrapper, private val rxBus: RxBusWrapper,
private val constraintChecker: ConstraintChecker, private val constraintChecker: ConstraintChecker,
aapsLogger: AAPSLogger, aapsLogger: AAPSLogger,
private val config: Config,
private val locationServiceHelper: LocationServiceHelper,
private val dateUtil: DateUtil private val dateUtil: DateUtil
) : 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)
.showInList(config.APS)
.neverVisible(!config.APS)
.alwaysEnabled(!config.APS)
.preferencesId(R.xml.pref_automation) .preferencesId(R.xml.pref_automation)
.description(R.string.automation_description), .description(R.string.automation_description),
aapsLogger, resourceHelper, injector aapsLogger, resourceHelper, injector
@ -68,7 +75,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 +83,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}}\"]}"
} }
@ -87,10 +95,7 @@ class AutomationPlugin @Inject constructor(
} }
override fun onStart() { override fun onStart() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) locationServiceHelper.startService(context)
context.startForegroundService(Intent(context, LocationService::class.java))
else
context.startService(Intent(context, LocationService::class.java))
super.onStart() super.onStart()
loadFromSP() loadFromSP()
@ -101,17 +106,14 @@ class AutomationPlugin @Inject constructor(
.observeOn(Schedulers.io()) .observeOn(Schedulers.io())
.subscribe({ e -> .subscribe({ e ->
if (e.isChanged(resourceHelper, R.string.key_location)) { if (e.isChanged(resourceHelper, R.string.key_location)) {
context.stopService(Intent(context, LocationService::class.java)) locationServiceHelper.stopService(context)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) locationServiceHelper.startService(context)
context.startForegroundService(Intent(context, LocationService::class.java))
else
context.startService(Intent(context, LocationService::class.java))
} }
}, { fabricPrivacy.logException(it) }) }, fabricPrivacy::logException)
disposable += rxBus disposable += rxBus
.toObservable(EventAutomationDataChanged::class.java) .toObservable(EventAutomationDataChanged::class.java)
.observeOn(Schedulers.io()) .observeOn(Schedulers.io())
.subscribe({ storeToSP() }, { fabricPrivacy.logException(it) }) .subscribe({ storeToSP() }, fabricPrivacy::logException)
disposable += rxBus disposable += rxBus
.toObservable(EventLocationChange::class.java) .toObservable(EventLocationChange::class.java)
.observeOn(Schedulers.io()) .observeOn(Schedulers.io())
@ -120,19 +122,19 @@ class AutomationPlugin @Inject constructor(
aapsLogger.debug(LTag.AUTOMATION, "Grabbed location: $it.location.latitude $it.location.longitude Provider: $it.location.provider") aapsLogger.debug(LTag.AUTOMATION, "Grabbed location: $it.location.latitude $it.location.longitude Provider: $it.location.provider")
processActions() processActions()
} }
}, { fabricPrivacy.logException(it) }) }, fabricPrivacy::logException)
disposable += rxBus disposable += rxBus
.toObservable(EventChargingState::class.java) .toObservable(EventChargingState::class.java)
.observeOn(Schedulers.io()) .observeOn(Schedulers.io())
.subscribe({ processActions() }, { fabricPrivacy.logException(it) }) .subscribe({ processActions() }, fabricPrivacy::logException)
disposable += rxBus disposable += rxBus
.toObservable(EventNetworkChange::class.java) .toObservable(EventNetworkChange::class.java)
.observeOn(Schedulers.io()) .observeOn(Schedulers.io())
.subscribe({ processActions() }, { fabricPrivacy.logException(it) }) .subscribe({ processActions() }, fabricPrivacy::logException)
disposable += rxBus disposable += rxBus
.toObservable(EventAutosensCalculationFinished::class.java) .toObservable(EventAutosensCalculationFinished::class.java)
.observeOn(Schedulers.io()) .observeOn(Schedulers.io())
.subscribe({ processActions() }, { fabricPrivacy.logException(it) }) .subscribe({ processActions() }, fabricPrivacy::logException)
disposable += rxBus disposable += rxBus
.toObservable(EventBTChange::class.java) .toObservable(EventBTChange::class.java)
.observeOn(Schedulers.io()) .observeOn(Schedulers.io())
@ -140,13 +142,13 @@ class AutomationPlugin @Inject constructor(
aapsLogger.debug(LTag.AUTOMATION, "Grabbed new BT event: $it") aapsLogger.debug(LTag.AUTOMATION, "Grabbed new BT event: $it")
btConnects.add(it) btConnects.add(it)
processActions() processActions()
}, { fabricPrivacy.logException(it) }) }, fabricPrivacy::logException)
} }
override fun onStop() { override fun onStop() {
disposable.clear() disposable.clear()
loopHandler.removeCallbacks(refreshLoop) loopHandler.removeCallbacks(refreshLoop)
context.stopService(Intent(context, LocationService::class.java)) locationServiceHelper.stopService(context)
super.onStop() super.onStop()
} }
@ -183,20 +185,26 @@ class AutomationPlugin @Inject constructor(
@Synchronized @Synchronized
private fun processActions() { private fun processActions() {
var userEventsEnabled = config.APS
if (config.APS) {
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) { val iterator : MutableIterator<AutomationEvent> = automationEvents.iterator()
while (iterator.hasNext()) {
val event = iterator.next()
if (event.isEnabled && event.shouldRun() && event.trigger.shouldRun() && event.getPreconditions().shouldRun()) { if (event.isEnabled && event.shouldRun() && event.trigger.shouldRun() && event.getPreconditions().shouldRun()) {
if (event.systemAction || userEventsEnabled) {
val actions = event.actions val actions = event.actions
for (action in actions) { for (action in actions) {
action.doAction(object : Callback() { action.doAction(object : Callback() {
@ -219,6 +227,8 @@ class AutomationPlugin @Inject constructor(
} }
SystemClock.sleep(1100) SystemClock.sleep(1100)
event.lastRun = DateUtil.now() event.lastRun = DateUtil.now()
if (event.autoRemove) automationEvents.remove(event)
}
} }
} }
// we cannot detect connected BT devices // we cannot detect connected BT devices
@ -230,6 +240,44 @@ class AutomationPlugin @Inject constructor(
storeToSP() // save last run time storeToSP() // save last run time
} }
@Synchronized
fun add(event: AutomationEvent) {
automationEvents.add(event)
rxBus.send(EventAutomationDataChanged())
}
@Synchronized
fun addIfNotExists(event: AutomationEvent) {
for (e in automationEvents) {
if (event.title == e.title) return
}
automationEvents.add(event)
rxBus.send(EventAutomationDataChanged())
}
@Synchronized
fun set(event: AutomationEvent, index: Int) {
automationEvents[index] = event
rxBus.send(EventAutomationDataChanged())
}
@Synchronized
fun removeAt(index: Int) {
automationEvents.removeAt(index)
rxBus.send(EventAutomationDataChanged())
}
@Synchronized
fun at(index: Int) = automationEvents[index]
fun size() = automationEvents.size
@Synchronized
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),

View file

@ -33,6 +33,9 @@ class ActionAlarm(injector: HasAndroidInjector) : Action(injector) {
var text = InputString(injector) 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 friendlyName(): Int = R.string.alarm
override fun shortDescription(): String = resourceHelper.gs(R.string.alarm_message, text.value) override fun shortDescription(): String = resourceHelper.gs(R.string.alarm_message, text.value)
@DrawableRes override fun icon(): Int = R.drawable.ic_access_alarm_24dp @DrawableRes override fun icon(): Int = R.drawable.ic_access_alarm_24dp

View file

@ -26,6 +26,7 @@ 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 javax.inject.Inject import javax.inject.Inject
@ -66,9 +67,13 @@ class EditEventDialog : DialogFragmentWithDate() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
binding.okcancel.ok.visibility = (!event.readOnly).toVisibility()
binding.inputEventTitle.setText(event.title) binding.inputEventTitle.setText(event.title)
binding.inputEventTitle.isFocusable = !event.readOnly
binding.triggerDescription.text = event.trigger.friendlyDescription() binding.triggerDescription.text = event.trigger.friendlyDescription()
binding.editTrigger.visibility = (!event.readOnly).toVisibility()
binding.editTrigger.setOnClickListener { binding.editTrigger.setOnClickListener {
val args = Bundle() val args = Bundle()
args.putString("trigger", event.trigger.toJSON()) args.putString("trigger", event.trigger.toJSON())
@ -82,6 +87,7 @@ class EditEventDialog : DialogFragmentWithDate() {
binding.actionListView.layoutManager = LinearLayoutManager(context) binding.actionListView.layoutManager = LinearLayoutManager(context)
binding.actionListView.adapter = actionListAdapter binding.actionListView.adapter = actionListAdapter
binding.addAction.visibility = (!event.readOnly).toVisibility()
binding.addAction.setOnClickListener { ChooseActionDialog().show(childFragmentManager, "ChooseActionDialog") } binding.addAction.setOnClickListener { ChooseActionDialog().show(childFragmentManager, "ChooseActionDialog") }
showPreconditions() showPreconditions()
@ -92,31 +98,28 @@ 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
binding.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 {
@ -140,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
@ -189,6 +192,7 @@ 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) {
if (!event.readOnly)
view.findViewById<LinearLayout>(R.id.automation_layoutText).setOnClickListener { view.findViewById<LinearLayout>(R.id.automation_layoutText).setOnClickListener {
if (action.hasDialog()) { if (action.hasDialog()) {
val args = Bundle() val args = Bundle()
@ -199,11 +203,14 @@ class EditEventDialog : DialogFragmentWithDate() {
dialog.show(childFragmentManager, "EditActionDialog") dialog.show(childFragmentManager, "EditActionDialog")
} }
} }
view.findViewById<ImageView>(R.id.automation_iconTrash).setOnClickListener { view.findViewById<ImageView>(R.id.automation_iconTrash).run {
visibility = (!event.readOnly).toVisibility()
setOnClickListener {
event.actions.remove(action) event.actions.remove(action)
recyclerView.notifyDataSetChanged() recyclerView.notifyDataSetChanged()
rxBus.send(EventAutomationUpdateGui()) 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

@ -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)

View file

@ -1,5 +1,6 @@
package info.nightscout.androidaps.plugins.general.food package info.nightscout.androidaps.plugins.general.food
import android.annotation.SuppressLint
import android.content.DialogInterface import android.content.DialogInterface
import android.graphics.Paint import android.graphics.Paint
import android.os.Bundle import android.os.Bundle
@ -10,11 +11,12 @@ import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.AdapterView import android.widget.AdapterView
import android.widget.ArrayAdapter import android.widget.ArrayAdapter
import android.widget.TextView
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import dagger.android.support.DaggerFragment import dagger.android.support.DaggerFragment
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.databinding.FoodFragmentBinding
import info.nightscout.androidaps.databinding.FoodItemBinding
import info.nightscout.androidaps.events.EventFoodDatabaseChanged import info.nightscout.androidaps.events.EventFoodDatabaseChanged
import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.plugins.general.food.FoodFragment.RecyclerViewAdapter.FoodsViewHolder import info.nightscout.androidaps.plugins.general.food.FoodFragment.RecyclerViewAdapter.FoodsViewHolder
@ -24,7 +26,6 @@ import info.nightscout.androidaps.utils.alertDialogs.OKDialog.showConfirmation
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.food_fragment.*
import java.util.* import java.util.*
import javax.inject.Inject import javax.inject.Inject
import kotlin.collections.ArrayList import kotlin.collections.ArrayList
@ -41,24 +42,32 @@ class FoodFragment : DaggerFragment() {
private lateinit var unfiltered: List<Food> private lateinit var unfiltered: List<Food>
private lateinit var filtered: MutableList<Food> private lateinit var filtered: MutableList<Food>
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { private var _binding: FoodFragmentBinding? = null
return inflater.inflate(R.layout.food_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 = FoodFragmentBinding.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)
food_recyclerview.setHasFixedSize(true) binding.recyclerview.setHasFixedSize(true)
food_recyclerview.layoutManager = LinearLayoutManager(view.context) binding.recyclerview.layoutManager = LinearLayoutManager(view.context)
food_recyclerview.adapter = RecyclerViewAdapter(foodPlugin.service?.foodData ?: ArrayList()) binding.recyclerview.adapter = RecyclerViewAdapter(foodPlugin.service?.foodData
?: ArrayList())
food_clearfilter.setOnClickListener { binding.clearfilter.setOnClickListener {
food_filter.setText("") binding.filter.setText("")
food_category.setSelection(0) binding.category.setSelection(0)
food_subcategory.setSelection(0) binding.subcategory.setSelection(0)
filterData() filterData()
} }
food_category.onItemSelectedListener = object : AdapterView.OnItemSelectedListener { binding.category.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) {
fillSubcategories() fillSubcategories()
filterData() filterData()
@ -69,7 +78,7 @@ class FoodFragment : DaggerFragment() {
filterData() filterData()
} }
} }
food_subcategory.onItemSelectedListener = object : AdapterView.OnItemSelectedListener { binding.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()
} }
@ -78,7 +87,7 @@ class FoodFragment : DaggerFragment() {
filterData() filterData()
} }
} }
food_filter.addTextChangedListener(object : TextWatcher { binding.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) {
filterData() filterData()
@ -92,7 +101,8 @@ class FoodFragment : DaggerFragment() {
filterData() filterData()
} }
@Synchronized override fun onResume() { @Synchronized
override fun onResume() {
super.onResume() super.onResume()
disposable.add(rxBus disposable.add(rxBus
.toObservable(EventFoodDatabaseChanged::class.java) .toObservable(EventFoodDatabaseChanged::class.java)
@ -102,11 +112,18 @@ class FoodFragment : DaggerFragment() {
updateGui() updateGui()
} }
@Synchronized override fun onPause() { @Synchronized
override fun onPause() {
super.onPause() super.onPause()
disposable.clear() disposable.clear()
} }
@Synchronized
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
private fun loadData() { private fun loadData() {
unfiltered = foodPlugin.service?.foodData ?: ArrayList() unfiltered = foodPlugin.service?.foodData ?: ArrayList()
} }
@ -121,12 +138,12 @@ class FoodFragment : DaggerFragment() {
categories.add(0, resourceHelper.gs(R.string.none)) categories.add(0, resourceHelper.gs(R.string.none))
context?.let { context -> context?.let { context ->
val adapterCategories = ArrayAdapter(context, R.layout.spinner_centered, categories) val adapterCategories = ArrayAdapter(context, R.layout.spinner_centered, categories)
food_category.adapter = adapterCategories binding.category.adapter = adapterCategories
} }
} }
private fun fillSubcategories() { private fun fillSubcategories() {
val categoryFilter = food_category.selectedItem.toString() val categoryFilter = binding.category.selectedItem.toString()
val subCatSet: MutableSet<CharSequence> = HashSet() val subCatSet: MutableSet<CharSequence> = HashSet()
if (categoryFilter != resourceHelper.gs(R.string.none)) { if (categoryFilter != resourceHelper.gs(R.string.none)) {
for (f in unfiltered) { for (f in unfiltered) {
@ -138,65 +155,61 @@ class FoodFragment : DaggerFragment() {
subcategories.add(0, resourceHelper.gs(R.string.none)) subcategories.add(0, resourceHelper.gs(R.string.none))
context?.let { context -> context?.let { context ->
val adapterSubcategories = ArrayAdapter(context, R.layout.spinner_centered, subcategories) val adapterSubcategories = ArrayAdapter(context, R.layout.spinner_centered, subcategories)
food_subcategory.adapter = adapterSubcategories binding.subcategory.adapter = adapterSubcategories
} }
} }
private fun filterData() { private fun filterData() {
val textFilter = food_filter.text.toString() val textFilter = binding.filter.text.toString()
val categoryFilter = food_category.selectedItem.toString() val categoryFilter = binding.category.selectedItem.toString()
val subcategoryFilter = food_subcategory.selectedItem.toString() val subcategoryFilter = binding.subcategory.selectedItem.toString()
val newfiltered = ArrayList<Food>() val newFiltered = ArrayList<Food>()
for (f in unfiltered) { for (f in unfiltered) {
if (f.name == null || f.category == null || f.subcategory == null) continue if (f.name == null || f.category == null || f.subcategory == null) continue
if (subcategoryFilter != resourceHelper.gs(R.string.none) && f.subcategory != subcategoryFilter) continue if (subcategoryFilter != resourceHelper.gs(R.string.none) && f.subcategory != subcategoryFilter) continue
if (categoryFilter != resourceHelper.gs(R.string.none) && f.category != categoryFilter) continue if (categoryFilter != resourceHelper.gs(R.string.none) && f.category != categoryFilter) continue
if (textFilter != "" && !f.name.toLowerCase(Locale.getDefault()).contains(textFilter.toLowerCase(Locale.getDefault()))) continue if (textFilter != "" && !f.name.toLowerCase(Locale.getDefault()).contains(textFilter.toLowerCase(Locale.getDefault()))) continue
newfiltered.add(f) newFiltered.add(f)
} }
filtered = newfiltered filtered = newFiltered
updateGui() updateGui()
} }
protected fun updateGui() { private fun updateGui() {
food_recyclerview?.swapAdapter(RecyclerViewAdapter(filtered), true) binding.recyclerview.swapAdapter(RecyclerViewAdapter(filtered), true)
} }
inner class RecyclerViewAdapter internal constructor(var foodList: List<Food>) : RecyclerView.Adapter<FoodsViewHolder>() { inner class RecyclerViewAdapter internal constructor(var foodList: List<Food>) : RecyclerView.Adapter<FoodsViewHolder>() {
override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): FoodsViewHolder { override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): FoodsViewHolder {
val v = LayoutInflater.from(viewGroup.context).inflate(R.layout.food_item, viewGroup, false) val v = LayoutInflater.from(viewGroup.context).inflate(R.layout.food_item, viewGroup, false)
return FoodsViewHolder(v) return FoodsViewHolder(v)
} }
@SuppressLint("SetTextI18n")
override fun onBindViewHolder(holder: FoodsViewHolder, position: Int) { override fun onBindViewHolder(holder: FoodsViewHolder, position: Int) {
val food = foodList[position] val food = foodList[position]
holder.ns.visibility = if (food._id != null) View.VISIBLE else View.GONE holder.binding.nsSign.visibility = if (food._id != null) View.VISIBLE else View.GONE
holder.name.text = food.name holder.binding.name.text = food.name
holder.portion.text = food.portion.toString() + food.units holder.binding.portion.text = food.portion.toString() + food.units
holder.carbs.text = food.carbs.toString() + resourceHelper.gs(R.string.shortgramm) holder.binding.carbs.text = food.carbs.toString() + resourceHelper.gs(R.string.shortgramm)
holder.fat.text = resourceHelper.gs(R.string.shortfat) + ": " + food.fat + resourceHelper.gs(R.string.shortgramm) holder.binding.fat.text = resourceHelper.gs(R.string.shortfat) + ": " + food.fat + resourceHelper.gs(R.string.shortgramm)
if (food.fat == 0) holder.fat.visibility = View.INVISIBLE if (food.fat == 0) holder.binding.fat.visibility = View.INVISIBLE
holder.protein.text = resourceHelper.gs(R.string.shortprotein) + ": " + food.protein + resourceHelper.gs(R.string.shortgramm) holder.binding.protein.text = resourceHelper.gs(R.string.shortprotein) + ": " + food.protein + resourceHelper.gs(R.string.shortgramm)
if (food.protein == 0) holder.protein.visibility = View.INVISIBLE if (food.protein == 0) holder.binding.protein.visibility = View.INVISIBLE
holder.energy.text = resourceHelper.gs(R.string.shortenergy) + ": " + food.energy + resourceHelper.gs(R.string.shortkilojoul) holder.binding.energy.text = resourceHelper.gs(R.string.shortenergy) + ": " + food.energy + resourceHelper.gs(R.string.shortkilojoul)
if (food.energy == 0) holder.energy.visibility = View.INVISIBLE if (food.energy == 0) holder.binding.energy.visibility = View.INVISIBLE
holder.remove.tag = food holder.binding.remove.tag = food
} }
override fun getItemCount(): Int = foodList.size override fun getItemCount(): Int = foodList.size
inner class FoodsViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { inner class FoodsViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
var name: TextView = itemView.findViewById(R.id.food_name)
var portion: TextView = itemView.findViewById(R.id.food_portion) val binding = FoodItemBinding.bind(itemView)
var carbs: TextView = itemView.findViewById(R.id.food_carbs)
var fat: TextView = itemView.findViewById(R.id.food_fat)
var protein: TextView = itemView.findViewById(R.id.food_protein)
var energy: TextView = itemView.findViewById(R.id.food_energy)
var ns: TextView = itemView.findViewById(R.id.ns_sign)
var remove: TextView = itemView.findViewById(R.id.food_remove)
init { init {
remove.setOnClickListener { v: View -> binding.remove.setOnClickListener { v: View ->
val food = v.tag as Food val food = v.tag as Food
activity?.let { activity -> activity?.let { activity ->
showConfirmation(activity, resourceHelper.gs(R.string.confirmation), resourceHelper.gs(R.string.removerecord) + "\n" + food.name, DialogInterface.OnClickListener { _: DialogInterface?, _: Int -> showConfirmation(activity, resourceHelper.gs(R.string.confirmation), resourceHelper.gs(R.string.removerecord) + "\n" + food.name, DialogInterface.OnClickListener { _: DialogInterface?, _: Int ->
@ -207,7 +220,7 @@ class FoodFragment : DaggerFragment() {
}, null) }, null)
} }
} }
remove.paintFlags = remove.paintFlags or Paint.UNDERLINE_TEXT_FLAG binding.remove.paintFlags = binding.remove.paintFlags or Paint.UNDERLINE_TEXT_FLAG
} }
} }
} }

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

@ -12,11 +12,12 @@ 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.DaggerAppCompatActivityWithResult
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.interfaces.ConfigInterface
import info.nightscout.androidaps.interfaces.ImportExportPrefsInterface
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
@ -39,6 +40,7 @@ import java.io.IOException
import java.util.* import java.util.*
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
import kotlin.system.exitProcess
/** /**
* Created by mike on 03.07.2016. * Created by mike on 03.07.2016.
@ -52,31 +54,30 @@ 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 config: ConfigInterface,
private val androidPermission: AndroidPermission, 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
) { ) : ImportExportPrefsInterface {
val TAG = LTag.CORE override fun prefsFileExists(): Boolean {
fun prefsFileExists(): Boolean {
return prefFileList.listPreferenceFiles().size > 0 return prefFileList.listPreferenceFiles().size > 0
} }
fun exportSharedPreferences(f: Fragment) { override fun exportSharedPreferences(f: Fragment) {
f.activity?.let { exportSharedPreferences(it) } f.activity?.let { exportSharedPreferences(it) }
} }
fun verifyStoragePermissions(fragment: Fragment, onGranted: Runnable) { override fun verifyStoragePermissions(fragment: Fragment, onGranted: Runnable) {
fragment.context?.let { ctx -> fragment.context?.let { ctx ->
val permission = ContextCompat.checkSelfPermission(ctx, 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.activity?.let { fragment.activity?.let {
androidPermission.askForPermission(it, arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE, androidPermission.askForPermission(it,
Manifest.permission.WRITE_EXTERNAL_STORAGE), AndroidPermission.CASE_STORAGE) arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE))
} }
} else { } else {
onGranted.run() onGranted.run()
@ -92,7 +93,7 @@ class ImportExportPrefs @Inject constructor(
metadata[PrefsMetadataKey.CREATED_AT] = PrefMetadata(DateUtil.toISOString(Date()), PrefsStatus.OK) metadata[PrefsMetadataKey.CREATED_AT] = PrefMetadata(DateUtil.toISOString(Date()), PrefsStatus.OK)
metadata[PrefsMetadataKey.AAPS_VERSION] = PrefMetadata(BuildConfig.VERSION_NAME, PrefsStatus.OK) metadata[PrefsMetadataKey.AAPS_VERSION] = PrefMetadata(BuildConfig.VERSION_NAME, PrefsStatus.OK)
metadata[PrefsMetadataKey.AAPS_FLAVOUR] = PrefMetadata(BuildConfig.FLAVOR, PrefsStatus.OK) metadata[PrefsMetadataKey.AAPS_FLAVOUR] = PrefMetadata(BuildConfig.FLAVOR, PrefsStatus.OK)
metadata[PrefsMetadataKey.DEVICE_MODEL] = PrefMetadata(getCurrentDeviceModelString(), PrefsStatus.OK) metadata[PrefsMetadataKey.DEVICE_MODEL] = PrefMetadata(config.currentDeviceModelString, PrefsStatus.OK)
if (prefsEncryptionIsDisabled()) { if (prefsEncryptionIsDisabled()) {
metadata[PrefsMetadataKey.ENCRYPTION] = PrefMetadata("Disabled", PrefsStatus.DISABLED) metadata[PrefsMetadataKey.ENCRYPTION] = PrefMetadata("Disabled", PrefsStatus.DISABLED)
@ -118,12 +119,11 @@ class ImportExportPrefs @Inject constructor(
// name we detect from OS // name we detect from OS
val systemName = n1 ?: n2 ?: n3 ?: n4 ?: n5 ?: n6 ?: defaultPatientName val systemName = n1 ?: n2 ?: n3 ?: n4 ?: n5 ?: n6 ?: defaultPatientName
val name = if (patientName.isNotEmpty() && patientName != defaultPatientName) patientName else systemName return if (patientName.isNotEmpty() && patientName != defaultPatientName) patientName else systemName
return name
} }
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: FragmentActivity, @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 ->
@ -133,6 +133,7 @@ class ImportExportPrefs @Inject constructor(
}) })
} }
@Suppress("SameParameterValue")
private fun askForEncryptionPass(activity: FragmentActivity, @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 ->
@ -142,6 +143,7 @@ class ImportExportPrefs @Inject constructor(
}) })
} }
@Suppress("SameParameterValue")
private fun askForMasterPassIfNeeded(activity: FragmentActivity, @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("")
@ -238,47 +240,45 @@ class ImportExportPrefs @Inject constructor(
ToastUtils.okToast(activity, resourceHelper.gs(R.string.exported)) ToastUtils.okToast(activity, resourceHelper.gs(R.string.exported))
} catch (e: FileNotFoundException) { } catch (e: FileNotFoundException) {
ToastUtils.errorToast(activity, resourceHelper.gs(R.string.filenotfound) + " " + newFile) ToastUtils.errorToast(activity, resourceHelper.gs(R.string.filenotfound) + " " + newFile)
log.error(TAG, "Unhandled exception", e) log.error(LTag.CORE, "Unhandled exception", e)
} catch (e: IOException) { } catch (e: IOException) {
ToastUtils.errorToast(activity, e.message) ToastUtils.errorToast(activity, e.message)
log.error(TAG, "Unhandled exception", e) log.error(LTag.CORE, "Unhandled exception", e)
} catch (e: PrefFileNotFoundError) { } catch (e: PrefFileNotFoundError) {
ToastUtils.Long.errorToast(activity, resourceHelper.gs(R.string.preferences_export_canceled) ToastUtils.Long.errorToast(activity, resourceHelper.gs(R.string.preferences_export_canceled)
+ "\n\n" + resourceHelper.gs(R.string.filenotfound) + "\n\n" + resourceHelper.gs(R.string.filenotfound)
+ ": " + e.message + ": " + e.message
+ "\n\n" + resourceHelper.gs(R.string.needstoragepermission)) + "\n\n" + resourceHelper.gs(R.string.needstoragepermission))
log.error(TAG, "File system exception", e) log.error(LTag.CORE, "File system exception", e)
} catch (e: PrefIOError) { } catch (e: PrefIOError) {
ToastUtils.Long.errorToast(activity, resourceHelper.gs(R.string.preferences_export_canceled) ToastUtils.Long.errorToast(activity, resourceHelper.gs(R.string.preferences_export_canceled)
+ "\n\n" + resourceHelper.gs(R.string.needstoragepermission) + "\n\n" + resourceHelper.gs(R.string.needstoragepermission)
+ ": " + e.message) + ": " + e.message)
log.error(TAG, "File system exception", e) log.error(LTag.CORE, "File system exception", e)
} }
} }
} }
fun importSharedPreferences(fragment: Fragment) { override fun importSharedPreferences(fragment: Fragment) {
fragment.activity?.let { fragmentAct -> fragment.activity?.let { fragmentAct ->
importSharedPreferences(fragmentAct) importSharedPreferences(fragmentAct)
} }
} }
fun importSharedPreferences(activity: FragmentActivity) { override fun importSharedPreferences(activity: FragmentActivity) {
try { try {
if (activity is SingleFragmentActivity) if (activity is DaggerAppCompatActivityWithResult)
activity.callForPrefFile.launch(null)
if (activity is MainActivity)
activity.callForPrefFile.launch(null) 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
ToastUtils.errorToast(activity, resourceHelper.gs(R.string.goto_main_try_again)) ToastUtils.errorToast(activity, resourceHelper.gs(R.string.goto_main_try_again))
log.error(TAG, "Internal android framework exception", e) log.error(LTag.CORE, "Internal android framework exception", e)
} }
} }
fun importSharedPreferences(activity: FragmentActivity, importFile: PrefsFile) { override fun importSharedPreferences(activity: FragmentActivity, importFile: PrefsFile) {
askToConfirmImport(activity, importFile) { password -> askToConfirmImport(activity, importFile) { password ->
@ -298,7 +298,7 @@ class ImportExportPrefs @Inject constructor(
promptForDecryptionPasswordIfNeeded(activity, prefsAttempted, importOkAttempted, format, importFile) { prefs, importOk -> promptForDecryptionPasswordIfNeeded(activity, prefsAttempted, importOkAttempted, format, importFile) { prefs, importOk ->
// if at end we allow to import preferences // if at end we allow to import preferences
val importPossible = (importOk || buildHelper.isEngineeringMode()) && (prefs.values.size > 0) val importPossible = (importOk || buildHelper.isEngineeringMode()) && (prefs.values.isNotEmpty())
PrefImportSummaryDialog.showSummary(activity, importOk, importPossible, prefs, { PrefImportSummaryDialog.showSummary(activity, importOk, importPossible, prefs, {
if (importPossible) { if (importPossible) {
@ -322,9 +322,9 @@ class ImportExportPrefs @Inject constructor(
} catch (e: PrefFileNotFoundError) { } catch (e: PrefFileNotFoundError) {
ToastUtils.errorToast(activity, resourceHelper.gs(R.string.filenotfound) + " " + importFile) ToastUtils.errorToast(activity, resourceHelper.gs(R.string.filenotfound) + " " + importFile)
log.error(TAG, "Unhandled exception", e) log.error(LTag.CORE, "Unhandled exception", e)
} catch (e: PrefIOError) { } catch (e: PrefIOError) {
log.error(TAG, "Unhandled exception", e) log.error(LTag.CORE, "Unhandled exception", e)
ToastUtils.errorToast(activity, e.message) ToastUtils.errorToast(activity, e.message)
} }
} }
@ -343,13 +343,13 @@ class ImportExportPrefs @Inject constructor(
private fun restartAppAfterImport(context: Context) { private fun restartAppAfterImport(context: Context) {
sp.putBoolean(R.string.key_setupwizard_processed, true) sp.putBoolean(R.string.key_setupwizard_processed, true)
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(LTag.CORE, "Exiting")
rxBus.send(EventAppExit()) rxBus.send(EventAppExit())
if (context is AppCompatActivity) { if (context is AppCompatActivity) {
context.finish() context.finish()
} }
System.runFinalization() System.runFinalization()
System.exit(0) exitProcess(0)
}) })
} }
} }

View file

@ -8,12 +8,13 @@ import android.view.ViewGroup
import dagger.android.support.DaggerFragment import dagger.android.support.DaggerFragment
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.MaintenanceFragmentBinding
import info.nightscout.androidaps.interfaces.ImportExportPrefsInterface
import info.nightscout.androidaps.plugins.general.food.FoodPlugin import info.nightscout.androidaps.plugins.general.food.FoodPlugin
import info.nightscout.androidaps.plugins.general.maintenance.activities.LogSettingActivity import info.nightscout.androidaps.plugins.general.maintenance.activities.LogSettingActivity
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin
import info.nightscout.androidaps.utils.alertDialogs.OKDialog 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.maintenance_fragment.*
import javax.inject.Inject import javax.inject.Inject
class MaintenanceFragment : DaggerFragment() { class MaintenanceFragment : DaggerFragment() {
@ -23,17 +24,24 @@ class MaintenanceFragment : DaggerFragment() {
@Inject lateinit var resourceHelper: ResourceHelper @Inject lateinit var resourceHelper: ResourceHelper
@Inject lateinit var treatmentsPlugin: TreatmentsPlugin @Inject lateinit var treatmentsPlugin: TreatmentsPlugin
@Inject lateinit var foodPlugin: FoodPlugin @Inject lateinit var foodPlugin: FoodPlugin
@Inject lateinit var importExportPrefs: ImportExportPrefs @Inject lateinit var importExportPrefs: ImportExportPrefsInterface
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { private var _binding: MaintenanceFragmentBinding? = null
return inflater.inflate(R.layout.maintenance_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 = MaintenanceFragmentBinding.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)
log_send.setOnClickListener { maintenancePlugin.sendLogs() } binding.logSend.setOnClickListener { maintenancePlugin.sendLogs() }
log_delete.setOnClickListener { maintenancePlugin.deleteLogs() } binding.logDelete.setOnClickListener { maintenancePlugin.deleteLogs() }
nav_resetdb.setOnClickListener { binding.navResetdb.setOnClickListener {
activity?.let { activity -> activity?.let { activity ->
OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.maintenance), resourceHelper.gs(R.string.reset_db_confirm), Runnable { OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.maintenance), resourceHelper.gs(R.string.reset_db_confirm), Runnable {
MainApp.getDbHelper().resetDatabases() MainApp.getDbHelper().resetDatabases()
@ -44,18 +52,24 @@ class MaintenanceFragment : DaggerFragment() {
}) })
} }
} }
nav_export.setOnClickListener { binding.navExport.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 { binding.navImport.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)) } binding.navLogsettings.setOnClickListener { startActivity(Intent(activity, LogSettingActivity::class.java)) }
}
@Synchronized
override fun onDestroyView() {
super.onDestroyView()
_binding = null
} }
} }

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

@ -7,37 +7,41 @@ import android.widget.LinearLayout
import android.widget.TextView import android.widget.TextView
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.activities.NoSplashAppCompatActivity import info.nightscout.androidaps.activities.NoSplashAppCompatActivity
import info.nightscout.androidaps.databinding.ActivityLogsettingBinding
import info.nightscout.androidaps.logging.L import info.nightscout.androidaps.logging.L
import kotlinx.android.synthetic.main.activity_logsetting.*
import javax.inject.Inject import javax.inject.Inject
class LogSettingActivity : NoSplashAppCompatActivity() { class LogSettingActivity : NoSplashAppCompatActivity() {
@Inject lateinit var l :L @Inject lateinit var l: L
private lateinit var binding: ActivityLogsettingBinding
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setContentView(R.layout.activity_logsetting) binding = ActivityLogsettingBinding.inflate(layoutInflater)
setContentView(binding.root)
createViewsForSettings() createViewsForSettings()
logsettings_reset.setOnClickListener { binding.reset.setOnClickListener {
l.resetToDefaults() l.resetToDefaults()
createViewsForSettings() createViewsForSettings()
} }
ok.setOnClickListener { finish() } binding.ok.setOnClickListener { finish() }
} }
private fun createViewsForSettings() { private fun createViewsForSettings() {
logsettings_placeholder.removeAllViews() binding.placeholder.removeAllViews()
for (element in l.getLogElements()) { for (element in l.getLogElements()) {
val logViewHolder = LogViewHolder(element) val logViewHolder = LogViewHolder(element)
logsettings_placeholder.addView(logViewHolder.baseView) binding.placeholder.addView(logViewHolder.baseView)
} }
} }
internal inner class LogViewHolder(element: L.LogElement) { internal inner class LogViewHolder(element: L.LogElement) {
@Suppress("InflateParams") @Suppress("InflateParams")
var baseView = layoutInflater.inflate(R.layout.logsettings_item, null) as LinearLayout var baseView = layoutInflater.inflate(R.layout.logsettings_item, null) as LinearLayout

View file

@ -1,135 +0,0 @@
package info.nightscout.androidaps.plugins.general.maintenance.activities
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.view.LayoutInflater
import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.fragment.app.FragmentActivity
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import dagger.android.support.DaggerAppCompatActivity
import info.nightscout.androidaps.R
import info.nightscout.androidaps.plugins.general.maintenance.PrefFileListProvider
import info.nightscout.androidaps.plugins.general.maintenance.PrefsFile
import info.nightscout.androidaps.plugins.general.maintenance.PrefsFileContract
import info.nightscout.androidaps.plugins.general.maintenance.formats.PrefsFormatsHandler
import info.nightscout.androidaps.plugins.general.maintenance.formats.PrefsMetadataKey
import info.nightscout.androidaps.plugins.general.maintenance.formats.PrefsStatus
import info.nightscout.androidaps.utils.locale.LocaleHelper
import info.nightscout.androidaps.utils.resources.ResourceHelper
import kotlinx.android.synthetic.main.maintenance_importlist_activity.*
import javax.inject.Inject
class PrefImportListActivity : DaggerAppCompatActivity() {
@Inject lateinit var resourceHelper: ResourceHelper
@Inject lateinit var prefFileListProvider: PrefFileListProvider
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setTheme(R.style.AppTheme)
setContentView(R.layout.maintenance_importlist_activity)
title = resourceHelper.gs(R.string.preferences_import_list_title)
supportActionBar?.setDisplayHomeAsUpEnabled(true)
supportActionBar?.setDisplayShowHomeEnabled(true)
supportActionBar?.setDisplayShowTitleEnabled(true)
importlist_recyclerview.layoutManager = LinearLayoutManager(this)
importlist_recyclerview.adapter = RecyclerViewAdapter(prefFileListProvider.listPreferenceFiles(loadMetadata = true))
}
inner class RecyclerViewAdapter internal constructor(private var prefFileList: List<PrefsFile>) : RecyclerView.Adapter<RecyclerViewAdapter.PrefFileViewHolder>() {
inner class PrefFileViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
var fileName: TextView = itemView.findViewById(R.id.filelist_name)
var fileDir: TextView = itemView.findViewById(R.id.filelist_dir)
var metaDateTime: TextView = itemView.findViewById(R.id.meta_date_time)
var metaDeviceName: TextView = itemView.findViewById(R.id.meta_device_name)
var metaAppVersion: TextView = itemView.findViewById(R.id.meta_app_version)
var metaVariantFormat: TextView = itemView.findViewById(R.id.meta_variant_format)
var metalineName: View = itemView.findViewById(R.id.metaline_name)
var metaDateTimeIcon: View = itemView.findViewById(R.id.meta_date_time_icon)
init {
itemView.isClickable = true
itemView.setOnClickListener {
val prefFile = fileName.tag as PrefsFile
val i = Intent()
i.putExtra(PrefsFileContract.OUTPUT_PARAM, prefFile)
setResult(FragmentActivity.RESULT_OK, i)
finish()
}
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PrefFileViewHolder {
val v = LayoutInflater.from(parent.context).inflate(R.layout.maintenance_importlist_item, parent, false)
return PrefFileViewHolder(v)
}
override fun getItemCount(): Int {
return prefFileList.size
}
override fun onBindViewHolder(holder: PrefFileViewHolder, position: Int) {
val prefFile = prefFileList[position]
holder.fileName.text = prefFile.file.name
holder.fileName.tag = prefFile
holder.fileDir.text = resourceHelper.gs(R.string.in_directory, prefFile.file.parentFile.absolutePath)
val visible = if (prefFile.handler == PrefsFormatsHandler.CLASSIC) View.GONE else View.VISIBLE
holder.metalineName.visibility = visible
holder.metaDateTimeIcon.visibility = visible
holder.metaAppVersion.visibility = visible
if (prefFile.handler == PrefsFormatsHandler.CLASSIC) {
holder.metaVariantFormat.text = resourceHelper.gs(R.string.metadata_format_old)
holder.metaVariantFormat.setTextColor(resourceHelper.gc(R.color.metadataTextWarning))
holder.metaDateTime.text = " "
} else {
prefFile.metadata[PrefsMetadataKey.AAPS_FLAVOUR]?.let {
holder.metaVariantFormat.text = it.value
val color = if (it.status == PrefsStatus.OK) R.color.metadataOk else R.color.metadataTextWarning
holder.metaVariantFormat.setTextColor(resourceHelper.gc(color))
}
prefFile.metadata[PrefsMetadataKey.CREATED_AT]?.let {
holder.metaDateTime.text = prefFileListProvider.formatExportedAgo(it.value)
}
prefFile.metadata[PrefsMetadataKey.AAPS_VERSION]?.let {
holder.metaAppVersion.text = it.value
val color = if (it.status == PrefsStatus.OK) R.color.metadataOk else R.color.metadataTextWarning
holder.metaAppVersion.setTextColor(resourceHelper.gc(color))
}
prefFile.metadata[PrefsMetadataKey.DEVICE_NAME]?.let {
holder.metaDeviceName.text = it.value
}
}
}
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
if (item.itemId == android.R.id.home) {
finish()
return true
}
return false
}
public override fun attachBaseContext(newBase: Context) {
super.attachBaseContext(LocaleHelper.wrap(newBase))
}
}

View file

@ -44,6 +44,7 @@ import info.nightscout.androidaps.plugins.general.nsclient.services.NSClientServ
import info.nightscout.androidaps.utils.FabricPrivacy; import info.nightscout.androidaps.utils.FabricPrivacy;
import info.nightscout.androidaps.utils.HtmlHelper; import info.nightscout.androidaps.utils.HtmlHelper;
import info.nightscout.androidaps.utils.ToastUtils; import info.nightscout.androidaps.utils.ToastUtils;
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;
import io.reactivex.disposables.CompositeDisposable; import io.reactivex.disposables.CompositeDisposable;
@ -60,6 +61,7 @@ public class NSClientPlugin extends PluginBase {
private final FabricPrivacy fabricPrivacy; private final FabricPrivacy fabricPrivacy;
private final SP sp; private final SP sp;
private final Config config; private final Config config;
private final BuildHelper buildHelper;
public Handler handler; public Handler handler;
@ -85,11 +87,13 @@ public class NSClientPlugin extends PluginBase {
FabricPrivacy fabricPrivacy, FabricPrivacy fabricPrivacy,
SP sp, SP sp,
NsClientReceiverDelegate nsClientReceiverDelegate, NsClientReceiverDelegate nsClientReceiverDelegate,
Config config Config config,
BuildHelper buildHelper
) { ) {
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)
@ -105,6 +109,7 @@ public class NSClientPlugin extends PluginBase {
this.sp = sp; this.sp = sp;
this.nsClientReceiverDelegate = nsClientReceiverDelegate; this.nsClientReceiverDelegate = nsClientReceiverDelegate;
this.config = config; this.config = config;
this.buildHelper = buildHelper;
if (config.getNSCLIENT()) { if (config.getNSCLIENT()) {
getPluginDescription().alwaysEnabled(true).visibleByDefault(true); getPluginDescription().alwaysEnabled(true).visibleByDefault(true);
@ -196,9 +201,11 @@ public class NSClientPlugin extends PluginBase {
SwitchPreference key_ns_autobackfill = preferenceFragment.findPreference(resourceHelper.gs(R.string.key_ns_autobackfill)); SwitchPreference key_ns_autobackfill = preferenceFragment.findPreference(resourceHelper.gs(R.string.key_ns_autobackfill));
if (key_ns_autobackfill != null) key_ns_autobackfill.setVisible(false); 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)); 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); 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)); 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); 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)); SwitchPreference key_ns_upload_only = preferenceFragment.findPreference(resourceHelper.gs(R.string.key_ns_upload_only));
if (key_ns_upload_only != null) { if (key_ns_upload_only != null) {
key_ns_upload_only.setVisible(false); key_ns_upload_only.setVisible(false);
@ -206,6 +213,11 @@ public class NSClientPlugin extends PluginBase {
} }
SwitchPreference key_ns_sync_use_absolute = preferenceFragment.findPreference(resourceHelper.gs(R.string.key_ns_sync_use_absolute)); 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); if (key_ns_sync_use_absolute != null) key_ns_sync_use_absolute.setVisible(false);
} else {
// APS or pumpcontrol mode
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(buildHelper.isEngineeringMode());
} }
} }

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)
@ -84,6 +85,7 @@ class OpenHumansUploader @Inject constructor(
} }
private val openHumansAPI = OpenHumansAPI(OPEN_HUMANS_URL, CLIENT_ID, CLIENT_SECRET, REDIRECT_URL) private val openHumansAPI = OpenHumansAPI(OPEN_HUMANS_URL, CLIENT_ID, CLIENT_SECRET, REDIRECT_URL)
@Suppress("PrivatePropertyName")
private val FILE_NAME_DATE_FORMAT = SimpleDateFormat("yyyyMMdd'T'HHmmss", Locale.US).apply { timeZone = TimeZone.getTimeZone("UTC") } private val FILE_NAME_DATE_FORMAT = SimpleDateFormat("yyyyMMdd'T'HHmmss", Locale.US).apply { timeZone = TimeZone.getTimeZone("UTC") }
private var isSetup private var isSetup
@ -125,12 +127,12 @@ class OpenHumansUploader @Inject constructor(
private val appId: UUID private val appId: UUID
get() { get() {
val id = sp.getStringOrNull("openhumans_appid", null) val id = sp.getStringOrNull("openhumans_appid", null)
if (id == null) { return if (id == null) {
val generated = UUID.randomUUID() val generated = UUID.randomUUID()
sp.putString("openhumans_appid", generated.toString()) sp.putString("openhumans_appid", generated.toString())
return generated generated
} else { } else {
return UUID.fromString(id) UUID.fromString(id)
} }
} }
@ -139,7 +141,7 @@ class OpenHumansUploader @Inject constructor(
private val wakeLock = (context.getSystemService(Context.POWER_SERVICE) as PowerManager) private val wakeLock = (context.getSystemService(Context.POWER_SERVICE) as PowerManager)
.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "AndroidAPS::OpenHumans") .newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "AndroidAPS::OpenHumans")
val preferenceChangeDisposable = CompositeDisposable() private val preferenceChangeDisposable = CompositeDisposable()
override fun onStart() { override fun onStart() {
super.onStart() super.onStart()
@ -452,7 +454,8 @@ class OpenHumansUploader @Inject constructor(
aapsLogger.error(LTag.OHUPLOADER, "Segmental upload exceptional", it) aapsLogger.error(LTag.OHUPLOADER, "Segmental upload exceptional", it)
} }
fun uploadData(maxEntries: Long?): Completable = gatherData(maxEntries) @Suppress("SameParameterValue")
private fun uploadData(maxEntries: Long?): Completable = gatherData(maxEntries)
.flatMap { data -> refreshAccessTokensIfNeeded().map { accessToken -> accessToken to data } } .flatMap { data -> refreshAccessTokensIfNeeded().map { accessToken -> accessToken to data } }
.flatMap { uploadFile(it.first, it.second).andThen(Single.just(it.second)) } .flatMap { uploadFile(it.first, it.second).andThen(Single.just(it.second)) }
.flatMapCompletable { .flatMapCompletable {
@ -615,7 +618,6 @@ class OpenHumansUploader @Inject constructor(
} }
private fun setupNotificationChannel() { private fun setupNotificationChannel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val notificationManagerCompat = NotificationManagerCompat.from(context) val notificationManagerCompat = NotificationManagerCompat.from(context)
notificationManagerCompat.createNotificationChannel(NotificationChannel( notificationManagerCompat.createNotificationChannel(NotificationChannel(
NOTIFICATION_CHANNEL, NOTIFICATION_CHANNEL,
@ -623,7 +625,6 @@ class OpenHumansUploader @Inject constructor(
NotificationManager.IMPORTANCE_DEFAULT NotificationManager.IMPORTANCE_DEFAULT
)) ))
} }
}
private class UploadData( private class UploadData(
val fileName: String, val fileName: String,
@ -632,6 +633,7 @@ class OpenHumansUploader @Inject constructor(
val highestQueueId: Long? val highestQueueId: Long?
) )
@Suppress("PrivatePropertyName")
private val HEX_DIGITS = "0123456789ABCDEF".toCharArray() private val HEX_DIGITS = "0123456789ABCDEF".toCharArray()
private fun ByteArray.toHexString(): String { private fun ByteArray.toHexString(): String {

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
@ -31,11 +28,7 @@ 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.* import info.nightscout.androidaps.interfaces.*
import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.AAPSLogger
@ -72,8 +65,7 @@ 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_fragment.overview_notifications import kotlinx.android.synthetic.main.overview_fragment.*
import kotlinx.android.synthetic.main.overview_fragment_nsclient.*
import kotlinx.android.synthetic.main.overview_graphs_layout.* import kotlinx.android.synthetic.main.overview_graphs_layout.*
import kotlinx.android.synthetic.main.overview_info_layout.* import kotlinx.android.synthetic.main.overview_info_layout.*
import kotlinx.android.synthetic.main.overview_loop_pumpstatus_layout.* import kotlinx.android.synthetic.main.overview_loop_pumpstatus_layout.*
@ -145,20 +137,21 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
dm = DisplayMetrics() dm = DisplayMetrics()
activity?.windowManager?.defaultDisplay?.getMetrics(dm) activity?.windowManager?.defaultDisplay?.getMetrics(dm)
val screenWidth = dm.widthPixels return inflater.inflate(R.layout.overview_fragment, container, false)
val screenHeight = dm.heightPixels
smallWidth = screenWidth <= Constants.SMALL_WIDTH
smallHeight = screenHeight <= Constants.SMALL_HEIGHT
val landscape = screenHeight < screenWidth
return inflater.inflate(skinProvider.activeSkin().overviewLayout(landscape, resourceHelper.gb(R.bool.isTablet), smallHeight), container, false)
} }
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 // pre-process landscape mode
skinProvider.activeSkin().preProcessLandscapeOverviewLayout(dm, view, resourceHelper.gb(R.bool.isTablet)) val screenWidth = dm.widthPixels
val screenHeight = dm.heightPixels
smallWidth = screenWidth <= Constants.SMALL_WIDTH
smallHeight = screenHeight <= Constants.SMALL_HEIGHT
val landscape = screenHeight < screenWidth
skinProvider.activeSkin().preProcessLandscapeOverviewLayout(dm, view, landscape, resourceHelper.gb(R.bool.isTablet), smallHeight)
nsclient_layout?.visibility = config.NSCLIENT.toVisibility()
overview_pumpstatus?.setBackgroundColor(resourceHelper.gc(R.color.colorInitializingBorder)) overview_pumpstatus?.setBackgroundColor(resourceHelper.gc(R.color.colorInitializingBorder))
@ -184,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)
@ -196,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() {
@ -213,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) })
@ -276,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 { TreatmentDialog().show(childFragmentManager, "Overview") }) R.id.overview_treatmentbutton -> protectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, UIRunnable { if(isAdded) TreatmentDialog().show(childFragmentManager, "Overview") })
R.id.overview_wizardbutton -> protectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, UIRunnable { WizardDialog().show(childFragmentManager, "Overview") }) R.id.overview_wizardbutton -> protectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, UIRunnable { if(isAdded) WizardDialog().show(childFragmentManager, "Overview") })
R.id.overview_insulinbutton -> protectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, UIRunnable { InsulinDialog().show(childFragmentManager, "Overview") }) R.id.overview_insulinbutton -> protectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, UIRunnable { if(isAdded) InsulinDialog().show(childFragmentManager, "Overview") })
R.id.overview_quickwizardbutton -> protectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, UIRunnable { onClickQuickWizard() }) R.id.overview_quickwizardbutton -> protectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, UIRunnable { if(isAdded) onClickQuickWizard() })
R.id.overview_carbsbutton -> protectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, UIRunnable { CarbsDialog().show(childFragmentManager, "Overview") }) R.id.overview_carbsbutton -> protectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, UIRunnable { if(isAdded) CarbsDialog().show(childFragmentManager, "Overview") })
R.id.overview_temptarget -> protectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, UIRunnable { if(isAdded) TempTargetDialog().show(childFragmentManager, "Overview") })
R.id.overview_activeprofile -> {
ProfileViewerDialog().also { pvd ->
pvd.arguments = Bundle().also {
it.putLong("time", DateUtil.now())
it.putInt("mode", ProfileViewerDialog.Mode.RUNNING_PROFILE.ordinal)
}
}.show(childFragmentManager, "ProfileViewDialog")
}
R.id.overview_cgmbutton -> { R.id.overview_cgmbutton -> {
if (xdripPlugin.isEnabled(PluginType.BGSOURCE)) if (xdripPlugin.isEnabled(PluginType.BGSOURCE))
@ -335,6 +329,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
val lastRun = loopPlugin.lastRun val lastRun = loopPlugin.lastRun
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) {
protectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, UIRunnable {
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(), { ?: "".toSpanned(), {
aapsLogger.debug("USER ENTRY: ACCEPT TEMP BASAL") aapsLogger.debug("USER ENTRY: ACCEPT TEMP BASAL")
@ -343,9 +338,18 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
actionStringHandler.handleInitiate("cancelChangeRequest") actionStringHandler.handleInitiate("cancelChangeRequest")
loopPlugin.acceptChangeRequest() loopPlugin.acceptChangeRequest()
}) })
})
} }
} }
} }
R.id.overview_apsmode -> {
protectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, UIRunnable {
if(isAdded) LoopDialog().also { dialog ->
dialog.arguments = Bundle().also { it.putInt("showOkCancel", 1) }
}.show(childFragmentManager, "Overview")
})
}
} }
} }
} }
@ -370,6 +374,20 @@ 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 -> {
activity?.let { activity ->
protectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, UIRunnable {
LoopDialog().also { dialog ->
dialog.arguments = Bundle().also { it.putInt("showOkCancel", 0) }
}.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
} }
@ -456,10 +474,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
@ -785,6 +801,8 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
private fun updateGraph(lastRun: LoopInterface.LastRun?, predictionsAvailable: Boolean, lowLine: Double, highLine: Double, pump: PumpInterface, profile: Profile) { private fun updateGraph(lastRun: LoopInterface.LastRun?, predictionsAvailable: Boolean, lowLine: Double, highLine: Double, pump: PumpInterface, profile: Profile) {
viewLifecycleOwner.lifecycleScope.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()
@ -802,7 +820,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)
@ -824,20 +842,23 @@ 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)
// set manual x bounds to have nice steps
graphData.formatAxis(fromTime, endTime)
// Treatments // Treatments
graphData.addTreatments(fromTime, endTime) graphData.addTreatments(fromTime, endTime)
if (overviewMenus.setting[0][OverviewMenus.CharType.ACT.ordinal])
// set manual x bounds to have nice steps
graphData.setNumVerticalLables()
graphData.formatAxis(fromTime, endTime)
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
@ -848,7 +869,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
@ -858,22 +879,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)
@ -885,16 +906,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.ProfileFunction
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.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,23 @@ 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 settingsCopy = setting
val numOfGraphs = settingsCopy.size // 1 main + x secondary
chartButton.setOnClickListener { v: View -> chartButton.setOnClickListener { v: View ->
val predictionsAvailable: Boolean = when { val predictionsAvailable: Boolean = when {
@ -124,7 +101,7 @@ class OverviewMenus @Inject constructor(
for (g in 0 until numOfGraphs) { for (g in 0 until numOfGraphs) {
if (g != 0 && g < numOfGraphs) { if (g != 0 && g < numOfGraphs) {
val dividerItem = popup.menu.add(Menu.NONE, g, Menu.NONE, "------- " + "Graph" + " " + g + " -------") val dividerItem = popup.menu.add(Menu.NONE, g, Menu.NONE, "------- ${resourceHelper.gs(R.string.graph_menu_divider_header)} $g -------")
dividerItem.isCheckable = true dividerItem.isCheckable = true
dividerItem.isChecked = true dividerItem.isChecked = true
} }
@ -141,12 +118,12 @@ 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 = settingsCopy[g][m.ordinal]
} }
} }
} }
if (numOfGraphs < MAX_GRAPHS) { if (numOfGraphs < MAX_GRAPHS) {
val dividerItem = popup.menu.add(Menu.NONE, numOfGraphs, Menu.NONE, "------- " + "Graph" + " " + numOfGraphs + " -------") val dividerItem = popup.menu.add(Menu.NONE, numOfGraphs, Menu.NONE, "------- ${resourceHelper.gs(R.string.graph_menu_divider_header)} $numOfGraphs -------")
dividerItem.isCheckable = true dividerItem.isCheckable = true
dividerItem.isChecked = false dividerItem.isChecked = false
} }
@ -155,14 +132,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 +152,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

@ -41,6 +41,7 @@ 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)

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,22 +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_sensorbatterylevel: TextView?, careportal_pbage: TextView?, careportal_batterylevel: TextView?) { fun updateStatusLights(careportal_cannula_age: TextView?, careportal_insulin_age: TextView?, careportal_reservoir_level: TextView?, careportal_sensor_age: TextView?, careportal_sensor_battery_level: TextView?, careportal_pb_age: TextView?, careportal_battery_level: TextView?) {
val pump = activePlugin.activePump val pump = activePlugin.activePump
val bgSource = activePlugin.activeBgSource 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_cannula_age, 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_insulin_age, 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_sensor_age, 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_pb_age, 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 (bgSource.sensorBatteryLevel != -1) if (!config.NSCLIENT) {
handleLevel(careportal_sensorbatterylevel, R.string.key_statuslights_sbat_critical, 5.0, R.string.key_statuslights_sbat_warning, 20.0, bgSource.sensorBatteryLevel.toDouble(), "%") if (pump.model() == PumpType.Insulet_Omnipod) {
else handleOmnipodReservoirLevel(careportal_reservoir_level, R.string.key_statuslights_res_critical, 10.0, R.string.key_statuslights_res_warning, 80.0, pump.reservoirLevel, "U")
careportal_sensorbatterylevel?.text = "" } else {
handleLevel(careportal_reservoir_level, 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_sensor_battery_level, R.string.key_statuslights_sbat_critical, 5.0, R.string.key_statuslights_sbat_warning, 20.0, bgSource.sensorBatteryLevel.toDouble(), "%")
else
careportal_sensor_battery_level?.text = ""
}
if (!config.NSCLIENT) {
if (pump.model() == PumpType.Insulet_Omnipod && pump is OmnipodPumpPlugin) { // instance of 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_battery_level, R.string.key_statuslights_bat_critical, 26.0, R.string.key_statuslights_bat_warning, 51.0, pump.batteryLevel.toDouble(), "%", pump.isUseRileyLinkBatteryLevel)
} else if (pump.model() != PumpType.AccuChekCombo) {
handleLevel(careportal_battery_level, R.string.key_statuslights_bat_critical, 26.0, R.string.key_statuslights_bat_warning, 51.0, pump.batteryLevel.toDouble(), "%")
}
} }
if (!config.NSCLIENT && 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) {
@ -64,4 +79,26 @@ 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
@Suppress("SameParameterValue")
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)
}
}
@Suppress("SameParameterValue")
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

@ -11,28 +11,29 @@ import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.activities.NoSplashAppCompatActivity import info.nightscout.androidaps.activities.NoSplashAppCompatActivity
import info.nightscout.androidaps.databinding.OverviewQuickwizardlistActivityBinding
import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.plugins.general.overview.dialogs.EditQuickWizardDialog import info.nightscout.androidaps.plugins.general.overview.dialogs.EditQuickWizardDialog
import info.nightscout.androidaps.plugins.general.overview.events.EventQuickWizardChange import info.nightscout.androidaps.plugins.general.overview.events.EventQuickWizardChange
import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.DateUtil
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.resources.ResourceHelper
import info.nightscout.androidaps.utils.wizard.QuickWizard import info.nightscout.androidaps.utils.wizard.QuickWizard
import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable import io.reactivex.disposables.CompositeDisposable
import kotlinx.android.synthetic.main.overview_quickwizardlist_activity.*
import javax.inject.Inject import javax.inject.Inject
class QuickWizardListActivity : NoSplashAppCompatActivity() { class QuickWizardListActivity : NoSplashAppCompatActivity() {
@Inject lateinit var rxBus: RxBusWrapper @Inject lateinit var rxBus: RxBusWrapper
@Inject lateinit var resourceHelper: ResourceHelper
@Inject lateinit var fabricPrivacy: FabricPrivacy @Inject lateinit var fabricPrivacy: FabricPrivacy
@Inject lateinit var quickWizard: QuickWizard @Inject lateinit var quickWizard: QuickWizard
@Inject lateinit var dateUtil: DateUtil @Inject lateinit var dateUtil: DateUtil
private var disposable: CompositeDisposable = CompositeDisposable() private var disposable: CompositeDisposable = CompositeDisposable()
private lateinit var binding: OverviewQuickwizardlistActivityBinding
private inner class RecyclerViewAdapter(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 {
@ -49,6 +50,7 @@ class QuickWizardListActivity : NoSplashAppCompatActivity() {
override fun getItemCount(): Int = quickWizard.size() override fun getItemCount(): Int = quickWizard.size()
private inner class QuickWizardEntryViewHolder(itemView: View, 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)
@ -75,13 +77,14 @@ class QuickWizardListActivity : NoSplashAppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setContentView(R.layout.overview_quickwizardlist_activity) binding = OverviewQuickwizardlistActivityBinding.inflate(layoutInflater)
setContentView(binding.root)
overview_quickwizardactivity_recyclerview?.setHasFixedSize(true) binding.recyclerview.setHasFixedSize(true)
overview_quickwizardactivity_recyclerview?.layoutManager = LinearLayoutManager(this) binding.recyclerview.layoutManager = LinearLayoutManager(this)
overview_quickwizardactivity_recyclerview?.adapter = RecyclerViewAdapter(supportFragmentManager) binding.recyclerview.adapter = RecyclerViewAdapter(supportFragmentManager)
overview_quickwizardactivity_add_button.setOnClickListener { binding.addButton.setOnClickListener {
val manager = supportFragmentManager val manager = supportFragmentManager
val editQuickWizardDialog = EditQuickWizardDialog() val editQuickWizardDialog = EditQuickWizardDialog()
editQuickWizardDialog.show(manager, "EditQuickWizardDialog") editQuickWizardDialog.show(manager, "EditQuickWizardDialog")
@ -95,7 +98,7 @@ class QuickWizardListActivity : NoSplashAppCompatActivity() {
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
.subscribe({ .subscribe({
val adapter = RecyclerViewAdapter(supportFragmentManager) val adapter = RecyclerViewAdapter(supportFragmentManager)
overview_quickwizardactivity_recyclerview?.swapAdapter(adapter, false) binding.recyclerview.swapAdapter(adapter, false)
}, { fabricPrivacy.logException(it) }) }, { fabricPrivacy.logException(it) })
} }

View file

@ -17,11 +17,11 @@ import info.nightscout.androidaps.data.Profile
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.LoopInterface import info.nightscout.androidaps.interfaces.LoopInterface
import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.androidaps.interfaces.TreatmentsInterface import info.nightscout.androidaps.interfaces.TreatmentsInterface
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.openAPSSMB.SMBDefaults import info.nightscout.androidaps.plugins.aps.openAPSSMB.SMBDefaults
import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.androidaps.plugins.general.overview.graphExtensions.* import info.nightscout.androidaps.plugins.general.overview.graphExtensions.*
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensResult import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensResult
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin
@ -80,16 +80,20 @@ class GraphData(
for (prediction in predictions) if (prediction.value >= 40) bgListArray.add(prediction) for (prediction in predictions) if (prediction.value >= 40) bgListArray.add(prediction)
} }
maxBgValue = Profile.fromMgdlToUnits(maxBgValue, units) maxBgValue = Profile.fromMgdlToUnits(maxBgValue, units)
maxBgValue = if (units == Constants.MGDL) Round.roundTo(maxBgValue, 40.0) + 80 else Round.roundTo(maxBgValue, 2.0) + 4 maxBgValue = addUpperChartMargin(maxBgValue)
if (highLine > maxBgValue) maxBgValue = highLine if (highLine > maxBgValue) maxBgValue = highLine
val numOfVerticalLines = if (units == Constants.MGDL) (maxBgValue / 40 + 1).toInt() else (maxBgValue / 2 + 1).toInt()
maxY = maxBgValue maxY = maxBgValue
minY = 0.0 minY = 0.0
// set manual y bounds to have nice steps
graph.gridLabelRenderer.numVerticalLabels = numOfVerticalLines
addSeries(PointsWithLabelGraphSeries(Array(bgListArray.size) { i -> bgListArray[i] })) addSeries(PointsWithLabelGraphSeries(Array(bgListArray.size) { i -> bgListArray[i] }))
} }
internal fun setNumVerticalLables() {
graph.gridLabelRenderer.numVerticalLabels = if (units == Constants.MGDL) (maxY / 40 + 1).toInt() else (maxY / 2 + 1).toInt()
}
private fun addUpperChartMargin(maxBgValue: Double) =
if (units == Constants.MGDL) Round.roundTo(maxBgValue, 40.0) + 80 else Round.roundTo(maxBgValue, 2.0) + 4
fun addInRangeArea(fromTime: Long, toTime: Long, lowLine: Double, highLine: Double) { fun addInRangeArea(fromTime: Long, toTime: Long, lowLine: Double, highLine: Double) {
val inRangeAreaSeries: AreaGraphSeries<DoubleDataPoint> val inRangeAreaSeries: AreaGraphSeries<DoubleDataPoint>
val inRangeAreaDataPoints = arrayOf( val inRangeAreaDataPoints = arrayOf(
@ -233,44 +237,45 @@ class GraphData(
fun addTreatments(fromTime: Long, endTime: Long) { fun addTreatments(fromTime: Long, endTime: Long) {
val filteredTreatments: MutableList<DataPointWithLabelInterface> = ArrayList() val filteredTreatments: MutableList<DataPointWithLabelInterface> = ArrayList()
val treatments = treatmentsPlugin.treatmentsFromHistory treatmentsPlugin.treatmentsFromHistory
for (tx in treatments.indices) { .filterTimeframe(fromTime, endTime)
val t = treatments[tx] .filter { !it.isSMB || it.isValid }
if (t.x < fromTime || t.x > endTime) continue .forEach {
if (t.isSMB && !t.isValid) continue it.y = getNearestBg(it.x.toLong())
t.y = getNearestBg(t.x.toLong()) filteredTreatments.add(it)
filteredTreatments.add(t)
} }
// ProfileSwitch // ProfileSwitch
val profileSwitches = treatmentsPlugin.profileSwitchesFromHistory.list treatmentsPlugin.profileSwitchesFromHistory.list
for (tx in profileSwitches.indices) { .filterTimeframe(fromTime, endTime)
val t: DataPointWithLabelInterface = profileSwitches[tx] .forEach(filteredTreatments::add)
if (t.x < fromTime || t.x > endTime) continue
filteredTreatments.add(t)
}
// Extended bolus // Extended bolus
if (!activePlugin.activePump.isFakingTempsByExtendedBoluses) { if (!activePlugin.activePump.isFakingTempsByExtendedBoluses) {
val extendedBoluses = treatmentsPlugin.extendedBolusesFromHistory.list treatmentsPlugin.extendedBolusesFromHistory.list
for (tx in extendedBoluses.indices) { .filterTimeframe(fromTime, endTime)
val t: DataPointWithLabelInterface = extendedBoluses[tx] .filter { it.duration != 0L }
if (t.x + t.duration < fromTime || t.x > endTime) continue .forEach {
if (t.duration == 0L) continue it.y = getNearestBg(it.x.toLong())
t.y = getNearestBg(t.x.toLong()) filteredTreatments.add(it)
filteredTreatments.add(t)
} }
} }
// Careportal // Careportal
val careportalEvents = MainApp.getDbHelper().getCareportalEventsFromTime(fromTime - 6 * 60 * 60 * 1000, true) MainApp.getDbHelper().getCareportalEventsFromTime(fromTime - 6 * 60 * 60 * 1000, true)
for (tx in careportalEvents.indices) { .filterTimeframe(fromTime, endTime)
val t: DataPointWithLabelInterface = careportalEvents[tx] .forEach {
if (t.x + t.duration < fromTime || t.x > endTime) continue it.y = getNearestBg(it.x.toLong())
t.y = getNearestBg(t.x.toLong()) filteredTreatments.add(it)
filteredTreatments.add(t)
} }
addSeries(PointsWithLabelGraphSeries(Array(filteredTreatments.size) { i -> filteredTreatments[i] }))
// increase maxY if a treatment forces it's own height that's higher than a BG value
filteredTreatments.map { it.y }
.maxOrNull()
?.let(::addUpperChartMargin)
?.let { maxY = maxOf(maxY, it) }
addSeries(PointsWithLabelGraphSeries(filteredTreatments.toTypedArray()))
} }
private fun getNearestBg(date: Long): Double { private fun getNearestBg(date: Long): Double {
@ -604,3 +609,6 @@ class GraphData(
graph.onDataChanged(false, false) graph.onDataChanged(false, false)
} }
} }
private fun <E : DataPointWithLabelInterface> List<E>.filterTimeframe(fromTime: Long, endTime: Long): List<E> =
filter { it.x + it.duration >= fromTime && it.x <= endTime }

View file

@ -8,7 +8,6 @@ import android.content.Context
import android.content.Intent import android.content.Intent
import android.media.AudioManager import android.media.AudioManager
import android.media.RingtoneManager import android.media.RingtoneManager
import android.os.Build
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
@ -16,7 +15,9 @@ import android.widget.Button
import android.widget.TextView import android.widget.TextView
import androidx.cardview.widget.CardView import androidx.cardview.widget.CardView
import androidx.core.app.NotificationCompat import androidx.core.app.NotificationCompat
import androidx.core.app.TaskStackBuilder
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import info.nightscout.androidaps.MainActivity
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.logging.LTag
@ -24,6 +25,7 @@ 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.AlarmSoundServiceHelper import info.nightscout.androidaps.services.AlarmSoundServiceHelper
import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.androidNotification.openAppIntent
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
import info.nightscout.androidaps.utils.sharedPreferences.SP import info.nightscout.androidaps.utils.sharedPreferences.SP
@ -69,7 +71,7 @@ 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, true) && n !is NotificationWithAction) {
raiseSystemNotification(n) raiseSystemNotification(n)
if (usesChannels && n.soundId != null && n.soundId != 0) alarmSoundServiceHelper.startAlarm(context, n.soundId) if (usesChannels && n.soundId != null && n.soundId != 0) alarmSoundServiceHelper.startAlarm(context, n.soundId)
} else { } else {
@ -114,6 +116,7 @@ class NotificationStore @Inject constructor(
.setStyle(NotificationCompat.BigTextStyle().bigText(n.text)) .setStyle(NotificationCompat.BigTextStyle().bigText(n.text))
.setPriority(NotificationCompat.PRIORITY_MAX) .setPriority(NotificationCompat.PRIORITY_MAX)
.setDeleteIntent(deleteIntent(n.id)) .setDeleteIntent(deleteIntent(n.id))
.setContentIntent(openAppIntent(context))
if (n.level == Notification.URGENT) { if (n.level == Notification.URGENT) {
notificationBuilder.setVibrate(longArrayOf(1000, 1000, 1000, 1000)) notificationBuilder.setVibrate(longArrayOf(1000, 1000, 1000, 1000))
.setContentTitle(resourceHelper.gs(R.string.urgent_alarm)) .setContentTitle(resourceHelper.gs(R.string.urgent_alarm))
@ -132,7 +135,6 @@ class NotificationStore @Inject constructor(
} }
fun createNotificationChannel() { fun createNotificationChannel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
usesChannels = true usesChannels = true
val mNotificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager val mNotificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
@SuppressLint("WrongConstant") val channel = NotificationChannel(CHANNEL_ID, @SuppressLint("WrongConstant") val channel = NotificationChannel(CHANNEL_ID,
@ -140,7 +142,6 @@ class NotificationStore @Inject constructor(
NotificationManager.IMPORTANCE_HIGH) NotificationManager.IMPORTANCE_HIGH)
mNotificationManager.createNotificationChannel(channel) mNotificationManager.createNotificationChannel(channel)
} }
}
@Synchronized @Synchronized
fun updateNotifications(notificationsView: RecyclerView) { fun updateNotifications(notificationsView: RecyclerView) {
@ -162,16 +163,6 @@ class NotificationStore @Inject constructor(
return clone return clone
} }
/*
private fun unSnooze() {
if (sp.getBoolean(R.string.key_nsalarm_staledata, false)) {
val notification = Notification(Notification.NSALARM, resourceHelper.gs(R.string.nsalarm_staledata), Notification.URGENT)
sp.putLong(R.string.key_snoozedTo, System.currentTimeMillis())
add(notification)
aapsLogger.debug(LTag.NOTIFICATION, "Snoozed to current time and added back notification!")
}
}
*/
inner class NotificationRecyclerViewAdapter internal constructor(private val notificationsList: List<Notification>) : RecyclerView.Adapter<NotificationRecyclerViewAdapter.NotificationsViewHolder>() { inner class NotificationRecyclerViewAdapter internal constructor(private val notificationsList: List<Notification>) : RecyclerView.Adapter<NotificationRecyclerViewAdapter.NotificationsViewHolder>() {
override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): NotificationsViewHolder { override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): NotificationsViewHolder {

View file

@ -3,6 +3,7 @@ package info.nightscout.androidaps.plugins.general.persistentNotification
import android.app.Notification import android.app.Notification
import android.app.Service import android.app.Service
import android.content.Intent import android.content.Intent
import android.os.Binder
import android.os.IBinder import android.os.IBinder
import dagger.android.DaggerService import dagger.android.DaggerService
import info.nightscout.androidaps.events.EventAppExit import info.nightscout.androidaps.events.EventAppExit
@ -27,7 +28,13 @@ class DummyService : DaggerService() {
private val disposable = CompositeDisposable() private val disposable = CompositeDisposable()
override fun onBind(intent: Intent?): IBinder? = null inner class LocalBinder : Binder() {
fun getService(): DummyService = this@DummyService
}
private val binder = LocalBinder()
override fun onBind(intent: Intent): IBinder = binder
override fun onCreate() { override fun onCreate() {
super.onCreate() super.onCreate()
@ -44,7 +51,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

@ -0,0 +1,66 @@
package info.nightscout.androidaps.plugins.general.persistentNotification
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.ServiceConnection
import android.os.Build
import android.os.IBinder
import androidx.annotation.RequiresApi
import info.nightscout.androidaps.interfaces.NotificationHolderInterface
import javax.inject.Inject
import javax.inject.Singleton
/*
This code replaces following
val alarm = Intent(context, DummyService::class.java)
alarm.putExtra("soundid", n.soundId)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) context.startForegroundService(alarm) else context.startService(alarm)
it fails randomly with error
Context.startForegroundService() did not then call Service.startForeground(): ServiceRecord{e317f7e u0 info.nightscout.nsclient/info.nightscout.androidaps.services.DummyService}
*/
@RequiresApi(Build.VERSION_CODES.O)
@Singleton
class DummyServiceHelper @Inject constructor(
private val notificationHolder: NotificationHolderInterface
) {
fun startService(context: Context) {
val connection = object : ServiceConnection {
override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
// The binder of the service that returns the instance that is created.
val binder: DummyService.LocalBinder = service as DummyService.LocalBinder
val dummyService: DummyService = binder.getService()
context.startForegroundService(Intent(context, DummyService::class.java))
// This is the key: Without waiting Android Framework to call this method
// inside Service.onCreate(), immediately call here to post the notification.
dummyService.startForeground(notificationHolder.notificationID, notificationHolder.notification)
// Release the connection to prevent leaks.
context.unbindService(this)
}
override fun onServiceDisconnected(name: ComponentName?) {
}
}
try {
context.bindService(Intent(context, DummyService::class.java), connection, Context.BIND_AUTO_CREATE)
} catch (ignored: RuntimeException) {
// This is probably a broadcast receiver context even though we are calling getApplicationContext().
// Just call startForegroundService instead since we cannot bind a service to a
// broadcast receiver context. The service also have to call startForeground in
// this case.
context.startForegroundService(Intent(context, DummyService::class.java))
}
}
fun stopService(context: Context) {
context.stopService(Intent(context, DummyService::class.java))
}
}

View file

@ -5,7 +5,6 @@ import android.app.NotificationManager
import android.app.PendingIntent import android.app.PendingIntent
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.os.Build
import androidx.core.app.NotificationCompat import androidx.core.app.NotificationCompat
import androidx.core.app.RemoteInput import androidx.core.app.RemoteInput
import androidx.core.app.TaskStackBuilder import androidx.core.app.TaskStackBuilder
@ -24,6 +23,7 @@ import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventAutos
import info.nightscout.androidaps.utils.DecimalFormatter import info.nightscout.androidaps.utils.DecimalFormatter
import info.nightscout.androidaps.utils.FabricPrivacy import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.androidNotification.NotificationHolder import info.nightscout.androidaps.utils.androidNotification.NotificationHolder
import info.nightscout.androidaps.utils.androidNotification.openAppIntent
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
import io.reactivex.disposables.CompositeDisposable import io.reactivex.disposables.CompositeDisposable
@ -31,18 +31,20 @@ import io.reactivex.schedulers.Schedulers
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
@Suppress("PrivatePropertyName")
@Singleton @Singleton
class PersistentNotificationPlugin @Inject constructor( class PersistentNotificationPlugin @Inject constructor(
injector: HasAndroidInjector, injector: HasAndroidInjector,
aapsLogger: AAPSLogger, aapsLogger: AAPSLogger,
resourceHelper: ResourceHelper, resourceHelper: ResourceHelper,
private var profileFunction: ProfileFunction, private val profileFunction: ProfileFunction,
private var fabricPrivacy: FabricPrivacy, private val fabricPrivacy: FabricPrivacy,
private var activePlugins: ActivePluginProvider, private val activePlugins: ActivePluginProvider,
private var iobCobCalculatorPlugin: IobCobCalculatorPlugin, private val iobCobCalculatorPlugin: IobCobCalculatorPlugin,
private var rxBus: RxBusWrapper, private val rxBus: RxBusWrapper,
private var context: Context, private val context: Context,
private var notificationHolder: NotificationHolder, private val notificationHolder: NotificationHolder,
private val dummyServiceHelper: DummyServiceHelper,
private val iconsProvider: IconsProvider, private val iconsProvider: IconsProvider,
private val databaseHelper: DatabaseHelperInterface private val databaseHelper: DatabaseHelperInterface
) : PluginBase(PluginDescription() ) : PluginBase(PluginDescription()
@ -106,25 +108,20 @@ class PersistentNotificationPlugin @Inject constructor(
} }
private fun createNotificationChannel() { private fun createNotificationChannel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val mNotificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager val mNotificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
val channel = NotificationChannel(notificationHolder.channelID, notificationHolder.channelID as CharSequence, NotificationManager.IMPORTANCE_HIGH) val channel = NotificationChannel(notificationHolder.channelID, notificationHolder.channelID as CharSequence, NotificationManager.IMPORTANCE_HIGH)
mNotificationManager.createNotificationChannel(channel) mNotificationManager.createNotificationChannel(channel)
} }
}
override fun onStop() { override fun onStop() {
disposable.clear() disposable.clear()
context.stopService(Intent(context, DummyService::class.java)) dummyServiceHelper.stopService(context)
super.onStop() super.onStop()
} }
private fun triggerNotificationUpdate() { private fun triggerNotificationUpdate() {
updateNotification() updateNotification()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) dummyServiceHelper.startService(context)
context.startForegroundService(Intent(context, DummyService::class.java))
else
context.startService(Intent(context, DummyService::class.java))
} }
private fun updateNotification() { private fun updateNotification() {
@ -134,31 +131,31 @@ class PersistentNotificationPlugin @Inject constructor(
var line3: String? = null var line3: String? = null
var unreadConversationBuilder: NotificationCompat.CarExtender.UnreadConversation.Builder? = null var unreadConversationBuilder: NotificationCompat.CarExtender.UnreadConversation.Builder? = null
if (profileFunction.isProfileValid("Notification")) { if (profileFunction.isProfileValid("Notification")) {
var line1_aa: String var line1aa: String
val units = profileFunction.getUnits() val units = profileFunction.getUnits()
val lastBG = iobCobCalculatorPlugin.lastBg() val lastBG = iobCobCalculatorPlugin.lastBg()
val glucoseStatus = GlucoseStatus(injector).glucoseStatusData val glucoseStatus = GlucoseStatus(injector).glucoseStatusData
if (lastBG != null) { if (lastBG != null) {
line1_aa = lastBG.valueToUnitsToString(units) line1aa = lastBG.valueToUnitsToString(units)
line1 = line1_aa line1 = line1aa
if (glucoseStatus != null) { if (glucoseStatus != null) {
line1 += (" Δ" + Profile.toSignedUnitsString(glucoseStatus.delta, glucoseStatus.delta * Constants.MGDL_TO_MMOLL, units) line1 += (" Δ" + Profile.toSignedUnitsString(glucoseStatus.delta, glucoseStatus.delta * Constants.MGDL_TO_MMOLL, units)
+ " avgΔ" + Profile.toSignedUnitsString(glucoseStatus.avgdelta, glucoseStatus.avgdelta * Constants.MGDL_TO_MMOLL, units)) + " avgΔ" + Profile.toSignedUnitsString(glucoseStatus.avgdelta, glucoseStatus.avgdelta * Constants.MGDL_TO_MMOLL, units))
line1_aa += " " + lastBG.directionToSymbol(databaseHelper) line1aa += " " + lastBG.directionToSymbol(databaseHelper)
} else { } else {
line1 += " " + line1 += " " +
resourceHelper.gs(R.string.old_data) + resourceHelper.gs(R.string.old_data) +
" " " "
line1_aa += "$line1." line1aa += "$line1."
} }
} else { } else {
line1_aa = resourceHelper.gs(R.string.missed_bg_readings) line1aa = resourceHelper.gs(R.string.missed_bg_readings)
line1 = line1_aa line1 = line1aa
} }
val activeTemp = activePlugins.activeTreatments.getTempBasalFromHistory(System.currentTimeMillis()) val activeTemp = activePlugins.activeTreatments.getTempBasalFromHistory(System.currentTimeMillis())
if (activeTemp != null) { if (activeTemp != null) {
line1 += " " + activeTemp.toStringShort() line1 += " " + activeTemp.toStringShort()
line1_aa += " " + activeTemp.toStringShort() + "." line1aa += " " + activeTemp.toStringShort() + "."
} }
//IOB //IOB
activePlugins.activeTreatments.updateTotalIOBTreatments() activePlugins.activeTreatments.updateTotalIOBTreatments()
@ -166,11 +163,11 @@ class PersistentNotificationPlugin @Inject constructor(
val bolusIob = activePlugins.activeTreatments.lastCalculationTreatments.round() val bolusIob = activePlugins.activeTreatments.lastCalculationTreatments.round()
val basalIob = activePlugins.activeTreatments.lastCalculationTempBasals.round() val basalIob = activePlugins.activeTreatments.lastCalculationTempBasals.round()
line2 = resourceHelper.gs(R.string.treatments_iob_label_string) + " " + DecimalFormatter.to2Decimal(bolusIob.iob + basalIob.basaliob) + "U " + resourceHelper.gs(R.string.cob) + ": " + iobCobCalculatorPlugin.getCobInfo(false, "PersistentNotificationPlugin").generateCOBString() line2 = resourceHelper.gs(R.string.treatments_iob_label_string) + " " + DecimalFormatter.to2Decimal(bolusIob.iob + basalIob.basaliob) + "U " + resourceHelper.gs(R.string.cob) + ": " + iobCobCalculatorPlugin.getCobInfo(false, "PersistentNotificationPlugin").generateCOBString()
val line2_aa = resourceHelper.gs(R.string.treatments_iob_label_string) + " " + DecimalFormatter.to2Decimal(bolusIob.iob + basalIob.basaliob) + "U. " + resourceHelper.gs(R.string.cob) + ": " + iobCobCalculatorPlugin.getCobInfo(false, "PersistentNotificationPlugin").generateCOBString() + "." val line2aa = resourceHelper.gs(R.string.treatments_iob_label_string) + " " + DecimalFormatter.to2Decimal(bolusIob.iob + basalIob.basaliob) + "U. " + resourceHelper.gs(R.string.cob) + ": " + iobCobCalculatorPlugin.getCobInfo(false, "PersistentNotificationPlugin").generateCOBString() + "."
line3 = DecimalFormatter.to2Decimal(pump.baseBasalRate) + " U/h" line3 = DecimalFormatter.to2Decimal(pump.baseBasalRate) + " U/h"
var line3_aa = DecimalFormatter.to2Decimal(pump.baseBasalRate) + " U/h." var line3aa = DecimalFormatter.to2Decimal(pump.baseBasalRate) + " U/h."
line3 += " - " + profileFunction.getProfileName() line3 += " - " + profileFunction.getProfileName()
line3_aa += " - " + profileFunction.getProfileName() + "." line3aa += " - " + profileFunction.getProfileName() + "."
/// For Android Auto /// For Android Auto
val msgReadIntent = Intent() val msgReadIntent = Intent()
.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES) .addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES)
@ -194,12 +191,12 @@ class PersistentNotificationPlugin @Inject constructor(
// Build a RemoteInput for receiving voice input from devices // Build a RemoteInput for receiving voice input from devices
val remoteInput = RemoteInput.Builder(EXTRA_VOICE_REPLY).build() val remoteInput = RemoteInput.Builder(EXTRA_VOICE_REPLY).build()
// Create the UnreadConversation // Create the UnreadConversation
unreadConversationBuilder = NotificationCompat.CarExtender.UnreadConversation.Builder(line1_aa + "\n" + line2_aa) unreadConversationBuilder = NotificationCompat.CarExtender.UnreadConversation.Builder(line1aa + "\n" + line2aa)
.setLatestTimestamp(System.currentTimeMillis()) .setLatestTimestamp(System.currentTimeMillis())
.setReadPendingIntent(msgReadPendingIntent) .setReadPendingIntent(msgReadPendingIntent)
.setReplyAction(msgReplyPendingIntent, remoteInput) .setReplyAction(msgReplyPendingIntent, remoteInput)
/// Add dot to produce a "more natural sounding result" /// Add dot to produce a "more natural sounding result"
unreadConversationBuilder.addMessage(line3_aa) unreadConversationBuilder.addMessage(line3aa)
/// End Android Auto /// End Android Auto
} else { } else {
line1 = resourceHelper.gs(R.string.noprofileset) line1 = resourceHelper.gs(R.string.noprofileset)
@ -219,15 +216,7 @@ class PersistentNotificationPlugin @Inject constructor(
.setUnreadConversation(unreadConversationBuilder.build())) .setUnreadConversation(unreadConversationBuilder.build()))
} }
/// End Android Auto /// End Android Auto
val resultIntent = Intent(context, MainActivity::class.java) builder.setContentIntent(openAppIntent(context))
val stackBuilder = TaskStackBuilder.create(context)
stackBuilder.addParentStack(MainActivity::class.java)
stackBuilder.addNextIntent(resultIntent)
val resultPendingIntent = stackBuilder.getPendingIntent(
0,
PendingIntent.FLAG_UPDATE_CURRENT
)
builder.setContentIntent(resultPendingIntent)
val mNotificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager val mNotificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
val notification = builder.build() val notification = builder.build()
mNotificationManager.notify(notificationHolder.notificationID, notification) mNotificationManager.notify(notificationHolder.notificationID, notification)

View file

@ -66,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)

View file

@ -21,17 +21,16 @@ import info.nightscout.androidaps.plugins.general.smsCommunicator.otp.OneTimePas
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.alertDialogs.OKDialog import info.nightscout.androidaps.utils.alertDialogs.OKDialog
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
import javax.inject.Inject import javax.inject.Inject
class SmsCommunicatorOtpActivity : NoSplashAppCompatActivity() { class SmsCommunicatorOtpActivity : NoSplashAppCompatActivity() {
@Inject lateinit var fabricPrivacy: FabricPrivacy @Inject lateinit var fabricPrivacy: FabricPrivacy
@Inject lateinit var rxBus: RxBusWrapper @Inject lateinit var rxBus: RxBusWrapper
@Inject lateinit var smsCommunicatorPlugin: SmsCommunicatorPlugin @Inject lateinit var smsCommunicatorPlugin: SmsCommunicatorPlugin
@Inject lateinit var otp: OneTimePassword @Inject lateinit var otp: OneTimePassword
@Inject lateinit var resourceHelper: ResourceHelper
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)

View file

@ -182,20 +182,20 @@ class ActionStringHandler @Inject constructor(
return return
} }
val bgReading = iobCobCalculatorPlugin.actualBg() val bgReading = iobCobCalculatorPlugin.actualBg()
if (bgReading == null && useBG) { if (bgReading == null) {
sendError("No recent BG to base calculation on!") sendError("No recent BG to base calculation on!")
return return
} }
val cobInfo = iobCobCalculatorPlugin.getCobInfo(false, "Wizard wear") val cobInfo = iobCobCalculatorPlugin.getCobInfo(false, "Wizard wear")
if (useCOB && (cobInfo.displayCob == null)) { if (cobInfo.displayCob == null) {
sendError("Unknown COB! BG reading missing or recent app restart?") sendError("Unknown COB! BG reading missing or recent app restart?")
return return
} }
val format = DecimalFormat("0.00") val format = DecimalFormat("0.00")
val formatInt = DecimalFormat("0") val formatInt = DecimalFormat("0")
val bolusWizard = BolusWizard(injector).doCalc(profile, profileName, activePlugin.activeTreatments.tempTargetFromHistory, val bolusWizard = BolusWizard(injector).doCalc(profile, profileName, activePlugin.activeTreatments.tempTargetFromHistory,
carbsAfterConstraints, cobInfo.displayCob!!, bgReading!!.valueToUnits(profileFunction.getUnits()), carbsAfterConstraints, cobInfo.displayCob, bgReading.valueToUnits(profileFunction.getUnits()),
0.0, percentage.toDouble(), useBG, useCOB, useBolusIOB, useBasalIOB, false, useTT, useTrend) 0.0, percentage.toDouble(), useBG, useCOB, useBolusIOB, useBasalIOB, false, useTT, useTrend, false)
if (Math.abs(bolusWizard.insulinAfterConstraints - bolusWizard.calculatedTotalInsulin) >= 0.01) { if (Math.abs(bolusWizard.insulinAfterConstraints - bolusWizard.calculatedTotalInsulin) >= 0.01) {
sendError("Insulin constraint violation!" + sendError("Insulin constraint violation!" +
"\nCannot deliver " + format.format(bolusWizard.calculatedTotalInsulin) + "!") "\nCannot deliver " + format.format(bolusWizard.calculatedTotalInsulin) + "!")
@ -215,7 +215,7 @@ class ActionStringHandler @Inject constructor(
if (useCOB) rMessage += "\nFrom" + formatInt.format(cobInfo.displayCob) + "g COB : " + format.format(bolusWizard.insulinFromCOB) + "U" if (useCOB) rMessage += "\nFrom" + formatInt.format(cobInfo.displayCob) + "g COB : " + format.format(bolusWizard.insulinFromCOB) + "U"
if (useBG) rMessage += "\nFrom BG: " + format.format(bolusWizard.insulinFromBG) + "U" if (useBG) rMessage += "\nFrom BG: " + format.format(bolusWizard.insulinFromBG) + "U"
if (useBolusIOB) rMessage += "\nBolus IOB: " + format.format(bolusWizard.insulinFromBolusIOB) + "U" if (useBolusIOB) rMessage += "\nBolus IOB: " + format.format(bolusWizard.insulinFromBolusIOB) + "U"
if (useBasalIOB) rMessage += "\nBasal IOB: " + format.format(bolusWizard.insulinFromBasalsIOB) + "U" if (useBasalIOB) rMessage += "\nBasal IOB: " + format.format(bolusWizard.insulinFromBasalIOB) + "U"
if (useTrend) rMessage += "\nFrom 15' trend: " + format.format(bolusWizard.insulinFromTrend) + "U" if (useTrend) rMessage += "\nFrom 15' trend: " + format.format(bolusWizard.insulinFromTrend) + "U"
if (percentage != 100) { if (percentage != 100) {
rMessage += "\nPercentage: " + format.format(bolusWizard.totalBeforePercentageAdjustment) + "U * " + percentage + "% -> ~" + format.format(bolusWizard.calculatedTotalInsulin) + "U" rMessage += "\nPercentage: " + format.format(bolusWizard.totalBeforePercentageAdjustment) + "U * " + percentage + "% -> ~" + format.format(bolusWizard.calculatedTotalInsulin) + "U"

View file

@ -5,21 +5,34 @@ import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import dagger.android.support.DaggerFragment import dagger.android.support.DaggerFragment
import info.nightscout.androidaps.R import info.nightscout.androidaps.databinding.WearFragmentBinding
import kotlinx.android.synthetic.main.wear_fragment.*
import javax.inject.Inject import javax.inject.Inject
class WearFragment : DaggerFragment() { class WearFragment : DaggerFragment() {
@Inject lateinit var wearPlugin: WearPlugin @Inject lateinit var wearPlugin: WearPlugin
private var _binding: WearFragmentBinding? = 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 {
return inflater.inflate(R.layout.wear_fragment, container, false) _binding = WearFragmentBinding.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)
wear_resend.setOnClickListener { wearPlugin.resendDataToWatch() } binding.resend.setOnClickListener { wearPlugin.resendDataToWatch() }
wear_opensettings.setOnClickListener { wearPlugin.openSettings() } binding.opensettings.setOnClickListener { wearPlugin.openSettings() }
}
@Synchronized
override fun onDestroyView() {
super.onDestroyView()
_binding = null
} }
} }

View file

@ -39,6 +39,7 @@ class WearPlugin @Inject constructor(
) : PluginBase(PluginDescription() ) : PluginBase(PluginDescription()
.mainType(PluginType.GENERAL) .mainType(PluginType.GENERAL)
.fragmentClass(WearFragment::class.java.name) .fragmentClass(WearFragment::class.java.name)
.pluginIcon(R.drawable.ic_watch)
.pluginName(R.string.wear) .pluginName(R.string.wear)
.shortName(R.string.wear_shortname) .shortName(R.string.wear_shortname)
.preferencesId(R.xml.pref_wear) .preferencesId(R.xml.pref_wear)

View file

@ -43,6 +43,7 @@ class StatusLinePlugin @Inject constructor(
) : PluginBase( ) : PluginBase(
PluginDescription() PluginDescription()
.mainType(PluginType.GENERAL) .mainType(PluginType.GENERAL)
.pluginIcon((R.drawable.ic_blooddrop_48))
.pluginName(R.string.xdripstatus) .pluginName(R.string.xdripstatus)
.shortName(R.string.xdripstatus_shortname) .shortName(R.string.xdripstatus_shortname)
.neverVisible(true) .neverVisible(true)

View file

@ -31,6 +31,7 @@ class InsulinLyumjevPlugin @Inject constructor(
init { init {
pluginDescription pluginDescription
.pluginIcon(R.drawable.ic_insulin)
.pluginName(R.string.lyumjev) .pluginName(R.string.lyumjev)
.description(R.string.description_insulin_lyumjev) .description(R.string.description_insulin_lyumjev)
} }

View file

@ -29,6 +29,7 @@ abstract class InsulinOrefBasePlugin(
) : PluginBase(PluginDescription() ) : PluginBase(PluginDescription()
.mainType(PluginType.INSULIN) .mainType(PluginType.INSULIN)
.fragmentClass(InsulinFragment::class.java.name) .fragmentClass(InsulinFragment::class.java.name)
.pluginIcon(R.drawable.ic_insulin)
.shortName(R.string.insulin_shortname) .shortName(R.string.insulin_shortname)
.visibleByDefault(false), .visibleByDefault(false),
aapsLogger, resourceHelper, injector aapsLogger, resourceHelper, injector

View file

@ -49,6 +49,7 @@ class InsulinOrefFreePeakPlugin @Inject constructor(
init { init {
pluginDescription pluginDescription
.pluginIcon(R.drawable.ic_insulin)
.pluginName(R.string.free_peak_oref) .pluginName(R.string.free_peak_oref)
.preferencesId(R.xml.pref_insulinoreffreepeak) .preferencesId(R.xml.pref_insulinoreffreepeak)
.description(R.string.description_insulin_free_peak) .description(R.string.description_insulin_free_peak)

View file

@ -37,6 +37,7 @@ class LocalProfilePlugin @Inject constructor(
.mainType(PluginType.PROFILE) .mainType(PluginType.PROFILE)
.fragmentClass(LocalProfileFragment::class.java.name) .fragmentClass(LocalProfileFragment::class.java.name)
.enableByDefault(true) .enableByDefault(true)
.pluginIcon(R.drawable.ic_local_profile)
.pluginName(R.string.localprofile) .pluginName(R.string.localprofile)
.shortName(R.string.localprofile_shortname) .shortName(R.string.localprofile_shortname)
.description(R.string.description_profile_local) .description(R.string.description_profile_local)

View file

@ -8,8 +8,9 @@ import android.widget.AdapterView
import android.widget.ArrayAdapter import android.widget.ArrayAdapter
import dagger.android.support.DaggerFragment import dagger.android.support.DaggerFragment
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.databinding.NsprofileFragmentBinding
import info.nightscout.androidaps.interfaces.ProfileFunction import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.plugins.profile.ns.events.EventNSProfileUpdateGUI import info.nightscout.androidaps.plugins.profile.ns.events.EventNSProfileUpdateGUI
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
@ -20,9 +21,6 @@ import info.nightscout.androidaps.utils.extensions.plusAssign
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.close.*
import kotlinx.android.synthetic.main.nsprofile_fragment.*
import kotlinx.android.synthetic.main.profileviewer_fragment.*
import javax.inject.Inject import javax.inject.Inject
class NSProfileFragment : DaggerFragment() { class NSProfileFragment : DaggerFragment() {
@ -36,18 +34,25 @@ class NSProfileFragment : DaggerFragment() {
private var disposable: CompositeDisposable = CompositeDisposable() private var disposable: CompositeDisposable = CompositeDisposable()
private var _binding: NsprofileFragmentBinding? = 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 {
return inflater.inflate(R.layout.nsprofile_fragment, container, false) _binding = NsprofileFragmentBinding.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)
close.visibility = View.GONE // not needed for fragment binding.profileviewer.closeLayout.close.visibility = View.GONE // not needed for fragment
nsprofile_profileswitch.setOnClickListener { binding.profileswitch.setOnClickListener {
val name = nsprofile_spinner.selectedItem?.toString() ?: "" val name = binding.spinner.selectedItem?.toString() ?: ""
nsProfilePlugin.profile?.let { store -> nsProfilePlugin.profile?.let { store ->
store.getSpecificProfile(name)?.let { store.getSpecificProfile(name)?.let {
activity?.let { activity -> activity?.let { activity ->
@ -60,43 +65,46 @@ class NSProfileFragment : DaggerFragment() {
} }
} }
nsprofile_spinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener { binding.spinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
override fun onNothingSelected(parent: AdapterView<*>?) { override fun onNothingSelected(parent: AdapterView<*>?) {
profileview_invalidprofile.visibility = View.VISIBLE if (_binding == null) return
profileview_noprofile.visibility = View.VISIBLE binding.profileviewer.invalidprofile.visibility = View.VISIBLE
profileview_units.text = "" binding.profileviewer.noprofile.visibility = View.VISIBLE
profileview_dia.text = "" binding.profileviewer.units.text = ""
profileview_activeprofile.text = "" binding.profileviewer.dia.text = ""
profileview_ic.text = "" binding.profileviewer.activeprofile.text = ""
profileview_isf.text = "" binding.profileviewer.ic.text = ""
profileview_basal.text = "" binding.profileviewer.isf.text = ""
profileview_basaltotal.text = "" binding.profileviewer.basal.text = ""
profileview_target.text = "" binding.profileviewer.basaltotal.text = ""
nsprofile_profileswitch.visibility = View.GONE binding.profileviewer.target.text = ""
binding.profileswitch.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) {
val name = nsprofile_spinner.getItemAtPosition(position).toString() if (_binding == null) return
val name = binding.spinner.getItemAtPosition(position).toString()
nsprofile_profileswitch.visibility = View.GONE binding.profileswitch.visibility = View.GONE
nsProfilePlugin.profile?.let { store -> nsProfilePlugin.profile?.let { store ->
store.getSpecificProfile(name)?.let { profile -> store.getSpecificProfile(name)?.let { profile ->
profileview_units.text = profile.units if (_binding == null) return
profileview_dia.text = resourceHelper.gs(R.string.format_hours, profile.dia) binding.profileviewer.units.text = profile.units
profileview_activeprofile.text = name binding.profileviewer.dia.text = resourceHelper.gs(R.string.format_hours, profile.dia)
profileview_ic.text = profile.icList binding.profileviewer.activeprofile.text = name
profileview_isf.text = profile.isfList binding.profileviewer.ic.text = profile.icList
profileview_basal.text = profile.basalList binding.profileviewer.isf.text = profile.isfList
profileview_basaltotal.text = String.format(resourceHelper.gs(R.string.profile_total), DecimalFormatter.to2Decimal(profile.baseBasalSum())) binding.profileviewer.basal.text = profile.basalList
profileview_target.text = profile.targetList binding.profileviewer.basaltotal.text = String.format(resourceHelper.gs(R.string.profile_total), DecimalFormatter.to2Decimal(profile.baseBasalSum()))
basal_graph.show(profile) binding.profileviewer.target.text = profile.targetList
binding.profileviewer.basalGraph.show(profile)
if (profile.isValid("NSProfileFragment")) { if (profile.isValid("NSProfileFragment")) {
profileview_invalidprofile.visibility = View.GONE binding.profileviewer.invalidprofile.visibility = View.GONE
nsprofile_profileswitch.visibility = View.VISIBLE binding.profileswitch.visibility = View.VISIBLE
} else { } else {
profileview_invalidprofile.visibility = View.VISIBLE binding.profileviewer.invalidprofile.visibility = View.VISIBLE
nsprofile_profileswitch.visibility = View.GONE binding.profileswitch.visibility = View.GONE
} }
} }
} }
@ -120,21 +128,29 @@ class NSProfileFragment : DaggerFragment() {
disposable.clear() disposable.clear()
} }
@Synchronized
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
@Synchronized @Synchronized
fun updateGUI() { fun updateGUI() {
if (profileview_noprofile == null) return if (_binding == null) return
profileview_noprofile.visibility = View.VISIBLE binding.profileviewer.noprofile.visibility = View.VISIBLE
nsProfilePlugin.profile?.let { profileStore -> nsProfilePlugin.profile?.let { profileStore ->
context?.let { context ->
val profileList = profileStore.getProfileList() val profileList = profileStore.getProfileList()
val adapter = ArrayAdapter(context!!, R.layout.spinner_centered, profileList) val adapter = ArrayAdapter(context, R.layout.spinner_centered, profileList)
nsprofile_spinner.adapter = adapter binding.spinner.adapter = adapter
// set selected to actual profile // set selected to actual profile
for (p in profileList.indices) { for (p in profileList.indices) {
if (profileList[p] == profileFunction.getProfileName()) if (profileList[p] == profileFunction.getProfileName())
nsprofile_spinner.setSelection(p) binding.spinner.setSelection(p)
}
binding.profileviewer.noprofile.visibility = View.GONE
} }
profileview_noprofile.visibility = View.GONE
} }
} }
} }

View file

@ -32,6 +32,7 @@ class NSProfilePlugin @Inject constructor(
) : PluginBase(PluginDescription() ) : PluginBase(PluginDescription()
.mainType(PluginType.PROFILE) .mainType(PluginType.PROFILE)
.fragmentClass(NSProfileFragment::class.java.name) .fragmentClass(NSProfileFragment::class.java.name)
.pluginIcon(R.drawable.ic_nightscout_profile)
.pluginName(R.string.nsprofile) .pluginName(R.string.nsprofile)
.shortName(R.string.profileviewer_shortname) .shortName(R.string.profileviewer_shortname)
.alwaysEnabled(config.NSCLIENT) .alwaysEnabled(config.NSCLIENT)

View file

@ -147,7 +147,7 @@ public class ComboPlugin extends PumpPluginBase implements PumpInterface, Constr
super(new PluginDescription() super(new PluginDescription()
.mainType(PluginType.PUMP) .mainType(PluginType.PUMP)
.fragmentClass(ComboFragment.class.getName()) .fragmentClass(ComboFragment.class.getName())
.pluginIcon(R.drawable.ic_combo) .pluginIcon(R.drawable.ic_combo_128)
.pluginName(R.string.combopump) .pluginName(R.string.combopump)
.shortName(R.string.combopump_shortname) .shortName(R.string.combopump_shortname)
.description(R.string.description_pump_combo), .description(R.string.description_pump_combo),
@ -338,7 +338,7 @@ public class ComboPlugin extends PumpPluginBase implements PumpInterface, Constr
* Runs pump initialization if needed and reads the pump state from the main screen. * Runs pump initialization if needed and reads the pump state from the main screen.
*/ */
@Override @Override
public synchronized void getPumpStatus() { public synchronized void getPumpStatus(String reason) {
getAapsLogger().debug(LTag.PUMP, "getPumpStatus called"); getAapsLogger().debug(LTag.PUMP, "getPumpStatus called");
if (!pump.initialized) { if (!pump.initialized) {
initializePump(); initializePump();

View file

@ -6,7 +6,6 @@ import android.content.ComponentName;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.ServiceConnection; import android.content.ServiceConnection;
import android.os.Build;
import android.os.Handler; import android.os.Handler;
import android.os.IBinder; import android.os.IBinder;
import android.os.Looper; import android.os.Looper;
@ -57,7 +56,6 @@ import info.nightscout.androidaps.plugins.bus.RxBusWrapper;
import info.nightscout.androidaps.plugins.common.ManufacturerType; import info.nightscout.androidaps.plugins.common.ManufacturerType;
import info.nightscout.androidaps.plugins.general.actions.defs.CustomAction; import info.nightscout.androidaps.plugins.general.actions.defs.CustomAction;
import info.nightscout.androidaps.plugins.general.actions.defs.CustomActionType; import info.nightscout.androidaps.plugins.general.actions.defs.CustomActionType;
import info.nightscout.androidaps.queue.commands.CustomCommand;
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.general.nsclient.UploadQueue;
import info.nightscout.androidaps.plugins.general.overview.events.EventDismissNotification; import info.nightscout.androidaps.plugins.general.overview.events.EventDismissNotification;
@ -135,6 +133,7 @@ import info.nightscout.androidaps.plugins.pump.insight.exceptions.app_layer_erro
import info.nightscout.androidaps.plugins.pump.insight.utils.ExceptionTranslator; import info.nightscout.androidaps.plugins.pump.insight.utils.ExceptionTranslator;
import info.nightscout.androidaps.plugins.pump.insight.utils.ParameterBlockUtil; import info.nightscout.androidaps.plugins.pump.insight.utils.ParameterBlockUtil;
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin; import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin;
import info.nightscout.androidaps.queue.commands.CustomCommand;
import info.nightscout.androidaps.utils.DateUtil; import info.nightscout.androidaps.utils.DateUtil;
import info.nightscout.androidaps.utils.TimeChangeType; import info.nightscout.androidaps.utils.TimeChangeType;
import info.nightscout.androidaps.utils.resources.ResourceHelper; import info.nightscout.androidaps.utils.resources.ResourceHelper;
@ -219,7 +218,7 @@ public class LocalInsightPlugin extends PumpPluginBase implements PumpInterface,
DateUtil dateUtil DateUtil dateUtil
) { ) {
super(new PluginDescription() super(new PluginDescription()
.pluginIcon(R.drawable.ic_insight) .pluginIcon(R.drawable.ic_insight_128)
.pluginName(R.string.insight_local) .pluginName(R.string.insight_local)
.shortName(R.string.insightpump_shortname) .shortName(R.string.insightpump_shortname)
.mainType(PluginType.PUMP) .mainType(PluginType.PUMP)
@ -294,13 +293,11 @@ public class LocalInsightPlugin extends PumpPluginBase implements PumpInterface,
} }
private void createNotificationChannel() { private void createNotificationChannel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
NotificationChannel channel = new NotificationChannel(ALERT_CHANNEL_ID, resourceHelper.gs(R.string.insight_alert_notification_channel), NotificationManager.IMPORTANCE_HIGH); NotificationChannel channel = new NotificationChannel(ALERT_CHANNEL_ID, resourceHelper.gs(R.string.insight_alert_notification_channel), NotificationManager.IMPORTANCE_HIGH);
channel.setSound(null, null); channel.setSound(null, null);
notificationManager.createNotificationChannel(channel); notificationManager.createNotificationChannel(channel);
} }
}
@Override @Override
protected void onStop() { protected void onStop() {
@ -370,7 +367,7 @@ public class LocalInsightPlugin extends PumpPluginBase implements PumpInterface,
} }
@Override @Override
public void getPumpStatus() { public void getPumpStatus(String reason) {
try { try {
tbrOverNotificationBlock = ParameterBlockUtil.readParameterBlock(connectionService, Service.CONFIGURATION, TBROverNotificationBlock.class); tbrOverNotificationBlock = ParameterBlockUtil.readParameterBlock(connectionService, Service.CONFIGURATION, TBROverNotificationBlock.class);
readHistory(); readHistory();
@ -600,7 +597,7 @@ public class LocalInsightPlugin extends PumpPluginBase implements PumpInterface,
bolusMessage.setDuration(0); bolusMessage.setDuration(0);
bolusMessage.setExtendedAmount(0); bolusMessage.setExtendedAmount(0);
bolusMessage.setImmediateAmount(insulin); bolusMessage.setImmediateAmount(insulin);
bolusMessage.setVibration(sp.getBoolean(detailedBolusInfo.isSMB ? R.string.key_disable_vibration_auto : R.string.key_disable_vibration ,false)); bolusMessage.setVibration(sp.getBoolean(detailedBolusInfo.isSMB ? R.string.key_disable_vibration_auto : R.string.key_disable_vibration, false));
bolusID = connectionService.requestMessage(bolusMessage).await().getBolusId(); bolusID = connectionService.requestMessage(bolusMessage).await().getBolusId();
bolusCancelled = false; bolusCancelled = false;
} }
@ -725,7 +722,7 @@ public class LocalInsightPlugin extends PumpPluginBase implements PumpInterface,
if (cancelTBRResult.success) { if (cancelTBRResult.success) {
PumpEnactResult ebResult = setExtendedBolusOnly((absoluteRate - getBaseBasalRate()) / 60D PumpEnactResult ebResult = setExtendedBolusOnly((absoluteRate - getBaseBasalRate()) / 60D
* ((double) durationInMinutes), durationInMinutes, * ((double) durationInMinutes), durationInMinutes,
sp.getBoolean(R.string.key_disable_vibration_auto,false)); sp.getBoolean(R.string.key_disable_vibration_auto, false));
if (ebResult.success) { if (ebResult.success) {
result.success = true; result.success = true;
result.enacted = true; result.enacted = true;
@ -803,7 +800,8 @@ public class LocalInsightPlugin extends PumpPluginBase implements PumpInterface,
@NonNull @Override @NonNull @Override
public PumpEnactResult setExtendedBolus(Double insulin, Integer durationInMinutes) { public PumpEnactResult setExtendedBolus(Double insulin, Integer durationInMinutes) {
PumpEnactResult result = cancelExtendedBolusOnly(); PumpEnactResult result = cancelExtendedBolusOnly();
if (result.success) result = setExtendedBolusOnly(insulin, durationInMinutes, sp.getBoolean(R.string.key_disable_vibration,false)); if (result.success)
result = setExtendedBolusOnly(insulin, durationInMinutes, sp.getBoolean(R.string.key_disable_vibration, false));
try { try {
fetchStatus(); fetchStatus();
readHistory(); readHistory();

View file

@ -57,6 +57,7 @@ public class MDIPlugin extends PumpPluginBase implements PumpInterface {
) { ) {
super(new PluginDescription() super(new PluginDescription()
.mainType(PluginType.PUMP) .mainType(PluginType.PUMP)
.pluginIcon(R.drawable.ic_ict)
.pluginName(R.string.mdi) .pluginName(R.string.mdi)
.description(R.string.description_pump_mdi), .description(R.string.description_pump_mdi),
injector, aapsLogger, resourceHelper, commandQueue injector, aapsLogger, resourceHelper, commandQueue
@ -132,7 +133,7 @@ public class MDIPlugin extends PumpPluginBase implements PumpInterface {
} }
@Override @Override
public void getPumpStatus() { public void getPumpStatus(String reason) {
} }
@NonNull @Override @NonNull @Override

View file

@ -7,6 +7,7 @@ import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import dagger.android.support.DaggerFragment import dagger.android.support.DaggerFragment
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.databinding.VirtualpumpFragmentBinding
import info.nightscout.androidaps.events.EventExtendedBolusChange import info.nightscout.androidaps.events.EventExtendedBolusChange
import info.nightscout.androidaps.events.EventTempBasalChange import info.nightscout.androidaps.events.EventTempBasalChange
import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.plugins.bus.RxBusWrapper
@ -18,10 +19,10 @@ import info.nightscout.androidaps.utils.extensions.plusAssign
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.virtualpump_fragment.*
import javax.inject.Inject import javax.inject.Inject
class VirtualPumpFragment : DaggerFragment() { class VirtualPumpFragment : DaggerFragment() {
@Inject lateinit var rxBus: RxBusWrapper @Inject lateinit var rxBus: RxBusWrapper
@Inject lateinit var resourceHelper: ResourceHelper @Inject lateinit var resourceHelper: ResourceHelper
@Inject lateinit var fabricPrivacy: FabricPrivacy @Inject lateinit var fabricPrivacy: FabricPrivacy
@ -40,8 +41,15 @@ class VirtualPumpFragment : DaggerFragment() {
} }
} }
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { private var _binding: VirtualpumpFragmentBinding? = null
return inflater.inflate(R.layout.virtualpump_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 = VirtualpumpFragmentBinding.inflate(inflater, container, false)
return binding.root
} }
@Synchronized @Synchronized
@ -70,20 +78,27 @@ class VirtualPumpFragment : DaggerFragment() {
loopHandler.removeCallbacks(refreshLoop) loopHandler.removeCallbacks(refreshLoop)
} }
@Synchronized
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
@Synchronized @Synchronized
private fun updateGui() { private fun updateGui() {
virtualpump_basabasalrate?.text = resourceHelper.gs(R.string.pump_basebasalrate, virtualPumpPlugin.baseBasalRate) if (_binding == null) return
virtualpump_tempbasal?.text = treatmentsPlugin.getTempBasalFromHistory(System.currentTimeMillis())?.toStringFull() binding.basabasalrate.text = resourceHelper.gs(R.string.pump_basebasalrate, virtualPumpPlugin.baseBasalRate)
binding.tempbasal.text = treatmentsPlugin.getTempBasalFromHistory(System.currentTimeMillis())?.toStringFull()
?: "" ?: ""
virtualpump_extendedbolus?.text = treatmentsPlugin.getExtendedBolusFromHistory(System.currentTimeMillis())?.toString() binding.extendedbolus.text = treatmentsPlugin.getExtendedBolusFromHistory(System.currentTimeMillis())?.toString()
?: "" ?: ""
virtualpump_battery?.text = resourceHelper.gs(R.string.format_percent, virtualPumpPlugin.batteryPercent) binding.battery.text = resourceHelper.gs(R.string.format_percent, virtualPumpPlugin.batteryPercent)
virtualpump_reservoir?.text = resourceHelper.gs(R.string.formatinsulinunits, virtualPumpPlugin.reservoirInUnits.toDouble()) binding.reservoir.text = resourceHelper.gs(R.string.formatinsulinunits, virtualPumpPlugin.reservoirInUnits.toDouble())
virtualPumpPlugin.refreshConfiguration() virtualPumpPlugin.refreshConfiguration()
val pumpType = virtualPumpPlugin.pumpType val pumpType = virtualPumpPlugin.pumpType
virtualpump_type?.text = pumpType?.description binding.type.text = pumpType?.description
virtualpump_type_def?.text = pumpType?.getFullDescription(resourceHelper.gs(R.string.virtualpump_pump_def), pumpType.hasExtendedBasals(), resourceHelper) binding.typeDef.text = pumpType?.getFullDescription(resourceHelper.gs(R.string.virtualpump_pump_def), pumpType.hasExtendedBasals(), resourceHelper)
} }
} }

View file

@ -58,6 +58,7 @@ class VirtualPumpPlugin @Inject constructor(
) : PumpPluginBase(PluginDescription() ) : PumpPluginBase(PluginDescription()
.mainType(PluginType.PUMP) .mainType(PluginType.PUMP)
.fragmentClass(VirtualPumpFragment::class.java.name) .fragmentClass(VirtualPumpFragment::class.java.name)
.pluginIcon(R.drawable.ic_virtual_pump)
.pluginName(R.string.virtualpump) .pluginName(R.string.virtualpump)
.shortName(R.string.virtualpump_shortname) .shortName(R.string.virtualpump_shortname)
.preferencesId(R.xml.pref_virtualpump) .preferencesId(R.xml.pref_virtualpump)
@ -178,7 +179,7 @@ class VirtualPumpPlugin @Inject constructor(
override fun disconnect(reason: String) {} override fun disconnect(reason: String) {}
override fun stopConnecting() {} override fun stopConnecting() {}
override fun getPumpStatus() { override fun getPumpStatus(reason: String?) {
lastDataTime = System.currentTimeMillis() lastDataTime = System.currentTimeMillis()
} }

View file

@ -56,6 +56,7 @@ public class SensitivityAAPSPlugin extends AbstractSensitivityPlugin {
) { ) {
super(new PluginDescription() super(new PluginDescription()
.mainType(PluginType.SENSITIVITY) .mainType(PluginType.SENSITIVITY)
.pluginIcon(R.drawable.ic_generic_icon)
.pluginName(R.string.sensitivityaaps) .pluginName(R.string.sensitivityaaps)
.shortName(R.string.sensitivity_shortname) .shortName(R.string.sensitivity_shortname)
.preferencesId(R.xml.pref_absorption_aaps) .preferencesId(R.xml.pref_absorption_aaps)

View file

@ -55,6 +55,7 @@ public class SensitivityOref1Plugin extends AbstractSensitivityPlugin {
) { ) {
super(new PluginDescription() super(new PluginDescription()
.mainType(PluginType.SENSITIVITY) .mainType(PluginType.SENSITIVITY)
.pluginIcon(R.drawable.ic_generic_icon)
.pluginName(R.string.sensitivityoref1) .pluginName(R.string.sensitivityoref1)
.shortName(R.string.sensitivity_shortname) .shortName(R.string.sensitivity_shortname)
.enableByDefault(true) .enableByDefault(true)

View file

@ -51,6 +51,7 @@ public class SensitivityWeightedAveragePlugin extends AbstractSensitivityPlugin
) { ) {
super(new PluginDescription() super(new PluginDescription()
.mainType(PluginType.SENSITIVITY) .mainType(PluginType.SENSITIVITY)
.pluginIcon(R.drawable.ic_generic_icon)
.pluginName(R.string.sensitivityweightedaverage) .pluginName(R.string.sensitivityweightedaverage)
.shortName(R.string.sensitivity_shortname) .shortName(R.string.sensitivity_shortname)
.preferencesId(R.xml.pref_absorption_aaps) .preferencesId(R.xml.pref_absorption_aaps)

View file

@ -38,6 +38,7 @@ class DexcomPlugin @Inject constructor(
) : PluginBase(PluginDescription() ) : PluginBase(PluginDescription()
.mainType(PluginType.BGSOURCE) .mainType(PluginType.BGSOURCE)
.fragmentClass(BGSourceFragment::class.java.name) .fragmentClass(BGSourceFragment::class.java.name)
.pluginIcon(R.drawable.ic_dexcom_g6)
.pluginName(R.string.dexcom_app_patched) .pluginName(R.string.dexcom_app_patched)
.shortName(R.string.dexcom_short) .shortName(R.string.dexcom_short)
.preferencesId(R.xml.pref_bgsourcedexcom) .preferencesId(R.xml.pref_bgsourcedexcom)

View file

@ -34,6 +34,7 @@ class EversensePlugin @Inject constructor(
) : PluginBase(PluginDescription() ) : PluginBase(PluginDescription()
.mainType(PluginType.BGSOURCE) .mainType(PluginType.BGSOURCE)
.fragmentClass(BGSourceFragment::class.java.name) .fragmentClass(BGSourceFragment::class.java.name)
.pluginIcon(R.drawable.ic_eversense)
.pluginName(R.string.eversense) .pluginName(R.string.eversense)
.shortName(R.string.eversense_shortname) .shortName(R.string.eversense_shortname)
.preferencesId(R.xml.pref_bgsource) .preferencesId(R.xml.pref_bgsource)

View file

@ -24,6 +24,7 @@ class GlimpPlugin @Inject constructor(
) : PluginBase(PluginDescription() ) : PluginBase(PluginDescription()
.mainType(PluginType.BGSOURCE) .mainType(PluginType.BGSOURCE)
.fragmentClass(BGSourceFragment::class.java.name) .fragmentClass(BGSourceFragment::class.java.name)
.pluginIcon(R.drawable.ic_glimp)
.pluginName(R.string.Glimp) .pluginName(R.string.Glimp)
.preferencesId(R.xml.pref_bgsource) .preferencesId(R.xml.pref_bgsource)
.description(R.string.description_source_glimp), .description(R.string.description_source_glimp),

View file

@ -25,6 +25,7 @@ class MM640gPlugin @Inject constructor(
) : PluginBase(PluginDescription() ) : PluginBase(PluginDescription()
.mainType(PluginType.BGSOURCE) .mainType(PluginType.BGSOURCE)
.fragmentClass(BGSourceFragment::class.java.name) .fragmentClass(BGSourceFragment::class.java.name)
.pluginIcon(R.drawable.ic_generic_cgm)
.pluginName(R.string.MM640g) .pluginName(R.string.MM640g)
.description(R.string.description_source_mm640g), .description(R.string.description_source_mm640g),
aapsLogger, resourceHelper, injector aapsLogger, resourceHelper, injector

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