diff --git a/app/build.gradle b/app/build.gradle
index 453bbeb071..e3666c9961 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -29,8 +29,7 @@ ext {
powermockVersion = "1.7.3"
dexmakerVersion = "1.2"
retrofit2Version = '2.8.1'
- okhttp3Version = '4.5.0'
- coroutinesVersion = '1.3.5'
+ okhttp3Version = '4.6.0'
}
@@ -165,6 +164,7 @@ android {
}
firebaseDisable {
System.setProperty("disableFirebase", "true")
+ ext.enableCrashlytics = false
}
}
productFlavors {
@@ -252,9 +252,9 @@ dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation 'com.google.android.gms:play-services-wearable:17.0.0'
implementation "com.google.android.gms:play-services-location:17.0.0"
- implementation 'com.google.firebase:firebase-core:17.3.0'
- implementation 'com.google.firebase:firebase-auth:19.3.0'
- implementation 'com.google.firebase:firebase-database:19.2.1'
+ implementation 'com.google.firebase:firebase-core:17.4.0'
+ implementation 'com.google.firebase:firebase-auth:19.3.1'
+ implementation 'com.google.firebase:firebase-database:19.3.0'
implementation('com.crashlytics.sdk.android:crashlytics:2.10.1@aar') {
transitive = true;
}
@@ -267,7 +267,9 @@ dependencies {
implementation 'androidx.recyclerview:recyclerview:1.1.0'
implementation 'androidx.gridlayout:gridlayout:1.0.0'
implementation 'androidx.percentlayout:percentlayout:1.0.0'
- implementation "androidx.preference:preference-ktx:1.1.0"
+ implementation "androidx.preference:preference-ktx:1.1.1"
+ implementation "androidx.activity:activity:${activityVersion}"
+ implementation "androidx.activity:activity-ktx:${activityVersion}"
implementation 'com.google.android.material:material:1.1.0'
implementation 'com.wdullaer:materialdatetimepicker:4.2.3'
@@ -278,7 +280,7 @@ dependencies {
implementation("com.github.tony19:logback-android-classic:1.1.1-6") {
exclude group: "com.google.android", module: "android"
}
- implementation "org.apache.commons:commons-lang3:3.9"
+ implementation 'org.apache.commons:commons-lang3:3.10'
implementation 'org.slf4j:slf4j-api:1.7.30'
// Graphview cannot be upgraded
implementation "com.jjoe64:graphview:4.0.1"
@@ -295,28 +297,28 @@ dependencies {
exclude group: "org.json", module: "json"
}
implementation "com.google.code.gson:gson:2.8.6"
- implementation ("com.google.guava:guava:24.1-jre") {
+ implementation('com.google.guava:guava:29.0-jre') {
exclude group: "com.google.code.findbugs", module: "jsr305"
}
implementation 'com.google.code.findbugs:jsr305:3.0.2'
- implementation "net.danlew:android.joda:2.10.3"
+ implementation 'net.danlew:android.joda:2.10.6'
- implementation 'org.mozilla:rhino:1.7.11'
+ implementation 'org.mozilla:rhino:1.7.12'
implementation 'com.github.DavidProdinger:weekdays-selector:1.1.0'
implementation 'com.github.kenglxn.QRGen:android:2.6.0'
implementation 'com.eatthepath:java-otp:0.2.0'
- testImplementation "junit:junit:4.12"
+ testImplementation "junit:junit:4.13"
testImplementation "org.json:json:20190722"
testImplementation "org.mockito:mockito-core:2.8.47"
testImplementation "org.powermock:powermock-api-mockito2:${powermockVersion}"
testImplementation "org.powermock:powermock-module-junit4-rule-agent:${powermockVersion}"
testImplementation "org.powermock:powermock-module-junit4-rule:${powermockVersion}"
testImplementation "org.powermock:powermock-module-junit4:${powermockVersion}"
- testImplementation "joda-time:joda-time:2.10.5"
+ testImplementation 'joda-time:joda-time:2.10.6'
testImplementation('com.google.truth:truth:1.0.1') {
exclude group: "com.google.guava", module: "guava"
exclude group: "com.google.code.findbugs", module: "jsr305"
@@ -337,24 +339,24 @@ dependencies {
implementation "com.squareup.retrofit2:converter-gson:$retrofit2Version"
// Phone checker
- implementation 'com.scottyab:rootbeer-lib:0.0.7'
+ implementation 'com.scottyab:rootbeer-lib:0.0.8'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0-alpha03'
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
- androidTestImplementation 'androidx.test:rules:1.3.0-alpha03'
+ androidTestImplementation 'androidx.test:rules:1.3.0-beta01'
androidTestImplementation 'com.google.code.findbugs:jsr305:3.0.2'
/* Dagger2 - We are going to use dagger.android which includes
* support for Activity and fragment injection so we need to include
* the following dependencies */
- implementation 'com.google.dagger:dagger-android:2.25.2'
- implementation 'com.google.dagger:dagger-android-support:2.25.2'
- annotationProcessor 'com.google.dagger:dagger-compiler:2.25.2'
- annotationProcessor 'com.google.dagger:dagger-android-processor:2.25.2'
- kapt 'com.google.dagger:dagger-android-processor:2.25.2'
+ implementation "com.google.dagger:dagger-android:$dagger_version"
+ implementation "com.google.dagger:dagger-android-support:$dagger_version"
+ annotationProcessor "com.google.dagger:dagger-compiler:$dagger_version"
+ annotationProcessor "com.google.dagger:dagger-android-processor:$dagger_version"
+ kapt "com.google.dagger:dagger-android-processor:$dagger_version"
/* Dagger2 - default dependency */
- kapt 'com.google.dagger:dagger-compiler:2.25.2'
+ kapt "com.google.dagger:dagger-compiler:$dagger_version"
androidTestImplementation 'androidx.test.uiautomator:uiautomator:2.2.0'
}
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index d46a35c1bf..cd4b814b6c 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -82,6 +82,7 @@
+
diff --git a/app/src/main/java/info/nightscout/androidaps/MainActivity.kt b/app/src/main/java/info/nightscout/androidaps/MainActivity.kt
index 4bcfd5611a..4e58a1f21f 100644
--- a/app/src/main/java/info/nightscout/androidaps/MainActivity.kt
+++ b/app/src/main/java/info/nightscout/androidaps/MainActivity.kt
@@ -47,7 +47,6 @@ import info.nightscout.androidaps.plugins.constraints.versionChecker.VersionChec
import info.nightscout.androidaps.plugins.general.nsclient.data.NSSettingsStatus
import info.nightscout.androidaps.plugins.general.smsCommunicator.SmsCommunicatorPlugin
import info.nightscout.androidaps.setupwizard.SetupWizardActivity
-import info.nightscout.androidaps.utils.tabs.TabPageAdapter
import info.nightscout.androidaps.utils.AndroidPermission
import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.LocaleHelper
@@ -58,6 +57,8 @@ import info.nightscout.androidaps.utils.protection.ProtectionCheck
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.tabs.TabPageAdapter
+import info.nightscout.androidaps.utils.ui.UIRunnable
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable
import kotlinx.android.synthetic.main.activity_main.*
@@ -160,12 +161,9 @@ class MainActivity : NoSplashAppCompatActivity() {
override fun onResume() {
super.onResume()
protectionCheck.queryProtection(this, ProtectionCheck.Protection.APPLICATION, null,
- Runnable {
- OKDialog.show(this, "", resourceHelper.gs(R.string.authorizationfailed), Runnable { finish() })
- },
- Runnable {
- OKDialog.show(this, "", resourceHelper.gs(R.string.authorizationfailed), Runnable { finish() })
- })
+ UIRunnable(Runnable { OKDialog.show(this, "", resourceHelper.gs(R.string.authorizationfailed), Runnable { finish() }) }),
+ UIRunnable(Runnable { OKDialog.show(this, "", resourceHelper.gs(R.string.authorizationfailed), Runnable { finish() }) })
+ )
}
private fun setWakeLock() {
@@ -197,6 +195,7 @@ class MainActivity : NoSplashAppCompatActivity() {
}
}
main_pager.adapter = pageAdapter
+ main_pager.offscreenPageLimit = 8 // This may cause more memory consumption
checkPluginPreferences(main_pager)
// Tabs
diff --git a/app/src/main/java/info/nightscout/androidaps/activities/MyPreferenceFragment.kt b/app/src/main/java/info/nightscout/androidaps/activities/MyPreferenceFragment.kt
index d2057f3c19..ad5d314a14 100644
--- a/app/src/main/java/info/nightscout/androidaps/activities/MyPreferenceFragment.kt
+++ b/app/src/main/java/info/nightscout/androidaps/activities/MyPreferenceFragment.kt
@@ -280,7 +280,7 @@ class MyPreferenceFragment : PreferenceFragmentCompat(), OnSharedPreferenceChang
}
for (plugin in pluginStore.plugins) {
- pref?.let { pref-> pref.getKey()?.let { plugin.updatePreferenceSummary(pref) }}
+ pref?.let { it.key?.let { plugin.updatePreferenceSummary(pref) }}
}
val hmacPasswords = arrayOf(
diff --git a/app/src/main/java/info/nightscout/androidaps/db/CareportalEvent.java b/app/src/main/java/info/nightscout/androidaps/db/CareportalEvent.java
index d77d563e09..ea9e44e7fe 100644
--- a/app/src/main/java/info/nightscout/androidaps/db/CareportalEvent.java
+++ b/app/src/main/java/info/nightscout/androidaps/db/CareportalEvent.java
@@ -106,7 +106,7 @@ public class CareportalEvent implements DataPointWithLabelInterface, Interval {
}
public String age(boolean useShortText, ResourceHelper resourceHelper) {
- Map diff = computeDiff(date, System.currentTimeMillis());
+ Map diff = DateUtil.computeDiff(date, System.currentTimeMillis());
String days = " " + resourceHelper.gs(R.string.days) + " ";
String hours = " " + resourceHelper.gs(R.string.hours) + " ";
@@ -135,23 +135,6 @@ public class CareportalEvent implements DataPointWithLabelInterface, Interval {
"}";
}
- //Map:{DAYS=1, HOURS=3, MINUTES=46, SECONDS=40, MILLISECONDS=0, MICROSECONDS=0, NANOSECONDS=0}
- private static Map computeDiff(long date1, long date2) {
- long diffInMillies = date2 - date1;
- List units = new ArrayList<>(EnumSet.allOf(TimeUnit.class));
- Collections.reverse(units);
- Map result = new LinkedHashMap<>();
- long milliesRest = diffInMillies;
- for (TimeUnit unit : units) {
- long diff = unit.convert(milliesRest, TimeUnit.MILLISECONDS);
- long diffInMilliesForUnit = unit.toMillis(diff);
- milliesRest = milliesRest - diffInMilliesForUnit;
- result.put(unit, diff);
- }
- return result;
- }
-
-
public boolean isEvent5minBack(List list, long time) {
for (int i = 0; i < list.size(); i++) {
CareportalEvent event = list.get(i);
diff --git a/app/src/main/java/info/nightscout/androidaps/db/TemporaryBasal.java b/app/src/main/java/info/nightscout/androidaps/db/TemporaryBasal.java
index aa902b0867..937022196c 100644
--- a/app/src/main/java/info/nightscout/androidaps/db/TemporaryBasal.java
+++ b/app/src/main/java/info/nightscout/androidaps/db/TemporaryBasal.java
@@ -510,9 +510,9 @@ public class TemporaryBasal implements Interval, DbObjectBase {
} else {
rate = absoluteRate;
}
- return DecimalFormatter.to2Decimal(rate) + "U/h ";
+ return DecimalFormatter.to2Decimal(rate) + "U/h";
} else { // percent
- return percentRate + "% ";
+ return percentRate + "%";
}
}
diff --git a/app/src/main/java/info/nightscout/androidaps/dependencyInjection/ActivitiesModule.kt b/app/src/main/java/info/nightscout/androidaps/dependencyInjection/ActivitiesModule.kt
index 93cac53038..2f6d515b0e 100644
--- a/app/src/main/java/info/nightscout/androidaps/dependencyInjection/ActivitiesModule.kt
+++ b/app/src/main/java/info/nightscout/androidaps/dependencyInjection/ActivitiesModule.kt
@@ -6,6 +6,7 @@ import info.nightscout.androidaps.MainActivity
import info.nightscout.androidaps.activities.*
import info.nightscout.androidaps.historyBrowser.HistoryBrowseActivity
import info.nightscout.androidaps.plugins.general.maintenance.activities.LogSettingActivity
+import info.nightscout.androidaps.plugins.general.maintenance.activities.PrefImportListActivity
import info.nightscout.androidaps.plugins.general.overview.activities.QuickWizardListActivity
import info.nightscout.androidaps.plugins.general.smsCommunicator.activities.SmsCommunicatorOtpActivity
import info.nightscout.androidaps.plugins.pump.common.dialog.RileyLinkBLEScanActivity
@@ -18,8 +19,6 @@ import info.nightscout.androidaps.plugins.pump.insight.activities.InsightAlertAc
import info.nightscout.androidaps.plugins.pump.insight.activities.InsightPairingActivity
import info.nightscout.androidaps.plugins.pump.insight.activities.InsightPairingInformationActivity
import info.nightscout.androidaps.plugins.pump.medtronic.dialog.MedtronicHistoryActivity
-import info.nightscout.androidaps.plugins.pump.omnipod.dialogs.PodHistoryActivity
-import info.nightscout.androidaps.plugins.pump.omnipod.dialogs.PodManagementActivity
import info.nightscout.androidaps.setupwizard.SetupWizardActivity
@Module
@@ -50,5 +49,5 @@ abstract class ActivitiesModule {
@ContributesAndroidInjector abstract fun contributesStatsActivity(): StatsActivity
@ContributesAndroidInjector abstract fun contributesSurveyActivity(): SurveyActivity
@ContributesAndroidInjector abstract fun contributesTDDStatsActivity(): TDDStatsActivity
-
+ @ContributesAndroidInjector abstract fun contributesPrefImportListActivity(): PrefImportListActivity
}
\ No newline at end of file
diff --git a/app/src/main/java/info/nightscout/androidaps/dependencyInjection/AppComponent.kt b/app/src/main/java/info/nightscout/androidaps/dependencyInjection/AppComponent.kt
index 1bb1595863..a836da500e 100644
--- a/app/src/main/java/info/nightscout/androidaps/dependencyInjection/AppComponent.kt
+++ b/app/src/main/java/info/nightscout/androidaps/dependencyInjection/AppComponent.kt
@@ -69,7 +69,8 @@ import javax.inject.Singleton
PreferencesModule::class,
OverviewModule::class,
DataClassesModule::class,
- SMSModule::class
+ SMSModule::class,
+ UIModule::class
]
)
interface AppComponent : AndroidInjector {
diff --git a/app/src/main/java/info/nightscout/androidaps/dependencyInjection/AppModule.kt b/app/src/main/java/info/nightscout/androidaps/dependencyInjection/AppModule.kt
index 548402341b..944fe3615f 100644
--- a/app/src/main/java/info/nightscout/androidaps/dependencyInjection/AppModule.kt
+++ b/app/src/main/java/info/nightscout/androidaps/dependencyInjection/AppModule.kt
@@ -23,7 +23,11 @@ import info.nightscout.androidaps.utils.storage.FileStorage
import info.nightscout.androidaps.utils.storage.Storage
import javax.inject.Singleton
-@Module(includes = [AppModule.AppBindings::class, PluginsModule::class])
+@Module(includes = [
+ AppModule.AppBindings::class,
+ PluginsModule::class,
+ SkinsModule::class
+])
open class AppModule {
@Provides
diff --git a/app/src/main/java/info/nightscout/androidaps/dependencyInjection/OmnipodModule.kt b/app/src/main/java/info/nightscout/androidaps/dependencyInjection/OmnipodModule.kt
index d60f2d8bfb..ccb538dfbd 100644
--- a/app/src/main/java/info/nightscout/androidaps/dependencyInjection/OmnipodModule.kt
+++ b/app/src/main/java/info/nightscout/androidaps/dependencyInjection/OmnipodModule.kt
@@ -4,6 +4,8 @@ import dagger.Module
import dagger.android.ContributesAndroidInjector
import info.nightscout.androidaps.plugins.pump.omnipod.comm.OmnipodCommunicationManager
import info.nightscout.androidaps.plugins.pump.omnipod.defs.state.PodSessionState
+import info.nightscout.androidaps.plugins.pump.omnipod.dialogs.PodHistoryActivity
+import info.nightscout.androidaps.plugins.pump.omnipod.dialogs.PodManagementActivity
import info.nightscout.androidaps.plugins.pump.omnipod.dialogs.wizard.pages.InitPodRefreshAction
import info.nightscout.androidaps.plugins.pump.omnipod.driver.comm.AapsOmnipodManager
import info.nightscout.androidaps.plugins.pump.omnipod.driver.ui.OmnipodUITask
@@ -12,10 +14,15 @@ import info.nightscout.androidaps.plugins.pump.omnipod.driver.ui.OmnipodUITask
@Suppress("unused")
abstract class OmnipodModule {
+ // Activities
+ @ContributesAndroidInjector abstract fun contributesPodManagementActivity(): PodManagementActivity
+ @ContributesAndroidInjector abstract fun contributesPodHistoryActivity(): PodHistoryActivity
+
@ContributesAndroidInjector abstract fun omnipodCommunicationManagerProvider(): OmnipodCommunicationManager
@ContributesAndroidInjector abstract fun omnipodUITaskProvider(): OmnipodUITask
@ContributesAndroidInjector abstract fun aapsOmnipodManagerProvider(): AapsOmnipodManager
@ContributesAndroidInjector abstract fun initPodRefreshAction(): InitPodRefreshAction
@ContributesAndroidInjector abstract fun podSessionState(): PodSessionState
-}
\ No newline at end of file
+
+}
diff --git a/app/src/main/java/info/nightscout/androidaps/dependencyInjection/PreferencesModule.kt b/app/src/main/java/info/nightscout/androidaps/dependencyInjection/PreferencesModule.kt
index fa2df68ef0..39fb959c15 100644
--- a/app/src/main/java/info/nightscout/androidaps/dependencyInjection/PreferencesModule.kt
+++ b/app/src/main/java/info/nightscout/androidaps/dependencyInjection/PreferencesModule.kt
@@ -3,6 +3,7 @@ package info.nightscout.androidaps.dependencyInjection
import dagger.Module
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.formats.ClassicPrefsFormat
import info.nightscout.androidaps.plugins.general.maintenance.formats.EncryptedPrefsFormat
import info.nightscout.androidaps.utils.CryptoUtil
@@ -15,4 +16,5 @@ abstract class PreferencesModule {
@ContributesAndroidInjector abstract fun importExportPrefsInjector(): ImportExportPrefs
@ContributesAndroidInjector abstract fun encryptedPrefsFormatInjector(): EncryptedPrefsFormat
@ContributesAndroidInjector abstract fun classicPrefsFormatInjector(): ClassicPrefsFormat
+ @ContributesAndroidInjector abstract fun prefImportListProviderInjector(): PrefFileListProvider
}
\ No newline at end of file
diff --git a/app/src/main/java/info/nightscout/androidaps/dependencyInjection/SkinsModule.kt b/app/src/main/java/info/nightscout/androidaps/dependencyInjection/SkinsModule.kt
new file mode 100644
index 0000000000..ebd4691f38
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/dependencyInjection/SkinsModule.kt
@@ -0,0 +1,30 @@
+package info.nightscout.androidaps.dependencyInjection
+
+import dagger.Binds
+import dagger.Module
+import dagger.Provides
+import dagger.multibindings.IntKey
+import dagger.multibindings.IntoMap
+import info.nightscout.androidaps.skins.SkinButtonsOn
+import info.nightscout.androidaps.skins.SkinClassic
+import info.nightscout.androidaps.skins.SkinInterface
+import javax.inject.Qualifier
+
+@Module
+open class SkinsModule {
+
+ @Provides
+ @Skin
+ @IntoMap
+ @IntKey(0)
+ fun bindsSkinClassic(skinClassic: SkinClassic): SkinInterface = skinClassic
+
+ @Provides
+ @Skin
+ @IntoMap
+ @IntKey(10)
+ fun bindsSkinButtonsOn(skinButtonsOn: SkinButtonsOn): SkinInterface = skinButtonsOn
+
+ @Qualifier
+ annotation class Skin
+}
\ No newline at end of file
diff --git a/app/src/main/java/info/nightscout/androidaps/dependencyInjection/UIModule.kt b/app/src/main/java/info/nightscout/androidaps/dependencyInjection/UIModule.kt
new file mode 100644
index 0000000000..50abc0b69a
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/dependencyInjection/UIModule.kt
@@ -0,0 +1,21 @@
+package info.nightscout.androidaps.dependencyInjection
+
+import dagger.Module
+import dagger.android.ContributesAndroidInjector
+import info.nightscout.androidaps.plugins.aps.loop.APSResult
+import info.nightscout.androidaps.plugins.aps.openAPSAMA.DetermineBasalResultAMA
+import info.nightscout.androidaps.plugins.aps.openAPSSMB.DetermineBasalAdapterSMBJS
+import info.nightscout.androidaps.plugins.aps.openAPSSMB.DetermineBasalResultSMB
+import info.nightscout.androidaps.plugins.constraints.objectives.objectives.*
+import info.nightscout.androidaps.plugins.general.overview.graphData.GraphData
+import info.nightscout.androidaps.plugins.general.overview.notifications.NotificationWithAction
+import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensData
+import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobOref1Thread
+import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobThread
+import info.nightscout.androidaps.skins.SkinListPreference
+
+@Module
+@Suppress("unused")
+abstract class UIModule {
+ @ContributesAndroidInjector abstract fun skinListPreferenceInjector(): SkinListPreference
+}
\ No newline at end of file
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/ObjectivesFragment.kt b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/ObjectivesFragment.kt
index d891a89dda..5fe20f2968 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/ObjectivesFragment.kt
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/ObjectivesFragment.kt
@@ -212,7 +212,7 @@ class ObjectivesFragment : DaggerFragment() {
bundle.putInt("currentTask", taskPosition)
dialog.arguments = bundle
ObjectivesExamDialog.objective = objective
- fragmentManager?.let { dialog.show(it, "ObjectivesFragment") }
+ dialog.show(childFragmentManager, "ObjectivesFragment")
}
}
// horizontal line
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/phoneChecker/PhoneCheckerPlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/phoneChecker/PhoneCheckerPlugin.kt
index 749f7f795c..4ea2d78989 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/phoneChecker/PhoneCheckerPlugin.kt
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/phoneChecker/PhoneCheckerPlugin.kt
@@ -41,7 +41,7 @@ class PhoneCheckerPlugin @Inject constructor(
override fun onStart() {
super.onStart()
- phoneRooted = RootBeer(context).isRootedWithoutBusyBoxCheck()
+ phoneRooted = RootBeer(context).isRooted()
devMode = isDevModeEnabled()
}
}
\ No newline at end of file
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/versionChecker/VersionCheckerUtils.kt b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/versionChecker/VersionCheckerUtils.kt
index d1ce90fc72..636d623bd0 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/versionChecker/VersionCheckerUtils.kt
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/versionChecker/VersionCheckerUtils.kt
@@ -116,6 +116,14 @@ class VersionCheckerUtils @Inject constructor(
private fun String?.toNumberList() =
this?.numericVersionPart().takeIf { !it.isNullOrBlank() }?.split(".")?.map { it.toInt() }
+ fun versionDigits(versionString: String?): IntArray {
+ val digits = mutableListOf()
+ versionString?.numericVersionPart().toNumberList()?.let {
+ digits.addAll(it.take(4))
+ }
+ return digits.toIntArray()
+ }
+
fun findVersion(file: String?): String? {
val regex = "(.*)version(.*)\"(((\\d+)\\.)+(\\d+))\"(.*)".toRegex()
return file?.lines()?.filter { regex.matches(it) }?.mapNotNull { regex.matchEntire(it)?.groupValues?.getOrNull(3) }?.firstOrNull()
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/actions/ActionsFragment.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/actions/ActionsFragment.kt
index 9e80d9d331..6a324d74cc 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/general/actions/ActionsFragment.kt
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/actions/ActionsFragment.kt
@@ -25,14 +25,15 @@ import info.nightscout.androidaps.plugins.general.actions.defs.CustomAction
import info.nightscout.androidaps.plugins.general.overview.StatusLightHandler
import info.nightscout.androidaps.queue.Callback
import info.nightscout.androidaps.utils.FabricPrivacy
-import info.nightscout.androidaps.utils.alertDialogs.OKDialog
import info.nightscout.androidaps.utils.SingleClickButton
+import info.nightscout.androidaps.utils.alertDialogs.OKDialog
import info.nightscout.androidaps.utils.buildHelper.BuildHelper
import info.nightscout.androidaps.utils.extensions.plusAssign
-import info.nightscout.androidaps.utils.resources.ResourceHelper
-import info.nightscout.androidaps.utils.sharedPreferences.SP
import info.nightscout.androidaps.utils.extensions.toVisibility
import info.nightscout.androidaps.utils.protection.ProtectionCheck
+import info.nightscout.androidaps.utils.resources.ResourceHelper
+import info.nightscout.androidaps.utils.sharedPreferences.SP
+import info.nightscout.androidaps.utils.ui.UIRunnable
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable
import kotlinx.android.synthetic.main.actions_fragment.*
@@ -68,19 +69,19 @@ class ActionsFragment : DaggerFragment() {
super.onViewCreated(view, savedInstanceState)
actions_profileswitch.setOnClickListener {
- fragmentManager?.let { ProfileSwitchDialog().show(it, "Actions") }
+ ProfileSwitchDialog().show(childFragmentManager, "Actions")
}
actions_temptarget.setOnClickListener {
- fragmentManager?.let { TempTargetDialog().show(it, "Actions") }
+ TempTargetDialog().show(childFragmentManager, "Actions")
}
actions_extendedbolus.setOnClickListener {
activity?.let { activity ->
- protectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, Runnable {
+ protectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, UIRunnable(Runnable {
OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.extended_bolus), resourceHelper.gs(R.string.ebstopsloop),
Runnable {
- fragmentManager?.let { ExtendedBolusDialog().show(it, "Actions") }
+ ExtendedBolusDialog().show(childFragmentManager, "Actions")
}, null)
- })
+ }))
}
}
actions_extendedbolus_cancel.setOnClickListener {
@@ -101,7 +102,7 @@ class ActionsFragment : DaggerFragment() {
}
}
actions_settempbasal.setOnClickListener {
- fragmentManager?.let { TempBasalDialog().show(it, "Actions") }
+ TempBasalDialog().show(childFragmentManager, "Actions")
}
actions_canceltempbasal.setOnClickListener {
if (activePlugin.activeTreatments.isTempBasalInProgress) {
@@ -122,25 +123,25 @@ class ActionsFragment : DaggerFragment() {
}
actions_fill.setOnClickListener {
activity?.let { activity ->
- protectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, Runnable { fragmentManager?.let { FillDialog().show(it, "FillDialog") } })
+ protectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, UIRunnable(Runnable { FillDialog().show(childFragmentManager, "FillDialog") }))
}
}
actions_historybrowser.setOnClickListener { startActivity(Intent(context, HistoryBrowseActivity::class.java)) }
actions_tddstats.setOnClickListener { startActivity(Intent(context, TDDStatsActivity::class.java)) }
actions_bgcheck.setOnClickListener {
- fragmentManager?.let { CareDialog().setOptions(CareDialog.EventType.BGCHECK, R.string.careportal_bgcheck).show(it, "Actions") }
+ CareDialog().setOptions(CareDialog.EventType.BGCHECK, R.string.careportal_bgcheck).show(childFragmentManager, "Actions")
}
actions_cgmsensorinsert.setOnClickListener {
- fragmentManager?.let { CareDialog().setOptions(CareDialog.EventType.SENSOR_INSERT, R.string.careportal_cgmsensorinsert).show(it, "Actions") }
+ CareDialog().setOptions(CareDialog.EventType.SENSOR_INSERT, R.string.careportal_cgmsensorinsert).show(childFragmentManager, "Actions")
}
actions_pumpbatterychange.setOnClickListener {
- fragmentManager?.let { CareDialog().setOptions(CareDialog.EventType.BATTERY_CHANGE, R.string.careportal_pumpbatterychange).show(it, "Actions") }
+ CareDialog().setOptions(CareDialog.EventType.BATTERY_CHANGE, R.string.careportal_pumpbatterychange).show(childFragmentManager, "Actions")
}
actions_note.setOnClickListener {
- fragmentManager?.let { CareDialog().setOptions(CareDialog.EventType.NOTE, R.string.careportal_note).show(it, "Actions") }
+ CareDialog().setOptions(CareDialog.EventType.NOTE, R.string.careportal_note).show(childFragmentManager, "Actions")
}
actions_exercise.setOnClickListener {
- fragmentManager?.let { CareDialog().setOptions(CareDialog.EventType.EXERCISE, R.string.careportal_exercise).show(it, "Actions") }
+ CareDialog().setOptions(CareDialog.EventType.EXERCISE, R.string.careportal_exercise).show(childFragmentManager, "Actions")
}
sp.putBoolean(R.string.key_objectiveuseactions, true)
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/AutomationFragment.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/AutomationFragment.kt
index 4cf73af02f..3e472a9ce9 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/AutomationFragment.kt
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/AutomationFragment.kt
@@ -72,7 +72,7 @@ class AutomationFragment : DaggerFragment(), OnStartDragListener {
args.putString("event", AutomationEvent(mainApp).toJSON())
args.putInt("position", -1) // New event
dialog.arguments = args
- fragmentManager?.let { dialog.show(it, "EditEventDialog") }
+ dialog.show(childFragmentManager, "EditEventDialog")
}
val callback: ItemTouchHelper.Callback = SimpleItemTouchHelperCallback(eventListAdapter)
@@ -182,7 +182,7 @@ class AutomationFragment : DaggerFragment(), OnStartDragListener {
args.putString("event", event.toJSON())
args.putInt("position", position)
dialog.arguments = args
- fragmentManager?.let { dialog.show(it, "EditEventDialog") }
+ dialog.show(childFragmentManager, "EditEventDialog")
}
// Start a drag whenever the handle view it touched
holder.iconSort.setOnTouchListener { v: View, motionEvent: MotionEvent ->
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/dialogs/EditEventDialog.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/dialogs/EditEventDialog.kt
index 21a62bc0a5..44929a9dee 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/dialogs/EditEventDialog.kt
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/dialogs/EditEventDialog.kt
@@ -66,15 +66,15 @@ class EditEventDialog : DialogFragmentWithDate() {
args.putString("trigger", event.trigger.toJSON())
val dialog = EditTriggerDialog()
dialog.arguments = args
- fragmentManager?.let { dialog.show(it, "EditTriggerDialog") }
+ dialog.show(childFragmentManager, "EditTriggerDialog")
}
// setup action list view
- fragmentManager?.let { actionListAdapter = ActionListAdapter() }
+ actionListAdapter = ActionListAdapter()
automation_actionListView.layoutManager = LinearLayoutManager(context)
automation_actionListView.adapter = actionListAdapter
- automation_addAction.setOnClickListener { fragmentManager?.let { ChooseActionDialog().show(it, "ChooseActionDialog") } }
+ automation_addAction.setOnClickListener { ChooseActionDialog().show(childFragmentManager, "ChooseActionDialog") }
showPreconditions()
@@ -187,9 +187,7 @@ class EditEventDialog : DialogFragmentWithDate() {
args.putString("action", action.toJSON())
val dialog = EditActionDialog()
dialog.arguments = args
- fragmentManager?.let {
- dialog.show(it, "EditActionDialog")
- }
+ dialog.show(childFragmentManager, "EditActionDialog")
}
}
view.findViewById(R.id.automation_iconTrash).setOnClickListener {
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/careportal/CareportalFragment.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/careportal/CareportalFragment.kt
index 613dfeab32..4007e43b45 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/general/careportal/CareportalFragment.kt
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/careportal/CareportalFragment.kt
@@ -125,9 +125,7 @@ class CareportalFragment : DaggerFragment(), View.OnClickListener {
R.id.careportal_openapsoffline -> newDialog.setOptions(OPENAPSOFFLINE, R.string.careportal_openapsoffline)
R.id.careportal_temporarytarget -> newDialog.setOptions(TEMPTARGET, R.string.careportal_temporarytarget)
}
- fragmentManager?.let {
- NewNSTreatmentDialog().show(it, "CareportalFragment")
- }
+ NewNSTreatmentDialog().show(childFragmentManager, "CareportalFragment")
}
private fun updateGUI() {
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/maintenance/ImportExportPrefs.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/maintenance/ImportExportPrefs.kt
index 1d72212fb3..4d9021bb71 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/general/maintenance/ImportExportPrefs.kt
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/maintenance/ImportExportPrefs.kt
@@ -6,12 +6,12 @@ import android.bluetooth.BluetoothAdapter
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
-import android.os.Build
-import android.os.Environment
import android.provider.Settings
+import androidx.activity.invoke
import androidx.annotation.StringRes
import androidx.core.content.ContextCompat
import androidx.fragment.app.Fragment
+import androidx.fragment.app.FragmentActivity
import info.nightscout.androidaps.BuildConfig
import info.nightscout.androidaps.R
import info.nightscout.androidaps.activities.PreferencesActivity
@@ -22,9 +22,9 @@ import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.plugins.general.maintenance.formats.*
import info.nightscout.androidaps.plugins.general.smsCommunicator.otp.OneTimePassword
import info.nightscout.androidaps.utils.DateUtil
+import info.nightscout.androidaps.utils.ToastUtils
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
import info.nightscout.androidaps.utils.alertDialogs.OKDialog.show
-import info.nightscout.androidaps.utils.ToastUtils
import info.nightscout.androidaps.utils.alertDialogs.PrefImportSummaryDialog
import info.nightscout.androidaps.utils.alertDialogs.TwoMessagesAlertDialog
import info.nightscout.androidaps.utils.alertDialogs.WarningDialog
@@ -32,8 +32,6 @@ import info.nightscout.androidaps.utils.buildHelper.BuildHelper
import info.nightscout.androidaps.utils.protection.PasswordCheck
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.sharedPreferences.SP
-import org.joda.time.DateTime
-import org.joda.time.Days
import java.io.File
import java.io.FileNotFoundException
import java.io.IOException
@@ -51,37 +49,25 @@ private val PERMISSIONS_STORAGE = arrayOf(
Manifest.permission.WRITE_EXTERNAL_STORAGE
)
-private const val IMPORT_AGE_NOT_YET_OLD_DAYS = 60
-
@Singleton
class ImportExportPrefs @Inject constructor(
private var log: AAPSLogger,
private val resourceHelper: ResourceHelper,
private val sp: SP,
private val buildHelper: BuildHelper,
- private val otp: OneTimePassword,
private val rxBus: RxBusWrapper,
private val passwordCheck: PasswordCheck,
private val classicPrefsFormat: ClassicPrefsFormat,
- private val encryptedPrefsFormat: EncryptedPrefsFormat
+ private val encryptedPrefsFormat: EncryptedPrefsFormat,
+ private val prefFileList: PrefFileListProvider
) {
val TAG = LTag.CORE
- private val path = File(Environment.getExternalStorageDirectory().toString())
-
- private val file = File(path, resourceHelper.gs(R.string.app_name) + "Preferences")
- private val encFile = File(path, resourceHelper.gs(R.string.app_name) + "Preferences.json")
-
- fun prefsImportFile(): File {
- return if (encFile.exists()) encFile else file
- }
-
fun prefsFileExists(): Boolean {
- return encFile.exists() || file.exists()
+ return prefFileList.listPreferenceFiles().size > 0
}
-
fun exportSharedPreferences(f: Fragment) {
f.activity?.let { exportSharedPreferences(it) }
}
@@ -135,9 +121,6 @@ class ImportExportPrefs @Inject constructor(
return name
}
- private fun getCurrentDeviceModelString() =
- Build.MANUFACTURER + " " + Build.MODEL + " (" + Build.DEVICE + ")"
-
private fun prefsEncryptionIsDisabled() =
buildHelper.isEngineeringMode() && !sp.getBoolean(resourceHelper.gs(R.string.key_maintenance_encrypt_exported_prefs), true)
@@ -173,36 +156,41 @@ class ImportExportPrefs @Inject constructor(
return true
}
- private fun askToConfirmExport(activity: Activity, then: ((password: String) -> Unit)) {
+ private fun askToConfirmExport(activity: Activity, fileToExport: File, then: ((password: String) -> Unit)) {
if (!prefsEncryptionIsDisabled() && !assureMasterPasswordSet(activity, R.string.nav_export)) return
TwoMessagesAlertDialog.showAlert(activity, resourceHelper.gs(R.string.nav_export),
- resourceHelper.gs(R.string.export_to) + " " + encFile + " ?",
+ resourceHelper.gs(R.string.export_to) + " " + fileToExport + " ?",
resourceHelper.gs(R.string.password_preferences_encrypt_prompt), {
askForMasterPassIfNeeded(activity, R.string.preferences_export_canceled, then)
- }, null, R.drawable.ic_header_export)
+ }, null, R.drawable.ic_header_export)
}
- private fun askToConfirmImport(activity: Activity, fileToImport: File, then: ((password: String) -> Unit)) {
+ private fun askToConfirmImport(activity: Activity, fileToImport: PrefsFile, then: ((password: String) -> Unit)) {
- if (encFile.exists()) {
+ if (fileToImport.handler == PrefsFormatsHandler.ENCRYPTED) {
if (!assureMasterPasswordSet(activity, R.string.nav_import)) return
TwoMessagesAlertDialog.showAlert(activity, resourceHelper.gs(R.string.nav_import),
- resourceHelper.gs(R.string.import_from) + " " + fileToImport + " ?",
+ resourceHelper.gs(R.string.import_from) + " " + fileToImport.file + " ?",
resourceHelper.gs(R.string.password_preferences_decrypt_prompt), {
askForMasterPass(activity, R.string.preferences_import_canceled, then)
}, null, R.drawable.ic_header_import)
} else {
OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.nav_import),
- resourceHelper.gs(R.string.import_from) + " " + fileToImport + " ?",
+ resourceHelper.gs(R.string.import_from) + " " + fileToImport.file + " ?",
Runnable { then("") })
}
}
private fun exportSharedPreferences(activity: Activity) {
- askToConfirmExport(activity) { password ->
+
+ prefFileList.ensureExportDirExists()
+ val legacyFile = prefFileList.legacyFile()
+ val newFile = prefFileList.newExportFile()
+
+ askToConfirmExport(activity, newFile) { password ->
try {
val entries: MutableMap = mutableMapOf()
for ((key, value) in sp.getAll()) {
@@ -211,12 +199,14 @@ class ImportExportPrefs @Inject constructor(
val prefs = Prefs(entries, prepareMetadata(activity))
- classicPrefsFormat.savePreferences(file, prefs)
- encryptedPrefsFormat.savePreferences(encFile, prefs, password)
+ if (BuildConfig.DEBUG && buildHelper.isEngineeringMode()) {
+ classicPrefsFormat.savePreferences(legacyFile, prefs)
+ }
+ encryptedPrefsFormat.savePreferences(newFile, prefs, password)
ToastUtils.okToast(activity, resourceHelper.gs(R.string.exported))
} catch (e: FileNotFoundException) {
- ToastUtils.errorToast(activity, resourceHelper.gs(R.string.filenotfound) + " " + encFile)
+ ToastUtils.errorToast(activity, resourceHelper.gs(R.string.filenotfound) + " " + newFile)
log.error(TAG, "Unhandled exception", e)
} catch (e: IOException) {
ToastUtils.errorToast(activity, e.message)
@@ -226,21 +216,38 @@ class ImportExportPrefs @Inject constructor(
}
fun importSharedPreferences(fragment: Fragment) {
- fragment.activity?.let { importSharedPreferences(it) }
+ fragment.activity?.let { fragmentAct ->
+ val callForPrefFile = fragmentAct.registerForActivityResult(PrefsFileContract()) {
+ it?.let {
+ importSharedPreferences(fragmentAct, it)
+ }
+ }
+ callForPrefFile.invoke()
+ }
}
- fun importSharedPreferences(activity: Activity) {
+ fun importSharedPreferences(activity: FragmentActivity) {
+ val callForPrefFile = activity.registerForActivityResult(PrefsFileContract()) {
+ it?.let {
+ importSharedPreferences(activity, it)
+ }
+ }
+ callForPrefFile.invoke()
+ }
- val importFile = prefsImportFile()
+ private fun importSharedPreferences(activity: Activity, importFile: PrefsFile) {
askToConfirmImport(activity, importFile) { password ->
- val format: PrefsFormat = if (encFile.exists()) encryptedPrefsFormat else classicPrefsFormat
+ val format: PrefsFormat = when (importFile.handler) {
+ PrefsFormatsHandler.CLASSIC -> classicPrefsFormat
+ PrefsFormatsHandler.ENCRYPTED -> encryptedPrefsFormat
+ }
try {
- val prefs = format.loadPreferences(importFile, password)
- prefs.metadata = checkMetadata(prefs.metadata)
+ val prefs = format.loadPreferences(importFile.file, password)
+ prefs.metadata = prefFileList.checkMetadata(prefs.metadata)
// import is OK when we do not have errors (warnings are allowed)
val importOk = checkIfImportIsOk(prefs)
@@ -276,45 +283,6 @@ class ImportExportPrefs @Inject constructor(
}
}
- // check metadata for known issues, change their status and add info with explanations
- private fun checkMetadata(metadata: Map): Map {
- val meta = metadata.toMutableMap()
-
- meta[PrefsMetadataKey.AAPS_FLAVOUR]?.let { flavour ->
- val flavourOfPrefs = flavour.value
- if (flavour.value != BuildConfig.FLAVOR) {
- flavour.status = PrefsStatus.WARN
- flavour.info = resourceHelper.gs(R.string.metadata_warning_different_flavour, flavourOfPrefs, BuildConfig.FLAVOR)
- }
- }
-
- meta[PrefsMetadataKey.DEVICE_MODEL]?.let { model ->
- if (model.value != getCurrentDeviceModelString()) {
- model.status = PrefsStatus.WARN
- model.info = resourceHelper.gs(R.string.metadata_warning_different_device)
- }
- }
-
- meta[PrefsMetadataKey.CREATED_AT]?.let { createdAt ->
- try {
- val date1 = DateTime.parse(createdAt.value);
- val date2 = DateTime.now()
-
- val daysOld = Days.daysBetween(date1.toLocalDate(), date2.toLocalDate()).getDays()
-
- if (daysOld > IMPORT_AGE_NOT_YET_OLD_DAYS) {
- createdAt.status = PrefsStatus.WARN
- createdAt.info = resourceHelper.gs(R.string.metadata_warning_old_export, daysOld.toString())
- }
- } catch (e: Exception) {
- createdAt.status = PrefsStatus.WARN
- createdAt.info = resourceHelper.gs(R.string.metadata_warning_date_format)
- }
- }
-
- return meta
- }
-
private fun checkIfImportIsOk(prefs: Prefs): Boolean {
var importOk = true
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/maintenance/PrefFileListProvider.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/maintenance/PrefFileListProvider.kt
new file mode 100644
index 0000000000..52910dfff1
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/maintenance/PrefFileListProvider.kt
@@ -0,0 +1,219 @@
+package info.nightscout.androidaps.plugins.general.maintenance
+
+import android.app.Activity
+import android.content.Context
+import android.content.Intent
+import android.os.Build
+import android.os.Environment
+import android.os.Parcelable
+import androidx.activity.result.contract.ActivityResultContract
+import info.nightscout.androidaps.BuildConfig
+import info.nightscout.androidaps.R
+import info.nightscout.androidaps.logging.AAPSLogger
+import info.nightscout.androidaps.plugins.constraints.versionChecker.VersionCheckerUtils
+import info.nightscout.androidaps.plugins.general.maintenance.activities.PrefImportListActivity
+import info.nightscout.androidaps.plugins.general.maintenance.formats.*
+import info.nightscout.androidaps.utils.resources.ResourceHelper
+import info.nightscout.androidaps.utils.sharedPreferences.SP
+import info.nightscout.androidaps.utils.storage.Storage
+import kotlinx.android.parcel.Parcelize
+import kotlinx.android.parcel.RawValue
+import org.joda.time.DateTime
+import org.joda.time.Days
+import org.joda.time.Hours
+import org.joda.time.LocalDateTime
+import org.joda.time.format.DateTimeFormat
+import java.io.File
+import javax.inject.Inject
+import javax.inject.Singleton
+
+enum class PrefsImportDir {
+ ROOT_DIR,
+ AAPS_DIR
+}
+
+@Parcelize
+data class PrefsFile(
+ val file: File,
+ val baseDir: File,
+ val dirKind: PrefsImportDir,
+ val handler: PrefsFormatsHandler,
+
+ // metadata here is used only for list display
+ val metadata: @RawValue Map
+) : Parcelable
+
+class PrefsFileContract : ActivityResultContract() {
+
+ companion object {
+ const val OUTPUT_PARAM = "prefs_file"
+ }
+
+ override fun parseResult(resultCode: Int, intent: Intent?): PrefsFile? {
+ return when (resultCode) {
+ Activity.RESULT_OK -> intent?.getParcelableExtra(OUTPUT_PARAM)
+ else -> null
+ }
+ }
+
+ override fun createIntent(context: Context, input: Void?): Intent {
+ return Intent(context, PrefImportListActivity::class.java)
+ }
+}
+
+fun getCurrentDeviceModelString() =
+ Build.MANUFACTURER + " " + Build.MODEL + " (" + Build.DEVICE + ")"
+
+@Singleton
+class PrefFileListProvider @Inject constructor(
+ private val resourceHelper: ResourceHelper,
+ private val classicPrefsFormat: ClassicPrefsFormat,
+ private val encryptedPrefsFormat: EncryptedPrefsFormat,
+ private val storage: Storage,
+ private val versionCheckerUtils: VersionCheckerUtils
+) {
+
+ companion object {
+ private val path = File(Environment.getExternalStorageDirectory().toString())
+ private val aapsPath = File(path, "AAPS" + File.separator + "preferences")
+ private const val IMPORT_AGE_NOT_YET_OLD_DAYS = 60
+ }
+
+ /**
+ * This function tries to list possible preference files from main SDCard root dir and AAPS/preferences dir
+ * and tries to do quick assessment for preferences format plausibility.
+ * It does NOT load full metadata or is 100% accurate - it tries to do QUICK detection, based on:
+ * - file name and extension
+ * - predicted file contents
+ */
+ fun listPreferenceFiles(loadMetadata: Boolean = false): MutableList {
+ val prefFiles = mutableListOf()
+
+ // searching rood dir for legacy files
+ path.walk().maxDepth(1).filter { it.isFile && (it.name.endsWith(".json") || it.name.contains("Preferences")) }.forEach {
+ val contents = storage.getFileContents(it)
+ val detectedNew = encryptedPrefsFormat.isPreferencesFile(it, contents)
+ val detectedOld = !detectedNew && classicPrefsFormat.isPreferencesFile(it, contents)
+ if (detectedNew || detectedOld) {
+ val formatHandler = if (detectedNew) PrefsFormatsHandler.ENCRYPTED else PrefsFormatsHandler.CLASSIC
+ prefFiles.add(PrefsFile(it, path, PrefsImportDir.ROOT_DIR, formatHandler, metadataFor(loadMetadata, formatHandler, contents)))
+ }
+ }
+
+ // searching dedicated dir, only for new JSON format
+ aapsPath.walk().filter { it.isFile && it.name.endsWith(".json") }.forEach {
+ val contents = storage.getFileContents(it)
+ if (encryptedPrefsFormat.isPreferencesFile(it, contents)) {
+ prefFiles.add(PrefsFile(it, aapsPath, PrefsImportDir.AAPS_DIR, PrefsFormatsHandler.ENCRYPTED, metadataFor(loadMetadata, PrefsFormatsHandler.ENCRYPTED, contents)))
+ }
+ }
+
+ // we sort only if we have metadata to be used for that
+ if (loadMetadata) {
+ prefFiles.sortWith(
+ compareByDescending { it.handler }
+ .thenBy { it.metadata[PrefsMetadataKey.AAPS_FLAVOUR]?.status }
+ .thenByDescending { it.metadata[PrefsMetadataKey.CREATED_AT]?.value }
+ )
+ }
+
+ return prefFiles
+ }
+
+ private fun metadataFor(loadMetadata: Boolean, formatHandler: PrefsFormatsHandler, contents: String): PrefMetadataMap {
+ if (!loadMetadata) {
+ return mapOf()
+ }
+ return checkMetadata(when (formatHandler) {
+ PrefsFormatsHandler.CLASSIC -> classicPrefsFormat.loadMetadata(contents)
+ PrefsFormatsHandler.ENCRYPTED -> encryptedPrefsFormat.loadMetadata(contents)
+ })
+ }
+
+ fun legacyFile(): File {
+ return File(path, resourceHelper.gs(R.string.app_name) + "Preferences")
+ }
+
+ fun ensureExportDirExists() {
+ if (!aapsPath.exists()) {
+ aapsPath.mkdirs()
+ }
+ }
+
+ fun newExportFile(): File {
+ val timeLocal = LocalDateTime.now().toString(DateTimeFormat.forPattern("yyyy-MM-dd'_'HHmmss"))
+ return File(aapsPath, timeLocal + "_" + BuildConfig.FLAVOR + ".json")
+ }
+
+ // check metadata for known issues, change their status and add info with explanations
+ fun checkMetadata(metadata: Map): Map {
+ val meta = metadata.toMutableMap()
+
+ meta[PrefsMetadataKey.AAPS_FLAVOUR]?.let { flavour ->
+ val flavourOfPrefs = flavour.value
+ if (flavour.value != BuildConfig.FLAVOR) {
+ flavour.status = PrefsStatus.WARN
+ flavour.info = resourceHelper.gs(R.string.metadata_warning_different_flavour, flavourOfPrefs, BuildConfig.FLAVOR)
+ }
+ }
+
+ meta[PrefsMetadataKey.DEVICE_MODEL]?.let { model ->
+ if (model.value != getCurrentDeviceModelString()) {
+ model.status = PrefsStatus.WARN
+ model.info = resourceHelper.gs(R.string.metadata_warning_different_device)
+ }
+ }
+
+ meta[PrefsMetadataKey.CREATED_AT]?.let { createdAt ->
+ try {
+ val date1 = DateTime.parse(createdAt.value);
+ val date2 = DateTime.now()
+
+ val daysOld = Days.daysBetween(date1.toLocalDate(), date2.toLocalDate()).getDays()
+
+ if (daysOld > IMPORT_AGE_NOT_YET_OLD_DAYS) {
+ createdAt.status = PrefsStatus.WARN
+ createdAt.info = resourceHelper.gs(R.string.metadata_warning_old_export, daysOld.toString())
+ }
+ } catch (e: Exception) {
+ createdAt.status = PrefsStatus.WARN
+ createdAt.info = resourceHelper.gs(R.string.metadata_warning_date_format)
+ }
+ }
+
+ meta[PrefsMetadataKey.AAPS_VERSION]?.let { version ->
+ val currentAppVer = versionCheckerUtils.versionDigits(BuildConfig.VERSION_NAME)
+ val metadataVer = versionCheckerUtils.versionDigits(version.value)
+
+ if ((currentAppVer.size >= 2) && (metadataVer.size >= 2) && (Math.abs(currentAppVer[1] - metadataVer[1]) > 1)) {
+ version.status = PrefsStatus.WARN
+ version.info = resourceHelper.gs(R.string.metadata_warning_different_version)
+ }
+
+ if ((currentAppVer.isNotEmpty()) && (metadataVer.isNotEmpty()) && (currentAppVer[0] != metadataVer[0])) {
+ version.status = PrefsStatus.WARN
+ version.info = resourceHelper.gs(R.string.metadata_urgent_different_version)
+ }
+ }
+
+ return meta
+ }
+
+ fun formatExportedAgo(utcTime: String): String {
+ val refTime = DateTime.now()
+ val itTime = DateTime.parse(utcTime)
+ val days = Days.daysBetween(itTime, refTime).days
+ val hours = Hours.hoursBetween(itTime, refTime).hours
+
+ return if (hours == 0) {
+ resourceHelper.gs(R.string.exported_less_than_hour_ago)
+ } else if ((hours < 24) && (hours > 0)) {
+ resourceHelper.gs(R.string.exported_ago, resourceHelper.gq(R.plurals.objective_hours, hours, hours))
+ } else if ((days < IMPORT_AGE_NOT_YET_OLD_DAYS) && (days > 0)) {
+ resourceHelper.gs(R.string.exported_ago, resourceHelper.gq(R.plurals.objective_days, days, days))
+ } else {
+ resourceHelper.gs(R.string.exported_at, utcTime.substring(0, 10))
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/maintenance/activities/PrefImportListActivity.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/maintenance/activities/PrefImportListActivity.kt
new file mode 100644
index 0000000000..7703166d04
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/maintenance/activities/PrefImportListActivity.kt
@@ -0,0 +1,135 @@
+package info.nightscout.androidaps.plugins.general.maintenance.activities
+
+import android.app.Activity
+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.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.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) : RecyclerView.Adapter() {
+
+ 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(Activity.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))
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/maintenance/formats/ClassicPrefsFormat.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/maintenance/formats/ClassicPrefsFormat.kt
index 4689f549a6..40b1ceada4 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/general/maintenance/formats/ClassicPrefsFormat.kt
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/maintenance/formats/ClassicPrefsFormat.kt
@@ -1,5 +1,6 @@
package info.nightscout.androidaps.plugins.general.maintenance.formats
+import info.nightscout.androidaps.Constants
import info.nightscout.androidaps.R
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.storage.Storage
@@ -19,6 +20,11 @@ class ClassicPrefsFormat @Inject constructor(
val FORMAT_KEY = "aaps_old"
}
+ override fun isPreferencesFile(file: File, preloadedContents: String?): Boolean {
+ val contents = preloadedContents ?: storage.getFileContents(file)
+ return contents.contains("units::" + Constants.MGDL) || contents.contains("units::" + Constants.MMOL)
+ }
+
override fun savePreferences(file: File, prefs: Prefs, masterPassword: String?) {
try {
val contents = prefs.values.entries.joinToString("\n") { entry ->
@@ -35,7 +41,6 @@ class ClassicPrefsFormat @Inject constructor(
override fun loadPreferences(file: File, masterPassword: String?): Prefs {
var lineParts: Array
val entries: MutableMap = mutableMapOf()
- val metadata: MutableMap = mutableMapOf()
try {
val rawLines = storage.getFileContents(file).split("\n")
@@ -46,9 +51,7 @@ class ClassicPrefsFormat @Inject constructor(
}
}
- metadata[PrefsMetadataKey.FILE_FORMAT] = PrefMetadata(FORMAT_KEY, PrefsStatus.WARN, resourceHelper.gs(R.string.metadata_warning_outdated_format))
-
- return Prefs(entries, metadata)
+ return Prefs(entries, loadMetadata())
} catch (e: FileNotFoundException) {
throw PrefFileNotFoundError(file.absolutePath)
@@ -57,4 +60,10 @@ class ClassicPrefsFormat @Inject constructor(
}
}
+ override fun loadMetadata(contents: String?): PrefMetadataMap {
+ val metadata: MutableMap = mutableMapOf()
+ metadata[PrefsMetadataKey.FILE_FORMAT] = PrefMetadata(FORMAT_KEY, PrefsStatus.WARN, resourceHelper.gs(R.string.metadata_warning_outdated_format))
+ return metadata
+ }
+
}
\ No newline at end of file
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/maintenance/formats/EncryptedPrefsFormat.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/maintenance/formats/EncryptedPrefsFormat.kt
index 463b5a31cb..ec88c07bec 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/general/maintenance/formats/EncryptedPrefsFormat.kt
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/maintenance/formats/EncryptedPrefsFormat.kt
@@ -27,6 +27,16 @@ class EncryptedPrefsFormat @Inject constructor(
val FORMAT_KEY_NOENC = "aaps_structured"
private val KEY_CONSCIENCE = "if you remove/change this, please make sure you know the consequences!"
+ private val FORMAT_TEST_REGEX = Regex("(\\\"format\\\"\\s*\\:\\s*\\\"aaps_[^\"]*\\\")")
+ }
+
+ override fun isPreferencesFile(file: File, preloadedContents: String?): Boolean {
+ return if (file.absolutePath.endsWith(".json")) {
+ val contents = preloadedContents ?: storage.getFileContents(file)
+ FORMAT_TEST_REGEX.containsMatchIn(contents)
+ } else {
+ false
+ }
}
override fun savePreferences(file: File, prefs: Prefs, masterPassword: String?) {
@@ -97,7 +107,6 @@ class EncryptedPrefsFormat @Inject constructor(
override fun loadPreferences(file: File, masterPassword: String?): Prefs {
val entries: MutableMap = mutableMapOf()
- val metadata: MutableMap = mutableMapOf()
val issues = LinkedList()
try {
@@ -105,25 +114,11 @@ class EncryptedPrefsFormat @Inject constructor(
val fileContents = jsonBody.replace(Regex("(?is)(\\\"file_hash\\\"\\s*\\:\\s*\\\")([^\"]*)(\\\")"), "$1--to-be-calculated--$3")
val calculatedFileHash = cryptoUtil.hmac256(fileContents, KEY_CONSCIENCE)
val container = JSONObject(jsonBody)
+ val metadata: MutableMap = loadMetadata(container)
- if (container.has(PrefsMetadataKey.FILE_FORMAT.key) && container.has("security") && container.has("content") && container.has("metadata")) {
+ if (container.has(PrefsMetadataKey.FILE_FORMAT.key) && container.has("security") && container.has("content")) {
val fileFormat = container.getString(PrefsMetadataKey.FILE_FORMAT.key)
-
- if ((fileFormat != FORMAT_KEY_ENC) && (fileFormat != FORMAT_KEY_NOENC)) {
- throw PrefFormatError("Unsupported file format: " + fileFormat)
- }
-
- val meta = container.getJSONObject("metadata")
val security = container.getJSONObject("security")
-
- metadata[PrefsMetadataKey.FILE_FORMAT] = PrefMetadata(fileFormat, PrefsStatus.OK)
- for (key in meta.keys()) {
- val metaKey = PrefsMetadataKey.fromKey(key)
- if (metaKey != null) {
- metadata[metaKey] = PrefMetadata(meta.getString(key), PrefsStatus.OK)
- }
- }
-
val encrypted = fileFormat == FORMAT_KEY_ENC
var secure: PrefsStatus = PrefsStatus.OK
var decryptedOk = false
@@ -208,8 +203,6 @@ class EncryptedPrefsFormat @Inject constructor(
}
metadata[PrefsMetadataKey.ENCRYPTION] = PrefMetadata(encryptionDescStr, secure, issuesStr)
- } else {
- metadata[PrefsMetadataKey.FILE_FORMAT] = PrefMetadata(resourceHelper.gs(R.string.prefdecrypt_wrong_json), PrefsStatus.ERROR)
}
return Prefs(entries, metadata)
@@ -223,4 +216,35 @@ class EncryptedPrefsFormat @Inject constructor(
}
}
+ override fun loadMetadata(contents: String?): PrefMetadataMap {
+ contents?.let {
+ val container = JSONObject(contents)
+ return loadMetadata(container)
+ }
+ return mutableMapOf()
+ }
+
+ private fun loadMetadata(container: JSONObject): MutableMap {
+ val metadata: MutableMap = mutableMapOf()
+ if (container.has(PrefsMetadataKey.FILE_FORMAT.key) && container.has("security") && container.has("content") && container.has("metadata")) {
+ val fileFormat = container.getString(PrefsMetadataKey.FILE_FORMAT.key)
+ if ((fileFormat != FORMAT_KEY_ENC) && (fileFormat != FORMAT_KEY_NOENC)) {
+ metadata[PrefsMetadataKey.FILE_FORMAT] = PrefMetadata(resourceHelper.gs(R.string.metadata_format_other), PrefsStatus.ERROR)
+ } else {
+ val meta = container.getJSONObject("metadata")
+ metadata[PrefsMetadataKey.FILE_FORMAT] = PrefMetadata(fileFormat, PrefsStatus.OK)
+ for (key in meta.keys()) {
+ val metaKey = PrefsMetadataKey.fromKey(key)
+ if (metaKey != null) {
+ metadata[metaKey] = PrefMetadata(meta.getString(key), PrefsStatus.OK)
+ }
+ }
+ }
+ } else {
+ metadata[PrefsMetadataKey.FILE_FORMAT] = PrefMetadata(resourceHelper.gs(R.string.prefdecrypt_wrong_json), PrefsStatus.ERROR)
+ }
+
+ return metadata;
+ }
+
}
\ No newline at end of file
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/maintenance/formats/PrefsFormat.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/maintenance/formats/PrefsFormat.kt
index a47add0dd7..d0d3935023 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/general/maintenance/formats/PrefsFormat.kt
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/maintenance/formats/PrefsFormat.kt
@@ -1,12 +1,14 @@
package info.nightscout.androidaps.plugins.general.maintenance.formats
import android.content.Context
+import android.os.Parcelable
import androidx.annotation.DrawableRes
import androidx.annotation.StringRes
import info.nightscout.androidaps.R
+import kotlinx.android.parcel.Parcelize
import java.io.File
-enum class PrefsMetadataKey(val key: String, @DrawableRes val icon:Int, @StringRes val label:Int) {
+enum class PrefsMetadataKey(val key: String, @DrawableRes val icon: Int, @StringRes val label: Int) {
FILE_FORMAT("format", R.drawable.ic_meta_format, R.string.metadata_label_format),
CREATED_AT("created_at", R.drawable.ic_meta_date, R.string.metadata_label_created_at),
@@ -33,16 +35,15 @@ enum class PrefsMetadataKey(val key: String, @DrawableRes val icon:Int, @StringR
}
}
-
}
- fun formatForDisplay(context: Context, value:String): String {
+ fun formatForDisplay(context: Context, value: String): String {
return when (this) {
FILE_FORMAT -> when (value) {
- ClassicPrefsFormat.FORMAT_KEY -> context.getString(R.string.metadata_format_old)
- EncryptedPrefsFormat.FORMAT_KEY_ENC -> context.getString(R.string.metadata_format_new)
+ ClassicPrefsFormat.FORMAT_KEY -> context.getString(R.string.metadata_format_old)
+ EncryptedPrefsFormat.FORMAT_KEY_ENC -> context.getString(R.string.metadata_format_new)
EncryptedPrefsFormat.FORMAT_KEY_NOENC -> context.getString(R.string.metadata_format_debug)
- else -> context.getString(R.string.metadata_format_other)
+ else -> context.getString(R.string.metadata_format_other)
}
CREATED_AT -> value.replace("T", " ").replace("Z", " (UTC)")
else -> value
@@ -51,16 +52,21 @@ enum class PrefsMetadataKey(val key: String, @DrawableRes val icon:Int, @StringR
}
-data class PrefMetadata(var value : String, var status : PrefsStatus, var info : String? = null)
+@Parcelize
+data class PrefMetadata(var value: String, var status: PrefsStatus, var info: String? = null) : Parcelable
-data class Prefs(val values : Map, var metadata : Map)
+typealias PrefMetadataMap = Map
+
+data class Prefs(val values: Map, var metadata: PrefMetadataMap)
interface PrefsFormat {
fun savePreferences(file: File, prefs: Prefs, masterPassword: String? = null)
- fun loadPreferences(file: File, masterPassword: String? = null) : Prefs
+ fun loadPreferences(file: File, masterPassword: String? = null): Prefs
+ fun loadMetadata(contents: String? = null): PrefMetadataMap
+ fun isPreferencesFile(file: File, preloadedContents: String? = null): Boolean
}
-enum class PrefsStatus(@DrawableRes val icon:Int) {
+enum class PrefsStatus(@DrawableRes val icon: Int) {
OK(R.drawable.ic_meta_ok),
WARN(R.drawable.ic_meta_warning),
ERROR(R.drawable.ic_meta_error),
@@ -68,6 +74,11 @@ enum class PrefsStatus(@DrawableRes val icon:Int) {
DISABLED(R.drawable.ic_meta_error)
}
+enum class PrefsFormatsHandler {
+ CLASSIC,
+ ENCRYPTED
+}
+
class PrefFileNotFoundError(message: String) : Exception(message)
class PrefIOError(message: String) : Exception(message)
class PrefFormatError(message: String) : Exception(message)
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/OverviewFragment.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/OverviewFragment.kt
index 962e443c66..4a6455e41c 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/OverviewFragment.kt
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/OverviewFragment.kt
@@ -57,6 +57,7 @@ import info.nightscout.androidaps.plugins.source.DexcomPlugin
import info.nightscout.androidaps.plugins.source.XdripPlugin
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin
import info.nightscout.androidaps.queue.CommandQueue
+import info.nightscout.androidaps.skins.SkinProvider
import info.nightscout.androidaps.utils.*
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
import info.nightscout.androidaps.utils.buildHelper.BuildHelper
@@ -64,41 +65,33 @@ import info.nightscout.androidaps.utils.extensions.toVisibility
import info.nightscout.androidaps.utils.protection.ProtectionCheck
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.sharedPreferences.SP
+import info.nightscout.androidaps.utils.ui.UIRunnable
import info.nightscout.androidaps.utils.wizard.QuickWizard
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.schedulers.Schedulers
-import kotlinx.android.synthetic.main.overview_fragment.*
-import kotlinx.android.synthetic.main.overview_fragment.careportal_canulaage
-import kotlinx.android.synthetic.main.overview_fragment.careportal_insulinage
-import kotlinx.android.synthetic.main.overview_fragment.careportal_reservoirlevel
-import kotlinx.android.synthetic.main.overview_fragment.careportal_sensorage
-import kotlinx.android.synthetic.main.overview_fragment.careportal_pbage
-import kotlinx.android.synthetic.main.overview_fragment.careportal_batterylevel
-import kotlinx.android.synthetic.main.overview_fragment.overview_activeprofile
-import kotlinx.android.synthetic.main.overview_fragment.overview_apsmode
-import kotlinx.android.synthetic.main.overview_fragment.overview_arrow
-import kotlinx.android.synthetic.main.overview_fragment.overview_basebasal
-import kotlinx.android.synthetic.main.overview_fragment.overview_bg
-import kotlinx.android.synthetic.main.overview_fragment.overview_bggraph
-import kotlinx.android.synthetic.main.overview_fragment.overview_carbsbutton
-import kotlinx.android.synthetic.main.overview_fragment.overview_chartMenuButton
-import kotlinx.android.synthetic.main.overview_fragment.overview_cob
-import kotlinx.android.synthetic.main.overview_fragment.overview_extendedbolus
-import kotlinx.android.synthetic.main.overview_fragment.overview_insulinbutton
-import kotlinx.android.synthetic.main.overview_fragment.overview_iob
-import kotlinx.android.synthetic.main.overview_fragment.overview_iobcalculationprogess
-import kotlinx.android.synthetic.main.overview_fragment.overview_iobgraph
-import kotlinx.android.synthetic.main.overview_fragment.overview_looplayout
+import kotlinx.android.synthetic.main.overview_buttons_layout.*
+import kotlinx.android.synthetic.main.overview_buttons_layout.overview_carbsbutton
+import kotlinx.android.synthetic.main.overview_buttons_layout.overview_insulinbutton
+import kotlinx.android.synthetic.main.overview_buttons_layout.overview_quickwizardbutton
+import kotlinx.android.synthetic.main.overview_buttons_layout.overview_treatmentbutton
+import kotlinx.android.synthetic.main.overview_buttons_layout.overview_wizardbutton
import kotlinx.android.synthetic.main.overview_fragment.overview_notifications
-import kotlinx.android.synthetic.main.overview_fragment.overview_pumpstatus
-import kotlinx.android.synthetic.main.overview_fragment.overview_pumpstatuslayout
-import kotlinx.android.synthetic.main.overview_fragment.overview_quickwizardbutton
-import kotlinx.android.synthetic.main.overview_fragment.overview_sensitivity
-import kotlinx.android.synthetic.main.overview_fragment.overview_temptarget
-import kotlinx.android.synthetic.main.overview_fragment.overview_treatmentbutton
-import kotlinx.android.synthetic.main.overview_fragment.overview_wizardbutton
import kotlinx.android.synthetic.main.overview_fragment_nsclient_tablet.*
+import kotlinx.android.synthetic.main.overview_graphs_layout.overview_bggraph
+import kotlinx.android.synthetic.main.overview_graphs_layout.overview_chartMenuButton
+import kotlinx.android.synthetic.main.overview_graphs_layout.overview_iobcalculationprogess
+import kotlinx.android.synthetic.main.overview_graphs_layout.overview_iobgraph
+import kotlinx.android.synthetic.main.overview_info_layout.*
+import kotlinx.android.synthetic.main.overview_info_layout.overview_arrow
+import kotlinx.android.synthetic.main.overview_info_layout.overview_basebasal
+import kotlinx.android.synthetic.main.overview_info_layout.overview_bg
+import kotlinx.android.synthetic.main.overview_info_layout.overview_cob
+import kotlinx.android.synthetic.main.overview_info_layout.overview_extendedbolus
+import kotlinx.android.synthetic.main.overview_info_layout.overview_iob
+import kotlinx.android.synthetic.main.overview_info_layout.overview_sensitivity
+import kotlinx.android.synthetic.main.overview_loop_pumpstatus_layout.*
+import kotlinx.android.synthetic.main.overview_statuslights_layout.*
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
@@ -140,6 +133,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
@Inject lateinit var protectionCheck: ProtectionCheck
@Inject lateinit var fabricPrivacy: FabricPrivacy
@Inject lateinit var overviewMenus: OverviewMenus
+ @Inject lateinit var skinProvider: SkinProvider
private val disposable = CompositeDisposable()
@@ -170,19 +164,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
smallHeight = screenHeight <= Constants.SMALL_HEIGHT
val landscape = screenHeight < screenWidth
- return when {
- resourceHelper.gb(R.bool.isTablet) && Config.NSCLIENT ->
- inflater.inflate(R.layout.overview_fragment_nsclient_tablet, container, false)
-
- Config.NSCLIENT ->
- inflater.inflate(R.layout.overview_fragment_nsclient, container, false)
-
- smallHeight || landscape ->
- inflater.inflate(R.layout.overview_fragment_landscape, container, false)
-
- else ->
- inflater.inflate(R.layout.overview_fragment, container, false)
- }
+ return inflater.inflate(skinProvider.activeSkin().overviewLayout(landscape, resourceHelper.gb(R.bool.isTablet), smallHeight), container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
@@ -226,7 +208,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
super.onPause()
disposable.clear()
loopHandler.removeCallbacksAndMessages(null)
- overview_apsmode?.let { unregisterForContextMenu(it) }
+ overview_apsmode_llayout?.let { unregisterForContextMenu(it) }
overview_activeprofile?.let { unregisterForContextMenu(it) }
overview_temptarget?.let { unregisterForContextMenu(it) }
}
@@ -300,7 +282,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
}
loopHandler.postDelayed(refreshLoop, 60 * 1000L)
- overview_apsmode?.let { registerForContextMenu(overview_apsmode) }
+ overview_apsmode_llayout?.let { registerForContextMenu(overview_apsmode) }
overview_activeprofile?.let { registerForContextMenu(it) }
overview_temptarget?.let { registerForContextMenu(it) }
updateGUI("onResume")
@@ -312,26 +294,20 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
}
override fun onContextItemSelected(item: MenuItem): Boolean {
- val manager = fragmentManager
- return if (manager != null && overviewMenus.onContextItemSelected(item, manager)) true else super.onContextItemSelected(item)
+ return if (overviewMenus.onContextItemSelected(item, childFragmentManager)) true else super.onContextItemSelected(item)
}
override fun onClick(v: View) {
- val manager = fragmentManager ?: return
// 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
- if (manager.isStateSaved) return
+ if (childFragmentManager.isStateSaved) return
activity?.let { activity ->
when (v.id) {
- R.id.overview_treatmentbutton -> protectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, Runnable { TreatmentDialog().show(manager, "Overview") })
- R.id.overview_wizardbutton -> protectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, Runnable { WizardDialog().show(manager, "Overview") })
- R.id.overview_insulinbutton -> protectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, Runnable { InsulinDialog().show(manager, "Overview") })
- R.id.overview_quickwizardbutton -> protectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, Runnable { onClickQuickWizard() })
- R.id.overview_carbsbutton -> protectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, Runnable { CarbsDialog().show(manager, "Overview") })
-
- R.id.overview_pumpstatus -> {
- if (activePlugin.activePump.isSuspended || !activePlugin.activePump.isInitialized) commandQueue.readStatus("RefreshClicked", null)
- }
+ R.id.overview_treatmentbutton -> protectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, UIRunnable(Runnable { TreatmentDialog().show(childFragmentManager, "Overview") }))
+ R.id.overview_wizardbutton -> protectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, UIRunnable(Runnable { WizardDialog().show(childFragmentManager, "Overview") }))
+ R.id.overview_insulinbutton -> protectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, UIRunnable(Runnable { InsulinDialog().show(childFragmentManager, "Overview") }))
+ R.id.overview_quickwizardbutton -> protectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, UIRunnable(Runnable { onClickQuickWizard() }))
+ R.id.overview_carbsbutton -> protectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, UIRunnable(Runnable { CarbsDialog().show(childFragmentManager, "Overview") }))
R.id.overview_cgmbutton -> {
if (xdripPlugin.isEnabled(PluginType.BGSOURCE))
@@ -346,7 +322,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
R.id.overview_calibrationbutton -> {
if (xdripPlugin.isEnabled(PluginType.BGSOURCE)) {
- CalibrationDialog().show(manager, "CalibrationDialog")
+ CalibrationDialog().show(childFragmentManager, "CalibrationDialog")
} else if (dexcomPlugin.isEnabled(PluginType.BGSOURCE)) {
try {
dexcomPlugin.findDexcomPackageName()?.let {
@@ -570,9 +546,9 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
val glucoseStatus = GlucoseStatus(injector).glucoseStatusData
if (glucoseStatus != null) {
- overview_delta?.text = "Δ ${Profile.toUnitsString(glucoseStatus.delta, glucoseStatus.delta * Constants.MGDL_TO_MMOLL, units)} $units"
+ overview_delta?.text = "Δ ${Profile.toSignedUnitsString(glucoseStatus.delta, glucoseStatus.delta * Constants.MGDL_TO_MMOLL, units)}"
overview_deltashort?.text = Profile.toSignedUnitsString(glucoseStatus.delta, glucoseStatus.delta * Constants.MGDL_TO_MMOLL, units)
- overview_avgdelta?.text = "øΔ15m: ${Profile.toUnitsString(glucoseStatus.short_avgdelta, glucoseStatus.short_avgdelta * Constants.MGDL_TO_MMOLL, units)}\nøΔ40m: ${Profile.toUnitsString(glucoseStatus.long_avgdelta, glucoseStatus.long_avgdelta * Constants.MGDL_TO_MMOLL, units)}"
+ overview_avgdelta?.text = "Δ15m: ${Profile.toUnitsString(glucoseStatus.short_avgdelta, glucoseStatus.short_avgdelta * Constants.MGDL_TO_MMOLL, units)}\nΔ40m: ${Profile.toUnitsString(glucoseStatus.long_avgdelta, glucoseStatus.long_avgdelta * Constants.MGDL_TO_MMOLL, units)}"
} else {
overview_delta?.text = "Δ " + resourceHelper.gs(R.string.notavailable)
overview_deltashort?.text = "---"
@@ -597,53 +573,72 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
if (Config.APS && pump.pumpDescription.isTempBasalCapable) {
overview_apsmode?.visibility = View.VISIBLE
when {
- loopPlugin.isEnabled(PluginType.LOOP) && loopPlugin.isSuperBolus -> {
- overview_apsmode?.text = String.format(resourceHelper.gs(R.string.loopsuperbolusfor), loopPlugin.minutesToEndOfSuspend())
- overview_apsmode?.setBackgroundColor(resourceHelper.gc(R.color.ribbonWarning))
- overview_apsmode?.setTextColor(resourceHelper.gc(R.color.ribbonTextWarning))
+ loopPlugin.isEnabled() && loopPlugin.isSuperBolus -> {
+ overview_apsmode.setImageResource(R.drawable.loop_superbolus)
+ overview_apsmode_text?.text = DateUtil.age(loopPlugin.minutesToEndOfSuspend() * 60000L, true, resourceHelper)
+ //overview_apsmode_text?.text = String.format(resourceHelper.gs(R.string.loopsuperbolusfor), loopPlugin.minutesToEndOfSuspend())
+// overview_apsmode_text?.setBackgroundColor(resourceHelper.gc(R.color.ribbonWarning))
+// overview_apsmode_text?.setTextColor(resourceHelper.gc(R.color.ribbonTextWarning))
}
- loopPlugin.isDisconnected -> {
- overview_apsmode?.text = String.format(resourceHelper.gs(R.string.loopdisconnectedfor), loopPlugin.minutesToEndOfSuspend())
- overview_apsmode?.setBackgroundColor(resourceHelper.gc(R.color.ribbonCritical))
- overview_apsmode?.setTextColor(resourceHelper.gc(R.color.ribbonTextCritical))
+ loopPlugin.isDisconnected -> {
+ overview_apsmode.setImageResource(R.drawable.loop_disconnected)
+ overview_apsmode_text?.text = DateUtil.age(loopPlugin.minutesToEndOfSuspend() * 60000L, true, resourceHelper)
+// overview_apsmode_text?.text = String.format(resourceHelper.gs(R.string.loopdisconnectedfor), loopPlugin.minutesToEndOfSuspend())
+// overview_apsmode_text?.setBackgroundColor(resourceHelper.gc(R.color.ribbonCritical))
+// overview_apsmode_text?.setTextColor(resourceHelper.gc(R.color.ribbonTextCritical))
}
- loopPlugin.isEnabled(PluginType.LOOP) && loopPlugin.isSuspended -> {
- overview_apsmode?.text = String.format(resourceHelper.gs(R.string.loopsuspendedfor), loopPlugin.minutesToEndOfSuspend())
- overview_apsmode?.setBackgroundColor(resourceHelper.gc(R.color.ribbonWarning))
- overview_apsmode?.setTextColor(resourceHelper.gc(R.color.ribbonTextWarning))
+ loopPlugin.isEnabled() && loopPlugin.isSuspended -> {
+ overview_apsmode.setImageResource(R.drawable.loop_paused)
+ overview_apsmode_text?.text = DateUtil.age(loopPlugin.minutesToEndOfSuspend() * 60000L, true, resourceHelper)
+// overview_apsmode_text?.text = String.format(resourceHelper.gs(R.string.loopsuspendedfor), loopPlugin.minutesToEndOfSuspend())
+// overview_apsmode_text?.setBackgroundColor(resourceHelper.gc(R.color.ribbonWarning))
+// overview_apsmode_text?.setTextColor(resourceHelper.gc(R.color.ribbonTextWarning))
}
- pump.isSuspended -> {
- overview_apsmode?.text = resourceHelper.gs(R.string.pumpsuspended)
- overview_apsmode?.setBackgroundColor(resourceHelper.gc(R.color.ribbonWarning))
- overview_apsmode?.setTextColor(resourceHelper.gc(R.color.ribbonTextWarning))
+ pump.isSuspended -> {
+ overview_apsmode.setImageResource(R.drawable.loop_paused)
+ overview_apsmode_text?.text = ""
+// overview_apsmode_text?.text = resourceHelper.gs(R.string.pumpsuspended)
+// overview_apsmode_text?.setBackgroundColor(resourceHelper.gc(R.color.ribbonWarning))
+// overview_apsmode_text?.setTextColor(resourceHelper.gc(R.color.ribbonTextWarning))
}
- loopPlugin.isEnabled(PluginType.LOOP) -> {
- val isLGS = loopPlugin.isLGS
- overview_apsmode?.text =
- if (closedLoopEnabled.value())
- if (isLGS)
- resourceHelper.gs(R.string.lgs)
- else
- resourceHelper.gs(R.string.closedloop)
- else
- resourceHelper.gs(R.string.openloop)
-
- overview_apsmode?.setBackgroundColor(if (isLGS) resourceHelper.gc(R.color.ribbonUnusual) else resourceHelper.gc(R.color.ribbonDefault))
- overview_apsmode?.setTextColor(resourceHelper.gc(R.color.ribbonTextDefault))
+ loopPlugin.isEnabled() && closedLoopEnabled.value() && loopPlugin.isLGS -> {
+ overview_apsmode.setImageResource(R.drawable.loop_lgs)
+ overview_apsmode_text?.text = ""
+// overview_apsmode_text?.text = resourceHelper.gs(R.string.closedloop)
+// overview_apsmode_text?.setBackgroundColor(resourceHelper.gc(R.color.ribbonDefault))
+// overview_apsmode_text?.setTextColor(resourceHelper.gc(R.color.ribbonTextDefault))
}
- else -> {
- overview_apsmode?.text = resourceHelper.gs(R.string.disabledloop)
- overview_apsmode?.setBackgroundColor(resourceHelper.gc(R.color.ribbonCritical))
- overview_apsmode?.setTextColor(resourceHelper.gc(R.color.ribbonTextCritical))
+ loopPlugin.isEnabled() && closedLoopEnabled.value() -> {
+ overview_apsmode.setImageResource(R.drawable.loop_closed)
+ overview_apsmode_text?.text = ""
+// overview_apsmode_text?.text = resourceHelper.gs(R.string.closedloop)
+// overview_apsmode_text?.setBackgroundColor(resourceHelper.gc(R.color.ribbonDefault))
+// overview_apsmode_text?.setTextColor(resourceHelper.gc(R.color.ribbonTextDefault))
+ }
+
+ loopPlugin.isEnabled() && !closedLoopEnabled.value() -> {
+ overview_apsmode.setImageResource(R.drawable.loop_open)
+ overview_apsmode_text?.text = ""
+// overview_apsmode_text?.text = resourceHelper.gs(R.string.openloop)
+// overview_apsmode_text?.setBackgroundColor(resourceHelper.gc(R.color.ribbonDefault))
+// overview_apsmode_text?.setTextColor(resourceHelper.gc(R.color.ribbonTextDefault))
+ }
+
+ else -> {
+ overview_apsmode.setImageResource(R.drawable.loop_disabled)
+ overview_apsmode_text?.text = ""
+// overview_apsmode_text?.text = resourceHelper.gs(R.string.disabledloop)
+// overview_apsmode_text?.setBackgroundColor(resourceHelper.gc(R.color.ribbonCritical))
+// overview_apsmode_text?.setTextColor(resourceHelper.gc(R.color.ribbonTextCritical))
}
}
} else {
- overview_apsmode?.visibility = View.GONE
+ overview_apsmode_text?.visibility = View.GONE
}
// temp target
@@ -660,9 +655,9 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
// Basal, TBR
val activeTemp = treatmentsPlugin.getTempBasalFromHistory(System.currentTimeMillis())
- overview_basebasal?.text = activeTemp?.let { if (resourceHelper.shortTextMode()) "T: " + activeTemp.toStringVeryShort() else activeTemp.toStringFull() }
+ overview_basebasal?.text = activeTemp?.let { if (resourceHelper.shortTextMode()) "T:" + activeTemp.toStringVeryShort() else activeTemp.toStringFull() }
?: resourceHelper.gs(R.string.pump_basebasalrate, profile.basal)
- overview_basebasal?.setOnClickListener {
+ overview_basal_llayout?.setOnClickListener {
var fullText = "${resourceHelper.gs(R.string.pump_basebasalrate_label)}: ${resourceHelper.gs(R.string.pump_basebasalrate, profile.basal)}"
if (activeTemp != null)
fullText += "\n" + resourceHelper.gs(R.string.pump_tempbasal_label) + ": " + activeTemp.toStringFull()
@@ -672,6 +667,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
}
overview_basebasal?.setTextColor(activeTemp?.let { resourceHelper.gc(R.color.basal) }
?: resourceHelper.gc(R.color.defaulttextcolor))
+ overview_basebasal_icon.setImageResource(if (activeTemp != null) R.drawable.icon_cp_basal_start else R.drawable.icon_cp_basal_end)
// Extended bolus
val extendedBolus = treatmentsPlugin.getExtendedBolusFromHistory(System.currentTimeMillis())
@@ -684,7 +680,9 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
OKDialog.show(it, resourceHelper.gs(R.string.extended_bolus), extendedBolus.toString())
}
}
+ overview_extended_llayout?.visibility = (extendedBolus != null && !pump.isFakingTempsByExtendedBoluses).toVisibility()
+ // Active profile
overview_activeprofile?.text = profileFunction.getProfileNameWithDuration()
if (profile.percentage != 100 || profile.timeshift != 0) {
overview_activeprofile?.setBackgroundColor(resourceHelper.gc(R.color.ribbonWarning))
@@ -702,23 +700,15 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
val bolusIob = treatmentsPlugin.lastCalculationTreatments.round()
val basalIob = treatmentsPlugin.lastCalculationTempBasals.round()
overview_iob?.text = when {
- resourceHelper.shortTextMode() -> {
+ resourceHelper.shortTextMode() ->
resourceHelper.gs(R.string.formatinsulinunits, bolusIob.iob + basalIob.basaliob)
- }
- resourceHelper.gb(R.bool.isTablet) -> {
- resourceHelper.gs(R.string.formatinsulinunits, bolusIob.iob + basalIob.basaliob) + " (" +
- resourceHelper.gs(R.string.bolus) + ": " + resourceHelper.gs(R.string.formatinsulinunits, bolusIob.iob) +
- resourceHelper.gs(R.string.basal) + ": " + resourceHelper.gs(R.string.formatinsulinunits, basalIob.basaliob) + ")"
- }
-
- else -> {
+ else ->
resourceHelper.gs(R.string.formatinsulinunits, bolusIob.iob + basalIob.basaliob) + " (" +
resourceHelper.gs(R.string.formatinsulinunits, bolusIob.iob) + "/" +
resourceHelper.gs(R.string.formatinsulinunits, basalIob.basaliob) + ")"
- }
}
- overview_iob?.setOnClickListener {
+ overview_iob_llayout?.setOnClickListener {
activity?.let {
OKDialog.show(it, resourceHelper.gs(R.string.iob),
resourceHelper.gs(R.string.formatinsulinunits, bolusIob.iob + basalIob.basaliob) + "\n" +
@@ -736,7 +726,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
var cobText: String = resourceHelper.gs(R.string.value_unavailable_short)
val cobInfo = iobCobCalculatorPlugin.getCobInfo(false, "Overview COB")
if (cobInfo.displayCob != null) {
- cobText = DecimalFormatter.to0Decimal(cobInfo.displayCob)
+ cobText = resourceHelper.gs(R.string.format_carbs, cobInfo.displayCob.toInt())
if (cobInfo.futureCarbs > 0) cobText += "(" + DecimalFormatter.to0Decimal(cobInfo.futureCarbs) + ")"
}
overview_cob?.text = cobText
@@ -757,9 +747,10 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
overview_uploader?.setOnClickListener { activity?.let { OKDialog.show(it, resourceHelper.gs(R.string.uploader), nsDeviceStatus.extendedUploaderStatus) } }
// Sensitivity
- iobCobCalculatorPlugin.getLastAutosensData("Overview")?.let { autosensData ->
- overview_sensitivity?.text = String.format(Locale.ENGLISH, "%.0f%%", autosensData.autosensResult.ratio * 100)
- }
+ overview_sensitivity?.text =
+ iobCobCalculatorPlugin.getLastAutosensData("Overview")?.let { autosensData ->
+ String.format(Locale.ENGLISH, "%.0f%%", autosensData.autosensResult.ratio * 100)
+ } ?: ""
// ****** GRAPH *******
GlobalScope.launch(Dispatchers.Main) {
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/profile/local/LocalProfileFragment.kt b/app/src/main/java/info/nightscout/androidaps/plugins/profile/local/LocalProfileFragment.kt
index 3acf960195..f26bacf8ec 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/profile/local/LocalProfileFragment.kt
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/profile/local/LocalProfileFragment.kt
@@ -178,7 +178,7 @@ class LocalProfileFragment : DaggerFragment() {
localprofile_profileswitch.setOnClickListener {
// TODO: select in dialog localProfilePlugin.currentProfileIndex
- fragmentManager?.let { ProfileSwitchDialog().show(it, "NewNSTreatmentDialog") }
+ ProfileSwitchDialog().show(childFragmentManager, "NewNSTreatmentDialog")
}
localprofile_reset.setOnClickListener {
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/pump/danaR/DanaRFragment.kt b/app/src/main/java/info/nightscout/androidaps/plugins/pump/danaR/DanaRFragment.kt
index 60420d6d70..9a8477ae2d 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/pump/danaR/DanaRFragment.kt
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/pump/danaR/DanaRFragment.kt
@@ -71,21 +71,19 @@ class DanaRFragment : DaggerFragment() {
danar_history.setOnClickListener { startActivity(Intent(context, DanaRHistoryActivity::class.java)) }
danar_viewprofile.setOnClickListener {
- fragmentManager?.let { fragmentManager ->
- val profile = danaRPump.createConvertedProfile()?.getDefaultProfile()
- ?: return@let
- val profileName = danaRPump.createConvertedProfile()?.getDefaultProfileName()
- ?: return@let
- val args = Bundle()
- args.putLong("time", DateUtil.now())
- args.putInt("mode", ProfileViewerDialog.Mode.CUSTOM_PROFILE.ordinal)
- args.putString("customProfile", profile.data.toString())
- args.putString("customProfileUnits", profile.units)
- args.putString("customProfileName", profileName)
- val pvd = ProfileViewerDialog()
- pvd.arguments = args
- pvd.show(fragmentManager, "ProfileViewDialog")
- }
+ val profile = danaRPump.createConvertedProfile()?.getDefaultProfile()
+ ?: return@setOnClickListener
+ val profileName = danaRPump.createConvertedProfile()?.getDefaultProfileName()
+ ?: return@setOnClickListener
+ val args = Bundle()
+ args.putLong("time", DateUtil.now())
+ args.putInt("mode", ProfileViewerDialog.Mode.CUSTOM_PROFILE.ordinal)
+ args.putString("customProfile", profile.data.toString())
+ args.putString("customProfileUnits", profile.units)
+ args.putString("customProfileName", profileName)
+ val pvd = ProfileViewerDialog()
+ pvd.arguments = args
+ pvd.show(childFragmentManager, "ProfileViewDialog")
}
danar_stats.setOnClickListener { startActivity(Intent(context, TDDStatsActivity::class.java)) }
danar_user_options.setOnClickListener { startActivity(Intent(context, DanaRUserOptionsActivity::class.java)) }
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/OmnipodFragment.kt b/app/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/OmnipodFragment.kt
index fce29225d4..6dba697009 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/OmnipodFragment.kt
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/OmnipodFragment.kt
@@ -176,7 +176,7 @@ class OmnipodFragment : DaggerFragment() {
disposable += rxBus
.toObservable(EventPreferenceChange::class.java)
.observeOn(Schedulers.io())
- .subscribe({ event ->
+ .subscribe({
setVisibilityOfPodDebugButton()
}, { fabricPrivacy.logException(it) })
}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/OmnipodPumpPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/OmnipodPumpPlugin.java
index dd6d7295b7..466a6be10f 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/OmnipodPumpPlugin.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/OmnipodPumpPlugin.java
@@ -619,15 +619,7 @@ public class OmnipodPumpPlugin extends PumpPluginAbstract implements OmnipodPump
if (omnipodUtil.getPodSessionState() != null) {
podSessionState = omnipodUtil.getPodSessionState();
} else {
- String podState = sp.getString(OmnipodConst.Prefs.PodState, "");
-
- aapsLogger.info(LTag.PUMP, "PodSessionState-SP: loaded from SharedPreferences: " + podState);
-
- if (StringUtils.isNotEmpty(podState)) {
- podSessionState = omnipodUtil.getGsonInstance().fromJson(podState, PodSessionState.class);
- podSessionState.injectDaggerClass(injector);
- omnipodUtil.setPodSessionState(podSessionState);
- }
+ podSessionState = omnipodUtil.loadSessionState();
}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/util/OmnipodUtil.java b/app/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/util/OmnipodUtil.java
index a0d6203309..f002989e3c 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/util/OmnipodUtil.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/util/OmnipodUtil.java
@@ -8,6 +8,7 @@ import com.google.gson.JsonDeserializer;
import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSerializer;
+import org.apache.commons.lang3.StringUtils;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import org.joda.time.format.ISODateTimeFormat;
@@ -15,10 +16,12 @@ import org.joda.time.format.ISODateTimeFormat;
import javax.inject.Inject;
import javax.inject.Singleton;
+import dagger.android.HasAndroidInjector;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.interfaces.ActivePluginProvider;
import info.nightscout.androidaps.logging.AAPSLogger;
+import info.nightscout.androidaps.logging.LTag;
import info.nightscout.androidaps.plugins.bus.RxBusWrapper;
import info.nightscout.androidaps.plugins.pump.common.defs.PumpType;
import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.RileyLinkUtil;
@@ -46,6 +49,7 @@ public class OmnipodUtil {
private final OmnipodPumpStatus omnipodPumpStatus;
private final ActivePluginProvider activePlugins;
private final SP sp;
+ private final HasAndroidInjector injector;
private boolean lowLevelDebug = true;
private OmnipodCommandType currentCommand;
@@ -63,7 +67,8 @@ public class OmnipodUtil {
RileyLinkUtil rileyLinkUtil,
OmnipodPumpStatus omnipodPumpStatus,
SP sp,
- ActivePluginProvider activePlugins
+ ActivePluginProvider activePlugins,
+ HasAndroidInjector injector
) {
this.aapsLogger = aapsLogger;
this.rxBus = rxBus;
@@ -71,6 +76,7 @@ public class OmnipodUtil {
this.omnipodPumpStatus = omnipodPumpStatus;
this.sp = sp;
this.activePlugins = activePlugins;
+ this.injector = injector;
}
@@ -223,4 +229,20 @@ public class OmnipodUtil {
public SP getSp() {
return this.sp;
}
+
+ public PodSessionState loadSessionState() {
+ String podState = sp.getString(OmnipodConst.Prefs.PodState, "");
+
+ aapsLogger.info(LTag.PUMP, "PodSessionState-SP: loaded from SharedPreferences: " + podState);
+
+ if (StringUtils.isNotEmpty(podState)) {
+ PodSessionState podSessionState = gsonInstance.fromJson(podState, PodSessionState.class);
+ podSessionState.injectDaggerClass(injector);
+ setPodSessionState(podSessionState);
+
+ return podSessionState;
+ }
+
+ return null;
+ }
}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/treatments/fragments/TreatmentsBolusFragment.kt b/app/src/main/java/info/nightscout/androidaps/plugins/treatments/fragments/TreatmentsBolusFragment.kt
index a6b1cdf296..7e130ceab9 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/treatments/fragments/TreatmentsBolusFragment.kt
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/treatments/fragments/TreatmentsBolusFragment.kt
@@ -145,12 +145,10 @@ class TreatmentsBolusFragment : DaggerFragment() {
init {
calculation.setOnClickListener {
val treatment = it.tag as Treatment
- fragmentManager?.let { fragmentManager ->
- if (treatment.getBoluscalc() != null) {
- val wizardDialog = WizardInfoDialog()
- wizardDialog.setData(treatment.getBoluscalc()!!)
- wizardDialog.show(fragmentManager, "WizardInfoDialog")
- }
+ if (treatment.getBoluscalc() != null) {
+ val wizardDialog = WizardInfoDialog()
+ wizardDialog.setData(treatment.getBoluscalc()!!)
+ wizardDialog.show(childFragmentManager, "WizardInfoDialog")
}
}
calculation.paintFlags = calculation.paintFlags or Paint.UNDERLINE_TEXT_FLAG
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/treatments/fragments/TreatmentsProfileSwitchFragment.kt b/app/src/main/java/info/nightscout/androidaps/plugins/treatments/fragments/TreatmentsProfileSwitchFragment.kt
index 10bdf42de5..d45d547ef0 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/treatments/fragments/TreatmentsProfileSwitchFragment.kt
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/treatments/fragments/TreatmentsProfileSwitchFragment.kt
@@ -156,7 +156,7 @@ class TreatmentsProfileSwitchFragment : DaggerFragment() {
args.putInt("mode", ProfileViewerDialog.Mode.RUNNING_PROFILE.ordinal)
val pvd = ProfileViewerDialog()
pvd.arguments = args
- fragmentManager?.let { pvd.show(it, "ProfileViewDialog") }
+ pvd.show(childFragmentManager, "ProfileViewDialog")
}
}
}
diff --git a/app/src/main/java/info/nightscout/androidaps/skins/SkinButtonsOn.kt b/app/src/main/java/info/nightscout/androidaps/skins/SkinButtonsOn.kt
new file mode 100644
index 0000000000..3bc092dfc2
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/skins/SkinButtonsOn.kt
@@ -0,0 +1,20 @@
+package info.nightscout.androidaps.skins
+
+import info.nightscout.androidaps.Config
+import info.nightscout.androidaps.R
+import javax.inject.Inject
+import javax.inject.Singleton
+
+@Singleton
+class SkinButtonsOn @Inject constructor() : SkinInterface {
+
+ override val description: Int get() = R.string.buttonson_desrciption
+
+ override fun overviewLayout(isLandscape: Boolean, isTablet: Boolean, isSmallHeight: Boolean): Int =
+ when {
+ Config.NSCLIENT && isTablet -> R.layout.overview_fragment_nsclient_tablet
+ Config.NSCLIENT -> R.layout.overview_fragment_nsclient
+ else -> R.layout.overview_fragment
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/info/nightscout/androidaps/skins/SkinClassic.kt b/app/src/main/java/info/nightscout/androidaps/skins/SkinClassic.kt
new file mode 100644
index 0000000000..15e69e9ad9
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/skins/SkinClassic.kt
@@ -0,0 +1,21 @@
+package info.nightscout.androidaps.skins
+
+import info.nightscout.androidaps.Config
+import info.nightscout.androidaps.R
+import javax.inject.Inject
+import javax.inject.Singleton
+
+@Singleton
+class SkinClassic @Inject constructor(): SkinInterface {
+
+ override val description: Int get() = R.string.classic_desrciption
+
+ override fun overviewLayout(isLandscape: Boolean, isTablet: Boolean, isSmallHeight: Boolean): Int =
+ when {
+ Config.NSCLIENT && isTablet -> R.layout.overview_fragment_nsclient_tablet
+ Config.NSCLIENT -> R.layout.overview_fragment_nsclient
+ isSmallHeight || isLandscape -> R.layout.overview_fragment_landscape
+ else -> R.layout.overview_fragment
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/info/nightscout/androidaps/skins/SkinInterface.kt b/app/src/main/java/info/nightscout/androidaps/skins/SkinInterface.kt
new file mode 100644
index 0000000000..6a9d055a13
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/skins/SkinInterface.kt
@@ -0,0 +1,10 @@
+package info.nightscout.androidaps.skins
+
+import androidx.annotation.LayoutRes
+import androidx.annotation.StringRes
+
+interface SkinInterface {
+ @get:StringRes val description : Int
+
+ @LayoutRes fun overviewLayout(isLandscape : Boolean, isTablet : Boolean, isSmallHeight : Boolean): Int
+}
\ No newline at end of file
diff --git a/app/src/main/java/info/nightscout/androidaps/skins/SkinListPreference.kt b/app/src/main/java/info/nightscout/androidaps/skins/SkinListPreference.kt
new file mode 100644
index 0000000000..977f19c268
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/skins/SkinListPreference.kt
@@ -0,0 +1,29 @@
+package info.nightscout.androidaps.skins
+
+import android.content.Context
+import android.util.AttributeSet
+import androidx.preference.ListPreference
+import dagger.android.HasAndroidInjector
+import java.util.*
+import javax.inject.Inject
+
+class SkinListPreference(context: Context, attrs: AttributeSet?)
+ : ListPreference(context, attrs) {
+
+ @Inject lateinit var skinProvider: SkinProvider
+
+ constructor(context: Context) : this(context, null)
+
+ init {
+ (context.applicationContext as HasAndroidInjector).androidInjector().inject(this)
+ val entries = Vector()
+ val values = Vector()
+
+ for (skin in skinProvider.list) {
+ values.addElement(skin.javaClass.name)
+ entries.addElement(context.getString(skin.description))
+ }
+ entryValues = values.toTypedArray()
+ setEntries(entries.toTypedArray())
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/info/nightscout/androidaps/skins/SkinProvider.kt b/app/src/main/java/info/nightscout/androidaps/skins/SkinProvider.kt
new file mode 100644
index 0000000000..5ea6a97501
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/skins/SkinProvider.kt
@@ -0,0 +1,22 @@
+package info.nightscout.androidaps.skins
+
+import info.nightscout.androidaps.R
+import info.nightscout.androidaps.dependencyInjection.SkinsModule
+import info.nightscout.androidaps.utils.sharedPreferences.SP
+import okhttp3.internal.toImmutableMap
+import javax.inject.Inject
+import javax.inject.Singleton
+
+@Singleton
+class SkinProvider @Inject constructor(
+ val sp: SP,
+ @SkinsModule.Skin val allSkins: Map<@JvmSuppressWildcards Int, @JvmSuppressWildcards SkinInterface>
+) {
+
+ fun activeSkin(): SkinInterface =
+ list.firstOrNull { it.javaClass.name == sp.getString(R.string.key_skin, "") }
+ ?: list.first()
+
+ val list: List
+ get() = allSkins.toImmutableMap().toList().sortedBy { it.first }.map { it.second }
+}
\ No newline at end of file
diff --git a/app/src/main/java/info/nightscout/androidaps/utils/DateUtil.java b/app/src/main/java/info/nightscout/androidaps/utils/DateUtil.java
index 82fabc52b7..f058896f19 100644
--- a/app/src/main/java/info/nightscout/androidaps/utils/DateUtil.java
+++ b/app/src/main/java/info/nightscout/androidaps/utils/DateUtil.java
@@ -11,11 +11,18 @@ import java.text.DateFormat;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.text.SimpleDateFormat;
+import java.util.ArrayList;
import java.util.Calendar;
+import java.util.Collections;
import java.util.Date;
+import java.util.EnumSet;
import java.util.GregorianCalendar;
+import java.util.LinkedHashMap;
+import java.util.List;
import java.util.Locale;
+import java.util.Map;
import java.util.TimeZone;
+import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -270,6 +277,42 @@ public class DateUtil {
return TimeZone.getDefault().getOffset(timestamp) / 60000;
}
+ //Map:{DAYS=1, HOURS=3, MINUTES=46, SECONDS=40, MILLISECONDS=0, MICROSECONDS=0, NANOSECONDS=0}
+ public static Map computeDiff(long date1, long date2) {
+ long diffInMillies = date2 - date1;
+ List units = new ArrayList<>(EnumSet.allOf(TimeUnit.class));
+ Collections.reverse(units);
+ Map result = new LinkedHashMap<>();
+ long milliesRest = diffInMillies;
+ for (TimeUnit unit : units) {
+ long diff = unit.convert(milliesRest, TimeUnit.MILLISECONDS);
+ long diffInMilliesForUnit = unit.toMillis(diff);
+ milliesRest = milliesRest - diffInMilliesForUnit;
+ result.put(unit, diff);
+ }
+ return result;
+ }
+
+ public static String age(long milliseconds, boolean useShortText, ResourceHelper resourceHelper) {
+ Map diff = computeDiff(0L, milliseconds);
+
+ String days = " " + resourceHelper.gs(R.string.days) + " ";
+ String hours = " " + resourceHelper.gs(R.string.hours) + " ";
+ String minutes = " " + resourceHelper.gs(R.string.unit_minutes) + " ";
+
+ if (useShortText) {
+ days = resourceHelper.gs(R.string.shortday);
+ hours = resourceHelper.gs(R.string.shorthour);
+ minutes = resourceHelper.gs(R.string.shortminute);
+ }
+
+ String result = "";
+ if (diff.get(TimeUnit.DAYS) > 0) result += diff.get(TimeUnit.DAYS) + days;
+ if (diff.get(TimeUnit.HOURS) > 0) result += diff.get(TimeUnit.HOURS) + hours;
+ if (diff.get(TimeUnit.DAYS) == 0) result += diff.get(TimeUnit.MINUTES) + minutes;
+ return result;
+ }
+
public static String niceTimeScalar(long t, ResourceHelper resourceHelper) {
String unit = resourceHelper.gs(R.string.unit_second);
t = t / 1000;
diff --git a/app/src/main/res/drawable-hdpi/bad.png b/app/src/main/res/drawable-hdpi/bad.png
new file mode 100644
index 0000000000..139bf1ddee
Binary files /dev/null and b/app/src/main/res/drawable-hdpi/bad.png differ
diff --git a/app/src/main/res/drawable-hdpi/good.png b/app/src/main/res/drawable-hdpi/good.png
new file mode 100644
index 0000000000..05723ff4ea
Binary files /dev/null and b/app/src/main/res/drawable-hdpi/good.png differ
diff --git a/app/src/main/res/drawable-hdpi/loop_closed.png b/app/src/main/res/drawable-hdpi/loop_closed.png
new file mode 100644
index 0000000000..066dd4c26a
Binary files /dev/null and b/app/src/main/res/drawable-hdpi/loop_closed.png differ
diff --git a/app/src/main/res/drawable-hdpi/loop_disabled.png b/app/src/main/res/drawable-hdpi/loop_disabled.png
new file mode 100644
index 0000000000..268a9bc76b
Binary files /dev/null and b/app/src/main/res/drawable-hdpi/loop_disabled.png differ
diff --git a/app/src/main/res/drawable-hdpi/loop_disconnected.png b/app/src/main/res/drawable-hdpi/loop_disconnected.png
new file mode 100644
index 0000000000..bfff44ea1e
Binary files /dev/null and b/app/src/main/res/drawable-hdpi/loop_disconnected.png differ
diff --git a/app/src/main/res/drawable-hdpi/loop_lgs.png b/app/src/main/res/drawable-hdpi/loop_lgs.png
new file mode 100644
index 0000000000..e45fda615b
Binary files /dev/null and b/app/src/main/res/drawable-hdpi/loop_lgs.png differ
diff --git a/app/src/main/res/drawable-hdpi/loop_open.png b/app/src/main/res/drawable-hdpi/loop_open.png
new file mode 100644
index 0000000000..cdefc55ce8
Binary files /dev/null and b/app/src/main/res/drawable-hdpi/loop_open.png differ
diff --git a/app/src/main/res/drawable-hdpi/loop_pause.png b/app/src/main/res/drawable-hdpi/loop_pause.png
new file mode 100644
index 0000000000..bb97008a07
Binary files /dev/null and b/app/src/main/res/drawable-hdpi/loop_pause.png differ
diff --git a/app/src/main/res/drawable-hdpi/loop_superbolus.png b/app/src/main/res/drawable-hdpi/loop_superbolus.png
new file mode 100644
index 0000000000..d9cec8f047
Binary files /dev/null and b/app/src/main/res/drawable-hdpi/loop_superbolus.png differ
diff --git a/app/src/main/res/drawable-hdpi/soso.png b/app/src/main/res/drawable-hdpi/soso.png
new file mode 100644
index 0000000000..f7a9be577e
Binary files /dev/null and b/app/src/main/res/drawable-hdpi/soso.png differ
diff --git a/app/src/main/res/drawable-mdpi/bad.png b/app/src/main/res/drawable-mdpi/bad.png
new file mode 100644
index 0000000000..9210154195
Binary files /dev/null and b/app/src/main/res/drawable-mdpi/bad.png differ
diff --git a/app/src/main/res/drawable-mdpi/good.png b/app/src/main/res/drawable-mdpi/good.png
new file mode 100644
index 0000000000..a15f82c2b2
Binary files /dev/null and b/app/src/main/res/drawable-mdpi/good.png differ
diff --git a/app/src/main/res/drawable-mdpi/loop_closed.png b/app/src/main/res/drawable-mdpi/loop_closed.png
new file mode 100644
index 0000000000..ba4283035b
Binary files /dev/null and b/app/src/main/res/drawable-mdpi/loop_closed.png differ
diff --git a/app/src/main/res/drawable-mdpi/loop_disabled.png b/app/src/main/res/drawable-mdpi/loop_disabled.png
new file mode 100644
index 0000000000..e4650ec0ac
Binary files /dev/null and b/app/src/main/res/drawable-mdpi/loop_disabled.png differ
diff --git a/app/src/main/res/drawable-mdpi/loop_disconnected.png b/app/src/main/res/drawable-mdpi/loop_disconnected.png
new file mode 100644
index 0000000000..0bc9949349
Binary files /dev/null and b/app/src/main/res/drawable-mdpi/loop_disconnected.png differ
diff --git a/app/src/main/res/drawable-mdpi/loop_lgs.png b/app/src/main/res/drawable-mdpi/loop_lgs.png
new file mode 100644
index 0000000000..a49229d4d8
Binary files /dev/null and b/app/src/main/res/drawable-mdpi/loop_lgs.png differ
diff --git a/app/src/main/res/drawable-mdpi/loop_open.png b/app/src/main/res/drawable-mdpi/loop_open.png
new file mode 100644
index 0000000000..f82346f739
Binary files /dev/null and b/app/src/main/res/drawable-mdpi/loop_open.png differ
diff --git a/app/src/main/res/drawable-mdpi/loop_paused.png b/app/src/main/res/drawable-mdpi/loop_paused.png
new file mode 100644
index 0000000000..7258615f66
Binary files /dev/null and b/app/src/main/res/drawable-mdpi/loop_paused.png differ
diff --git a/app/src/main/res/drawable-mdpi/loop_superbolus.png b/app/src/main/res/drawable-mdpi/loop_superbolus.png
new file mode 100644
index 0000000000..34a61c1bf3
Binary files /dev/null and b/app/src/main/res/drawable-mdpi/loop_superbolus.png differ
diff --git a/app/src/main/res/drawable-mdpi/soso.png b/app/src/main/res/drawable-mdpi/soso.png
new file mode 100644
index 0000000000..91d9bd7ddf
Binary files /dev/null and b/app/src/main/res/drawable-mdpi/soso.png differ
diff --git a/app/src/main/res/drawable-xhdpi/bad.png b/app/src/main/res/drawable-xhdpi/bad.png
new file mode 100644
index 0000000000..46dca7155f
Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/bad.png differ
diff --git a/app/src/main/res/drawable-xhdpi/good.png b/app/src/main/res/drawable-xhdpi/good.png
new file mode 100644
index 0000000000..08946fed3e
Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/good.png differ
diff --git a/app/src/main/res/drawable-xhdpi/loop_closed.png b/app/src/main/res/drawable-xhdpi/loop_closed.png
new file mode 100644
index 0000000000..f7548add59
Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/loop_closed.png differ
diff --git a/app/src/main/res/drawable-xhdpi/loop_disabled.png b/app/src/main/res/drawable-xhdpi/loop_disabled.png
new file mode 100644
index 0000000000..0f7db5d681
Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/loop_disabled.png differ
diff --git a/app/src/main/res/drawable-xhdpi/loop_disconnected.png b/app/src/main/res/drawable-xhdpi/loop_disconnected.png
new file mode 100644
index 0000000000..7db5047b9f
Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/loop_disconnected.png differ
diff --git a/app/src/main/res/drawable-xhdpi/loop_lgs.png b/app/src/main/res/drawable-xhdpi/loop_lgs.png
new file mode 100644
index 0000000000..baa073ac8c
Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/loop_lgs.png differ
diff --git a/app/src/main/res/drawable-xhdpi/loop_open.png b/app/src/main/res/drawable-xhdpi/loop_open.png
new file mode 100644
index 0000000000..55726849d0
Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/loop_open.png differ
diff --git a/app/src/main/res/drawable-xhdpi/loop_paused.png b/app/src/main/res/drawable-xhdpi/loop_paused.png
new file mode 100644
index 0000000000..399ec449bc
Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/loop_paused.png differ
diff --git a/app/src/main/res/drawable-xhdpi/loop_superbolus.png b/app/src/main/res/drawable-xhdpi/loop_superbolus.png
new file mode 100644
index 0000000000..8bcf96248b
Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/loop_superbolus.png differ
diff --git a/app/src/main/res/drawable-xhdpi/soso.png b/app/src/main/res/drawable-xhdpi/soso.png
new file mode 100644
index 0000000000..8e19db274b
Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/soso.png differ
diff --git a/app/src/main/res/drawable-xxhdpi/bad.png b/app/src/main/res/drawable-xxhdpi/bad.png
new file mode 100644
index 0000000000..b7a3201d60
Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/bad.png differ
diff --git a/app/src/main/res/drawable-xxhdpi/good.png b/app/src/main/res/drawable-xxhdpi/good.png
new file mode 100644
index 0000000000..9f5c243b04
Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/good.png differ
diff --git a/app/src/main/res/drawable-xxhdpi/loop_closed.png b/app/src/main/res/drawable-xxhdpi/loop_closed.png
new file mode 100644
index 0000000000..5418ef1e7e
Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/loop_closed.png differ
diff --git a/app/src/main/res/drawable-xxhdpi/loop_disabled.png b/app/src/main/res/drawable-xxhdpi/loop_disabled.png
new file mode 100644
index 0000000000..580dc5a5f5
Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/loop_disabled.png differ
diff --git a/app/src/main/res/drawable-xxhdpi/loop_disconnected.png b/app/src/main/res/drawable-xxhdpi/loop_disconnected.png
new file mode 100644
index 0000000000..6e991f8ebf
Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/loop_disconnected.png differ
diff --git a/app/src/main/res/drawable-xxhdpi/loop_lgs.png b/app/src/main/res/drawable-xxhdpi/loop_lgs.png
new file mode 100644
index 0000000000..86b4910f33
Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/loop_lgs.png differ
diff --git a/app/src/main/res/drawable-xxhdpi/loop_open.png b/app/src/main/res/drawable-xxhdpi/loop_open.png
new file mode 100644
index 0000000000..1d35a9c987
Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/loop_open.png differ
diff --git a/app/src/main/res/drawable-xxhdpi/loop_paused.png b/app/src/main/res/drawable-xxhdpi/loop_paused.png
new file mode 100644
index 0000000000..6db561b858
Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/loop_paused.png differ
diff --git a/app/src/main/res/drawable-xxhdpi/loop_superbolus.png b/app/src/main/res/drawable-xxhdpi/loop_superbolus.png
new file mode 100644
index 0000000000..c5187cf95d
Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/loop_superbolus.png differ
diff --git a/app/src/main/res/drawable-xxhdpi/soso.png b/app/src/main/res/drawable-xxhdpi/soso.png
new file mode 100644
index 0000000000..6caac0cc05
Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/soso.png differ
diff --git a/app/src/main/res/drawable-xxxhdpi/bad.png b/app/src/main/res/drawable-xxxhdpi/bad.png
new file mode 100644
index 0000000000..484bd8fd0b
Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/bad.png differ
diff --git a/app/src/main/res/drawable-xxxhdpi/good.png b/app/src/main/res/drawable-xxxhdpi/good.png
new file mode 100644
index 0000000000..eb81a2b978
Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/good.png differ
diff --git a/app/src/main/res/drawable-xxxhdpi/loop_closed.png b/app/src/main/res/drawable-xxxhdpi/loop_closed.png
new file mode 100644
index 0000000000..bd78239462
Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/loop_closed.png differ
diff --git a/app/src/main/res/drawable-xxxhdpi/loop_disabled.png b/app/src/main/res/drawable-xxxhdpi/loop_disabled.png
new file mode 100644
index 0000000000..824d6b9db1
Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/loop_disabled.png differ
diff --git a/app/src/main/res/drawable-xxxhdpi/loop_disconnected.png b/app/src/main/res/drawable-xxxhdpi/loop_disconnected.png
new file mode 100644
index 0000000000..9c451cca88
Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/loop_disconnected.png differ
diff --git a/app/src/main/res/drawable-xxxhdpi/loop_lgs.png b/app/src/main/res/drawable-xxxhdpi/loop_lgs.png
new file mode 100644
index 0000000000..80848ff60a
Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/loop_lgs.png differ
diff --git a/app/src/main/res/drawable-xxxhdpi/loop_open.png b/app/src/main/res/drawable-xxxhdpi/loop_open.png
new file mode 100644
index 0000000000..f010399a53
Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/loop_open.png differ
diff --git a/app/src/main/res/drawable-xxxhdpi/loop_paused.png b/app/src/main/res/drawable-xxxhdpi/loop_paused.png
new file mode 100644
index 0000000000..36f9bcb5a5
Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/loop_paused.png differ
diff --git a/app/src/main/res/drawable-xxxhdpi/loop_superbolus.png b/app/src/main/res/drawable-xxxhdpi/loop_superbolus.png
new file mode 100644
index 0000000000..018bf70188
Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/loop_superbolus.png differ
diff --git a/app/src/main/res/drawable-xxxhdpi/soso.png b/app/src/main/res/drawable-xxxhdpi/soso.png
new file mode 100644
index 0000000000..50b8f3fa5c
Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/soso.png differ
diff --git a/app/src/main/res/drawable/ic_swap_vert_black_48dp_green.xml b/app/src/main/res/drawable/ic_swap_vert_black_48dp_green.xml
new file mode 100644
index 0000000000..f78eaede2c
--- /dev/null
+++ b/app/src/main/res/drawable/ic_swap_vert_black_48dp_green.xml
@@ -0,0 +1,5 @@
+
+
+
diff --git a/app/src/main/res/layout/maintenance_importlist_activity.xml b/app/src/main/res/layout/maintenance_importlist_activity.xml
new file mode 100644
index 0000000000..0bdd43b927
--- /dev/null
+++ b/app/src/main/res/layout/maintenance_importlist_activity.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/maintenance_importlist_item.xml b/app/src/main/res/layout/maintenance_importlist_item.xml
new file mode 100644
index 0000000000..8c2cfc0557
--- /dev/null
+++ b/app/src/main/res/layout/maintenance_importlist_item.xml
@@ -0,0 +1,169 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/overview_buttons_layout.xml b/app/src/main/res/layout/overview_buttons_layout.xml
new file mode 100644
index 0000000000..5c97104159
--- /dev/null
+++ b/app/src/main/res/layout/overview_buttons_layout.xml
@@ -0,0 +1,117 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/overview_fragment.xml b/app/src/main/res/layout/overview_fragment.xml
index f122376c2f..747f53798e 100644
--- a/app/src/main/res/layout/overview_fragment.xml
+++ b/app/src/main/res/layout/overview_fragment.xml
@@ -1,628 +1,39 @@
-
+ android:layout_weight="1"
+ android:layout_width="wrap_content"
+ android:layout_height="0dp">
-
-
-
-
-
+ android:layout_height="wrap_content" />
-
+
+
-
+
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
diff --git a/app/src/main/res/layout/overview_fragment_landscape.xml b/app/src/main/res/layout/overview_fragment_landscape.xml
index 471634ea8a..2d6250384d 100644
--- a/app/src/main/res/layout/overview_fragment_landscape.xml
+++ b/app/src/main/res/layout/overview_fragment_landscape.xml
@@ -1,628 +1,40 @@
-
+ android:layout_weight="1"
+ tools:ignore="UselessParent">
-
-
-
-
-
+ android:layout_height="wrap_content" />
-
+
+
-
+
-
+
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
+
diff --git a/app/src/main/res/layout/overview_fragment_nsclient.xml b/app/src/main/res/layout/overview_fragment_nsclient.xml
index 504e88c789..c4ce063e29 100644
--- a/app/src/main/res/layout/overview_fragment_nsclient.xml
+++ b/app/src/main/res/layout/overview_fragment_nsclient.xml
@@ -1,466 +1,32 @@
-
+ android:layout_weight="1"
+ android:layout_width="wrap_content"
+ android:layout_height="0dp">
-
-
-
-
-
+ android:layout_height="wrap_content" />
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+ android:textSize="16sp" />
+ android:textSize="16sp" />
+ android:textSize="16sp" />
-
+
-
-
-
-
-
-
-
-
+
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
diff --git a/app/src/main/res/layout/overview_fragment_nsclient_tablet.xml b/app/src/main/res/layout/overview_fragment_nsclient_tablet.xml
index 585a72159a..5c4340eea6 100644
--- a/app/src/main/res/layout/overview_fragment_nsclient_tablet.xml
+++ b/app/src/main/res/layout/overview_fragment_nsclient_tablet.xml
@@ -27,82 +27,7 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/overview_info_layout.xml b/app/src/main/res/layout/overview_info_layout.xml
new file mode 100644
index 0000000000..9f2cdd8c2f
--- /dev/null
+++ b/app/src/main/res/layout/overview_info_layout.xml
@@ -0,0 +1,242 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/overview_loop_pumpstatus_layout.xml b/app/src/main/res/layout/overview_loop_pumpstatus_layout.xml
new file mode 100644
index 0000000000..98c0d0bd62
--- /dev/null
+++ b/app/src/main/res/layout/overview_loop_pumpstatus_layout.xml
@@ -0,0 +1,64 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/overview_notification_item.xml b/app/src/main/res/layout/overview_notification_item.xml
index 0c0d36ad25..03b5688fc3 100644
--- a/app/src/main/res/layout/overview_notification_item.xml
+++ b/app/src/main/res/layout/overview_notification_item.xml
@@ -1,7 +1,6 @@
-
+ android:layout_height="wrap_content"
+ android:gravity="center_vertical"
+ android:orientation="horizontal">
+
+
+ android:text="@string/dismiss" />
-
-
-
+
diff --git a/app/src/main/res/layout/overview_statuslights_layout.xml b/app/src/main/res/layout/overview_statuslights_layout.xml
new file mode 100644
index 0000000000..930f996736
--- /dev/null
+++ b/app/src/main/res/layout/overview_statuslights_layout.xml
@@ -0,0 +1,97 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
index c1873d786f..de49a0aee5 100644
--- a/app/src/main/res/values/colors.xml
+++ b/app/src/main/res/values/colors.xml
@@ -90,7 +90,11 @@
#FF8C00
#03A9F4
+ #77dd77
#FF8C00
#FF5555
+ #FFFFFF
+ #BBBBBB
+
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 2d287ee70c..e19342032a 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -192,7 +192,6 @@
Disable loop
Enable loop
- LGS
New suggestion available
Unsupported version of Nightscout
LOOP DISABLED BY CONSTRAINTS
@@ -257,6 +256,8 @@
Export canceled! Preferences were NOT exported!
Import canceled! Preferences were NOT imported!
+ Select file to import
+
Please check preferences before importing:
Preferences cannot be imported!
Preferences should not be imported!
@@ -270,6 +271,8 @@
You are using the outdated legacy format from old versions of AAPS, which is not secure! Only use it as a last resort, if you do not have an export in current, JSON format.
Imported preferences are already %1$s days old! Maybe you have more up-to-date preferences or you choose the wrong file? Remember to export preferences regularly!
Invalid date-time format!
+ Preferences from different minor version of application. It is OK if you are importing after upgrade, but check after import if preferences are still correct!
+ Preferences from different major version of application. Major versions differ significantly and may have incompatible preferences! Make sure after import that preferences are still correct!
File format
Created at
@@ -297,6 +300,12 @@
Missing encryption configuration, settings format is invalid!
Unsupported or not specified encryption algorithm!
+ exported today
+ exported %1$s ago
+ exported at %1$s
+ exported less than hour ago
+ in directory: %1$s
+
DanaR
Connecting
Connected
@@ -477,7 +486,7 @@
MM640g
Ongoing Notification
OLD DATA
- %1$d min ago
+ %1$dm ago
%1$dmin ago
Local Profile
OpenAPS AMA
@@ -596,7 +605,7 @@
Show detailed IOB
Break down IOB into bolus and basal IOB on the watchface
not successful - please check phone
- Not available
+ n/a
smscommunicator_allowednumbers
smscommunicator_remotecommandsallowed
Patient age
@@ -1026,7 +1035,7 @@
fromNSAreCommingFakedExtendedBoluses
Engineering mode enabled
Engineering mode not enabled and not on release branch
- %1$.2f U/h
+ %1$.2fU/h
Reading basal profile
The pump history has changed after the bolus calculation was performed. The bolus was not delivered. Please recalculate if a bolus is still needed.
Bolus successfully delivered, but adding the treatment entry failed. This can happen if two small boluses of the same size are administered within the last two minutes. Please check the pump history and treatment entries and use the Careportal to add missing entries. Make sure not to add any entries for the exact same minute and same amount.
@@ -1099,7 +1108,6 @@
Setup Wizard
FINISH
Select your language
- language
openapsama_min_5m_carbimpact
Asked: %1$.2fU Delivered: %2$.2fU Error code: %3$s
First insulin increment
@@ -1549,10 +1557,6 @@
STOP
Selected
RileyLink Scan
- Bluetooth Low Energy not supported.
- Bluetooth not enabled.
- Location Is Not Enabled
- For Bluetooth discovery to work on newer devices, location must be enabled. AAPS does not track your location and it can be disabled after pairing is successful.
Enable
No
Scanning
@@ -1825,6 +1829,10 @@
statuslights_copy_ns
Copy NS settings (if exists)?
statuslights_overview_advanced
+ Original skin
+ Buttons are always displayed on bottom of screen
+ skin
+ Skin
diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml
index 4914afa9fe..747db85115 100644
--- a/app/src/main/res/values/styles.xml
+++ b/app/src/main/res/values/styles.xml
@@ -16,12 +16,6 @@
- @color/dialog_title_icon_tint
-
-
+
\ No newline at end of file
diff --git a/core/src/main/res/values/strings.xml b/core/src/main/res/values/strings.xml
index b89cf096bd..be67629d42 100644
--- a/core/src/main/res/values/strings.xml
+++ b/core/src/main/res/values/strings.xml
@@ -1,10 +1,17 @@
enable_fabric
+ language
+
Confirmation
Message
OK
Cancel
DISMISS
+ Bluetooth Low Energy not supported.
+ Bluetooth not enabled.
+ Location Is Not Enabled
+ For Bluetooth discovery to work on newer devices, location must be enabled. AAPS does not track your location and it can be disabled after pairing is successful.
+
\ No newline at end of file
diff --git a/gradle.properties b/gradle.properties
index 1bc51c91af..43ad963b2f 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -15,7 +15,7 @@
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
-# org.gradle.parallel=true
+org.gradle.parallel=true
org.gradle.jvmargs=-Xmx2g
diff --git a/wear/build.gradle b/wear/build.gradle
index dc73e3c4f0..ffe7617086 100644
--- a/wear/build.gradle
+++ b/wear/build.gradle
@@ -122,9 +122,9 @@ dependencies {
implementation 'androidx.wear:wear:1.0.0'
implementation('me.denley.wearpreferenceactivity:wearpreferenceactivity:0.5.0')
implementation('com.github.lecho:hellocharts-library:1.5.8@aar')
-
- testImplementation "junit:junit:4.12"
- testImplementation "org.json:json:20140107"
+
+ testImplementation 'junit:junit:4.13'
+ testImplementation 'org.json:json:20190722'
testImplementation ("org.mockito:mockito-core:2.8.47") {
exclude group: 'net.bytebuddy', module: 'byte-buddy'
exclude group: 'net.bytebuddy', module: 'byte-buddy-android'
@@ -139,8 +139,8 @@ dependencies {
testImplementation "org.powermock:powermock-module-junit4-rule-agent:${powermockVersion}"
testImplementation "org.powermock:powermock-module-junit4-rule:${powermockVersion}"
testImplementation "org.powermock:powermock-module-junit4:${powermockVersion}"
- testImplementation "joda-time:joda-time:2.9.9"
- testImplementation("com.google.truth:truth:0.39") {
+ testImplementation 'joda-time:joda-time:2.10.6'
+ testImplementation('com.google.truth:truth:1.0.1') {
exclude group: "com.google.guava", module: "guava"
}
testImplementation "org.skyscreamer:jsonassert:1.5.0"