diff --git a/app/src/main/kotlin/app/aaps/MainApp.kt b/app/src/main/kotlin/app/aaps/MainApp.kt index 661846701ef5..ca926033025a 100644 --- a/app/src/main/kotlin/app/aaps/MainApp.kt +++ b/app/src/main/kotlin/app/aaps/MainApp.kt @@ -422,7 +422,9 @@ class MainApp : Application(), HasAndroidInjector { // set values for different builds // 3.3 if (preferences.get(UnitDoubleKey.OverviewLowMark) == 0.0) preferences.remove(UnitDoubleKey.OverviewLowMark) + if (preferences.get(UnitDoubleKey.OverviewVeryLowMark) == 0.0) preferences.remove(UnitDoubleKey.OverviewVeryLowMark) if (preferences.get(UnitDoubleKey.OverviewHighMark) == 0.0) preferences.remove(UnitDoubleKey.OverviewHighMark) + if (preferences.get(UnitDoubleKey.OverviewVeryHighMark) == 0.0) preferences.remove(UnitDoubleKey.OverviewVeryHighMark) if (preferences.getIfExists(BooleanKey.GeneralSimpleMode) == null) preferences.put(BooleanKey.GeneralSimpleMode, !preferences.get(BooleanNonKey.GeneralSetupWizardProcessed)) // Migrate from OpenAPSSMBDynamicISFPlugin diff --git a/core/interfaces/src/main/kotlin/app/aaps/core/interfaces/overview/LastBgData.kt b/core/interfaces/src/main/kotlin/app/aaps/core/interfaces/overview/LastBgData.kt index 23ff69398d57..c6fd38b83be9 100644 --- a/core/interfaces/src/main/kotlin/app/aaps/core/interfaces/overview/LastBgData.kt +++ b/core/interfaces/src/main/kotlin/app/aaps/core/interfaces/overview/LastBgData.kt @@ -18,6 +18,13 @@ interface LastBgData { */ fun lastBg(): InMemoryGlucoseValue? + /** + * Is last value below display very low target? + * + * @return true if below + */ + fun isVeryLow(): Boolean + /** * Is last value below display low target? * @@ -32,6 +39,13 @@ interface LastBgData { */ fun isHigh(): Boolean + /** + * Is last value above display high very target? + * + * @return true if above + */ + fun isVeryHigh(): Boolean + /** * Description for a11y * diff --git a/core/interfaces/src/main/kotlin/app/aaps/core/interfaces/overview/graph/CalculationResults.kt b/core/interfaces/src/main/kotlin/app/aaps/core/interfaces/overview/graph/CalculationResults.kt index 8095eaa91080..531ef47162ff 100644 --- a/core/interfaces/src/main/kotlin/app/aaps/core/interfaces/overview/graph/CalculationResults.kt +++ b/core/interfaces/src/main/kotlin/app/aaps/core/interfaces/overview/graph/CalculationResults.kt @@ -15,9 +15,11 @@ import app.aaps.core.data.model.TrendArrow */ enum class BgRange { + VERY_HIGH, // Above very high mark HIGH, // Above high mark IN_RANGE, // Within target range - LOW // Below low mark + LOW, // Below low mark + VERY_LOW // Below very low mark } /** diff --git a/core/interfaces/src/main/kotlin/app/aaps/core/interfaces/rx/weardata/EventData.kt b/core/interfaces/src/main/kotlin/app/aaps/core/interfaces/rx/weardata/EventData.kt index 6f637866eab2..59e7a4f1f770 100644 --- a/core/interfaces/src/main/kotlin/app/aaps/core/interfaces/rx/weardata/EventData.kt +++ b/core/interfaces/src/main/kotlin/app/aaps/core/interfaces/rx/weardata/EventData.kt @@ -299,8 +299,10 @@ sealed class EventData : Event() { val avgDeltaDetailed: String = "--", val sgvLevel: Long = 0, val sgv: Double, + val veryHigh: Double, // veryHighLine val high: Double, // highLine val low: Double, // lowLine + val veryLow: Double, // veryLowLine val color: Int = 0, val deltaMgdl: Double? = null, val avgDeltaMgdl: Double? = null, diff --git a/core/interfaces/src/test/kotlin/app/aaps/core/interfaces/rx/weardata/EventDataTest.kt b/core/interfaces/src/test/kotlin/app/aaps/core/interfaces/rx/weardata/EventDataTest.kt index 27be941de858..7f6dacfa6f70 100644 --- a/core/interfaces/src/test/kotlin/app/aaps/core/interfaces/rx/weardata/EventDataTest.kt +++ b/core/interfaces/src/test/kotlin/app/aaps/core/interfaces/rx/weardata/EventDataTest.kt @@ -140,11 +140,11 @@ class EventDataTest { assertThat(EventData.deserializeByte(it.serializeByte())).isEqualTo(it) assertThat(EventData.deserialize(it.serialize())).isEqualTo(it) } - EventData.SingleBg(dataset = 0, 1, sgv = 2.0, high = 3.0, low = 4.0).let { + EventData.SingleBg(dataset = 0, 1, sgv = 2.0, veryHigh = 5.0, high = 3.0, low = 4.0, veryLow = 6.0).let { assertThat(EventData.deserializeByte(it.serializeByte())).isEqualTo(it) assertThat(EventData.deserialize(it.serialize())).isEqualTo(it) } - EventData.GraphData(arrayListOf(EventData.SingleBg(dataset = 0, 1, sgv = 2.0, high = 3.0, low = 4.0))).let { + EventData.GraphData(arrayListOf(EventData.SingleBg(dataset = 0, 1, sgv = 2.0, veryHigh = 5.0, high = 3.0, low = 4.0, veryLow = 6.0))).let { assertThat(EventData.deserializeByte(it.serializeByte())).isEqualTo(it) assertThat(EventData.deserialize(it.serialize())).isEqualTo(it) } @@ -152,7 +152,7 @@ class EventDataTest { arrayListOf(EventData.TreatmentData.TempBasal(1, 2.0, 3, 4.0, 5.0)), arrayListOf(EventData.TreatmentData.Basal(1, 2, 3.0)), arrayListOf(EventData.TreatmentData.Treatment(1, 2.0, 3.0, true, isValid = true)), - arrayListOf(EventData.SingleBg(dataset = 0, 1, sgv = 2.0, high = 3.0, low = 4.0)) + arrayListOf(EventData.SingleBg(dataset = 0, 1, sgv = 2.0, veryHigh = 5.0, high = 3.0, low = 4.0, veryLow = 6.0)) ).let { assertThat(EventData.deserializeByte(it.serializeByte())).isEqualTo(it) assertThat(EventData.deserialize(it.serialize())).isEqualTo(it) diff --git a/core/keys/src/main/kotlin/app/aaps/core/keys/UnitDoubleKey.kt b/core/keys/src/main/kotlin/app/aaps/core/keys/UnitDoubleKey.kt index 2ea135e7e099..a6eb3bfd3ded 100644 --- a/core/keys/src/main/kotlin/app/aaps/core/keys/UnitDoubleKey.kt +++ b/core/keys/src/main/kotlin/app/aaps/core/keys/UnitDoubleKey.kt @@ -21,8 +21,10 @@ enum class UnitDoubleKey( override val exportable: Boolean = true ) : UnitDoublePreferenceKey { + OverviewVeryLowMark(key = "very_low_mark", defaultValue = 72.0, minMgdl = 25, maxMgdl =100, titleResId = R.string.pref_title_very_low_mark, showInNsClientMode = false), OverviewLowMark(key = "low_mark", defaultValue = 72.0, minMgdl = 25, maxMgdl = 160, titleResId = R.string.pref_title_low_mark, showInNsClientMode = false, hideParentScreenIfHidden = true), OverviewHighMark(key = "high_mark", defaultValue = 180.0, minMgdl = 90, maxMgdl = 250, titleResId = R.string.pref_title_high_mark, showInNsClientMode = false), + OverviewVeryHighMark(key = "very_high_mark", defaultValue = 401.0, minMgdl =180, maxMgdl = 401, titleResId = R.string.pref_title_very_high_mark, showInNsClientMode = false), ApsLgsThreshold( key = "lgsThreshold", defaultValue = 65.0, diff --git a/core/keys/src/main/res/values/strings.xml b/core/keys/src/main/res/values/strings.xml index fdba4bb0e079..f6448767cc3d 100644 --- a/core/keys/src/main/res/values/strings.xml +++ b/core/keys/src/main/res/values/strings.xml @@ -448,8 +448,10 @@ Default value: 1 This is another key OpenAPS safety cap, and specifies by what factor you can exceed the regular 120 maxSMB/maxUAM minutes. Increase this experimental value slowly and with caution. + Very Low BG mark Low BG mark High BG mark + Very High BG mark LGS threshold diff --git a/core/ui/src/main/kotlin/app/aaps/core/ui/compose/GeneralColors.kt b/core/ui/src/main/kotlin/app/aaps/core/ui/compose/GeneralColors.kt index 00267b8662ef..b765de612d8f 100644 --- a/core/ui/src/main/kotlin/app/aaps/core/ui/compose/GeneralColors.kt +++ b/core/ui/src/main/kotlin/app/aaps/core/ui/compose/GeneralColors.kt @@ -132,7 +132,7 @@ val LightGeneralColors = GeneralColors( bgInRange = Color(0xFF00FF00), // pure green for in-range BG (matches @color/inRange) bgLow = Color(0xFFFF0000), // pure red for low BG (matches @color/low) bgVeryLow = Color(0xFF8B0000), // dark red for very low BG (Dexcom TIR 5-range) - bgVeryHigh = Color(0xFFD84315), // deep orange-red for very high BG (Dexcom TIR 5-range) + bgVeryHigh = Color(0xFFFF0000), // red for very high BG (Dexcom TIR 5-range) bgTargetRangeArea = Color(0x2800FF00), // green with ~16% alpha for target range area (matches @color/inRangeBackground) originalBgValue = Color(0xFFFFFFFF), // white for regular CGM readings (matches originalBgValueColor attr) iobPrediction = Color(0xFF1E88E5), // blue for IOB predictions (matches iobColor attr) @@ -189,7 +189,7 @@ val DarkGeneralColors = GeneralColors( bgInRange = Color(0xFF00FF00), // pure green for in-range BG (matches @color/inRange - same in both modes) bgLow = Color(0xFFFF0000), // pure red for low BG (matches @color/low - same in both modes) bgVeryLow = Color(0xFFB71C1C), // dark red for very low BG (dark mode, Dexcom TIR 5-range) - bgVeryHigh = Color(0xFFFB8C00), // orange for very high BG (dark mode, differentiates from yellow bgHigh) + bgVeryHigh = Color(0xFFFF0000), // red for very high BG (dark mode, differentiates from yellow bgHigh) bgTargetRangeArea = Color(0x4000FF00), // green with ~25% alpha for target range area (matches @color/inRangeBackground in values-night) originalBgValue = Color(0xFFFFFFFF), // white for regular CGM readings (same in both modes) iobPrediction = Color(0xFF64B5F6), // lighter blue for IOB predictions (dark mode) diff --git a/core/ui/src/main/kotlin/app/aaps/core/ui/compose/preference/PreferenceSliderWithButtons.kt b/core/ui/src/main/kotlin/app/aaps/core/ui/compose/preference/PreferenceSliderWithButtons.kt index 447d916b10f7..733ace6fb4c5 100644 --- a/core/ui/src/main/kotlin/app/aaps/core/ui/compose/preference/PreferenceSliderWithButtons.kt +++ b/core/ui/src/main/kotlin/app/aaps/core/ui/compose/preference/PreferenceSliderWithButtons.kt @@ -22,7 +22,7 @@ import app.aaps.core.ui.compose.dialogs.ValueInputDialog import app.aaps.core.ui.compose.formatSliderDisplayValue import java.text.DecimalFormat -private const val MAX_SLIDER_STEPS = 200.0 +private const val MAX_SLIDER_STEPS = 260.0 /** * Preference-row variant of [SliderWithButtons]. Forwards to [SliderWithButtons] when the diff --git a/core/ui/src/main/res/values/colors.xml b/core/ui/src/main/res/values/colors.xml index 6f16cc9848ba..e787c6c3463d 100644 --- a/core/ui/src/main/res/values/colors.xml +++ b/core/ui/src/main/res/values/colors.xml @@ -29,7 +29,9 @@ #00FF00 - #FF0000 + #FF0000 + #FFFF00 #FFFF00 + #FF0000 diff --git a/core/ui/src/main/res/values/strings.xml b/core/ui/src/main/res/values/strings.xml index 8b07c425758d..599b6c54dbf8 100644 --- a/core/ui/src/main/res/values/strings.xml +++ b/core/ui/src/main/res/values/strings.xml @@ -177,8 +177,10 @@ rising rapidly none unknown + very high high in range + very low low Remove Activate profile diff --git a/implementation/src/main/kotlin/app/aaps/implementation/overview/LastBgDataImpl.kt b/implementation/src/main/kotlin/app/aaps/implementation/overview/LastBgDataImpl.kt index 5f5b4f5126a7..872021bbf429 100644 --- a/implementation/src/main/kotlin/app/aaps/implementation/overview/LastBgDataImpl.kt +++ b/implementation/src/main/kotlin/app/aaps/implementation/overview/LastBgDataImpl.kt @@ -30,6 +30,11 @@ class LastBgDataImpl @Inject constructor( iobCobCalculator.ads.bucketedData?.firstOrNull() ?: runBlocking { persistenceLayer.getLastGlucoseValue() }?.let { InMemoryGlucoseValue.fromGv(it) } + override fun isVeryLow(): Boolean = + lastBg()?.let { lastBg -> + lastBg.valueToUnits(profileFunction.getUnits()) < preferences.get(UnitDoubleKey.OverviewVeryLowMark) + } == true + override fun isLow(): Boolean = lastBg()?.let { lastBg -> lastBg.valueToUnits(profileFunction.getUnits()) < preferences.get(UnitDoubleKey.OverviewLowMark) @@ -40,9 +45,16 @@ class LastBgDataImpl @Inject constructor( lastBg.valueToUnits(profileFunction.getUnits()) > preferences.get(UnitDoubleKey.OverviewHighMark) } == true + override fun isVeryHigh(): Boolean = + lastBg()?.let { lastBg -> + lastBg.valueToUnits(profileFunction.getUnits()) > preferences.get(UnitDoubleKey.OverviewVeryHighMark) + } == true + override fun lastBgDescription(): String = when { + isVeryLow() -> rh.gs(app.aaps.core.ui.R.string.a11y_very_low) isLow() -> rh.gs(app.aaps.core.ui.R.string.a11y_low) + isVeryHigh() -> rh.gs(app.aaps.core.ui.R.string.a11y_very_high) isHigh() -> rh.gs(app.aaps.core.ui.R.string.a11y_high) else -> rh.gs(app.aaps.core.ui.R.string.a11y_inrange) } diff --git a/plugins/configuration/src/main/kotlin/app/aaps/plugins/configuration/setupwizard/SWDefinition.kt b/plugins/configuration/src/main/kotlin/app/aaps/plugins/configuration/setupwizard/SWDefinition.kt index c00e2308999f..224c49a641a9 100644 --- a/plugins/configuration/src/main/kotlin/app/aaps/plugins/configuration/setupwizard/SWDefinition.kt +++ b/plugins/configuration/src/main/kotlin/app/aaps/plugins/configuration/setupwizard/SWDefinition.kt @@ -158,6 +158,14 @@ class SWDefinition @Inject constructor( private val displaySettings get() = swScreenProvider.get().with(R.string.display_settings) .skippable(false) + .add( + swEditNumberWithUnitsProvider.get() + .preference(UnitDoubleKey.OverviewVeryLowMark) + .updateDelay(5) + .label(R.string.very_low_mark) + .comment(R.string.very_low_mark_comment) + ) + .add(swBreakProvider.get()) .add( swEditNumberWithUnitsProvider.get() .preference(UnitDoubleKey.OverviewLowMark) @@ -173,6 +181,14 @@ class SWDefinition @Inject constructor( .label(R.string.high_mark) .comment(R.string.high_mark_comment) ) + .add(swBreakProvider.get()) + .add( + swEditNumberWithUnitsProvider.get() + .preference(UnitDoubleKey.OverviewVeryHighMark) + .updateDelay(5) + .label(R.string.very_high_mark) + .comment(R.string.very_high_mark_comment) + ) private val screenPermissions get() = swScreenProvider.get().with(R.string.setupwizard_permissions) diff --git a/plugins/configuration/src/main/res/values/strings.xml b/plugins/configuration/src/main/res/values/strings.xml index 393228ee4e57..5605b3ec2f0b 100644 --- a/plugins/configuration/src/main/res/values/strings.xml +++ b/plugins/configuration/src/main/res/values/strings.xml @@ -11,10 +11,14 @@ MUST NOT BE USED TO MAKE MEDICAL DECISIONS. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM “AS IS” WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. I UNDERSTAND AND AGREE Display Settings + VERY LOW mark LOW mark HIGH mark + VERY HIGH mark + Very Low value of in range area (display only) Lower value of in range area (display only) Higher value of in range area (display only) + Even Higher value of in range area (display only) Stored settings found Master password is used for backup encryption and to override security in application. Remember it or store on a safe place. diff --git a/plugins/sync/src/main/kotlin/app/aaps/plugins/sync/tizen/TizenPlugin.kt b/plugins/sync/src/main/kotlin/app/aaps/plugins/sync/tizen/TizenPlugin.kt index 7a4efec8a17e..c7170ea3d4bc 100644 --- a/plugins/sync/src/main/kotlin/app/aaps/plugins/sync/tizen/TizenPlugin.kt +++ b/plugins/sync/src/main/kotlin/app/aaps/plugins/sync/tizen/TizenPlugin.kt @@ -161,8 +161,10 @@ class TizenPlugin @Inject constructor( bundle.putString("slopeArrow", lastBG.trendArrow.text) // direction arrow as string bundle.putDouble("deltaMgdl", glucoseStatus.delta) // bg delta in mgdl bundle.putDouble("avgDeltaMgdl", glucoseStatus.shortAvgDelta) // average bg delta + bundle.putDouble("veryHigh", preferences.get(UnitDoubleKey.OverviewVeryHighMark)) // predefined topmost value of in range (yellow area) bundle.putDouble("high", preferences.get(UnitDoubleKey.OverviewHighMark)) // predefined top value of in range (green area) bundle.putDouble("low", preferences.get(UnitDoubleKey.OverviewLowMark)) // predefined bottom value of in range + bundle.putDouble("veryLow", preferences.get(UnitDoubleKey.OverviewVeryLowMark)) // predefined very bottom value of in range } private fun iobCob(bundle: Bundle) { diff --git a/plugins/sync/src/main/kotlin/app/aaps/plugins/sync/wear/wearintegration/DataHandlerMobile.kt b/plugins/sync/src/main/kotlin/app/aaps/plugins/sync/wear/wearintegration/DataHandlerMobile.kt index 9d25697eb4a5..417e18e252a9 100644 --- a/plugins/sync/src/main/kotlin/app/aaps/plugins/sync/wear/wearintegration/DataHandlerMobile.kt +++ b/plugins/sync/src/main/kotlin/app/aaps/plugins/sync/wear/wearintegration/DataHandlerMobile.kt @@ -1600,13 +1600,15 @@ class DataHandlerMobile @Inject constructor( // Hoist out of the per-bucket map: getGlucoseStatusData copies the bucketed table and runs a polynomial fit on every call. val glucoseStatus = glucoseStatusProvider.getGlucoseStatusData(true) val units = profileFunction.getUnits() + val veryLowLine = profileUtil.convertToMgdl(preferences.get(UnitDoubleKey.OverviewVeryLowMark), units) val lowLine = profileUtil.convertToMgdl(preferences.get(UnitDoubleKey.OverviewLowMark), units) val highLine = profileUtil.convertToMgdl(preferences.get(UnitDoubleKey.OverviewHighMark), units) + val veryHighLine = profileUtil.convertToMgdl(preferences.get(UnitDoubleKey.OverviewVeryHighMark), units) val slopeArrow = (trendCalculator.getTrendArrow(iobCobCalculator.ads) ?: TrendArrow.NONE).symbol rxBus.send( EventMobileToWear( EventData.GraphData( - ArrayList(bucketedData.map { buildSingleBg(it, glucoseStatus, units, lowLine, highLine, slopeArrow) }) + ArrayList(bucketedData.map { buildSingleBg(it, glucoseStatus, units, veryLowLine, lowLine, highLine, veryHighLine, slopeArrow) }) ) ) ) @@ -1791,8 +1793,10 @@ class DataHandlerMobile @Inject constructor( timeStamp = bg.timestamp, glucoseUnits = GlucoseUnit.MGDL.asText, sgv = bg.value, + veryHigh = 0.0, high = 0.0, low = 0.0, + veryLow = 0.0, color = predictionColor(bg) ) ) @@ -1933,18 +1937,22 @@ class DataHandlerMobile @Inject constructor( private fun getSingleBG(glucoseValue: InMemoryGlucoseValue): EventData.SingleBg { val glucoseStatus = glucoseStatusProvider.getGlucoseStatusData(true) val units = profileFunction.getUnits() + val veryLowLine = profileUtil.convertToMgdl(preferences.get(UnitDoubleKey.OverviewVeryLowMark), units) val lowLine = profileUtil.convertToMgdl(preferences.get(UnitDoubleKey.OverviewLowMark), units) val highLine = profileUtil.convertToMgdl(preferences.get(UnitDoubleKey.OverviewHighMark), units) + val veryHighLine = profileUtil.convertToMgdl(preferences.get(UnitDoubleKey.OverviewVeryHighMark), units) val slopeArrow = (trendCalculator.getTrendArrow(iobCobCalculator.ads) ?: TrendArrow.NONE).symbol - return buildSingleBg(glucoseValue, glucoseStatus, units, lowLine, highLine, slopeArrow) + return buildSingleBg(glucoseValue, glucoseStatus, units, veryLowLine, lowLine, highLine, veryHighLine, slopeArrow) } private fun buildSingleBg( glucoseValue: InMemoryGlucoseValue, glucoseStatus: GlucoseStatus?, units: GlucoseUnit, + veryLowLine: Double, lowLine: Double, highLine: Double, + veryHighLine: Double, slopeArrow: String ): EventData.SingleBg = EventData.SingleBg( @@ -1957,10 +1965,18 @@ class DataHandlerMobile @Inject constructor( deltaDetailed = glucoseStatus?.let { deltaStringDetailed(it.delta, it.delta * Constants.MGDL_TO_MMOLL, units) } ?: "--", avgDelta = glucoseStatus?.let { deltaString(it.shortAvgDelta, it.shortAvgDelta * Constants.MGDL_TO_MMOLL, units) } ?: "--", avgDeltaDetailed = glucoseStatus?.let { deltaStringDetailed(it.shortAvgDelta, it.shortAvgDelta * Constants.MGDL_TO_MMOLL, units) } ?: "--", - sgvLevel = if (glucoseValue.recalculated > highLine) 1L else if (glucoseValue.recalculated < lowLine) -1L else 0L, + sgvLevel = when { + glucoseValue.recalculated > veryHighLine -> 2L + glucoseValue.recalculated > highLine -> 1L + glucoseValue.recalculated < veryLowLine -> -2L + glucoseValue.recalculated < lowLine -> -1L + else -> 0L + }, sgv = glucoseValue.recalculated, + veryHigh = veryHighLine, high = highLine, low = lowLine, + veryLow = veryLowLine, color = 0, deltaMgdl = glucoseStatus?.delta, avgDeltaMgdl = glucoseStatus?.shortAvgDelta diff --git a/plugins/sync/src/test/kotlin/app/aaps/plugins/sync/tizen/TizenPluginTest.kt b/plugins/sync/src/test/kotlin/app/aaps/plugins/sync/tizen/TizenPluginTest.kt index f8908b0518dd..ee7d4310c97b 100644 --- a/plugins/sync/src/test/kotlin/app/aaps/plugins/sync/tizen/TizenPluginTest.kt +++ b/plugins/sync/src/test/kotlin/app/aaps/plugins/sync/tizen/TizenPluginTest.kt @@ -94,8 +94,10 @@ internal class TizenPluginTest : TestBaseWithProfile() { assertThat(bundle.containsKey("slopeArrow")).isTrue() assertThat(bundle.containsKey("deltaMgdl")).isTrue() assertThat(bundle.containsKey("avgDeltaMgdl")).isTrue() + assertThat(bundle.containsKey("veryHigh")).isTrue() assertThat(bundle.containsKey("high")).isTrue() assertThat(bundle.containsKey("low")).isTrue() + assertThat(bundle.containsKey("veryLow")).isTrue() assertThat(bundle.containsKey("bolusIob")).isTrue() assertThat(bundle.containsKey("basalIob")).isTrue() assertThat(bundle.containsKey("iob")).isTrue() diff --git a/shared/impl/src/main/kotlin/app/aaps/shared/impl/weardata/JsonKeys.kt b/shared/impl/src/main/kotlin/app/aaps/shared/impl/weardata/JsonKeys.kt index a2475be56d26..e5a036636037 100644 --- a/shared/impl/src/main/kotlin/app/aaps/shared/impl/weardata/JsonKeys.kt +++ b/shared/impl/src/main/kotlin/app/aaps/shared/impl/weardata/JsonKeys.kt @@ -3,9 +3,11 @@ package app.aaps.shared.impl.weardata enum class JsonKeys(val key: String) { METADATA("metadata"), ENABLESECOND("enableSecond"), + VERYHIGHCOLOR("veryhighColor"), HIGHCOLOR("highColor"), MIDCOLOR("midColor"), LOWCOLOR("lowColor"), + VERYLOWCOLOR("veryLowColor"), LOWBATCOLOR("lowBatColor"), CARBCOLOR("carbColor"), BASALBACKGROUNDCOLOR("basalBackgroundColor"), diff --git a/ui/src/main/kotlin/app/aaps/ui/compose/components/DialogStatusBar.kt b/ui/src/main/kotlin/app/aaps/ui/compose/components/DialogStatusBar.kt index f5f572a759b0..9fde4b44b25d 100644 --- a/ui/src/main/kotlin/app/aaps/ui/compose/components/DialogStatusBar.kt +++ b/ui/src/main/kotlin/app/aaps/ui/compose/components/DialogStatusBar.kt @@ -129,7 +129,9 @@ private fun Separator() { @Composable private fun BgRange.toColor() = when (this) { - BgRange.HIGH -> AapsTheme.generalColors.bgHigh - BgRange.IN_RANGE -> AapsTheme.generalColors.bgInRange - BgRange.LOW -> AapsTheme.generalColors.bgLow + BgRange.VERY_HIGH -> AapsTheme.generalColors.bgVeryHigh + BgRange.HIGH -> AapsTheme.generalColors.bgHigh + BgRange.IN_RANGE -> AapsTheme.generalColors.bgInRange + BgRange.LOW -> AapsTheme.generalColors.bgLow + BgRange.VERY_LOW -> AapsTheme.generalColors.bgVeryLow } diff --git a/ui/src/main/kotlin/app/aaps/ui/compose/overview/BgInfoSection.kt b/ui/src/main/kotlin/app/aaps/ui/compose/overview/BgInfoSection.kt index 20deef4264da..0f26e75b6a3d 100644 --- a/ui/src/main/kotlin/app/aaps/ui/compose/overview/BgInfoSection.kt +++ b/ui/src/main/kotlin/app/aaps/ui/compose/overview/BgInfoSection.kt @@ -193,9 +193,11 @@ fun BgInfoSection( */ @Composable private fun BgRange.toColor(): Color = when (this) { - BgRange.HIGH -> AapsTheme.generalColors.bgHigh - BgRange.IN_RANGE -> AapsTheme.generalColors.bgInRange - BgRange.LOW -> AapsTheme.generalColors.bgLow + BgRange.VERY_HIGH -> AapsTheme.generalColors.bgVeryHigh + BgRange.HIGH -> AapsTheme.generalColors.bgHigh + BgRange.IN_RANGE -> AapsTheme.generalColors.bgInRange + BgRange.VERY_LOW -> AapsTheme.generalColors.bgVeryLow + BgRange.LOW -> AapsTheme.generalColors.bgLow } /** diff --git a/ui/src/main/kotlin/app/aaps/ui/compose/overview/OverviewDataCacheImpl.kt b/ui/src/main/kotlin/app/aaps/ui/compose/overview/OverviewDataCacheImpl.kt index a5ac257c1bad..dbc3db265922 100644 --- a/ui/src/main/kotlin/app/aaps/ui/compose/overview/OverviewDataCacheImpl.kt +++ b/ui/src/main/kotlin/app/aaps/ui/compose/overview/OverviewDataCacheImpl.kt @@ -489,14 +489,18 @@ class OverviewDataCacheImpl @AssistedInject constructor( } val bgMgdl = lastGv.recalculated + val veryHighMark = preferences.get(UnitDoubleKey.OverviewVeryHighMark) val highMark = preferences.get(UnitDoubleKey.OverviewHighMark) val lowMark = preferences.get(UnitDoubleKey.OverviewLowMark) + val veryLowMark = preferences.get(UnitDoubleKey.OverviewVeryLowMark) val valueInUnits = profileUtil.fromMgdlToUnits(bgMgdl) val bgRange = when { - valueInUnits > highMark -> BgRange.HIGH - valueInUnits < lowMark -> BgRange.LOW - else -> BgRange.IN_RANGE + valueInUnits > veryHighMark -> BgRange.VERY_HIGH + valueInUnits > highMark -> BgRange.HIGH + valueInUnits < veryLowMark -> BgRange.VERY_LOW + valueInUnits < lowMark -> BgRange.LOW + else -> BgRange.IN_RANGE } val isOutdated = lastGv.timestamp < dateUtil.now() - 9 * 60 * 1000L diff --git a/ui/src/main/kotlin/app/aaps/ui/compose/overview/graphs/BgGraphCompose.kt b/ui/src/main/kotlin/app/aaps/ui/compose/overview/graphs/BgGraphCompose.kt index 645cf8d8709a..75ed52501fb2 100644 --- a/ui/src/main/kotlin/app/aaps/ui/compose/overview/graphs/BgGraphCompose.kt +++ b/ui/src/main/kotlin/app/aaps/ui/compose/overview/graphs/BgGraphCompose.kt @@ -131,9 +131,11 @@ fun BgGraphCompose( // Colors from theme (stable - won't change) val regularColor = AapsTheme.generalColors.originalBgValue + val veryLowColor = AapsTheme.generalColors.bgVeryLow val lowColor = AapsTheme.generalColors.bgLow val inRangeColor = AapsTheme.generalColors.bgInRange val highColor = AapsTheme.generalColors.bgHigh + val veryHighColor = AapsTheme.generalColors.bgVeryHigh val basalColor = AapsTheme.elementColors.tempBasal val targetLineColor = AapsTheme.elementColors.tempTarget val activityColor = AapsTheme.elementColors.activity @@ -322,8 +324,8 @@ fun BgGraphCompose( bucketedData.associateBy { timestampToX(it.timestamp, minTimestamp) } } - val bucketedPointProvider = remember(bucketedLookup, lowColor, inRangeColor, highColor) { - BucketedPointProvider(bucketedLookup, lowColor, inRangeColor, highColor) + val bucketedPointProvider = remember(bucketedLookup, veryLowColor, lowColor, inRangeColor, highColor, veryHighColor) { + BucketedPointProvider(bucketedLookup, veryLowColor, lowColor, inRangeColor, highColor, veryHighColor) } // Time formatter and axis configuration diff --git a/ui/src/main/kotlin/app/aaps/ui/compose/overview/graphs/BucketedPointProvider.kt b/ui/src/main/kotlin/app/aaps/ui/compose/overview/graphs/BucketedPointProvider.kt index 9dcf4667705b..297c735cda6e 100644 --- a/ui/src/main/kotlin/app/aaps/ui/compose/overview/graphs/BucketedPointProvider.kt +++ b/ui/src/main/kotlin/app/aaps/ui/compose/overview/graphs/BucketedPointProvider.kt @@ -19,15 +19,19 @@ import com.patrykandpatrick.vico.compose.common.data.ExtraStore @Immutable class BucketedPointProvider( private val dataLookup: Map, + veryLowColor: Color, lowColor: Color, inRangeColor: Color, - highColor: Color + highColor: Color, + veryHighColor: Color ) : LineCartesianLayer.PointProvider { // Pre-build point components for efficiency + private val veryLowPoint = createFilledPoint(veryLowColor) private val lowPoint = createFilledPoint(lowColor) private val inRangePoint = createFilledPoint(inRangeColor) private val highPoint = createFilledPoint(highColor) + private val veryHighPoint = createFilledPoint(veryHighColor) private fun createFilledPoint(color: Color) = LineCartesianLayer.Point( component = ShapeComponent( @@ -45,9 +49,11 @@ class BucketedPointProvider( val dataPoint = dataLookup[entry.x] ?: return inRangePoint // fallback return when (dataPoint.range) { - BgRange.LOW -> lowPoint - BgRange.IN_RANGE -> inRangePoint - BgRange.HIGH -> highPoint + BgRange.VERY_LOW -> veryLowPoint + BgRange.LOW -> lowPoint + BgRange.IN_RANGE -> inRangePoint + BgRange.HIGH -> highPoint + BgRange.VERY_HIGH -> veryHighPoint } } diff --git a/ui/src/main/kotlin/app/aaps/ui/search/BuiltInSearchables.kt b/ui/src/main/kotlin/app/aaps/ui/search/BuiltInSearchables.kt index 8e00289a953b..44ce109edca8 100644 --- a/ui/src/main/kotlin/app/aaps/ui/search/BuiltInSearchables.kt +++ b/ui/src/main/kotlin/app/aaps/ui/search/BuiltInSearchables.kt @@ -82,8 +82,10 @@ class BuiltInSearchables @Inject constructor( key = "range_settings", titleResId = app.aaps.core.keys.R.string.prefs_range_title, items = listOf( + UnitDoubleKey.OverviewVeryLowMark, UnitDoubleKey.OverviewLowMark, - UnitDoubleKey.OverviewHighMark + UnitDoubleKey.OverviewHighMark, + UnitDoubleKey.OverviewVeryHighMark ) ), diff --git a/ui/src/main/kotlin/app/aaps/ui/widget/glance/BgGraphBitmapRenderer.kt b/ui/src/main/kotlin/app/aaps/ui/widget/glance/BgGraphBitmapRenderer.kt index 76c97a7df625..baaadcc8f0f7 100644 --- a/ui/src/main/kotlin/app/aaps/ui/widget/glance/BgGraphBitmapRenderer.kt +++ b/ui/src/main/kotlin/app/aaps/ui/widget/glance/BgGraphBitmapRenderer.kt @@ -20,9 +20,11 @@ data class BgGraphInput( ) data class BgGraphColors( + val veryLow: Int, val low: Int, val inRange: Int, - val high: Int + val high: Int, + val veryHigh: Int ) /** @@ -64,9 +66,11 @@ class BgGraphBitmapRenderer { } private fun colorForRange(range: BgRange, colors: BgGraphColors): Int = when (range) { - BgRange.LOW -> colors.low - BgRange.IN_RANGE -> colors.inRange - BgRange.HIGH -> colors.high + BgRange.VERY_LOW -> colors.veryLow + BgRange.LOW -> colors.low + BgRange.IN_RANGE -> colors.inRange + BgRange.VERY_HIGH -> colors.veryHigh + BgRange.HIGH -> colors.high } companion object { diff --git a/ui/src/main/kotlin/app/aaps/ui/widget/glance/BgGraphStateLoader.kt b/ui/src/main/kotlin/app/aaps/ui/widget/glance/BgGraphStateLoader.kt index eb59bca49659..b1012fefc15e 100644 --- a/ui/src/main/kotlin/app/aaps/ui/widget/glance/BgGraphStateLoader.kt +++ b/ui/src/main/kotlin/app/aaps/ui/widget/glance/BgGraphStateLoader.kt @@ -79,9 +79,11 @@ class BgGraphStateLoader @Inject constructor( ) val colors = BgGraphColors( + veryLow = rh.gc(app.aaps.core.ui.R.color.widget_very_low), low = rh.gc(app.aaps.core.ui.R.color.widget_low), inRange = rh.gc(app.aaps.core.ui.R.color.widget_inrange), - high = rh.gc(app.aaps.core.ui.R.color.widget_high) + high = rh.gc(app.aaps.core.ui.R.color.widget_high), + veryHigh = rh.gc(app.aaps.core.ui.R.color.widget_very_high) ) // Current BG + trend (same logic as WidgetStateLoader) @@ -89,9 +91,11 @@ class BgGraphStateLoader @Inject constructor( val bgText = lastBg?.let { profileUtil.fromMgdlToStringInUnits(it.recalculated) } ?: rh.gs(app.aaps.core.ui.R.string.value_unavailable_short) val bgColor = when { - lastBgData.isLow() -> colors.low - lastBgData.isHigh() -> colors.high - else -> colors.inRange + lastBgData.isVeryLow() -> colors.veryLow + lastBgData.isLow() -> colors.low + lastBgData.isVeryHigh() -> colors.veryHigh + lastBgData.isHigh() -> colors.high + else -> colors.inRange } val strikeThrough = !lastBgData.isActualBg() val trendArrow = trendCalculator.getTrendArrow(iobCobCalculator.ads) diff --git a/ui/src/main/kotlin/app/aaps/ui/widget/glance/WidgetStateLoader.kt b/ui/src/main/kotlin/app/aaps/ui/widget/glance/WidgetStateLoader.kt index c463a46e3842..f3d0ea994119 100644 --- a/ui/src/main/kotlin/app/aaps/ui/widget/glance/WidgetStateLoader.kt +++ b/ui/src/main/kotlin/app/aaps/ui/widget/glance/WidgetStateLoader.kt @@ -60,7 +60,9 @@ class WidgetStateLoader @Inject constructor( val bgText = lastBg?.let { profileUtil.fromMgdlToStringInUnits(it.recalculated) } ?: rh.gs(app.aaps.core.ui.R.string.value_unavailable_short) val bgColor = when { + lastBgData.isVeryLow() -> rh.gc(app.aaps.core.ui.R.color.widget_very_low) lastBgData.isLow() -> rh.gc(app.aaps.core.ui.R.color.widget_low) + lastBgData.isVeryHigh() -> rh.gc(app.aaps.core.ui.R.color.widget_very_high) lastBgData.isHigh() -> rh.gc(app.aaps.core.ui.R.color.widget_high) else -> rh.gc(app.aaps.core.ui.R.color.widget_inrange) } diff --git a/wear/src/main/kotlin/app/aaps/wear/complications/ModernBaseComplicationProviderService.kt b/wear/src/main/kotlin/app/aaps/wear/complications/ModernBaseComplicationProviderService.kt index 65d372bf1a7b..91f8c300bbfb 100644 --- a/wear/src/main/kotlin/app/aaps/wear/complications/ModernBaseComplicationProviderService.kt +++ b/wear/src/main/kotlin/app/aaps/wear/complications/ModernBaseComplicationProviderService.kt @@ -213,8 +213,10 @@ abstract class ModernBaseComplicationProviderService : ComplicationDataSourceSer avgDeltaDetailed = "+3.1", sgvLevel = 0L, sgv = 120.0, + veryHigh = 240.0, high = 180.0, low = 70.0, + veryLow = 55.0, color = 0 ), statusData = app.aaps.core.interfaces.rx.weardata.EventData.Status( diff --git a/wear/src/main/kotlin/app/aaps/wear/data/ComplicationStore.kt b/wear/src/main/kotlin/app/aaps/wear/data/ComplicationStore.kt index ef4d9e00ed78..c9de2075697c 100644 --- a/wear/src/main/kotlin/app/aaps/wear/data/ComplicationStore.kt +++ b/wear/src/main/kotlin/app/aaps/wear/data/ComplicationStore.kt @@ -24,8 +24,10 @@ data class ComplicationData( avgDeltaDetailed = "--", sgvLevel = 0L, sgv = 0.0, + veryHigh = 0.0, high = 0.0, low = 0.0, + veryLow = 0.0, color = 0 ), val bgData1: EventData.SingleBg = EventData.SingleBg( @@ -40,8 +42,10 @@ data class ComplicationData( avgDeltaDetailed = "--", sgvLevel = 0L, sgv = 0.0, + veryHigh = 0.0, high = 0.0, low = 0.0, + veryLow = 0.0, color = 0 ), val bgData2: EventData.SingleBg = EventData.SingleBg( @@ -56,8 +60,10 @@ data class ComplicationData( avgDeltaDetailed = "--", sgvLevel = 0L, sgv = 0.0, + veryHigh = 0.0, high = 0.0, low = 0.0, + veryLow = 0.0, color = 0 ), val statusData: EventData.Status = EventData.Status( diff --git a/wear/src/main/kotlin/app/aaps/wear/watchfaces/CircleWatchface.kt b/wear/src/main/kotlin/app/aaps/wear/watchfaces/CircleWatchface.kt index 3104f864e2cd..47fb72b69421 100644 --- a/wear/src/main/kotlin/app/aaps/wear/watchfaces/CircleWatchface.kt +++ b/wear/src/main/kotlin/app/aaps/wear/watchfaces/CircleWatchface.kt @@ -279,11 +279,15 @@ class CircleWatchface : WatchFace() { angleBig = ((hour + minute / 60f) / 12f * 360 - 90 - BIG_HAND_WIDTH / 2f + 360) % 360 angleSMALL = (minute / 60f * 360 - 90 - SMALL_HAND_WIDTH / 2f + 360) % 360 color = 0 + when (singleBg[0].sgvLevel.toInt()) { + -2 -> color = veryLowColor -1 -> color = lowColor 0 -> color = inRangeColor 1 -> color = highColor + 2 -> color = veryHighColor } + circlePaint.shader = null circlePaint.style = Paint.Style.STROKE circlePaint.strokeWidth = CIRCLE_WIDTH @@ -318,12 +322,16 @@ class CircleWatchface : WatchFace() { } // defining color for dark and bright - private val lowColor: Int + private val veryLowColor: Int get() = if (sp.getBoolean(R.string.key_dark, true)) Color.argb(255, 255, 120, 120) else Color.argb(255, 255, 80, 80) + private val lowColor: Int + get() = if (sp.getBoolean(R.string.key_dark, true)) Color.argb(255, 255, 255, 120) else Color.argb(255, 255, 80, 80) private val inRangeColor: Int get() = if (sp.getBoolean(R.string.key_dark, true)) Color.argb(255, 120, 255, 120) else Color.argb(255, 0, 240, 0) private val highColor: Int get() = if (sp.getBoolean(R.string.key_dark, true)) Color.argb(255, 255, 255, 120) else Color.argb(255, 255, 200, 0) + private val veryHighColor: Int + get() = if (sp.getBoolean(R.string.key_dark, true)) Color.argb(255, 255, 120, 120) else Color.argb(255, 255, 200, 0) private val backgroundColor: Int get() = if (sp.getBoolean(R.string.key_dark, true)) Color.BLACK else Color.WHITE val textColor: Int @@ -335,8 +343,10 @@ class CircleWatchface : WatchFace() { //Perfect low and High indicators if (bgDataList.isNotEmpty()) { addIndicator(canvas, 100f, Color.LTGRAY) + addIndicator(canvas, bgDataList.iterator().next().veryLow.toFloat(), veryLowColor) addIndicator(canvas, bgDataList.iterator().next().low.toFloat(), lowColor) addIndicator(canvas, bgDataList.iterator().next().high.toFloat(), highColor) + addIndicator(canvas, bgDataList.iterator().next().veryHigh.toFloat(), veryHighColor) if (sp.getBoolean("softRingHistory", true)) { for (data in bgDataList) { addReadingSoft(canvas, data) @@ -432,9 +442,15 @@ class CircleWatchface : WatchFace() { indicatorColor = Color.LTGRAY } var barColor = Color.GRAY - if (entry.sgv >= entry.high) { + if (entry.sgv >= entry.veryHigh) { + indicatorColor = veryHighColor + barColor = darken(veryHighColor) + } else if (entry.sgv >= entry.high) { indicatorColor = highColor barColor = darken(highColor) + } else if (entry.sgv <= entry.veryLow) { + indicatorColor = veryLowColor + barColor = darken(veryLowColor) } else if (entry.sgv <= entry.low) { indicatorColor = lowColor barColor = darken(lowColor) diff --git a/wear/src/main/kotlin/app/aaps/wear/watchfaces/CustomWatchface.kt b/wear/src/main/kotlin/app/aaps/wear/watchfaces/CustomWatchface.kt index 6a864ce1478c..9a2b61cb218c 100644 --- a/wear/src/main/kotlin/app/aaps/wear/watchfaces/CustomWatchface.kt +++ b/wear/src/main/kotlin/app/aaps/wear/watchfaces/CustomWatchface.kt @@ -73,9 +73,11 @@ class CustomWatchface : BaseWatchFace() { private var jsonString = "" private fun bgColor(dataSet: Int): Int = when (singleBg[dataSet].sgvLevel) { - 1L -> highColor - 0L -> midColor - -1L -> lowColor + 2L -> veryHighColor + 1L -> highColor + 0L -> midColor + -1L -> lowColor + -2L -> veryLowColor else -> midColor } @@ -254,9 +256,11 @@ class CustomWatchface : BaseWatchFace() { binding.dayName.text = dateUtil.dayNameString(dayNameFormat).substringBeforeLast(".") // Update dayName and month according to format on cwf loading binding.month.text = dateUtil.monthString(monthFormat).substringBeforeLast(".") val jsonColor = dynPref[json.optString(JsonKeys.DYNPREFCOLOR.key)] ?: json + veryHighColor = getColor(jsonColor.optString(JsonKeys.VERYHIGHCOLOR.key), ContextCompat.getColor(this, R.color.dark_veryHighColor)) highColor = getColor(jsonColor.optString(JsonKeys.HIGHCOLOR.key), ContextCompat.getColor(this, R.color.dark_highColor)) midColor = getColor(jsonColor.optString(JsonKeys.MIDCOLOR.key), ContextCompat.getColor(this, R.color.inrange)) lowColor = getColor(jsonColor.optString(JsonKeys.LOWCOLOR.key), ContextCompat.getColor(this, R.color.low)) + veryLowColor = getColor(jsonColor.optString(JsonKeys.VERYLOWCOLOR.key), ContextCompat.getColor(this, R.color.veryLow)) lowBatColor = getColor(jsonColor.optString(JsonKeys.LOWBATCOLOR.key), ContextCompat.getColor(this, R.color.dark_uploaderBatteryEmpty)) carbColor = getColor(jsonColor.optString(JsonKeys.CARBCOLOR.key), ContextCompat.getColor(this, R.color.carbs)) basalBackgroundColor = getColor(jsonColor.optString(JsonKeys.BASALBACKGROUNDCOLOR.key), ContextCompat.getColor(this, R.color.basal_dark)) @@ -378,9 +382,11 @@ class CustomWatchface : BaseWatchFace() { } private fun setDefaultColors() { + veryHighColor = "#FF0000".toColorInt() highColor = "#FFFF00".toColorInt() midColor = "#00FF00".toColorInt() - lowColor = "#FF0000".toColorInt() + lowColor = "#FFFF00".toColorInt() + veryLowColor = "#FF0000".toColorInt() carbColor = ContextCompat.getColor(this, R.color.carbs) basalBackgroundColor = ContextCompat.getColor(this, R.color.basal_dark) basalCenterColor = ContextCompat.getColor(this, R.color.basal_light) @@ -615,9 +621,12 @@ class CustomWatchface : BaseWatchFace() { var highCustom: Drawable? = null var lowCustom: Drawable? = null var textDrawable: Drawable? = null + fun drawable(cwf: CustomWatchface): Drawable? = dynData?.getDrawable(cwf) ?: when (cwf.singleBg[0].sgvLevel) { + 2L -> highCustom ?: rangeCustom 1L -> highCustom ?: rangeCustom 0L -> rangeCustom + -2L -> lowCustom ?: rangeCustom -1L -> lowCustom ?: rangeCustom else -> rangeCustom } @@ -852,7 +861,7 @@ class CustomWatchface : BaseWatchFace() { private enum class ValueMap(val key: String, val min: Double, val max: Double) { NONE("", 0.0, 0.0), SGV(ViewKeys.SGV.key, 39.0, 400.0), - SGV_LEVEL(JsonKeyValues.SGV_LEVEL.key, -1.0, 1.0), + SGV_LEVEL(JsonKeyValues.SGV_LEVEL.key, -2.0, 2.0), DIRECTION(ViewKeys.DIRECTION.key, 1.0, 7.0), DELTA(ViewKeys.DELTA.key, -25.0, 25.0), AVG_DELTA(ViewKeys.AVG_DELTA.key, -25.0, 25.0), diff --git a/wear/src/main/kotlin/app/aaps/wear/watchfaces/DigitalStyleWatchface.kt b/wear/src/main/kotlin/app/aaps/wear/watchfaces/DigitalStyleWatchface.kt index ac3b333d7f1f..6f3511d24b97 100644 --- a/wear/src/main/kotlin/app/aaps/wear/watchfaces/DigitalStyleWatchface.kt +++ b/wear/src/main/kotlin/app/aaps/wear/watchfaces/DigitalStyleWatchface.kt @@ -28,11 +28,14 @@ class DigitalStyleWatchface : BaseWatchFace() { override fun setColorDark() { val color = when (singleBg[0].sgvLevel) { + 2L -> R.color.dark_veryHighColor 1L -> R.color.dark_highColor 0L -> R.color.dark_midColor -1L -> R.color.dark_lowColor + -2L -> R.color.dark_veryLowColor else -> R.color.dark_midColor } + binding.sgv.setTextColor(ContextCompat.getColor(this, color)) binding.direction.setTextColor(ContextCompat.getColor(this, color)) diff --git a/wear/src/main/kotlin/app/aaps/wear/watchfaces/utils/BaseWatchFace.kt b/wear/src/main/kotlin/app/aaps/wear/watchfaces/utils/BaseWatchFace.kt index 801533a835f4..a9a9a29271fa 100644 --- a/wear/src/main/kotlin/app/aaps/wear/watchfaces/utils/BaseWatchFace.kt +++ b/wear/src/main/kotlin/app/aaps/wear/watchfaces/utils/BaseWatchFace.kt @@ -127,8 +127,10 @@ abstract class BaseWatchFace : WatchFace() { var loopLevelExt2 = -1 var enableExt1 = false var enableExt2 = false + var veryHighColor = Color.RED var highColor = Color.YELLOW - var lowColor = Color.RED + var lowColor = Color.YELLOW + var veryLowColor = Color.RED var midColor = Color.WHITE var gridColor = Color.WHITE var basalBackgroundColor = Color.BLUE @@ -701,12 +703,14 @@ abstract class BaseWatchFace : WatchFace() { if (lowResMode) BgGraphBuilder( sp, dateUtil, graphData.entries, treatmentData.predictions, treatmentData.temps, treatmentData.basals, treatmentData.boluses, pointSize, - midColor, gridColor, basalBackgroundColor, basalCenterColor, bolusColor, carbColor, timeframe + midColor, gridColor, + basalBackgroundColor, basalCenterColor, bolusColor, carbColor, timeframe ) else BgGraphBuilder( - sp, dateUtil, graphData.entries, treatmentData.predictions, treatmentData.temps, treatmentData.basals, treatmentData.boluses, - pointSize, highColor, lowColor, midColor, gridColor, basalBackgroundColor, basalCenterColor, bolusColor, carbColor, timeframe + sp, dateUtil, graphData.entries, treatmentData.predictions, treatmentData.temps, treatmentData.basals, treatmentData.boluses, pointSize, + veryHighColor, highColor, lowColor, veryLowColor, midColor, gridColor, + basalBackgroundColor, basalCenterColor, bolusColor, carbColor, timeframe ) binding.chart?.lineChartData = bgGraphBuilder.lineData() binding.chart?.isViewportCalculationEnabled = true diff --git a/wear/src/main/kotlin/app/aaps/wear/watchfaces/utils/BgGraphBuilder.kt b/wear/src/main/kotlin/app/aaps/wear/watchfaces/utils/BgGraphBuilder.kt index 712eaa5056c1..91e23404782c 100644 --- a/wear/src/main/kotlin/app/aaps/wear/watchfaces/utils/BgGraphBuilder.kt +++ b/wear/src/main/kotlin/app/aaps/wear/watchfaces/utils/BgGraphBuilder.kt @@ -65,8 +65,10 @@ class BgGraphBuilder( private val basalWatchDataList: ArrayList, private val bolusWatchDataList: ArrayList, private val pointSize: Int, + private val veryHighColor: Int, private val highColor: Int, private val lowColor: Int, + private val veryLowColor: Int, private val midColor: Int, private val gridColour: Int, private val basalBackgroundColor: Int, @@ -79,11 +81,15 @@ class BgGraphBuilder( private var endingTime: Long = System.currentTimeMillis() + 1000L * 60 * 6 * timeSpan private var startingTime: Long = System.currentTimeMillis() - 1000L * 60 * 60 * timeSpan private var fuzzyTimeDiv = (1000 * 60 * 1).toDouble() + private var veryHighMark: Double = bgDataList[bgDataList.size - 1].veryHigh private var highMark: Double = bgDataList[bgDataList.size - 1].high private var lowMark: Double = bgDataList[bgDataList.size - 1].low + private var veryLowMark: Double = bgDataList[bgDataList.size - 1].veryLow private val inRangeValues: MutableList = ArrayList() + private val veryHighValues: MutableList = ArrayList() private val highValues: MutableList = ArrayList() private val lowValues: MutableList = ArrayList() + private val veryLowValues: MutableList = ArrayList() private val predictionEndTime: Long get() { @@ -130,11 +136,17 @@ class BgGraphBuilder( tempWatchDataList: List, basalWatchDataList: ArrayList, bolusWatchDataList: ArrayList, - aPointSize: Int, aMidColor: Int, gridColour: Int, basalBackgroundColor: Int, basalCenterColor: Int, bolusInvalidColor: Int, carbsColor: Int, timeSpan: Int + aPointSize: Int, + aMidColor: Int, + gridColour: Int, + basalBackgroundColor: Int, + basalCenterColor: Int, + bolusInvalidColor: Int, + carbsColor: Int, + timeSpan: Int ) : this( - sp, dateUtil, - aBgList, predictionsList, tempWatchDataList, basalWatchDataList, - bolusWatchDataList, aPointSize, aMidColor, aMidColor, aMidColor, gridColour, + sp, dateUtil, aBgList, predictionsList, tempWatchDataList, basalWatchDataList, bolusWatchDataList, aPointSize, + aMidColor, aMidColor, aMidColor, aMidColor, aMidColor, gridColour, basalBackgroundColor, basalCenterColor, bolusInvalidColor, carbsColor, timeSpan ) @@ -166,11 +178,15 @@ class BgGraphBuilder( private fun defaultLines(): List { addBgReadingValues() val lines: MutableList = ArrayList() + lines.add(veryHighLine()) lines.add(highLine()) lines.add(lowLine()) + lines.add(veryLowLine()) lines.add(inRangeValuesLine()) + lines.add(veryLowValuesLine()) lines.add(lowValuesLine()) lines.add(highValuesLine()) + lines.add(veryHighValuesLine()) var minChart = lowMark var maxChart = highMark for ((_, _, _, _, _, _, _, _, _, _, sgv) in bgDataList) { @@ -289,7 +305,7 @@ class BgGraphBuilder( private fun addPredictionLines(lines: MutableList) { val values: MutableMap> = HashMap() - for ((_, timeStamp, _, _, _, _, _, _, _, _, sgv, _, _, color) in predictionsList) { + for ((_, timeStamp, _, _, _, _, _, _, _, _, _, _, sgv, _, _, color) in predictionsList) { if (timeStamp <= predictionEndTime) { val value = min(sgv, UPPER_CUTOFF_SGV) if (!values.containsKey(color)) { @@ -310,6 +326,14 @@ class BgGraphBuilder( } } + private fun veryHighValuesLine(): Line = + Line(veryHighValues).also { veryHighValuesLine -> + veryHighValuesLine.color = veryHighColor + veryHighValuesLine.setHasLines(false) + veryHighValuesLine.pointRadius = pointSize + veryHighValuesLine.setHasPoints(true) + } + private fun highValuesLine(): Line = Line(highValues).also { highValuesLine -> highValuesLine.color = highColor @@ -326,6 +350,14 @@ class BgGraphBuilder( lowValuesLine.setHasPoints(true) } + private fun veryLowValuesLine(): Line = + Line(veryLowValues).also { veryLowValuesLine -> + veryLowValuesLine.color = veryLowColor + veryLowValuesLine.setHasLines(false) + veryLowValuesLine.pointRadius = pointSize + veryLowValuesLine.setHasPoints(true) + } + private fun inRangeValuesLine(): Line = Line(inRangeValues).also { inRangeValuesLine -> inRangeValuesLine.color = midColor @@ -357,11 +389,13 @@ class BgGraphBuilder( for ((_, timeStamp, _, _, _, _, _, _, _, _, sgv) in bgDataList) { if (timeStamp > startingTime) { when { - sgv >= 450 -> highValues.add(PointValue(fuzz(timeStamp), 450.toFloat())) + sgv >= 450 -> veryHighValues.add(PointValue(fuzz(timeStamp), 450.toFloat())) + sgv >= veryHighMark -> veryHighValues.add(PointValue(fuzz(timeStamp), sgv.toFloat())) sgv >= highMark -> highValues.add(PointValue(fuzz(timeStamp), sgv.toFloat())) sgv >= lowMark -> inRangeValues.add(PointValue(fuzz(timeStamp), sgv.toFloat())) - sgv >= 40 -> lowValues.add(PointValue(fuzz(timeStamp), sgv.toFloat())) - sgv >= 11 -> lowValues.add(PointValue(fuzz(timeStamp), 40.toFloat())) + sgv >= veryLowMark -> veryLowValues.add(PointValue(fuzz(timeStamp), sgv.toFloat())) + sgv >= 40 -> veryLowValues.add(PointValue(fuzz(timeStamp), sgv.toFloat())) + sgv >= 11 -> veryLowValues.add(PointValue(fuzz(timeStamp), 40.toFloat())) } } } @@ -378,6 +412,17 @@ class BgGraphBuilder( } } + private fun veryHighLine(): Line { + val veryHighLineValues: MutableList = ArrayList() + veryHighLineValues.add(PointValue(fuzz(startingTime), veryHighMark.toFloat())) + veryHighLineValues.add(PointValue(fuzz(endingTime), veryHighMark.toFloat())) + return Line(veryHighLineValues).also { veryHighLine -> + veryHighLine.setHasPoints(false) + veryHighLine.strokeWidth = 1 + veryHighLine.color = veryHighColor + } + } + private fun lowLine(): Line { val lowLineValues: MutableList = ArrayList() lowLineValues.add(PointValue(fuzz(startingTime), lowMark.toFloat())) @@ -389,6 +434,17 @@ class BgGraphBuilder( } } + private fun veryLowLine(): Line { + val veryLowLineValues: MutableList = ArrayList() + veryLowLineValues.add(PointValue(fuzz(startingTime), veryLowMark.toFloat())) + veryLowLineValues.add(PointValue(fuzz(endingTime), veryLowMark.toFloat())) + return Line(veryLowLineValues).also { veryLowLine -> + veryLowLine.setHasPoints(false) + veryLowLine.color = veryLowColor + veryLowLine.strokeWidth = 1 + } + } + /////////AXIS RELATED////////////// private fun yAxis(): Axis = Axis().also { yAxis -> diff --git a/wear/src/main/kotlin/app/aaps/wear/watchfaces/utils/SimpleUi.kt b/wear/src/main/kotlin/app/aaps/wear/watchfaces/utils/SimpleUi.kt index 4b83e078d6ae..37f86f30a234 100644 --- a/wear/src/main/kotlin/app/aaps/wear/watchfaces/utils/SimpleUi.kt +++ b/wear/src/main/kotlin/app/aaps/wear/watchfaces/utils/SimpleUi.kt @@ -29,9 +29,11 @@ class SimpleUi @Inject constructor( private lateinit var mSvgPaint: Paint private lateinit var mDirectionPaint: Paint private var mYOffset = 0f + private val colorDarkVeryHigh = ContextCompat.getColor(context, R.color.dark_veryHighColor) private val colorDarkHigh = ContextCompat.getColor(context, R.color.dark_highColor) private var colorDarkMid = ContextCompat.getColor(context, R.color.dark_midColor) private var colorDarkLow = ContextCompat.getColor(context, R.color.dark_lowColor) + private var colorDarkVeryLow = ContextCompat.getColor(context, R.color.dark_veryLowColor) private var displayWidth = 0 private var displayHeight = 0 private lateinit var callback: () -> Unit @@ -97,8 +99,11 @@ class SimpleUi @Inject constructor( private fun getBgColour(level: Long): Int = when (level) { + 2L -> colorDarkVeryHigh 1L -> colorDarkHigh 0L -> colorDarkMid + -1L -> colorDarkLow + -2L -> colorDarkVeryLow else -> colorDarkLow } diff --git a/wear/src/main/res/values/colors.xml b/wear/src/main/res/values/colors.xml index bc898c87b504..c2ae5b26f8bd 100644 --- a/wear/src/main/res/values/colors.xml +++ b/wear/src/main/res/values/colors.xml @@ -31,8 +31,10 @@ #ffff00 #ff4444 + @color/RED @color/yellow_A200 - @color/RED + @color/yellow_A200 + @color/RED @color/grey_50 @color/grey_50 @@ -52,7 +54,8 @@ #00FF00 #67DFE8 #FFFB8C00 - #FF0000 + #FFFF00 + #FF0000 #77dd77 diff --git a/workflow/src/main/kotlin/app/aaps/workflow/PostCalculationWorker.kt b/workflow/src/main/kotlin/app/aaps/workflow/PostCalculationWorker.kt index c2f1ed557dea..7369e94c2a66 100644 --- a/workflow/src/main/kotlin/app/aaps/workflow/PostCalculationWorker.kt +++ b/workflow/src/main/kotlin/app/aaps/workflow/PostCalculationWorker.kt @@ -115,8 +115,10 @@ class PostCalculationWorker( data.overviewData.endTime = data.overviewData.toTime } + val veryHighMarkInUnits = preferences.get(UnitDoubleKey.OverviewVeryHighMark) val highMarkInUnits = preferences.get(UnitDoubleKey.OverviewHighMark) val lowMarkInUnits = preferences.get(UnitDoubleKey.OverviewLowMark) + val veryLowMarkInUnits = preferences.get(UnitDoubleKey.OverviewVeryLowMark) val predictionDataPoints = apsResult?.predictionsAsGv ?.filter { it.value >= 40 } @@ -126,9 +128,11 @@ class PostCalculationWorker( timestamp = gv.timestamp, value = valueInUnits, range = when { - valueInUnits > highMarkInUnits -> BgRange.HIGH - valueInUnits < lowMarkInUnits -> BgRange.LOW - else -> BgRange.IN_RANGE + valueInUnits > veryHighMarkInUnits -> BgRange.VERY_HIGH + valueInUnits > highMarkInUnits -> BgRange.HIGH + valueInUnits < veryLowMarkInUnits -> BgRange.VERY_LOW + valueInUnits < lowMarkInUnits -> BgRange.LOW + else -> BgRange.IN_RANGE }, type = when (gv.sourceSensor) { SourceSensor.IOB_PREDICTION -> BgType.IOB_PREDICTION diff --git a/workflow/src/main/kotlin/app/aaps/workflow/PrepareGraphDataWorker.kt b/workflow/src/main/kotlin/app/aaps/workflow/PrepareGraphDataWorker.kt index 9a69a2f468fc..62a7cca16d4e 100644 --- a/workflow/src/main/kotlin/app/aaps/workflow/PrepareGraphDataWorker.kt +++ b/workflow/src/main/kotlin/app/aaps/workflow/PrepareGraphDataWorker.kt @@ -180,17 +180,21 @@ class PrepareGraphDataWorker( val newFromTime = newToTime - T.hours(Constants.GRAPH_TIME_RANGE_HOURS.toLong()).msecs() data.cache.updateTimeRange(TimeRange(fromTime = newFromTime, toTime = newToTime, endTime = newToTime)) + val veryHighMark = preferences.get(UnitDoubleKey.OverviewVeryHighMark) val highMark = preferences.get(UnitDoubleKey.OverviewHighMark) val lowMark = preferences.get(UnitDoubleKey.OverviewLowMark) + val veryLowMark = preferences.get(UnitDoubleKey.OverviewVeryLowMark) val bucketedDataPoints = bucketedData .filter { it.timestamp in newFromTime..newToTime } .map { value -> val valueInUnits = profileUtil.fromMgdlToUnits(value.recalculated) val range = when { - valueInUnits > highMark -> BgRange.HIGH - valueInUnits < lowMark -> BgRange.LOW - else -> BgRange.IN_RANGE + valueInUnits > veryHighMark -> BgRange.VERY_HIGH + valueInUnits > highMark -> BgRange.HIGH + valueInUnits < veryLowMark -> BgRange.VERY_LOW + valueInUnits < lowMark -> BgRange.LOW + else -> BgRange.IN_RANGE } BgDataPoint( timestamp = value.timestamp, @@ -210,8 +214,10 @@ class PrepareGraphDataWorker( val fromTime = toTime - T.hours(Constants.GRAPH_TIME_RANGE_HOURS.toLong()).msecs() val bgReadingsArray = persistenceLayer.getBgReadingsDataFromTimeToTime(fromTime, toTime, false) + val veryHighMarkInUnits = preferences.get(UnitDoubleKey.OverviewVeryHighMark) val highMarkInUnits = preferences.get(UnitDoubleKey.OverviewHighMark) val lowMarkInUnits = preferences.get(UnitDoubleKey.OverviewLowMark) + val veryLowMarkInUnits = preferences.get(UnitDoubleKey.OverviewVeryLowMark) val bgDataPoints = bgReadingsArray .filter { it.timestamp in fromTime..toTime } @@ -221,9 +227,11 @@ class PrepareGraphDataWorker( timestamp = bg.timestamp, value = valueInUnits, range = when { - valueInUnits > highMarkInUnits -> BgRange.HIGH - valueInUnits < lowMarkInUnits -> BgRange.LOW - else -> BgRange.IN_RANGE + valueInUnits > veryHighMarkInUnits -> BgRange.VERY_HIGH + valueInUnits > highMarkInUnits -> BgRange.HIGH + valueInUnits < veryLowMarkInUnits -> BgRange.VERY_LOW + valueInUnits < lowMarkInUnits -> BgRange.LOW + else -> BgRange.IN_RANGE }, type = BgType.REGULAR )