commit
5627f38f97
124 changed files with 4316 additions and 875 deletions
|
@ -109,7 +109,7 @@ android {
|
|||
defaultConfig {
|
||||
multiDexEnabled true
|
||||
versionCode 1500
|
||||
version "3.0.0.1-dev"
|
||||
version "3.0.0.1-dev-a"
|
||||
buildConfigField "String", "VERSION", '"' + version + '"'
|
||||
buildConfigField "String", "BUILDVERSION", '"' + generateGitBuild() + '-' + generateDate() + '"'
|
||||
buildConfigField "String", "REMOTE", '"' + generateGitRemote() + '"'
|
||||
|
|
1231
app/src/main/assets/OpenAPSSMBDynamicISF/determine-basal.js
Normal file
1231
app/src/main/assets/OpenAPSSMBDynamicISF/determine-basal.js
Normal file
File diff suppressed because it is too large
Load diff
|
@ -239,6 +239,10 @@ class ProfileHelperActivity : NoSplashAppCompatActivity() {
|
|||
}
|
||||
ToastUtils.showToastInUiThread(this, R.string.invalidinput)
|
||||
}
|
||||
binding.age.editText?.id?.let { binding.ageLabel.labelFor = it }
|
||||
binding.tdd.editText?.id?.let { binding.tddLabel.labelFor = it }
|
||||
binding.weight.editText?.id?.let { binding.weightLabel.labelFor = it }
|
||||
binding.basalpctfromtdd.editText?.id?.let { binding.basalpctfromtddLabel.labelFor = it }
|
||||
|
||||
switchTab(0, typeSelected[0], false)
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ import info.nightscout.androidaps.plugins.aps.openAPSAMA.DetermineBasalAdapterAM
|
|||
import info.nightscout.androidaps.plugins.aps.openAPSAMA.DetermineBasalResultAMA
|
||||
import info.nightscout.androidaps.plugins.aps.openAPSSMB.DetermineBasalAdapterSMBJS
|
||||
import info.nightscout.androidaps.plugins.aps.openAPSSMB.DetermineBasalResultSMB
|
||||
import info.nightscout.androidaps.plugins.aps.openAPSSMBDynamicISF.DetermineBasalAdapterSMBDynamicISFJS
|
||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobOref1Thread
|
||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobThread
|
||||
|
||||
|
@ -19,6 +20,7 @@ abstract class APSModule {
|
|||
@ContributesAndroidInjector abstract fun determineBasalResultAMAInjector(): DetermineBasalResultAMA
|
||||
@ContributesAndroidInjector abstract fun determineBasalAdapterAMAJSInjector(): DetermineBasalAdapterAMAJS
|
||||
@ContributesAndroidInjector abstract fun determineBasalAdapterSMBJSInjector(): DetermineBasalAdapterSMBJS
|
||||
@ContributesAndroidInjector abstract fun determineBasalAdapterSMBAutoISFJSInjector(): DetermineBasalAdapterSMBDynamicISFJS
|
||||
@ContributesAndroidInjector abstract fun iobCobThreadInjector(): IobCobThread
|
||||
@ContributesAndroidInjector abstract fun iobCobOref1ThreadInjector(): IobCobOref1Thread
|
||||
}
|
|
@ -14,6 +14,7 @@ import info.nightscout.androidaps.plugin.general.openhumans.OpenHumansUploader
|
|||
import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin
|
||||
import info.nightscout.androidaps.plugins.aps.openAPSAMA.OpenAPSAMAPlugin
|
||||
import info.nightscout.androidaps.plugins.aps.openAPSSMB.OpenAPSSMBPlugin
|
||||
import info.nightscout.androidaps.plugins.aps.openAPSSMBDynamicISF.OpenAPSSMBDynamicISFPlugin
|
||||
import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin
|
||||
import info.nightscout.androidaps.plugins.constraints.bgQualityCheck.BgQualityCheckPlugin
|
||||
import info.nightscout.androidaps.plugins.constraints.dstHelper.DstHelperPlugin
|
||||
|
@ -212,6 +213,12 @@ abstract class PluginsModule {
|
|||
@IntKey(220)
|
||||
abstract fun bindOpenAPSSMBPlugin(plugin: OpenAPSSMBPlugin): PluginBase
|
||||
|
||||
@Binds
|
||||
@APS
|
||||
@IntoMap
|
||||
@IntKey(222)
|
||||
abstract fun bindOpenAPSSMBAutoISFPlugin(plugin: OpenAPSSMBDynamicISFPlugin): PluginBase
|
||||
|
||||
@Binds
|
||||
@AllConfigs
|
||||
@IntoMap
|
||||
|
|
|
@ -64,6 +64,7 @@ class CalibrationDialog : DialogFragmentWithDate() {
|
|||
binding.bg.setParams(savedInstanceState?.getDouble("bg")
|
||||
?: bg, 36.0, 500.0, 1.0, DecimalFormat("0"), false, binding.okcancel.ok)
|
||||
binding.units.text = if (units == GlucoseUnit.MMOL) rh.gs(R.string.mmol) else rh.gs(R.string.mgdl)
|
||||
binding.bg.editText?.id?.let { binding.bgLabel.labelFor = it }
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
|
|
|
@ -137,32 +137,39 @@ class CarbsDialog : DialogFragmentWithDate() {
|
|||
savedInstanceState?.getDouble("carbs")
|
||||
?: 0.0, 0.0, maxCarbs, 1.0, DecimalFormat("0"), false, binding.okcancel.ok, textWatcher
|
||||
)
|
||||
|
||||
binding.plus1.text = toSignedString(sp.getInt(R.string.key_carbs_button_increment_1, FAV1_DEFAULT))
|
||||
val plus1text = toSignedString(sp.getInt(R.string.key_carbs_button_increment_1, FAV1_DEFAULT))
|
||||
binding.plus1.text = plus1text
|
||||
binding.plus1.contentDescription = rh.gs(R.string.treatments_wizard_carbs_label) + " " + plus1text
|
||||
binding.plus1.setOnClickListener {
|
||||
binding.carbs.value = max(
|
||||
0.0, binding.carbs.value
|
||||
+ sp.getInt(R.string.key_carbs_button_increment_1, FAV1_DEFAULT)
|
||||
)
|
||||
validateInputs()
|
||||
binding.carbs.announceValue()
|
||||
}
|
||||
|
||||
binding.plus2.text = toSignedString(sp.getInt(R.string.key_carbs_button_increment_2, FAV2_DEFAULT))
|
||||
val plus2text = toSignedString(sp.getInt(R.string.key_carbs_button_increment_2, FAV2_DEFAULT))
|
||||
binding.plus2.text = plus2text
|
||||
binding.plus2.contentDescription = rh.gs(R.string.treatments_wizard_carbs_label) + " " + plus2text
|
||||
binding.plus2.setOnClickListener {
|
||||
binding.carbs.value = max(
|
||||
0.0, binding.carbs.value
|
||||
+ sp.getInt(R.string.key_carbs_button_increment_2, FAV2_DEFAULT)
|
||||
)
|
||||
validateInputs()
|
||||
binding.carbs.announceValue()
|
||||
}
|
||||
|
||||
binding.plus3.text = toSignedString(sp.getInt(R.string.key_carbs_button_increment_3, FAV3_DEFAULT))
|
||||
val plus3text = toSignedString(sp.getInt(R.string.key_carbs_button_increment_3, FAV3_DEFAULT))
|
||||
binding.plus3.text = plus3text
|
||||
binding.plus2.contentDescription = rh.gs(R.string.treatments_wizard_carbs_label) + " " + plus3text
|
||||
binding.plus3.setOnClickListener {
|
||||
binding.carbs.value = max(
|
||||
0.0, binding.carbs.value
|
||||
+ sp.getInt(R.string.key_carbs_button_increment_3, FAV3_DEFAULT)
|
||||
)
|
||||
validateInputs()
|
||||
binding.carbs.announceValue()
|
||||
}
|
||||
|
||||
setOnValueChangedListener { eventTime: Long ->
|
||||
|
@ -188,6 +195,9 @@ class CarbsDialog : DialogFragmentWithDate() {
|
|||
binding.hypoTt.isChecked = false
|
||||
binding.activityTt.isChecked = false
|
||||
}
|
||||
binding.duration.editText?.id?.let { binding.durationLabel.labelFor = it }
|
||||
binding.time.editText?.id?.let { binding.timeLabel.labelFor = it }
|
||||
binding.carbs.editText?.id?.let { binding.carbsLabel.labelFor = it }
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
|
|
|
@ -165,6 +165,8 @@ class CareDialog : DialogFragmentWithDate() {
|
|||
?: 0.0, 0.0, Constants.MAX_PROFILE_SWITCH_DURATION, 10.0, DecimalFormat("0"), false, binding.okcancel.ok)
|
||||
if (options == EventType.NOTE || options == EventType.QUESTION || options == EventType.ANNOUNCEMENT || options == EventType.EXERCISE)
|
||||
binding.notesLayout.root.visibility = View.VISIBLE // independent to preferences
|
||||
binding.bg.editText?.id?.let { binding.bgLabel.labelFor = it }
|
||||
binding.duration.editText?.id?.let { binding.durationLabel.labelFor = it }
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
|
|
|
@ -70,6 +70,8 @@ class ExtendedBolusDialog : DialogFragmentWithDate() {
|
|||
val extendedMaxDuration = pumpDescription.extendedBolusMaxDuration
|
||||
binding.duration.setParams(savedInstanceState?.getDouble("duration")
|
||||
?: extendedDurationStep, extendedDurationStep, extendedMaxDuration, extendedDurationStep, DecimalFormat("0"), false, binding.okcancel.ok)
|
||||
binding.insulin.editText?.id?.let { binding.insulinLabel.labelFor = it }
|
||||
binding.duration.editText?.id?.let { binding.durationLabel.labelFor = it }
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
|
|
|
@ -96,7 +96,7 @@ class FillDialog : DialogFragmentWithDate() {
|
|||
} else {
|
||||
binding.fillPresetButton3.visibility = View.GONE
|
||||
}
|
||||
|
||||
binding.fillInsulinamount.editText?.id?.let { binding.fillLabel.labelFor = it }
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
|
|
|
@ -116,29 +116,40 @@ class InsulinDialog : DialogFragmentWithDate() {
|
|||
binding.amount.setParams(savedInstanceState?.getDouble("amount")
|
||||
?: 0.0, 0.0, maxInsulin, activePlugin.activePump.pumpDescription.bolusStep, DecimalFormatter.pumpSupportedBolusFormat(activePlugin.activePump), false, binding.okcancel.ok, textWatcher)
|
||||
|
||||
binding.plus05.text = sp.getDouble(rh.gs(R.string.key_insulin_button_increment_1), PLUS1_DEFAULT).toSignedString(activePlugin.activePump)
|
||||
val plus05Text = sp.getDouble(rh.gs(R.string.key_insulin_button_increment_1), PLUS1_DEFAULT).toSignedString(activePlugin.activePump)
|
||||
binding.plus05.text = plus05Text
|
||||
binding.plus05.contentDescription = rh.gs(R.string.overview_insulin_label) + " " + plus05Text
|
||||
binding.plus05.setOnClickListener {
|
||||
binding.amount.value = max(0.0, binding.amount.value
|
||||
+ sp.getDouble(rh.gs(R.string.key_insulin_button_increment_1), PLUS1_DEFAULT))
|
||||
validateInputs()
|
||||
binding.amount.announceValue()
|
||||
}
|
||||
binding.plus10.text = sp.getDouble(rh.gs(R.string.key_insulin_button_increment_2), PLUS2_DEFAULT).toSignedString(activePlugin.activePump)
|
||||
val plus10Text = sp.getDouble(rh.gs(R.string.key_insulin_button_increment_2), PLUS2_DEFAULT).toSignedString(activePlugin.activePump)
|
||||
binding.plus10.text = plus10Text
|
||||
binding.plus10.contentDescription = rh.gs(R.string.overview_insulin_label) + " " + plus10Text
|
||||
binding.plus10.setOnClickListener {
|
||||
binding.amount.value = max(0.0, binding.amount.value
|
||||
+ sp.getDouble(rh.gs(R.string.key_insulin_button_increment_2), PLUS2_DEFAULT))
|
||||
validateInputs()
|
||||
binding.amount.announceValue()
|
||||
}
|
||||
binding.plus20.text = sp.getDouble(rh.gs(R.string.key_insulin_button_increment_3), PLUS3_DEFAULT).toSignedString(activePlugin.activePump)
|
||||
val plus20Text = sp.getDouble(rh.gs(R.string.key_insulin_button_increment_3), PLUS3_DEFAULT).toSignedString(activePlugin.activePump)
|
||||
binding.plus20.text = plus20Text
|
||||
binding.plus20.contentDescription = rh.gs(R.string.overview_insulin_label) + " " + plus20Text
|
||||
binding.plus20.setOnClickListener {
|
||||
binding.amount.value = max(0.0, binding.amount.value
|
||||
+ sp.getDouble(rh.gs(R.string.key_insulin_button_increment_3), PLUS3_DEFAULT))
|
||||
validateInputs()
|
||||
binding.amount.announceValue()
|
||||
}
|
||||
|
||||
binding.timeLayout.visibility = View.GONE
|
||||
binding.recordOnly.setOnCheckedChangeListener { _, isChecked: Boolean ->
|
||||
binding.timeLayout.visibility = isChecked.toVisibility()
|
||||
}
|
||||
binding.amount.editText?.id?.let { binding.insulinLabel.labelFor = it }
|
||||
binding.time.editText?.id?.let { binding.timeLabel.labelFor = it }
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
|
|
|
@ -148,6 +148,9 @@ class ProfileSwitchDialog : DialogFragmentWithDate() {
|
|||
}
|
||||
}
|
||||
binding.ttLayout.visibility = View.GONE
|
||||
binding.duration.editText?.id?.let { binding.durationLabel.labelFor = it }
|
||||
binding.percentage.editText?.id?.let { binding.percentageLabel.labelFor = it }
|
||||
binding.timeshift.editText?.id?.let { binding.timeshiftLabel.labelFor = it }
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
|
|
|
@ -86,6 +86,9 @@ class TempBasalDialog : DialogFragmentWithDate() {
|
|||
binding.percentLayout.visibility = View.GONE
|
||||
binding.absoluteLayout.visibility = View.VISIBLE
|
||||
}
|
||||
binding.basalPercentInput.editText?.id?.let { binding.basalPercentLabel.labelFor = it }
|
||||
binding.basalAbsoluteInput.editText?.id?.let { binding.basalAbsoluteLabel.labelFor = it }
|
||||
binding.duration.editText?.id?.let { binding.durationLabel.labelFor = it }
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
|
|
|
@ -120,6 +120,8 @@ class TempTargetDialog : DialogFragmentWithDate() {
|
|||
longClick(it)
|
||||
return@setOnLongClickListener true
|
||||
}
|
||||
binding.duration.editText?.id?.let { binding.durationLabel.labelFor = it }
|
||||
binding.temptarget.editText?.id?.let { binding.temptargetLabel.labelFor = it }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -106,6 +106,8 @@ class TreatmentDialog : DialogFragmentWithDate() {
|
|||
binding.insulin.setParams(savedInstanceState?.getDouble("insulin")
|
||||
?: 0.0, 0.0, maxInsulin, pumpDescription.bolusStep, DecimalFormatter.pumpSupportedBolusFormat(activePlugin.activePump), false, binding.okcancel.ok, textWatcher)
|
||||
binding.recordOnlyLayout.visibility = View.GONE
|
||||
binding.insulin.editText?.id?.let { binding.insulinLabel.labelFor = it }
|
||||
binding.carbs.editText?.id?.let { binding.carbsLabel.labelFor = it }
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
|
|
|
@ -70,7 +70,7 @@ class WizardInfoDialog : DaggerDialogFragment() {
|
|||
val units = profileFunction.getUnits()
|
||||
val bgString = Profile.toUnitsString(data.glucoseValue, data.glucoseValue * Constants.MGDL_TO_MMOLL, units)
|
||||
val isf = Profile.toUnits(data.isf, data.isf * Constants.MGDL_TO_MMOLL, units)
|
||||
val trend = Profile.toUnitsString(data.glucoseTrend * 3, data.glucoseTrend * 3 * Constants.MGDL_TO_MMOLL, profileFunction.getUnits())
|
||||
val trend = Profile.toUnitsString(data.glucoseTrend * 3, data.glucoseTrend * 3 * Constants.MGDL_TO_MMOLL, units)
|
||||
// BG
|
||||
binding.bg.text = rh.gs(R.string.format_bg_isf, bgString, isf)
|
||||
binding.bgInsulin.text = rh.gs(R.string.formatinsulinunits, data.glucoseInsulin)
|
||||
|
|
|
@ -7,6 +7,7 @@ import info.nightscout.androidaps.data.MealData
|
|||
import info.nightscout.androidaps.extensions.convertedToAbsolute
|
||||
import info.nightscout.androidaps.extensions.getPassedDurationToTimeInMinutes
|
||||
import info.nightscout.androidaps.extensions.plannedRemainingMinutes
|
||||
import info.nightscout.androidaps.interfaces.DetermineBasalAdapterInterface
|
||||
import info.nightscout.androidaps.interfaces.GlucoseUnit
|
||||
import info.nightscout.androidaps.interfaces.IobCobCalculator
|
||||
import info.nightscout.androidaps.interfaces.Profile
|
||||
|
@ -14,6 +15,7 @@ import info.nightscout.androidaps.interfaces.ProfileFunction
|
|||
import info.nightscout.shared.logging.AAPSLogger
|
||||
import info.nightscout.shared.logging.LTag
|
||||
import info.nightscout.androidaps.plugins.aps.logger.LoggerCallback
|
||||
import info.nightscout.androidaps.plugins.aps.loop.APSResult
|
||||
import info.nightscout.androidaps.plugins.aps.loop.ScriptReader
|
||||
import info.nightscout.androidaps.plugins.aps.openAPSSMB.SMBDefaults
|
||||
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
|
||||
|
@ -30,7 +32,7 @@ import java.nio.charset.StandardCharsets
|
|||
import javax.inject.Inject
|
||||
import kotlin.math.min
|
||||
|
||||
class DetermineBasalAdapterAMAJS internal constructor(scriptReader: ScriptReader, injector: HasAndroidInjector) {
|
||||
class DetermineBasalAdapterAMAJS internal constructor(scriptReader: ScriptReader, injector: HasAndroidInjector) : DetermineBasalAdapterInterface {
|
||||
|
||||
private val injector: HasAndroidInjector
|
||||
|
||||
|
@ -48,21 +50,15 @@ class DetermineBasalAdapterAMAJS internal constructor(scriptReader: ScriptReader
|
|||
private var currentTemp = JSONObject()
|
||||
private var autosensData = JSONObject()
|
||||
|
||||
var currentTempParam: String? = null
|
||||
private set
|
||||
var iobDataParam: String? = null
|
||||
private set
|
||||
var glucoseStatusParam: String? = null
|
||||
private set
|
||||
var profileParam: String? = null
|
||||
private set
|
||||
var mealDataParam: String? = null
|
||||
private set
|
||||
var scriptDebug = ""
|
||||
private set
|
||||
override var currentTempParam: String? = null
|
||||
override var iobDataParam: String? = null
|
||||
override var glucoseStatusParam: String? = null
|
||||
override var profileParam: String? = null
|
||||
override var mealDataParam: String? = null
|
||||
override var scriptDebug = ""
|
||||
|
||||
@Suppress("SpellCheckingInspection")
|
||||
operator fun invoke(): DetermineBasalResultAMA? {
|
||||
override operator fun invoke(): APSResult? {
|
||||
aapsLogger.debug(LTag.APS, ">>> Invoking determine_basal <<<")
|
||||
aapsLogger.debug(LTag.APS, "Glucose status: " + glucoseStatus.toString().also { glucoseStatusParam = it })
|
||||
aapsLogger.debug(LTag.APS, "IOB data: " + iobData.toString().also { iobDataParam = it })
|
||||
|
@ -143,18 +139,25 @@ class DetermineBasalAdapterAMAJS internal constructor(scriptReader: ScriptReader
|
|||
}
|
||||
|
||||
@Suppress("SpellCheckingInspection")
|
||||
@Throws(JSONException::class) fun setData(profile: Profile,
|
||||
maxIob: Double,
|
||||
maxBasal: Double,
|
||||
minBg: Double,
|
||||
maxBg: Double,
|
||||
targetBg: Double,
|
||||
basalRate: Double,
|
||||
iobArray: Array<IobTotal>,
|
||||
glucoseStatus: GlucoseStatus,
|
||||
mealData: MealData,
|
||||
autosensDataRatio: Double,
|
||||
tempTargetSet: Boolean) {
|
||||
@Throws(JSONException::class)
|
||||
override fun setData(
|
||||
profile: Profile,
|
||||
maxIob: Double,
|
||||
maxBasal: Double,
|
||||
minBg: Double,
|
||||
maxBg: Double,
|
||||
targetBg: Double,
|
||||
basalRate: Double,
|
||||
iobArray: Array<IobTotal>,
|
||||
glucoseStatus: GlucoseStatus,
|
||||
mealData: MealData,
|
||||
autosensDataRatio: Double,
|
||||
tempTargetSet: Boolean,
|
||||
microBolusAllowed: Boolean,
|
||||
uamAllowed: Boolean,
|
||||
advancedFiltering: Boolean,
|
||||
isSaveCgmSource: Boolean
|
||||
) {
|
||||
this.profile = JSONObject()
|
||||
this.profile.put("max_iob", maxIob)
|
||||
this.profile.put("dia", min(profile.dia, 3.0))
|
||||
|
|
|
@ -96,7 +96,7 @@ class OpenAPSAMAFragment : DaggerFragment() {
|
|||
binding.result.text = jsonFormatter.format(lastAPSResult.json)
|
||||
binding.request.text = lastAPSResult.toSpanned()
|
||||
}
|
||||
openAPSAMAPlugin.lastDetermineBasalAdapterAMAJS?.let { determineBasalAdapterAMAJS ->
|
||||
openAPSAMAPlugin.lastDetermineBasalAdapter?.let { determineBasalAdapterAMAJS ->
|
||||
binding.glucosestatus.text = jsonFormatter.format(determineBasalAdapterAMAJS.glucoseStatusParam)
|
||||
binding.currenttemp.text = jsonFormatter.format(determineBasalAdapterAMAJS.currentTempParam)
|
||||
try {
|
||||
|
|
|
@ -60,8 +60,8 @@ class OpenAPSAMAPlugin @Inject constructor(
|
|||
// last values
|
||||
override var lastAPSRun: Long = 0
|
||||
override var lastAPSResult: DetermineBasalResultAMA? = null
|
||||
var lastDetermineBasalAdapterAMAJS: DetermineBasalAdapterAMAJS? = null
|
||||
var lastAutosensResult: AutosensResult = AutosensResult()
|
||||
override var lastDetermineBasalAdapter: DetermineBasalAdapterInterface? = null
|
||||
override var lastAutosensResult: AutosensResult = AutosensResult()
|
||||
|
||||
override fun specialEnableCondition(): Boolean {
|
||||
return try {
|
||||
|
@ -158,7 +158,7 @@ class OpenAPSAMAPlugin @Inject constructor(
|
|||
// Fix bug determine basal
|
||||
if (determineBasalResultAMA == null) {
|
||||
aapsLogger.error(LTag.APS, "SMB calculation returned null")
|
||||
lastDetermineBasalAdapterAMAJS = null
|
||||
lastDetermineBasalAdapter = null
|
||||
lastAPSResult = null
|
||||
lastAPSRun = 0
|
||||
} else {
|
||||
|
@ -167,8 +167,8 @@ class OpenAPSAMAPlugin @Inject constructor(
|
|||
val now = System.currentTimeMillis()
|
||||
determineBasalResultAMA.json?.put("timestamp", dateUtil.toISOString(now))
|
||||
determineBasalResultAMA.inputConstraints = inputConstraints
|
||||
lastDetermineBasalAdapterAMAJS = determineBasalAdapterAMAJS
|
||||
lastAPSResult = determineBasalResultAMA
|
||||
lastDetermineBasalAdapter = determineBasalAdapterAMAJS
|
||||
lastAPSResult = determineBasalResultAMA as DetermineBasalResultAMA
|
||||
lastAPSRun = now
|
||||
}
|
||||
rxBus.send(EventOpenAPSUpdateGui())
|
||||
|
|
|
@ -7,14 +7,11 @@ import info.nightscout.androidaps.data.MealData
|
|||
import info.nightscout.androidaps.extensions.convertedToAbsolute
|
||||
import info.nightscout.androidaps.extensions.getPassedDurationToTimeInMinutes
|
||||
import info.nightscout.androidaps.extensions.plannedRemainingMinutes
|
||||
import info.nightscout.androidaps.interfaces.ActivePlugin
|
||||
import info.nightscout.androidaps.interfaces.GlucoseUnit
|
||||
import info.nightscout.androidaps.interfaces.IobCobCalculator
|
||||
import info.nightscout.androidaps.interfaces.Profile
|
||||
import info.nightscout.androidaps.interfaces.ProfileFunction
|
||||
import info.nightscout.androidaps.interfaces.*
|
||||
import info.nightscout.shared.logging.AAPSLogger
|
||||
import info.nightscout.shared.logging.LTag
|
||||
import info.nightscout.androidaps.plugins.aps.logger.LoggerCallback
|
||||
import info.nightscout.androidaps.plugins.aps.loop.APSResult
|
||||
import info.nightscout.androidaps.plugins.aps.loop.ScriptReader
|
||||
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
|
||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus
|
||||
|
@ -31,7 +28,7 @@ import java.lang.reflect.InvocationTargetException
|
|||
import java.nio.charset.StandardCharsets
|
||||
import javax.inject.Inject
|
||||
|
||||
class DetermineBasalAdapterSMBJS internal constructor(private val scriptReader: ScriptReader, private val injector: HasAndroidInjector) {
|
||||
class DetermineBasalAdapterSMBJS internal constructor(private val scriptReader: ScriptReader, private val injector: HasAndroidInjector) : DetermineBasalAdapterInterface {
|
||||
|
||||
@Inject lateinit var aapsLogger: AAPSLogger
|
||||
@Inject lateinit var constraintChecker: ConstraintChecker
|
||||
|
@ -51,21 +48,16 @@ class DetermineBasalAdapterSMBJS internal constructor(private val scriptReader:
|
|||
private var smbAlwaysAllowed = false
|
||||
private var currentTime: Long = 0
|
||||
private var saveCgmSource = false
|
||||
var currentTempParam: String? = null
|
||||
private set
|
||||
var iobDataParam: String? = null
|
||||
private set
|
||||
var glucoseStatusParam: String? = null
|
||||
private set
|
||||
var profileParam: String? = null
|
||||
private set
|
||||
var mealDataParam: String? = null
|
||||
private set
|
||||
var scriptDebug = ""
|
||||
private set
|
||||
|
||||
override var currentTempParam: String? = null
|
||||
override var iobDataParam: String? = null
|
||||
override var glucoseStatusParam: String? = null
|
||||
override var profileParam: String? = null
|
||||
override var mealDataParam: String? = null
|
||||
override var scriptDebug = ""
|
||||
|
||||
@Suppress("SpellCheckingInspection")
|
||||
operator fun invoke(): DetermineBasalResultSMB? {
|
||||
override operator fun invoke(): APSResult? {
|
||||
aapsLogger.debug(LTag.APS, ">>> Invoking determine_basal <<<")
|
||||
aapsLogger.debug(LTag.APS, "Glucose status: " + mGlucoseStatus.toString().also { glucoseStatusParam = it })
|
||||
aapsLogger.debug(LTag.APS, "IOB data: " + iobData.toString().also { iobDataParam = it })
|
||||
|
@ -155,22 +147,24 @@ class DetermineBasalAdapterSMBJS internal constructor(private val scriptReader:
|
|||
return determineBasalResultSMB
|
||||
}
|
||||
|
||||
@Suppress("SpellCheckingInspection") fun setData(profile: Profile,
|
||||
maxIob: Double,
|
||||
maxBasal: Double,
|
||||
minBg: Double,
|
||||
maxBg: Double,
|
||||
targetBg: Double,
|
||||
basalRate: Double,
|
||||
iobArray: Array<IobTotal>,
|
||||
glucoseStatus: GlucoseStatus,
|
||||
mealData: MealData,
|
||||
autosensDataRatio: Double,
|
||||
tempTargetSet: Boolean,
|
||||
microBolusAllowed: Boolean,
|
||||
uamAllowed: Boolean,
|
||||
advancedFiltering: Boolean,
|
||||
isSaveCgmSource: Boolean
|
||||
@Suppress("SpellCheckingInspection")
|
||||
override fun setData(
|
||||
profile: Profile,
|
||||
maxIob: Double,
|
||||
maxBasal: Double,
|
||||
minBg: Double,
|
||||
maxBg: Double,
|
||||
targetBg: Double,
|
||||
basalRate: Double,
|
||||
iobArray: Array<IobTotal>,
|
||||
glucoseStatus: GlucoseStatus,
|
||||
mealData: MealData,
|
||||
autosensDataRatio: Double,
|
||||
tempTargetSet: Boolean,
|
||||
microBolusAllowed: Boolean,
|
||||
uamAllowed: Boolean,
|
||||
advancedFiltering: Boolean,
|
||||
isSaveCgmSource: Boolean
|
||||
) {
|
||||
val pump = activePlugin.activePump
|
||||
val pumpBolusStep = pump.pumpDescription.bolusStep
|
||||
|
|
|
@ -10,6 +10,7 @@ class DetermineBasalResultSMB private constructor(injector: HasAndroidInjector)
|
|||
|
||||
private var eventualBG = 0.0
|
||||
private var snoozeBG = 0.0
|
||||
var variableSens: Double? = null
|
||||
|
||||
internal constructor(injector: HasAndroidInjector, result: JSONObject) : this(injector) {
|
||||
date = dateUtil.now()
|
||||
|
@ -50,6 +51,7 @@ class DetermineBasalResultSMB private constructor(injector: HasAndroidInjector)
|
|||
aapsLogger.error(LTag.APS, "Error parsing 'deliverAt' date: $date", e)
|
||||
}
|
||||
}
|
||||
if (result.has("variable_sens")) variableSens = result.getDouble("variable_sens");
|
||||
} catch (e: JSONException) {
|
||||
aapsLogger.error(LTag.APS, "Error parsing determine-basal result JSON", e)
|
||||
}
|
||||
|
|
|
@ -9,8 +9,7 @@ import android.view.ViewGroup
|
|||
import dagger.android.support.DaggerFragment
|
||||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.databinding.OpenapsamaFragmentBinding
|
||||
import info.nightscout.shared.logging.AAPSLogger
|
||||
import info.nightscout.shared.logging.LTag
|
||||
import info.nightscout.androidaps.interfaces.ActivePlugin
|
||||
import info.nightscout.androidaps.plugins.aps.events.EventOpenAPSUpdateGui
|
||||
import info.nightscout.androidaps.plugins.aps.events.EventOpenAPSUpdateResultGui
|
||||
import info.nightscout.androidaps.plugins.bus.RxBus
|
||||
|
@ -19,6 +18,8 @@ import info.nightscout.androidaps.utils.FabricPrivacy
|
|||
import info.nightscout.androidaps.utils.JSONFormatter
|
||||
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 io.reactivex.disposables.CompositeDisposable
|
||||
import io.reactivex.rxkotlin.plusAssign
|
||||
import org.json.JSONArray
|
||||
|
@ -34,7 +35,7 @@ class OpenAPSSMBFragment : DaggerFragment() {
|
|||
@Inject lateinit var rxBus: RxBus
|
||||
@Inject lateinit var rh: ResourceHelper
|
||||
@Inject lateinit var fabricPrivacy: FabricPrivacy
|
||||
@Inject lateinit var openAPSSMBPlugin: OpenAPSSMBPlugin
|
||||
@Inject lateinit var activePlugin: ActivePlugin
|
||||
@Inject lateinit var dateUtil: DateUtil
|
||||
@Inject lateinit var jsonFormatter: JSONFormatter
|
||||
|
||||
|
@ -44,8 +45,7 @@ class OpenAPSSMBFragment : DaggerFragment() {
|
|||
// onDestroyView.
|
||||
private val binding get() = _binding!!
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
|
||||
savedInstanceState: Bundle?): View {
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
|
||||
_binding = OpenapsamaFragmentBinding.inflate(inflater, container, false)
|
||||
return binding.root
|
||||
}
|
||||
|
@ -54,7 +54,7 @@ class OpenAPSSMBFragment : DaggerFragment() {
|
|||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
binding.run.setOnClickListener {
|
||||
openAPSSMBPlugin.invoke("OpenAPSSMB button", false)
|
||||
activePlugin.activeAPS.invoke("OpenAPSSMB button", false)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -92,11 +92,12 @@ class OpenAPSSMBFragment : DaggerFragment() {
|
|||
@Synchronized
|
||||
fun updateGUI() {
|
||||
if (_binding == null) return
|
||||
val openAPSSMBPlugin = activePlugin.activeAPS
|
||||
openAPSSMBPlugin.lastAPSResult?.let { lastAPSResult ->
|
||||
binding.result.text = jsonFormatter.format(lastAPSResult.json)
|
||||
binding.request.text = lastAPSResult.toSpanned()
|
||||
}
|
||||
openAPSSMBPlugin.lastDetermineBasalAdapterSMBJS?.let { determineBasalAdapterSMBJS ->
|
||||
openAPSSMBPlugin.lastDetermineBasalAdapter?.let { determineBasalAdapterSMBJS ->
|
||||
binding.glucosestatus.text = jsonFormatter.format(determineBasalAdapterSMBJS.glucoseStatusParam)
|
||||
binding.currenttemp.text = jsonFormatter.format(determineBasalAdapterSMBJS.currentTempParam)
|
||||
try {
|
||||
|
|
|
@ -10,8 +10,6 @@ import info.nightscout.androidaps.database.AppRepository
|
|||
import info.nightscout.androidaps.database.ValueWrapper
|
||||
import info.nightscout.androidaps.extensions.target
|
||||
import info.nightscout.androidaps.interfaces.*
|
||||
import info.nightscout.shared.logging.AAPSLogger
|
||||
import info.nightscout.shared.logging.LTag
|
||||
import info.nightscout.androidaps.plugins.aps.events.EventOpenAPSUpdateGui
|
||||
import info.nightscout.androidaps.plugins.aps.events.EventOpenAPSUpdateResultGui
|
||||
import info.nightscout.androidaps.plugins.aps.loop.ScriptReader
|
||||
|
@ -24,6 +22,8 @@ import info.nightscout.androidaps.utils.HardLimits
|
|||
import info.nightscout.androidaps.utils.Profiler
|
||||
import info.nightscout.androidaps.utils.Round
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||
import info.nightscout.shared.logging.AAPSLogger
|
||||
import info.nightscout.shared.logging.LTag
|
||||
import info.nightscout.shared.sharedPreferences.SP
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
@ -37,7 +37,7 @@ class OpenAPSSMBPlugin @Inject constructor(
|
|||
private val constraintChecker: ConstraintChecker,
|
||||
rh: ResourceHelper,
|
||||
private val profileFunction: ProfileFunction,
|
||||
private val context: Context,
|
||||
val context: Context,
|
||||
private val activePlugin: ActivePlugin,
|
||||
private val iobCobCalculator: IobCobCalculator,
|
||||
private val hardLimits: HardLimits,
|
||||
|
@ -46,23 +46,24 @@ class OpenAPSSMBPlugin @Inject constructor(
|
|||
private val dateUtil: DateUtil,
|
||||
private val repository: AppRepository,
|
||||
private val glucoseStatusProvider: GlucoseStatusProvider
|
||||
) : PluginBase(PluginDescription()
|
||||
.mainType(PluginType.APS)
|
||||
.fragmentClass(OpenAPSSMBFragment::class.java.name)
|
||||
.pluginIcon(R.drawable.ic_generic_icon)
|
||||
.pluginName(R.string.openapssmb)
|
||||
.shortName(R.string.smb_shortname)
|
||||
.preferencesId(R.xml.pref_openapssmb)
|
||||
.description(R.string.description_smb)
|
||||
.setDefault(),
|
||||
) : PluginBase(
|
||||
PluginDescription()
|
||||
.mainType(PluginType.APS)
|
||||
.fragmentClass(OpenAPSSMBFragment::class.java.name)
|
||||
.pluginIcon(R.drawable.ic_generic_icon)
|
||||
.pluginName(R.string.openapssmb)
|
||||
.shortName(R.string.smb_shortname)
|
||||
.preferencesId(R.xml.pref_openapssmb)
|
||||
.description(R.string.description_smb)
|
||||
.setDefault(),
|
||||
aapsLogger, rh, injector
|
||||
), APS, Constraints {
|
||||
|
||||
// last values
|
||||
override var lastAPSRun: Long = 0
|
||||
override var lastAPSResult: DetermineBasalResultSMB? = null
|
||||
var lastDetermineBasalAdapterSMBJS: DetermineBasalAdapterSMBJS? = null
|
||||
var lastAutosensResult = AutosensResult()
|
||||
override var lastDetermineBasalAdapter: DetermineBasalAdapterInterface? = null
|
||||
override var lastAutosensResult = AutosensResult()
|
||||
|
||||
override fun specialEnableCondition(): Boolean {
|
||||
return try {
|
||||
|
@ -120,15 +121,34 @@ class OpenAPSSMBPlugin @Inject constructor(
|
|||
}.value()
|
||||
|
||||
var minBg = hardLimits.verifyHardLimits(Round.roundTo(profile.getTargetLowMgdl(), 0.1), R.string.profile_low_target, HardLimits.VERY_HARD_LIMIT_MIN_BG[0], HardLimits.VERY_HARD_LIMIT_MIN_BG[1])
|
||||
var maxBg = hardLimits.verifyHardLimits(Round.roundTo(profile.getTargetHighMgdl(), 0.1), R.string.profile_high_target, HardLimits.VERY_HARD_LIMIT_MAX_BG[0], HardLimits.VERY_HARD_LIMIT_MAX_BG[1])
|
||||
var maxBg =
|
||||
hardLimits.verifyHardLimits(Round.roundTo(profile.getTargetHighMgdl(), 0.1), R.string.profile_high_target, HardLimits.VERY_HARD_LIMIT_MAX_BG[0], HardLimits.VERY_HARD_LIMIT_MAX_BG[1])
|
||||
var targetBg = hardLimits.verifyHardLimits(profile.getTargetMgdl(), R.string.temp_target_value, HardLimits.VERY_HARD_LIMIT_TARGET_BG[0], HardLimits.VERY_HARD_LIMIT_TARGET_BG[1])
|
||||
var isTempTarget = false
|
||||
val tempTarget = repository.getTemporaryTargetActiveAt(dateUtil.now()).blockingGet()
|
||||
if (tempTarget is ValueWrapper.Existing) {
|
||||
isTempTarget = true
|
||||
minBg = hardLimits.verifyHardLimits(tempTarget.value.lowTarget, R.string.temp_target_low_target, HardLimits.VERY_HARD_LIMIT_TEMP_MIN_BG[0].toDouble(), HardLimits.VERY_HARD_LIMIT_TEMP_MIN_BG[1].toDouble())
|
||||
maxBg = hardLimits.verifyHardLimits(tempTarget.value.highTarget, R.string.temp_target_high_target, HardLimits.VERY_HARD_LIMIT_TEMP_MAX_BG[0].toDouble(), HardLimits.VERY_HARD_LIMIT_TEMP_MAX_BG[1].toDouble())
|
||||
targetBg = hardLimits.verifyHardLimits(tempTarget.value.target(), R.string.temp_target_value, HardLimits.VERY_HARD_LIMIT_TEMP_TARGET_BG[0].toDouble(), HardLimits.VERY_HARD_LIMIT_TEMP_TARGET_BG[1].toDouble())
|
||||
minBg =
|
||||
hardLimits.verifyHardLimits(
|
||||
tempTarget.value.lowTarget,
|
||||
R.string.temp_target_low_target,
|
||||
HardLimits.VERY_HARD_LIMIT_TEMP_MIN_BG[0].toDouble(),
|
||||
HardLimits.VERY_HARD_LIMIT_TEMP_MIN_BG[1].toDouble()
|
||||
)
|
||||
maxBg =
|
||||
hardLimits.verifyHardLimits(
|
||||
tempTarget.value.highTarget,
|
||||
R.string.temp_target_high_target,
|
||||
HardLimits.VERY_HARD_LIMIT_TEMP_MAX_BG[0].toDouble(),
|
||||
HardLimits.VERY_HARD_LIMIT_TEMP_MAX_BG[1].toDouble()
|
||||
)
|
||||
targetBg =
|
||||
hardLimits.verifyHardLimits(
|
||||
tempTarget.value.target(),
|
||||
R.string.temp_target_value,
|
||||
HardLimits.VERY_HARD_LIMIT_TEMP_TARGET_BG[0].toDouble(),
|
||||
HardLimits.VERY_HARD_LIMIT_TEMP_TARGET_BG[1].toDouble()
|
||||
)
|
||||
}
|
||||
if (!hardLimits.checkHardLimits(profile.dia, R.string.profile_dia, hardLimits.minDia(), hardLimits.maxDia())) return
|
||||
if (!hardLimits.checkHardLimits(profile.getIcTimeFromMidnight(Profile.secondsFromMidnight()), R.string.profile_carbs_ratio_value, hardLimits.minIC(), hardLimits.maxIC())) return
|
||||
|
@ -165,8 +185,9 @@ class OpenAPSSMBPlugin @Inject constructor(
|
|||
profiler.log(LTag.APS, "SMB data gathering", start)
|
||||
start = System.currentTimeMillis()
|
||||
|
||||
DetermineBasalAdapterSMBJS(ScriptReader(context), injector).also { determineBasalAdapterSMBJS ->
|
||||
determineBasalAdapterSMBJS.setData(profile, maxIob, maxBasal, minBg, maxBg, targetBg,
|
||||
provideDetermineBasalAdapter().also { determineBasalAdapterSMBJS ->
|
||||
determineBasalAdapterSMBJS.setData(
|
||||
profile, maxIob, maxBasal, minBg, maxBg, targetBg,
|
||||
activePlugin.activePump.baseBasalRate,
|
||||
iobArray,
|
||||
glucoseStatus,
|
||||
|
@ -176,24 +197,26 @@ class OpenAPSSMBPlugin @Inject constructor(
|
|||
smbAllowed.value(),
|
||||
uam.value(),
|
||||
advancedFiltering.value(),
|
||||
activePlugin.activeBgSource.javaClass.simpleName == "DexcomPlugin")
|
||||
activePlugin.activeBgSource.javaClass.simpleName == "DexcomPlugin"
|
||||
)
|
||||
val now = System.currentTimeMillis()
|
||||
val determineBasalResultSMB = determineBasalAdapterSMBJS.invoke()
|
||||
profiler.log(LTag.APS, "SMB calculation", start)
|
||||
if (determineBasalResultSMB == null) {
|
||||
aapsLogger.error(LTag.APS, "SMB calculation returned null")
|
||||
lastDetermineBasalAdapterSMBJS = null
|
||||
lastDetermineBasalAdapter = null
|
||||
lastAPSResult = null
|
||||
lastAPSRun = 0
|
||||
} else {
|
||||
// TODO still needed with oref1?
|
||||
// Fix bug determine basal
|
||||
if (determineBasalResultSMB.rate == 0.0 && determineBasalResultSMB.duration == 0 && iobCobCalculator.getTempBasalIncludingConvertedExtended(dateUtil.now()) == null) determineBasalResultSMB.tempBasalRequested = false
|
||||
if (determineBasalResultSMB.rate == 0.0 && determineBasalResultSMB.duration == 0 && iobCobCalculator.getTempBasalIncludingConvertedExtended(dateUtil.now()) == null) determineBasalResultSMB.tempBasalRequested =
|
||||
false
|
||||
determineBasalResultSMB.iob = iobArray[0]
|
||||
determineBasalResultSMB.json?.put("timestamp", dateUtil.toISOString(now))
|
||||
determineBasalResultSMB.inputConstraints = inputConstraints
|
||||
lastDetermineBasalAdapterSMBJS = determineBasalAdapterSMBJS
|
||||
lastAPSResult = determineBasalResultSMB
|
||||
lastDetermineBasalAdapter = determineBasalAdapterSMBJS
|
||||
lastAPSResult = determineBasalResultSMB as DetermineBasalResultSMB
|
||||
lastAPSRun = now
|
||||
}
|
||||
}
|
||||
|
@ -204,4 +227,6 @@ class OpenAPSSMBPlugin @Inject constructor(
|
|||
value.set(aapsLogger, false)
|
||||
return value
|
||||
}
|
||||
|
||||
fun provideDetermineBasalAdapter(): DetermineBasalAdapterInterface = DetermineBasalAdapterSMBJS(ScriptReader(context), injector)
|
||||
}
|
|
@ -0,0 +1,296 @@
|
|||
package info.nightscout.androidaps.plugins.aps.openAPSSMBDynamicISF
|
||||
|
||||
import dagger.android.HasAndroidInjector
|
||||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.data.IobTotal
|
||||
import info.nightscout.androidaps.data.MealData
|
||||
import info.nightscout.androidaps.database.AppRepository
|
||||
import info.nightscout.androidaps.extensions.convertedToAbsolute
|
||||
import info.nightscout.androidaps.extensions.getPassedDurationToTimeInMinutes
|
||||
import info.nightscout.androidaps.extensions.plannedRemainingMinutes
|
||||
import info.nightscout.androidaps.interfaces.ActivePlugin
|
||||
import info.nightscout.androidaps.interfaces.GlucoseUnit
|
||||
import info.nightscout.androidaps.interfaces.IobCobCalculator
|
||||
import info.nightscout.androidaps.interfaces.Profile
|
||||
import info.nightscout.androidaps.interfaces.ProfileFunction
|
||||
import info.nightscout.androidaps.plugins.aps.logger.LoggerCallback
|
||||
import info.nightscout.androidaps.plugins.aps.loop.ScriptReader
|
||||
import info.nightscout.androidaps.interfaces.DetermineBasalAdapterInterface
|
||||
import info.nightscout.androidaps.plugins.aps.openAPSSMB.DetermineBasalResultSMB
|
||||
import info.nightscout.androidaps.plugins.aps.openAPSSMB.SMBDefaults
|
||||
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
|
||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus
|
||||
import info.nightscout.androidaps.utils.DateUtil
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||
import info.nightscout.androidaps.utils.stats.TddCalculator
|
||||
import info.nightscout.shared.SafeParse
|
||||
import info.nightscout.shared.logging.AAPSLogger
|
||||
import info.nightscout.shared.logging.LTag
|
||||
import info.nightscout.shared.sharedPreferences.SP
|
||||
import org.json.JSONArray
|
||||
import org.json.JSONException
|
||||
import org.json.JSONObject
|
||||
import org.mozilla.javascript.*
|
||||
import org.mozilla.javascript.Function
|
||||
import java.io.IOException
|
||||
import java.lang.reflect.InvocationTargetException
|
||||
import java.nio.charset.StandardCharsets
|
||||
import javax.inject.Inject
|
||||
|
||||
class DetermineBasalAdapterSMBDynamicISFJS internal constructor(private val scriptReader: ScriptReader, private val injector: HasAndroidInjector) : DetermineBasalAdapterInterface {
|
||||
|
||||
@Inject lateinit var aapsLogger: AAPSLogger
|
||||
@Inject lateinit var constraintChecker: ConstraintChecker
|
||||
@Inject lateinit var sp: SP
|
||||
@Inject lateinit var rh: ResourceHelper
|
||||
@Inject lateinit var profileFunction: ProfileFunction
|
||||
@Inject lateinit var iobCobCalculator: IobCobCalculator
|
||||
@Inject lateinit var activePlugin: ActivePlugin
|
||||
@Inject lateinit var repository: AppRepository
|
||||
@Inject lateinit var dateUtil: DateUtil
|
||||
@Inject lateinit var tddCalculator: TddCalculator
|
||||
|
||||
private var profile = JSONObject()
|
||||
private var mGlucoseStatus = JSONObject()
|
||||
private var iobData: JSONArray? = null
|
||||
private var mealData = JSONObject()
|
||||
private var currentTemp = JSONObject()
|
||||
private var autosensData = JSONObject()
|
||||
private var microBolusAllowed = false
|
||||
private var smbAlwaysAllowed = false
|
||||
private var currentTime: Long = 0
|
||||
private var saveCgmSource = false
|
||||
|
||||
override var currentTempParam: String? = null
|
||||
override var iobDataParam: String? = null
|
||||
override var glucoseStatusParam: String? = null
|
||||
override var profileParam: String? = null
|
||||
override var mealDataParam: String? = null
|
||||
override var scriptDebug = ""
|
||||
|
||||
@Suppress("SpellCheckingInspection")
|
||||
override operator fun invoke(): DetermineBasalResultSMB? {
|
||||
aapsLogger.debug(LTag.APS, ">>> Invoking determine_basal <<<")
|
||||
aapsLogger.debug(LTag.APS, "Glucose status: " + mGlucoseStatus.toString().also { glucoseStatusParam = it })
|
||||
aapsLogger.debug(LTag.APS, "IOB data: " + iobData.toString().also { iobDataParam = it })
|
||||
aapsLogger.debug(LTag.APS, "Current temp: " + currentTemp.toString().also { currentTempParam = it })
|
||||
aapsLogger.debug(LTag.APS, "Profile: " + profile.toString().also { profileParam = it })
|
||||
aapsLogger.debug(LTag.APS, "Meal data: " + mealData.toString().also { mealDataParam = it })
|
||||
aapsLogger.debug(LTag.APS, "Autosens data: $autosensData")
|
||||
aapsLogger.debug(LTag.APS, "Reservoir data: " + "undefined")
|
||||
aapsLogger.debug(LTag.APS, "MicroBolusAllowed: $microBolusAllowed")
|
||||
aapsLogger.debug(LTag.APS, "SMBAlwaysAllowed: $smbAlwaysAllowed")
|
||||
aapsLogger.debug(LTag.APS, "CurrentTime: $currentTime")
|
||||
aapsLogger.debug(LTag.APS, "isSaveCgmSource: $saveCgmSource")
|
||||
var determineBasalResultSMB: DetermineBasalResultSMB? = null
|
||||
val rhino = Context.enter()
|
||||
val scope: Scriptable = rhino.initStandardObjects()
|
||||
// Turn off optimization to make Rhino Android compatible
|
||||
rhino.optimizationLevel = -1
|
||||
try {
|
||||
|
||||
//register logger callback for console.log and console.error
|
||||
ScriptableObject.defineClass(scope, LoggerCallback::class.java)
|
||||
val myLogger = rhino.newObject(scope, "LoggerCallback", null)
|
||||
scope.put("console2", scope, myLogger)
|
||||
rhino.evaluateString(scope, readFile("OpenAPSAMA/loggerhelper.js"), "JavaScript", 0, null)
|
||||
|
||||
//set module parent
|
||||
rhino.evaluateString(scope, "var module = {\"parent\":Boolean(1)};", "JavaScript", 0, null)
|
||||
rhino.evaluateString(scope, "var round_basal = function round_basal(basal, profile) { return basal; };", "JavaScript", 0, null)
|
||||
rhino.evaluateString(scope, "require = function() {return round_basal;};", "JavaScript", 0, null)
|
||||
|
||||
//generate functions "determine_basal" and "setTempBasal"
|
||||
rhino.evaluateString(scope, readFile("OpenAPSSMBDynamicISF/determine-basal.js"), "JavaScript", 0, null)
|
||||
rhino.evaluateString(scope, readFile("OpenAPSSMB/basal-set-temp.js"), "setTempBasal.js", 0, null)
|
||||
val determineBasalObj = scope["determine_basal", scope]
|
||||
val setTempBasalFunctionsObj = scope["tempBasalFunctions", scope]
|
||||
|
||||
//call determine-basal
|
||||
if (determineBasalObj is Function && setTempBasalFunctionsObj is NativeObject) {
|
||||
|
||||
//prepare parameters
|
||||
val params = arrayOf(
|
||||
makeParam(mGlucoseStatus, rhino, scope),
|
||||
makeParam(currentTemp, rhino, scope),
|
||||
makeParamArray(iobData, rhino, scope),
|
||||
makeParam(profile, rhino, scope),
|
||||
makeParam(autosensData, rhino, scope),
|
||||
makeParam(mealData, rhino, scope),
|
||||
setTempBasalFunctionsObj,
|
||||
java.lang.Boolean.valueOf(microBolusAllowed),
|
||||
makeParam(null, rhino, scope), // reservoir data as undefined
|
||||
java.lang.Long.valueOf(currentTime),
|
||||
java.lang.Boolean.valueOf(saveCgmSource)
|
||||
)
|
||||
val jsResult = determineBasalObj.call(rhino, scope, scope, params) as NativeObject
|
||||
scriptDebug = LoggerCallback.scriptDebug
|
||||
|
||||
// Parse the jsResult object to a JSON-String
|
||||
val result = NativeJSON.stringify(rhino, scope, jsResult, null, null).toString()
|
||||
aapsLogger.debug(LTag.APS, "Result: $result")
|
||||
try {
|
||||
val resultJson = JSONObject(result)
|
||||
determineBasalResultSMB = DetermineBasalResultSMB(injector, resultJson)
|
||||
} catch (e: JSONException) {
|
||||
aapsLogger.error(LTag.APS, "Unhandled exception", e)
|
||||
}
|
||||
} else {
|
||||
aapsLogger.error(LTag.APS, "Problem loading JS Functions")
|
||||
}
|
||||
} catch (e: IOException) {
|
||||
aapsLogger.error(LTag.APS, "IOException")
|
||||
} catch (e: RhinoException) {
|
||||
aapsLogger.error(LTag.APS, "RhinoException: (" + e.lineNumber() + "," + e.columnNumber() + ") " + e.toString())
|
||||
} catch (e: IllegalAccessException) {
|
||||
aapsLogger.error(LTag.APS, e.toString())
|
||||
} catch (e: InstantiationException) {
|
||||
aapsLogger.error(LTag.APS, e.toString())
|
||||
} catch (e: InvocationTargetException) {
|
||||
aapsLogger.error(LTag.APS, e.toString())
|
||||
} finally {
|
||||
Context.exit()
|
||||
}
|
||||
glucoseStatusParam = mGlucoseStatus.toString()
|
||||
iobDataParam = iobData.toString()
|
||||
currentTempParam = currentTemp.toString()
|
||||
profileParam = profile.toString()
|
||||
mealDataParam = mealData.toString()
|
||||
return determineBasalResultSMB
|
||||
}
|
||||
|
||||
@Suppress("SpellCheckingInspection")
|
||||
override fun setData(
|
||||
profile: Profile,
|
||||
maxIob: Double,
|
||||
maxBasal: Double,
|
||||
minBg: Double,
|
||||
maxBg: Double,
|
||||
targetBg: Double,
|
||||
basalRate: Double,
|
||||
iobArray: Array<IobTotal>,
|
||||
glucoseStatus: GlucoseStatus,
|
||||
mealData: MealData,
|
||||
autosensDataRatio: Double,
|
||||
tempTargetSet: Boolean,
|
||||
microBolusAllowed: Boolean,
|
||||
uamAllowed: Boolean,
|
||||
advancedFiltering: Boolean,
|
||||
isSaveCgmSource: Boolean
|
||||
) {
|
||||
val pump = activePlugin.activePump
|
||||
val pumpBolusStep = pump.pumpDescription.bolusStep
|
||||
this.profile.put("max_iob", maxIob)
|
||||
//mProfile.put("dia", profile.getDia());
|
||||
this.profile.put("type", "current")
|
||||
this.profile.put("max_daily_basal", profile.getMaxDailyBasal())
|
||||
this.profile.put("max_basal", maxBasal)
|
||||
this.profile.put("min_bg", minBg)
|
||||
this.profile.put("max_bg", maxBg)
|
||||
this.profile.put("target_bg", targetBg)
|
||||
this.profile.put("carb_ratio", profile.getIc())
|
||||
this.profile.put("sens", profile.getIsfMgdl())
|
||||
this.profile.put("max_daily_safety_multiplier", sp.getInt(R.string.key_openapsama_max_daily_safety_multiplier, 3))
|
||||
this.profile.put("current_basal_safety_multiplier", sp.getDouble(R.string.key_openapsama_current_basal_safety_multiplier, 4.0))
|
||||
|
||||
//mProfile.put("high_temptarget_raises_sensitivity", SP.getBoolean(R.string.key_high_temptarget_raises_sensitivity, SMBDefaults.high_temptarget_raises_sensitivity));
|
||||
this.profile.put("high_temptarget_raises_sensitivity", false)
|
||||
//mProfile.put("low_temptarget_lowers_sensitivity", SP.getBoolean(R.string.key_low_temptarget_lowers_sensitivity, SMBDefaults.low_temptarget_lowers_sensitivity));
|
||||
this.profile.put("low_temptarget_lowers_sensitivity", false)
|
||||
this.profile.put("sensitivity_raises_target", sp.getBoolean(R.string.key_sensitivity_raises_target, SMBDefaults.sensitivity_raises_target))
|
||||
this.profile.put("resistance_lowers_target", sp.getBoolean(R.string.key_resistance_lowers_target, SMBDefaults.resistance_lowers_target))
|
||||
this.profile.put("adv_target_adjustments", SMBDefaults.adv_target_adjustments)
|
||||
this.profile.put("exercise_mode", SMBDefaults.exercise_mode)
|
||||
this.profile.put("half_basal_exercise_target", SMBDefaults.half_basal_exercise_target)
|
||||
this.profile.put("maxCOB", SMBDefaults.maxCOB)
|
||||
this.profile.put("skip_neutral_temps", pump.setNeutralTempAtFullHour())
|
||||
// min_5m_carbimpact is not used within SMB determinebasal
|
||||
//if (mealData.usedMinCarbsImpact > 0) {
|
||||
// mProfile.put("min_5m_carbimpact", mealData.usedMinCarbsImpact);
|
||||
//} else {
|
||||
// mProfile.put("min_5m_carbimpact", SP.getDouble(R.string.key_openapsama_min_5m_carbimpact, SMBDefaults.min_5m_carbimpact));
|
||||
//}
|
||||
this.profile.put("remainingCarbsCap", SMBDefaults.remainingCarbsCap)
|
||||
this.profile.put("enableUAM", uamAllowed)
|
||||
this.profile.put("A52_risk_enable", SMBDefaults.A52_risk_enable)
|
||||
val smbEnabled = sp.getBoolean(R.string.key_use_smb, false)
|
||||
this.profile.put("SMBInterval", sp.getInt(R.string.key_smbinterval, SMBDefaults.SMBInterval))
|
||||
this.profile.put("enableSMB_with_COB", smbEnabled && sp.getBoolean(R.string.key_enableSMB_with_COB, false))
|
||||
this.profile.put("enableSMB_with_temptarget", smbEnabled && sp.getBoolean(R.string.key_enableSMB_with_temptarget, false))
|
||||
this.profile.put("allowSMB_with_high_temptarget", smbEnabled && sp.getBoolean(R.string.key_allowSMB_with_high_temptarget, false))
|
||||
this.profile.put("enableSMB_always", smbEnabled && sp.getBoolean(R.string.key_enableSMB_always, false) && advancedFiltering)
|
||||
this.profile.put("enableSMB_after_carbs", smbEnabled && sp.getBoolean(R.string.key_enableSMB_after_carbs, false) && advancedFiltering)
|
||||
this.profile.put("maxSMBBasalMinutes", sp.getInt(R.string.key_smbmaxminutes, SMBDefaults.maxSMBBasalMinutes))
|
||||
this.profile.put("maxUAMSMBBasalMinutes", sp.getInt(R.string.key_uamsmbmaxminutes, SMBDefaults.maxUAMSMBBasalMinutes))
|
||||
//set the min SMB amount to be the amount set by the pump.
|
||||
this.profile.put("bolus_increment", pumpBolusStep)
|
||||
this.profile.put("carbsReqThreshold", sp.getInt(R.string.key_carbsReqThreshold, SMBDefaults.carbsReqThreshold))
|
||||
this.profile.put("current_basal", basalRate)
|
||||
this.profile.put("temptargetSet", tempTargetSet)
|
||||
this.profile.put("autosens_max", SafeParse.stringToDouble(sp.getString(R.string.key_openapsama_autosens_max, "1.2")))
|
||||
if (profileFunction.getUnits() == GlucoseUnit.MMOL) {
|
||||
this.profile.put("out_units", "mmol/L")
|
||||
}
|
||||
val now = System.currentTimeMillis()
|
||||
val tb = iobCobCalculator.getTempBasalIncludingConvertedExtended(now)
|
||||
currentTemp.put("temp", "absolute")
|
||||
currentTemp.put("duration", tb?.plannedRemainingMinutes ?: 0)
|
||||
currentTemp.put("rate", tb?.convertedToAbsolute(now, profile) ?: 0.0)
|
||||
// as we have non default temps longer than 30 mintues
|
||||
if (tb != null) currentTemp.put("minutesrunning", tb.getPassedDurationToTimeInMinutes(now))
|
||||
|
||||
iobData = iobCobCalculator.convertToJSONArray(iobArray)
|
||||
mGlucoseStatus.put("glucose", glucoseStatus.glucose)
|
||||
mGlucoseStatus.put("noise", glucoseStatus.noise)
|
||||
if (sp.getBoolean(R.string.key_always_use_shortavg, false)) {
|
||||
mGlucoseStatus.put("delta", glucoseStatus.shortAvgDelta)
|
||||
} else {
|
||||
mGlucoseStatus.put("delta", glucoseStatus.delta)
|
||||
}
|
||||
|
||||
mGlucoseStatus.put("short_avgdelta", glucoseStatus.shortAvgDelta)
|
||||
mGlucoseStatus.put("long_avgdelta", glucoseStatus.longAvgDelta)
|
||||
mGlucoseStatus.put("date", glucoseStatus.date)
|
||||
this.mealData.put("carbs", mealData.carbs)
|
||||
this.mealData.put("mealCOB", mealData.mealCOB)
|
||||
this.mealData.put("slopeFromMaxDeviation", mealData.slopeFromMaxDeviation)
|
||||
this.mealData.put("slopeFromMinDeviation", mealData.slopeFromMinDeviation)
|
||||
this.mealData.put("lastBolusTime", mealData.lastBolusTime)
|
||||
this.mealData.put("lastCarbTime", mealData.lastCarbTime)
|
||||
|
||||
this.mealData.put("TDDAIMI7", tddCalculator.averageTDD(tddCalculator.calculate(7)).totalAmount)
|
||||
this.mealData.put("TDDPUMP", tddCalculator.calculateDaily().totalAmount)
|
||||
|
||||
if (constraintChecker.isAutosensModeEnabled().value()) {
|
||||
autosensData.put("ratio", autosensDataRatio)
|
||||
} else {
|
||||
autosensData.put("ratio", 1.0)
|
||||
}
|
||||
this.microBolusAllowed = microBolusAllowed
|
||||
smbAlwaysAllowed = advancedFiltering
|
||||
currentTime = now
|
||||
saveCgmSource = isSaveCgmSource
|
||||
}
|
||||
|
||||
private fun makeParam(jsonObject: JSONObject?, rhino: Context, scope: Scriptable): Any {
|
||||
return if (jsonObject == null) Undefined.instance
|
||||
else NativeJSON.parse(rhino, scope, jsonObject.toString()) { _: Context?, _: Scriptable?, _: Scriptable?, objects: Array<Any?> -> objects[1] }
|
||||
}
|
||||
|
||||
private fun makeParamArray(jsonArray: JSONArray?, rhino: Context, scope: Scriptable): Any {
|
||||
return NativeJSON.parse(rhino, scope, jsonArray.toString()) { _: Context?, _: Scriptable?, _: Scriptable?, objects: Array<Any?> -> objects[1] }
|
||||
}
|
||||
|
||||
@Throws(IOException::class) private fun readFile(filename: String): String {
|
||||
val bytes = scriptReader.readFile(filename)
|
||||
var string = String(bytes, StandardCharsets.UTF_8)
|
||||
if (string.startsWith("#!/usr/bin/env node")) {
|
||||
string = string.substring(20)
|
||||
}
|
||||
return string
|
||||
}
|
||||
|
||||
init {
|
||||
injector.androidInjector().inject(this)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
package info.nightscout.androidaps.plugins.aps.openAPSSMBDynamicISF
|
||||
|
||||
import android.content.Context
|
||||
import dagger.android.HasAndroidInjector
|
||||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.annotations.OpenForTesting
|
||||
import info.nightscout.androidaps.database.AppRepository
|
||||
import info.nightscout.androidaps.interfaces.ActivePlugin
|
||||
import info.nightscout.androidaps.interfaces.IobCobCalculator
|
||||
import info.nightscout.androidaps.interfaces.ProfileFunction
|
||||
import info.nightscout.androidaps.plugins.aps.loop.ScriptReader
|
||||
import info.nightscout.androidaps.interfaces.DetermineBasalAdapterInterface
|
||||
import info.nightscout.androidaps.plugins.aps.openAPSSMB.OpenAPSSMBPlugin
|
||||
import info.nightscout.androidaps.plugins.bus.RxBus
|
||||
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
|
||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatusProvider
|
||||
import info.nightscout.androidaps.utils.DateUtil
|
||||
import info.nightscout.androidaps.utils.HardLimits
|
||||
import info.nightscout.androidaps.utils.Profiler
|
||||
import info.nightscout.androidaps.utils.buildHelper.BuildHelper
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||
import info.nightscout.shared.logging.AAPSLogger
|
||||
import info.nightscout.shared.sharedPreferences.SP
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@OpenForTesting
|
||||
@Singleton
|
||||
class OpenAPSSMBDynamicISFPlugin @Inject constructor(
|
||||
injector: HasAndroidInjector,
|
||||
aapsLogger: AAPSLogger,
|
||||
rxBus: RxBus,
|
||||
constraintChecker: ConstraintChecker,
|
||||
rh: ResourceHelper,
|
||||
profileFunction: ProfileFunction,
|
||||
context: Context,
|
||||
activePlugin: ActivePlugin,
|
||||
iobCobCalculator: IobCobCalculator,
|
||||
hardLimits: HardLimits,
|
||||
profiler: Profiler,
|
||||
sp: SP,
|
||||
dateUtil: DateUtil,
|
||||
repository: AppRepository,
|
||||
glucoseStatusProvider: GlucoseStatusProvider,
|
||||
private val buildHelper: BuildHelper
|
||||
) : OpenAPSSMBPlugin(
|
||||
injector,
|
||||
aapsLogger,
|
||||
rxBus,
|
||||
constraintChecker,
|
||||
rh,
|
||||
profileFunction,
|
||||
context,
|
||||
activePlugin,
|
||||
iobCobCalculator,
|
||||
hardLimits,
|
||||
profiler,
|
||||
sp,
|
||||
dateUtil,
|
||||
repository,
|
||||
glucoseStatusProvider
|
||||
) {
|
||||
|
||||
init {
|
||||
pluginDescription
|
||||
.pluginName(R.string.openaps_smb_dynamic_isf)
|
||||
.description(R.string.description_smb_dynamic_isf)
|
||||
.setDefault(false)
|
||||
}
|
||||
|
||||
override fun specialEnableCondition(): Boolean = buildHelper.isEngineeringMode() && buildHelper.isDev()
|
||||
|
||||
override fun provideDetermineBasalAdapter(): DetermineBasalAdapterInterface = DetermineBasalAdapterSMBDynamicISFJS(ScriptReader(context), injector)
|
||||
}
|
|
@ -48,6 +48,7 @@ import info.nightscout.androidaps.interfaces.*
|
|||
import info.nightscout.shared.logging.AAPSLogger
|
||||
import info.nightscout.androidaps.logging.UserEntryLogger
|
||||
import info.nightscout.androidaps.plugins.aps.loop.events.EventNewOpenLoopNotification
|
||||
import info.nightscout.androidaps.plugins.aps.openAPSSMB.DetermineBasalResultSMB
|
||||
import info.nightscout.androidaps.plugins.bus.RxBus
|
||||
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
|
||||
import info.nightscout.androidaps.plugins.constraints.bgQualityCheck.BgQualityCheckPlugin
|
||||
|
@ -603,7 +604,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
|
|||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||
binding.infoLayout.apsMode.stateDescription = rh.gs(stringRes)
|
||||
} else {
|
||||
binding.infoLayout.apsMode.contentDescription = rh.gs(R.string.apsmode_title) + " " + rh.gs(stringRes)
|
||||
binding.infoLayout.apsMode.contentDescription = rh.gs(R.string.apsmode_title) + " " + rh.gs(stringRes)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -671,6 +672,21 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
|
|||
binding.infoLayout.apsModeText.visibility = View.GONE
|
||||
}
|
||||
}
|
||||
// Show variable sensitivity
|
||||
val request = loop.lastRun?.request
|
||||
if (request is DetermineBasalResultSMB) {
|
||||
val isfMgdl = profileFunction.getProfile()?.getIsfMgdl()
|
||||
val variableSens = request.variableSens
|
||||
if (variableSens != isfMgdl && variableSens != null && isfMgdl != null) {
|
||||
binding.infoLayout.variableSensitivity.text =
|
||||
String.format(
|
||||
Locale.getDefault(), "%1$.1f→%2$.1f",
|
||||
Profile.toUnits(isfMgdl, isfMgdl * Constants.MGDL_TO_MMOLL, profileFunction.getUnits()),
|
||||
Profile.toUnits(variableSens, variableSens * Constants.MGDL_TO_MMOLL, profileFunction.getUnits())
|
||||
)
|
||||
binding.infoLayout.variableSensitivity.visibility = View.VISIBLE
|
||||
} else binding.infoLayout.variableSensitivity.visibility = View.GONE
|
||||
} else binding.infoLayout.variableSensitivity.visibility = View.GONE
|
||||
} else {
|
||||
//nsclient
|
||||
binding.infoLayout.apsMode.visibility = View.GONE
|
||||
|
@ -774,7 +790,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
|
|||
|
||||
val outDate = (if (!overviewData.isActualBg) rh.gs(R.string.a11y_bg_outdated) else "")
|
||||
binding.infoLayout.bg.contentDescription =
|
||||
rh.gs(R.string.a11y_blood_glucose) + " " + binding.infoLayout.bg.text.toString() + " " + overviewData.lastBgDescription + " " + outDate
|
||||
rh.gs(R.string.a11y_blood_glucose) + " " + binding.infoLayout.bg.text.toString() + " " + overviewData.lastBgDescription + " " + outDate
|
||||
|
||||
binding.infoLayout.timeAgo.text = dateUtil.minAgo(rh, overviewData.lastBg?.timestamp)
|
||||
binding.infoLayout.timeAgo.contentDescription = dateUtil.minAgoLong(rh, overviewData.lastBg?.timestamp)
|
||||
|
|
|
@ -1,12 +1,18 @@
|
|||
package info.nightscout.androidaps.plugins.general.overview.activities
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.view.LayoutInflater
|
||||
import android.view.MotionEvent
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.Button
|
||||
import android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
import androidx.fragment.app.FragmentManager
|
||||
import androidx.recyclerview.widget.ItemTouchHelper
|
||||
import androidx.recyclerview.widget.ItemTouchHelper.*
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import info.nightscout.androidaps.R
|
||||
|
@ -20,6 +26,8 @@ import info.nightscout.androidaps.utils.FabricPrivacy
|
|||
import io.reactivex.rxkotlin.plusAssign
|
||||
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
||||
import info.nightscout.androidaps.utils.wizard.QuickWizard
|
||||
import info.nightscout.androidaps.utils.wizard.QuickWizardEntry
|
||||
import info.nightscout.shared.sharedPreferences.SP
|
||||
import io.reactivex.disposables.CompositeDisposable
|
||||
import javax.inject.Inject
|
||||
|
||||
|
@ -30,20 +38,95 @@ class QuickWizardListActivity : NoSplashAppCompatActivity() {
|
|||
@Inject lateinit var fabricPrivacy: FabricPrivacy
|
||||
@Inject lateinit var quickWizard: QuickWizard
|
||||
@Inject lateinit var dateUtil: DateUtil
|
||||
@Inject lateinit var sp: SP
|
||||
|
||||
private var disposable: CompositeDisposable = CompositeDisposable()
|
||||
|
||||
private lateinit var binding: OverviewQuickwizardlistActivityBinding
|
||||
|
||||
private val itemTouchHelper by lazy {
|
||||
val simpleItemTouchCallback = object : ItemTouchHelper.SimpleCallback(UP or DOWN or START or END, 0) {
|
||||
|
||||
override fun onMove(
|
||||
recyclerView: RecyclerView,
|
||||
viewHolder: RecyclerView.ViewHolder,
|
||||
target: RecyclerView.ViewHolder
|
||||
): Boolean {
|
||||
val adapter = recyclerView.adapter as RecyclerViewAdapter
|
||||
val from = viewHolder.layoutPosition
|
||||
val to = target.layoutPosition
|
||||
adapter.moveItem(from, to)
|
||||
adapter.notifyItemMoved(from, to)
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
|
||||
}
|
||||
|
||||
override fun onSelectedChanged(viewHolder: RecyclerView.ViewHolder?, actionState: Int) {
|
||||
super.onSelectedChanged(viewHolder, actionState)
|
||||
|
||||
if (actionState == ACTION_STATE_DRAG) {
|
||||
viewHolder?.itemView?.alpha = 0.5f
|
||||
}
|
||||
}
|
||||
|
||||
override fun clearView(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder) {
|
||||
super.clearView(recyclerView, viewHolder)
|
||||
|
||||
viewHolder.itemView.alpha = 1.0f
|
||||
|
||||
val adapter = recyclerView.adapter as RecyclerViewAdapter
|
||||
adapter.onDrop()
|
||||
}
|
||||
}
|
||||
|
||||
ItemTouchHelper(simpleItemTouchCallback)
|
||||
}
|
||||
|
||||
fun startDragging(viewHolder: RecyclerView.ViewHolder) {
|
||||
itemTouchHelper.startDrag(viewHolder)
|
||||
}
|
||||
|
||||
private inner class RecyclerViewAdapter(var fragmentManager: FragmentManager) : RecyclerView.Adapter<RecyclerViewAdapter.QuickWizardEntryViewHolder>() {
|
||||
|
||||
@SuppressLint("ClickableViewAccessibility")
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): QuickWizardEntryViewHolder {
|
||||
return QuickWizardEntryViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.overview_quickwizardlist_item, parent, false), fragmentManager)
|
||||
val itemView = LayoutInflater.from(parent.context).inflate(R.layout.overview_quickwizardlist_item, parent, false)
|
||||
val viewHolder = QuickWizardEntryViewHolder(itemView, fragmentManager)
|
||||
|
||||
viewHolder.handleView.setOnTouchListener { _, event ->
|
||||
if (event.actionMasked == MotionEvent.ACTION_DOWN) {
|
||||
startDragging(viewHolder)
|
||||
}
|
||||
return@setOnTouchListener true
|
||||
}
|
||||
|
||||
return viewHolder
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: QuickWizardEntryViewHolder, position: Int) {
|
||||
holder.from.text = dateUtil.timeString(quickWizard[position].validFromDate())
|
||||
holder.to.text = dateUtil.timeString(quickWizard[position].validToDate())
|
||||
val wearControl = sp.getBoolean(R.string.key_wear_control, false)
|
||||
|
||||
if (wearControl) {
|
||||
holder.handleView.visibility = View.VISIBLE
|
||||
} else {
|
||||
holder.handleView.visibility = View.GONE
|
||||
}
|
||||
if (quickWizard[position].device() == QuickWizardEntry.DEVICE_ALL) {
|
||||
holder.device.visibility = View.GONE
|
||||
} else {
|
||||
holder.device.visibility = View.VISIBLE
|
||||
holder.device.setImageResource(
|
||||
when (quickWizard[position].device()) {
|
||||
QuickWizardEntry.DEVICE_WATCH -> R.drawable.ic_watch
|
||||
else -> R.drawable.ic_smartphone
|
||||
}
|
||||
)
|
||||
}
|
||||
holder.buttonText.text = quickWizard[position].buttonText()
|
||||
holder.carbs.text = rh.gs(R.string.format_carbs, quickWizard[position].carbs())
|
||||
}
|
||||
|
@ -55,6 +138,8 @@ class QuickWizardListActivity : NoSplashAppCompatActivity() {
|
|||
val buttonText: TextView = itemView.findViewById(R.id.overview_quickwizard_item_buttonText)
|
||||
val carbs: TextView = itemView.findViewById(R.id.overview_quickwizard_item_carbs)
|
||||
val from: TextView = itemView.findViewById(R.id.overview_quickwizard_item_from)
|
||||
val handleView: ImageView = itemView.findViewById(R.id.handleView)
|
||||
val device: ImageView = itemView.findViewById(R.id.overview_quickwizard_item_device)
|
||||
val to: TextView = itemView.findViewById(R.id.overview_quickwizard_item_to)
|
||||
private val editButton: Button = itemView.findViewById(R.id.overview_quickwizard_item_edit_button)
|
||||
private val removeButton: Button = itemView.findViewById(R.id.overview_quickwizard_item_remove_button)
|
||||
|
@ -74,6 +159,16 @@ class QuickWizardListActivity : NoSplashAppCompatActivity() {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun moveItem(from: Int, to: Int) {
|
||||
Log.i("QuickWizard", "moveItem")
|
||||
quickWizard.move(from, to)
|
||||
}
|
||||
|
||||
fun onDrop() {
|
||||
Log.i("QuickWizard", "onDrop")
|
||||
rxBus.send(EventQuickWizardChange())
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
|
@ -84,6 +179,7 @@ class QuickWizardListActivity : NoSplashAppCompatActivity() {
|
|||
binding.recyclerview.setHasFixedSize(true)
|
||||
binding.recyclerview.layoutManager = LinearLayoutManager(this)
|
||||
binding.recyclerview.adapter = RecyclerViewAdapter(supportFragmentManager)
|
||||
itemTouchHelper.attachToRecyclerView(binding.recyclerview)
|
||||
|
||||
binding.addButton.setOnClickListener {
|
||||
val manager = supportFragmentManager
|
||||
|
@ -98,13 +194,13 @@ class QuickWizardListActivity : NoSplashAppCompatActivity() {
|
|||
.toObservable(EventQuickWizardChange::class.java)
|
||||
.observeOn(aapsSchedulers.main)
|
||||
.subscribe({
|
||||
val adapter = RecyclerViewAdapter(supportFragmentManager)
|
||||
binding.recyclerview.swapAdapter(adapter, false)
|
||||
}, fabricPrivacy::logException)
|
||||
val adapter = RecyclerViewAdapter(supportFragmentManager)
|
||||
binding.recyclerview.swapAdapter(adapter, false)
|
||||
}, fabricPrivacy::logException)
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
disposable.clear()
|
||||
super.onPause()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ import android.view.ViewGroup
|
|||
import android.view.Window
|
||||
import android.view.WindowManager
|
||||
import dagger.android.support.DaggerDialogFragment
|
||||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.databinding.OverviewEditquickwizardDialogBinding
|
||||
import info.nightscout.shared.logging.AAPSLogger
|
||||
import info.nightscout.androidaps.plugins.bus.RxBus
|
||||
|
@ -21,6 +22,7 @@ import info.nightscout.androidaps.utils.extensions.setEnableForChildren
|
|||
import info.nightscout.androidaps.utils.extensions.setSelection
|
||||
import info.nightscout.androidaps.utils.wizard.QuickWizard
|
||||
import info.nightscout.androidaps.utils.wizard.QuickWizardEntry
|
||||
import info.nightscout.shared.sharedPreferences.SP
|
||||
import org.json.JSONException
|
||||
import javax.inject.Inject
|
||||
|
||||
|
@ -30,9 +32,9 @@ class EditQuickWizardDialog : DaggerDialogFragment(), View.OnClickListener {
|
|||
@Inject lateinit var aapsLogger: AAPSLogger
|
||||
@Inject lateinit var quickWizard: QuickWizard
|
||||
@Inject lateinit var dateUtil: DateUtil
|
||||
@Inject lateinit var sp: SP
|
||||
|
||||
var position = -1
|
||||
|
||||
var fromSeconds: Int = 0
|
||||
var toSeconds: Int = 0
|
||||
|
||||
|
@ -42,8 +44,10 @@ class EditQuickWizardDialog : DaggerDialogFragment(), View.OnClickListener {
|
|||
// onDestroyView.
|
||||
private val binding get() = _binding!!
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
|
||||
savedInstanceState: Bundle?): View {
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater, container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View {
|
||||
dialog?.window?.requestFeature(Window.FEATURE_NO_TITLE)
|
||||
dialog?.window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN)
|
||||
isCancelable = true
|
||||
|
@ -57,6 +61,14 @@ class EditQuickWizardDialog : DaggerDialogFragment(), View.OnClickListener {
|
|||
position = bundle.getInt("position", -1)
|
||||
}
|
||||
val entry = if (position == -1) quickWizard.newEmptyItem() else quickWizard[position]
|
||||
if (sp.getBoolean(R.string.key_wear_control, false)) {
|
||||
binding.deviceLabel.visibility = View.VISIBLE
|
||||
binding.device.visibility = View.VISIBLE
|
||||
} else {
|
||||
binding.deviceLabel.visibility = View.GONE
|
||||
binding.device.visibility = View.GONE
|
||||
}
|
||||
|
||||
binding.okcancel.ok.setOnClickListener {
|
||||
try {
|
||||
entry.storage.put("buttonText", binding.buttonEdit.text.toString())
|
||||
|
@ -66,10 +78,14 @@ class EditQuickWizardDialog : DaggerDialogFragment(), View.OnClickListener {
|
|||
entry.storage.put("useBG", binding.useBg.selectedItemPosition)
|
||||
entry.storage.put("useCOB", binding.useCob.selectedItemPosition)
|
||||
entry.storage.put("useBolusIOB", binding.useBolusIob.selectedItemPosition)
|
||||
entry.storage.put("device", binding.device.selectedItemPosition)
|
||||
entry.storage.put("useBasalIOB", binding.useBasalIob.selectedItemPosition)
|
||||
entry.storage.put("useTrend", binding.useTrend.selectedItemPosition)
|
||||
entry.storage.put("useSuperBolus", binding.useSuperBolus.selectedItemPosition)
|
||||
entry.storage.put("useTempTarget", binding.useTempTarget.selectedItemPosition)
|
||||
entry.storage.put("usePercentage", binding.usePercentage.selectedItemPosition)
|
||||
val percentage = SafeParse.stringToInt(binding.percentage.text.toString())
|
||||
entry.storage.put("percentage", percentage)
|
||||
} catch (e: JSONException) {
|
||||
aapsLogger.error("Unhandled exception", e)
|
||||
}
|
||||
|
@ -88,7 +104,8 @@ class EditQuickWizardDialog : DaggerDialogFragment(), View.OnClickListener {
|
|||
|
||||
binding.from.setOnClickListener {
|
||||
context?.let {
|
||||
TimePickerDialog(it, fromTimeSetListener,
|
||||
TimePickerDialog(
|
||||
it, fromTimeSetListener,
|
||||
T.secs(fromSeconds.toLong()).hours().toInt(),
|
||||
T.secs((fromSeconds % 3600).toLong()).mins().toInt(),
|
||||
DateFormat.is24HourFormat(context)
|
||||
|
@ -105,13 +122,29 @@ class EditQuickWizardDialog : DaggerDialogFragment(), View.OnClickListener {
|
|||
|
||||
binding.to.setOnClickListener {
|
||||
context?.let {
|
||||
TimePickerDialog(it, toTimeSetListener,
|
||||
TimePickerDialog(
|
||||
it, toTimeSetListener,
|
||||
T.secs(toSeconds.toLong()).hours().toInt(),
|
||||
T.secs((toSeconds % 3600).toLong()).mins().toInt(),
|
||||
DateFormat.is24HourFormat(context)
|
||||
).show()
|
||||
}
|
||||
}
|
||||
|
||||
fun usePercentage(custom: Boolean) {
|
||||
if (custom) {
|
||||
binding.percentageLabel.visibility = View.VISIBLE
|
||||
binding.percentage.visibility = View.VISIBLE
|
||||
} else {
|
||||
binding.percentageLabel.visibility = View.GONE
|
||||
binding.percentage.visibility = View.GONE
|
||||
}
|
||||
}
|
||||
|
||||
binding.usePercentage.setOnCheckedChangeListener { _, checkedId ->
|
||||
usePercentage(checkedId == R.id.use_percentage_custom)
|
||||
}
|
||||
|
||||
toSeconds = entry.validTo()
|
||||
binding.to.text = dateUtil.timeString(dateUtil.secondsOfTheDayToMilliseconds(toSeconds))
|
||||
|
||||
|
@ -122,10 +155,13 @@ class EditQuickWizardDialog : DaggerDialogFragment(), View.OnClickListener {
|
|||
binding.useCob.setSelection(entry.useCOB())
|
||||
binding.useBolusIob.setSelection(entry.useBolusIOB())
|
||||
binding.useBasalIob.setSelection(entry.useBasalIOB())
|
||||
binding.device.setSelection(entry.device())
|
||||
binding.useTrend.setSelection(entry.useTrend())
|
||||
binding.useSuperBolus.setSelection(entry.useSuperBolus())
|
||||
binding.useTempTarget.setSelection(entry.useTempTarget())
|
||||
|
||||
binding.usePercentage.setSelection(entry.usePercentage())
|
||||
usePercentage(entry.usePercentage() == QuickWizardEntry.CUSTOM)
|
||||
binding.percentage.setText(entry.percentage().toString())
|
||||
binding.useCobYes.setOnClickListener(this)
|
||||
binding.useCobNo.setOnClickListener(this)
|
||||
processCob()
|
||||
|
|
|
@ -2,6 +2,7 @@ package info.nightscout.androidaps.plugins.general.wear
|
|||
|
||||
import android.app.NotificationManager
|
||||
import android.content.Context
|
||||
import android.util.Log
|
||||
import dagger.android.HasAndroidInjector
|
||||
import info.nightscout.androidaps.Constants
|
||||
import info.nightscout.androidaps.R
|
||||
|
@ -39,11 +40,11 @@ import info.nightscout.androidaps.utils.resources.ResourceHelper
|
|||
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
||||
import info.nightscout.shared.sharedPreferences.SP
|
||||
import info.nightscout.androidaps.utils.wizard.BolusWizard
|
||||
import info.nightscout.androidaps.utils.wizard.QuickWizard
|
||||
import info.nightscout.shared.SafeParse
|
||||
import io.reactivex.disposables.CompositeDisposable
|
||||
import io.reactivex.rxkotlin.plusAssign
|
||||
import java.text.DateFormat
|
||||
import java.text.DecimalFormat
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
@ -71,6 +72,7 @@ class ActionStringHandler @Inject constructor(
|
|||
private val activePlugin: ActivePlugin,
|
||||
private val iobCobCalculator: IobCobCalculator,
|
||||
private val localInsightPlugin: LocalInsightPlugin,
|
||||
private val quickWizard: QuickWizard,
|
||||
private val danaRPlugin: DanaRPlugin,
|
||||
private val danaRKoreanPlugin: DanaRKoreanPlugin,
|
||||
private val danaRv2Plugin: DanaRv2Plugin,
|
||||
|
@ -79,7 +81,8 @@ class ActionStringHandler @Inject constructor(
|
|||
private val dateUtil: DateUtil,
|
||||
private val config: Config,
|
||||
private val repository: AppRepository,
|
||||
private val uel: UserEntryLogger
|
||||
private val uel: UserEntryLogger,
|
||||
private val defaultValueHelper: DefaultValueHelper
|
||||
) {
|
||||
|
||||
private val timeout = 65 * 1000
|
||||
|
@ -107,9 +110,11 @@ class ActionStringHandler @Inject constructor(
|
|||
|
||||
@Synchronized
|
||||
private fun handleInitiate(actionString: String) {
|
||||
//TODO: i18n
|
||||
Log.i("ActionStringHandler", "handleInitiate actionString=" + actionString)
|
||||
if (!sp.getBoolean(R.string.key_wear_control, false)) return
|
||||
lastBolusWizard = null
|
||||
var rTitle = "CONFIRM" //TODO: i18n
|
||||
var rTitle = rh.gs(R.string.confirm).uppercase()
|
||||
var rMessage = ""
|
||||
var rAction = ""
|
||||
// do the parsing and check constraints
|
||||
|
@ -136,6 +141,11 @@ class ActionStringHandler @Inject constructor(
|
|||
val carbs = SafeParse.stringToInt(act[2])
|
||||
val insulinAfterConstraints = constraintChecker.applyBolusConstraints(Constraint(insulin)).value()
|
||||
val carbsAfterConstraints = constraintChecker.applyCarbsConstraints(Constraint(carbs)).value()
|
||||
val pump = activePlugin.activePump
|
||||
if (insulinAfterConstraints > 0 && (!pump.isInitialized() || pump.isSuspended() || loop.isDisconnected)) {
|
||||
sendError(rh.gs(R.string.wizard_pump_not_available))
|
||||
return
|
||||
}
|
||||
rMessage += rh.gs(R.string.bolus) + ": " + insulinAfterConstraints + "U\n"
|
||||
rMessage += rh.gs(R.string.carbs) + ": " + carbsAfterConstraints + "g"
|
||||
if (insulinAfterConstraints - insulin != 0.0 || carbsAfterConstraints - carbs != 0) {
|
||||
|
@ -143,32 +153,72 @@ class ActionStringHandler @Inject constructor(
|
|||
}
|
||||
rAction += "bolus $insulinAfterConstraints $carbsAfterConstraints"
|
||||
} else if ("temptarget" == act[0]) { ///////////////////////////////////////////////////////// TEMPTARGET
|
||||
val isMGDL = java.lang.Boolean.parseBoolean(act[1])
|
||||
if (profileFunction.getUnits() == GlucoseUnit.MGDL != isMGDL) {
|
||||
sendError("Different units used on watch and phone!")
|
||||
return
|
||||
}
|
||||
val duration = SafeParse.stringToInt(act[2])
|
||||
if (duration == 0) {
|
||||
rMessage += "Zero-Temp-Target - cancelling running Temp-Targets?"
|
||||
aapsLogger.info(LTag.WEAR, "temptarget received: $act")
|
||||
if ("cancel" == act[1]) {
|
||||
rMessage += rh.gs(R.string.wear_action_tempt_cancel_message)
|
||||
rAction = "temptarget true 0 0 0"
|
||||
} else if ("preset" == act[1]) {
|
||||
val presetIsMGDL = profileFunction.getUnits() == GlucoseUnit.MGDL
|
||||
val preset = act[2]
|
||||
when (preset) {
|
||||
"activity" -> {
|
||||
val activityTTDuration = defaultValueHelper.determineActivityTTDuration()
|
||||
val activityTT = defaultValueHelper.determineActivityTT()
|
||||
val reason = rh.gs(R.string.activity)
|
||||
rMessage += rh.gs(R.string.wear_action_tempt_preset_message, reason, activityTT, activityTTDuration)
|
||||
rAction = "temptarget $presetIsMGDL $activityTTDuration $activityTT $activityTT"
|
||||
}
|
||||
|
||||
"hypo" -> {
|
||||
val hypoTTDuration = defaultValueHelper.determineHypoTTDuration()
|
||||
val hypoTT = defaultValueHelper.determineHypoTT()
|
||||
val reason = rh.gs(R.string.hypo)
|
||||
rMessage += rh.gs(R.string.wear_action_tempt_preset_message, reason, hypoTT, hypoTTDuration)
|
||||
rAction = "temptarget $presetIsMGDL $hypoTTDuration $hypoTT $hypoTT"
|
||||
}
|
||||
|
||||
"eating" -> {
|
||||
val eatingSoonTTDuration = defaultValueHelper.determineEatingSoonTTDuration()
|
||||
val eatingSoonTT = defaultValueHelper.determineEatingSoonTT()
|
||||
val reason = rh.gs(R.string.eatingsoon)
|
||||
rMessage += rh.gs(R.string.wear_action_tempt_preset_message, reason, eatingSoonTT, eatingSoonTTDuration)
|
||||
rAction = "temptarget $presetIsMGDL $eatingSoonTTDuration $eatingSoonTT $eatingSoonTT"
|
||||
}
|
||||
|
||||
else -> {
|
||||
sendError(rh.gs(R.string.wear_action_tempt_preset_error, preset))
|
||||
return
|
||||
}
|
||||
}
|
||||
} else {
|
||||
var low = SafeParse.stringToDouble(act[3])
|
||||
var high = SafeParse.stringToDouble(act[4])
|
||||
if (!isMGDL) {
|
||||
low *= Constants.MMOLL_TO_MGDL
|
||||
high *= Constants.MMOLL_TO_MGDL
|
||||
}
|
||||
if (low < HardLimits.VERY_HARD_LIMIT_TEMP_MIN_BG[0] || low > HardLimits.VERY_HARD_LIMIT_TEMP_MIN_BG[1]) {
|
||||
sendError("Min-BG out of range!")
|
||||
val isMGDL = java.lang.Boolean.parseBoolean(act[1])
|
||||
if (profileFunction.getUnits() == GlucoseUnit.MGDL != isMGDL) {
|
||||
sendError(rh.gs(R.string.wear_action_tempt_unit_error))
|
||||
return
|
||||
}
|
||||
if (high < HardLimits.VERY_HARD_LIMIT_TEMP_MAX_BG[0] || high > HardLimits.VERY_HARD_LIMIT_TEMP_MAX_BG[1]) {
|
||||
sendError("Max-BG out of range!")
|
||||
return
|
||||
val duration = SafeParse.stringToInt(act[2])
|
||||
if (duration == 0) {
|
||||
rMessage += rh.gs(R.string.wear_action_tempt_zero_message)
|
||||
rAction = "temptarget true 0 0 0"
|
||||
} else {
|
||||
var low = SafeParse.stringToDouble(act[3])
|
||||
var high = SafeParse.stringToDouble(act[4])
|
||||
if (!isMGDL) {
|
||||
low *= Constants.MMOLL_TO_MGDL
|
||||
high *= Constants.MMOLL_TO_MGDL
|
||||
}
|
||||
if (low < HardLimits.VERY_HARD_LIMIT_TEMP_MIN_BG[0] || low > HardLimits.VERY_HARD_LIMIT_TEMP_MIN_BG[1]) {
|
||||
sendError(rh.gs(R.string.wear_action_tempt_min_bg_error))
|
||||
return
|
||||
}
|
||||
if (high < HardLimits.VERY_HARD_LIMIT_TEMP_MAX_BG[0] || high > HardLimits.VERY_HARD_LIMIT_TEMP_MAX_BG[1]) {
|
||||
sendError(rh.gs(R.string.wear_action_tempt_max_bg_error))
|
||||
return
|
||||
}
|
||||
rMessage += if (act[3] === act[4]) rh.gs(R.string.wear_action_tempt_manual_message, act[3], act[2])
|
||||
else rh.gs(R.string.wear_action_tempt_manual_range_message, act[3], act[4], act[2])
|
||||
rAction = actionString
|
||||
}
|
||||
rMessage += "Temptarget:\nMin: " + act[3] + "\nMax: " + act[4] + "\nDuration: " + act[2]
|
||||
rAction = actionString
|
||||
}
|
||||
} else if ("status" == act[0]) { ////////////////////////////////////////////// STATUS
|
||||
rTitle = "STATUS"
|
||||
|
@ -186,10 +236,15 @@ class ActionStringHandler @Inject constructor(
|
|||
sendError("Update APP on Watch!")
|
||||
return
|
||||
} else if ("wizard2" == act[0]) { ////////////////////////////////////////////// WIZARD
|
||||
val pump = activePlugin.activePump
|
||||
if (!pump.isInitialized() || pump.isSuspended() || loop.isDisconnected) {
|
||||
sendError(rh.gs(R.string.wizard_pump_not_available))
|
||||
return
|
||||
}
|
||||
val carbsBeforeConstraints = SafeParse.stringToInt(act[1])
|
||||
val carbsAfterConstraints = constraintChecker.applyCarbsConstraints(Constraint(carbsBeforeConstraints)).value()
|
||||
if (carbsAfterConstraints - carbsBeforeConstraints != 0) {
|
||||
sendError("Carb constraint violation!")
|
||||
sendError(rh.gs(R.string.wizard_carbs_constraint))
|
||||
return
|
||||
}
|
||||
val useBG = sp.getBoolean(R.string.key_wearwizard_bg, true)
|
||||
|
@ -202,52 +257,94 @@ class ActionStringHandler @Inject constructor(
|
|||
val profile = profileFunction.getProfile()
|
||||
val profileName = profileFunction.getProfileName()
|
||||
if (profile == null) {
|
||||
sendError("No profile found!")
|
||||
sendError(rh.gs(R.string.wizard_no_active_profile))
|
||||
return
|
||||
}
|
||||
val bgReading = iobCobCalculator.ads.actualBg()
|
||||
if (bgReading == null) {
|
||||
sendError("No recent BG to base calculation on!")
|
||||
sendError(rh.gs(R.string.wizard_no_actual_bg))
|
||||
return
|
||||
}
|
||||
val cobInfo = iobCobCalculator.getCobInfo(false, "Wizard wear")
|
||||
if (cobInfo.displayCob == null) {
|
||||
sendError("Unknown COB! BG reading missing or recent app restart?")
|
||||
sendError(rh.gs(R.string.wizard_no_cob))
|
||||
return
|
||||
}
|
||||
val format = DecimalFormat("0.00")
|
||||
val formatInt = DecimalFormat("0")
|
||||
val dbRecord = repository.getTemporaryTargetActiveAt(dateUtil.now()).blockingGet()
|
||||
val tempTarget = if (dbRecord is ValueWrapper.Existing) dbRecord.value else null
|
||||
|
||||
val bolusWizard = BolusWizard(injector).doCalc(profile, profileName, tempTarget,
|
||||
carbsAfterConstraints, if (cobInfo.displayCob != null) cobInfo.displayCob!! else 0.0, bgReading.valueToUnits(profileFunction.getUnits()),
|
||||
0.0, percentage, useBG, useCOB, useBolusIOB, useBasalIOB, false, useTT, useTrend, false)
|
||||
if (abs(bolusWizard.insulinAfterConstraints - bolusWizard.calculatedTotalInsulin) >= 0.01) {
|
||||
sendError("Insulin constraint violation!" +
|
||||
"\nCannot deliver " + format.format(bolusWizard.calculatedTotalInsulin) + "!")
|
||||
val bolusWizard = BolusWizard(injector).doCalc(
|
||||
profile, profileName, tempTarget,
|
||||
carbsAfterConstraints, cobInfo.displayCob!!, bgReading.valueToUnits(profileFunction.getUnits()),
|
||||
0.0, percentage, useBG, useCOB, useBolusIOB, useBasalIOB, false, useTT, useTrend, false
|
||||
)
|
||||
val insulinAfterConstraints = bolusWizard.insulinAfterConstraints
|
||||
val minStep = pump.pumpDescription.pumpType.determineCorrectBolusStepSize(insulinAfterConstraints)
|
||||
if (abs(insulinAfterConstraints - bolusWizard.calculatedTotalInsulin) >= minStep) {
|
||||
sendError(rh.gs(R.string.wizard_constraint_bolus_size, bolusWizard.calculatedTotalInsulin))
|
||||
return
|
||||
}
|
||||
if (bolusWizard.calculatedTotalInsulin <= 0 && bolusWizard.carbs <= 0) {
|
||||
rAction = "info"
|
||||
rTitle = "INFO"
|
||||
rTitle = rh.gs(R.string.info)
|
||||
} else {
|
||||
rAction = actionString
|
||||
}
|
||||
rMessage += "Carbs: " + bolusWizard.carbs + "g"
|
||||
rMessage += "\nBolus: " + format.format(bolusWizard.calculatedTotalInsulin) + "U"
|
||||
rMessage += rh.gs(R.string.wizard_result, bolusWizard.calculatedTotalInsulin, bolusWizard.carbs)
|
||||
rMessage += "\n_____________"
|
||||
rMessage += "\nCalc (IC:" + DecimalFormatter.to1Decimal(bolusWizard.ic) + ", " + "ISF:" + DecimalFormatter.to1Decimal(bolusWizard.sens) + "): "
|
||||
rMessage += "\nFrom Carbs: " + format.format(bolusWizard.insulinFromCarbs) + "U"
|
||||
if (useCOB) rMessage += "\nFrom" + formatInt.format(cobInfo.displayCob) + "g COB : " + format.format(bolusWizard.insulinFromCOB) + "U"
|
||||
if (useBG) rMessage += "\nFrom BG: " + format.format(bolusWizard.insulinFromBG) + "U"
|
||||
if (useBolusIOB) rMessage += "\nBolus IOB: " + format.format(bolusWizard.insulinFromBolusIOB) + "U"
|
||||
if (useBasalIOB) rMessage += "\nBasal IOB: " + format.format(bolusWizard.insulinFromBasalIOB) + "U"
|
||||
if (useTrend) rMessage += "\nFrom 15' trend: " + format.format(bolusWizard.insulinFromTrend) + "U"
|
||||
if (percentage != 100) {
|
||||
rMessage += "\nPercentage: " + format.format(bolusWizard.totalBeforePercentageAdjustment) + "U * " + percentage + "% -> ~" + format.format(bolusWizard.calculatedTotalInsulin) + "U"
|
||||
}
|
||||
rMessage += "\n" + bolusWizard.explainShort()
|
||||
lastBolusWizard = bolusWizard
|
||||
} else if ("quick_wizard" == act[0]) {
|
||||
val guid = act[1]
|
||||
val actualBg = iobCobCalculator.ads.actualBg()
|
||||
val profile = profileFunction.getProfile()
|
||||
val profileName = profileFunction.getProfileName()
|
||||
val quickWizardEntry = quickWizard.get(guid)
|
||||
Log.i("QuickWizard", "handleInitiate: quick_wizard " + quickWizardEntry?.buttonText() + " c " + quickWizardEntry?.carbs())
|
||||
if (quickWizardEntry == null) {
|
||||
sendError(rh.gs(R.string.quick_wizard_not_available))
|
||||
return
|
||||
}
|
||||
if (actualBg == null) {
|
||||
sendError(rh.gs(R.string.wizard_no_actual_bg))
|
||||
return
|
||||
}
|
||||
if (profile == null) {
|
||||
sendError(rh.gs(R.string.wizard_no_active_profile))
|
||||
return
|
||||
}
|
||||
val cobInfo = iobCobCalculator.getCobInfo(false, "QuickWizard wear")
|
||||
if (cobInfo.displayCob == null) {
|
||||
sendError(rh.gs(R.string.wizard_no_cob))
|
||||
return
|
||||
}
|
||||
val pump = activePlugin.activePump
|
||||
if (!pump.isInitialized() || pump.isSuspended() || loop.isDisconnected) {
|
||||
sendError(rh.gs(R.string.wizard_pump_not_available))
|
||||
return
|
||||
}
|
||||
|
||||
val wizard = quickWizardEntry.doCalc(profile, profileName, actualBg, true)
|
||||
|
||||
val carbsAfterConstraints = constraintChecker.applyCarbsConstraints(Constraint(quickWizardEntry.carbs())).value()
|
||||
if (carbsAfterConstraints != quickWizardEntry.carbs()) {
|
||||
sendError(rh.gs(R.string.wizard_carbs_constraint))
|
||||
return
|
||||
}
|
||||
val insulinAfterConstraints = wizard.insulinAfterConstraints
|
||||
val minStep = pump.pumpDescription.pumpType.determineCorrectBolusStepSize(insulinAfterConstraints)
|
||||
if (abs(insulinAfterConstraints - wizard.calculatedTotalInsulin) >= minStep) {
|
||||
sendError(rh.gs(R.string.wizard_constraint_bolus_size, wizard.calculatedTotalInsulin))
|
||||
return
|
||||
}
|
||||
|
||||
rMessage = rh.gs(R.string.quick_wizard_message, quickWizardEntry.buttonText(), wizard.calculatedTotalInsulin, quickWizardEntry.carbs())
|
||||
rAction = "bolus $insulinAfterConstraints $carbsAfterConstraints"
|
||||
Log.i("QuickWizard", "handleInitiate: quick_wizard action=$rAction")
|
||||
|
||||
rMessage += "\n_____________"
|
||||
rMessage += "\n" + wizard.explainShort()
|
||||
|
||||
} else if ("opencpp" == act[0]) {
|
||||
val activeProfileSwitch = repository.getEffectiveProfileSwitchActiveAt(dateUtil.now()).blockingGet()
|
||||
if (activeProfileSwitch is ValueWrapper.Existing) { // read CPP values
|
||||
|
@ -331,7 +428,10 @@ class ActionStringHandler @Inject constructor(
|
|||
rAction = "cancelChangeRequest"
|
||||
wearPlugin.requestNotificationCancel(rAction)
|
||||
return
|
||||
} else return
|
||||
} else {
|
||||
sendError(rh.gs(R.string.wear_unknown_action_string) + act[0])
|
||||
return
|
||||
}
|
||||
// send result
|
||||
wearPlugin.requestActionConfirmation(rTitle, rMessage, rAction)
|
||||
lastSentTimestamp = System.currentTimeMillis()
|
||||
|
@ -560,39 +660,45 @@ class ActionStringHandler @Inject constructor(
|
|||
}
|
||||
//send profile to pump
|
||||
uel.log(Action.PROFILE_SWITCH, Sources.Wear,
|
||||
ValueWithUnit.Percent(percentage),
|
||||
ValueWithUnit.Hour(timeshift).takeIf { timeshift != 0 })
|
||||
ValueWithUnit.Percent(percentage),
|
||||
ValueWithUnit.Hour(timeshift).takeIf { timeshift != 0 })
|
||||
profileFunction.createProfileSwitch(0, percentage, timeshift)
|
||||
}
|
||||
|
||||
private fun generateTempTarget(duration: Int, low: Double, high: Double) {
|
||||
if (duration != 0) {
|
||||
disposable += repository.runTransactionForResult(InsertAndCancelCurrentTemporaryTargetTransaction(
|
||||
timestamp = System.currentTimeMillis(),
|
||||
duration = TimeUnit.MINUTES.toMillis(duration.toLong()),
|
||||
reason = TemporaryTarget.Reason.WEAR,
|
||||
lowTarget = Profile.toMgdl(low, profileFunction.getUnits()),
|
||||
highTarget = Profile.toMgdl(high, profileFunction.getUnits())
|
||||
)).subscribe({ result ->
|
||||
result.inserted.forEach { aapsLogger.debug(LTag.DATABASE, "Inserted temp target $it") }
|
||||
result.updated.forEach { aapsLogger.debug(LTag.DATABASE, "Updated temp target $it") }
|
||||
}, {
|
||||
aapsLogger.error(LTag.DATABASE, "Error while saving temporary target", it)
|
||||
})
|
||||
uel.log(Action.TT, Sources.Wear,
|
||||
disposable += repository.runTransactionForResult(
|
||||
InsertAndCancelCurrentTemporaryTargetTransaction(
|
||||
timestamp = System.currentTimeMillis(),
|
||||
duration = TimeUnit.MINUTES.toMillis(duration.toLong()),
|
||||
reason = TemporaryTarget.Reason.WEAR,
|
||||
lowTarget = Profile.toMgdl(low, profileFunction.getUnits()),
|
||||
highTarget = Profile.toMgdl(high, profileFunction.getUnits())
|
||||
)
|
||||
).subscribe({ result ->
|
||||
result.inserted.forEach { aapsLogger.debug(LTag.DATABASE, "Inserted temp target $it") }
|
||||
result.updated.forEach { aapsLogger.debug(LTag.DATABASE, "Updated temp target $it") }
|
||||
}, {
|
||||
aapsLogger.error(LTag.DATABASE, "Error while saving temporary target", it)
|
||||
})
|
||||
uel.log(
|
||||
Action.TT, Sources.Wear,
|
||||
ValueWithUnit.TherapyEventTTReason(TemporaryTarget.Reason.WEAR),
|
||||
ValueWithUnit.fromGlucoseUnit(low, profileFunction.getUnits().asText),
|
||||
ValueWithUnit.fromGlucoseUnit(high, profileFunction.getUnits().asText).takeIf { low != high },
|
||||
ValueWithUnit.Minute(duration))
|
||||
ValueWithUnit.Minute(duration)
|
||||
)
|
||||
} else {
|
||||
disposable += repository.runTransactionForResult(CancelCurrentTemporaryTargetIfAnyTransaction(System.currentTimeMillis()))
|
||||
.subscribe({ result ->
|
||||
result.updated.forEach { aapsLogger.debug(LTag.DATABASE, "Updated temp target $it") }
|
||||
}, {
|
||||
aapsLogger.error(LTag.DATABASE, "Error while saving temporary target", it)
|
||||
})
|
||||
uel.log(Action.CANCEL_TT, Sources.Wear,
|
||||
ValueWithUnit.TherapyEventTTReason(TemporaryTarget.Reason.WEAR))
|
||||
result.updated.forEach { aapsLogger.debug(LTag.DATABASE, "Updated temp target $it") }
|
||||
}, {
|
||||
aapsLogger.error(LTag.DATABASE, "Error while saving temporary target", it)
|
||||
})
|
||||
uel.log(
|
||||
Action.CANCEL_TT, Sources.Wear,
|
||||
ValueWithUnit.TherapyEventTTReason(TemporaryTarget.Reason.WEAR)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -601,13 +707,15 @@ class ActionStringHandler @Inject constructor(
|
|||
detailedBolusInfo.insulin = amount
|
||||
detailedBolusInfo.bolusType = DetailedBolusInfo.BolusType.PRIMING
|
||||
uel.log(Action.PRIME_BOLUS, Sources.Wear,
|
||||
ValueWithUnit.Insulin(amount).takeIf { amount != 0.0 })
|
||||
ValueWithUnit.Insulin(amount).takeIf { amount != 0.0 })
|
||||
commandQueue.bolus(detailedBolusInfo, object : Callback() {
|
||||
override fun run() {
|
||||
if (!result.success) {
|
||||
sendError(rh.gs(R.string.treatmentdeliveryerror) +
|
||||
"\n" +
|
||||
result.comment)
|
||||
sendError(
|
||||
rh.gs(R.string.treatmentdeliveryerror) +
|
||||
"\n" +
|
||||
result.comment
|
||||
)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
@ -615,9 +723,9 @@ class ActionStringHandler @Inject constructor(
|
|||
|
||||
private fun doECarbs(carbs: Int, time: Long, duration: Int) {
|
||||
uel.log(if (duration == 0) Action.CARBS else Action.EXTENDED_CARBS, Sources.Wear,
|
||||
ValueWithUnit.Timestamp(time),
|
||||
ValueWithUnit.Gram(carbs),
|
||||
ValueWithUnit.Hour(duration).takeIf { duration != 0 })
|
||||
ValueWithUnit.Timestamp(time),
|
||||
ValueWithUnit.Gram(carbs),
|
||||
ValueWithUnit.Hour(duration).takeIf { duration != 0 })
|
||||
doBolus(0.0, carbs, time, duration)
|
||||
}
|
||||
|
||||
|
@ -636,15 +744,17 @@ class ActionStringHandler @Inject constructor(
|
|||
else -> Action.TREATMENT
|
||||
}
|
||||
uel.log(action, Sources.Wear,
|
||||
ValueWithUnit.Insulin(amount).takeIf { amount != 0.0 },
|
||||
ValueWithUnit.Gram(carbs).takeIf { carbs != 0 },
|
||||
ValueWithUnit.Hour(carbsDuration).takeIf { carbsDuration != 0 })
|
||||
ValueWithUnit.Insulin(amount).takeIf { amount != 0.0 },
|
||||
ValueWithUnit.Gram(carbs).takeIf { carbs != 0 },
|
||||
ValueWithUnit.Hour(carbsDuration).takeIf { carbsDuration != 0 })
|
||||
commandQueue.bolus(detailedBolusInfo, object : Callback() {
|
||||
override fun run() {
|
||||
if (!result.success) {
|
||||
sendError(rh.gs(R.string.treatmentdeliveryerror) +
|
||||
"\n" +
|
||||
result.comment)
|
||||
sendError(
|
||||
rh.gs(R.string.treatmentdeliveryerror) +
|
||||
"\n" +
|
||||
result.comment
|
||||
)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
@ -665,4 +775,4 @@ class ActionStringHandler @Inject constructor(
|
|||
lastConfirmActionString = null
|
||||
lastBolusWizard = null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -46,6 +46,7 @@ import info.nightscout.androidaps.interfaces.Loop;
|
|||
import info.nightscout.androidaps.interfaces.PluginBase;
|
||||
import info.nightscout.androidaps.interfaces.Profile;
|
||||
import info.nightscout.androidaps.interfaces.ProfileFunction;
|
||||
import info.nightscout.androidaps.utils.wizard.QuickWizardEntry;
|
||||
import info.nightscout.shared.logging.AAPSLogger;
|
||||
import info.nightscout.shared.logging.LTag;
|
||||
import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin;
|
||||
|
@ -62,6 +63,7 @@ import info.nightscout.androidaps.utils.DecimalFormatter;
|
|||
import info.nightscout.androidaps.utils.DefaultValueHelper;
|
||||
import info.nightscout.androidaps.utils.TrendCalculator;
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper;
|
||||
import info.nightscout.androidaps.utils.wizard.QuickWizard;
|
||||
import info.nightscout.shared.sharedPreferences.SP;
|
||||
|
||||
public class WatchUpdaterService extends WearableListenerService implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener {
|
||||
|
@ -81,6 +83,7 @@ public class WatchUpdaterService extends WearableListenerService implements Goog
|
|||
@Inject ReceiverStatusStore receiverStatusStore;
|
||||
@Inject Config config;
|
||||
@Inject public TrendCalculator trendCalculator;
|
||||
@Inject public QuickWizard quickWizard;
|
||||
|
||||
public static final String ACTION_RESEND = WatchUpdaterService.class.getName().concat(".Resend");
|
||||
public static final String ACTION_OPEN_SETTINGS = WatchUpdaterService.class.getName().concat(".OpenSettings");
|
||||
|
@ -101,12 +104,14 @@ public class WatchUpdaterService extends WearableListenerService implements Goog
|
|||
private static final String OPEN_SETTINGS_PATH = "/openwearsettings";
|
||||
private static final String NEW_STATUS_PATH = "/sendstatustowear";
|
||||
private static final String NEW_PREFERENCES_PATH = "/sendpreferencestowear";
|
||||
private static final String QUICK_WIZARD_PATH = "/send_quick_wizard";
|
||||
public static final String BASAL_DATA_PATH = "/nightscout_watch_basal";
|
||||
public static final String BOLUS_PROGRESS_PATH = "/nightscout_watch_bolusprogress";
|
||||
public static final String ACTION_CONFIRMATION_REQUEST_PATH = "/nightscout_watch_actionconfirmationrequest";
|
||||
public static final String ACTION_CHANGECONFIRMATION_REQUEST_PATH = "/nightscout_watch_changeconfirmationrequest";
|
||||
public static final String ACTION_CANCELNOTIFICATION_REQUEST_PATH = "/nightscout_watch_cancelnotificationrequest";
|
||||
|
||||
String TAG = "WatchUpdateService";
|
||||
|
||||
private static boolean lastLoopStatus;
|
||||
|
||||
|
@ -156,7 +161,7 @@ public class WatchUpdaterService extends WearableListenerService implements Goog
|
|||
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||
String action = intent != null ? intent.getAction() : null;
|
||||
|
||||
// Log.d(TAG, logPrefix + "onStartCommand: " + action);
|
||||
// Log.d(TAG, "onStartCommand: " + action);
|
||||
|
||||
if (wearIntegration()) {
|
||||
handler.post(() -> {
|
||||
|
@ -235,7 +240,7 @@ public class WatchUpdaterService extends WearableListenerService implements Goog
|
|||
super.onPeerConnected(peer);
|
||||
String id = peer.getId();
|
||||
String name = peer.getDisplayName();
|
||||
// Log.d(TAG, logPrefix + "onPeerConnected peer name & ID: " + name + "|" + id);
|
||||
Log.d(TAG, "onPeerConnected peer name & ID: " + name + "|" + id);
|
||||
}
|
||||
|
||||
|
||||
|
@ -244,14 +249,14 @@ public class WatchUpdaterService extends WearableListenerService implements Goog
|
|||
super.onPeerDisconnected(peer);
|
||||
String id = peer.getId();
|
||||
String name = peer.getDisplayName();
|
||||
// Log.d(TAG, logPrefix + "onPeerDisconnected peer name & ID: " + name + "|" + id);
|
||||
Log.d(TAG, "onPeerDisconnected peer name & ID: " + name + "|" + id);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onMessageReceived(MessageEvent event) {
|
||||
|
||||
// Log.d(TAG, logPrefix + "onMessageRecieved: " + event);
|
||||
// Log.d(TAG, "onMessageRecieved: " + event);
|
||||
|
||||
if (wearIntegration()) {
|
||||
if (event != null && event.getPath().equals(WEARABLE_RESEND_PATH)) {
|
||||
|
@ -283,7 +288,7 @@ public class WatchUpdaterService extends WearableListenerService implements Goog
|
|||
private void sendData() {
|
||||
|
||||
GlucoseValue lastBG = iobCobCalculator.getAds().lastBg();
|
||||
// Log.d(TAG, logPrefix + "LastBg=" + lastBG);
|
||||
// Log.d(TAG, "LastBg=" + lastBG);
|
||||
if (lastBG != null) {
|
||||
GlucoseStatus glucoseStatus = glucoseStatusProvider.getGlucoseStatusData();
|
||||
|
||||
|
@ -364,6 +369,10 @@ public class WatchUpdaterService extends WearableListenerService implements Goog
|
|||
if (googleApiClient != null && !googleApiClient.isConnected() && !googleApiClient.isConnecting()) {
|
||||
googleApiConnect();
|
||||
}
|
||||
|
||||
sendPreferences();
|
||||
sendQuickWizard();
|
||||
|
||||
long startTime = System.currentTimeMillis() - (long) (60000 * 60 * 5.5);
|
||||
GlucoseValue last_bg = iobCobCalculator.getAds().lastBg();
|
||||
|
||||
|
@ -382,7 +391,6 @@ public class WatchUpdaterService extends WearableListenerService implements Goog
|
|||
entries.putDataMapArrayList("entries", dataMaps);
|
||||
(new SendToDataLayerThread(WEARABLE_DATA_PATH, googleApiClient)).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, entries);
|
||||
}
|
||||
sendPreferences();
|
||||
sendBasals();
|
||||
sendStatus();
|
||||
}
|
||||
|
@ -720,19 +728,62 @@ public class WatchUpdaterService extends WearableListenerService implements Goog
|
|||
private void sendPreferences() {
|
||||
if (googleApiClient != null && googleApiClient.isConnected()) {
|
||||
|
||||
GlucoseUnit units = profileFunction.getUnits();
|
||||
boolean wearcontrol = sp.getBoolean(R.string.key_wear_control, false);
|
||||
|
||||
boolean mgdl = units.equals(GlucoseUnit.MGDL);
|
||||
int percentage = sp.getInt(R.string.key_boluswizard_percentage, 100);
|
||||
int maxCarbs = sp.getInt(R.string.key_treatmentssafety_maxcarbs, 48);
|
||||
double maxBolus = sp.getDouble(R.string.key_treatmentssafety_maxbolus, 3.0);
|
||||
PutDataMapRequest dataMapRequest = PutDataMapRequest.create(NEW_PREFERENCES_PATH);
|
||||
//unique content
|
||||
dataMapRequest.getDataMap().putLong("timestamp", System.currentTimeMillis());
|
||||
dataMapRequest.getDataMap().putBoolean(rh.gs(R.string.key_wear_control), wearcontrol);
|
||||
dataMapRequest.getDataMap().putBoolean(rh.gs(R.string.key_units_mgdl), mgdl);
|
||||
dataMapRequest.getDataMap().putInt(rh.gs(R.string.key_boluswizard_percentage), percentage);
|
||||
dataMapRequest.getDataMap().putInt(rh.gs(R.string.key_treatmentssafety_maxcarbs), maxCarbs);
|
||||
dataMapRequest.getDataMap().putDouble(rh.gs(R.string.key_treatmentssafety_maxbolus),maxBolus);
|
||||
PutDataRequest putDataRequest = dataMapRequest.asPutDataRequest();
|
||||
Wearable.DataApi.putDataItem(googleApiClient, putDataRequest);
|
||||
} else {
|
||||
Log.e("SendStatus", "No connection to wearable available!");
|
||||
Log.e("SendPreferences", "No connection to wearable available!");
|
||||
}
|
||||
}
|
||||
|
||||
private void sendQuickWizard() {
|
||||
if (googleApiClient != null && googleApiClient.isConnected()) {
|
||||
int size = quickWizard.size();
|
||||
ArrayList<DataMap> entities = new ArrayList<>();
|
||||
for(int i=0; i < size; i++) {
|
||||
QuickWizardEntry q = quickWizard.get(i);
|
||||
if (q.forDevice(QuickWizardEntry.DEVICE_WATCH)) {
|
||||
entities.add(quickMap(q));
|
||||
}
|
||||
}
|
||||
|
||||
PutDataMapRequest dataMapRequest = PutDataMapRequest.create(QUICK_WIZARD_PATH);
|
||||
|
||||
DataMap dm = dataMapRequest.getDataMap();
|
||||
dm.putLong("timestamp", System.currentTimeMillis());
|
||||
dm.putDataMapArrayList("quick_wizard", entities);
|
||||
|
||||
PutDataRequest putDataRequest = dataMapRequest.asPutDataRequest();
|
||||
Log.i(TAG, "sendQuickWizard: " + putDataRequest);
|
||||
Wearable.DataApi.putDataItem(googleApiClient, putDataRequest);
|
||||
} else {
|
||||
Log.e("sendQuickWizard", "No connection to wearable available!");
|
||||
}
|
||||
}
|
||||
|
||||
private DataMap quickMap(QuickWizardEntry q) {
|
||||
DataMap dm = new DataMap();
|
||||
dm.putString("guid", q.guid());
|
||||
dm.putString("button_text", q.buttonText());
|
||||
dm.putInt("carbs", q.carbs());
|
||||
dm.putInt("from", q.validFrom());
|
||||
dm.putInt("to", q.validTo());
|
||||
return dm;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private String generateStatusString(Profile profile, String currentBasal, String iobSum, String iobDetail, String bgiString) {
|
||||
|
||||
|
|
|
@ -121,6 +121,7 @@ class LocalProfileFragment : DaggerFragment() {
|
|||
processVisibilityOnClick(it)
|
||||
binding.target.visibility = View.VISIBLE
|
||||
}
|
||||
binding.dia.editText?.id?.let { binding.diaLabel.labelFor = it }
|
||||
}
|
||||
|
||||
fun build() {
|
||||
|
|
|
@ -58,13 +58,13 @@ class TddCalculator @Inject constructor(
|
|||
val tbr = tempBasals[t]
|
||||
val profile = profileFunction.getProfile(t) ?: continue
|
||||
val absoluteRate = tbr?.convertedToAbsolute(t, profile) ?: profile.getBasal(t)
|
||||
tdd.basalAmount += absoluteRate / 60.0 * 5.0
|
||||
tdd.basalAmount += absoluteRate / T.mins(60).msecs().toDouble() * calculationStep.toDouble()
|
||||
|
||||
if (!activePlugin.activePump.isFakingTempsByExtendedBoluses) {
|
||||
// they are not included in TBRs
|
||||
val eb = iobCobCalculator.getExtendedBolus(t)
|
||||
val absoluteEbRate = eb?.rate ?: 0.0
|
||||
tdd.bolusAmount += absoluteEbRate / 60.0 * 5.0
|
||||
tdd.bolusAmount += absoluteEbRate / T.mins(60).msecs().toDouble() * calculationStep.toDouble()
|
||||
}
|
||||
result.put(midnight, tdd)
|
||||
}
|
||||
|
@ -76,7 +76,54 @@ class TddCalculator @Inject constructor(
|
|||
return result
|
||||
}
|
||||
|
||||
private fun averageTDD(tdds: LongSparseArray<TotalDailyDose>): TotalDailyDose {
|
||||
fun calculateDaily():TotalDailyDose {
|
||||
val startTime = MidnightTime.calc(dateUtil.now() )
|
||||
val endTime = dateUtil.now()
|
||||
val tdd = TotalDailyDose(timestamp = startTime)
|
||||
//val result = TotalDailyDose()
|
||||
repository.getBolusesDataFromTimeToTime(startTime, endTime, true).blockingGet()
|
||||
.filter { it.type != Bolus.Type.PRIMING }
|
||||
.forEach { t ->
|
||||
//val midnight = MidnightTime.calc(t.timestamp)
|
||||
//val tdd = result[midnight] ?: TotalDailyDose(timestamp = midnight)
|
||||
tdd.bolusAmount += t.amount
|
||||
//result.put(midnight, tdd)
|
||||
}
|
||||
repository.getCarbsDataFromTimeToTimeExpanded(startTime, endTime, true).blockingGet().forEach { t ->
|
||||
//val midnight = MidnightTime.calc(t.timestamp)
|
||||
//val tdd = result[midnight] ?: TotalDailyDose(timestamp = midnight)
|
||||
tdd.carbs += t.amount
|
||||
//result.put(midnight, tdd)
|
||||
}
|
||||
val calculationStep = T.mins(5).msecs()
|
||||
for (t in startTime until endTime step calculationStep) {
|
||||
|
||||
//val midnight = MidnightTime.calc(t)
|
||||
//val tdd = result[midnight] ?: TotalDailyDose(timestamp = midnight)
|
||||
val tbr = iobCobCalculator.getTempBasalIncludingConvertedExtended(t)
|
||||
val profile = profileFunction.getProfile(t) ?: continue
|
||||
val absoluteRate = tbr?.convertedToAbsolute(t, profile) ?: profile.getBasal(t)
|
||||
tdd.basalAmount += absoluteRate / T.mins(5).msecs().toDouble() * calculationStep.toDouble()
|
||||
|
||||
if (!activePlugin.activePump.isFakingTempsByExtendedBoluses) {
|
||||
// they are not included in TBRs
|
||||
val eb = iobCobCalculator.getExtendedBolus(t)
|
||||
val absoluteEbRate = eb?.rate ?: 0.0
|
||||
tdd.bolusAmount += absoluteEbRate / T.mins(5).msecs().toDouble() * calculationStep.toDouble()
|
||||
}
|
||||
//result.put(midnight, tdd)
|
||||
}
|
||||
//for (i in 0 until tdd.size()) {
|
||||
//val tdd = result.valueAt(i)
|
||||
tdd.totalAmount = tdd.bolusAmount + tdd.basalAmount
|
||||
//}
|
||||
|
||||
|
||||
aapsLogger.debug(LTag.CORE, tdd.toString())
|
||||
return tdd
|
||||
}
|
||||
|
||||
fun averageTDD(tdds: LongSparseArray<TotalDailyDose>): TotalDailyDose {
|
||||
val totalTdd = TotalDailyDose(timestamp = dateUtil.now())
|
||||
for (i in 0 until tdds.size()) {
|
||||
val tdd = tdds.valueAt(i)
|
||||
|
|
|
@ -112,7 +112,7 @@ public class TimeListEdit {
|
|||
float factor = layout.getContext().getResources().getDisplayMetrics().density;
|
||||
finalAdd = new ImageView(context);
|
||||
finalAdd.setImageResource(R.drawable.ic_add);
|
||||
finalAdd.setContentDescription(layout.getContext().getResources().getString(R.string.addnew));
|
||||
finalAdd.setContentDescription(layout.getContext().getResources().getString(R.string.a11y_add_new_to_list));
|
||||
LinearLayout.LayoutParams illp = new LinearLayout.LayoutParams((int) (35d * factor), (int) (35 * factor));
|
||||
illp.setMargins(0, 25, 0, 25); // llp.setMargins(left, top, right, bottom);
|
||||
illp.gravity = Gravity.CENTER;
|
||||
|
|
|
@ -18,6 +18,8 @@ import info.nightscout.androidaps.database.entities.ValueWithUnit
|
|||
import info.nightscout.androidaps.database.transactions.InsertOrUpdateBolusCalculatorResultTransaction
|
||||
import info.nightscout.androidaps.events.EventRefreshOverview
|
||||
import info.nightscout.androidaps.extensions.formatColor
|
||||
import info.nightscout.androidaps.extensions.highValueToUnitsToString
|
||||
import info.nightscout.androidaps.extensions.lowValueToUnitsToString
|
||||
import info.nightscout.androidaps.interfaces.*
|
||||
import info.nightscout.shared.logging.AAPSLogger
|
||||
import info.nightscout.shared.logging.LTag
|
||||
|
@ -135,27 +137,28 @@ class BolusWizard @Inject constructor(
|
|||
private var quickWizard: Boolean = true
|
||||
var usePercentage: Boolean = false
|
||||
|
||||
fun doCalc(profile: Profile,
|
||||
profileName: String,
|
||||
tempTarget: TemporaryTarget?,
|
||||
carbs: Int,
|
||||
cob: Double,
|
||||
bg: Double,
|
||||
correction: Double,
|
||||
percentageCorrection: Int = 100,
|
||||
useBg: Boolean,
|
||||
useCob: Boolean,
|
||||
includeBolusIOB: Boolean,
|
||||
includeBasalIOB: Boolean,
|
||||
useSuperBolus: Boolean,
|
||||
useTT: Boolean,
|
||||
useTrend: Boolean,
|
||||
useAlarm: Boolean,
|
||||
notes: String = "",
|
||||
carbTime: Int = 0,
|
||||
usePercentage: Boolean = false,
|
||||
totalPercentage: Double = 100.0,
|
||||
quickWizard: Boolean = false
|
||||
fun doCalc(
|
||||
profile: Profile,
|
||||
profileName: String,
|
||||
tempTarget: TemporaryTarget?,
|
||||
carbs: Int,
|
||||
cob: Double,
|
||||
bg: Double,
|
||||
correction: Double,
|
||||
percentageCorrection: Int = 100,
|
||||
useBg: Boolean,
|
||||
useCob: Boolean,
|
||||
includeBolusIOB: Boolean,
|
||||
includeBasalIOB: Boolean,
|
||||
useSuperBolus: Boolean,
|
||||
useTT: Boolean,
|
||||
useTrend: Boolean,
|
||||
useAlarm: Boolean,
|
||||
notes: String = "",
|
||||
carbTime: Int = 0,
|
||||
usePercentage: Boolean = false,
|
||||
totalPercentage: Double = 100.0,
|
||||
quickWizard: Boolean = false
|
||||
): BolusWizard {
|
||||
|
||||
this.profile = profile
|
||||
|
@ -314,7 +317,9 @@ class BolusWizard @Inject constructor(
|
|||
actions.add(rh.gs(R.string.carbs) + ": " + rh.gs(R.string.format_carbs, carbs).formatColor(rh, R.color.carbs) + timeShift)
|
||||
}
|
||||
if (insulinFromCOB > 0) {
|
||||
actions.add(rh.gs(R.string.cobvsiob) + ": " + rh.gs(R.string.formatsignedinsulinunits, insulinFromBolusIOB + insulinFromBasalIOB + insulinFromCOB + insulinFromBG).formatColor(rh, R.color.cobAlert))
|
||||
actions.add(
|
||||
rh.gs(R.string.cobvsiob) + ": " + rh.gs(R.string.formatsignedinsulinunits, insulinFromBolusIOB + insulinFromBasalIOB + insulinFromCOB + insulinFromBG).formatColor(rh, R.color.cobAlert)
|
||||
)
|
||||
val absorptionRate = iobCobCalculator.ads.slowAbsorptionPercentage(60)
|
||||
if (absorptionRate > .25)
|
||||
actions.add(rh.gs(R.string.slowabsorptiondetected, rh.gc(R.color.cobAlert), (absorptionRate * 100).toInt()))
|
||||
|
@ -344,8 +349,8 @@ class BolusWizard @Inject constructor(
|
|||
carbTimer.removeEatReminder()
|
||||
if (sp.getBoolean(R.string.key_usebolusadvisor, false) && Profile.toMgdl(bg, profile.units) > 180 && carbs > 0 && carbTime >= 0)
|
||||
OKDialog.showYesNoCancel(ctx, rh.gs(R.string.bolusadvisor), rh.gs(R.string.bolusadvisormessage),
|
||||
{ bolusAdvisorProcessing(ctx) },
|
||||
{ commonProcessing(ctx) }
|
||||
{ bolusAdvisorProcessing(ctx) },
|
||||
{ commonProcessing(ctx) }
|
||||
)
|
||||
else
|
||||
commonProcessing(ctx)
|
||||
|
@ -367,10 +372,13 @@ class BolusWizard @Inject constructor(
|
|||
carbTime = 0
|
||||
bolusCalculatorResult = createBolusCalculatorResult()
|
||||
notes = this@BolusWizard.notes
|
||||
uel.log(Action.BOLUS_ADVISOR, if (quickWizard) Sources.QuickWizard else Sources.WizardDialog,
|
||||
uel.log(
|
||||
Action.BOLUS_ADVISOR,
|
||||
if (quickWizard) Sources.QuickWizard else Sources.WizardDialog,
|
||||
notes,
|
||||
ValueWithUnit.TherapyEventType(eventType.toDBbEventType()),
|
||||
ValueWithUnit.Insulin(insulinAfterConstraints))
|
||||
ValueWithUnit.Insulin(insulinAfterConstraints)
|
||||
)
|
||||
if (insulin > 0) {
|
||||
commandQueue.bolus(this, object : Callback() {
|
||||
override fun run() {
|
||||
|
@ -385,6 +393,26 @@ class BolusWizard @Inject constructor(
|
|||
})
|
||||
}
|
||||
|
||||
fun explainShort(): String {
|
||||
var message = rh.gs(R.string.wizard_explain_calc, ic, sens)
|
||||
message += "\n" + rh.gs(R.string.wizard_explain_carbs, insulinFromCarbs)
|
||||
if (useTT && tempTarget != null) {
|
||||
val tt = if (tempTarget?.lowTarget == tempTarget?.highTarget) tempTarget?.lowValueToUnitsToString(profile.units)
|
||||
else rh.gs(R.string.wizard_explain_tt_to, tempTarget?.lowValueToUnitsToString(profile.units), tempTarget?.highValueToUnitsToString(profile.units))
|
||||
message += "\n" + rh.gs(R.string.wizard_explain_tt, tt)
|
||||
}
|
||||
if (useCob) message += "\n" + rh.gs(R.string.wizard_explain_cob, cob, insulinFromCOB)
|
||||
if (useBg) message += "\n" + rh.gs(R.string.wizard_explain_bg, insulinFromBG)
|
||||
if (includeBolusIOB) message += "\n" + rh.gs(R.string.wizard_explain_bolus_iob, insulinFromBolusIOB)
|
||||
if (includeBasalIOB) message += "\n" + rh.gs(R.string.wizard_explain_basal_iob, insulinFromBasalIOB)
|
||||
if (useTrend) message += "\n" + rh.gs(R.string.wizard_explain_trend, insulinFromTrend)
|
||||
if (useSuperBolus) message += "\n" + rh.gs(R.string.wizard_explain_superbolus, insulinFromSuperBolus)
|
||||
if (percentageCorrection != 100) {
|
||||
message += "\n" + rh.gs(R.string.wizard_explain_percent, totalBeforePercentageAdjustment, percentageCorrection, calculatedTotalInsulin)
|
||||
}
|
||||
return message
|
||||
}
|
||||
|
||||
private fun commonProcessing(ctx: Context) {
|
||||
val profile = profileFunction.getProfile() ?: return
|
||||
val pump = activePlugin.activePump
|
||||
|
@ -433,17 +461,17 @@ class BolusWizard @Inject constructor(
|
|||
bolusCalculatorResult = createBolusCalculatorResult()
|
||||
notes = this@BolusWizard.notes
|
||||
if (insulin > 0 || carbs > 0) {
|
||||
val action = when {
|
||||
val action = when {
|
||||
insulinAfterConstraints.equals(0.0) -> Action.CARBS
|
||||
carbs.equals(0.0) -> Action.BOLUS
|
||||
else -> Action.TREATMENT
|
||||
}
|
||||
uel.log(action, if (quickWizard) Sources.QuickWizard else Sources.WizardDialog,
|
||||
notes,
|
||||
ValueWithUnit.TherapyEventType(eventType.toDBbEventType()),
|
||||
ValueWithUnit.Insulin(insulinAfterConstraints).takeIf { insulinAfterConstraints != 0.0 },
|
||||
ValueWithUnit.Gram(this@BolusWizard.carbs).takeIf { this@BolusWizard.carbs != 0 },
|
||||
ValueWithUnit.Minute(carbTime).takeIf { carbTime != 0 })
|
||||
notes,
|
||||
ValueWithUnit.TherapyEventType(eventType.toDBbEventType()),
|
||||
ValueWithUnit.Insulin(insulinAfterConstraints).takeIf { insulinAfterConstraints != 0.0 },
|
||||
ValueWithUnit.Gram(this@BolusWizard.carbs).takeIf { this@BolusWizard.carbs != 0 },
|
||||
ValueWithUnit.Minute(carbTime).takeIf { carbTime != 0 })
|
||||
commandQueue.bolus(this, object : Callback() {
|
||||
override fun run() {
|
||||
if (!result.success) {
|
||||
|
@ -469,9 +497,9 @@ class BolusWizard @Inject constructor(
|
|||
private fun calcPercentageWithConstraints() {
|
||||
calculatedPercentage = 100.0
|
||||
if (totalBeforePercentageAdjustment != insulinFromCorrection)
|
||||
calculatedPercentage = calculatedTotalInsulin/(totalBeforePercentageAdjustment-insulinFromCorrection) * 100
|
||||
calculatedPercentage = calculatedTotalInsulin / (totalBeforePercentageAdjustment - insulinFromCorrection) * 100
|
||||
calculatedPercentage = max(calculatedPercentage, 10.0)
|
||||
calculatedPercentage = min(calculatedPercentage,250.0)
|
||||
calculatedPercentage = min(calculatedPercentage, 250.0)
|
||||
}
|
||||
|
||||
private fun calcCorrectionWithConstraints() {
|
||||
|
@ -481,4 +509,4 @@ class BolusWizard @Inject constructor(
|
|||
calculatedCorrection = max(-constraintChecker.getMaxBolusAllowed().value(), calculatedCorrection)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
package info.nightscout.androidaps.utils.wizard
|
||||
|
||||
import android.util.Log
|
||||
import dagger.android.HasAndroidInjector
|
||||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.shared.sharedPreferences.SP
|
||||
import org.json.JSONArray
|
||||
import org.json.JSONObject
|
||||
import java.util.*
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
|
@ -18,6 +20,18 @@ class QuickWizard @Inject constructor(
|
|||
|
||||
init {
|
||||
setData(JSONArray(sp.getString(R.string.key_quickwizard, "[]")))
|
||||
setGuidsForOldEntries()
|
||||
}
|
||||
|
||||
private fun setGuidsForOldEntries() {
|
||||
// for migration purposes; guid is a new required property
|
||||
for (i in 0 until storage.length()) {
|
||||
val entry = QuickWizardEntry(injector).from(storage.get(i) as JSONObject, i)
|
||||
if (entry.guid() == "") {
|
||||
val guid = UUID.randomUUID().toString()
|
||||
entry.storage.put("guid", guid)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun getActive(): QuickWizardEntry? {
|
||||
|
@ -41,6 +55,38 @@ class QuickWizard @Inject constructor(
|
|||
operator fun get(position: Int): QuickWizardEntry =
|
||||
QuickWizardEntry(injector).from(storage.get(position) as JSONObject, position)
|
||||
|
||||
fun get(guid: String): QuickWizardEntry? {
|
||||
for (i in 0 until storage.length()) {
|
||||
val entry = QuickWizardEntry(injector).from(storage.get(i) as JSONObject, i)
|
||||
if (entry.guid() == guid) {
|
||||
return entry
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
fun move(from: Int, to: Int) {
|
||||
Log.i("QuickWizard", "moveItem: $from $to")
|
||||
val fromEntry = storage[from] as JSONObject
|
||||
storage.remove(from)
|
||||
addToPos(to, fromEntry, storage)
|
||||
save()
|
||||
}
|
||||
|
||||
fun removePos(pos: Int, jsonObj: JSONObject?, jsonArr: JSONArray) {
|
||||
for (i in jsonArr.length() downTo pos + 1) {
|
||||
jsonArr.put(i, jsonArr[i - 1])
|
||||
}
|
||||
jsonArr.put(pos, jsonObj)
|
||||
}
|
||||
|
||||
private fun addToPos(pos: Int, jsonObj: JSONObject?, jsonArr: JSONArray) {
|
||||
for (i in jsonArr.length() downTo pos + 1) {
|
||||
jsonArr.put(i, jsonArr[i - 1])
|
||||
}
|
||||
jsonArr.put(pos, jsonObj)
|
||||
}
|
||||
|
||||
fun newEmptyItem(): QuickWizardEntry {
|
||||
return QuickWizardEntry(injector)
|
||||
}
|
||||
|
@ -57,4 +103,5 @@ class QuickWizard @Inject constructor(
|
|||
storage.remove(position)
|
||||
save()
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@ import info.nightscout.androidaps.utils.JsonHelper.safeGetString
|
|||
import info.nightscout.shared.sharedPreferences.SP
|
||||
import org.json.JSONException
|
||||
import org.json.JSONObject
|
||||
import java.util.*
|
||||
import javax.inject.Inject
|
||||
|
||||
class QuickWizardEntry @Inject constructor(private val injector: HasAndroidInjector) {
|
||||
|
@ -41,11 +42,26 @@ class QuickWizardEntry @Inject constructor(private val injector: HasAndroidInjec
|
|||
const val NO = 1
|
||||
private const val POSITIVE_ONLY = 2
|
||||
private const val NEGATIVE_ONLY = 3
|
||||
const val DEVICE_ALL = 0
|
||||
const val DEVICE_PHONE = 1
|
||||
const val DEVICE_WATCH = 2
|
||||
const val DEFAULT = 0
|
||||
const val CUSTOM = 1
|
||||
}
|
||||
|
||||
init {
|
||||
injector.androidInjector().inject(this)
|
||||
val emptyData = "{\"buttonText\":\"\",\"carbs\":0,\"validFrom\":0,\"validTo\":86340}"
|
||||
val guid = UUID.randomUUID().toString()
|
||||
val emptyData = """{
|
||||
"guid": "$guid",
|
||||
"buttonText": "",
|
||||
"carbs": 0,
|
||||
"validFrom": 0,
|
||||
"validTo": 86340,
|
||||
"device": "all",
|
||||
"usePercentage": "default",
|
||||
"percentage": 100
|
||||
}""".trimMargin()
|
||||
try {
|
||||
storage = JSONObject(emptyData)
|
||||
} catch (e: JSONException) {
|
||||
|
@ -55,6 +71,8 @@ class QuickWizardEntry @Inject constructor(private val injector: HasAndroidInjec
|
|||
|
||||
/*
|
||||
{
|
||||
guid: string,
|
||||
device: string, // (phone, watch, all)
|
||||
buttonText: "Meal",
|
||||
carbs: 36,
|
||||
validFrom: 8 * 60 * 60, // seconds from midnight
|
||||
|
@ -66,15 +84,18 @@ class QuickWizardEntry @Inject constructor(private val injector: HasAndroidInjec
|
|||
useTrend: 0,
|
||||
useSuperBolus: 0,
|
||||
useTemptarget: 0
|
||||
usePercentage: string, // default, custom
|
||||
percentage: int,
|
||||
}
|
||||
*/
|
||||
fun from(entry: JSONObject, position: Int): QuickWizardEntry {
|
||||
// TODO set guid if missing for migration
|
||||
storage = entry
|
||||
this.position = position
|
||||
return this
|
||||
}
|
||||
|
||||
fun isActive(): Boolean = profileFunction.secondsFromMidnight() >= validFrom() && profileFunction.secondsFromMidnight() <= validTo()
|
||||
fun isActive(): Boolean = profileFunction.secondsFromMidnight() >= validFrom() && profileFunction.secondsFromMidnight() <= validTo() && forDevice(DEVICE_PHONE)
|
||||
|
||||
fun doCalc(profile: Profile, profileName: String, lastBG: GlucoseValue, _synchronized: Boolean): BolusWizard {
|
||||
val dbRecord = repository.getTemporaryTargetActiveAt(dateUtil.now()).blockingGet()
|
||||
|
@ -119,10 +140,16 @@ class QuickWizardEntry @Inject constructor(private val injector: HasAndroidInjec
|
|||
} else if (useTrend() == NEGATIVE_ONLY && glucoseStatus != null && glucoseStatus.shortAvgDelta < 0) {
|
||||
trend = true
|
||||
}
|
||||
val percentage = sp.getInt(R.string.key_boluswizard_percentage, 100)
|
||||
val percentage = if (usePercentage() == DEFAULT) sp.getInt(R.string.key_boluswizard_percentage, 100) else percentage()
|
||||
return BolusWizard(injector).doCalc(profile, profileName, tempTarget, carbs(), cob, bg, 0.0, percentage, true, useCOB() == YES, bolusIOB, basalIOB, superBolus, useTempTarget() == YES, trend, false, buttonText(), quickWizard = true) //tbc, ok if only quickwizard, but if other sources elsewhere use Sources.QuickWizard
|
||||
}
|
||||
|
||||
fun guid(): String = safeGetString(storage, "guid", "")
|
||||
|
||||
fun device(): Int = safeGetInt(storage, "device", DEVICE_ALL)
|
||||
|
||||
fun forDevice(device: Int) = device() == device || device() == DEVICE_ALL
|
||||
|
||||
fun buttonText(): String = safeGetString(storage, "buttonText", "")
|
||||
|
||||
fun carbs(): Int = safeGetInt(storage, "carbs")
|
||||
|
@ -148,4 +175,8 @@ class QuickWizardEntry @Inject constructor(private val injector: HasAndroidInjec
|
|||
fun useSuperBolus(): Int = safeGetInt(storage, "useSuperBolus", NO)
|
||||
|
||||
fun useTempTarget(): Int = safeGetInt(storage, "useTempTarget", NO)
|
||||
}
|
||||
|
||||
fun usePercentage(): Int = safeGetInt(storage, "usePercentage", DEFAULT)
|
||||
|
||||
fun percentage(): Int = safeGetInt(storage, "percentage", 100)
|
||||
}
|
||||
|
|
|
@ -83,14 +83,14 @@
|
|||
android:layout_width="150dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="10dp"
|
||||
android:labelFor="@+id/age"
|
||||
android:text="@string/age"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Medium" />
|
||||
|
||||
<info.nightscout.androidaps.utils.ui.NumberPicker
|
||||
android:id="@+id/age"
|
||||
android:layout_width="130dp"
|
||||
android:layout_height="40dp" />
|
||||
android:layout_height="40dp"
|
||||
app:customContentDescription="@string/age" />
|
||||
|
||||
</TableRow>
|
||||
|
||||
|
@ -105,14 +105,14 @@
|
|||
android:layout_width="150dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="10dp"
|
||||
android:labelFor="@+id/weight"
|
||||
android:text="@string/tdd_total"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Medium" />
|
||||
|
||||
<info.nightscout.androidaps.utils.ui.NumberPicker
|
||||
android:id="@+id/tdd"
|
||||
android:layout_width="130dp"
|
||||
android:layout_height="40dp" />
|
||||
android:layout_height="40dp"
|
||||
app:customContentDescription="@string/tdd_total" />
|
||||
|
||||
</TableRow>
|
||||
|
||||
|
@ -123,18 +123,18 @@
|
|||
android:gravity="center_vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/weigth_label"
|
||||
android:id="@+id/weight_label"
|
||||
android:layout_width="150dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="10dp"
|
||||
android:labelFor="@+id/weight"
|
||||
android:text="@string/weight_label"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Medium" />
|
||||
|
||||
<info.nightscout.androidaps.utils.ui.NumberPicker
|
||||
android:id="@+id/weight"
|
||||
android:layout_width="130dp"
|
||||
android:layout_height="40dp" />
|
||||
android:layout_height="40dp"
|
||||
app:customContentDescription="@string/weight_label" />
|
||||
|
||||
</TableRow>
|
||||
|
||||
|
@ -149,14 +149,14 @@
|
|||
android:layout_width="150dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="10dp"
|
||||
android:labelFor="@+id/basalpctfromtdd"
|
||||
android:text="@string/basalpctfromtdd_label"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Medium" />
|
||||
|
||||
<info.nightscout.androidaps.utils.ui.NumberPicker
|
||||
android:id="@+id/basalpctfromtdd"
|
||||
android:layout_width="130dp"
|
||||
android:layout_height="40dp" />
|
||||
android:layout_height="40dp"
|
||||
app:customContentDescription="@string/basalpctfromtdd_label" />
|
||||
|
||||
</TableRow>
|
||||
|
||||
|
|
|
@ -58,6 +58,7 @@
|
|||
android:paddingTop="10dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/bg_label"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
|
@ -70,7 +71,8 @@
|
|||
<info.nightscout.androidaps.utils.ui.NumberPicker
|
||||
android:id="@+id/bg"
|
||||
android:layout_width="130dp"
|
||||
android:layout_height="40dp" />
|
||||
android:layout_height="40dp"
|
||||
app:customContentDescription="@string/treatments_wizard_bg_label" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/units"
|
||||
|
|
|
@ -93,6 +93,7 @@
|
|||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/time_label"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
|
@ -105,25 +106,24 @@
|
|||
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<ImageView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:src="@drawable/ic_access_alarm_24dp" />
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/alarmCheckBox"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:checked="false"
|
||||
android:padding="2dp" />
|
||||
android:padding="2dp"
|
||||
android:layoutDirection="rtl"
|
||||
android:contentDescription="@string/a11y_carb_reminder"
|
||||
android:drawableEnd="@drawable/ic_access_alarm_24dp" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<info.nightscout.androidaps.utils.ui.MinutesNumberPicker
|
||||
android:id="@+id/time"
|
||||
android:layout_width="130dp"
|
||||
android:layout_height="40dp" />
|
||||
android:layout_height="40dp"
|
||||
app:customContentDescription="@string/time_offset" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
|
@ -143,6 +143,7 @@
|
|||
android:layout_gravity="center_vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/duration_label"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
|
@ -156,7 +157,8 @@
|
|||
android:id="@+id/duration"
|
||||
android:layout_width="130dp"
|
||||
android:layout_height="40dp"
|
||||
android:layout_gravity="center_horizontal" />
|
||||
android:layout_gravity="center_horizontal"
|
||||
app:customContentDescription="@string/careportal_newnstreatment_duration_label" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
|
@ -176,6 +178,7 @@
|
|||
android:layout_gravity="center_vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/carbs_label"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
|
@ -190,7 +193,8 @@
|
|||
<info.nightscout.androidaps.utils.ui.NumberPicker
|
||||
android:id="@+id/carbs"
|
||||
android:layout_width="130dp"
|
||||
android:layout_height="40dp" />
|
||||
android:layout_height="40dp"
|
||||
app:customContentDescription="@string/treatments_wizard_carbs_label" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
|
|
|
@ -86,6 +86,7 @@
|
|||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/bg_label"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
|
@ -98,7 +99,8 @@
|
|||
<info.nightscout.androidaps.utils.ui.NumberPicker
|
||||
android:id="@+id/bg"
|
||||
android:layout_width="130dp"
|
||||
android:layout_height="40dp" />
|
||||
android:layout_height="40dp"
|
||||
app:customContentDescription="@string/treatments_wizard_bg_label" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/bg_units"
|
||||
|
@ -121,6 +123,7 @@
|
|||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/duration_label"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
|
@ -133,7 +136,8 @@
|
|||
<info.nightscout.androidaps.utils.ui.MinutesNumberPicker
|
||||
android:id="@+id/duration"
|
||||
android:layout_width="130dp"
|
||||
android:layout_height="40dp" />
|
||||
android:layout_height="40dp"
|
||||
app:customContentDescription="@string/careportal_newnstreatment_duration_label" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
|
|
|
@ -53,6 +53,7 @@
|
|||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/insulin_label"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
|
@ -65,7 +66,8 @@
|
|||
<info.nightscout.androidaps.utils.ui.NumberPicker
|
||||
android:id="@+id/insulin"
|
||||
android:layout_width="130dp"
|
||||
android:layout_height="40dp" />
|
||||
android:layout_height="40dp"
|
||||
app:customContentDescription="@string/overview_insulin_label" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
|
@ -86,6 +88,7 @@
|
|||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/duration_label"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
|
@ -98,7 +101,8 @@
|
|||
<info.nightscout.androidaps.utils.ui.MinutesNumberPicker
|
||||
android:id="@+id/duration"
|
||||
android:layout_width="130dp"
|
||||
android:layout_height="40dp" />
|
||||
android:layout_height="40dp"
|
||||
app:customContentDescription="@string/careportal_newnstreatment_duration_label" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
|
|
|
@ -75,6 +75,7 @@
|
|||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/fill_label"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
|
@ -89,7 +90,8 @@
|
|||
android:layout_height="40dp"
|
||||
android:layout_gravity="end"
|
||||
android:paddingLeft="5dp"
|
||||
android:paddingRight="5dp" />
|
||||
android:paddingRight="5dp"
|
||||
app:customContentDescription="@string/overview_insulin_label" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
|
|
|
@ -76,6 +76,7 @@
|
|||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/time_label"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
|
@ -88,7 +89,8 @@
|
|||
<info.nightscout.androidaps.utils.ui.MinutesNumberPicker
|
||||
android:id="@+id/time"
|
||||
android:layout_width="130dp"
|
||||
android:layout_height="40dp" />
|
||||
android:layout_height="40dp"
|
||||
app:customContentDescription="@string/time_offset"/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
|
@ -109,6 +111,7 @@
|
|||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/insulin_label"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
|
@ -121,7 +124,8 @@
|
|||
<info.nightscout.androidaps.utils.ui.NumberPicker
|
||||
android:id="@+id/amount"
|
||||
android:layout_width="130dp"
|
||||
android:layout_height="40dp" />
|
||||
android:layout_height="40dp"
|
||||
app:customContentDescription="@string/overview_insulin_label"/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
|
@ -147,6 +151,7 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"
|
||||
android:contentDescription="Increment insuline with 0.5"
|
||||
android:text="+0.5" />
|
||||
|
||||
<Button
|
||||
|
|
|
@ -58,6 +58,7 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:width="120dp"
|
||||
android:labelFor="@+id/profile"
|
||||
android:padding="10dp"
|
||||
android:text="@string/profile_label"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
||||
|
@ -95,6 +96,7 @@
|
|||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/duration_label"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
|
@ -108,7 +110,8 @@
|
|||
<info.nightscout.androidaps.utils.ui.MinutesNumberPicker
|
||||
android:id="@+id/duration"
|
||||
android:layout_width="130dp"
|
||||
android:layout_height="40dp" />
|
||||
android:layout_height="40dp"
|
||||
app:customContentDescription="@string/careportal_newnstreatment_duration_label"/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
|
@ -129,6 +132,7 @@
|
|||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/percentage_label"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
|
@ -142,7 +146,8 @@
|
|||
<info.nightscout.androidaps.utils.ui.NumberPicker
|
||||
android:id="@+id/percentage"
|
||||
android:layout_width="130dp"
|
||||
android:layout_height="40dp" />
|
||||
android:layout_height="40dp"
|
||||
app:customContentDescription="@string/careportal_newnstreatment_percentage_label"/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
|
@ -163,6 +168,7 @@
|
|||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/timeshift_label"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
|
@ -176,7 +182,8 @@
|
|||
<info.nightscout.androidaps.utils.ui.NumberPicker
|
||||
android:id="@+id/timeshift"
|
||||
android:layout_width="130dp"
|
||||
android:layout_height="40dp" />
|
||||
android:layout_height="40dp"
|
||||
app:customContentDescription="@string/careportal_newnstreatment_timeshift_label"/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
|
|
|
@ -54,6 +54,7 @@
|
|||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/basal_percent_label"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
|
@ -66,7 +67,8 @@
|
|||
<info.nightscout.androidaps.utils.ui.NumberPicker
|
||||
android:id="@+id/basal_percent_input"
|
||||
android:layout_width="130dp"
|
||||
android:layout_height="40dp" />
|
||||
android:layout_height="40dp"
|
||||
app:customContentDescription="@string/basal_rate" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
|
@ -88,6 +90,7 @@
|
|||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/basal_absolute_label"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
|
@ -100,7 +103,8 @@
|
|||
<info.nightscout.androidaps.utils.ui.NumberPicker
|
||||
android:id="@+id/basal_absolute_input"
|
||||
android:layout_width="130dp"
|
||||
android:layout_height="40dp" />
|
||||
android:layout_height="40dp"
|
||||
app:customContentDescription="@string/basal_rate" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
|
@ -121,6 +125,7 @@
|
|||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/duration_label"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
|
@ -133,7 +138,8 @@
|
|||
<info.nightscout.androidaps.utils.ui.MinutesNumberPicker
|
||||
android:id="@+id/duration"
|
||||
android:layout_width="130dp"
|
||||
android:layout_height="40dp" />
|
||||
android:layout_height="40dp"
|
||||
app:customContentDescription="@string/careportal_newnstreatment_duration_label" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
|
|
|
@ -54,6 +54,7 @@
|
|||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/temptarget_label"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
|
@ -67,7 +68,8 @@
|
|||
android:id="@+id/temptarget"
|
||||
android:layout_width="130dp"
|
||||
android:layout_height="40dp"
|
||||
android:layout_gravity="center_vertical" />
|
||||
android:layout_gravity="center_vertical"
|
||||
app:customContentDescription="@string/target_label" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/units"
|
||||
|
@ -89,6 +91,7 @@
|
|||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/duration_label"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
|
@ -101,7 +104,8 @@
|
|||
<info.nightscout.androidaps.utils.ui.MinutesNumberPicker
|
||||
android:id="@+id/duration"
|
||||
android:layout_width="130dp"
|
||||
android:layout_height="40dp" />
|
||||
android:layout_height="40dp"
|
||||
app:customContentDescription="@string/careportal_newnstreatment_duration_label" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
|
@ -127,6 +131,7 @@
|
|||
android:layout_gravity="center_vertical"
|
||||
android:width="120dp"
|
||||
android:padding="10dp"
|
||||
android:labelFor="@+id/reason"
|
||||
android:text="@string/reason"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
||||
android:textStyle="bold" />
|
||||
|
|
|
@ -63,6 +63,7 @@
|
|||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/insulin_label"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
|
@ -75,7 +76,8 @@
|
|||
<info.nightscout.androidaps.utils.ui.NumberPicker
|
||||
android:id="@+id/insulin"
|
||||
android:layout_width="130dp"
|
||||
android:layout_height="40dp" />
|
||||
android:layout_height="40dp"
|
||||
app:customContentDescription="@string/overview_insulin_label" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
|
@ -96,6 +98,7 @@
|
|||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/carbs_label"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
|
@ -108,7 +111,8 @@
|
|||
<info.nightscout.androidaps.utils.ui.NumberPicker
|
||||
android:id="@+id/carbs"
|
||||
android:layout_width="130dp"
|
||||
android:layout_height="40dp" />
|
||||
android:layout_height="40dp"
|
||||
app:customContentDescription="@string/treatments_wizard_carbs_label" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
|
|
|
@ -240,6 +240,69 @@
|
|||
android:textAppearance="?android:attr/textAppearanceSmall" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center|center_vertical"
|
||||
android:layout_marginTop="0dp"
|
||||
android:background="@android:color/transparent"
|
||||
android:orientation="horizontal"
|
||||
android:padding="0dp">
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/bg_checkbox_icon"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:paddingStart="5dp"
|
||||
android:paddingEnd="5dp"
|
||||
android:scaleX="0.7"
|
||||
android:scaleY="0.7"
|
||||
android:button="@drawable/checkbox_bg_icon"
|
||||
android:checked="true"
|
||||
android:contentDescription="@string/treatments_wizard_bg_label" />
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/trend_checkbox_icon"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:paddingStart="5dp"
|
||||
android:paddingEnd="5dp"
|
||||
android:scaleX="0.7"
|
||||
android:scaleY="0.7"
|
||||
android:button="@drawable/checkbox_trend_icon"
|
||||
android:checked="true"
|
||||
android:contentDescription="@string/bg_trend_label" />
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/iob_checkbox_icon"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:paddingStart="5dp"
|
||||
android:paddingEnd="5dp"
|
||||
android:scaleX="0.9"
|
||||
android:scaleY="0.9"
|
||||
android:button="@drawable/checkbox_iob_icon"
|
||||
android:checked="true"
|
||||
android:contentDescription="@string/iob" />
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/cob_checkbox_icon"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:paddingStart="5dp"
|
||||
android:paddingEnd="5dp"
|
||||
android:scaleX="0.7"
|
||||
android:scaleY="0.7"
|
||||
android:button="@drawable/checkbox_cob_icon"
|
||||
android:checked="true"
|
||||
android:contentDescription="@string/treatments_wizard_cob_label" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/done_background"
|
||||
|
@ -260,39 +323,7 @@
|
|||
android:contentDescription="@string/show_calculation"
|
||||
android:drawableEnd="@drawable/ic_visibility" />
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/bg_checkbox_icon"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="fill_parent"
|
||||
android:button="@drawable/checkbox_bg_icon"
|
||||
android:checked="true"
|
||||
android:contentDescription="@string/treatments_wizard_bg_label" />
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/trend_checkbox_icon"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="fill_parent"
|
||||
android:button="@drawable/checkbox_trend_icon"
|
||||
android:checked="true"
|
||||
android:contentDescription="@string/bg_trend_label" />
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/iob_checkbox_icon"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="fill_parent"
|
||||
android:button="@drawable/checkbox_iob_icon"
|
||||
android:checked="true"
|
||||
android:contentDescription="@string/iob" />
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/cob_checkbox_icon"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="fill_parent"
|
||||
android:button="@drawable/checkbox_cob_icon"
|
||||
android:checked="true"
|
||||
android:contentDescription="@string/treatments_wizard_cob_label" />
|
||||
|
||||
<include
|
||||
<include
|
||||
android:id="@+id/okcancel"
|
||||
layout="@layout/okcancel" />
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
android:layout_marginStart="10dp"
|
||||
android:layout_marginTop="10dp"
|
||||
android:layout_marginBottom="10dp"
|
||||
android:labelFor="@+id/spinner"
|
||||
android:text="@string/selected_profile"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium" />
|
||||
|
||||
|
@ -97,7 +98,7 @@
|
|||
android:layout_height="35dp"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginStart="15dp"
|
||||
android:contentDescription="@string/addnew"
|
||||
android:contentDescription="@string/a11y_add_new_profile"
|
||||
app:srcCompat="@drawable/ic_add" />
|
||||
|
||||
<ImageView
|
||||
|
@ -106,7 +107,7 @@
|
|||
android:layout_height="35dp"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginStart="15dp"
|
||||
android:contentDescription="@string/clone_label"
|
||||
android:contentDescription="@string/a11y_clone_profile"
|
||||
app:srcCompat="@drawable/ic_clone" />
|
||||
|
||||
<ImageView
|
||||
|
@ -115,7 +116,7 @@
|
|||
android:layout_height="35dp"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginStart="15dp"
|
||||
android:contentDescription="@string/remove_label"
|
||||
android:contentDescription="@string/a11y_delete_current_profile"
|
||||
android:scaleX="1"
|
||||
android:scaleY="1"
|
||||
app:srcCompat="@drawable/ic_remove" />
|
||||
|
@ -190,7 +191,7 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_horizontal"
|
||||
android:text="@string/dia_label"
|
||||
android:text="@string/dia_long_label"
|
||||
android:textColor="@android:color/white"
|
||||
android:textSize="20sp" />
|
||||
|
||||
|
@ -202,6 +203,7 @@
|
|||
android:paddingTop="5dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/dia_label"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
|
@ -214,7 +216,8 @@
|
|||
android:layout_width="130dp"
|
||||
android:layout_height="40dp"
|
||||
android:layout_marginEnd="10dp"
|
||||
android:layout_marginBottom="10dp" />
|
||||
android:layout_marginBottom="10dp"
|
||||
app:customContentDescription="@string/dia" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
|
|
|
@ -108,6 +108,35 @@
|
|||
|
||||
</LinearLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/device_label"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/overview_editquickwizard_show_on_device"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Medium" />
|
||||
|
||||
<RadioGroup
|
||||
android:id="@+id/device"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_margin="15dp">
|
||||
|
||||
<RadioButton
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="All" />
|
||||
|
||||
<RadioButton
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Phone" />
|
||||
|
||||
<RadioButton
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Watch" />
|
||||
|
||||
</RadioGroup>
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
|
@ -276,7 +305,6 @@
|
|||
|
||||
</RadioGroup>
|
||||
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
|
@ -301,6 +329,47 @@
|
|||
|
||||
</RadioGroup>
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/overview_editquickwizard_usepercentage"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Medium" />
|
||||
|
||||
<RadioGroup
|
||||
android:id="@+id/use_percentage"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_margin="15dp">
|
||||
|
||||
<RadioButton
|
||||
android:id="@+id/use_percentage_default"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/app_default" />
|
||||
|
||||
<RadioButton
|
||||
android:id="@+id/use_percentage_custom"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/custom" />
|
||||
|
||||
</RadioGroup>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/percentage_label"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/overview_editquickwizard_percentage"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Medium" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/percentage"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:ems="10"
|
||||
android:inputType="number"
|
||||
android:maxLength="3"
|
||||
android:paddingLeft="10dp" />
|
||||
|
||||
<include
|
||||
android:id="@+id/okcancel"
|
||||
|
|
|
@ -407,6 +407,19 @@
|
|||
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
|
||||
android:textStyle="bold"
|
||||
tools:ignore="HardcodedText" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/variable_sensitivity"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="-9dp"
|
||||
android:gravity="center_horizontal"
|
||||
android:paddingBottom="3dp"
|
||||
android:text="n/a"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
|
||||
android:textStyle="bold"
|
||||
android:visibility="visible"
|
||||
tools:ignore="HardcodedText" />
|
||||
</LinearLayout>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -16,9 +16,9 @@
|
|||
android:orientation="vertical">
|
||||
|
||||
<LinearLayout
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="wrap_content"
|
||||
|
@ -29,37 +29,64 @@
|
|||
card_view:srcCompat="@drawable/ic_quick_wizard" />
|
||||
|
||||
<LinearLayout
|
||||
android:orientation="vertical"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content">
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:baselineAligned="true"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/overview_quickwizard_item_buttonText"
|
||||
<TextView
|
||||
android:id="@+id/overview_quickwizard_item_buttonText"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingLeft="10dp"
|
||||
android:text="Sample button text"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
|
||||
android:textColor="@color/cardObjectiveText"
|
||||
android:textStyle="normal|bold" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/overview_quickwizard_item_carbs"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingLeft="10dp"
|
||||
android:text="36g"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
|
||||
android:textColor="@color/cardObjectiveText"
|
||||
android:textStyle="normal|bold" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/overview_quickwizard_item_device"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingLeft="10dp"
|
||||
android:text="Sample button text"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
|
||||
android:textStyle="normal|bold"
|
||||
android:textColor="@color/cardObjectiveText" />
|
||||
android:adjustViewBounds="false"
|
||||
android:cropToPadding="false"
|
||||
android:paddingRight="10dp"
|
||||
android:scaleType="fitStart"
|
||||
card_view:srcCompat="@drawable/ic_smartphone" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/overview_quickwizard_item_carbs"
|
||||
<ImageView
|
||||
android:id="@+id/handleView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingLeft="10dp"
|
||||
android:text="36g"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
|
||||
android:textColor="@color/cardObjectiveText"
|
||||
android:textStyle="normal|bold" />
|
||||
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_centerVertical="true"
|
||||
android:adjustViewBounds="false"
|
||||
android:cropToPadding="false"
|
||||
android:scaleType="fitStart"
|
||||
card_view:srcCompat="@drawable/ic_reorder_gray_24dp" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
@ -88,9 +115,9 @@
|
|||
android:textStyle="normal|bold" />
|
||||
|
||||
<TextView
|
||||
android:text="-"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
android:layout_height="wrap_content"
|
||||
android:text="-" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/overview_quickwizard_item_to"
|
||||
|
|
|
@ -80,6 +80,7 @@
|
|||
<string name="description_ns_client">Synchronizes your data with Nightscout</string>
|
||||
<string name="description_ama">State of the algorithm in 2017</string>
|
||||
<string name="description_smb">Most recent algorithm for advanced users</string>
|
||||
<string name="description_smb_dynamic_isf">Most recent algorithm for advanced users with dynamic/automatic ISF</string>
|
||||
<string name="description_overview">Displays the current state of your loop and buttons for most common actions</string>
|
||||
<string name="description_persistent_notification">Shows an ongoing notification with a short overview of what your loop is doing</string>
|
||||
<string name="description_profile_local">Define a profile which is available offline.</string>
|
||||
|
@ -313,7 +314,7 @@
|
|||
<string name="wear">Wear</string>
|
||||
<string name="resend_all_data">Resend All Data</string>
|
||||
<string name="open_settings_on_wear">Open Settings on Wear</string>
|
||||
<string name="basal_rate">Basal rate:</string>
|
||||
<string name="basal_rate">Basal rate</string>
|
||||
<string name="basalvaluebelowminimum">Basal value below minimum. Profile not set!</string>
|
||||
<string name="sms_actualbg">BG:</string>
|
||||
<string name="sms_lastbg">Last BG:</string>
|
||||
|
@ -535,6 +536,7 @@
|
|||
<string name="ns_localbroadcasts">Enable broadcasts to other apps (like xDrip+). Do not enable if you have more than one instance of AAPS or NSClient installed!</string>
|
||||
<string name="ns_localbroadcasts_title">Enable local Broadcasts.</string>
|
||||
<string name="openapssmb">OpenAPS SMB</string>
|
||||
<string name="openaps_smb_dynamic_isf">OpenAPS SMB Dynamic ISF</string>
|
||||
<string name="key_use_smb" translatable="false">use_smb</string>
|
||||
<string name="key_use_uam" translatable="false">use_uam</string>
|
||||
<string name="key_smb_enable_carbs_suggestions_threshold" translatable="false">smb_enable_carbs_suggestions_threshold</string>
|
||||
|
@ -617,6 +619,7 @@
|
|||
<string name="negativeonly">Negative only</string>
|
||||
<string name="overview_editquickwizard_usecob">COB calculation</string>
|
||||
<string name="overview_editquickwizard_usetemptarget">Temporary target calculation</string>
|
||||
<string name="overview_editquickwizard_usepercentage">Percentage calculation</string>
|
||||
<string name="loopenabled">Loop enabled</string>
|
||||
<string name="apsselected">APS selected</string>
|
||||
<string name="nsclienthaswritepermission">NSClient has write permission</string>
|
||||
|
@ -953,8 +956,8 @@
|
|||
<string name="low_mark_comment">Lower value of in range area (display only)</string>
|
||||
<string name="high_mark_comment">Higher value of in range area (display only)</string>
|
||||
|
||||
<string name="age">Age:</string>
|
||||
<string name="weight_label">Weight:</string>
|
||||
<string name="age">Age</string>
|
||||
<string name="weight_label">Weight</string>
|
||||
<string name="id">ID:</string>
|
||||
<string name="submit">Submit</string>
|
||||
<string name="mostcommonprofile">Most common profile:</string>
|
||||
|
@ -1164,5 +1167,44 @@
|
|||
<string name="a11y_insulin_label">insulin</string>
|
||||
<string name="a11y_blood_glucose">blood glucose</string>
|
||||
<string name="a11y_bg_outdated">outdated</string>
|
||||
<string name="a11y_carb_reminder">set reminder</string>
|
||||
<string name="a11y_add_new_profile">add new profile</string>
|
||||
<string name="a11y_clone_profile">clone current profile</string>
|
||||
<string name="a11y_delete_current_profile">delete current profile</string>
|
||||
<string name="a11y_add_new_to_list">add new to list</string>
|
||||
|
||||
<!-- WEAR OS-->
|
||||
<string name="wear_action_tempt_preset_error">Temptarget unknown preset: %1$s</string>
|
||||
<string name="wear_action_tempt_cancel_message">Cancelling running Temp-Targets?</string>
|
||||
<string name="wear_action_tempt_unit_error">Different units used on watch and phone!</string>
|
||||
<string name="wear_action_tempt_zero_message">Zero-Temp-Target - cancelling running Temp-Targets?</string>
|
||||
<string name="wear_action_tempt_min_bg_error">Min-BG out of range!</string>
|
||||
<string name="wear_action_tempt_max_bg_error">Max-BG out of range!</string>
|
||||
<string name="wear_action_tempt_manual_range_message">Temptarget:\nMin: %1$s\nMax: %2$s\nDuration: %3$s</string>
|
||||
<string name="wear_action_tempt_manual_message">Temptarget:\nTarget: %1$s\nDuration: %2$s</string>
|
||||
<string name="wear_action_tempt_preset_message">Temptarget:\Reason: %1$s\nTarget: %2$s\nDuration: %3$s</string>
|
||||
<string name="quick_wizard_message">QuickWizard: %1$s\nInsulin: %2$.2fU\nCarbs: %3$dg</string>
|
||||
<string name="wizard_result">Calc. Wizard:\nInsulin: %1$.2fU\nCarbs: %2$dg</string>
|
||||
<string name="overview_editquickwizard_show_on_device">Show entry on device:</string>
|
||||
<string name="quick_wizard_not_available">Selected quickwizard no longer available, please refresh your tile</string>
|
||||
<string name="wizard_no_actual_bg">No recent BG to base calculation on!</string>
|
||||
<string name="wizard_no_active_profile">No active profile set!</string>
|
||||
<string name="wizard_no_cob">Unknown COB! BG reading missing or recent app restart?</string>
|
||||
<string name="wizard_carbs_constraint">Carb constraint violation!</string>
|
||||
<string name="wizard_explain_calc">Calc (IC: %2$.1f, ISF: %2$.1f) from:"</string>
|
||||
<string name="wizard_explain_carbs">Carbs: %1$.2fU</string>
|
||||
<string name="wizard_explain_cob">COB: %1$.0fg %2$.2fU</string>
|
||||
<string name="wizard_explain_bg">BG: %1$.2fU</string>
|
||||
<string name="wizard_explain_basal_iob">Basal IOB: %1$.2fU</string>
|
||||
<string name="wizard_explain_bolus_iob">Bolus IOB: %1$.2fU</string>
|
||||
<string name="wizard_explain_superbolus">Superbolus: %1$.2fU</string>
|
||||
<string name="wizard_explain_trend">15\' trend: %1$.2fU</string>
|
||||
<string name="wizard_explain_percent">Percentage: %1$.2fU x %2$d%% ≈ %3$.2fU</string>
|
||||
<string name="wizard_constraint_bolus_size">Insulin constraint violation!\nCannot deliver %1$.2fU</string>
|
||||
<string name="wizard_explain_tt">TempT: %1$s</string>
|
||||
<string name="wizard_explain_tt_to">%1$s to %2$s</string>
|
||||
<string name="wizard_pump_not_available">No pump available!</string>
|
||||
<string name="wear_unknown_action_string">Unknown action command:</string>
|
||||
<string name="overview_editquickwizard_percentage">Percentage</string>
|
||||
<string name="app_default">Application default</string>
|
||||
</resources>
|
||||
|
|
|
@ -278,7 +278,7 @@ class AutomationPlugin @Inject constructor(
|
|||
|
||||
@Synchronized
|
||||
fun removeIfExists(event: AutomationEvent) {
|
||||
for (e in automationEvents) {
|
||||
for (e in automationEvents.reversed()) {
|
||||
if (event.title == e.title) {
|
||||
automationEvents.remove(e)
|
||||
rxBus.send(EventAutomationDataChanged())
|
||||
|
@ -301,6 +301,7 @@ class AutomationPlugin @Inject constructor(
|
|||
@Synchronized
|
||||
fun at(index: Int) = automationEvents[index]
|
||||
|
||||
@Synchronized
|
||||
fun size() = automationEvents.size
|
||||
|
||||
@Synchronized
|
||||
|
@ -309,6 +310,7 @@ class AutomationPlugin @Inject constructor(
|
|||
rxBus.send(EventAutomationDataChanged())
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
fun userEvents(): List<AutomationEvent> {
|
||||
val list = mutableListOf<AutomationEvent>()
|
||||
val iterator: MutableIterator<AutomationEvent> = automationEvents.iterator()
|
||||
|
|
|
@ -9,7 +9,7 @@ buildscript {
|
|||
rxkotlin_version = '2.4.0'
|
||||
room_version = '2.3.0'
|
||||
lifecycle_version = '2.3.1'
|
||||
dagger_version = '2.40.5'
|
||||
dagger_version = '2.41'
|
||||
coroutines_version = '1.4.1'
|
||||
activity_version = '1.3.1'
|
||||
fragmentktx_version = '1.3.6'
|
||||
|
@ -41,7 +41,7 @@ buildscript {
|
|||
maven { url "https://plugins.gradle.org/m2/" } // jacoco 0.2
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:7.1.1'
|
||||
classpath 'com.android.tools.build:gradle:7.1.0'
|
||||
classpath 'com.google.gms:google-services:4.3.10'
|
||||
classpath 'com.google.firebase:firebase-crashlytics-gradle:2.8.1'
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ import android.content.Context
|
|||
import android.telephony.SmsManager
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import info.nightscout.androidaps.utils.FabricPrivacy
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelperImplementation
|
||||
import javax.inject.Singleton
|
||||
|
@ -17,7 +18,7 @@ open class CoreModule {
|
|||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideResources(context: Context): ResourceHelper = ResourceHelperImplementation(context)
|
||||
fun provideResources(context: Context, fabricPrivacy: FabricPrivacy): ResourceHelper = ResourceHelperImplementation(context, fabricPrivacy)
|
||||
|
||||
@Provides
|
||||
fun smsManager() : SmsManager = SmsManager.getDefault()
|
||||
|
|
|
@ -1,10 +1,14 @@
|
|||
package info.nightscout.androidaps.interfaces
|
||||
|
||||
import info.nightscout.androidaps.plugins.aps.loop.APSResult
|
||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensResult
|
||||
|
||||
interface APS {
|
||||
|
||||
val lastAPSResult: APSResult?
|
||||
val lastAPSRun: Long
|
||||
var lastDetermineBasalAdapter: DetermineBasalAdapterInterface?
|
||||
var lastAutosensResult: AutosensResult
|
||||
|
||||
operator fun invoke(initiator: String, tempBasalFallback: Boolean)
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
package info.nightscout.androidaps.interfaces
|
||||
|
||||
import info.nightscout.androidaps.data.IobTotal
|
||||
import info.nightscout.androidaps.data.MealData
|
||||
import info.nightscout.androidaps.plugins.aps.loop.APSResult
|
||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus
|
||||
|
||||
interface DetermineBasalAdapterInterface {
|
||||
|
||||
var currentTempParam: String?
|
||||
var iobDataParam: String?
|
||||
var glucoseStatusParam: String?
|
||||
var profileParam: String?
|
||||
var mealDataParam: String?
|
||||
var scriptDebug: String
|
||||
|
||||
fun setData(profile: Profile,
|
||||
maxIob: Double,
|
||||
maxBasal: Double,
|
||||
minBg: Double,
|
||||
maxBg: Double,
|
||||
targetBg: Double,
|
||||
basalRate: Double,
|
||||
iobArray: Array<IobTotal>,
|
||||
glucoseStatus: GlucoseStatus,
|
||||
mealData: MealData,
|
||||
autosensDataRatio: Double,
|
||||
tempTargetSet: Boolean,
|
||||
microBolusAllowed: Boolean = false,
|
||||
uamAllowed: Boolean = false,
|
||||
advancedFiltering: Boolean = false,
|
||||
isSaveCgmSource: Boolean = false
|
||||
) {}
|
||||
|
||||
operator fun invoke(): APSResult?
|
||||
}
|
|
@ -35,5 +35,5 @@ class PluginDescription {
|
|||
fun enableByDefault(enableByDefault: Boolean): PluginDescription = this.also { it.enableByDefault = enableByDefault }
|
||||
fun visibleByDefault(visibleByDefault: Boolean): PluginDescription = this.also { it.visibleByDefault = visibleByDefault }
|
||||
fun description(description: Int): PluginDescription = this.also { it.description = description }
|
||||
fun setDefault(): PluginDescription = this.also { it.defaultPlugin = true }
|
||||
fun setDefault(value: Boolean = true): PluginDescription = this.also { it.defaultPlugin = value }
|
||||
}
|
|
@ -77,10 +77,16 @@ class FabricPrivacy @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
// Crashlytics log message
|
||||
fun logMessage(message: String) {
|
||||
aapsLogger.info(LTag.CORE,"Crashlytics log message: $message")
|
||||
FirebaseCrashlytics.getInstance().log(message)
|
||||
}
|
||||
|
||||
// Crashlytics logException
|
||||
fun logException(throwable: Throwable) {
|
||||
aapsLogger.error("Crashlytics log exception: ", throwable)
|
||||
FirebaseCrashlytics.getInstance().recordException(throwable)
|
||||
aapsLogger.error("Exception: ", throwable)
|
||||
}
|
||||
|
||||
fun fabricEnabled(): Boolean {
|
||||
|
|
|
@ -11,17 +11,35 @@ import android.util.DisplayMetrics
|
|||
import androidx.annotation.*
|
||||
import androidx.core.content.ContextCompat
|
||||
import info.nightscout.androidaps.core.R
|
||||
import info.nightscout.androidaps.utils.FabricPrivacy
|
||||
import java.util.*
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
* Created by adrian on 2019-12-23.
|
||||
*/
|
||||
class ResourceHelperImplementation @Inject constructor(private val context: Context) : ResourceHelper {
|
||||
class ResourceHelperImplementation @Inject constructor(private val context: Context, private val fabricPrivacy: FabricPrivacy) : ResourceHelper {
|
||||
|
||||
override fun gs(@StringRes id: Int): String = context.getString(id)
|
||||
|
||||
override fun gs(@StringRes id: Int, vararg args: Any?): String = context.getString(id, *args)
|
||||
override fun gs(@StringRes id: Int, vararg args: Any?) : String {
|
||||
return try {
|
||||
context.getString(id, *args)
|
||||
} catch (exception: Exception) {
|
||||
val resourceName = context.resources.getResourceEntryName(id)
|
||||
val resourceValue = context.getString(id)
|
||||
val currentLocale: Locale = context.resources.configuration.locale
|
||||
fabricPrivacy.logMessage("Failed to get string for resource $resourceName ($id) '$resourceValue' for locale $currentLocale with args ${args.map{it.toString()}}")
|
||||
fabricPrivacy.logException(exception)
|
||||
try {
|
||||
gsNotLocalised(id, *args)
|
||||
} catch (exceptionNonLocalized: Exception) {
|
||||
fabricPrivacy.logMessage("Fallback failed to get string for resource $resourceName ($id) '$resourceValue' with args ${args.map { it.toString() }}")
|
||||
fabricPrivacy.logException(exceptionNonLocalized)
|
||||
"FAILED to get string $resourceName"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun gq(@PluralsRes id: Int, quantity: Int, vararg args: Any?): String =
|
||||
context.resources.getQuantityString(id, quantity, *args)
|
||||
|
@ -29,7 +47,7 @@ class ResourceHelperImplementation @Inject constructor(private val context: Cont
|
|||
override fun gsNotLocalised(@StringRes id: Int, vararg args: Any?): String =
|
||||
with(Configuration(context.resources.configuration)) {
|
||||
setLocale(Locale.ENGLISH)
|
||||
context.createConfigurationContext(this).getString(id, args)
|
||||
context.createConfigurationContext(this).getString(id, *args)
|
||||
}
|
||||
|
||||
override fun gc(@ColorRes id: Int): Int = ContextCompat.getColor(context, id)
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
android:shape="rectangle">
|
||||
<stroke android:width="1dp" android:color="@color/colorLightGray" />
|
||||
<solid android:color="@android:color/white" />
|
||||
<corners android:radius="4dp" />
|
||||
</shape>
|
||||
</item>
|
||||
</layer-list>
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
<vector
|
||||
android:height="48dp"
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="48dp"
|
||||
android:viewportHeight="24"
|
||||
android:height="48dp"
|
||||
android:viewportWidth="24"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="#67DFE8" android:pathData="M18.501,12.002l-0.428,0.564L8.179,5.064c-0.092,-0.07 -0.212,-0.09 -0.323,-0.055L5.115,5.89L1.571,3.501L4.755,6.36L4.647,9.243c-0.004,0.116 0.047,0.226 0.14,0.296l9.895,7.502l-0.428,0.564c-0.26,0.343 -0.193,0.832 0.15,1.092s0.832,0.193 1.092,-0.15l1.653,-2.18l2.219,1.683l-0.719,0.948c-0.26,0.343 -0.193,0.832 0.15,1.092c0.343,0.26 0.832,0.193 1.092,-0.15l2.379,-3.138c0.26,-0.343 0.193,-0.832 -0.15,-1.092c-0.343,-0.26 -0.832,-0.193 -1.092,0.15l-0.719,0.948l-2.219,-1.683l1.653,-2.18c0.26,-0.343 0.193,-0.832 -0.15,-1.092S18.762,11.659 18.501,12.002zM5.458,6.524l2.44,-0.783l9.748,7.39L17.26,13.64l-5.754,-4.362c-0.091,-0.069 -0.221,-0.053 -0.293,0.035L9.087,11.91l-0.67,-0.508l1.526,-1.833c0.002,-0.002 0.004,-0.005 0.006,-0.008c0.068,-0.09 0.054,-0.219 -0.033,-0.291c-0.09,-0.075 -0.224,-0.063 -0.299,0.027l-1.538,1.848l-0.769,-0.583l1.526,-1.833c0.002,-0.002 0.004,-0.005 0.006,-0.008c0.068,-0.09 0.054,-0.219 -0.033,-0.291c-0.09,-0.075 -0.224,-0.063 -0.299,0.027L6.97,10.305L6.201,9.721l1.526,-1.833C7.728,7.886 7.731,7.882 7.732,7.88c0.068,-0.09 0.054,-0.219 -0.033,-0.291C7.609,7.513 7.475,7.526 7.4,7.616L5.861,9.464L5.362,9.085L5.458,6.524z"/>
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#67DFE8"
|
||||
android:pathData="M18.501,12.002l-0.428,0.564L8.179,5.064c-0.092,-0.07 -0.212,-0.09 -0.323,-0.055L5.115,5.89L1.571,3.501L4.755,6.36L4.647,9.243c-0.004,0.116 0.047,0.226 0.14,0.296l9.895,7.502l-0.428,0.564c-0.26,0.343 -0.193,0.832 0.15,1.092s0.832,0.193 1.092,-0.15l1.653,-2.18l2.219,1.683l-0.719,0.948c-0.26,0.343 -0.193,0.832 0.15,1.092c0.343,0.26 0.832,0.193 1.092,-0.15l2.379,-3.138c0.26,-0.343 0.193,-0.832 -0.15,-1.092c-0.343,-0.26 -0.832,-0.193 -1.092,0.15l-0.719,0.948l-2.219,-1.683l1.653,-2.18c0.26,-0.343 0.193,-0.832 -0.15,-1.092S18.762,11.659 18.501,12.002zM5.458,6.524l2.44,-0.783l9.748,7.39L17.26,13.64l-5.754,-4.362c-0.091,-0.069 -0.221,-0.053 -0.293,0.035L9.087,11.91l-0.67,-0.508l1.526,-1.833c0.002,-0.002 0.004,-0.005 0.006,-0.008c0.068,-0.09 0.054,-0.219 -0.033,-0.291c-0.09,-0.075 -0.224,-0.063 -0.299,0.027l-1.538,1.848l-0.769,-0.583l1.526,-1.833c0.002,-0.002 0.004,-0.005 0.006,-0.008c0.068,-0.09 0.054,-0.219 -0.033,-0.291c-0.09,-0.075 -0.224,-0.063 -0.299,0.027L6.97,10.305L6.201,9.721l1.526,-1.833C7.728,7.886 7.731,7.882 7.732,7.88c0.068,-0.09 0.054,-0.219 -0.033,-0.291C7.609,7.513 7.475,7.526 7.4,7.616L5.861,9.464L5.362,9.085L5.458,6.524z" />
|
||||
</vector>
|
||||
|
|
5
core/src/main/res/drawable/ic_smartphone.xml
Normal file
5
core/src/main/res/drawable/ic_smartphone.xml
Normal file
|
@ -0,0 +1,5 @@
|
|||
<vector android:height="24dp" android:tint="#FFFFFF"
|
||||
android:viewportHeight="24" android:viewportWidth="24"
|
||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="@android:color/white" android:pathData="M17,1.01L7,1c-1.1,0 -2,0.9 -2,2v18c0,1.1 0.9,2 2,2h10c1.1,0 2,-0.9 2,-2V3c0,-1.1 -0.9,-1.99 -2,-1.99zM17,19H7V5h10v14z"/>
|
||||
</vector>
|
|
@ -9,13 +9,13 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:width="120dp"
|
||||
android:labelFor="@+id/eventtime"
|
||||
android:paddingLeft="10dp"
|
||||
android:paddingRight="4dp"
|
||||
android:text="@string/event_time_label"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
||||
android:textStyle="bold" />
|
||||
|
||||
|
||||
<TextView
|
||||
android:id="@+id/eventdate"
|
||||
android:layout_width="wrap_content"
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
<string name="key_virtualpump_type" translatable="false">virtualpump_type</string>
|
||||
<string name="key_quickwizard" translatable="false">QuickWizard</string>
|
||||
<string name="key_wear_control" translatable="false">wearcontrol</string>
|
||||
<string name="key_units_mgdl" translatable="false">units_mgdl</string>
|
||||
<string name="key_show_notes_entry_dialogs" translatable="false">show_notes_entry_dialogs</string>
|
||||
<string name="key_openapsama_autosens_max" translatable="false">autosens_max</string>
|
||||
<string name="key_openapsama_autosens_min" translatable="false">autosens_min</string>
|
||||
|
|
|
@ -25,7 +25,7 @@ dependencies {
|
|||
api "io.reactivex.rxjava2:rxandroid:$rxandroid_version"
|
||||
api("io.reactivex.rxjava2:rxkotlin:$rxkotlin_version")
|
||||
|
||||
api "com.google.code.gson:gson:2.8.9"
|
||||
api "com.google.code.gson:gson:2.9.0"
|
||||
|
||||
api "androidx.room:room-runtime:$room_version"
|
||||
kapt "androidx.room:room-compiler:$room_version"
|
||||
|
|
|
@ -30,7 +30,7 @@ android {
|
|||
targetCompatibility JavaVersion.VERSION_11
|
||||
}
|
||||
|
||||
lintOptions {
|
||||
lint {
|
||||
checkReleaseBuilds false
|
||||
disable 'MissingTranslation'
|
||||
disable 'ExtraTranslation'
|
||||
|
|
|
@ -768,7 +768,7 @@ class MedtronicPumpPlugin @Inject constructor(
|
|||
medtronicPumpStatus.tempBasalAmount = absoluteRate
|
||||
medtronicPumpStatus.tempBasalLength = durationInMinutes
|
||||
|
||||
val tempData = PumpDbEntryTBR(absoluteRate, true, durationInMinutes, tbrType)
|
||||
val tempData = PumpDbEntryTBR(absoluteRate, true, durationInMinutes * 60, tbrType)
|
||||
|
||||
medtronicPumpStatus.runningTBRWithTemp = tempData
|
||||
pumpSyncStorage.addTemporaryBasalRateWithTempId(tempData, true, this)
|
||||
|
|
|
@ -3,7 +3,11 @@ package info.nightscout.androidaps.plugins.pump.common.hw.rileylink.ble
|
|||
import android.annotation.SuppressLint
|
||||
import android.bluetooth.*
|
||||
import android.content.Context
|
||||
import android.content.pm.PackageManager
|
||||
import android.os.Build
|
||||
import android.os.SystemClock
|
||||
import androidx.core.content.ContextCompat
|
||||
import info.nightscout.androidaps.interfaces.Config
|
||||
import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.RileyLinkConst
|
||||
import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.RileyLinkUtil
|
||||
import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.ble.data.GattAttributes
|
||||
|
@ -32,14 +36,15 @@ import javax.inject.Singleton
|
|||
* Added: State handling, configuration of RF for different configuration ranges, connection handling
|
||||
*/
|
||||
@Singleton
|
||||
class RileyLinkBLE @Inject constructor(private val context: Context) {
|
||||
|
||||
@Inject lateinit var aapsLogger: AAPSLogger
|
||||
@Inject lateinit var rileyLinkServiceData: RileyLinkServiceData
|
||||
@Inject lateinit var rileyLinkUtil: RileyLinkUtil
|
||||
@Inject lateinit var sp: SP
|
||||
@Inject lateinit var orangeLink: OrangeLinkImpl
|
||||
|
||||
class RileyLinkBLE @Inject constructor(
|
||||
private val context: Context,
|
||||
private val aapsLogger: AAPSLogger,
|
||||
private val rileyLinkServiceData: RileyLinkServiceData,
|
||||
private val rileyLinkUtil: RileyLinkUtil,
|
||||
private val sp: SP,
|
||||
private val orangeLink: OrangeLinkImpl,
|
||||
private val config: Config
|
||||
) {
|
||||
private val gattDebugEnabled = true
|
||||
private var manualDisconnect = false
|
||||
|
||||
|
@ -154,7 +159,12 @@ class RileyLinkBLE @Inject constructor(private val context: Context) {
|
|||
aapsLogger.error(LTag.PUMPBTCOMM, "RileyLink device is null, can't do connectGatt.")
|
||||
return
|
||||
}
|
||||
bluetoothConnectionGatt = rileyLinkDevice?.connectGatt(context, true, bluetoothGattCallback)
|
||||
if (config.PUMPDRIVERS && Build.VERSION.SDK_INT >= /*Build.VERSION_CODES.S*/31 &&
|
||||
ContextCompat.checkSelfPermission(context, "android.permission.BLUETOOTH_CONNECT") == PackageManager.PERMISSION_GRANTED
|
||||
) {
|
||||
aapsLogger.debug(LTag.PUMPBTCOMM, "no permission")
|
||||
return
|
||||
} else bluetoothConnectionGatt = rileyLinkDevice?.connectGatt(context, true, bluetoothGattCallback)
|
||||
// , BluetoothDevice.TRANSPORT_LE
|
||||
if (bluetoothConnectionGatt == null)
|
||||
aapsLogger.error(LTag.PUMPBTCOMM, "Failed to connect to Bluetooth Low Energy device at " + bluetoothAdapter?.address)
|
||||
|
|
|
@ -53,7 +53,7 @@ android {
|
|||
defaultConfig {
|
||||
applicationId "info.nightscout.androidaps"
|
||||
minSdkVersion 23
|
||||
targetSdkVersion 28
|
||||
targetSdkVersion 29
|
||||
versionCode 2
|
||||
versionName "1.0.3"
|
||||
buildConfigField "String", "BUILDVERSION", generateGitBuild()
|
||||
|
@ -107,7 +107,6 @@ dependencies {
|
|||
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
|
||||
implementation 'androidx.wear:wear:1.2.0'
|
||||
|
||||
|
||||
compileOnly "com.google.android.wearable:wearable:${wearableVersion}"
|
||||
implementation "com.google.android.support:wearable:${wearableVersion}"
|
||||
implementation "com.google.android.gms:play-services-wearable:${playServicesWearable}"
|
||||
|
@ -115,6 +114,10 @@ dependencies {
|
|||
implementation(name: 'wearpreferenceactivity-0.5.0', ext: 'aar')
|
||||
implementation('com.github.lecho:hellocharts-library:1.5.8@aar')
|
||||
|
||||
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.0'
|
||||
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-guava:1.6.0'
|
||||
implementation "androidx.core:core-ktx:$core_version"
|
||||
implementation "androidx.wear.tiles:tiles:1.0.1"
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
|
||||
|
||||
testImplementation "junit:junit:$junit_version"
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
package="info.nightscout.androidaps">
|
||||
|
||||
<uses-feature android:name="android.hardware.type.watch" />
|
||||
|
@ -8,6 +9,7 @@
|
|||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||
<uses-permission android:name="android.permission.VIBRATE" />
|
||||
|
||||
<uses-sdk tools:overrideLibrary="androidx.wear.tiles" />
|
||||
|
||||
<application
|
||||
android:name=".Aaps"
|
||||
|
@ -256,6 +258,10 @@
|
|||
android:host="*"
|
||||
android:pathPrefix="/openwearsettings"
|
||||
android:scheme="wear" />
|
||||
<data
|
||||
android:host="*"
|
||||
android:pathPrefix="/send_quick_wizard"
|
||||
android:scheme="wear" />
|
||||
<data
|
||||
android:host="*"
|
||||
android:pathPrefix="/sendstatustowear"
|
||||
|
@ -508,6 +514,54 @@
|
|||
android:value="0" />
|
||||
</service>
|
||||
|
||||
<service
|
||||
android:name=".tile.ActionsTileService"
|
||||
android:exported="true"
|
||||
android:label="@string/label_actions_tile"
|
||||
android:permission="com.google.android.wearable.permission.BIND_TILE_PROVIDER">
|
||||
<intent-filter>
|
||||
<action android:name="androidx.wear.tiles.action.BIND_TILE_PROVIDER" />
|
||||
</intent-filter>
|
||||
|
||||
<meta-data
|
||||
android:name="com.google.android.clockwork.tiles.PROVIDER_CONFIG_ACTION"
|
||||
android:value="tile_configuration_activity" />
|
||||
<meta-data
|
||||
android:name="androidx.wear.tiles.PREVIEW"
|
||||
android:resource="@drawable/action_tile_preview" />
|
||||
</service>
|
||||
|
||||
<service
|
||||
android:name=".tile.TempTargetTileService"
|
||||
android:exported="true"
|
||||
android:label="@string/label_temp_target_tile"
|
||||
android:permission="com.google.android.wearable.permission.BIND_TILE_PROVIDER">
|
||||
<intent-filter>
|
||||
<action android:name="androidx.wear.tiles.action.BIND_TILE_PROVIDER" />
|
||||
</intent-filter>
|
||||
|
||||
<meta-data
|
||||
android:name="com.google.android.clockwork.tiles.PROVIDER_CONFIG_ACTION"
|
||||
android:value="tile_configuration_tempt" />
|
||||
<meta-data
|
||||
android:name="androidx.wear.tiles.PREVIEW"
|
||||
android:resource="@drawable/temp_target_tile_preview" />
|
||||
</service>
|
||||
|
||||
<service
|
||||
android:name=".tile.QuickWizardTileService"
|
||||
android:exported="true"
|
||||
android:label="@string/label_quick_wizard_tile"
|
||||
android:permission="com.google.android.wearable.permission.BIND_TILE_PROVIDER">
|
||||
<intent-filter>
|
||||
<action android:name="androidx.wear.tiles.action.BIND_TILE_PROVIDER" />
|
||||
</intent-filter>
|
||||
|
||||
<meta-data
|
||||
android:name="androidx.wear.tiles.PREVIEW"
|
||||
android:resource="@drawable/quick_wizard_tile_preview" />
|
||||
</service>
|
||||
|
||||
<receiver android:name=".complications.ComplicationTapBroadcastReceiver" />
|
||||
|
||||
<activity
|
||||
|
@ -523,6 +577,7 @@
|
|||
android:label="@string/menu_settings" />
|
||||
<activity
|
||||
android:name=".interaction.actions.WizardActivity"
|
||||
android:exported="true"
|
||||
android:label="@string/menu_wizard" />
|
||||
<activity
|
||||
android:name=".interaction.menus.FillMenuActivity"
|
||||
|
@ -530,9 +585,14 @@
|
|||
<activity
|
||||
android:name=".interaction.menus.StatusMenuActivity"
|
||||
android:label="@string/menu_status" />
|
||||
<activity
|
||||
android:name=".interaction.actions.TreatmentActivity"
|
||||
android:exported="true"
|
||||
android:label="@string/menu_treatment" />
|
||||
<activity
|
||||
android:name=".interaction.actions.BolusActivity"
|
||||
android:label="@string/action_bolus" />
|
||||
android:exported="true"
|
||||
android:label="@string/action_insulin" />
|
||||
<activity
|
||||
android:name=".interaction.actions.CPPActivity"
|
||||
android:label="@string/status_cpp" />
|
||||
|
@ -542,14 +602,21 @@
|
|||
android:launchMode="singleInstance" />
|
||||
<activity
|
||||
android:name=".interaction.actions.FillActivity"
|
||||
android:exported="true"
|
||||
android:label="@string/menu_prime_fill" />
|
||||
<activity
|
||||
android:name=".interaction.actions.ECarbActivity"
|
||||
android:exported="true"
|
||||
android:label="@string/action_carbs" />
|
||||
<activity
|
||||
android:name=".interaction.actions.TempTargetActivity"
|
||||
android:exported="true"
|
||||
android:label="@string/menu_tempt" />
|
||||
|
||||
<activity
|
||||
android:name=".interaction.actions.BackgroundActionActivity"
|
||||
android:exported="true" />
|
||||
|
||||
<activity android:name=".interaction.ConfigurationActivity">
|
||||
<intent-filter>
|
||||
<!-- action-name must be equal with name of xml-ressource where the configuration is describe -->
|
||||
|
@ -567,5 +634,16 @@
|
|||
<category android:name="android.intent.category.DEFAULT" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<activity android:name=".interaction.TileConfigurationActivity">
|
||||
<intent-filter>
|
||||
<action android:name="tile_configuration_activity" />
|
||||
<action android:name="tile_configuration_tempt" />
|
||||
|
||||
<category android:name="com.google.android.clockwork.tiles.category.PROVIDER_CONFIG" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
</application>
|
||||
</manifest>
|
||||
|
|
|
@ -15,7 +15,7 @@ import javax.inject.Inject;
|
|||
|
||||
import dagger.android.DaggerBroadcastReceiver;
|
||||
import info.nightscout.androidaps.R;
|
||||
import info.nightscout.androidaps.interaction.actions.BolusActivity;
|
||||
import info.nightscout.androidaps.interaction.actions.TreatmentActivity;
|
||||
import info.nightscout.androidaps.interaction.actions.ECarbActivity;
|
||||
import info.nightscout.androidaps.interaction.actions.WizardActivity;
|
||||
import info.nightscout.androidaps.interaction.menus.MainMenuActivity;
|
||||
|
@ -77,7 +77,7 @@ public class ComplicationTapBroadcastReceiver extends DaggerBroadcastReceiver {
|
|||
intentOpen = new Intent(context, WizardActivity.class);
|
||||
break;
|
||||
case BOLUS:
|
||||
intentOpen = new Intent(context, BolusActivity.class);
|
||||
intentOpen = new Intent(context, TreatmentActivity.class);
|
||||
break;
|
||||
case ECARB:
|
||||
intentOpen = new Intent(context, ECarbActivity.class);
|
||||
|
|
|
@ -13,18 +13,16 @@ import android.os.Build;
|
|||
import android.os.Bundle;
|
||||
import android.os.SystemClock;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.util.Base64;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.core.app.NotificationCompat;
|
||||
import androidx.core.app.NotificationManagerCompat;
|
||||
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
|
||||
import androidx.wear.tiles.TileService;
|
||||
|
||||
import com.google.android.gms.common.ConnectionResult;
|
||||
import com.google.android.gms.common.api.GoogleApiClient;
|
||||
import com.google.android.gms.common.api.PendingResult;
|
||||
import com.google.android.gms.common.api.ResultCallback;
|
||||
import com.google.android.gms.wearable.CapabilityApi;
|
||||
import com.google.android.gms.wearable.CapabilityInfo;
|
||||
import com.google.android.gms.wearable.ChannelApi;
|
||||
import com.google.android.gms.wearable.DataEvent;
|
||||
import com.google.android.gms.wearable.DataEventBuffer;
|
||||
|
@ -35,7 +33,8 @@ import com.google.android.gms.wearable.NodeApi;
|
|||
import com.google.android.gms.wearable.Wearable;
|
||||
import com.google.android.gms.wearable.WearableListenerService;
|
||||
|
||||
import java.util.Set;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
@ -46,9 +45,11 @@ import info.nightscout.androidaps.interaction.AAPSPreferences;
|
|||
import info.nightscout.androidaps.interaction.actions.AcceptActivity;
|
||||
import info.nightscout.androidaps.interaction.actions.CPPActivity;
|
||||
import info.nightscout.androidaps.interaction.utils.Persistence;
|
||||
import info.nightscout.shared.SafeParse;
|
||||
import info.nightscout.androidaps.interaction.utils.WearUtil;
|
||||
|
||||
import info.nightscout.androidaps.tile.ActionsTileService;
|
||||
import info.nightscout.androidaps.tile.QuickWizardTileService;
|
||||
import info.nightscout.androidaps.tile.TempTargetTileService;
|
||||
import info.nightscout.shared.SafeParse;
|
||||
|
||||
/**
|
||||
* Created by emmablack on 12/26/14.
|
||||
|
@ -59,7 +60,6 @@ public class ListenerService extends WearableListenerService implements GoogleAp
|
|||
@Inject WearUtil wearUtil;
|
||||
@Inject Persistence persistence;
|
||||
|
||||
private static final String WEARABLE_DATA_PATH = "/nightscout_watch_data";
|
||||
private static final String WEARABLE_RESEND_PATH = "/nightscout_watch_data_resend";
|
||||
private static final String WEARABLE_CANCELBOLUS_PATH = "/nightscout_watch_cancel_bolus";
|
||||
public static final String WEARABLE_CONFIRM_ACTIONSTRING_PATH = "/nightscout_watch_confirmactionstring";
|
||||
|
@ -68,13 +68,13 @@ public class ListenerService extends WearableListenerService implements GoogleAp
|
|||
private static final String OPEN_SETTINGS = "/openwearsettings";
|
||||
private static final String NEW_STATUS_PATH = "/sendstatustowear";
|
||||
private static final String NEW_PREFERENCES_PATH = "/sendpreferencestowear";
|
||||
private static final String QUICK_WIZARD_PATH = "/send_quick_wizard";
|
||||
public static final String BASAL_DATA_PATH = "/nightscout_watch_basal";
|
||||
public static final String BOLUS_PROGRESS_PATH = "/nightscout_watch_bolusprogress";
|
||||
public static final String ACTION_CONFIRMATION_REQUEST_PATH = "/nightscout_watch_actionconfirmationrequest";
|
||||
public static final String NEW_CHANGECONFIRMATIONREQUEST_PATH = "/nightscout_watch_changeconfirmationrequest";
|
||||
public static final String ACTION_CANCELNOTIFICATION_REQUEST_PATH = "/nightscout_watch_cancelnotificationrequest";
|
||||
|
||||
|
||||
public static final int BOLUS_PROGRESS_NOTIF_ID = 1;
|
||||
public static final int CONFIRM_NOTIF_ID = 2;
|
||||
public static final int CHANGE_NOTIF_ID = 556677;
|
||||
|
@ -85,29 +85,15 @@ public class ListenerService extends WearableListenerService implements GoogleAp
|
|||
private static final String ACTION_CONFIRMCHANGE = "com.dexdrip.stephenblack.nightwatch.CONFIRMCHANGE";
|
||||
private static final String ACTION_INITIATE_ACTION = "com.dexdrip.stephenblack.nightwatch.INITIATE_ACTION";
|
||||
|
||||
|
||||
private static final String ACTION_RESEND_BULK = "com.dexdrip.stephenblack.nightwatch.RESEND_BULK_DATA";
|
||||
private static final String AAPS_NOTIFY_CHANNEL_ID_OPENLOOP = "AndroidAPS-OpenLoop";
|
||||
private static final String AAPS_NOTIFY_CHANNEL_ID_BOLUSPROGRESS = "bolus progress vibration";
|
||||
private static final String AAPS_NOTIFY_CHANNEL_ID_BOLUSPROGRESS_SILENT = "bolus progress silent";
|
||||
|
||||
|
||||
GoogleApiClient googleApiClient;
|
||||
private long lastRequest = 0;
|
||||
|
||||
private DismissThread bolusprogressThread;
|
||||
private static final String TAG = "ListenerService";
|
||||
|
||||
private DataRequester mDataRequester = null;
|
||||
private static final int GET_CAPABILITIES_TIMEOUT_MS = 5000;
|
||||
|
||||
// Phone
|
||||
private static final String CAPABILITY_PHONE_APP = "phone_app_sync_bgs";
|
||||
private static final String MESSAGE_PATH_PHONE = "/phone_message_path";
|
||||
// Wear
|
||||
private static final String CAPABILITY_WEAR_APP = "wear_app_sync_bgs";
|
||||
private static final String MESSAGE_PATH_WEAR = "/wear_message_path";
|
||||
private final String mPhoneNodeId = null;
|
||||
private String localnode = null;
|
||||
private final String logPrefix = ""; // "WR: "
|
||||
|
||||
// Not derived from DaggerService, do injection here
|
||||
|
@ -117,143 +103,6 @@ public class ListenerService extends WearableListenerService implements GoogleAp
|
|||
super.onCreate();
|
||||
}
|
||||
|
||||
public class DataRequester extends AsyncTask<Void, Void, Void> {
|
||||
Context mContext;
|
||||
String path;
|
||||
byte[] payload;
|
||||
|
||||
|
||||
DataRequester(Context context, String thispath, byte[] thispayload) {
|
||||
path = thispath;
|
||||
payload = thispayload;
|
||||
// Log.d(TAG, logPrefix + "DataRequester DataRequester: " + thispath + " lastRequest:" + lastRequest);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected Void doInBackground(Void... params) {
|
||||
// Log.d(TAG, logPrefix + "DataRequester: doInBack: " + params);
|
||||
|
||||
try {
|
||||
|
||||
forceGoogleApiConnect();
|
||||
DataMap datamap;
|
||||
|
||||
if (isCancelled()) {
|
||||
Log.d(TAG, "doInBackground CANCELLED programmatically");
|
||||
return null;
|
||||
}
|
||||
|
||||
if (googleApiClient != null) {
|
||||
if (!googleApiClient.isConnected())
|
||||
googleApiClient.blockingConnect(15, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
// this code might not be needed in this way, but we need to see that later
|
||||
if ((googleApiClient != null) && (googleApiClient.isConnected())) {
|
||||
if ((System.currentTimeMillis() - lastRequest > 20 * 1000)) {
|
||||
|
||||
// enforce 20-second debounce period
|
||||
lastRequest = System.currentTimeMillis();
|
||||
|
||||
// NodeApi.GetConnectedNodesResult nodes =
|
||||
// Wearable.NodeApi.getConnectedNodes(googleApiClient).await();
|
||||
if (localnode == null || (localnode != null && localnode.isEmpty()))
|
||||
setLocalNodeName();
|
||||
|
||||
CapabilityInfo capabilityInfo = getCapabilities();
|
||||
|
||||
int count = 0;
|
||||
Node phoneNode = null;
|
||||
|
||||
if (capabilityInfo != null) {
|
||||
phoneNode = updatePhoneSyncBgsCapability(capabilityInfo);
|
||||
count = capabilityInfo.getNodes().size();
|
||||
}
|
||||
|
||||
Log.d(TAG, "doInBackground connected. CapabilityApi.GetCapabilityResult mPhoneNodeID="
|
||||
+ (phoneNode != null ? phoneNode.getId() : "") + " count=" + count + " localnode="
|
||||
+ localnode);// KS
|
||||
|
||||
if (count > 0) {
|
||||
|
||||
for (Node node : capabilityInfo.getNodes()) {
|
||||
|
||||
// Log.d(TAG, "doInBackground path: " + path);
|
||||
|
||||
switch (path) {
|
||||
// simple send as is payloads
|
||||
|
||||
case WEARABLE_RESEND_PATH:
|
||||
Wearable.MessageApi.sendMessage(googleApiClient, node.getId(),
|
||||
WEARABLE_RESEND_PATH, null);
|
||||
break;
|
||||
case WEARABLE_DATA_PATH:
|
||||
case WEARABLE_CANCELBOLUS_PATH:
|
||||
case WEARABLE_CONFIRM_ACTIONSTRING_PATH:
|
||||
case WEARABLE_INITIATE_ACTIONSTRING_PATH:
|
||||
case OPEN_SETTINGS:
|
||||
case NEW_STATUS_PATH:
|
||||
case NEW_PREFERENCES_PATH:
|
||||
case BASAL_DATA_PATH:
|
||||
case BOLUS_PROGRESS_PATH:
|
||||
case ACTION_CONFIRMATION_REQUEST_PATH:
|
||||
case NEW_CHANGECONFIRMATIONREQUEST_PATH:
|
||||
case ACTION_CANCELNOTIFICATION_REQUEST_PATH: {
|
||||
Log.w(TAG, logPrefix + "Unhandled path");
|
||||
// sendMessagePayload(node, path, path, payload);
|
||||
}
|
||||
|
||||
default:// SYNC_ALL_DATA
|
||||
// this fall through is messy and non-deterministic for new paths
|
||||
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
Log.d(TAG, logPrefix + "doInBackground connected but getConnectedNodes returns 0.");
|
||||
|
||||
}
|
||||
} else {
|
||||
// no resend
|
||||
Log.d(TAG, logPrefix + "Inside the timeout, will not be executed");
|
||||
|
||||
}
|
||||
} else {
|
||||
Log.d(TAG, logPrefix + "Not connected for sending: api "
|
||||
+ ((googleApiClient == null) ? "is NULL!" : "not null"));
|
||||
if (googleApiClient != null) {
|
||||
googleApiClient.connect();
|
||||
} else {
|
||||
googleApiConnect();
|
||||
}
|
||||
}
|
||||
|
||||
} catch (Exception ex) {
|
||||
Log.e(TAG, logPrefix + "Error executing DataRequester in background. Exception: " + ex.getMessage());
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public CapabilityInfo getCapabilities() {
|
||||
|
||||
CapabilityApi.GetCapabilityResult capabilityResult = Wearable.CapabilityApi.getCapability(googleApiClient,
|
||||
CAPABILITY_PHONE_APP, CapabilityApi.FILTER_REACHABLE).await(GET_CAPABILITIES_TIMEOUT_MS,
|
||||
TimeUnit.MILLISECONDS);
|
||||
|
||||
if (!capabilityResult.getStatus().isSuccess()) {
|
||||
Log.e(TAG, logPrefix + "doInBackground Failed to get capabilities, status: "
|
||||
+ capabilityResult.getStatus().getStatusMessage());
|
||||
return null;
|
||||
}
|
||||
|
||||
return capabilityResult.getCapability();
|
||||
|
||||
}
|
||||
|
||||
public class BolusCancelTask extends AsyncTask<Void, Void, Void> {
|
||||
Context mContext;
|
||||
|
||||
|
@ -263,8 +112,11 @@ public class ListenerService extends WearableListenerService implements GoogleAp
|
|||
|
||||
@Override
|
||||
protected Void doInBackground(Void... params) {
|
||||
// Log.d(TAG, logPrefix + "BolusCancelTask: doInBack: " + params);
|
||||
|
||||
Log.d(TAG, logPrefix + "BolusCancelTask.doInBackground: " + params);
|
||||
if (!googleApiClient.isConnected()) {
|
||||
Log.i(TAG, "BolusCancelTask.doInBackground: not connected");
|
||||
googleApiClient.blockingConnect(15, TimeUnit.SECONDS);
|
||||
}
|
||||
if (googleApiClient.isConnected()) {
|
||||
NodeApi.GetConnectedNodesResult nodes =
|
||||
Wearable.NodeApi.getConnectedNodes(googleApiClient).await();
|
||||
|
@ -272,16 +124,6 @@ public class ListenerService extends WearableListenerService implements GoogleAp
|
|||
Wearable.MessageApi.sendMessage(googleApiClient, node.getId(), WEARABLE_CANCELBOLUS_PATH, null);
|
||||
}
|
||||
|
||||
} else {
|
||||
googleApiClient.blockingConnect(15, TimeUnit.SECONDS);
|
||||
if (googleApiClient.isConnected()) {
|
||||
NodeApi.GetConnectedNodesResult nodes =
|
||||
Wearable.NodeApi.getConnectedNodes(googleApiClient).await();
|
||||
for (Node node : nodes.getNodes()) {
|
||||
Wearable.MessageApi.sendMessage(googleApiClient, node.getId(), WEARABLE_CANCELBOLUS_PATH, null);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -300,9 +142,12 @@ public class ListenerService extends WearableListenerService implements GoogleAp
|
|||
|
||||
@Override
|
||||
protected Void doInBackground(Void... params) {
|
||||
Log.i(TAG, "MessageActionTask.doInBackground: ");
|
||||
|
||||
forceGoogleApiConnect();
|
||||
|
||||
if (!googleApiClient.isConnected()) {
|
||||
Log.i(TAG, "MessageActionTask.doInBackground: not connected");
|
||||
googleApiClient.blockingConnect(15, TimeUnit.SECONDS);
|
||||
}
|
||||
if (googleApiClient.isConnected()) {
|
||||
NodeApi.GetConnectedNodesResult nodes =
|
||||
Wearable.NodeApi.getConnectedNodes(googleApiClient).await();
|
||||
|
@ -310,22 +155,42 @@ public class ListenerService extends WearableListenerService implements GoogleAp
|
|||
Wearable.MessageApi.sendMessage(googleApiClient, node.getId(), mMessagePath, mActionstring.getBytes());
|
||||
}
|
||||
|
||||
} else {
|
||||
googleApiClient.blockingConnect(15, TimeUnit.SECONDS);
|
||||
if (googleApiClient.isConnected()) {
|
||||
NodeApi.GetConnectedNodesResult nodes =
|
||||
Wearable.NodeApi.getConnectedNodes(googleApiClient).await();
|
||||
for (Node node : nodes.getNodes()) {
|
||||
Wearable.MessageApi.sendMessage(googleApiClient, node.getId(), mMessagePath, mActionstring.getBytes());
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public class ResendDataTask extends AsyncTask<Void, Void, Void> {
|
||||
Context mContext;
|
||||
|
||||
ResendDataTask(Context context) {
|
||||
mContext = context;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Void doInBackground(Void... params) {
|
||||
Log.d(TAG, logPrefix + "ResendDataTask.doInBackground: " + params);
|
||||
|
||||
if (!googleApiClient.isConnected()) {
|
||||
Log.i(TAG, "ResendDataTask.doInBackground: not connected");
|
||||
googleApiClient.blockingConnect(15, TimeUnit.SECONDS);
|
||||
}
|
||||
if (googleApiClient.isConnected()) {
|
||||
Log.i(TAG, "ResendDataTask.doInBackground: connected");
|
||||
NodeApi.GetConnectedNodesResult nodes = Wearable.NodeApi.getConnectedNodes(googleApiClient).await();
|
||||
for (Node node : nodes.getNodes()) {
|
||||
Wearable.MessageApi.sendMessage(googleApiClient, node.getId(), WEARABLE_RESEND_PATH, null);
|
||||
}
|
||||
} else {
|
||||
Log.i(TAG, "ResendDataTask.doInBackground: could not connect");
|
||||
}
|
||||
return null;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public void requestData() {
|
||||
sendData(WEARABLE_RESEND_PATH, null);
|
||||
new ResendDataTask(this).execute();
|
||||
}
|
||||
|
||||
public void cancelBolus() {
|
||||
|
@ -340,59 +205,6 @@ public class ListenerService extends WearableListenerService implements GoogleAp
|
|||
new MessageActionTask(this, WEARABLE_INITIATE_ACTIONSTRING_PATH, actionstring).execute();
|
||||
}
|
||||
|
||||
|
||||
private Node updatePhoneSyncBgsCapability(CapabilityInfo capabilityInfo) {
|
||||
// Log.d(TAG, "CapabilityInfo: " + capabilityInfo);
|
||||
|
||||
Set<Node> connectedNodes = capabilityInfo.getNodes();
|
||||
return pickBestNode(connectedNodes);
|
||||
// mPhoneNodeId = pickBestNodeId(connectedNodes);
|
||||
}
|
||||
|
||||
|
||||
private Node pickBestNode(Set<Node> nodes) {
|
||||
Node bestNode = null;
|
||||
// Find a nearby node or pick one arbitrarily
|
||||
for (Node node : nodes) {
|
||||
if (node.isNearby()) {
|
||||
return node;
|
||||
}
|
||||
bestNode = node;
|
||||
}
|
||||
return bestNode;
|
||||
}
|
||||
|
||||
|
||||
private synchronized void sendData(String path, byte[] payload) {
|
||||
// Log.d(TAG, "WR: sendData: path: " + path + ", payload=" + payload);
|
||||
|
||||
if (path == null)
|
||||
return;
|
||||
if (mDataRequester != null) {
|
||||
// Log.d(TAG, logPrefix + "sendData DataRequester != null lastRequest:" +
|
||||
// WearUtil.dateTimeText(lastRequest));
|
||||
if (mDataRequester.getStatus() != AsyncTask.Status.FINISHED) {
|
||||
// Log.d(TAG, logPrefix + "sendData Should be canceled? Let run 'til finished.");
|
||||
// mDataRequester.cancel(true);
|
||||
}
|
||||
}
|
||||
|
||||
Log.d(TAG,
|
||||
logPrefix + "sendData: execute lastRequest:" + wearUtil.dateTimeText(lastRequest));
|
||||
mDataRequester = (DataRequester) new DataRequester(this, path, payload).execute();
|
||||
// executeTask(mDataRequester);
|
||||
|
||||
// if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
|
||||
// Log.d(TAG, "sendData SDK < M call execute lastRequest:" + WearUtil.dateTimeText(lastRequest));
|
||||
// mDataRequester = (DataRequester) new DataRequester(this, path, payload).execute();
|
||||
// } else {
|
||||
// Log.d(TAG, "sendData SDK >= M call executeOnExecutor lastRequest:" + WearUtil.dateTimeText(lastRequest));
|
||||
// // TODO xdrip executor
|
||||
// mDataRequester = (DataRequester) new DataRequester(this, path, payload).executeOnExecutor(xdrip.executor);
|
||||
// }
|
||||
}
|
||||
|
||||
|
||||
private void googleApiConnect() {
|
||||
if (googleApiClient != null) {
|
||||
// Remove old listener(s)
|
||||
|
@ -416,20 +228,6 @@ public class ListenerService extends WearableListenerService implements GoogleAp
|
|||
Wearable.MessageApi.addListener(googleApiClient, this);
|
||||
}
|
||||
|
||||
|
||||
private void forceGoogleApiConnect() {
|
||||
if (googleApiClient == null || (!googleApiClient.isConnected() && !googleApiClient.isConnecting())) {
|
||||
try {
|
||||
Log.d(TAG, "forceGoogleApiConnect: forcing google api reconnection");
|
||||
googleApiConnect();
|
||||
Thread.sleep(2000);
|
||||
} catch (InterruptedException e) {
|
||||
//
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||
|
||||
|
@ -483,7 +281,6 @@ public class ListenerService extends WearableListenerService implements GoogleAp
|
|||
return START_STICKY;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onDataChanged(DataEventBuffer dataEvents) {
|
||||
|
||||
|
@ -541,12 +338,62 @@ public class ListenerService extends WearableListenerService implements GoogleAp
|
|||
LocalBroadcastManager.getInstance(this).sendBroadcast(messageIntent);
|
||||
} else if (path.equals(NEW_PREFERENCES_PATH)) {
|
||||
dataMap = DataMapItem.fromDataItem(event.getDataItem()).getDataMap();
|
||||
if (dataMap.containsKey("wearcontrol")) {
|
||||
boolean wearcontrol = dataMap.getBoolean("wearcontrol", false);
|
||||
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
|
||||
SharedPreferences.Editor editor = sharedPreferences.edit();
|
||||
editor.putBoolean("wearcontrol", wearcontrol);
|
||||
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
|
||||
SharedPreferences.Editor editor = sharedPreferences.edit();
|
||||
String keyControl = getString(R.string.key_wear_control);
|
||||
if (dataMap.containsKey(keyControl)) {
|
||||
boolean previousWearControl = sharedPreferences.getBoolean(keyControl, false);
|
||||
boolean wearControl = dataMap.getBoolean(keyControl, false);
|
||||
editor.putBoolean(keyControl, wearControl);
|
||||
editor.apply();
|
||||
if (wearControl != previousWearControl) {
|
||||
updateTiles();
|
||||
}
|
||||
}
|
||||
String keyPercentage = getString(R.string.key_boluswizard_percentage);
|
||||
if (dataMap.containsKey(keyPercentage)) {
|
||||
int wpercentage = dataMap.getInt(keyPercentage, 100);
|
||||
editor.putInt(keyPercentage, wpercentage);
|
||||
editor.apply();
|
||||
}
|
||||
String keyUnits = getString(R.string.key_units_mgdl);
|
||||
if (dataMap.containsKey(keyUnits)) {
|
||||
boolean mgdl = dataMap.getBoolean(keyUnits, true);
|
||||
editor.putBoolean(keyUnits, mgdl);
|
||||
editor.apply();
|
||||
}
|
||||
String keyMaxCarbs = getString(R.string.key_treatmentssafety_maxcarbs);
|
||||
if (dataMap.containsKey(keyMaxCarbs)) {
|
||||
int maxCarbs = dataMap.getInt(keyMaxCarbs, 48);
|
||||
editor.putInt(keyMaxCarbs, maxCarbs);
|
||||
editor.apply();
|
||||
}
|
||||
String keyMaxBolus = getString(R.string.key_treatmentssafety_maxbolus);
|
||||
if (dataMap.containsKey(keyMaxBolus)) {
|
||||
float maxBolus = (float)dataMap.getDouble(keyMaxBolus, 3.0f);
|
||||
editor.putFloat(keyMaxBolus, maxBolus);
|
||||
editor.apply();
|
||||
}
|
||||
|
||||
} else if (path.equals(QUICK_WIZARD_PATH)) {
|
||||
dataMap = DataMapItem.fromDataItem(event.getDataItem()).getDataMap();
|
||||
Log.i(TAG, "onDataChanged: QUICK_WIZARD_PATH" + dataMap);
|
||||
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
|
||||
dataMap.remove("timestamp");
|
||||
String key = getString(R.string.key_quick_wizard_data_map);
|
||||
String dataString = Base64.encodeToString(dataMap.toByteArray(), Base64.DEFAULT);
|
||||
if (!dataString.equals(sharedPreferences.getString(key, ""))) {
|
||||
SharedPreferences.Editor editor = sharedPreferences.edit();
|
||||
editor.putString(key, dataString);
|
||||
editor.apply();
|
||||
// Todo maybe add debounce function, due to 20 seconds update limit?
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
TileService.getUpdater(this)
|
||||
.requestUpdate(QuickWizardTileService.class);
|
||||
}
|
||||
Log.i(TAG, "onDataChanged: updated QUICK_WIZARD");
|
||||
} else {
|
||||
Log.i(TAG, "onDataChanged: ignore update");
|
||||
}
|
||||
} else if (path.equals(NEW_CHANGECONFIRMATIONREQUEST_PATH)) {
|
||||
String title = DataMapItem.fromDataItem(event.getDataItem()).getDataMap().getString("title");
|
||||
|
@ -568,6 +415,19 @@ public class ListenerService extends WearableListenerService implements GoogleAp
|
|||
}
|
||||
}
|
||||
|
||||
private void updateTiles() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
TileService.getUpdater(this)
|
||||
.requestUpdate(ActionsTileService.class);
|
||||
|
||||
TileService.getUpdater(this)
|
||||
.requestUpdate(TempTargetTileService.class);
|
||||
|
||||
TileService.getUpdater(this)
|
||||
.requestUpdate(QuickWizardTileService.class);
|
||||
}
|
||||
}
|
||||
|
||||
private void notifyChangeRequest(String title, String message, String actionstring) {
|
||||
// Create the NotificationChannel, but only on API 26+ because
|
||||
// the NotificationChannel class is new and not in the support library
|
||||
|
@ -639,7 +499,7 @@ public class ListenerService extends WearableListenerService implements GoogleAp
|
|||
PendingIntent cancelPendingIntent = PendingIntent.getService(this, 0, cancelIntent, 0);
|
||||
|
||||
NotificationCompat.Builder notificationBuilder =
|
||||
new NotificationCompat.Builder(this, vibrate ? AAPS_NOTIFY_CHANNEL_ID_BOLUSPROGRESS: AAPS_NOTIFY_CHANNEL_ID_BOLUSPROGRESS_SILENT)
|
||||
new NotificationCompat.Builder(this, vibrate ? AAPS_NOTIFY_CHANNEL_ID_BOLUSPROGRESS : AAPS_NOTIFY_CHANNEL_ID_BOLUSPROGRESS_SILENT)
|
||||
.setSmallIcon(R.drawable.ic_icon)
|
||||
.setContentTitle(getString(R.string.bolus_progress))
|
||||
.setContentText(progresspercent + "% - " + progresstatus)
|
||||
|
@ -696,7 +556,6 @@ public class ListenerService extends WearableListenerService implements GoogleAp
|
|||
bolusprogressThread.start();
|
||||
}
|
||||
|
||||
|
||||
private class DismissThread extends Thread {
|
||||
private final int notificationID;
|
||||
private final int seconds;
|
||||
|
@ -730,7 +589,7 @@ public class ListenerService extends WearableListenerService implements GoogleAp
|
|||
context.startService(intent);
|
||||
}
|
||||
|
||||
public static void initiateAction(Context context, String actionstring) {
|
||||
public static void initiateAction(Context context, @NotNull String actionstring) {
|
||||
Intent intent = new Intent(context, ListenerService.class);
|
||||
intent.putExtra("actionstring", actionstring);
|
||||
intent.setAction(ACTION_INITIATE_ACTION);
|
||||
|
@ -753,20 +612,8 @@ public class ListenerService extends WearableListenerService implements GoogleAp
|
|||
public void onConnected(Bundle bundle) {
|
||||
// Log.d(TAG, logPrefix + "onConnected call requestData");
|
||||
|
||||
CapabilityApi.CapabilityListener capabilityListener = new CapabilityApi.CapabilityListener() {
|
||||
|
||||
@Override
|
||||
public void onCapabilityChanged(CapabilityInfo capabilityInfo) {
|
||||
updatePhoneSyncBgsCapability(capabilityInfo);
|
||||
Log.d(TAG, logPrefix + "onConnected onCapabilityChanged mPhoneNodeID:" + mPhoneNodeId
|
||||
+ ", Capability: " + capabilityInfo);
|
||||
}
|
||||
};
|
||||
|
||||
Wearable.CapabilityApi.addCapabilityListener(googleApiClient, capabilityListener, CAPABILITY_PHONE_APP);
|
||||
|
||||
Wearable.ChannelApi.addListener(googleApiClient, this);
|
||||
requestData();
|
||||
// requestData();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -779,28 +626,6 @@ public class ListenerService extends WearableListenerService implements GoogleAp
|
|||
|
||||
}
|
||||
|
||||
|
||||
private void setLocalNodeName() {
|
||||
forceGoogleApiConnect();
|
||||
PendingResult<NodeApi.GetLocalNodeResult> result = Wearable.NodeApi.getLocalNode(googleApiClient);
|
||||
result.setResultCallback(new ResultCallback<NodeApi.GetLocalNodeResult>() {
|
||||
|
||||
@Override
|
||||
public void onResult(NodeApi.GetLocalNodeResult getLocalNodeResult) {
|
||||
if (!getLocalNodeResult.getStatus().isSuccess()) {
|
||||
Log.e(TAG, "ERROR: failed to getLocalNode Status="
|
||||
+ getLocalNodeResult.getStatus().getStatusMessage());
|
||||
} else {
|
||||
Log.d(TAG, "getLocalNode Status=: " + getLocalNodeResult.getStatus().getStatusMessage());
|
||||
Node getnode = getLocalNodeResult.getNode();
|
||||
localnode = getnode != null ? getnode.getDisplayName() + "|" + getnode.getId() : "";
|
||||
Log.d(TAG, "setLocalNodeName. localnode=" + localnode);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
|
|
|
@ -5,6 +5,8 @@ import android.os.Bundle;
|
|||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.core.content.ContextCompat;
|
||||
|
||||
import info.nightscout.androidaps.R;
|
||||
import preference.WearPreferenceActivity;
|
||||
|
||||
|
@ -14,21 +16,15 @@ public class AAPSPreferences extends WearPreferenceActivity {
|
|||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
addPreferencesFromResource(R.xml.preferences);
|
||||
ViewGroup view = (ViewGroup)getWindow().getDecorView();
|
||||
ViewGroup view = (ViewGroup) getWindow().getDecorView();
|
||||
removeBackgroundRecursively(view);
|
||||
view.setBackground(getResources().getDrawable(R.drawable.settings_background));
|
||||
view.setBackground(ContextCompat.getDrawable(this, R.drawable.settings_background));
|
||||
view.requestFocus();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPause(){
|
||||
super.onPause();
|
||||
finish();
|
||||
}
|
||||
|
||||
void removeBackgroundRecursively(View parent) {
|
||||
if (parent instanceof ViewGroup) {
|
||||
ViewGroup group = (ViewGroup)parent;
|
||||
ViewGroup group = (ViewGroup) parent;
|
||||
for (int i = 0; i < group.getChildCount(); i++) {
|
||||
removeBackgroundRecursively(group.getChildAt(i));
|
||||
}
|
||||
|
@ -36,5 +32,4 @@ public class AAPSPreferences extends WearPreferenceActivity {
|
|||
parent.setBackground(null);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,6 +5,9 @@ import android.os.Bundle;
|
|||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.core.content.ContextCompat;
|
||||
|
||||
import info.nightscout.androidaps.R;
|
||||
import preference.WearPreferenceActivity;
|
||||
|
||||
|
@ -14,14 +17,14 @@ public class ConfigurationActivity extends WearPreferenceActivity {
|
|||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setTitle("Watchface");
|
||||
String configFileName=getIntent().getAction();
|
||||
String configFileName = getIntent().getAction();
|
||||
int resXmlId = getResources().getIdentifier(configFileName, "xml", getApplicationContext().getPackageName());
|
||||
Log.d("ConfigurationActivity::onCreate --->> getIntent().getAction()",configFileName);
|
||||
Log.d("ConfigurationActivity::onCreate --->> resXmlId",String.valueOf(resXmlId));
|
||||
Log.d("ConfigurationActivity::onCreate --->> getIntent().getAction()", configFileName);
|
||||
Log.d("ConfigurationActivity::onCreate --->> resXmlId", String.valueOf(resXmlId));
|
||||
addPreferencesFromResource(resXmlId);
|
||||
ViewGroup view = (ViewGroup) getWindow().getDecorView();
|
||||
removeBackgroundRecursively(view);
|
||||
view.setBackground(getResources().getDrawable(R.drawable.settings_background));
|
||||
view.setBackground(ContextCompat.getDrawable(this, R.drawable.settings_background));
|
||||
view.requestFocus();
|
||||
}
|
||||
|
||||
|
@ -41,5 +44,4 @@ public class ConfigurationActivity extends WearPreferenceActivity {
|
|||
parent.setBackground(null);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
package info.nightscout.androidaps.interaction
|
||||
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.view.ViewGroup
|
||||
import androidx.wear.tiles.TileService
|
||||
import preference.WearPreferenceActivity
|
||||
import info.nightscout.androidaps.tile.ActionsTileService
|
||||
import info.nightscout.androidaps.tile.TempTargetTileService
|
||||
|
||||
var TAG = "ASTAG-config"
|
||||
|
||||
class TileConfigurationActivity : WearPreferenceActivity() {
|
||||
|
||||
private var configFileName: String? = null
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
title = "Tile"
|
||||
configFileName = intent.action
|
||||
val resXmlId = resources.getIdentifier(configFileName, "xml", applicationContext.packageName)
|
||||
Log.d("ConfigurationActivity::onCreate --->> getIntent().getAction()", configFileName!!)
|
||||
Log.d("ConfigurationActivity::onCreate --->> resXmlId", resXmlId.toString())
|
||||
addPreferencesFromResource(resXmlId)
|
||||
val view = window.decorView as ViewGroup
|
||||
view.requestFocus()
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
// Note that TileService updates are hard limited to once every 20 seconds.
|
||||
if (configFileName === "tile_configuration_activity") {
|
||||
Log.i(TAG, "onDestroy a: requestUpdate!!")
|
||||
TileService.getUpdater(this)
|
||||
.requestUpdate(ActionsTileService::class.java)
|
||||
} else if (configFileName === "tile_configuration_tempt") {
|
||||
Log.i(TAG, "onDestroy tt: requestUpdate!!")
|
||||
TileService.getUpdater(this)
|
||||
.requestUpdate(TempTargetTileService::class.java)
|
||||
} else {
|
||||
Log.i(TAG, "onDestroy : NO tile service available for $configFileName")
|
||||
}
|
||||
}
|
||||
}
|
|
@ -103,12 +103,9 @@ public class AcceptActivity extends ViewSelectorActivity {
|
|||
} else {
|
||||
final View view = LayoutInflater.from(getApplicationContext()).inflate(R.layout.action_send_item, container, false);
|
||||
final ImageView confirmbutton = view.findViewById(R.id.confirmbutton);
|
||||
confirmbutton.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
ListenerService.confirmAction(AcceptActivity.this, actionstring);
|
||||
finishAffinity();
|
||||
}
|
||||
confirmbutton.setOnClickListener((View v) -> {
|
||||
ListenerService.confirmAction(AcceptActivity.this, actionstring);
|
||||
finishAffinity();
|
||||
});
|
||||
container.addView(view);
|
||||
return view;
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
package info.nightscout.androidaps.interaction.actions
|
||||
|
||||
import android.app.Activity
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.widget.Toast
|
||||
import info.nightscout.androidaps.data.ListenerService
|
||||
|
||||
const val TAG = "QuickWizard"
|
||||
|
||||
class BackgroundActionActivity : Activity() {
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
val actionString = intent.extras?.getString("actionString")
|
||||
Log.i(TAG, "QuickWizardActivity.onCreate: actionString=$actionString")
|
||||
if (actionString != null) {
|
||||
ListenerService.initiateAction(this, actionString)
|
||||
val message = intent.extras?.getString("message")
|
||||
if (message != null) {
|
||||
Toast.makeText(this, message, Toast.LENGTH_LONG).show()
|
||||
}
|
||||
} else {
|
||||
Log.e(TAG, "BackgroundActionActivity.onCreate extras 'actionString' required")
|
||||
}
|
||||
finishAffinity()
|
||||
}
|
||||
|
||||
}
|
|
@ -1,6 +1,8 @@
|
|||
package info.nightscout.androidaps.interaction.actions;
|
||||
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Bundle;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.support.wearable.view.GridPagerAdapter;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
|
@ -14,19 +16,17 @@ import info.nightscout.androidaps.data.ListenerService;
|
|||
import info.nightscout.androidaps.interaction.utils.PlusMinusEditText;
|
||||
import info.nightscout.shared.SafeParse;
|
||||
|
||||
/**
|
||||
* Created by adrian on 09/02/17.
|
||||
*/
|
||||
|
||||
public class BolusActivity extends ViewSelectorActivity {
|
||||
|
||||
PlusMinusEditText editCarbs;
|
||||
PlusMinusEditText editInsulin;
|
||||
float maxBolus;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setAdapter(new MyGridViewPagerAdapter());
|
||||
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this);
|
||||
maxBolus = sp.getFloat(getString(R.string.key_treatmentssafety_maxbolus), 3f);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -35,11 +35,10 @@ public class BolusActivity extends ViewSelectorActivity {
|
|||
finish();
|
||||
}
|
||||
|
||||
|
||||
private class MyGridViewPagerAdapter extends GridPagerAdapter {
|
||||
@Override
|
||||
public int getColumnCount(int arg0) {
|
||||
return 3;
|
||||
return 2;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -56,35 +55,20 @@ public class BolusActivity extends ViewSelectorActivity {
|
|||
if (editInsulin != null) {
|
||||
def = SafeParse.stringToDouble(editInsulin.editText.getText().toString());
|
||||
}
|
||||
editInsulin = new PlusMinusEditText(view, R.id.amountfield, R.id.plusbutton, R.id.minusbutton, def, 0d, 30d, 0.1d, new DecimalFormat("#0.0"), false);
|
||||
editInsulin = new PlusMinusEditText(view, R.id.amountfield, R.id.plusbutton, R.id.minusbutton, def, 0d, (double)maxBolus, 0.1d, new DecimalFormat("#0.0"),false);
|
||||
setLabelToPlusMinusView(view, getString(R.string.action_insulin));
|
||||
container.addView(view);
|
||||
view.requestFocus();
|
||||
return view;
|
||||
} else if (col == 1) {
|
||||
final View view = getInflatedPlusMinusView(container);
|
||||
double def = 0;
|
||||
if (editCarbs != null) {
|
||||
def = SafeParse.stringToDouble(editCarbs.editText.getText().toString());
|
||||
}
|
||||
editCarbs = new PlusMinusEditText(view, R.id.amountfield, R.id.plusbutton, R.id.minusbutton, def, 0d, 150d, 1d, new DecimalFormat("0"), false);
|
||||
setLabelToPlusMinusView(view, getString(R.string.action_carbs));
|
||||
container.addView(view);
|
||||
return view;
|
||||
} else {
|
||||
|
||||
final View view = LayoutInflater.from(getApplicationContext()).inflate(R.layout.action_send_item, container, false);
|
||||
final ImageView confirmbutton = view.findViewById(R.id.confirmbutton);
|
||||
confirmbutton.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
//check if it can happen that the fagment is never created that hold data?
|
||||
// (you have to swipe past them anyways - but still)
|
||||
String actionstring = "bolus " + SafeParse.stringToDouble(editInsulin.editText.getText().toString())
|
||||
+ " " + SafeParse.stringToInt(editCarbs.editText.getText().toString());
|
||||
ListenerService.initiateAction(BolusActivity.this, actionstring);
|
||||
finishAffinity();
|
||||
}
|
||||
confirmbutton.setOnClickListener((View v) -> {
|
||||
String actionstring = "bolus " + SafeParse.stringToDouble(editInsulin.editText.getText().toString())
|
||||
+ " 0"; // Zero carbs
|
||||
ListenerService.initiateAction(BolusActivity.this, actionstring);
|
||||
confirmAction(BolusActivity.this, R.string.action_bolus_confirmation);
|
||||
finishAffinity();
|
||||
});
|
||||
container.addView(view);
|
||||
return view;
|
||||
|
@ -93,8 +77,6 @@ public class BolusActivity extends ViewSelectorActivity {
|
|||
|
||||
@Override
|
||||
public void destroyItem(ViewGroup container, int row, int col, Object view) {
|
||||
// Handle this to get the data before the view is destroyed?
|
||||
// Object should still be kept by this, just setup for reinit?
|
||||
container.removeView((View) view);
|
||||
}
|
||||
|
||||
|
|
|
@ -89,18 +89,15 @@ public class CPPActivity extends ViewSelectorActivity {
|
|||
|
||||
final View view = LayoutInflater.from(getApplicationContext()).inflate(R.layout.action_send_item, container, false);
|
||||
final ImageView confirmbutton = view.findViewById(R.id.confirmbutton);
|
||||
confirmbutton.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
confirmbutton.setOnClickListener((View v) -> {
|
||||
//check if it can happen that the fagment is never created that hold data?
|
||||
// (you have to swipe past them anyways - but still)
|
||||
|
||||
//check if it can happen that the fagment is never created that hold data?
|
||||
// (you have to swipe past them anyways - but still)
|
||||
|
||||
String actionstring = "cppset " + SafeParse.stringToInt(editTimeshift.editText.getText().toString())
|
||||
+ " " + SafeParse.stringToInt(editPercentage.editText.getText().toString());
|
||||
ListenerService.initiateAction(CPPActivity.this, actionstring);
|
||||
finishAffinity();
|
||||
}
|
||||
String actionstring = "cppset " + SafeParse.stringToInt(editTimeshift.editText.getText().toString())
|
||||
+ " " + SafeParse.stringToInt(editPercentage.editText.getText().toString());
|
||||
ListenerService.initiateAction(CPPActivity.this, actionstring);
|
||||
confirmAction(CPPActivity.this, R.string.action_cpp_confirmation);
|
||||
finishAffinity();
|
||||
});
|
||||
container.addView(view);
|
||||
return view;
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
package info.nightscout.androidaps.interaction.actions;
|
||||
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Bundle;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.support.wearable.view.GridPagerAdapter;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
|
@ -23,11 +25,14 @@ public class ECarbActivity extends ViewSelectorActivity {
|
|||
PlusMinusEditText editCarbs;
|
||||
PlusMinusEditText editStartTime;
|
||||
PlusMinusEditText editDuration;
|
||||
int maxCarbs;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setAdapter(new MyGridViewPagerAdapter());
|
||||
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this);
|
||||
maxCarbs = sp.getInt(getString(R.string.key_treatmentssafety_maxcarbs), 48);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -56,7 +61,7 @@ public class ECarbActivity extends ViewSelectorActivity {
|
|||
if (editCarbs != null) {
|
||||
def = SafeParse.stringToDouble(editCarbs.editText.getText().toString());
|
||||
}
|
||||
editCarbs = new PlusMinusEditText(view, R.id.amountfield, R.id.plusbutton, R.id.minusbutton, def, 0d, 150d, 1d, new DecimalFormat("0"), true);
|
||||
editCarbs = new PlusMinusEditText(view, R.id.amountfield, R.id.plusbutton, R.id.minusbutton, def, 0d, (double)maxCarbs, 1d, new DecimalFormat("0"), true);
|
||||
setLabelToPlusMinusView(view, getString(R.string.action_carbs));
|
||||
container.addView(view);
|
||||
view.requestFocus();
|
||||
|
@ -85,19 +90,18 @@ public class ECarbActivity extends ViewSelectorActivity {
|
|||
|
||||
final View view = LayoutInflater.from(getApplicationContext()).inflate(R.layout.action_send_item, container, false);
|
||||
final ImageView confirmbutton = view.findViewById(R.id.confirmbutton);
|
||||
confirmbutton.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
confirmbutton.setOnClickListener((View v) -> {
|
||||
|
||||
//check if it can happen that the fagment is never created that hold data?
|
||||
// (you have to swipe past them anyways - but still)
|
||||
//check if it can happen that the fagment is never created that hold data?
|
||||
// (you have to swipe past them anyways - but still)
|
||||
|
||||
String actionstring = "ecarbs " + SafeParse.stringToInt(editCarbs.editText.getText().toString())
|
||||
+ " " + SafeParse.stringToInt(editStartTime.editText.getText().toString())
|
||||
+ " " + SafeParse.stringToInt(editDuration.editText.getText().toString());
|
||||
ListenerService.initiateAction(ECarbActivity.this, actionstring);
|
||||
confirmAction(ECarbActivity.this, R.string.action_ecarb_confirmation);
|
||||
finishAffinity();
|
||||
|
||||
String actionstring = "ecarbs " + SafeParse.stringToInt(editCarbs.editText.getText().toString())
|
||||
+ " " + SafeParse.stringToInt(editStartTime.editText.getText().toString())
|
||||
+ " " + SafeParse.stringToInt(editDuration.editText.getText().toString());
|
||||
ListenerService.initiateAction(ECarbActivity.this, actionstring);
|
||||
finishAffinity();
|
||||
}
|
||||
});
|
||||
container.addView(view);
|
||||
return view;
|
||||
|
|
|
@ -63,17 +63,14 @@ public class FillActivity extends ViewSelectorActivity {
|
|||
|
||||
final View view = LayoutInflater.from(getApplicationContext()).inflate(R.layout.action_send_item, container, false);
|
||||
final ImageView confirmbutton = view.findViewById(R.id.confirmbutton);
|
||||
confirmbutton.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
|
||||
confirmbutton.setOnClickListener((View v) -> {
|
||||
//check if it can happen that the fagment is never created that hold data?
|
||||
// (you have to swipe past them anyways - but still)
|
||||
|
||||
String actionstring = "fill " + SafeParse.stringToDouble(editInsulin.editText.getText().toString());
|
||||
ListenerService.initiateAction(FillActivity.this, actionstring);
|
||||
confirmAction(FillActivity.this, R.string.action_fill_confirmation);
|
||||
finishAffinity();
|
||||
}
|
||||
});
|
||||
container.addView(view);
|
||||
return view;
|
||||
|
|
|
@ -8,7 +8,6 @@ import android.view.LayoutInflater;
|
|||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import java.text.DecimalFormat;
|
||||
|
||||
|
@ -32,6 +31,7 @@ public class TempTargetActivity extends ViewSelectorActivity {
|
|||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
setAdapter(new MyGridViewPagerAdapter());
|
||||
|
||||
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this);
|
||||
|
@ -61,8 +61,6 @@ public class TempTargetActivity extends ViewSelectorActivity {
|
|||
|
||||
if (col == 0) {
|
||||
final View view = getInflatedPlusMinusView(container);
|
||||
final TextView textView = view.findViewById(R.id.label);
|
||||
textView.setText("duration");
|
||||
if (time == null) {
|
||||
time = new PlusMinusEditText(view, R.id.amountfield, R.id.plusbutton, R.id.minusbutton, 60d, 0d, 24 * 60d, 5d, new DecimalFormat("0"), false);
|
||||
} else {
|
||||
|
@ -118,22 +116,19 @@ public class TempTargetActivity extends ViewSelectorActivity {
|
|||
|
||||
final View view = LayoutInflater.from(getApplicationContext()).inflate(R.layout.action_send_item, container, false);
|
||||
final ImageView confirmbutton = view.findViewById(R.id.confirmbutton);
|
||||
confirmbutton.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
confirmbutton.setOnClickListener((View v) -> {
|
||||
//check if it can happen that the fagment is never created that hold data?
|
||||
// (you have to swipe past them anyways - but still)
|
||||
|
||||
//check if it can happen that the fagment is never created that hold data?
|
||||
// (you have to swipe past them anyways - but still)
|
||||
String actionstring = "temptarget"
|
||||
+ " " + isMGDL
|
||||
+ " " + SafeParse.stringToInt(time.editText.getText().toString())
|
||||
+ " " + SafeParse.stringToDouble(lowRange.editText.getText().toString())
|
||||
+ " " + (isSingleTarget ? SafeParse.stringToDouble(lowRange.editText.getText().toString()) : SafeParse.stringToDouble(highRange.editText.getText().toString()));
|
||||
|
||||
String actionstring = "temptarget "
|
||||
+ " " + isMGDL
|
||||
+ " " + SafeParse.stringToInt(time.editText.getText().toString())
|
||||
+ " " + SafeParse.stringToDouble(lowRange.editText.getText().toString())
|
||||
+ " " + (isSingleTarget ? SafeParse.stringToDouble(lowRange.editText.getText().toString()) : SafeParse.stringToDouble(highRange.editText.getText().toString()));
|
||||
|
||||
ListenerService.initiateAction(TempTargetActivity.this, actionstring);
|
||||
finishAffinity();
|
||||
}
|
||||
ListenerService.initiateAction(TempTargetActivity.this, actionstring);
|
||||
confirmAction(TempTargetActivity.this, R.string.action_tempt_confirmation);
|
||||
finishAffinity();
|
||||
});
|
||||
container.addView(view);
|
||||
return view;
|
||||
|
|
|
@ -0,0 +1,112 @@
|
|||
package info.nightscout.androidaps.interaction.actions;
|
||||
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Bundle;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.support.wearable.view.GridPagerAdapter;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
|
||||
import java.text.DecimalFormat;
|
||||
|
||||
import info.nightscout.androidaps.R;
|
||||
import info.nightscout.androidaps.data.ListenerService;
|
||||
import info.nightscout.androidaps.interaction.utils.PlusMinusEditText;
|
||||
import info.nightscout.shared.SafeParse;
|
||||
|
||||
/**
|
||||
* Created by adrian on 09/02/17.
|
||||
*/
|
||||
|
||||
public class TreatmentActivity extends ViewSelectorActivity {
|
||||
|
||||
PlusMinusEditText editCarbs;
|
||||
PlusMinusEditText editInsulin;
|
||||
int maxCarbs;
|
||||
float maxBolus;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setAdapter(new MyGridViewPagerAdapter());
|
||||
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this);
|
||||
maxCarbs = sp.getInt(getString(R.string.key_treatmentssafety_maxcarbs), 48);
|
||||
maxBolus = sp.getFloat(getString(R.string.key_treatmentssafety_maxbolus), 3f);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPause() {
|
||||
super.onPause();
|
||||
finish();
|
||||
}
|
||||
|
||||
|
||||
private class MyGridViewPagerAdapter extends GridPagerAdapter {
|
||||
@Override
|
||||
public int getColumnCount(int arg0) {
|
||||
return 3;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRowCount() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object instantiateItem(ViewGroup container, int row, int col) {
|
||||
|
||||
if (col == 0) {
|
||||
final View view = getInflatedPlusMinusView(container);
|
||||
double def = 0;
|
||||
if (editInsulin != null) {
|
||||
def = SafeParse.stringToDouble(editInsulin.editText.getText().toString());
|
||||
}
|
||||
editInsulin = new PlusMinusEditText(view, R.id.amountfield, R.id.plusbutton, R.id.minusbutton, def, 0d, (double) maxBolus, 0.1d, new DecimalFormat("#0.0"),false);
|
||||
setLabelToPlusMinusView(view, getString(R.string.action_insulin));
|
||||
container.addView(view);
|
||||
view.requestFocus();
|
||||
return view;
|
||||
} else if (col == 1) {
|
||||
final View view = getInflatedPlusMinusView(container);
|
||||
double def = 0;
|
||||
if (editCarbs != null) {
|
||||
def = SafeParse.stringToDouble(editCarbs.editText.getText().toString());
|
||||
}
|
||||
editCarbs = new PlusMinusEditText(view, R.id.amountfield, R.id.plusbutton, R.id.minusbutton, def, 0d, (double)maxCarbs, 1d, new DecimalFormat("0"),false);
|
||||
setLabelToPlusMinusView(view, getString(R.string.action_carbs));
|
||||
container.addView(view);
|
||||
return view;
|
||||
} else {
|
||||
|
||||
final View view = LayoutInflater.from(getApplicationContext()).inflate(R.layout.action_send_item, container, false);
|
||||
final ImageView confirmbutton = view.findViewById(R.id.confirmbutton);
|
||||
confirmbutton.setOnClickListener((View v) -> {
|
||||
//check if it can happen that the fagment is never created that hold data?
|
||||
// (you have to swipe past them anyways - but still)
|
||||
String actionstring = "bolus " + SafeParse.stringToDouble(editInsulin.editText.getText().toString())
|
||||
+ " " + SafeParse.stringToInt(editCarbs.editText.getText().toString());
|
||||
ListenerService.initiateAction(TreatmentActivity.this, actionstring);
|
||||
confirmAction(TreatmentActivity.this, R.string.action_treatment_confirmation);
|
||||
finishAffinity();
|
||||
});
|
||||
container.addView(view);
|
||||
return view;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroyItem(ViewGroup container, int row, int col, Object view) {
|
||||
// Handle this to get the data before the view is destroyed?
|
||||
// Object should still be kept by this, just setup for reinit?
|
||||
container.removeView((View) view);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isViewFromObject(View view, Object object) {
|
||||
return view == object;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
package info.nightscout.androidaps.interaction.actions;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Bundle;
|
||||
import android.preference.PreferenceManager;
|
||||
|
@ -11,6 +12,7 @@ import android.view.LayoutInflater;
|
|||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.wear.widget.CurvedTextView;
|
||||
|
||||
|
@ -62,9 +64,9 @@ public class ViewSelectorActivity extends Activity {
|
|||
private void setTitleBasedOnScreenShape() {
|
||||
// intents can inject dynamic titles, otherwise we'll use the default
|
||||
String title = String.valueOf(getTitle());
|
||||
if (getIntent().getExtras() != null)
|
||||
if (getIntent().getExtras() != null) {
|
||||
title = getIntent().getExtras().getString("title", title);
|
||||
|
||||
}
|
||||
CurvedTextView titleViewCurved = findViewById(R.id.title_curved);
|
||||
TextView titleView = findViewById(R.id.title);
|
||||
if (this.getResources().getConfiguration().isScreenRound()) {
|
||||
|
@ -96,8 +98,12 @@ public class ViewSelectorActivity extends Activity {
|
|||
}
|
||||
|
||||
void setLabelToPlusMinusView(View view, String labelText) {
|
||||
final TextView textView = view.findViewById(R.id.label);
|
||||
textView.setText(labelText);
|
||||
final TextView textView = view.findViewById(R.id.label);
|
||||
textView.setText(labelText);
|
||||
}
|
||||
|
||||
void confirmAction(Context context, int text) {
|
||||
Toast.makeText(context, getString(text), Toast.LENGTH_LONG).show();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -26,6 +26,8 @@ public class WizardActivity extends ViewSelectorActivity {
|
|||
PlusMinusEditText editPercentage;
|
||||
|
||||
boolean hasPercentage;
|
||||
int percentage;
|
||||
int maxCarbs;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
|
@ -33,6 +35,8 @@ public class WizardActivity extends ViewSelectorActivity {
|
|||
setAdapter(new MyGridViewPagerAdapter());
|
||||
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this);
|
||||
hasPercentage = sp.getBoolean("wizardpercentage", false);
|
||||
percentage = sp.getInt(getString(R.string.key_boluswizard_percentage), 100);
|
||||
maxCarbs = sp.getInt(getString(R.string.key_treatmentssafety_maxcarbs), 48);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -58,10 +62,10 @@ public class WizardActivity extends ViewSelectorActivity {
|
|||
if (col == 0) {
|
||||
final View view = getInflatedPlusMinusView(container);
|
||||
if (editCarbs == null) {
|
||||
editCarbs = new PlusMinusEditText(view, R.id.amountfield, R.id.plusbutton, R.id.minusbutton, 0d, 0d, 150d, 1d, new DecimalFormat("0"), false);
|
||||
editCarbs = new PlusMinusEditText(view, R.id.amountfield, R.id.plusbutton, R.id.minusbutton, 0d, 0d, (double)maxCarbs, 1d, new DecimalFormat("0"), false);
|
||||
} else {
|
||||
double def = SafeParse.stringToDouble(editCarbs.editText.getText().toString());
|
||||
editCarbs = new PlusMinusEditText(view, R.id.amountfield, R.id.plusbutton, R.id.minusbutton, def, 0d, 150d, 1d, new DecimalFormat("0"), false);
|
||||
editCarbs = new PlusMinusEditText(view, R.id.amountfield, R.id.plusbutton, R.id.minusbutton, def, 0d, (double)maxCarbs, 1d, new DecimalFormat("0"),false);
|
||||
}
|
||||
setLabelToPlusMinusView(view, getString(R.string.action_carbs));
|
||||
container.addView(view);
|
||||
|
@ -70,7 +74,7 @@ public class WizardActivity extends ViewSelectorActivity {
|
|||
} else if (col == 1 && hasPercentage) {
|
||||
final View view = getInflatedPlusMinusView(container);
|
||||
if (editPercentage == null) {
|
||||
editPercentage = new PlusMinusEditText(view, R.id.amountfield, R.id.plusbutton, R.id.minusbutton, 100d, 50d, 150d, 1d, new DecimalFormat("0"), false);
|
||||
editPercentage = new PlusMinusEditText(view, R.id.amountfield, R.id.plusbutton, R.id.minusbutton, (double)percentage, 50d, 150d, 1d, new DecimalFormat("0"), false);
|
||||
} else {
|
||||
double def = SafeParse.stringToDouble(editPercentage.editText.getText().toString());
|
||||
editPercentage = new PlusMinusEditText(view, R.id.amountfield, R.id.plusbutton, R.id.minusbutton, def, 50d, 150d, 1d, new DecimalFormat("0"), false);
|
||||
|
@ -82,23 +86,16 @@ public class WizardActivity extends ViewSelectorActivity {
|
|||
|
||||
final View view = LayoutInflater.from(getApplicationContext()).inflate(R.layout.action_send_item, container, false);
|
||||
final ImageView confirmbutton = view.findViewById(R.id.confirmbutton);
|
||||
confirmbutton.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
|
||||
// check if it can happen that the fragment is never created that hold data?
|
||||
// (you have to swipe past them anyways - but still)
|
||||
|
||||
int percentage = 100;
|
||||
|
||||
if (editPercentage != null)
|
||||
percentage = SafeParse.stringToInt(editPercentage.editText.getText().toString());
|
||||
|
||||
String actionstring = "wizard2 " + SafeParse.stringToInt(editCarbs.editText.getText().toString())
|
||||
+ " " + percentage;
|
||||
ListenerService.initiateAction(WizardActivity.this, actionstring);
|
||||
finishAffinity();
|
||||
confirmbutton.setOnClickListener((View v) -> {
|
||||
if (editPercentage != null) {
|
||||
percentage = SafeParse.stringToInt(editPercentage.editText.getText().toString());
|
||||
}
|
||||
|
||||
String actionstring = "wizard2 " + SafeParse.stringToInt(editCarbs.editText.getText().toString())
|
||||
+ " " + percentage;
|
||||
ListenerService.initiateAction(WizardActivity.this, actionstring);
|
||||
confirmAction(WizardActivity.this, R.string.action_wizard_confirmation);
|
||||
finishAffinity();
|
||||
});
|
||||
container.addView(view);
|
||||
return view;
|
||||
|
|
|
@ -11,7 +11,7 @@ import java.util.List;
|
|||
import info.nightscout.androidaps.R;
|
||||
import info.nightscout.androidaps.data.ListenerService;
|
||||
import info.nightscout.androidaps.interaction.AAPSPreferences;
|
||||
import info.nightscout.androidaps.interaction.actions.BolusActivity;
|
||||
import info.nightscout.androidaps.interaction.actions.TreatmentActivity;
|
||||
import info.nightscout.androidaps.interaction.actions.ECarbActivity;
|
||||
import info.nightscout.androidaps.interaction.actions.TempTargetActivity;
|
||||
import info.nightscout.androidaps.interaction.actions.WizardActivity;
|
||||
|
@ -49,7 +49,7 @@ public class MainMenuActivity extends MenuListActivity {
|
|||
|
||||
if (showWizard) menuItems.add(new MenuItem(R.drawable.ic_calculator, getString(R.string.menu_wizard)));
|
||||
menuItems.add(new MenuItem(R.drawable.ic_e_carbs, getString(R.string.menu_ecarb)));
|
||||
menuItems.add(new MenuItem(R.drawable.ic_bolus, getString(R.string.menu_bolus)));
|
||||
menuItems.add(new MenuItem(R.drawable.ic_treatment, getString(R.string.menu_treatment)));
|
||||
menuItems.add(new MenuItem(R.drawable.ic_temptarget, getString(R.string.menu_tempt)));
|
||||
menuItems.add(new MenuItem(R.drawable.ic_settings, getString(R.string.menu_settings)));
|
||||
menuItems.add(new MenuItem(R.drawable.ic_status, getString(R.string.menu_status)));
|
||||
|
@ -73,8 +73,8 @@ public class MainMenuActivity extends MenuListActivity {
|
|||
intent = new Intent(this, TempTargetActivity.class);
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
this.startActivity(intent);
|
||||
} else if (getString(R.string.menu_bolus).equals(action)) {
|
||||
intent = new Intent(this, BolusActivity.class);
|
||||
} else if (getString(R.string.menu_treatment).equals(action)) {
|
||||
intent = new Intent(this, TreatmentActivity.class);
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
this.startActivity(intent);
|
||||
} else if (getString(R.string.menu_wizard).equals(action)) {
|
||||
|
|
|
@ -32,7 +32,7 @@ public class PlusMinusEditText implements View.OnKeyListener,
|
|||
Double minValue = 0d;
|
||||
Double maxValue = 1d;
|
||||
Double step = 1d;
|
||||
NumberFormat formater;
|
||||
NumberFormat formatter;
|
||||
boolean allowZero = false;
|
||||
boolean roundRobin;
|
||||
|
||||
|
@ -74,11 +74,11 @@ public class PlusMinusEditText implements View.OnKeyListener,
|
|||
private static final int MSG_INC = 0;
|
||||
private static final int MSG_DEC = 1;
|
||||
|
||||
public PlusMinusEditText(View view, int editTextID, int plusID, int minusID, Double initValue, Double minValue, Double maxValue, Double step, NumberFormat formater, boolean allowZero) {
|
||||
this(view, editTextID, plusID, minusID, initValue, minValue, maxValue, step, formater, allowZero, false);
|
||||
public PlusMinusEditText(View view, int editTextID, int plusID, int minusID, Double initValue, Double minValue, Double maxValue, Double step, NumberFormat formatter, boolean allowZero) {
|
||||
this(view, editTextID, plusID, minusID, initValue, minValue, maxValue, step, formatter, allowZero, false);
|
||||
}
|
||||
|
||||
public PlusMinusEditText(View view, int editTextID, int plusID, int minusID, Double initValue, Double minValue, Double maxValue, Double step, NumberFormat formater, boolean allowZero, boolean roundRobin) {
|
||||
public PlusMinusEditText(View view, int editTextID, int plusID, int minusID, Double initValue, Double minValue, Double maxValue, Double step, NumberFormat formatter, boolean allowZero, boolean roundRobin) {
|
||||
editText = view.findViewById(editTextID);
|
||||
minusImage = view.findViewById(minusID);
|
||||
plusImage = view.findViewById(plusID);
|
||||
|
@ -87,7 +87,7 @@ public class PlusMinusEditText implements View.OnKeyListener,
|
|||
this.minValue = minValue;
|
||||
this.maxValue = maxValue;
|
||||
this.step = step;
|
||||
this.formater = formater;
|
||||
this.formatter = formatter;
|
||||
this.allowZero = allowZero;
|
||||
this.roundRobin = roundRobin;
|
||||
|
||||
|
@ -159,7 +159,7 @@ public class PlusMinusEditText implements View.OnKeyListener,
|
|||
if (value == 0d && !allowZero)
|
||||
editText.setText("");
|
||||
else
|
||||
editText.setText(formater.format(value));
|
||||
editText.setText(formatter.format(value));
|
||||
}
|
||||
|
||||
private void startUpdating(boolean inc) {
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
package info.nightscout.androidaps.tile
|
||||
|
||||
import android.content.res.Resources
|
||||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.interaction.actions.BolusActivity
|
||||
import info.nightscout.androidaps.interaction.actions.TreatmentActivity
|
||||
import info.nightscout.androidaps.interaction.actions.ECarbActivity
|
||||
import info.nightscout.androidaps.interaction.actions.TempTargetActivity
|
||||
import info.nightscout.androidaps.interaction.actions.WizardActivity
|
||||
|
||||
object ActionSource : StaticTileSource() {
|
||||
|
||||
override val preferencePrefix = "tile_action_"
|
||||
|
||||
override fun getActions(resources: Resources): List<StaticAction> {
|
||||
return listOf(
|
||||
StaticAction(
|
||||
settingName = "wizard",
|
||||
buttonText = resources.getString(R.string.menu_wizard_short),
|
||||
iconRes = R.drawable.ic_calculator_green,
|
||||
activityClass = WizardActivity::class.java.name,
|
||||
),
|
||||
StaticAction(
|
||||
settingName = "treatment",
|
||||
buttonText = resources.getString(R.string.menu_treatment_short),
|
||||
iconRes = R.drawable.ic_bolus_carbs,
|
||||
activityClass = TreatmentActivity::class.java.name,
|
||||
),
|
||||
StaticAction(
|
||||
settingName = "bolus",
|
||||
buttonText = resources.getString(R.string.action_insulin),
|
||||
iconRes = R.drawable.ic_bolus,
|
||||
activityClass = BolusActivity::class.java.name,
|
||||
),
|
||||
StaticAction(
|
||||
settingName = "carbs",
|
||||
buttonText = resources.getString(R.string.action_carbs),
|
||||
iconRes = R.drawable.ic_carbs_orange,
|
||||
activityClass = ECarbActivity::class.java.name,
|
||||
),
|
||||
StaticAction(
|
||||
settingName = "temp_target",
|
||||
buttonText = resources.getString(R.string.menu_tempt),
|
||||
iconRes = R.drawable.ic_temptarget_flat,
|
||||
activityClass = TempTargetActivity::class.java.name,
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
override fun getResourceReferences(resources: Resources): List<Int> {
|
||||
return getActions(resources).map { it.iconRes }
|
||||
}
|
||||
|
||||
override fun getDefaultConfig(): Map<String, String> {
|
||||
return mapOf(
|
||||
"tile_action_1" to "wizard",
|
||||
"tile_action_2" to "treatment",
|
||||
"tile_action_3" to "carbs",
|
||||
"tile_action_4" to "temp_target"
|
||||
)
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
package info.nightscout.androidaps.tile
|
||||
|
||||
class ActionsTileService : TileBase() {
|
||||
override val resourceVersion = "ActionsTileService"
|
||||
override val source = ActionSource
|
||||
}
|
|
@ -0,0 +1,108 @@
|
|||
package info.nightscout.androidaps.tile
|
||||
|
||||
import android.content.Context
|
||||
import android.content.res.Resources
|
||||
import android.util.Base64
|
||||
import android.util.Log
|
||||
import androidx.preference.PreferenceManager
|
||||
import com.google.android.gms.wearable.DataMap
|
||||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.interaction.actions.BackgroundActionActivity
|
||||
import java.util.*
|
||||
|
||||
object QuickWizardSource : TileSource {
|
||||
|
||||
override fun getSelectedActions(context: Context): List<Action> {
|
||||
val quickList = mutableListOf<Action>()
|
||||
val quickMap = getDataMap(context)
|
||||
val sfm = secondsFromMidnight()
|
||||
|
||||
for (quick in quickMap) {
|
||||
val validFrom = quick.getInt("from", 0)
|
||||
val validTo = quick.getInt("to", 0)
|
||||
val isActive = sfm in validFrom..validTo
|
||||
val guid = quick.getString("guid", "")
|
||||
if (isActive && guid != "") {
|
||||
quickList.add(
|
||||
Action(
|
||||
buttonText = quick.getString("button_text", "?"),
|
||||
buttonTextSub = "${quick.getInt("carbs", 0)} g",
|
||||
iconRes = R.drawable.ic_quick_wizard,
|
||||
activityClass = BackgroundActionActivity::class.java.name,
|
||||
actionString = "quick_wizard $guid",
|
||||
message = context.resources.getString(R.string.action_quick_wizard_confirmation),
|
||||
)
|
||||
)
|
||||
Log.i(TAG, "getSelectedActions: active " + quick.getString("button_text", "?") + " guid=" + guid)
|
||||
} else {
|
||||
Log.i(TAG, "getSelectedActions: not active " + quick.getString("button_text", "?") + " guid=" + guid)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return quickList
|
||||
}
|
||||
|
||||
override fun getValidFor(context: Context): Long? {
|
||||
val quickMap = getDataMap(context)
|
||||
if (quickMap.size == 0) {
|
||||
return null
|
||||
}
|
||||
val sfm = secondsFromMidnight()
|
||||
var validTill = 24 * 60 * 60
|
||||
|
||||
for (quick in quickMap) {
|
||||
val validFrom = quick.getInt("from", 0)
|
||||
val validTo = quick.getInt("to", 0)
|
||||
val isActive = sfm in validFrom..validTo
|
||||
val guid = quick.getString("guid", "")
|
||||
Log.i(TAG, "valid: " + validFrom + "-" + validTo)
|
||||
if (guid != "") {
|
||||
if (isActive && validTill > validTo) {
|
||||
validTill = validTo
|
||||
}
|
||||
if (validFrom > sfm && validTill > validFrom) {
|
||||
validTill = validFrom
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val validWithin = 60
|
||||
val delta = (validTill - sfm + validWithin) * 1000L
|
||||
Log.i(TAG, "getValidTill: sfm" + sfm + " till" + validTill + " d=" + delta)
|
||||
return delta
|
||||
}
|
||||
|
||||
private fun getDataMap(context: Context): ArrayList<DataMap> {
|
||||
val sharedPrefs = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
val key = context.resources.getString(R.string.key_quick_wizard_data_map)
|
||||
if (sharedPrefs.contains(key)) {
|
||||
val rawB64Data: String? = sharedPrefs.getString(key, null)
|
||||
val rawData: ByteArray = Base64.decode(rawB64Data, Base64.DEFAULT)
|
||||
try {
|
||||
val map = DataMap.fromByteArray(rawData)
|
||||
return map.getDataMapArrayList("quick_wizard")
|
||||
|
||||
} catch (ex: IllegalArgumentException) {
|
||||
Log.e(TAG, "getSelectedActions: IllegalArgumentException ", ex)
|
||||
}
|
||||
}
|
||||
return arrayListOf()
|
||||
}
|
||||
|
||||
private fun secondsFromMidnight(): Int {
|
||||
val c = Calendar.getInstance()
|
||||
c.set(Calendar.HOUR_OF_DAY, 0)
|
||||
c.set(Calendar.MINUTE, 0)
|
||||
c.set(Calendar.SECOND, 0)
|
||||
c.set(Calendar.MILLISECOND, 0)
|
||||
val passed: Long = System.currentTimeMillis() - c.timeInMillis
|
||||
|
||||
return (passed / 1000).toInt()
|
||||
}
|
||||
|
||||
override fun getResourceReferences(resources: Resources): List<Int> {
|
||||
return listOf(R.drawable.ic_quick_wizard)
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
package info.nightscout.androidaps.tile
|
||||
|
||||
const val TAG = "QuickWizard"
|
||||
|
||||
class QuickWizardTileService : TileBase() {
|
||||
override val resourceVersion = "QuickWizardTileService"
|
||||
override val source = QuickWizardSource
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
package info.nightscout.androidaps.tile
|
||||
|
||||
import android.content.Context
|
||||
import android.content.SharedPreferences
|
||||
import android.content.res.Resources
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.preference.PreferenceManager
|
||||
|
||||
class StaticAction(
|
||||
val settingName: String,
|
||||
buttonText: String,
|
||||
buttonTextSub: String? = null,
|
||||
activityClass: String,
|
||||
@DrawableRes iconRes: Int,
|
||||
actionString: String? = null,
|
||||
message: String? = null,
|
||||
) : Action(buttonText, buttonTextSub, activityClass, iconRes, actionString, message)
|
||||
|
||||
abstract class StaticTileSource : TileSource {
|
||||
|
||||
abstract fun getActions(resources: Resources): List<StaticAction>
|
||||
|
||||
abstract val preferencePrefix: String
|
||||
abstract fun getDefaultConfig(): Map<String, String>
|
||||
|
||||
override fun getSelectedActions(context: Context): List<Action> {
|
||||
val sharedPrefs = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
setDefaultSettings(sharedPrefs)
|
||||
|
||||
val actionList: MutableList<Action> = mutableListOf()
|
||||
for (i in 1..4) {
|
||||
val action = getActionFromPreference(context.resources, sharedPrefs, i)
|
||||
if (action != null) {
|
||||
actionList.add(action)
|
||||
}
|
||||
}
|
||||
if (actionList.isEmpty()) {
|
||||
return getActions(context.resources).take(4)
|
||||
}
|
||||
return actionList
|
||||
}
|
||||
|
||||
override fun getValidFor(context: Context): Long? = null
|
||||
|
||||
private fun getActionFromPreference(resources: Resources, sharedPrefs: SharedPreferences, index: Int): Action? {
|
||||
val actionPref = sharedPrefs.getString(preferencePrefix + index, "none")
|
||||
return getActions(resources).find { action -> action.settingName == actionPref }
|
||||
}
|
||||
|
||||
private fun setDefaultSettings(sharedPrefs: SharedPreferences) {
|
||||
val defaults = getDefaultConfig()
|
||||
val firstKey = defaults.firstNotNullOf { settings -> settings.key }
|
||||
if (!sharedPrefs.contains(firstKey)) {
|
||||
val editor = sharedPrefs.edit()
|
||||
for ((key, value) in defaults) {
|
||||
editor.putString(key, value)
|
||||
}
|
||||
editor.apply()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
package info.nightscout.androidaps.tile
|
||||
|
||||
import android.content.res.Resources
|
||||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.interaction.actions.BackgroundActionActivity
|
||||
import info.nightscout.androidaps.interaction.actions.TempTargetActivity
|
||||
|
||||
object TempTargetSource : StaticTileSource() {
|
||||
|
||||
override val preferencePrefix = "tile_tempt_"
|
||||
|
||||
override fun getActions(resources: Resources): List<StaticAction> {
|
||||
val message = resources.getString(R.string.action_tempt_confirmation)
|
||||
return listOf(
|
||||
StaticAction(
|
||||
settingName = "activity",
|
||||
buttonText = resources.getString(R.string.temp_target_activity),
|
||||
iconRes = R.drawable.ic_target_activity,
|
||||
activityClass = BackgroundActionActivity::class.java.name,
|
||||
message = message,
|
||||
// actionString = "temptarget false 90 8.0 8.0",
|
||||
actionString = "temptarget preset activity",
|
||||
),
|
||||
StaticAction(
|
||||
settingName = "eating_soon",
|
||||
buttonText = resources.getString(R.string.temp_target_eating_soon),
|
||||
iconRes = R.drawable.ic_target_eatingsoon,
|
||||
activityClass = BackgroundActionActivity::class.java.name,
|
||||
message = message,
|
||||
// actionString = "temptarget false 45 4.5 4.5",
|
||||
actionString = "temptarget preset eating",
|
||||
),
|
||||
StaticAction(
|
||||
settingName = "hypo",
|
||||
buttonText = resources.getString(R.string.temp_target_hypo),
|
||||
iconRes = R.drawable.ic_target_hypo,
|
||||
activityClass = BackgroundActionActivity::class.java.name,
|
||||
message = message,
|
||||
// actionString = "temptarget false 45 7.0 7.0",
|
||||
actionString = "temptarget preset hypo",
|
||||
),
|
||||
StaticAction(
|
||||
settingName = "manual",
|
||||
buttonText = resources.getString(R.string.temp_target_manual),
|
||||
iconRes = R.drawable.ic_target_manual,
|
||||
activityClass = TempTargetActivity::class.java.name,
|
||||
),
|
||||
StaticAction(
|
||||
settingName = "cancel",
|
||||
buttonText = resources.getString(R.string.generic_cancel),
|
||||
iconRes = R.drawable.ic_target_cancel,
|
||||
activityClass = BackgroundActionActivity::class.java.name,
|
||||
message = message,
|
||||
actionString = "temptarget cancel",
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
override fun getResourceReferences(resources: Resources): List<Int> {
|
||||
return getActions(resources).map { it.iconRes }
|
||||
}
|
||||
|
||||
override fun getDefaultConfig(): Map<String, String> {
|
||||
return mapOf(
|
||||
"tile_tempt_1" to "activity",
|
||||
"tile_tempt_2" to "eating_soon",
|
||||
"tile_tempt_3" to "hypo",
|
||||
"tile_tempt_4" to "manual"
|
||||
)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
package info.nightscout.androidaps.tile
|
||||
|
||||
class TempTargetTileService : TileBase() {
|
||||
|
||||
override val resourceVersion = "TempTargetTileService"
|
||||
override val source = TempTargetSource;
|
||||
|
||||
}
|
297
wear/src/main/java/info/nightscout/androidaps/tile/TileBase.kt
Normal file
297
wear/src/main/java/info/nightscout/androidaps/tile/TileBase.kt
Normal file
|
@ -0,0 +1,297 @@
|
|||
package info.nightscout.androidaps.tile
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Build
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.preference.PreferenceManager
|
||||
import androidx.wear.tiles.ActionBuilders
|
||||
import androidx.wear.tiles.ColorBuilders.argb
|
||||
import androidx.wear.tiles.DeviceParametersBuilders.SCREEN_SHAPE_ROUND
|
||||
import androidx.wear.tiles.DeviceParametersBuilders.DeviceParameters
|
||||
import androidx.wear.tiles.DimensionBuilders.SpProp
|
||||
import androidx.wear.tiles.DimensionBuilders.dp
|
||||
import androidx.wear.tiles.DimensionBuilders.sp
|
||||
import androidx.wear.tiles.LayoutElementBuilders.*
|
||||
import androidx.wear.tiles.ModifiersBuilders.Background
|
||||
import androidx.wear.tiles.ModifiersBuilders.Clickable
|
||||
import androidx.wear.tiles.ModifiersBuilders.Corner
|
||||
import androidx.wear.tiles.ModifiersBuilders.Modifiers
|
||||
import androidx.wear.tiles.ModifiersBuilders.Semantics
|
||||
import androidx.wear.tiles.RequestBuilders
|
||||
import androidx.wear.tiles.RequestBuilders.ResourcesRequest
|
||||
import androidx.wear.tiles.ResourceBuilders.AndroidImageResourceByResId
|
||||
import androidx.wear.tiles.ResourceBuilders.ImageResource
|
||||
import androidx.wear.tiles.ResourceBuilders.Resources
|
||||
import androidx.wear.tiles.TileBuilders.Tile
|
||||
import androidx.wear.tiles.TileService
|
||||
import androidx.wear.tiles.TimelineBuilders.Timeline
|
||||
import androidx.wear.tiles.TimelineBuilders.TimelineEntry
|
||||
import com.google.common.util.concurrent.ListenableFuture
|
||||
import info.nightscout.androidaps.R
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.guava.future
|
||||
import kotlin.math.sqrt
|
||||
|
||||
private const val SPACING_ACTIONS = 3f
|
||||
private const val ICON_SIZE_FRACTION = 0.4f // Percentage of button diameter
|
||||
private const val BUTTON_COLOR = R.color.gray_850
|
||||
private const val LARGE_SCREEN_WIDTH_DP = 210
|
||||
|
||||
interface TileSource {
|
||||
|
||||
fun getResourceReferences(resources: android.content.res.Resources): List<Int>
|
||||
fun getSelectedActions(context: Context): List<Action>
|
||||
fun getValidFor(context: Context): Long?
|
||||
}
|
||||
|
||||
open class Action(
|
||||
val buttonText: String,
|
||||
val buttonTextSub: String? = null,
|
||||
val activityClass: String,
|
||||
@DrawableRes val iconRes: Int,
|
||||
val actionString: String? = null,
|
||||
val message: String? = null,
|
||||
)
|
||||
|
||||
enum class WearControl {
|
||||
NO_DATA, ENABLED, DISABLED
|
||||
}
|
||||
|
||||
abstract class TileBase : TileService() {
|
||||
|
||||
abstract val resourceVersion: String
|
||||
abstract val source: TileSource
|
||||
|
||||
private val serviceJob = Job()
|
||||
private val serviceScope = CoroutineScope(Dispatchers.IO + serviceJob)
|
||||
|
||||
override fun onTileRequest(
|
||||
requestParams: RequestBuilders.TileRequest
|
||||
): ListenableFuture<Tile> = serviceScope.future {
|
||||
val actionsSelected = getSelectedActions()
|
||||
val wearControl = getWearControl()
|
||||
val tile = Tile.Builder()
|
||||
.setResourcesVersion(resourceVersion)
|
||||
.setTimeline(
|
||||
Timeline.Builder().addTimelineEntry(
|
||||
TimelineEntry.Builder().setLayout(
|
||||
Layout.Builder().setRoot(layout(wearControl, actionsSelected, requestParams.deviceParameters!!)).build()
|
||||
).build()
|
||||
).build()
|
||||
)
|
||||
|
||||
val validFor = validFor()
|
||||
if (validFor != null) {
|
||||
tile.setFreshnessIntervalMillis(validFor)
|
||||
}
|
||||
tile.build()
|
||||
}
|
||||
|
||||
private fun getSelectedActions(): List<Action> {
|
||||
// TODO check why thi scan not be don in scope of the coroutine
|
||||
return source.getSelectedActions(this)
|
||||
}
|
||||
|
||||
private fun validFor(): Long? {
|
||||
return source.getValidFor(this)
|
||||
}
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.N)
|
||||
override fun onResourcesRequest(
|
||||
requestParams: ResourcesRequest
|
||||
): ListenableFuture<Resources> = serviceScope.future {
|
||||
Resources.Builder()
|
||||
.setVersion(resourceVersion)
|
||||
.apply {
|
||||
source.getResourceReferences(resources).forEach { resourceId ->
|
||||
addIdToImageMapping(
|
||||
resourceId.toString(),
|
||||
ImageResource.Builder()
|
||||
.setAndroidResourceByResId(
|
||||
AndroidImageResourceByResId.Builder()
|
||||
.setResourceId(resourceId)
|
||||
.build()
|
||||
)
|
||||
.build()
|
||||
)
|
||||
}
|
||||
}
|
||||
.build()
|
||||
}
|
||||
|
||||
private fun layout(wearControl: WearControl, actions: List<Action>, deviceParameters: DeviceParameters): LayoutElement {
|
||||
if (wearControl == WearControl.DISABLED) {
|
||||
return Text.Builder()
|
||||
.setText(resources.getString(R.string.wear_control_not_enabled))
|
||||
.build()
|
||||
} else if (wearControl == WearControl.NO_DATA) {
|
||||
return Text.Builder()
|
||||
.setText(resources.getString(R.string.wear_control_no_data))
|
||||
.build()
|
||||
}
|
||||
if (actions.isNotEmpty()) {
|
||||
with(Column.Builder()) {
|
||||
if (actions.size == 1 || actions.size == 3) {
|
||||
addContent(addRowSingle(actions[0], deviceParameters))
|
||||
}
|
||||
if (actions.size == 4 || actions.size == 2) {
|
||||
addContent(addRowDouble(actions[0], actions[1], deviceParameters))
|
||||
}
|
||||
if (actions.size == 3) {
|
||||
addContent(addRowDouble(actions[1], actions[2], deviceParameters))
|
||||
}
|
||||
if (actions.size == 4) {
|
||||
addContent(Spacer.Builder().setHeight(dp(SPACING_ACTIONS)).build())
|
||||
addContent(addRowDouble(actions[2], actions[3], deviceParameters))
|
||||
}
|
||||
return build()
|
||||
}
|
||||
}
|
||||
return Text.Builder()
|
||||
.setText(resources.getString(R.string.tile_no_config))
|
||||
.build()
|
||||
}
|
||||
|
||||
private fun addRowSingle(action: Action, deviceParameters: DeviceParameters): LayoutElement =
|
||||
Row.Builder()
|
||||
.addContent(action(action, deviceParameters))
|
||||
.build()
|
||||
|
||||
private fun addRowDouble(action1: Action, action2: Action, deviceParameters: DeviceParameters): LayoutElement =
|
||||
Row.Builder()
|
||||
.addContent(action(action1, deviceParameters))
|
||||
.addContent(Spacer.Builder().setWidth(dp(SPACING_ACTIONS)).build())
|
||||
.addContent(action(action2, deviceParameters))
|
||||
.build()
|
||||
|
||||
private fun doAction(action: Action): ActionBuilders.Action {
|
||||
val builder = ActionBuilders.AndroidActivity.Builder()
|
||||
.setClassName(action.activityClass)
|
||||
.setPackageName(this.packageName)
|
||||
if (action.actionString != null) {
|
||||
val actionString = ActionBuilders.AndroidStringExtra.Builder().setValue(action.actionString).build()
|
||||
builder.addKeyToExtraMapping("actionString", actionString)
|
||||
}
|
||||
if (action.message != null) {
|
||||
val message = ActionBuilders.AndroidStringExtra.Builder().setValue(action.message).build()
|
||||
builder.addKeyToExtraMapping("message", message)
|
||||
}
|
||||
|
||||
return ActionBuilders.LaunchAction.Builder()
|
||||
.setAndroidActivity(builder.build())
|
||||
.build()
|
||||
}
|
||||
|
||||
private fun action(action: Action, deviceParameters: DeviceParameters): LayoutElement {
|
||||
val circleDiameter = circleDiameter(deviceParameters)
|
||||
val text = action.buttonText
|
||||
val textSub = action.buttonTextSub
|
||||
return Box.Builder()
|
||||
.setWidth(dp(circleDiameter))
|
||||
.setHeight(dp(circleDiameter))
|
||||
.setModifiers(
|
||||
Modifiers.Builder()
|
||||
.setBackground(
|
||||
Background.Builder()
|
||||
.setColor(
|
||||
argb(ContextCompat.getColor(baseContext, BUTTON_COLOR))
|
||||
)
|
||||
.setCorner(
|
||||
Corner.Builder().setRadius(dp(circleDiameter / 2)).build()
|
||||
)
|
||||
.build()
|
||||
)
|
||||
.setSemantics(
|
||||
Semantics.Builder()
|
||||
.setContentDescription("$text $textSub")
|
||||
.build()
|
||||
)
|
||||
.setClickable(
|
||||
Clickable.Builder()
|
||||
.setOnClick(doAction(action))
|
||||
.build()
|
||||
)
|
||||
.build()
|
||||
)
|
||||
.addContent(addTextContent(action, deviceParameters))
|
||||
.build()
|
||||
}
|
||||
|
||||
private fun addTextContent(action: Action, deviceParameters: DeviceParameters): LayoutElement {
|
||||
val circleDiameter = circleDiameter(deviceParameters)
|
||||
val iconSize = dp(circleDiameter * ICON_SIZE_FRACTION)
|
||||
val text = action.buttonText
|
||||
val textSub = action.buttonTextSub
|
||||
val col = Column.Builder()
|
||||
.addContent(
|
||||
Image.Builder()
|
||||
.setWidth(iconSize)
|
||||
.setHeight(iconSize)
|
||||
.setResourceId(action.iconRes.toString())
|
||||
.build()
|
||||
).addContent(
|
||||
Text.Builder()
|
||||
.setText(text)
|
||||
.setFontStyle(
|
||||
FontStyle.Builder()
|
||||
.setWeight(FONT_WEIGHT_BOLD)
|
||||
.setColor(
|
||||
argb(ContextCompat.getColor(baseContext, R.color.white))
|
||||
)
|
||||
.setSize(buttonTextSize(deviceParameters, text))
|
||||
.build()
|
||||
)
|
||||
.build()
|
||||
)
|
||||
if (textSub != null) {
|
||||
col.addContent(
|
||||
Text.Builder()
|
||||
.setText(textSub)
|
||||
.setFontStyle(
|
||||
FontStyle.Builder()
|
||||
.setColor(
|
||||
argb(ContextCompat.getColor(baseContext, R.color.white))
|
||||
)
|
||||
.setSize(buttonTextSize(deviceParameters, textSub))
|
||||
.build()
|
||||
)
|
||||
.build()
|
||||
)
|
||||
}
|
||||
|
||||
return col.build()
|
||||
}
|
||||
|
||||
private fun circleDiameter(deviceParameters: DeviceParameters) = when (deviceParameters.screenShape) {
|
||||
SCREEN_SHAPE_ROUND -> ((sqrt(2f) - 1) * deviceParameters.screenHeightDp) - (2 * SPACING_ACTIONS)
|
||||
else -> 0.5f * deviceParameters.screenHeightDp - SPACING_ACTIONS
|
||||
}
|
||||
|
||||
private fun buttonTextSize(deviceParameters: DeviceParameters, text: String): SpProp {
|
||||
if (text.length > 6) {
|
||||
return sp(if (isLargeScreen(deviceParameters)) 14f else 12f)
|
||||
}
|
||||
return sp(if (isLargeScreen(deviceParameters)) 16f else 14f)
|
||||
}
|
||||
|
||||
private fun isLargeScreen(deviceParameters: DeviceParameters): Boolean {
|
||||
return deviceParameters.screenWidthDp >= LARGE_SCREEN_WIDTH_DP
|
||||
}
|
||||
|
||||
private fun getWearControl(): WearControl {
|
||||
val sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this)
|
||||
if (!sharedPrefs.contains("wearcontrol")) {
|
||||
return WearControl.NO_DATA
|
||||
}
|
||||
val wearControlPref = sharedPrefs.getBoolean("wearcontrol", false)
|
||||
if (wearControlPref) {
|
||||
return WearControl.ENABLED
|
||||
}
|
||||
return WearControl.DISABLED
|
||||
}
|
||||
|
||||
}
|
|
@ -71,6 +71,8 @@ public abstract class BaseWatchFace extends WatchFace implements SharedPreferenc
|
|||
INTENT_FILTER.addAction(Intent.ACTION_TIME_CHANGED);
|
||||
}
|
||||
|
||||
static IntentFilter iFilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
|
||||
|
||||
public final Point displaySize = new Point();
|
||||
public TextView mTime, mHour, mMinute, mTimePeriod, mSgv, mDirection, mTimestamp, mUploaderBattery, mRigBattery, mDelta, mAvgDelta, mStatus, mBasalRate, mIOB1, mIOB2, mCOB1, mCOB2, mBgi, mLoop, mDay, mDayName, mMonth, isAAPSv2, mHighLight, mLowLight;
|
||||
public ImageView mGlucoseDial, mDeltaGauge, mHourHand, mMinuteHand;
|
||||
|
@ -111,7 +113,6 @@ public abstract class BaseWatchFace extends WatchFace implements SharedPreferenc
|
|||
private Date mDateTime;
|
||||
private String mLastSvg = "", mLastDirection = "";
|
||||
private float mYOffset = 0;
|
||||
private Intent mBatteryStatus;
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
|
@ -145,10 +146,8 @@ public abstract class BaseWatchFace extends WatchFace implements SharedPreferenc
|
|||
}
|
||||
|
||||
private void setupBatteryReceiver() {
|
||||
IntentFilter iFilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
|
||||
mBatteryStatus = this.registerReceiver(null, iFilter);
|
||||
String setting = sharedPrefs.getString("simplify_ui", "off");
|
||||
if (setting.equals("charging") || setting.equals("ambient_charging") && batteryReceiver == null) {
|
||||
if ((setting.equals("charging") || setting.equals("ambient_charging")) && batteryReceiver == null) {
|
||||
IntentFilter intentBatteryFilter = new IntentFilter();
|
||||
intentBatteryFilter.addAction(BatteryManager.ACTION_CHARGING);
|
||||
intentBatteryFilter.addAction(BatteryManager.ACTION_DISCHARGING);
|
||||
|
@ -374,6 +373,7 @@ public abstract class BaseWatchFace extends WatchFace implements SharedPreferenc
|
|||
}
|
||||
|
||||
private boolean isCharging() {
|
||||
Intent mBatteryStatus = this.registerReceiver(null, iFilter);
|
||||
int status = mBatteryStatus.getIntExtra(BatteryManager.EXTRA_STATUS, -1);
|
||||
return status == BatteryManager.BATTERY_STATUS_CHARGING ||
|
||||
status == BatteryManager.BATTERY_STATUS_FULL;
|
||||
|
@ -658,7 +658,7 @@ public abstract class BaseWatchFace extends WatchFace implements SharedPreferenc
|
|||
}
|
||||
|
||||
private boolean isLowRes(WatchMode watchMode) {
|
||||
return (watchMode == WatchMode.LOW_BIT) || (watchMode == WatchMode.LOW_BIT_BURN_IN); // || (watchMode == WatchMode.LOW_BIT_BURN_IN);
|
||||
return watchMode == WatchMode.LOW_BIT || watchMode == WatchMode.LOW_BIT_BURN_IN;
|
||||
}
|
||||
|
||||
private boolean isSimpleUi() {
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 18 KiB |
Binary file not shown.
After Width: | Height: | Size: 14 KiB |
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue