This commit is contained in:
Milos Kozak 2022-03-11 08:23:16 +01:00
commit 21d0320e61
52 changed files with 817 additions and 554 deletions

View file

@ -44,5 +44,5 @@ Hints
* Start small, it is easier to review smaller changes that affect fewer parts of code
* Take a look into Issues list (https://github.com/nightscout/AndroidAPS/issues) - maybe there is something you can fix or implement
* For new features, make sure there is Issue to track progress and have on-topic discussion
* Reach out to community, discuss idea on Gitter (https://gitter.im/MilosKozak/AndroidAPS)
* Reach out to community, discuss idea on Discord (https://discord.gg/4fQUWHZ4Mw)
* Speak with other developers to minimise merge conflicts. Find out who worked, working or plan to work on speciffic issue or part of app

View file

@ -109,7 +109,7 @@ android {
defaultConfig {
multiDexEnabled true
versionCode 1500
version "3.0.0.1-dev-d"
version "3.0.0.1-dev-e"
buildConfigField "String", "VERSION", '"' + version + '"'
buildConfigField "String", "BUILDVERSION", '"' + generateGitBuild() + '-' + generateDate() + '"'
buildConfigField "String", "REMOTE", '"' + generateGitRemote() + '"'

View file

@ -89,7 +89,7 @@ class MainActivity : NoSplashAppCompatActivity() {
private var pluginPreferencesMenuItem: MenuItem? = null
private var menu: Menu? = null
private var menuOpen = false
private var isProtectionCheckActive = false
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
@ -168,11 +168,14 @@ class MainActivity : NoSplashAppCompatActivity() {
override fun onResume() {
super.onResume()
protectionCheck.queryProtection(this, ProtectionCheck.Protection.APPLICATION, null,
UIRunnable { OKDialog.show(this, "", rh.gs(R.string.authorizationfailed)) { finish() } },
UIRunnable { OKDialog.show(this, "", rh.gs(R.string.authorizationfailed)) { finish() } }
if (!isProtectionCheckActive) {
isProtectionCheckActive = true
protectionCheck.queryProtection(this, ProtectionCheck.Protection.APPLICATION, UIRunnable { isProtectionCheckActive = false },
UIRunnable { OKDialog.show(this, "", rh.gs(R.string.authorizationfailed)) { isProtectionCheckActive = false; finish() } },
UIRunnable { OKDialog.show(this, "", rh.gs(R.string.authorizationfailed)) { isProtectionCheckActive = false; finish() } }
)
}
}
private fun setWakeLock() {
val keepScreenOn = sp.getBoolean(R.string.key_keep_screen_on, false)
@ -417,6 +420,8 @@ class MainActivity : NoSplashAppCompatActivity() {
// Add to crash log too
FirebaseCrashlytics.getInstance().setCustomKey("HEAD", BuildConfig.HEAD)
FirebaseCrashlytics.getInstance().setCustomKey("Version", BuildConfig.VERSION)
FirebaseCrashlytics.getInstance().setCustomKey("BuildType", BuildConfig.BUILD_TYPE)
FirebaseCrashlytics.getInstance().setCustomKey("BuildFlavor", BuildConfig.FLAVOR)
FirebaseCrashlytics.getInstance().setCustomKey("Remote", remote)
FirebaseCrashlytics.getInstance().setCustomKey("Committed", BuildConfig.COMMITTED)
FirebaseCrashlytics.getInstance().setCustomKey("Hash", hashes[0])

View file

@ -8,17 +8,17 @@ import android.os.Bundle
import androidx.annotation.XmlRes
import androidx.preference.*
import dagger.android.support.AndroidSupportInjection
import info.nightscout.androidaps.interfaces.Config
import info.nightscout.androidaps.R
import info.nightscout.androidaps.danaRKorean.DanaRKoreanPlugin
import info.nightscout.androidaps.danaRv2.DanaRv2Plugin
import info.nightscout.androidaps.danar.DanaRPlugin
import info.nightscout.androidaps.danars.DanaRSPlugin
import info.nightscout.androidaps.diaconn.DiaconnG8Plugin
import info.nightscout.androidaps.interfaces.Profile
import info.nightscout.androidaps.events.EventPreferenceChange
import info.nightscout.androidaps.events.EventRebuildTabs
import info.nightscout.androidaps.interfaces.Config
import info.nightscout.androidaps.interfaces.PluginBase
import info.nightscout.androidaps.interfaces.Profile
import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.androidaps.plugin.general.openhumans.OpenHumansUploader
import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin
@ -43,17 +43,12 @@ import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpPlugin
import info.nightscout.androidaps.plugins.sensitivity.SensitivityAAPSPlugin
import info.nightscout.androidaps.plugins.sensitivity.SensitivityOref1Plugin
import info.nightscout.androidaps.plugins.sensitivity.SensitivityWeightedAveragePlugin
import info.nightscout.androidaps.plugins.source.DexcomPlugin
import info.nightscout.androidaps.plugins.source.EversensePlugin
import info.nightscout.androidaps.plugins.source.GlimpPlugin
import info.nightscout.androidaps.plugins.source.PoctechPlugin
import info.nightscout.androidaps.plugins.source.TomatoPlugin
import info.nightscout.androidaps.plugins.source.GlunovoPlugin
import info.nightscout.shared.SafeParse
import info.nightscout.androidaps.plugins.source.*
import info.nightscout.androidaps.utils.alertDialogs.OKDialog.show
import info.nightscout.androidaps.utils.protection.PasswordCheck
import info.nightscout.androidaps.utils.protection.ProtectionCheck
import info.nightscout.androidaps.utils.protection.ProtectionCheck.ProtectionType.*
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.shared.SafeParse
import info.nightscout.shared.sharedPreferences.SP
import javax.inject.Inject
@ -239,7 +234,7 @@ class MyPreferenceFragment : PreferenceFragmentCompat(), OnSharedPreferenceChang
rh.gs(R.string.key_application_protection) == key ||
rh.gs(R.string.key_bolus_protection) == key) &&
sp.getString(R.string.key_master_password, "") == "" &&
sp.getInt(key, ProtectionCheck.ProtectionType.NONE.ordinal) == ProtectionCheck.ProtectionType.BIOMETRIC.ordinal
sp.getInt(key, NONE.ordinal) == BIOMETRIC.ordinal
) {
activity?.let {
val title = rh.gs(R.string.unsecure_fallback_biometric)
@ -249,9 +244,9 @@ class MyPreferenceFragment : PreferenceFragmentCompat(), OnSharedPreferenceChang
}
// Master password erased with activated Biometric protection
val isBiometricActivated = sp.getInt(R.string.key_settings_protection, ProtectionCheck.ProtectionType.NONE.ordinal) == ProtectionCheck.ProtectionType.BIOMETRIC.ordinal ||
sp.getInt(R.string.key_application_protection, ProtectionCheck.ProtectionType.NONE.ordinal) == ProtectionCheck.ProtectionType.BIOMETRIC.ordinal ||
sp.getInt(R.string.key_bolus_protection, ProtectionCheck.ProtectionType.NONE.ordinal) == ProtectionCheck.ProtectionType.BIOMETRIC.ordinal
val isBiometricActivated = sp.getInt(R.string.key_settings_protection, NONE.ordinal) == BIOMETRIC.ordinal ||
sp.getInt(R.string.key_application_protection, NONE.ordinal) == BIOMETRIC.ordinal ||
sp.getInt(R.string.key_bolus_protection, NONE.ordinal) == BIOMETRIC.ordinal
if (rh.gs(R.string.key_master_password) == key && sp.getString(key, "") == "" && isBiometricActivated) {
activity?.let {
val title = rh.gs(R.string.unsecure_fallback_biometric)
@ -322,26 +317,35 @@ class MyPreferenceFragment : PreferenceFragmentCompat(), OnSharedPreferenceChang
if (pref is ListPreference) {
pref.setSummary(pref.entry)
// Preferences
// Preferences
if (pref.getKey() == rh.gs(R.string.key_settings_protection)) {
val pass: Preference? = findPreference(rh.gs(R.string.key_settings_password))
if (pass != null) pass.isEnabled = pref.value == ProtectionCheck.ProtectionType.CUSTOM_PASSWORD.ordinal.toString()
val usePassword = pref.value == CUSTOM_PASSWORD.ordinal.toString()
pass?.let { it.isVisible = usePassword }
val pin: Preference? = findPreference(rh.gs(R.string.key_settings_pin))
val usePin = pref.value == CUSTOM_PIN.ordinal.toString()
pin?.let { it.isVisible = usePin }
}
// Application
// Application
if (pref.getKey() == rh.gs(R.string.key_application_protection)) {
val pass: Preference? = findPreference(rh.gs(R.string.key_application_password))
if (pass != null) pass.isEnabled = pref.value == ProtectionCheck.ProtectionType.CUSTOM_PASSWORD.ordinal.toString()
val usePassword = pref.value == CUSTOM_PASSWORD.ordinal.toString()
pass?.let { it.isVisible = usePassword }
val pin: Preference? = findPreference(rh.gs(R.string.key_application_pin))
val usePin = pref.value == CUSTOM_PIN.ordinal.toString()
pin?.let { it.isVisible = usePin }
}
// Bolus
// Bolus
if (pref.getKey() == rh.gs(R.string.key_bolus_protection)) {
val pass: Preference? = findPreference(rh.gs(R.string.key_bolus_password))
if (pass != null) pass.isEnabled = pref.value == ProtectionCheck.ProtectionType.CUSTOM_PASSWORD.ordinal.toString()
val usePassword = pref.value == CUSTOM_PASSWORD.ordinal.toString()
pass?.let { it.isVisible = usePassword }
val pin: Preference? = findPreference(rh.gs(R.string.key_bolus_pin))
val usePin = pref.value == CUSTOM_PIN.ordinal.toString()
pin?.let { it.isVisible = usePin }
}
}
if (pref is EditTextPreference) {
if (pref.getKey().contains("password") || pref.getKey().contains("secret")) {
if (pref.getKey().contains("password") || pref.getKey().contains("pin") || pref.getKey().contains("secret")) {
pref.setSummary("******")
} else if (pref.text != null) {
pref.dialogMessage = pref.dialogMessage
@ -357,18 +361,25 @@ class MyPreferenceFragment : PreferenceFragmentCompat(), OnSharedPreferenceChang
rh.gs(R.string.key_bolus_password),
rh.gs(R.string.key_master_password),
rh.gs(R.string.key_application_password),
rh.gs(R.string.key_settings_password)
rh.gs(R.string.key_settings_password),
rh.gs(R.string.key_bolus_pin),
rh.gs(R.string.key_application_pin),
rh.gs(R.string.key_settings_pin)
)
if (pref is Preference) {
if ((pref.key != null) && (hmacPasswords.contains(pref.key))) {
if (sp.getString(pref.key, "").startsWith("hmac:")) {
pref.summary = "******"
} else {
if (pref.getKey().contains("pin")) {
pref.summary = rh.gs(R.string.pin_not_set)
}else {
pref.summary = rh.gs(R.string.password_not_set)
}
}
}
}
pref?.let { adjustUnitDependentPrefs(it) }
}
@ -411,6 +422,18 @@ class MyPreferenceFragment : PreferenceFragmentCompat(), OnSharedPreferenceChang
passwordCheck.setPassword(context, R.string.application_password, R.string.key_application_password)
return true
}
if (preference.key == rh.gs(R.string.key_settings_pin)) {
passwordCheck.setPassword(context, R.string.settings_pin, R.string.key_settings_pin, pinInput = true)
return true
}
if (preference.key == rh.gs(R.string.key_bolus_pin)) {
passwordCheck.setPassword(context, R.string.bolus_pin, R.string.key_bolus_pin, pinInput = true)
return true
}
if (preference.key == rh.gs(R.string.key_application_pin)) {
passwordCheck.setPassword(context, R.string.application_pin, R.string.key_application_pin, pinInput = true)
return true
}
// NSClient copy settings
if (preference.key == rh.gs(R.string.key_statuslights_copy_ns)) {
nsSettingStatus.copyStatusLightsNsSettings(context)

View file

@ -103,7 +103,7 @@ class TempTargetDialog : DialogFragmentWithDate() {
val adapterReason = ArrayAdapter(context, R.layout.spinner_centered, reasonList)
binding.reason.adapter = adapterReason
binding.targetCancel.setOnClickListener { shortClick(it) }
binding.targetCancel.setOnClickListener { binding.duration.value = 0.0; shortClick(it) }
binding.eatingSoon.setOnClickListener { shortClick(it) }
binding.activity.setOnClickListener { shortClick(it) }
binding.hypo.setOnClickListener { shortClick(it) }
@ -149,10 +149,6 @@ class TempTargetDialog : DialogFragmentWithDate() {
binding.duration.value = defaultValueHelper.determineHypoTTDuration().toDouble()
binding.reason.setSelection(reasonList.indexOf(rh.gs(R.string.hypo)))
}
R.id.cancel -> {
binding.duration.value = 0.0
}
}
}

View file

@ -438,10 +438,10 @@ class WizardDialog : DaggerDialogFragment() {
)
wizard?.let { wizard ->
binding.bg.text = String.format(rh.gs(R.string.format_bg_isf), valueToUnitsToString(Profile.toMgdl(bg, profileFunction.getUnits()), profileFunction.getUnits().asText), wizard.sens)
binding.bg.text = rh.gs(R.string.format_bg_isf, valueToUnitsToString(Profile.toMgdl(bg, profileFunction.getUnits()), profileFunction.getUnits().asText), wizard.sens)
binding.bgInsulin.text = rh.gs(R.string.formatinsulinunits, wizard.insulinFromBG)
binding.carbs.text = String.format(rh.gs(R.string.format_carbs_ic), carbs.toDouble(), wizard.ic)
binding.carbs.text = rh.gs(R.string.format_carbs_ic, carbs.toDouble(), wizard.ic)
binding.carbsInsulin.text = rh.gs(R.string.formatinsulinunits, wizard.insulinFromCarbs)
binding.iobInsulin.text = rh.gs(R.string.formatinsulinunits, wizard.insulinFromBolusIOB + wizard.insulinFromBasalIOB)
@ -464,7 +464,7 @@ class WizardDialog : DaggerDialogFragment() {
// COB
if (binding.cobCheckbox.isChecked) {
binding.cob.text = String.format(rh.gs(R.string.format_cob_ic), cob, wizard.ic)
binding.cob.text = rh.gs(R.string.format_cob_ic, cob, wizard.ic)
binding.cobInsulin.text = rh.gs(R.string.formatinsulinunits, wizard.insulinFromCOB)
} else {
binding.cob.text = ""

View file

@ -109,29 +109,29 @@ class SafetyPlugin @Inject constructor(
}
override fun applyBasalConstraints(absoluteRate: Constraint<Double>, profile: Profile): Constraint<Double> {
absoluteRate.setIfGreater(aapsLogger, 0.0, String.format(rh.gs(R.string.limitingbasalratio), 0.0, rh.gs(R.string.itmustbepositivevalue)), this)
absoluteRate.setIfGreater(aapsLogger, 0.0, rh.gs(R.string.limitingbasalratio, 0.0, rh.gs(R.string.itmustbepositivevalue)), this)
if (config.APS) {
var maxBasal = sp.getDouble(R.string.key_openapsma_max_basal, 1.0)
if (maxBasal < profile.getMaxDailyBasal()) {
maxBasal = profile.getMaxDailyBasal()
absoluteRate.addReason(rh.gs(R.string.increasingmaxbasal), this)
}
absoluteRate.setIfSmaller(aapsLogger, maxBasal, String.format(rh.gs(R.string.limitingbasalratio), maxBasal, rh.gs(R.string.maxvalueinpreferences)), this)
absoluteRate.setIfSmaller(aapsLogger, maxBasal,rh.gs(R.string.limitingbasalratio, maxBasal, rh.gs(R.string.maxvalueinpreferences)), this)
// Check percentRate but absolute rate too, because we know real current basal in pump
val maxBasalMultiplier = sp.getDouble(R.string.key_openapsama_current_basal_safety_multiplier, 4.0)
val maxFromBasalMultiplier = floor(maxBasalMultiplier * profile.getBasal() * 100) / 100
absoluteRate.setIfSmaller(aapsLogger, maxFromBasalMultiplier, String.format(rh.gs(R.string.limitingbasalratio), maxFromBasalMultiplier, rh.gs(R.string.maxbasalmultiplier)), this)
absoluteRate.setIfSmaller(aapsLogger, maxFromBasalMultiplier, rh.gs(R.string.limitingbasalratio, maxFromBasalMultiplier, rh.gs(R.string.maxbasalmultiplier)), this)
val maxBasalFromDaily = sp.getDouble(R.string.key_openapsama_max_daily_safety_multiplier, 3.0)
val maxFromDaily = floor(profile.getMaxDailyBasal() * maxBasalFromDaily * 100) / 100
absoluteRate.setIfSmaller(aapsLogger, maxFromDaily, String.format(rh.gs(R.string.limitingbasalratio), maxFromDaily, rh.gs(R.string.maxdailybasalmultiplier)), this)
absoluteRate.setIfSmaller(aapsLogger, maxFromDaily,rh.gs(R.string.limitingbasalratio, maxFromDaily, rh.gs(R.string.maxdailybasalmultiplier)), this)
}
absoluteRate.setIfSmaller(aapsLogger, hardLimits.maxBasal(), String.format(rh.gs(R.string.limitingbasalratio), hardLimits.maxBasal(), rh.gs(R.string.hardlimit)), this)
absoluteRate.setIfSmaller(aapsLogger, hardLimits.maxBasal(),rh.gs(R.string.limitingbasalratio, hardLimits.maxBasal(), rh.gs(R.string.hardlimit)), this)
val pump = activePlugin.activePump
// check for pump max
if (pump.pumpDescription.tempBasalStyle == PumpDescription.ABSOLUTE) {
val pumpLimit = pump.pumpDescription.pumpType.tbrSettings?.maxDose ?: 0.0
absoluteRate.setIfSmaller(aapsLogger, pumpLimit, String.format(rh.gs(R.string.limitingbasalratio), pumpLimit, rh.gs(R.string.pumplimit)), this)
absoluteRate.setIfSmaller(aapsLogger, pumpLimit, rh.gs(R.string.limitingbasalratio, pumpLimit, rh.gs(R.string.pumplimit)), this)
}
// do rounding
@ -151,19 +151,19 @@ class SafetyPlugin @Inject constructor(
val pump = activePlugin.activePump
var percentRateAfterConst = java.lang.Double.valueOf(absoluteConstraint.value() / currentBasal * 100).toInt()
percentRateAfterConst = if (percentRateAfterConst < 100) Round.ceilTo(percentRateAfterConst.toDouble(), pump.pumpDescription.tempPercentStep.toDouble()).toInt() else Round.floorTo(percentRateAfterConst.toDouble(), pump.pumpDescription.tempPercentStep.toDouble()).toInt()
percentRate.set(aapsLogger, percentRateAfterConst, String.format(rh.gs(R.string.limitingpercentrate), percentRateAfterConst, rh.gs(R.string.pumplimit)), this)
percentRate.set(aapsLogger, percentRateAfterConst, rh.gs(R.string.limitingpercentrate, percentRateAfterConst, rh.gs(R.string.pumplimit)), this)
if (pump.pumpDescription.tempBasalStyle == PumpDescription.PERCENT) {
val pumpLimit = pump.pumpDescription.pumpType.tbrSettings?.maxDose ?: 0.0
percentRate.setIfSmaller(aapsLogger, pumpLimit.toInt(), String.format(rh.gs(R.string.limitingbasalratio), pumpLimit, rh.gs(R.string.pumplimit)), this)
percentRate.setIfSmaller(aapsLogger, pumpLimit.toInt(), rh.gs(R.string.limitingbasalratio, pumpLimit, rh.gs(R.string.pumplimit)), this)
}
return percentRate
}
override fun applyBolusConstraints(insulin: Constraint<Double>): Constraint<Double> {
insulin.setIfGreater(aapsLogger, 0.0, String.format(rh.gs(R.string.limitingbolus), 0.0, rh.gs(R.string.itmustbepositivevalue)), this)
insulin.setIfGreater(aapsLogger, 0.0, rh.gs(R.string.limitingbolus, 0.0, rh.gs(R.string.itmustbepositivevalue)), this)
val maxBolus = sp.getDouble(R.string.key_treatmentssafety_maxbolus, 3.0)
insulin.setIfSmaller(aapsLogger, maxBolus, String.format(rh.gs(R.string.limitingbolus), maxBolus, rh.gs(R.string.maxvalueinpreferences)), this)
insulin.setIfSmaller(aapsLogger, hardLimits.maxBolus(), String.format(rh.gs(R.string.limitingbolus), hardLimits.maxBolus(), rh.gs(R.string.hardlimit)), this)
insulin.setIfSmaller(aapsLogger, maxBolus, rh.gs(R.string.limitingbolus, maxBolus, rh.gs(R.string.maxvalueinpreferences)), this)
insulin.setIfSmaller(aapsLogger, hardLimits.maxBolus(), rh.gs(R.string.limitingbolus, hardLimits.maxBolus(), rh.gs(R.string.hardlimit)), this)
val pump = activePlugin.activePump
val rounded = pump.pumpDescription.pumpType.determineCorrectBolusSize(insulin.value())
insulin.setIfDifferent(aapsLogger, rounded, rh.gs(R.string.pumplimit), this)
@ -171,10 +171,10 @@ class SafetyPlugin @Inject constructor(
}
override fun applyExtendedBolusConstraints(insulin: Constraint<Double>): Constraint<Double> {
insulin.setIfGreater(aapsLogger, 0.0, String.format(rh.gs(R.string.limitingextendedbolus), 0.0, rh.gs(R.string.itmustbepositivevalue)), this)
insulin.setIfGreater(aapsLogger, 0.0, rh.gs(R.string.limitingextendedbolus, 0.0, rh.gs(R.string.itmustbepositivevalue)), this)
val maxBolus = sp.getDouble(R.string.key_treatmentssafety_maxbolus, 3.0)
insulin.setIfSmaller(aapsLogger, maxBolus, String.format(rh.gs(R.string.limitingextendedbolus), maxBolus, rh.gs(R.string.maxvalueinpreferences)), this)
insulin.setIfSmaller(aapsLogger, hardLimits.maxBolus(), String.format(rh.gs(R.string.limitingextendedbolus), hardLimits.maxBolus(), rh.gs(R.string.hardlimit)), this)
insulin.setIfSmaller(aapsLogger, maxBolus, rh.gs(R.string.limitingextendedbolus, maxBolus, rh.gs(R.string.maxvalueinpreferences)), this)
insulin.setIfSmaller(aapsLogger, hardLimits.maxBolus(), rh.gs(R.string.limitingextendedbolus, hardLimits.maxBolus(), rh.gs(R.string.hardlimit)), this)
val pump = activePlugin.activePump
val rounded = pump.pumpDescription.pumpType.determineCorrectExtendedBolusSize(insulin.value())
insulin.setIfDifferent(aapsLogger, rounded, rh.gs(R.string.pumplimit), this)
@ -182,9 +182,9 @@ class SafetyPlugin @Inject constructor(
}
override fun applyCarbsConstraints(carbs: Constraint<Int>): Constraint<Int> {
carbs.setIfGreater(aapsLogger, 0, String.format(rh.gs(R.string.limitingcarbs), 0, rh.gs(R.string.itmustbepositivevalue)), this)
carbs.setIfGreater(aapsLogger, 0, rh.gs(R.string.limitingcarbs, 0, rh.gs(R.string.itmustbepositivevalue)), this)
val maxCarbs = sp.getInt(R.string.key_treatmentssafety_maxcarbs, 48)
carbs.setIfSmaller(aapsLogger, maxCarbs, String.format(rh.gs(R.string.limitingcarbs), maxCarbs, rh.gs(R.string.maxvalueinpreferences)), this)
carbs.setIfSmaller(aapsLogger, maxCarbs, rh.gs(R.string.limitingcarbs, maxCarbs, rh.gs(R.string.maxvalueinpreferences)), this)
return carbs
}
@ -192,11 +192,11 @@ class SafetyPlugin @Inject constructor(
val apsMode = sp.getString(R.string.key_aps_mode, "open")
val maxIobPref: Double = if (openAPSSMBPlugin.isEnabled() || OpenAPSSMBDynamicISFPlugin.isEnabled()) sp.getDouble(R.string.key_openapssmb_max_iob, 3.0) else sp.getDouble(R.string
.key_openapsma_max_iob, 1.5)
maxIob.setIfSmaller(aapsLogger, maxIobPref, String.format(rh.gs(R.string.limitingiob), maxIobPref, rh.gs(R.string.maxvalueinpreferences)), this)
if (openAPSAMAPlugin.isEnabled()) maxIob.setIfSmaller(aapsLogger, hardLimits.maxIobAMA(), String.format(rh.gs(R.string.limitingiob), hardLimits.maxIobAMA(), rh.gs(R.string.hardlimit)), this)
if (openAPSSMBPlugin.isEnabled()) maxIob.setIfSmaller(aapsLogger, hardLimits.maxIobSMB(), String.format(rh.gs(R.string.limitingiob), hardLimits.maxIobSMB(), rh.gs(R.string.hardlimit)), this)
if (OpenAPSSMBDynamicISFPlugin.isEnabled()) maxIob.setIfSmaller(aapsLogger, hardLimits.maxIobSMB(), String.format(rh.gs(R.string.limitingiob), hardLimits.maxIobSMB(), rh.gs(R.string.hardlimit)), this)
if (apsMode == "lgs") maxIob.setIfSmaller(aapsLogger, HardLimits.MAX_IOB_LGS, String.format(rh.gs(R.string.limitingiob), HardLimits.MAX_IOB_LGS, rh.gs(R.string.lowglucosesuspend)), this)
maxIob.setIfSmaller(aapsLogger, maxIobPref, rh.gs(R.string.limitingiob, maxIobPref, rh.gs(R.string.maxvalueinpreferences)), this)
if (openAPSAMAPlugin.isEnabled()) maxIob.setIfSmaller(aapsLogger, hardLimits.maxIobAMA(), rh.gs(R.string.limitingiob, hardLimits.maxIobAMA(), rh.gs(R.string.hardlimit)), this)
if (openAPSSMBPlugin.isEnabled()) maxIob.setIfSmaller(aapsLogger, hardLimits.maxIobSMB(), rh.gs(R.string.limitingiob, hardLimits.maxIobSMB(), rh.gs(R.string.hardlimit)), this)
if (OpenAPSSMBDynamicISFPlugin.isEnabled()) maxIob.setIfSmaller(aapsLogger, hardLimits.maxIobSMB(), rh.gs(R.string.limitingiob, hardLimits.maxIobSMB(), rh.gs(R.string.hardlimit)), this)
if (apsMode == "lgs") maxIob.setIfSmaller(aapsLogger, HardLimits.MAX_IOB_LGS, rh.gs(R.string.limitingiob, HardLimits.MAX_IOB_LGS, rh.gs(R.string.lowglucosesuspend)), this)
return maxIob
}

View file

@ -157,10 +157,20 @@ class ActionsFragment : DaggerFragment() {
cannulaOrPatch = view.findViewById(R.id.cannula_or_patch)
profileSwitch?.setOnClickListener {
ProfileSwitchDialog().show(childFragmentManager, "ProfileSwitchDialog")
activity?.let { activity ->
protectionCheck.queryProtection(
activity,
ProtectionCheck.Protection.BOLUS,
UIRunnable { ProfileSwitchDialog().show(childFragmentManager, "ProfileSwitchDialog")})
}
}
tempTarget?.setOnClickListener {
TempTargetDialog().show(childFragmentManager, "Actions")
activity?.let { activity ->
protectionCheck.queryProtection(
activity,
ProtectionCheck.Protection.BOLUS,
UIRunnable { TempTargetDialog().show(childFragmentManager, "Actions") })
}
}
extendedBolus?.setOnClickListener {
activity?.let { activity ->
@ -187,7 +197,12 @@ class ActionsFragment : DaggerFragment() {
}
}
setTempBasal?.setOnClickListener {
TempBasalDialog().show(childFragmentManager, "Actions")
activity?.let { activity ->
protectionCheck.queryProtection(
activity,
ProtectionCheck.Protection.BOLUS,
UIRunnable { TempBasalDialog().show(childFragmentManager, "Actions") })
}
}
cancelTempBasal?.setOnClickListener {
if (iobCobCalculator.getTempBasalIncludingConvertedExtended(dateUtil.now()) != null) {

View file

@ -27,6 +27,7 @@ import info.nightscout.androidaps.plugins.general.overview.OverviewData
import info.nightscout.androidaps.plugins.pump.omnipod.dash.history.database.DashHistoryDatabase
import info.nightscout.androidaps.plugins.pump.omnipod.eros.history.database.ErosHistoryDatabase
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
import info.nightscout.androidaps.utils.protection.ProtectionCheck
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.rx.AapsSchedulers
import io.reactivex.rxjava3.core.Completable.fromAction
@ -48,6 +49,7 @@ class MaintenanceFragment : DaggerFragment() {
@Inject lateinit var diaconnDatabase: DiaconnHistoryDatabase
@Inject lateinit var erosDatabase: ErosHistoryDatabase
@Inject lateinit var dashDatabase: DashHistoryDatabase
@Inject lateinit var protectionCheck: ProtectionCheck
@Inject lateinit var uel: UserEntryLogger
@Inject lateinit var dataSyncSelector: DataSyncSelector
@Inject lateinit var pumpSync: PumpSync
@ -128,6 +130,23 @@ class MaintenanceFragment : DaggerFragment() {
}
}
}
if (protectionCheck.isLocked(ProtectionCheck.Protection.PREFERENCES)) {
binding.mainLayout.visibility = View.GONE
} else {
binding.unlock.visibility = View.GONE
}
binding.unlock.setOnClickListener {
activity?.let { activity ->
protectionCheck.queryProtection(activity, ProtectionCheck.Protection.PREFERENCES, {
activity.runOnUiThread {
binding.mainLayout.visibility = View.VISIBLE
binding.unlock.visibility = View.GONE
}
})
}
}
}
@Synchronized

View file

@ -164,11 +164,11 @@ class NotificationStore @Inject constructor(
@Suppress("SetTextI18n")
holder.binding.text.text = dateUtil.timeString(notification.date) + " " + notification.text
when (notification.level) {
Notification.URGENT -> holder.binding.cv.setBackgroundColor(rh.gc(R.color.notificationUrgent))
Notification.NORMAL -> holder.binding.cv.setBackgroundColor(rh.gc(R.color.notificationNormal))
Notification.LOW -> holder.binding.cv.setBackgroundColor(rh.gc(R.color.notificationLow))
Notification.INFO -> holder.binding.cv.setBackgroundColor(rh.gc(R.color.notificationInfo))
Notification.ANNOUNCEMENT -> holder.binding.cv.setBackgroundColor(rh.gc(R.color.notificationAnnouncement))
Notification.URGENT -> holder.binding.cv.setBackgroundColor(rh.gac(R.attr.notificationUrgent))
Notification.NORMAL -> holder.binding.cv.setBackgroundColor(rh.gac(R.attr.notificationNormal))
Notification.LOW -> holder.binding.cv.setBackgroundColor(rh.gac(R.attr.notificationLow))
Notification.INFO -> holder.binding.cv.setBackgroundColor(rh.gac(R.attr.notificationInfo))
Notification.ANNOUNCEMENT -> holder.binding.cv.setBackgroundColor(rh.gac(R.attr.notificationAnnouncement))
}
}

View file

@ -328,7 +328,7 @@ class SmsCommunicatorPlugin @Inject constructor(
} else if (lastBG != null) {
val agoMilliseconds = dateUtil.now() - lastBG.timestamp
val agoMin = (agoMilliseconds / 60.0 / 1000.0).toInt()
reply = rh.gs(R.string.sms_lastbg) + " " + lastBG.valueToUnitsString(units) + " " + String.format(rh.gs(R.string.sms_minago), agoMin) + ", "
reply = rh.gs(R.string.sms_lastbg) + " " + lastBG.valueToUnitsString(units) + " " + rh.gs(R.string.sms_minago, agoMin) + ", "
}
val glucoseStatus = glucoseStatusProvider.glucoseStatusData
if (glucoseStatus != null) reply += rh.gs(R.string.sms_delta) + " " + Profile.toUnitsString(glucoseStatus.delta, glucoseStatus.delta * Constants.MGDL_TO_MMOLL, units) + " " + units + ", "
@ -348,7 +348,7 @@ class SmsCommunicatorPlugin @Inject constructor(
"DISABLE", "STOP" -> {
if (loop.enabled) {
val passCode = generatePassCode()
val reply = String.format(rh.gs(R.string.smscommunicator_loopdisablereplywithcode), passCode)
val reply = rh.gs(R.string.smscommunicator_loopdisablereplywithcode, passCode)
receivedSms.processed = true
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction(pumpCommand = false) {
override fun run() {
@ -372,7 +372,7 @@ class SmsCommunicatorPlugin @Inject constructor(
"ENABLE", "START" -> {
if (!loop.enabled) {
val passCode = generatePassCode()
val reply = String.format(rh.gs(R.string.smscommunicator_loopenablereplywithcode), passCode)
val reply = rh.gs(R.string.smscommunicator_loopenablereplywithcode, passCode)
receivedSms.processed = true
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction(pumpCommand = false) {
override fun run() {
@ -389,7 +389,7 @@ class SmsCommunicatorPlugin @Inject constructor(
"STATUS" -> {
val reply = if (loop.enabled) {
if (loop.isSuspended) String.format(rh.gs(R.string.loopsuspendedfor), loop.minutesToEndOfSuspend())
if (loop.isSuspended) rh.gs(R.string.loopsuspendedfor, loop.minutesToEndOfSuspend())
else rh.gs(R.string.smscommunicator_loopisenabled)
} else
rh.gs(R.string.loopisdisabled)
@ -399,7 +399,7 @@ class SmsCommunicatorPlugin @Inject constructor(
"RESUME" -> {
val passCode = generatePassCode()
val reply = String.format(rh.gs(R.string.smscommunicator_loopresumereplywithcode), passCode)
val reply = rh.gs(R.string.smscommunicator_loopresumereplywithcode, passCode)
receivedSms.processed = true
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction(pumpCommand = true) {
override fun run() {
@ -436,7 +436,7 @@ class SmsCommunicatorPlugin @Inject constructor(
return
} else {
val passCode = generatePassCode()
val reply = String.format(rh.gs(R.string.smscommunicator_suspendreplywithcode), duration, passCode)
val reply = rh.gs(R.string.smscommunicator_suspendreplywithcode, duration, passCode)
receivedSms.processed = true
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction(pumpCommand = true, duration) {
override fun run() {
@ -515,7 +515,7 @@ class SmsCommunicatorPlugin @Inject constructor(
receivedSms.processed = true
} else if ((divided.size == 2) && (divided[1].equals("CONNECT", ignoreCase = true))) {
val passCode = generatePassCode()
val reply = String.format(rh.gs(R.string.smscommunicator_pumpconnectwithcode), passCode)
val reply = rh.gs(R.string.smscommunicator_pumpconnectwithcode, passCode)
receivedSms.processed = true
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction(pumpCommand = true) {
override fun run() {
@ -548,7 +548,7 @@ class SmsCommunicatorPlugin @Inject constructor(
return
} else {
val passCode = generatePassCode()
val reply = String.format(rh.gs(R.string.smscommunicator_pumpdisconnectwithcode), duration, passCode)
val reply = rh.gs(R.string.smscommunicator_pumpdisconnectwithcode, duration, passCode)
receivedSms.processed = true
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction(pumpCommand = true) {
override fun run() {
@ -601,7 +601,7 @@ class SmsCommunicatorPlugin @Inject constructor(
if (profile == null) sendSMS(Sms(receivedSms.phoneNumber, rh.gs(R.string.noprofile)))
else {
val passCode = generatePassCode()
val reply = String.format(rh.gs(R.string.smscommunicator_profilereplywithcode), list[pIndex - 1], percentage, passCode)
val reply = rh.gs(R.string.smscommunicator_profilereplywithcode, list[pIndex - 1], percentage, passCode)
receivedSms.processed = true
val finalPercentage = percentage
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction(pumpCommand = true, list[pIndex - 1] as String, finalPercentage) {
@ -627,7 +627,7 @@ class SmsCommunicatorPlugin @Inject constructor(
private fun processBASAL(divided: Array<String>, receivedSms: Sms) {
if (divided[1].uppercase(Locale.getDefault()) == "CANCEL" || divided[1].uppercase(Locale.getDefault()) == "STOP") {
val passCode = generatePassCode()
val reply = String.format(rh.gs(R.string.smscommunicator_basalstopreplywithcode), passCode)
val reply = rh.gs(R.string.smscommunicator_basalstopreplywithcode, passCode)
receivedSms.processed = true
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction(pumpCommand = true) {
override fun run() {
@ -662,14 +662,14 @@ class SmsCommunicatorPlugin @Inject constructor(
else {
tempBasalPct = constraintChecker.applyBasalPercentConstraints(Constraint(tempBasalPct), profile).value()
val passCode = generatePassCode()
val reply = String.format(rh.gs(R.string.smscommunicator_basalpctreplywithcode), tempBasalPct, duration, passCode)
val reply = rh.gs(R.string.smscommunicator_basalpctreplywithcode, tempBasalPct, duration, passCode)
receivedSms.processed = true
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction(pumpCommand = true, tempBasalPct, duration) {
override fun run() {
commandQueue.tempBasalPercent(anInteger(), secondInteger(), true, profile, PumpSync.TemporaryBasalType.NORMAL, object : Callback() {
override fun run() {
if (result.success) {
var replyText = if (result.isPercent) String.format(rh.gs(R.string.smscommunicator_tempbasalset_percent), result.percent, result.duration) else String.format(rh.gs(R.string.smscommunicator_tempbasalset), result.absolute, result.duration)
var replyText = if (result.isPercent) rh.gs(R.string.smscommunicator_tempbasalset_percent, result.percent, result.duration) else rh.gs(R.string.smscommunicator_tempbasalset, result.absolute, result.duration)
replyText += "\n" + activePlugin.activePump.shortStatus(true)
sendSMSToAllNumbers(Sms(receivedSms.phoneNumber, replyText))
if (result.isPercent)
@ -706,15 +706,15 @@ class SmsCommunicatorPlugin @Inject constructor(
else {
tempBasal = constraintChecker.applyBasalConstraints(Constraint(tempBasal), profile).value()
val passCode = generatePassCode()
val reply = String.format(rh.gs(R.string.smscommunicator_basalreplywithcode), tempBasal, duration, passCode)
val reply = rh.gs(R.string.smscommunicator_basalreplywithcode, tempBasal, duration, passCode)
receivedSms.processed = true
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction(pumpCommand = true, tempBasal, duration) {
override fun run() {
commandQueue.tempBasalAbsolute(aDouble(), secondInteger(), true, profile, PumpSync.TemporaryBasalType.NORMAL, object : Callback() {
override fun run() {
if (result.success) {
var replyText = if (result.isPercent) String.format(rh.gs(R.string.smscommunicator_tempbasalset_percent), result.percent, result.duration)
else String.format(rh.gs(R.string.smscommunicator_tempbasalset), result.absolute, result.duration)
var replyText = if (result.isPercent) rh.gs(R.string.smscommunicator_tempbasalset_percent, result.percent, result.duration)
else rh.gs(R.string.smscommunicator_tempbasalset, result.absolute, result.duration)
replyText += "\n" + activePlugin.activePump.shortStatus(true)
sendSMSToAllNumbers(Sms(receivedSms.phoneNumber, replyText))
if (result.isPercent)
@ -743,7 +743,7 @@ class SmsCommunicatorPlugin @Inject constructor(
private fun processEXTENDED(divided: Array<String>, receivedSms: Sms) {
if (divided[1].uppercase(Locale.getDefault()) == "CANCEL" || divided[1].uppercase(Locale.getDefault()) == "STOP") {
val passCode = generatePassCode()
val reply = String.format(rh.gs(R.string.smscommunicator_extendedstopreplywithcode), passCode)
val reply = rh.gs(R.string.smscommunicator_extendedstopreplywithcode, passCode)
receivedSms.processed = true
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction(pumpCommand = true) {
override fun run() {
@ -773,14 +773,14 @@ class SmsCommunicatorPlugin @Inject constructor(
if (extended == 0.0 || duration == 0) sendSMS(Sms(receivedSms.phoneNumber, rh.gs(R.string.wrongformat)))
else {
val passCode = generatePassCode()
val reply = String.format(rh.gs(R.string.smscommunicator_extendedreplywithcode), extended, duration, passCode)
val reply = rh.gs(R.string.smscommunicator_extendedreplywithcode, extended, duration, passCode)
receivedSms.processed = true
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction(pumpCommand = true, extended, duration) {
override fun run() {
commandQueue.extendedBolus(aDouble(), secondInteger(), object : Callback() {
override fun run() {
if (result.success) {
var replyText = String.format(rh.gs(R.string.smscommunicator_extendedset), aDouble, duration)
var replyText = rh.gs(R.string.smscommunicator_extendedset, aDouble, duration)
if (config.APS) replyText += "\n" + rh.gs(R.string.loopsuspended)
replyText += "\n" + activePlugin.activePump.shortStatus(true)
sendSMSToAllNumbers(Sms(receivedSms.phoneNumber, replyText))
@ -817,9 +817,9 @@ class SmsCommunicatorPlugin @Inject constructor(
} else if (bolus > 0.0) {
val passCode = generatePassCode()
val reply = if (isMeal)
String.format(rh.gs(R.string.smscommunicator_mealbolusreplywithcode), bolus, passCode)
rh.gs(R.string.smscommunicator_mealbolusreplywithcode, bolus, passCode)
else
String.format(rh.gs(R.string.smscommunicator_bolusreplywithcode), bolus, passCode)
rh.gs(R.string.smscommunicator_bolusreplywithcode, bolus, passCode)
receivedSms.processed = true
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction(pumpCommand = true, bolus) {
override fun run() {
@ -833,9 +833,9 @@ class SmsCommunicatorPlugin @Inject constructor(
override fun run() {
if (resultSuccess) {
var replyText = if (isMeal)
String.format(rh.gs(R.string.smscommunicator_mealbolusdelivered), resultBolusDelivered)
rh.gs(R.string.smscommunicator_mealbolusdelivered, resultBolusDelivered)
else
String.format(rh.gs(R.string.smscommunicator_bolusdelivered), resultBolusDelivered)
rh.gs(R.string.smscommunicator_bolusdelivered, resultBolusDelivered)
replyText += "\n" + activePlugin.activePump.shortStatus(true)
lastRemoteBolusTime = dateUtil.now()
if (isMeal) {
@ -866,7 +866,7 @@ class SmsCommunicatorPlugin @Inject constructor(
val tt = if (currentProfile.units == GlucoseUnit.MMOL) {
DecimalFormatter.to1Decimal(eatingSoonTT)
} else DecimalFormatter.to0Decimal(eatingSoonTT)
replyText += "\n" + String.format(rh.gs(R.string.smscommunicator_mealbolusdelivered_tt), tt, eatingSoonTTDuration)
replyText += "\n" + rh.gs(R.string.smscommunicator_mealbolusdelivered_tt, tt, eatingSoonTTDuration)
}
}
sendSMSToAllNumbers(Sms(receivedSms.phoneNumber, replyText))
@ -920,7 +920,7 @@ class SmsCommunicatorPlugin @Inject constructor(
if (grams == 0) sendSMS(Sms(receivedSms.phoneNumber, rh.gs(R.string.wrongformat)))
else {
val passCode = generatePassCode()
val reply = String.format(rh.gs(R.string.smscommunicator_carbsreplywithcode), grams, dateUtil.timeString(time), passCode)
val reply = rh.gs(R.string.smscommunicator_carbsreplywithcode, grams, dateUtil.timeString(time), passCode)
receivedSms.processed = true
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction(pumpCommand = true, grams, time) {
override fun run() {
@ -930,7 +930,7 @@ class SmsCommunicatorPlugin @Inject constructor(
commandQueue.bolus(detailedBolusInfo, object : Callback() {
override fun run() {
if (result.success) {
var replyText = String.format(rh.gs(R.string.smscommunicator_carbsset), anInteger)
var replyText = rh.gs(R.string.smscommunicator_carbsset, anInteger)
replyText += "\n" + activePlugin.activePump.shortStatus(true)
sendSMSToAllNumbers(Sms(receivedSms.phoneNumber, replyText))
uel.log(Action.CARBS, Sources.SMS, activePlugin.activePump.shortStatus(true) + ": " + rh.gs(R.string.smscommunicator_carbsset, anInteger),
@ -956,7 +956,7 @@ class SmsCommunicatorPlugin @Inject constructor(
val isStop = divided[1].equals("STOP", ignoreCase = true) || divided[1].equals("CANCEL", ignoreCase = true)
if (isMeal || isActivity || isHypo) {
val passCode = generatePassCode()
val reply = String.format(rh.gs(R.string.smscommunicator_temptargetwithcode), divided[1].uppercase(Locale.getDefault()), passCode)
val reply = rh.gs(R.string.smscommunicator_temptargetwithcode, divided[1].uppercase(Locale.getDefault()), passCode)
receivedSms.processed = true
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction(pumpCommand = false) {
override fun run() {
@ -1009,7 +1009,7 @@ class SmsCommunicatorPlugin @Inject constructor(
aapsLogger.error(LTag.DATABASE, "Error while saving temporary target", it)
})
val ttString = if (units == GlucoseUnit.MMOL) DecimalFormatter.to1Decimal(tt) else DecimalFormatter.to0Decimal(tt)
val replyText = String.format(rh.gs(R.string.smscommunicator_tt_set), ttString, ttDuration)
val replyText = rh.gs(R.string.smscommunicator_tt_set, ttString, ttDuration)
sendSMSToAllNumbers(Sms(receivedSms.phoneNumber, replyText))
uel.log(Action.TT, Sources.SMS,
ValueWithUnit.fromGlucoseUnit(tt, units.asText),
@ -1018,7 +1018,7 @@ class SmsCommunicatorPlugin @Inject constructor(
})
} else if (isStop) {
val passCode = generatePassCode()
val reply = String.format(rh.gs(R.string.smscommunicator_temptargetcancel), passCode)
val reply = rh.gs(R.string.smscommunicator_temptargetcancel, passCode)
receivedSms.processed = true
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction(pumpCommand = false) {
override fun run() {
@ -1028,7 +1028,7 @@ class SmsCommunicatorPlugin @Inject constructor(
}, {
aapsLogger.error(LTag.DATABASE, "Error while saving temporary target", it)
})
val replyText = String.format(rh.gs(R.string.smscommunicator_tt_canceled))
val replyText = rh.gs(R.string.smscommunicator_tt_canceled)
sendSMSToAllNumbers(Sms(receivedSms.phoneNumber, replyText))
uel.log(Action.CANCEL_TT, Sources.SMS, rh.gs(R.string.smscommunicator_tt_canceled),
ValueWithUnit.SimpleString(rh.gsNotLocalised(R.string.smscommunicator_tt_canceled)))
@ -1043,12 +1043,12 @@ class SmsCommunicatorPlugin @Inject constructor(
|| divided[1].equals("DISABLE", ignoreCase = true))
if (isStop) {
val passCode = generatePassCode()
val reply = String.format(rh.gs(R.string.smscommunicator_stopsmswithcode), passCode)
val reply = rh.gs(R.string.smscommunicator_stopsmswithcode, passCode)
receivedSms.processed = true
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction(pumpCommand = false) {
override fun run() {
sp.putBoolean(R.string.key_smscommunicator_remotecommandsallowed, false)
val replyText = String.format(rh.gs(R.string.smscommunicator_stoppedsms))
val replyText = rh.gs(R.string.smscommunicator_stoppedsms)
sendSMSToAllNumbers(Sms(receivedSms.phoneNumber, replyText))
uel.log(Action.STOP_SMS, Sources.SMS, rh.gs(R.string.smscommunicator_stoppedsms),
ValueWithUnit.SimpleString(rh.gsNotLocalised(R.string.smscommunicator_stoppedsms)))
@ -1061,7 +1061,7 @@ class SmsCommunicatorPlugin @Inject constructor(
val cal = SafeParse.stringToDouble(divided[1])
if (cal > 0.0) {
val passCode = generatePassCode()
val reply = String.format(rh.gs(R.string.smscommunicator_calibrationreplywithcode), cal, passCode)
val reply = rh.gs(R.string.smscommunicator_calibrationreplywithcode, cal, passCode)
receivedSms.processed = true
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction(pumpCommand = false, cal) {
override fun run() {
@ -1127,7 +1127,7 @@ class SmsCommunicatorPlugin @Inject constructor(
}
private fun generatePassCode(): String =
String.format(rh.gs(R.string.smscommunicator_code_from_authenticator_for), otp.name())
rh.gs(R.string.smscommunicator_code_from_authenticator_for, otp.name())
private fun stripAccents(str: String): String {
var s = str

View file

@ -111,7 +111,7 @@ class ActionStringHandler @Inject constructor(
@Synchronized
private fun handleInitiate(actionString: String) {
//TODO: i18n
Log.i("ActionStringHandler", "handleInitiate actionString=" + actionString)
Log.i("ActionStringHandler", "handleInitiate actionString=$actionString")
if (!sp.getBoolean(R.string.key_wear_control, false)) return
lastBolusWizard = null
var rTitle = rh.gs(R.string.confirm).uppercase()
@ -640,10 +640,10 @@ class ActionStringHandler @Inject constructor(
var msg = ""
//check for validity
if (percentage < Constants.CPP_MIN_PERCENTAGE || percentage > Constants.CPP_MAX_PERCENTAGE) {
msg += String.format(rh.gs(R.string.valueoutofrange), "Profile-Percentage") + "\n"
msg += rh.gs(R.string.valueoutofrange, "Profile-Percentage") + "\n"
}
if (timeshift < 0 || timeshift > 23) {
msg += String.format(rh.gs(R.string.valueoutofrange), "Profile-Timeshift") + "\n"
msg += rh.gs(R.string.valueoutofrange, "Profile-Timeshift") + "\n"
}
val profile = profileFunction.getProfile()
if (profile == null) {

View file

@ -95,7 +95,7 @@ class WearPlugin @Inject constructor(
.toObservable(EventBolusRequested::class.java)
.observeOn(aapsSchedulers.io)
.subscribe({ event: EventBolusRequested ->
val status = String.format(rh.gs(R.string.bolusrequested), event.amount)
val status = rh.gs(R.string.bolusrequested, event.amount)
val intent = Intent(ctx, WatchUpdaterService::class.java).setAction(WatchUpdaterService.ACTION_SEND_BOLUSPROGRESS)
intent.putExtra("progresspercent", 0)
intent.putExtra("progressstatus", status)

View file

@ -29,6 +29,7 @@ import info.nightscout.androidaps.utils.DecimalFormatter
import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.HardLimits
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
import info.nightscout.androidaps.utils.protection.ProtectionCheck
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.rx.AapsSchedulers
import info.nightscout.androidaps.utils.ui.TimeListEdit
@ -49,6 +50,7 @@ class LocalProfileFragment : DaggerFragment() {
@Inject lateinit var fabricPrivacy: FabricPrivacy
@Inject lateinit var localProfilePlugin: LocalProfilePlugin
@Inject lateinit var hardLimits: HardLimits
@Inject lateinit var protectionCheck: ProtectionCheck
@Inject lateinit var dateUtil: DateUtil
@Inject lateinit var aapsSchedulers: AapsSchedulers
@Inject lateinit var uel: UserEntryLogger
@ -88,8 +90,7 @@ class LocalProfileFragment : DaggerFragment() {
private var _binding: LocalprofileFragmentBinding? = null
// This property is only valid between onCreateView and
// onDestroyView.
// This property is only valid between onCreateView and onDestroyView.
private val binding get() = _binding!!
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
@ -124,6 +125,23 @@ class LocalProfileFragment : DaggerFragment() {
binding.target.visibility = View.VISIBLE
}
binding.dia.editText?.id?.let { binding.diaLabel.labelFor = it }
if (protectionCheck.isLocked(ProtectionCheck.Protection.PREFERENCES)) {
binding.mainLayout.visibility = View.GONE
} else {
binding.unlock.visibility = View.GONE
}
binding.unlock.setOnClickListener {
activity?.let { activity ->
protectionCheck.queryProtection(activity, ProtectionCheck.Protection.PREFERENCES, {
activity.runOnUiThread {
binding.mainLayout.visibility = View.VISIBLE
binding.unlock.visibility = View.GONE
}
})
}
}
}
fun build() {

View file

@ -113,7 +113,7 @@ class AndroidPermission @Inject constructor(
@Synchronized
fun notifyForBatteryOptimizationPermission(activity: FragmentActivity) {
if (permissionNotGranted(activity, Manifest.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS)) {
val notification = NotificationWithAction(injector, Notification.PERMISSION_BATTERY, String.format(rh.gs(R.string.needwhitelisting), rh.gs(R.string.app_name)), Notification.URGENT)
val notification = NotificationWithAction(injector, Notification.PERMISSION_BATTERY, rh.gs(R.string.needwhitelisting, rh.gs(R.string.app_name)), Notification.URGENT)
notification.action(R.string.request) { askForPermission(activity, arrayOf(Manifest.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS)) }
rxBus.send(EventNewNotification(notification))
} else rxBus.send(EventDismissNotification(Notification.PERMISSION_BATTERY))

View file

@ -242,77 +242,67 @@
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center|center_vertical"
android:layout_marginTop="10dp"
android:background="@android:color/transparent"
android:orientation="horizontal"
android:padding="0dp">
android:layout_width="match_parent"
android:layout_height="45dp"
android:paddingHorizontal="10dp">
<CheckBox
<ToggleButton
android:id="@+id/bg_checkbox_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="15dp"
android:layout_marginRight="15dp"
android:button="@android:color/transparent"
style="?android:attr/borderlessButtonStyle"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:checked="true"
android:contentDescription="@string/treatments_wizard_bg_label"
android:drawableStart="@drawable/checkbox_bg_icon"
android:drawableTop="@drawable/checkbox_bg_icon"
android:scaleX="1.4"
android:scaleY="1.4" />
<CheckBox
<ToggleButton
android:id="@+id/tt_checkbox_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="15dp"
android:layout_marginRight="15dp"
android:button="@android:color/transparent"
style="?android:attr/borderlessButtonStyle"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:checked="true"
android:contentDescription="@string/treatments_wizard_tt_label"
android:drawableStart="@drawable/checkbox_tt_icon"
android:drawableTop="@drawable/checkbox_tt_icon"
android:scaleX="1.6"
android:scaleY="1.6"
android:visibility="gone" />
android:scaleY="1.6" />
<CheckBox
<ToggleButton
android:id="@+id/trend_checkbox_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="15dp"
android:layout_marginRight="15dp"
android:button="@android:color/transparent"
style="?android:attr/borderlessButtonStyle"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:checked="true"
android:contentDescription="@string/bg_trend_label"
android:drawableStart="@drawable/checkbox_trend_icon"
android:drawableTop="@drawable/checkbox_trend_icon"
android:scaleX="1.4"
android:scaleY="1.4" />
<CheckBox
<ToggleButton
android:id="@+id/iob_checkbox_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="15dp"
android:layout_marginRight="15dp"
android:button="@android:color/transparent"
style="?android:attr/borderlessButtonStyle"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:checked="true"
android:contentDescription="@string/iob"
android:drawableStart="@drawable/checkbox_iob_icon"
android:drawableTop="@drawable/checkbox_iob_icon"
android:scaleX="1.4"
android:scaleY="1.4" />
<CheckBox
<ToggleButton
android:id="@+id/cob_checkbox_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="15dp"
android:layout_marginRight="15dp"
android:button="@android:color/transparent"
style="?android:attr/borderlessButtonStyle"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:checked="true"
android:contentDescription="@string/treatments_wizard_cob_label"
android:drawableStart="@drawable/checkbox_cob_icon"
android:drawableTop="@drawable/checkbox_cob_icon"
android:scaleX="1.6"
android:scaleY="1.6" />

View file

@ -10,6 +10,20 @@
android:layout_height="wrap_content"
android:orientation="vertical">
<com.google.android.material.button.MaterialButton
android:id="@+id/unlock"
style="@style/GrayButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="@string/unlock_settings" />
<LinearLayout
android:id="@+id/main_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<com.google.android.material.textfield.TextInputLayout
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox.ExposedDropdownMenu"
android:layout_width="match_parent"
@ -361,6 +375,8 @@
</LinearLayout>
</LinearLayout>
</ScrollView>

View file

@ -5,7 +5,16 @@
android:paddingTop="2dp"
tools:context=".plugins.general.maintenance.MaintenanceFragment">
<com.google.android.material.button.MaterialButton
android:id="@+id/unlock"
style="@style/GrayButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="@string/unlock_settings" />
<LinearLayout
android:id="@+id/main_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">

View file

@ -7,7 +7,7 @@
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_margin="1dp"
card_view:cardBackgroundColor="@color/cardColorBackground"
card_view:cardBackgroundColor="@color/notificationUrgent"
card_view:cardCornerRadius="6dp">
<LinearLayout
@ -22,7 +22,9 @@
android:layout_height="wrap_content"
android:layout_marginStart="5dp"
android:layout_weight="1"
android:textColor="?attr/colorOnError"
android:maxLines="4"
android:textStyle="bold"
android:text="Notification text. Notification text. Notification text. Notification text. Notification text. Notification text. "
tools:ignore="HardcodedText" />

View file

@ -267,6 +267,7 @@
<string name="configbuilder_shortname">KONF</string>
<string name="loop_shortname">OKRUH</string>
<string name="oaps_shortname">OAPS</string>
<string name="dynisf_shortname">DYNISF</string>
<string name="localprofile_shortname">LPRF</string>
<string name="overview_shortname">PREH</string>
<string name="virtualpump_shortname">VPUM</string>
@ -432,6 +433,7 @@
<string name="ns_localbroadcasts">Povoliť vysielanie do iných aplikácií (napr. xDrip+). Nepovoľujte, pokiaľ máte nainštalovanú viac ako jednu AAPS, alebo NSClient inštanciu!</string>
<string name="ns_localbroadcasts_title">Povoliť lokálne vysielanie.</string>
<string name="openapssmb">OpenAPS SMB</string>
<string name="openaps_smb_dynamic_isf">Dynamická ISF</string>
<string name="enableuam">Povoliť UAM</string>
<string name="enablesmb">Povoliť SMB</string>
<string name="enablesmb_summary">Použiť Super Mikro Bolusy namiesto dočasných bazálov, pre zrýchleniu účinku</string>
@ -661,6 +663,9 @@
<string name="sensitivity_raises_target_title">Citlivosť zvyšuje cieľ</string>
<string name="sensitivity_raises_target_summary">Ak je zistená vyššia citlivosť, zvýši cieľovú hladinu glykémie</string>
<string name="careportal_removestartedevents">Vymazať udalosti \"AndroidAPS reštartovaný\"</string>
<string name="show_invalidated">Zobraziť neplatné</string>
<string name="hide_invalidated">Skryť zneplatnené</string>
<string name="remove_items">Odstrániť položky</string>
<string name="storedsettingsfound">Nájdené uložené nastavenia</string>
<string name="allow_hardware_pump_text">POZOR: Pokiaľ aktivujete a pripojíte skutočnú pumpu, AndroidAPS nakopíruje (a bude udržiavať) nastavenie bazálu z aktívneho profilu do pumpy. Nastavenie bazálu v pumpe bude prepísané. Pokiaľ si nieste istí, alebo nechcete prepísať bazály v pumpe, stlačte Zrušiť a opakujte prepnutie na inú pumpu neskôr.</string>
<string name="error_adding_treatment_title">Dáta ošetrení neúplné</string>
@ -877,6 +882,8 @@
<string name="ns_receive_profile_switch_summary">Prijať prepnutia profilov zadané prostredníctvom NS, alebo NSClienta</string>
<string name="ns_receive_offline_event">Prijímať udalosti APS offline</string>
<string name="ns_receive_offline_event_summary">Prijať APS offline udalosti zadané prostredníctvom NS, alebo NSClienta</string>
<string name="ns_receive_tbr_eb">Prijímať dočasný bazál a predĺžený bolus</string>
<string name="ns_receive_tbr_eb_summary">Prijať dočasný bazál a predĺžený bolus zadaný cez inú inštanciu</string>
<string name="ns_receive_insulin">Prijímať inzulín</string>
<string name="ns_receive_insulin_summary">Prijať inzulín vložený cez NS, alebo NSClient (nie je dodaný, iba započítaný do IOB)</string>
<string name="ns_receive_carbs">Prijímať sacharidy</string>
@ -969,4 +976,15 @@
<string name="wear_unknown_action_string">Neznámy príkaz k akcii:</string>
<string name="overview_editquickwizard_percentage">Percentuálny podiel</string>
<string name="app_default">Predvolené aplikáciou</string>
<string name="select_profile">Vyberte profil pre úpravu</string>
<string name="refresh_from_nightscout">Obnoviť z Nightscoutu</string>
<string name="remove_selected_items">Odstrániť vybrané položky</string>
<string name="select_for_removal">Vyberte pre odstránenie</string>
<string name="profile_changes">Zmeny profilu</string>
<string name="tempt_targets">Dočasné ciele</string>
<string name="carbs_and_bolus">Sacharidy a bolusy</string>
<string name="confirm_remove_multiple_items">Naozaj chcete odstrániť %1$d položku(y)</string>
<string name="hide_loop">Skryť uzavretý okruh</string>
<string name="show_loop">Zobraziť uzavretý okruh</string>
<string name="count_selected">Vybrané: %1$d</string>
</resources>

View file

@ -60,10 +60,10 @@
<string name="exercise_15g">等血糖值低于你的低血糖警戒线之后吃15克速升的活性碳水合物。</string>
<string name="exercise_hint1">https://androidaps.readthedocs.io/en/latest/EN/Usage/temptarget.html#activity-temp-target</string>
<string name="suspendloop_label">禁用/暂停闭环</string>
<string name="suspendloop_doigetinsulin">在禁用/暂停闭环时,是否可以输注胰岛素?</string>
<string name="suspendloop_yes">是的,胰岛素基础率可以正常输注的</string>
<string name="suspendloop_doigetinsulin">在禁用/暂停闭环时,我是否接收了胰岛素输注?</string>
<string name="suspendloop_yes">是的,胰岛素基础率仍在继续输注</string>
<string name="suspendloop_no">不,胰岛素停止输注。</string>
<string name="basaltest_label">Basal(基础率)ISF(胰岛素敏感系数)和I:C(胰岛素:碳水)测试</string>
<string name="basaltest_label">Basal基础率ISF胰岛素敏感系数I:C或ICR碳水化合物系数的测试</string>
<string name="basaltest_when">什么时候需要修订这些值?</string>
<string name="basaltest_beforeloop">在开始闭环之前。</string>
<string name="basaltest_havingregularhighlow">当经常出现高血糖或低血糖时。</string>
@ -84,7 +84,7 @@
<string name="prerequisites_own670g">一台 MiniMed 670G 泵。</string>
<string name="prerequisites_hint1">https://androidaps.readthedocs.io/en/latest/EN/Module/module.html</string>
<string name="prerequisites_smartwatch">一个智能手表.</string>
<string name="prerequisites_supportedcgm">一个可正常使用的 CGM。</string>
<string name="prerequisites_supportedcgm">受支持的CGM血糖监测产品</string>
<string name="prerequisites2_label">先决条件</string>
<string name="prerequisites2_what">什么是建立和使用 AndroidAPS的基本条件</string>
<string name="prerequisites2_profile">验证参数信息用于个人配置文件如ISF胰岛素敏感度系数、I:C胰岛素碳水比率、基础率、DIA胰岛素作用持续时间等等</string>
@ -93,9 +93,9 @@
<string name="prerequisites2_supportedcgm">一台安装了动态血糖监测应用或兼容软件的手机/设备,用于接收血糖数据。</string>
<string name="prerequisites2_hint1">https://androidaps.readthedocs.io/en/latest/EN/Module/module.html</string>
<string name="update_label">更新 AndroidAPS</string>
<string name="whatistrue">检查所有正确的答案.</string>
<string name="whatistrue">选择所有正确的答案.</string>
<string name="update_git">您需要在您的计算机上安装和配置Git。</string>
<string name="update_asap">更新的 AndroidAPS 版本发布时,先前的版本可能会在指定时间之后受到远程限制。</string>
<string name="update_asap">AndroidAPS更新发布正式版本时,先前的版本可能会在指定时间之后受到远程限制。</string>
<string name="update_keys">您应该保存并记住密钥的存储位置,并使用相同地签名密钥进行更新,与您以前的安装一样。</string>
<string name="update_neverupdate">如果该系统运作良好,就不要去更新系统。</string>
<string name="update_askfriend">如果您在构建应用时遇到困难,您可以安装一个由朋友构建的应用程序。</string>
@ -119,7 +119,7 @@
<string name="sensitivity_label">敏感度插件</string>
<string name="sensitivity_which">选择所有正确的答案。</string>
<string name="sensitivity_adjust">灵敏度插件允许AndroidAPS临时调整胰岛素敏感度的短暂变化(例如激素变化或与输液部位吸收相关的问题)。</string>
<string name="sensitivity_edit">灵敏度插件为用户提供基础率、 I:C比率和 ISF 的更改建议,可用来编辑配置文件。</string>
<string name="sensitivity_edit">灵敏度插件为用户提供basal基础率I:C碳水化合物系数和ISF胰岛素敏感系数的更改建议,可用来编辑配置文件。</string>
<string name="sensitivity_cannula">记录输注导管更换会将Autosens比率重置回100%。</string>
<string name="sensitivity_time">一些插件选项具有可配置的时间范围,可由用户设置。</string>
<string name="sensitivity_hint1">https://androidaps.readthedocs.io/en/latest/EN/Configuration/Sensitivity-detection-and-COB.html</string>
@ -195,13 +195,13 @@
<string name="profileswitchtime_iwant">如果您比平常早起 2 个小时您应该如何通知AndroidAPS应对个人日程表中的更改?</string>
<string name="profileswitchtime_2">以增加2小时的方式启动个人配置文件切换</string>
<string name="profileswitchtime__2">以减少2小时的方式启动个人配置文件切换</string>
<string name="profileswitchtime_tt">设置一个马上吃饭的临时的目标血糖值。</string>
<string name="profileswitchtime_tt">设置一个马上吃饭,临时的血糖目标值。</string>
<string name="profileswitchtime_100">将配置文件切换到100%以上。</string>
<string name="profileswitchtime_hint1">https://androidaps.readthedocs.io/en/latest/EN/Usage/Profiles.html?highlight=profilewitch#timeshift</string>
<string name="profileswitch4_label">修改配置文件</string>
<string name="profileswitch4_rates">基础率、胰岛素敏感系数ISF、胰岛素和碳水比率I:C等在配置文件中设定。</string>
<string name="profileswitch4_rates">Basal基础率ISF胰岛素敏感系数I:C碳水化合物系数等应该在配置文件中设定。</string>
<string name="profileswitch4_internet">激活对Nightscout配置文件的更改需要您的AndroidAPS 手机启用互联网连接。</string>
<string name="profileswitch4_sufficient">编辑配置文件并修改参数,足以进行任何更改</string>
<string name="profileswitch4_sufficient">编辑配置文件进行参数的修改,足以适应任何变化</string>
<string name="profileswitch4_multi">可以设置和选择多个配置文件,以适应不断变化的环境(例如激素变化、轮班工作、工作日/周末生活方式)。</string>
<string name="basalhelp_hint1">https://androidaps.readthedocs.io/en/latest/EN/Module/module.html#good-individual-dosage-algorithm-for-your-diabetes-therapy</string>
<string name="basalhelp_label">帮助调整基础率</string>

View file

@ -136,6 +136,7 @@
<item>@string/biometric</item>
<item>@string/master_password</item>
<item>@string/custom_password</item>
<item>@string/custom_pin</item>
</string-array>
<string-array name="protectiontypeValues">
@ -143,6 +144,7 @@
<item>1</item>
<item>2</item>
<item>3</item>
<item>4</item>
</string-array>
</resources>

View file

@ -40,11 +40,6 @@
<color name="colorScheduled">#de7550</color>
<color name="colorActive">#25912e</color>
<color name="notificationUrgent">#ff0400</color>
<color name="notificationNormal">#ff5e55</color>
<color name="notificationLow">#ff827c</color>
<color name="notificationInfo">#009705</color>
<color name="deviationgrey">#c8666666</color>
<color name="deviationgreen">#7200FF00</color>
<color name="deviationred">#72FF0000</color>

View file

@ -104,11 +104,11 @@
<string name="troubleshooting_wheretoask">Where can you look for help with AndroidAPS?</string>
<string name="troubleshooting_fb">You can ask for advice in the AndroidAPS Users Facebook group.</string>
<string name="troubleshooting_wiki">You should read (and re-read) the AndroidAPS documentation.</string>
<string name="troubleshooting_gitter">You can ask for advice and log technical problems or issues in the AndroidAPS Gitter room.</string>
<string name="troubleshooting_gitter">You can ask for advice and log technical problems or issues in the AndroidAPS Discord.</string>
<string name="troubleshooting_yourendo">You should ask your diabetes clinic/endocrinologist.</string>
<string name="troubleshooting_hint1">https://androidaps.readthedocs.io/en/latest/EN/Installing-AndroidAPS/Update-to-new-version.html#troubleshooting</string>
<string name="troubleshooting_hint2">https://www.facebook.com/groups/AndroidAPSUsers/</string>
<string name="troubleshooting_hint3">https://gitter.im/MilosKozak/AndroidAPS</string>
<string name="troubleshooting_hint3">https://discord.gg/4fQUWHZ4Mw</string>
<string name="insulin_label">Insulin Plugins</string>
<string name="insulin_ultrarapid">Which insulin should you use with the Ultra-Rapid Oref plugin?</string>
<string name="insulin_fiasp">Fiasp®</string>

View file

@ -46,10 +46,13 @@
android:title="@string/settings_protection" />
<Preference
android:inputType="textPassword"
android:key="@string/key_settings_password"
android:title="@string/settings_password" />
<Preference
android:key="@string/key_settings_pin"
android:title="@string/settings_pin" />
<ListPreference
android:defaultValue="0"
android:entries="@array/protectiontype"
@ -58,10 +61,13 @@
android:title="@string/application_protection" />
<Preference
android:inputType="textPassword"
android:key="@string/key_application_password"
android:title="@string/application_password" />
<Preference
android:key="@string/key_application_pin"
android:title="@string/application_pin" />
<ListPreference
android:defaultValue="0"
android:entries="@array/protectiontype"
@ -70,10 +76,13 @@
android:title="@string/bolus_protection" />
<Preference
android:inputType="textPassword"
android:key="@string/key_bolus_password"
android:title="@string/bolus_password" />
<Preference
android:key="@string/key_bolus_pin"
android:title="@string/bolus_pin" />
</PreferenceCategory>
<info.nightscout.androidaps.skins.SkinListPreference

View file

@ -1415,7 +1415,7 @@ public class ComboPlugin extends PumpPluginBase implements Pump, Constraints {
@NonNull @Override
public Constraint<Double> applyMaxIOBConstraints(@NonNull Constraint<Double> maxIob) {
if (lowSuspendOnlyLoopEnforcedUntil > System.currentTimeMillis())
maxIob.setIfSmaller(getAapsLogger(), 0d, String.format(getRh().gs(R.string.limitingmaxiob), 0d, getRh().gs(R.string.unsafeusage)), this);
maxIob.setIfSmaller(getAapsLogger(), 0d, getRh().gs(R.string.limitingmaxiob, 0d, getRh().gs(R.string.unsafeusage)), this);
return maxIob;
}

View file

@ -48,7 +48,7 @@
<string name="combo_check_date">O último bólus tem mais de 24 horas ou está no futuro. Por favor, verifique se a data está definida corretamente.</string>
<string name="combo_suspious_bolus_time">Hora/data da entrega do bólus na bomba parece errado, insulina ativa parece estar provavelmente incorreto. Verifique hora/data na bomba.</string>
<string name="combo_bolus_count">Contagem Bólus</string>
<string name="combo_tbr_count">Contagem Basal Teporária</string>
<string name="combo_tbr_count">Contagem Basal Temporária</string>
<string name="bolusstopped">Bolus interrompido</string>
<string name="bolusstopping">Interrompendo bolus</string>
<string name="pump_commerror_label">Contagem de erro comunicada</string>

View file

@ -51,4 +51,10 @@
<string name="combo_tbr_count">Počet dočasných bazálov</string>
<string name="bolusstopped">Bolus zastavený</string>
<string name="bolusstopping">Zastavenie bolusu</string>
<string name="pump_commerror_label">Počet chýb komun.</string>
<string name="show_comm_error_count_title">Zobr. počet chýb komun.</string>
<string name="show_comm_error_count_summary">Zobrazí počet chýb pri komunikácii s Ruffy. Číslo vyšše, ako 0 obvykle naznačuje problémy s Ruffy (môže byť nutné reštartovať).</string>
<string name="combo_error_display_never">Nikdy</string>
<string name="combo_error_display_error">Keď dôjde k chybe</string>
<string name="combo_error_display_always">Vždy</string>
</resources>

View file

@ -293,8 +293,8 @@ class ProfileViewerDialog : DaggerDialogFragment() {
val val1h = profile1.getTargetHighMgdlTimeFromMidnight(hour * 60 * 60)
val val2l = profile2.getTargetLowMgdlTimeFromMidnight(hour * 60 * 60)
val val2h = profile2.getTargetHighMgdlTimeFromMidnight(hour * 60 * 60)
val txt1 = dateUtil.format_HH_MM(hour * 60 * 60) + " " + Profile.toUnitsString(val1l, val1l * Constants.MGDL_TO_MMOLL, units) + " - " + Profile.toUnitsString(val1h, val1h * Constants.MGDL_TO_MMOLL, units) + " " + units
val txt2 = dateUtil.format_HH_MM(hour * 60 * 60) + " " + Profile.toUnitsString(val2l, val2l * Constants.MGDL_TO_MMOLL, units) + " - " + Profile.toUnitsString(val2h, val2h * Constants.MGDL_TO_MMOLL, units) + " " + units
val txt1 = dateUtil.format_HH_MM(hour * 60 * 60) + " " + Profile.toUnitsString(val1l, val1l * Constants.MGDL_TO_MMOLL, units) + " - " + Profile.toUnitsString(val1h, val1h * Constants.MGDL_TO_MMOLL, units) + " " + units.asText
val txt2 = dateUtil.format_HH_MM(hour * 60 * 60) + " " + Profile.toUnitsString(val2l, val2l * Constants.MGDL_TO_MMOLL, units) + " - " + Profile.toUnitsString(val2h, val2h * Constants.MGDL_TO_MMOLL, units) + " " + units.asText
if (val1l != prev1l || val1h != prev1h || val2l != prev2l || val2h != prev2h) {
s.append(formatColors(txt1, txt2))
s.append("<br>")

View file

@ -47,7 +47,7 @@ class EventPumpStatusChanged : EventStatus {
// status for startup wizard
override fun getStatus(rh: ResourceHelper): String {
return when (status) {
Status.CONNECTING -> String.format(rh.gs(R.string.connectingfor), secondsElapsed)
Status.CONNECTING -> rh.gs(R.string.connectingfor, secondsElapsed)
Status.HANDSHAKING -> rh.gs(R.string.handshaking)
Status.CONNECTED -> rh.gs(R.string.connected)
Status.PERFORMING -> performingAction

View file

@ -97,7 +97,7 @@ open class APSResult @Inject constructor(val injector: HasAndroidInjector) {
}
val carbsRequiredText: String
get() = String.format(rh.gs(R.string.carbsreq), carbsReq, carbsReqWithin)
get() = rh.gs(R.string.carbsreq, carbsReq, carbsReqWithin)
override fun toString(): String {
val pump = activePlugin.activePump

View file

@ -94,9 +94,9 @@ class HardLimits @Inject constructor(
if (newValue < lowLimit || newValue > highLimit) {
newValue = max(newValue, lowLimit)
newValue = min(newValue, highLimit)
var msg = String.format(rh.gs(R.string.valueoutofrange), rh.gs(valueName))
var msg = rh.gs(R.string.valueoutofrange, rh.gs(valueName))
msg += ".\n"
msg += String.format(rh.gs(R.string.valuelimitedto), value, newValue)
msg += rh.gs(R.string.valuelimitedto, value, newValue)
aapsLogger.error(msg)
disposable += repository.runTransaction(InsertTherapyEventAnnouncementTransaction(msg)).subscribe()
ToastUtils.showToastInUiThread(context, rxBus, msg, R.raw.error)

View file

@ -2,8 +2,12 @@ package info.nightscout.androidaps.utils.protection
import android.annotation.SuppressLint
import android.content.Context
import android.text.InputType
import android.view.LayoutInflater
import android.view.View
import android.view.WindowManager
import android.view.inputmethod.EditorInfo
import android.view.inputmethod.InputMethodManager
import android.widget.EditText
import android.widget.TextView
import androidx.annotation.StringRes
@ -33,13 +37,12 @@ class PasswordCheck @Inject constructor(
Asks for "managed" kind of password, checking if it is valid.
*/
@SuppressLint("InflateParams")
fun queryPassword(context: Context, @StringRes labelId: Int, @StringRes preference: Int, ok: ((String) -> Unit)?, cancel: (() -> Unit)? = null, fail: (() -> Unit)? = null) {
fun queryPassword(context: Context, @StringRes labelId: Int, @StringRes preference: Int, ok: ((String) -> Unit)?, cancel: (() -> Unit)? = null, fail: (() -> Unit)? = null, pinInput: Boolean = false) {
val password = sp.getString(preference, "")
if (password == "") {
ok?.invoke("")
return
}
val promptsView = LayoutInflater.from(context).inflate(R.layout.passwordprompt, null)
val alertDialogBuilder = AlertDialogHelper.Builder(context, R.style.DialogTheme)
alertDialogBuilder.setView(promptsView)
@ -48,40 +51,67 @@ class PasswordCheck @Inject constructor(
val userInput2 = promptsView.findViewById<View>(R.id.password_prompt_pass_confirm) as EditText
userInput2.visibility = View.GONE
if (pinInput) {
userInput.setHint(R.string.pin_hint)
userInput.inputType = InputType.TYPE_CLASS_NUMBER or InputType.TYPE_NUMBER_VARIATION_PASSWORD
}
val autoFillHintPasswordKind = context.getString(preference)
userInput.setAutofillHints(View.AUTOFILL_HINT_PASSWORD, "aaps_${autoFillHintPasswordKind}")
userInput.importantForAutofill = View.IMPORTANT_FOR_AUTOFILL_YES
fun validatePassword(): Boolean {
val enteredPassword = userInput.text.toString()
if (cryptoUtil.checkPassword(enteredPassword, password)) {
val im = context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
im.hideSoftInputFromWindow(userInput.windowToken, 0)
ok?.invoke(enteredPassword)
return true
}
val msg = if (pinInput) R.string.wrongpin else R.string.wrongpassword
ToastUtils.errorToast(context, context.getString(msg))
fail?.invoke()
return false
}
alertDialogBuilder
.setCancelable(false)
.setCustomTitle(AlertDialogHelper.buildCustomTitle(context, context.getString(labelId), R.drawable.ic_header_key))
.setPositiveButton(context.getString(R.string.ok)) { _, _ ->
val enteredPassword = userInput.text.toString()
if (cryptoUtil.checkPassword(enteredPassword, password)) ok?.invoke(enteredPassword)
else {
ToastUtils.errorToast(context, context.getString(R.string.wrongpassword))
fail?.invoke()
}
}
.setNegativeButton(context.getString(R.string.cancel)
) { dialog, _ ->
.setPositiveButton(context.getString(R.string.ok)) { _, _ -> validatePassword() }
.setNegativeButton(context.getString(R.string.cancel)) { dialog, _ ->
cancel?.invoke()
dialog.cancel()
}
alertDialogBuilder.create().show()
val alert = alertDialogBuilder.create().apply {
window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE)
show()
}
userInput.setOnEditorActionListener { _, actionId, _ ->
if (actionId == EditorInfo.IME_ACTION_DONE) {
if (validatePassword())
alert.dismiss()
true
} else {
false
}
}
}
@SuppressLint("InflateParams")
fun setPassword(context: Context, @StringRes labelId: Int, @StringRes preference: Int, ok: ((String) -> Unit)? = null, cancel: (() -> Unit)? = null, clear: (() -> Unit)? = null) {
fun setPassword(context: Context, @StringRes labelId: Int, @StringRes preference: Int, ok: ((String) -> Unit)? = null, cancel: (() -> Unit)? = null, clear: (() -> Unit)? = null, pinInput: Boolean = false) {
val promptsView = LayoutInflater.from(context).inflate(R.layout.passwordprompt, null)
val alertDialogBuilder = AlertDialogHelper.Builder(context, R.style.DialogTheme)
alertDialogBuilder.setView(promptsView)
val userInput = promptsView.findViewById<View>(R.id.password_prompt_pass) as EditText
val userInput2 = promptsView.findViewById<View>(R.id.password_prompt_pass_confirm) as EditText
if (pinInput) {
userInput.inputType = InputType.TYPE_CLASS_NUMBER or InputType.TYPE_NUMBER_VARIATION_PASSWORD
userInput2.inputType = InputType.TYPE_CLASS_NUMBER or InputType.TYPE_NUMBER_VARIATION_PASSWORD
userInput.setHint(R.string.pin_hint)
userInput2.setHint(R.string.pin_hint)
}
val autoFillHintPasswordKind = context.getString(preference)
userInput.setAutofillHints(AUTOFILL_HINT_NEW_PASSWORD, "aaps_${autoFillHintPasswordKind}")
userInput.importantForAutofill = View.IMPORTANT_FOR_AUTOFILL_YES
@ -93,18 +123,22 @@ class PasswordCheck @Inject constructor(
val enteredPassword = userInput.text.toString()
val enteredPassword2 = userInput2.text.toString()
if (enteredPassword != enteredPassword2) {
ToastUtils.errorToast(context, context.getString(R.string.passwords_dont_match))
val msg = if (pinInput) R.string.pin_dont_match else R.string.passwords_dont_match
ToastUtils.errorToast(context, context.getString(msg))
} else if (enteredPassword.isNotEmpty()) {
sp.putString(preference, cryptoUtil.hashPassword(enteredPassword))
ToastUtils.okToast(context, context.getString(R.string.password_set))
val msg = if (pinInput) R.string.pin_set else R.string.password_set
ToastUtils.okToast(context, context.getString(msg))
ok?.invoke(enteredPassword)
} else {
if (sp.contains(preference)) {
sp.remove(preference)
ToastUtils.graphicalToast(context, context.getString(R.string.password_cleared), R.drawable.ic_toast_delete_confirm)
val msg = if (pinInput) R.string.pin_cleared else R.string.password_cleared
ToastUtils.graphicalToast(context, context.getString(msg), R.drawable.ic_toast_delete_confirm)
clear?.invoke()
} else {
ToastUtils.warnToast(context, context.getString(R.string.password_not_changed))
val msg = if (pinInput) R.string.pin_not_changed else R.string.password_not_changed
ToastUtils.warnToast(context, context.getString(msg))
cancel?.invoke()
}
}
@ -112,7 +146,8 @@ class PasswordCheck @Inject constructor(
}
.setNegativeButton(context.getString(R.string.cancel)
) { dialog, _ ->
ToastUtils.infoToast(context, context.getString(R.string.password_not_changed))
val msg = if (pinInput) R.string.pin_not_changed else R.string.password_not_changed
ToastUtils.infoToast(context, context.getString(msg))
cancel?.invoke()
dialog.cancel()
}
@ -149,20 +184,35 @@ class PasswordCheck @Inject constructor(
userInput.setAutofillHints(View.AUTOFILL_HINT_PASSWORD, "aaps_${autoFillHintPasswordKind}")
userInput.importantForAutofill = View.IMPORTANT_FOR_AUTOFILL_YES
alertDialogBuilder
.setCancelable(false)
.setCustomTitle(AlertDialogHelper.buildCustomTitle(context, context.getString(labelId), R.drawable.ic_header_key))
.setPositiveButton(context.getString(R.string.ok)) { _, _ ->
fun validatePassword() {
val enteredPassword = userInput.text.toString()
ok?.invoke(enteredPassword)
}
alertDialogBuilder
.setCancelable(false)
.setCustomTitle(AlertDialogHelper.buildCustomTitle(context, context.getString(labelId), R.drawable.ic_header_key))
.setPositiveButton(context.getString(R.string.ok)) { _, _ -> validatePassword() }
.setNegativeButton(context.getString(R.string.cancel)
) { dialog, _ ->
cancel?.invoke()
dialog.cancel()
}
alertDialogBuilder.create().show()
val alert = alertDialogBuilder.create().apply {
window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE)
show()
}
userInput.setOnEditorActionListener { _, actionId, _ ->
if (actionId == EditorInfo.IME_ACTION_DONE) {
validatePassword()
alert.dismiss()
true
} else {
false
}
}
}
/**

View file

@ -22,7 +22,8 @@ class ProtectionCheck @Inject constructor(
NONE,
BIOMETRIC,
MASTER_PASSWORD,
CUSTOM_PASSWORD
CUSTOM_PASSWORD,
CUSTOM_PIN
}
private val passwordsResourceIDs = listOf(
@ -30,22 +31,33 @@ class ProtectionCheck @Inject constructor(
R.string.key_application_password,
R.string.key_bolus_password)
private val pinsResourceIDs = listOf(
R.string.key_settings_pin,
R.string.key_application_pin,
R.string.key_bolus_pin)
private val protectionTypeResourceIDs = listOf(
R.string.key_settings_protection,
R.string.key_application_protection,
R.string.key_bolus_protection)
private val titleResourceIDs = listOf(
private val titlePassResourceIDs = listOf(
R.string.settings_password,
R.string.application_password,
R.string.bolus_password)
private val titlePinResourceIDs = listOf(
R.string.settings_pin,
R.string.application_pin,
R.string.bolus_pin)
fun isLocked(protection: Protection): Boolean {
return when (ProtectionType.values()[sp.getInt(protectionTypeResourceIDs[protection.ordinal], ProtectionType.NONE.ordinal)]) {
ProtectionType.NONE -> false
ProtectionType.BIOMETRIC -> true
ProtectionType.MASTER_PASSWORD -> sp.getString(R.string.key_master_password, "") != ""
ProtectionType.CUSTOM_PASSWORD -> sp.getString(passwordsResourceIDs[protection.ordinal], "") != ""
ProtectionType.CUSTOM_PIN -> sp.getString(pinsResourceIDs[protection.ordinal], "") != ""
}
}
@ -55,11 +67,13 @@ class ProtectionCheck @Inject constructor(
ProtectionType.NONE ->
ok?.run()
ProtectionType.BIOMETRIC ->
BiometricCheck.biometricPrompt(activity, titleResourceIDs[protection.ordinal], ok, cancel, fail, passwordCheck)
BiometricCheck.biometricPrompt(activity, titlePassResourceIDs[protection.ordinal], ok, cancel, fail, passwordCheck)
ProtectionType.MASTER_PASSWORD ->
passwordCheck.queryPassword(activity, R.string.master_password, R.string.key_master_password, { ok?.run() }, { cancel?.run() }, { fail?.run() })
ProtectionType.CUSTOM_PASSWORD ->
passwordCheck.queryPassword(activity, titleResourceIDs[protection.ordinal], passwordsResourceIDs[protection.ordinal], { ok?.run() }, { cancel?.run() }, { fail?.run() })
passwordCheck.queryPassword(activity, titlePassResourceIDs[protection.ordinal], passwordsResourceIDs[protection.ordinal], { ok?.run() }, { cancel?.run() }, { fail?.run() })
ProtectionType.CUSTOM_PIN ->
passwordCheck.queryPassword(activity, titlePinResourceIDs[protection.ordinal], pinsResourceIDs[protection.ordinal], { ok?.run() }, { cancel?.run() }, { fail?.run() }, true)
}
}
}

View file

@ -1,5 +1,6 @@
package info.nightscout.androidaps.utils.resources
import android.content.Context
import android.content.res.AssetFileDescriptor
import android.graphics.Bitmap
import android.graphics.drawable.Drawable
@ -11,7 +12,7 @@ interface ResourceHelper {
fun gs(@StringRes id: Int, vararg args: Any?): String
fun gq(@PluralsRes id: Int, quantity: Int, vararg args: Any?): String
fun gsNotLocalised(@StringRes id: Int, vararg args: Any?): String
fun gc(@ColorRes id: Int): Int
@ColorInt fun gc(@ColorRes id: Int): Int
fun gd(@DrawableRes id: Int): Drawable?
fun gb(@BoolRes id :Int) : Boolean
fun gcs(@ColorRes id: Int): String
@ -23,4 +24,13 @@ interface ResourceHelper {
fun dpToPx(dp: Int): Int
fun dpToPx(dp: Float): Int
fun shortTextMode(): Boolean
/**
* Get Attribute Color based on theme style
*/
@ColorInt fun gac(@AttrRes attributeId: Int): Int
/**
* Get Attribute Color based on theme style for specified context
*/
@ColorInt fun gac(context: Context, @AttrRes attributeId: Int): Int
}

View file

@ -0,0 +1,13 @@
package info.nightscout.androidaps.utils.resources
import android.content.Context
import android.util.TypedValue
import androidx.annotation.AttrRes
import androidx.annotation.ColorInt
@ColorInt
fun Context.getThemeColor(@AttrRes attribute: Int) =
TypedValue().let {
theme.resolveAttribute(attribute, it, true)
it.data
}

View file

@ -9,6 +9,7 @@ import android.graphics.BitmapFactory
import android.graphics.drawable.Drawable
import android.util.DisplayMetrics
import androidx.annotation.*
import androidx.appcompat.view.ContextThemeWrapper
import androidx.core.content.ContextCompat
import info.nightscout.androidaps.core.R
import info.nightscout.androidaps.utils.FabricPrivacy
@ -83,4 +84,10 @@ class ResourceHelperImplementation @Inject constructor(private val context: Cont
}
override fun shortTextMode(): Boolean = !gb(R.bool.isTablet)
override fun gac(context: Context, attributeId: Int): Int =
context.getThemeColor(attributeId)
override fun gac(attributeId: Int): Int =
ContextThemeWrapper(this.context, R.style.AppTheme).getThemeColor(attributeId)
}

View file

@ -14,8 +14,7 @@
android:paddingEnd="10dp"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="@color/warningAccentText"
android:visibility="gone"
/>
android:visibility="gone" />
<EditText
android:id="@+id/password_prompt_pass"

View file

@ -4,6 +4,7 @@
<!-- General-->
<string name="refresh">Obnoviť</string>
<string name="error">Chyba</string>
<string name="save">Uložiť</string>
<string name="not_set_short">Nenastavené</string>
<string name="failedupdatebasalprofile">Chyba pri aktualizovaní bazálneho profilu</string>
<string name="profile_set_ok">Bazálny profil v pumpe aktualizovaný</string>
@ -376,6 +377,7 @@
<string name="uel_stat_reset">RESET ŠTATISTÍK</string>
<string name="uel_delete_logs">VYMAZAŤ LOGY</string>
<string name="uel_delete_future_treatments">VYMAZAŤ BUDÚCE OŠETRENIA</string>
<string name="delete_future_treatments">Odstrániť ošetrenia v budúcnosti</string>
<string name="uel_export_settings">EXPORTOVAŤ NASTAVENIA</string>
<string name="uel_import_settings">IMPORTOVAŤ NASTAVENIA</string>
<string name="uel_reset_databases">RESETOVAŤ DATABÁZY</string>

View file

@ -7,4 +7,12 @@
<declare-styleable name="NumberPicker">
<attr name="customContentDescription" format="string" />
</declare-styleable>
<!---Notification -->
<attr name="notificationUrgent" format="reference|color" />
<attr name="notificationNormal" format="reference|color" />
<attr name="notificationLow" format="reference|color" />
<attr name="notificationInfo" format="reference|color" />
<attr name="notificationAnnouncement" format="reference|color" />
</resources>

View file

@ -92,8 +92,14 @@
<color name="weekdayOutline">#1ea3e5</color>
<color name="weekendOutline">#1e88e5</color>
<!-- CareportalEvent-->
<!-- Notification-->
<color name="notificationAnnouncement">#FF8C00</color>
<color name="notificationUrgent">#ff0400</color>
<color name="notificationNormal">#ff5e55</color>
<color name="notificationLow">#ff827c</color>
<!-- Green Colors -->
<color name="notificationInfo">#009705</color>
<!-- Toasts-->
<color name="toastBorder">#666666</color>

View file

@ -7,11 +7,15 @@
<string name="bolus_protection">Bolus protection</string>
<string name="master_password">Master password</string>
<string name="settings_password">Settings password</string>
<string name="settings_pin">Settings PIN</string>
<string name="application_password">Application password</string>
<string name="application_pin">Application PIN</string>
<string name="bolus_password">Bolus password</string>
<string name="bolus_pin">Bolus PIN</string>
<string name="unlock_settings">Unlock settings</string>
<string name="biometric">Biometric</string>
<string name="custom_password">Custom password</string>
<string name="custom_pin">Custom PIN</string>
<string name="noprotection">No protection</string>
<string name="protection">Protection</string>
<string name="master_password_missing">Master password is not set!\n\nPlease set your Master password in Preferences (%1$s &#8594; %2$s)</string>
@ -19,15 +23,23 @@
<string name="unsecure_fallback_descriotion_biometric">In order to be effective, biometric protection needs a master password set for fallback.\n\nPlease set a master password!</string>
<string name="password_set">Password set!</string>
<string name="pin_set">PIN set!</string>
<string name="password_not_set">Password not set</string>
<string name="pin_not_set">PIN not set</string>
<string name="password_not_changed">Password not changed</string>
<string name="pin_not_changed">PIN not changed</string>
<string name="password_cleared">Password cleared!</string>
<string name="pin_cleared">PIN cleared!</string>
<string name="password_hint">Enter password here</string>
<string name="pin_hint">Enter PIN here</string>
<string name="key_master_password" translatable="false">master_password</string>
<string name="key_settings_password" translatable="false">settings_password</string>
<string name="key_settings_pin" translatable="false">settings_pin</string>
<string name="key_application_password" translatable="false">application_password</string>
<string name="key_application_pin" translatable="false">application_pin</string>
<string name="key_bolus_password" translatable="false">bolus_password</string>
<string name="key_bolus_pin" translatable="false">bolus_pin</string>
<string name="key_settings_protection" translatable="false">settings_protection</string>
<string name="key_application_protection" translatable="false">application_protection</string>
<string name="key_bolus_protection" translatable="false">bolus_protection</string>

View file

@ -222,7 +222,9 @@
<!-- Protection-->
<string name="wrongpassword">Wrong password</string>
<string name="wrongpin">Wrong PIN</string>
<string name="passwords_dont_match">Passwords don\'t match</string>
<string name="pin_dont_match">PINs don\'t match</string>
<!-- Profile-->
<string name="basalprofilenotaligned">Basal values not aligned to hours: %1$s</string>

View file

@ -22,6 +22,12 @@
<item name="android:textColorSecondary">@color/white</item>
<item name="android:textColorPrimary">@color/white</item>
<item name="android:textColor">@color/white</item>
<!---Notification -->
<item name="notificationUrgent">@color/notificationUrgent</item>
<item name="notificationNormal">@color/notificationNormal</item>
<item name="notificationLow">@color/notificationLow</item>
<item name="notificationInfo">@color/notificationInfo</item>
<item name="notificationAnnouncement">@color/notificationAnnouncement</item>
</style>
<style name="AppTheme.NoActionBar" parent="Theme.MaterialComponents.NoActionBar">

View file

@ -456,21 +456,21 @@ public abstract class AbstractDanaRPlugin extends PumpPluginBase implements Pump
@NonNull @Override
public Constraint<Double> applyBasalConstraints(Constraint<Double> absoluteRate, @NonNull Profile profile) {
absoluteRate.setIfSmaller(getAapsLogger(), danaPump.getMaxBasal(), String.format(getRh().gs(R.string.limitingbasalratio), danaPump.getMaxBasal(), getRh().gs(R.string.pumplimit)), this);
absoluteRate.setIfSmaller(getAapsLogger(), danaPump.getMaxBasal(), getRh().gs(R.string.limitingbasalratio, danaPump.getMaxBasal(), getRh().gs(R.string.pumplimit)), this);
return absoluteRate;
}
@NonNull @Override
public Constraint<Integer> applyBasalPercentConstraints(Constraint<Integer> percentRate, @NonNull Profile profile) {
percentRate.setIfGreater(getAapsLogger(), 0, String.format(getRh().gs(R.string.limitingpercentrate), 0, getRh().gs(R.string.itmustbepositivevalue)), this);
percentRate.setIfSmaller(getAapsLogger(), getPumpDescription().getMaxTempPercent(), String.format(getRh().gs(R.string.limitingpercentrate), getPumpDescription().getMaxTempPercent(), getRh().gs(R.string.pumplimit)), this);
percentRate.setIfGreater(getAapsLogger(), 0, getRh().gs(R.string.limitingpercentrate, 0, getRh().gs(R.string.itmustbepositivevalue)), this);
percentRate.setIfSmaller(getAapsLogger(), getPumpDescription().getMaxTempPercent(), getRh().gs(R.string.limitingpercentrate, getPumpDescription().getMaxTempPercent(), getRh().gs(R.string.pumplimit)), this);
return percentRate;
}
@NonNull @Override
public Constraint<Double> applyBolusConstraints(Constraint<Double> insulin) {
insulin.setIfSmaller(getAapsLogger(), danaPump.getMaxBolus(), String.format(getRh().gs(R.string.limitingbolus), danaPump.getMaxBolus(), getRh().gs(R.string.pumplimit)), this);
insulin.setIfSmaller(getAapsLogger(), danaPump.getMaxBolus(), getRh().gs(R.string.limitingbolus, danaPump.getMaxBolus(), getRh().gs(R.string.pumplimit)), this);
return insulin;
}

View file

@ -302,7 +302,7 @@ class DanaRSPlugin @Inject constructor(
0x40 -> error = rh.gs(R.string.speederror)
0x80 -> error = rh.gs(R.string.insulinlimitviolation)
}
result.comment = String.format(rh.gs(R.string.boluserrorcode), detailedBolusInfo.insulin, t.insulin, error)
result.comment = rh.gs(R.string.boluserrorcode, detailedBolusInfo.insulin, t.insulin, error)
} else result.comment = rh.gs(R.string.ok)
aapsLogger.debug(LTag.PUMP, "deliverTreatment: OK. Asked: " + detailedBolusInfo.insulin + " Delivered: " + result.bolusDelivered)
result

View file

@ -306,7 +306,7 @@ class DanaRSService : DaggerService() {
val expectedEnd = bolusStart + bolusDurationInMSec + 2000
while (System.currentTimeMillis() < expectedEnd) {
val waitTime = expectedEnd - System.currentTimeMillis()
bolusingEvent.status = String.format(rh.gs(R.string.waitingforestimatedbolusend), waitTime / 1000)
bolusingEvent.status = rh.gs(R.string.waitingforestimatedbolusend, waitTime / 1000)
rxBus.send(bolusingEvent)
SystemClock.sleep(1000)
}

View file

@ -406,7 +406,7 @@ class DiaconnG8Service : DaggerService() {
val totalwaitTime = (expectedEnd - System.currentTimeMillis()) / 1000
while (!diaconnG8Pump.bolusDone) {
val waitTime = (expectedEnd - System.currentTimeMillis()) / 1000
bolusingEvent.status = String.format(rh.gs(R.string.waitingforestimatedbolusend), if (waitTime < 0) 0 else waitTime)
bolusingEvent.status = rh.gs(R.string.waitingforestimatedbolusend, if (waitTime < 0) 0 else waitTime)
var progressPecent = 0
if (totalwaitTime > waitTime) {
progressPecent = ((totalwaitTime - waitTime) * 100 / totalwaitTime).toInt()

View file

@ -1583,22 +1583,22 @@ public class LocalInsightPlugin extends PumpPluginBase implements Pump, Constrai
@NonNull @Override
public Constraint<Integer> applyBasalPercentConstraints(Constraint<Integer> percentRate, @NonNull Profile profile) {
percentRate.setIfGreater(getAapsLogger(), 0, String.format(rh.gs(R.string.limitingpercentrate), 0, rh.gs(R.string.itmustbepositivevalue)), this);
percentRate.setIfSmaller(getAapsLogger(), getPumpDescription().getMaxTempPercent(), String.format(rh.gs(R.string.limitingpercentrate), getPumpDescription().getMaxTempPercent(), rh.gs(R.string.pumplimit)), this);
percentRate.setIfGreater(getAapsLogger(), 0, rh.gs(R.string.limitingpercentrate, 0, rh.gs(R.string.itmustbepositivevalue)), this);
percentRate.setIfSmaller(getAapsLogger(), getPumpDescription().getMaxTempPercent(), rh.gs(R.string.limitingpercentrate, getPumpDescription().getMaxTempPercent(), rh.gs(R.string.pumplimit)), this);
return percentRate;
}
@NonNull @Override
public Constraint<Double> applyBolusConstraints(@NonNull Constraint<Double> insulin) {
if (!limitsFetched) return insulin;
insulin.setIfSmaller(getAapsLogger(), maximumBolusAmount, String.format(rh.gs(R.string.limitingbolus), maximumBolusAmount, rh.gs(R.string.pumplimit)), this);
insulin.setIfSmaller(getAapsLogger(), maximumBolusAmount, rh.gs(R.string.limitingbolus, maximumBolusAmount, rh.gs(R.string.pumplimit)), this);
if (insulin.value() < minimumBolusAmount) {
//TODO: Add function to Constraints or use different approach
// This only works if the interface of the InsightPlugin is called last.
// If not, another constraint could theoretically set the value between 0 and minimumBolusAmount
insulin.set(getAapsLogger(), 0d, String.format(rh.gs(R.string.limitingbolus), minimumBolusAmount, rh.gs(R.string.pumplimit)), this);
insulin.set(getAapsLogger(), 0d, rh.gs(R.string.limitingbolus, minimumBolusAmount, rh.gs(R.string.pumplimit)), this);
}
return insulin;
}

View file

@ -16,8 +16,6 @@ import info.nightscout.androidaps.extensions.convertedToAbsolute
import info.nightscout.androidaps.extensions.plannedRemainingMinutes
import info.nightscout.androidaps.extensions.toStringFull
import info.nightscout.androidaps.interfaces.*
import info.nightscout.shared.logging.AAPSLogger
import info.nightscout.shared.logging.LTag
import info.nightscout.androidaps.plugins.bus.RxBus
import info.nightscout.androidaps.plugins.common.ManufacturerType
import info.nightscout.androidaps.plugins.general.actions.defs.CustomAction
@ -52,6 +50,8 @@ import info.nightscout.androidaps.utils.T
import info.nightscout.androidaps.utils.TimeChangeType
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.rx.AapsSchedulers
import info.nightscout.shared.logging.AAPSLogger
import info.nightscout.shared.logging.LTag
import info.nightscout.shared.sharedPreferences.SP
import io.reactivex.rxjava3.core.Completable
import io.reactivex.rxjava3.core.Single
@ -119,10 +119,13 @@ class OmnipodDashPumpPlugin @Inject constructor(
updatePodWarnings()
aapsLogger.info(LTag.PUMP, "statusChecker")
try {
createFakeTBRWhenNoActivePod()
.subscribeOn(aapsSchedulers.io)
.doOnError { aapsLogger.warn(LTag.PUMP, "Error on createFakeTBRWhenNoActivePod=$it") }
.blockingSubscribe()
.blockingAwait()
} catch (e: Exception) {
aapsLogger.warn(LTag.PUMP, "Error on createFakeTBRWhenNoActivePod=$e")
}
handler.postDelayed(statusChecker, STATUS_CHECK_INTERVAL_MS)
}
}
@ -247,10 +250,11 @@ class OmnipodDashPumpPlugin @Inject constructor(
try {
stopConnecting?.let {
omnipodManager.connect(it).ignoreElements()
.doOnError { aapsLogger.info(LTag.PUMPCOMM, "connect error=$it") }
.doOnComplete { podStateManager.incrementSuccessfulConnectionAttemptsAfterRetries() }
.blockingSubscribe()
.blockingAwait()
}
} catch (e: Exception) {
aapsLogger.info(LTag.PUMPCOMM, "connect error=$e")
} finally {
synchronized(this) {
stopConnecting = null
@ -279,6 +283,7 @@ class OmnipodDashPumpPlugin @Inject constructor(
return
}
try {
getPodStatus()
.doOnComplete {
aapsLogger.info(LTag.PUMP, "getPumpStatus executed with success")
@ -289,11 +294,10 @@ class OmnipodDashPumpPlugin @Inject constructor(
aapsLogger.info(LTag.PUMP, "recoverActivationFromPodStatus msg=$msg")
}
}
}.blockingAwait()
} catch (e: Exception) {
aapsLogger.error(LTag.PUMP, "Error in getPumpStatus", e)
}
.doOnError {
aapsLogger.error(LTag.PUMP, "Error in getPumpStatus", it)
}
.blockingSubscribe()
}
private fun getPodStatus(): Completable = Completable.concat(
@ -564,7 +568,8 @@ class OmnipodDashPumpPlugin @Inject constructor(
.comment(rh.gs(R.string.omnipod_dash_not_enough_insulin))
}
if (podStateManager.deliveryStatus == DeliveryStatus.BOLUS_AND_BASAL_ACTIVE ||
podStateManager.deliveryStatus == DeliveryStatus.BOLUS_AND_TEMP_BASAL_ACTIVE) {
podStateManager.deliveryStatus == DeliveryStatus.BOLUS_AND_TEMP_BASAL_ACTIVE
) {
return PumpEnactResult(injector)
.success(false)
.enacted(false)
@ -722,13 +727,13 @@ class OmnipodDashPumpPlugin @Inject constructor(
getPodStatus()
var errorGettingStatus: Throwable? = null
cmd
.doOnError {
errorGettingStatus = it
try {
cmd.blockingAwait()
} catch (e: Exception) {
errorGettingStatus = e
aapsLogger.debug(LTag.PUMP, "waitForBolusDeliveryToComplete errorGettingStatus=$errorGettingStatus")
Thread.sleep(BOLUS_RETRY_INTERVAL_MS) // retry every 3 sec
}
.blockingSubscribe()
if (errorGettingStatus != null) {
continue
}

View file

@ -40,6 +40,7 @@ import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
import info.nightscout.androidaps.utils.buildHelper.BuildHelper
import info.nightscout.androidaps.utils.protection.ProtectionCheck
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.rx.AapsSchedulers
import info.nightscout.shared.sharedPreferences.SP
@ -64,6 +65,7 @@ class OmnipodDashOverviewFragment : DaggerFragment() {
@Inject lateinit var omnipodDashPumpPlugin: OmnipodDashPumpPlugin
@Inject lateinit var podStateManager: OmnipodDashPodStateManager
@Inject lateinit var sp: SP
@Inject lateinit var protectionCheck: ProtectionCheck
@Inject lateinit var dateUtil: DateUtil
@Inject lateinit var aapsSchedulers: AapsSchedulers
@Inject lateinit var pumpSync: PumpSync
@ -93,8 +95,7 @@ class OmnipodDashOverviewFragment : DaggerFragment() {
private var _podInfoBinding: OmnipodCommonOverviewPodInfoBinding? = null
private var _buttonBinding: OmnipodCommonOverviewButtonsBinding? = null
// These properties are only valid between onCreateView and
// onDestroyView.
// These properties are only valid between onCreateView and onDestroyView.
val binding get() = _binding!!
private val bluetoothStatusBinding get() = _bluetoothStatusBinding!!
private val podInfoBinding get() = _podInfoBinding!!
@ -112,8 +113,12 @@ class OmnipodDashOverviewFragment : DaggerFragment() {
super.onViewCreated(view, savedInstanceState)
buttonBinding.buttonPodManagement.setOnClickListener {
// TODO add protection
startActivity(Intent(context, DashPodManagementActivity::class.java))
activity?.let { activity ->
protectionCheck.queryProtection(
activity,
ProtectionCheck.Protection.PREFERENCES,
UIRunnable { startActivity(Intent(context, DashPodManagementActivity::class.java)) })
}
}
buttonBinding.buttonResumeDelivery.setOnClickListener {

View file

@ -81,4 +81,5 @@
</plurals>
<string name="orange_use_scanning_level">Použi skenovanie</string>
<string name="orange_use_scanning_level_summary">Skenuj, predtým, ako sa pripojíš k OrangeLinku. Malo by to zlepšiť stabilitu pripojenia (môže byť použité i s inými klonmi RileyLinku, ak je to potrebné).</string>
<string name="rileylink_configuration">Konfigurácia RileyLinku</string>
</resources>