diff --git a/core/interfaces/src/main/kotlin/app/aaps/core/interfaces/insulin/ConcentrationHelper.kt b/core/interfaces/src/main/kotlin/app/aaps/core/interfaces/insulin/ConcentrationHelper.kt index db49dcbacf5..26091b4ccc9 100644 --- a/core/interfaces/src/main/kotlin/app/aaps/core/interfaces/insulin/ConcentrationHelper.kt +++ b/core/interfaces/src/main/kotlin/app/aaps/core/interfaces/insulin/ConcentrationHelper.kt @@ -53,10 +53,11 @@ interface ConcentrationHelper { * i.e. "4 U 5 min ago", and with both value if other concentration: i.e. for U200 "4 U (2 CU) 5 min ago" * * @param amount PumpInsulin - * @param ago String - * @return String with units (U100) or with both units if not U100 + * @param lastBolusTime Long + * @return String with units (U100) or with both units if not U100 and ago if less than 6 hour ago, else null */ fun insulinAmountAgoString(amount: PumpInsulin, ago: String): String + fun insulinAmountAgoString(amount: PumpInsulin, lastBolusTime: Long): String? /** * show insulinConcentration as a String i.e. "U100", "U200", ... diff --git a/core/objects/src/main/kotlin/app/aaps/core/objects/extensions/ExtendedBolusExtension.kt b/core/objects/src/main/kotlin/app/aaps/core/objects/extensions/ExtendedBolusExtension.kt index 5e3ca8d62b3..aca9323dc15 100644 --- a/core/objects/src/main/kotlin/app/aaps/core/objects/extensions/ExtendedBolusExtension.kt +++ b/core/objects/src/main/kotlin/app/aaps/core/objects/extensions/ExtendedBolusExtension.kt @@ -7,8 +7,10 @@ import app.aaps.core.data.model.TB import app.aaps.core.data.time.T import app.aaps.core.interfaces.aps.AutosensResult import app.aaps.core.interfaces.aps.IobTotal +import app.aaps.core.interfaces.insulin.ConcentrationHelper import app.aaps.core.interfaces.profile.EffectiveProfile import app.aaps.core.interfaces.profile.Profile +import app.aaps.core.interfaces.pump.PumpRate import app.aaps.core.interfaces.resources.ResourceHelper import app.aaps.core.interfaces.utils.DateUtil import kotlin.math.ceil @@ -26,6 +28,9 @@ val EB.plannedRemainingMinutes: Int fun EB.toStringFull(dateUtil: DateUtil, rh:ResourceHelper): String = rh.gs(app.aaps.core.ui.R.string.extended_bolus_full, rate, dateUtil.timeString(timestamp), getPassedDurationToTimeInMinutes(dateUtil.now()), T.msecs(duration).mins()) +fun EB.toStringFull(dateUtil: DateUtil, ch: ConcentrationHelper): String = + "${ch.basalRateString(PumpRate(rate), true)} ${dateUtil.timeString(timestamp)} ${getPassedDurationToTimeInMinutes(dateUtil.now())}/${T.msecs(duration).mins()}" + fun EB.toStringMedium(dateUtil: DateUtil, rh:ResourceHelper): String = rh.gs(app.aaps.core.ui.R.string.extended_bolus_medium, rate, getPassedDurationToTimeInMinutes(dateUtil.now()), T.msecs(duration).mins()) diff --git a/core/objects/src/main/kotlin/app/aaps/core/objects/extensions/TemporaryBasalExtension.kt b/core/objects/src/main/kotlin/app/aaps/core/objects/extensions/TemporaryBasalExtension.kt index 7573631ec57..b6d9fd951ad 100644 --- a/core/objects/src/main/kotlin/app/aaps/core/objects/extensions/TemporaryBasalExtension.kt +++ b/core/objects/src/main/kotlin/app/aaps/core/objects/extensions/TemporaryBasalExtension.kt @@ -6,8 +6,10 @@ import app.aaps.core.data.model.TB import app.aaps.core.data.time.T import app.aaps.core.interfaces.aps.AutosensResult import app.aaps.core.interfaces.aps.IobTotal +import app.aaps.core.interfaces.insulin.ConcentrationHelper import app.aaps.core.interfaces.profile.EffectiveProfile import app.aaps.core.interfaces.profile.Profile +import app.aaps.core.interfaces.pump.PumpRate import app.aaps.core.interfaces.resources.ResourceHelper import app.aaps.core.interfaces.utils.DateUtil import kotlin.math.ceil @@ -52,6 +54,24 @@ fun TB.toStringFull(profile: Profile, dateUtil: DateUtil, rh: ResourceHelper): S } } +fun TB.toStringFull(profile: Profile, dateUtil: DateUtil, ch: ConcentrationHelper): String { + val timeAndDuration = "${dateUtil.timeString(timestamp)} ${getPassedDurationToTimeInMinutes(dateUtil.now())}/${durationInMinutes}'" + + return when { + type == TB.Type.FAKE_EXTENDED -> { + "${ch.basalRateString(PumpRate(rate), true)} (${netExtendedRate(profile)}E) $timeAndDuration" + } + + isAbsolute -> { + "${ch.basalRateString(PumpRate(rate), true)} $timeAndDuration" + } + + else -> { // percent + "${ch.basalRateString(PumpRate(rate), false)} $timeAndDuration" + } + } +} + fun TB.toStringShort(rh: ResourceHelper): String = if (isAbsolute || type == TB.Type.FAKE_EXTENDED) rh.gs(app.aaps.core.ui.R.string.pump_base_basal_rate, rate) else rh.gs(app.aaps.core.ui.R.string.formatPercent, rate) diff --git a/core/ui/src/main/res/values/strings.xml b/core/ui/src/main/res/values/strings.xml index 95d0e19c185..31a5c37084f 100644 --- a/core/ui/src/main/res/values/strings.xml +++ b/core/ui/src/main/res/values/strings.xml @@ -724,6 +724,7 @@ Clicked connect to pump %1$.0f / %2$d U Daily units + Max daily units Pump icon View profile Pump history @@ -747,6 +748,7 @@ Firmware Bolus speed History + Over %1$s left Limiting max basal rate to %1$.2f U/h because of %2$s diff --git a/implementation/src/main/kotlin/app/aaps/implementation/insulin/ConcentrationHelperImpl.kt b/implementation/src/main/kotlin/app/aaps/implementation/insulin/ConcentrationHelperImpl.kt index 935141660c0..f6cf6634310 100644 --- a/implementation/src/main/kotlin/app/aaps/implementation/insulin/ConcentrationHelperImpl.kt +++ b/implementation/src/main/kotlin/app/aaps/implementation/insulin/ConcentrationHelperImpl.kt @@ -7,6 +7,7 @@ import app.aaps.core.interfaces.plugin.ActivePlugin import app.aaps.core.interfaces.pump.PumpInsulin import app.aaps.core.interfaces.pump.PumpRate import app.aaps.core.interfaces.resources.ResourceHelper +import app.aaps.core.interfaces.utils.DateUtil import app.aaps.core.interfaces.utils.DecimalFormatter import app.aaps.implementation.R import javax.inject.Inject @@ -18,7 +19,8 @@ class ConcentrationHelperImpl @Inject constructor( private val activePlugin: ActivePlugin, private val insulin: Insulin, private val rh: ResourceHelper, - private val decimalFormatter: DecimalFormatter + private val decimalFormatter: DecimalFormatter, + private val dateUtil: DateUtil ) : ConcentrationHelper { override fun isU100(): Boolean = concentration == 1.0 @@ -51,6 +53,12 @@ class ConcentrationHelperImpl @Inject constructor( } override fun insulinAmountAgoString(amount: PumpInsulin, ago: String): String = "${insulinAmountString(amount)} $ago" + override fun insulinAmountAgoString(amount: PumpInsulin, lastBolusTime: Long): String? { + val agoHours = (System.currentTimeMillis() - lastBolusTime).toDouble() / 3_600_000.0 + return if (agoHours < 6.0) { + "${insulinAmountString(amount)} ${dateUtil.sinceString(lastBolusTime, rh)}" + } else null + } override fun insulinConcentrationString(): String = rh.gs(R.string.insulin_concentration, (concentration * 100).toInt()) diff --git a/pump/combov2/src/main/kotlin/info/nightscout/pump/combov2/compose/ComboV2OverviewViewModel.kt b/pump/combov2/src/main/kotlin/info/nightscout/pump/combov2/compose/ComboV2OverviewViewModel.kt index acb3619d9b5..2403524f27a 100644 --- a/pump/combov2/src/main/kotlin/info/nightscout/pump/combov2/compose/ComboV2OverviewViewModel.kt +++ b/pump/combov2/src/main/kotlin/info/nightscout/pump/combov2/compose/ComboV2OverviewViewModel.kt @@ -6,8 +6,10 @@ import androidx.compose.material.icons.filled.Bluetooth import androidx.compose.material.icons.filled.BluetoothDisabled import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope +import app.aaps.core.interfaces.insulin.ConcentrationHelper import app.aaps.core.interfaces.logging.AAPSLogger import app.aaps.core.interfaces.logging.LTag +import app.aaps.core.interfaces.pump.PumpInsulin import app.aaps.core.interfaces.queue.CommandQueue import app.aaps.core.interfaces.resources.ResourceHelper import app.aaps.core.interfaces.rx.bus.RxBus @@ -42,6 +44,7 @@ import kotlin.math.max import kotlin.time.ExperimentalTime import info.nightscout.comboctl.base.Tbr as ComboCtlTbr import info.nightscout.comboctl.main.Pump as ComboCtlPump +import app.aaps.core.ui.R as CoreUiR sealed class ComboV2OverviewEvent { data object StartPairWizard : ComboV2OverviewEvent() @@ -62,6 +65,7 @@ class ComboV2OverviewViewModel @Inject constructor( rxBus: RxBus, private val commandQueue: CommandQueue, private val combov2Plugin: ComboV2Plugin, + private val ch: ConcentrationHelper, @ApplicationContext context: Context ) : ViewModel() { @@ -134,7 +138,7 @@ class ComboV2OverviewViewModel @Inject constructor( fun onRefreshClick() { aapsLogger.debug(LTag.PUMP, "Refresh button clicked") combov2Plugin.clearPumpErrorObservedFlag() - commandQueue.readStatus(rh.gs(app.aaps.core.ui.R.string.user_request), null) + commandQueue.readStatus(rh.gs(CoreUiR.string.user_request), null) } fun onPairClick() { @@ -153,14 +157,14 @@ class ComboV2OverviewViewModel @Inject constructor( private fun managementActions(isPaired: Boolean): List = listOf( if (isPaired) { PumpAction( - label = rh.gs(app.aaps.core.ui.R.string.pump_unpair), + label = rh.gs(CoreUiR.string.pump_unpair), icon = Icons.Filled.BluetoothDisabled, category = ActionCategory.MANAGEMENT, onClick = { onUnpairClick() } ) } else { PumpAction( - label = rh.gs(app.aaps.core.ui.R.string.pairing), + label = rh.gs(CoreUiR.string.pairing), icon = Icons.Filled.Bluetooth, category = ActionCategory.MANAGEMENT, onClick = { onPairClick() } @@ -207,15 +211,15 @@ class ComboV2OverviewViewModel @Inject constructor( snapshot.baseBasalRate?.let { add( PumpInfoRow( - label = rh.gs(app.aaps.core.ui.R.string.base_basal_rate_label), - value = rh.gs(app.aaps.core.ui.R.string.pump_base_basal_rate, it) + label = rh.gs(CoreUiR.string.base_basal_rate_label), + value = rh.gs(CoreUiR.string.pump_base_basal_rate, it) ) ) } if (snapshot.serialNumber.isNotEmpty()) { add( PumpInfoRow( - label = rh.gs(app.aaps.core.ui.R.string.serial_number), + label = rh.gs(CoreUiR.string.serial_number), value = snapshot.serialNumber ) ) @@ -240,8 +244,8 @@ class ComboV2OverviewViewModel @Inject constructor( val primaryActions = listOf( PumpAction( - label = rh.gs(app.aaps.core.ui.R.string.refresh), - iconRes = app.aaps.core.ui.R.drawable.ic_refresh, + label = rh.gs(CoreUiR.string.refresh), + iconRes = CoreUiR.drawable.ic_refresh, category = ActionCategory.PRIMARY, enabled = refreshEnabled, onClick = { onRefreshClick() } @@ -264,12 +268,12 @@ class ComboV2OverviewViewModel @Inject constructor( private fun driverStateText(state: ComboV2Plugin.DriverState): String = when (state) { ComboV2Plugin.DriverState.NotInitialized -> rh.gs(R.string.combov2_not_initialized) - ComboV2Plugin.DriverState.Disconnected -> rh.gs(app.aaps.core.ui.R.string.disconnected) - ComboV2Plugin.DriverState.Connecting -> rh.gs(app.aaps.core.ui.R.string.connecting) + ComboV2Plugin.DriverState.Disconnected -> rh.gs(CoreUiR.string.disconnected) + ComboV2Plugin.DriverState.Connecting -> rh.gs(CoreUiR.string.connecting) ComboV2Plugin.DriverState.CheckingPump -> rh.gs(R.string.combov2_checking_pump) ComboV2Plugin.DriverState.Ready -> rh.gs(R.string.combov2_ready) ComboV2Plugin.DriverState.Suspended -> rh.gs(R.string.combov2_suspended) - ComboV2Plugin.DriverState.Error -> rh.gs(app.aaps.core.ui.R.string.error) + ComboV2Plugin.DriverState.Error -> rh.gs(CoreUiR.string.error) is ComboV2Plugin.DriverState.ExecutingCommand -> when (val desc = state.description) { is ComboCtlPump.GettingBasalProfileCommandDesc -> @@ -309,7 +313,7 @@ class ComboV2OverviewViewModel @Inject constructor( else -> rh.gs(R.string.combov2_no_connection_for_n_mins, secondsPassed / 60) to StatusLevel.CRITICAL } return PumpInfoRow( - label = rh.gs(app.aaps.core.ui.R.string.last_connection_label), + label = rh.gs(CoreUiR.string.last_connection_label), value = text, level = level ) @@ -323,7 +327,7 @@ class ComboV2OverviewViewModel @Inject constructor( BatteryState.FULL_BATTERY -> rh.gs(R.string.combov2_battery_full) to StatusLevel.NORMAL } return PumpInfoRow( - label = rh.gs(app.aaps.core.ui.R.string.battery_label), + label = rh.gs(CoreUiR.string.battery_label), value = text, level = level ) @@ -337,8 +341,8 @@ class ComboV2OverviewViewModel @Inject constructor( ReservoirState.FULL -> StatusLevel.NORMAL } return PumpInfoRow( - label = rh.gs(app.aaps.core.ui.R.string.reservoir_label), - value = "${reservoirLevel.availableUnits} ${rh.gs(app.aaps.core.ui.R.string.insulin_unit_shortname)}", + label = rh.gs(CoreUiR.string.reservoir_label), + value = ch.insulinAmountString(PumpInsulin(reservoirLevel.availableUnits.toDouble())), level = level ) } @@ -346,21 +350,16 @@ class ComboV2OverviewViewModel @Inject constructor( @OptIn(ExperimentalTime::class) private fun lastBolusRow(lastBolus: ComboCtlPump.LastBolus?): PumpInfoRow? { if (lastBolus == null) return null - val secondsPassed = (System.currentTimeMillis() - lastBolus.timestamp.toEpochMilliseconds()) / 1000 - val bolusAgoText = when (secondsPassed) { - in 0..59 -> rh.gs(R.string.combov2_less_than_one_minute_ago) - else -> rh.gs(app.aaps.core.interfaces.R.string.minago, secondsPassed / 60) - } - val text = rh.gs( - R.string.combov2_last_bolus, - lastBolus.bolusAmount.cctlBolusToIU(), - rh.gs(app.aaps.core.ui.R.string.insulin_unit_shortname), - bolusAgoText - ) - return PumpInfoRow( - label = rh.gs(app.aaps.core.ui.R.string.last_bolus_label), - value = text + val text = ch.insulinAmountAgoString( + PumpInsulin(lastBolus.bolusAmount.cctlBolusToIU()), + lastBolus.timestamp.toEpochMilliseconds() ) + return text?.let { + PumpInfoRow( + label = rh.gs(CoreUiR.string.last_bolus_label), + value = it + ) + } } @OptIn(ExperimentalTime::class) @@ -375,7 +374,7 @@ class ComboV2OverviewViewModel @Inject constructor( else rh.gs(R.string.combov2_current_tbr_less_than_1min, currentTbr.percentage) return PumpInfoRow( - label = rh.gs(app.aaps.core.ui.R.string.tempbasal_label), + label = rh.gs(CoreUiR.string.tempbasal_label), value = text ) } diff --git a/pump/dana/src/main/kotlin/app/aaps/pump/dana/DanaPump.kt b/pump/dana/src/main/kotlin/app/aaps/pump/dana/DanaPump.kt index 4e6d8d7f343..9c67dc687e4 100644 --- a/pump/dana/src/main/kotlin/app/aaps/pump/dana/DanaPump.kt +++ b/pump/dana/src/main/kotlin/app/aaps/pump/dana/DanaPump.kt @@ -210,11 +210,11 @@ class DanaPump @Inject constructor( extendedBolusDuration = 0L extendedBolusAmount = 0.0 } - private val extendedBolusPassedMinutes: Int + val extendedBolusPassedMinutes: Int get() = T.msecs(max(0, dateUtil.now() - extendedBolusStart)).mins().toInt() val extendedBolusRemainingMinutes: Int get() = max(T.msecs(extendedBolusStart + extendedBolusDuration - dateUtil.now()).mins().toInt(), 0) - private val extendedBolusDurationInMinutes: Int + val extendedBolusDurationInMinutes: Int get() = T.msecs(extendedBolusDuration).mins().toInt() var extendedBolusAbsoluteRate: Double get() = extendedBolusAmount * T.hours(1).msecs() / extendedBolusDuration diff --git a/pump/dana/src/main/kotlin/app/aaps/pump/dana/compose/DanaOverviewViewModel.kt b/pump/dana/src/main/kotlin/app/aaps/pump/dana/compose/DanaOverviewViewModel.kt index cfbb68e41c7..274b9f9f10b 100644 --- a/pump/dana/src/main/kotlin/app/aaps/pump/dana/compose/DanaOverviewViewModel.kt +++ b/pump/dana/src/main/kotlin/app/aaps/pump/dana/compose/DanaOverviewViewModel.kt @@ -19,6 +19,7 @@ import app.aaps.core.interfaces.logging.LTag import app.aaps.core.interfaces.logging.UserEntryLogger import app.aaps.core.interfaces.plugin.ActivePlugin import app.aaps.core.interfaces.pump.PumpInsulin +import app.aaps.core.interfaces.pump.PumpRate import app.aaps.core.interfaces.queue.CommandQueue import app.aaps.core.interfaces.resources.ResourceHelper import app.aaps.core.interfaces.rx.AapsSchedulers @@ -53,6 +54,7 @@ import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.stateIn import javax.inject.Inject +import app.aaps.core.ui.R as CoreUiR sealed class DanaOverviewEvent { data object StartPairWizard : DanaOverviewEvent() @@ -148,7 +150,7 @@ open class DanaOverviewViewModel @Inject constructor( fun onRefreshClick() { aapsLogger.debug(LTag.PUMP, "Clicked connect to pump") danaPump.reset() - commandQueue.readStatus(rh.gs(app.aaps.core.ui.R.string.clicked_connect_to_pump), null) + commandQueue.readStatus(rh.gs(CoreUiR.string.clicked_connect_to_pump), null) } fun onHistoryClick() { @@ -199,7 +201,7 @@ open class DanaOverviewViewModel @Inject constructor( if (isConfigured) { add( PumpAction( - label = rh.gs(app.aaps.core.ui.R.string.pump_unpair), + label = rh.gs(CoreUiR.string.pump_unpair), icon = Icons.Filled.Bluetooth, category = ActionCategory.MANAGEMENT, onClick = { onUnpairClick() } @@ -208,7 +210,7 @@ open class DanaOverviewViewModel @Inject constructor( } else { add( PumpAction( - label = rh.gs(app.aaps.core.ui.R.string.pairing), + label = rh.gs(CoreUiR.string.pairing), icon = Icons.Filled.Bluetooth, category = ActionCategory.MANAGEMENT, onClick = { onPairClick() } @@ -247,31 +249,28 @@ open class DanaOverviewViewModel @Inject constructor( // Last bolus val lastBolus = if (lastBolusTime != null && lastBolusAmount != null) { - val agoHours = (System.currentTimeMillis() - lastBolusTime).toDouble() / 3_600_000.0 - if (agoHours < 6.0) { - ch.insulinAmountAgoString( - PumpInsulin(lastBolusAmount), - dateUtil.sinceString(lastBolusTime, rh) - ) - } else null + ch.insulinAmountAgoString( + PumpInsulin(lastBolusAmount), + lastBolusTime + ) } else null // Base basal rate val baseBasalRate = "( ${pump.activeProfile + 1} ) " + - rh.gs(app.aaps.core.ui.R.string.pump_base_basal_rate, activePump.baseBasalRate.cU) + ch.basalRateString(activePump.baseBasalRate, true) // Temp basal val tempBasalText = pump.temporaryBasalToString() // Extended bolus - val extendedBolusText = pump.extendedBolusToString() + val extendedBolusText = extendedBolusToString() // Battery val batteryText = battery?.let { "${it}%" } // Reservoir val reservoirText = if (reservoir > 0.0) - rh.gs(app.aaps.core.ui.R.string.reservoir_value, reservoir, 300) + "${ch.insulinAmountString(PumpInsulin(reservoir))}" // "/ 300 U" removed else null // Last connection warn level @@ -294,8 +293,8 @@ open class DanaOverviewViewModel @Inject constructor( // Reservoir warn level val reservoirLevel = when { - reservoir <= 20.0 -> StatusLevel.CRITICAL - reservoir <= 50.0 -> StatusLevel.WARNING + ch.fromPump(PumpInsulin(reservoir)) <= 20.0 -> StatusLevel.CRITICAL + ch.fromPump(PumpInsulin(reservoir)) <= 50.0 -> StatusLevel.WARNING else -> StatusLevel.NORMAL } @@ -306,29 +305,29 @@ open class DanaOverviewViewModel @Inject constructor( val infoRows = if (!isConfigured) emptyList() else buildList { // 1. Serial number pump.serialNumber.takeIf { it.isNotEmpty() }?.let { - add(PumpInfoRow(label = rh.gs(app.aaps.core.ui.R.string.serial_number), value = it)) + add(PumpInfoRow(label = rh.gs(CoreUiR.string.serial_number), value = it)) } // 2. Battery batteryText?.let { - add(PumpInfoRow(label = rh.gs(app.aaps.core.ui.R.string.battery_label), value = it, level = batteryLevel)) + add(PumpInfoRow(label = rh.gs(CoreUiR.string.battery_label), value = it, level = batteryLevel)) } // 3. Last connection if (lastConnection.isNotEmpty()) { - add(PumpInfoRow(label = rh.gs(app.aaps.core.ui.R.string.last_connection_label), value = lastConnection, level = lastConnectionLevel)) + add(PumpInfoRow(label = rh.gs(CoreUiR.string.last_connection_label), value = lastConnection, level = lastConnectionLevel)) } // 4. Last bolus lastBolus?.let { - add(PumpInfoRow(label = rh.gs(app.aaps.core.ui.R.string.last_bolus_label), value = it)) + add(PumpInfoRow(label = rh.gs(CoreUiR.string.last_bolus_label), value = it)) } // 5. Daily units add( PumpInfoRow( - label = rh.gs(app.aaps.core.ui.R.string.daily_units), - value = rh.gs(app.aaps.core.ui.R.string.reservoir_value, pump.dailyTotalUnits, pump.maxDailyTotalUnits), + label = rh.gs(CoreUiR.string.daily_units), + value = ch.insulinAmountString(PumpInsulin(pump.dailyTotalUnits)), // "/ ${pump.maxDailyTotalUnits} U" removed level = when { pump.dailyTotalUnits > pump.maxDailyTotalUnits * 0.9 -> StatusLevel.CRITICAL pump.dailyTotalUnits > pump.maxDailyTotalUnits * 0.75 -> StatusLevel.WARNING @@ -336,19 +335,25 @@ open class DanaOverviewViewModel @Inject constructor( } ) ) + add( + PumpInfoRow( + label = rh.gs(CoreUiR.string.max_daily_units), + value = ch.insulinAmountString(PumpInsulin(pump.maxDailyTotalUnits.toDouble())) // max TDD added in an additional row + ) + ) // 6. Base basal rate - add(PumpInfoRow(label = rh.gs(app.aaps.core.ui.R.string.base_basal_rate_label), value = baseBasalRate)) + add(PumpInfoRow(label = rh.gs(CoreUiR.string.base_basal_rate_label), value = baseBasalRate)) // 7. Temp basal (hidden when empty) - add(PumpInfoRow(label = rh.gs(app.aaps.core.ui.R.string.tempbasal_label), value = tempBasalText, visible = tempBasalText.isNotEmpty())) + add(PumpInfoRow(label = rh.gs(CoreUiR.string.tempbasal_label), value = tempBasalText, visible = tempBasalText.isNotEmpty())) // 8. Extended bolus (hidden when empty) - add(PumpInfoRow(label = rh.gs(app.aaps.core.ui.R.string.extended_bolus_label), value = extendedBolusText, visible = extendedBolusText.isNotEmpty())) + add(PumpInfoRow(label = rh.gs(CoreUiR.string.extended_bolus_label), value = extendedBolusText, visible = extendedBolusText.isNotEmpty())) // 9. Reservoir reservoirText?.let { - add(PumpInfoRow(label = rh.gs(app.aaps.core.ui.R.string.reservoir_label), value = it, level = reservoirLevel)) + add(PumpInfoRow(label = rh.gs(CoreUiR.string.reservoir_label), value = it, level = reservoirLevel)) } // 10. Basal/bolus step @@ -358,7 +363,7 @@ open class DanaOverviewViewModel @Inject constructor( if (pump.hwModel != 0) { add( PumpInfoRow( - label = rh.gs(app.aaps.core.ui.R.string.firmware), + label = rh.gs(CoreUiR.string.firmware), value = rh.gs(R.string.dana_model, pump.modelFriendlyName(), pump.hwModel, pump.protocol, pump.productCode) ) ) @@ -368,14 +373,14 @@ open class DanaOverviewViewModel @Inject constructor( // Actions val primaryActions = listOf( PumpAction( - label = rh.gs(app.aaps.core.ui.R.string.refresh), - iconRes = app.aaps.core.ui.R.drawable.ic_refresh, + label = rh.gs(CoreUiR.string.refresh), + iconRes = CoreUiR.drawable.ic_refresh, category = ActionCategory.PRIMARY, visible = isInitialized, onClick = { onRefreshClick() } ), PumpAction( - label = rh.gs(app.aaps.core.ui.R.string.pump_history), + label = rh.gs(CoreUiR.string.pump_history), icon = Icons.AutoMirrored.Filled.List, category = ActionCategory.PRIMARY, visible = isInitialized, @@ -393,4 +398,13 @@ open class DanaOverviewViewModel @Inject constructor( managementActions = managementActions ) } + + fun extendedBolusToString(): String { + val pump = danaPump + if (!pump.isExtendedInProgress) return "" + + return "E " + ch.basalRateString(PumpRate(pump.extendedBolusAbsoluteRate), true) + " @" + + dateUtil.timeString(pump.extendedBolusStart) + + " " + pump.extendedBolusPassedMinutes + "/" + pump.extendedBolusDurationInMinutes + "'" + } } diff --git a/pump/diaconn/src/main/kotlin/app/aaps/pump/diaconn/compose/DiaconnOverviewViewModel.kt b/pump/diaconn/src/main/kotlin/app/aaps/pump/diaconn/compose/DiaconnOverviewViewModel.kt index babb429798d..3f7f5f56330 100644 --- a/pump/diaconn/src/main/kotlin/app/aaps/pump/diaconn/compose/DiaconnOverviewViewModel.kt +++ b/pump/diaconn/src/main/kotlin/app/aaps/pump/diaconn/compose/DiaconnOverviewViewModel.kt @@ -58,6 +58,7 @@ import kotlinx.coroutines.flow.stateIn import javax.inject.Inject import kotlin.math.min import kotlin.math.roundToInt +import app.aaps.core.ui.R as CoreUiR sealed class DiaconnOverviewEvent { data object StartPairWizard : DiaconnOverviewEvent() @@ -151,7 +152,7 @@ class DiaconnOverviewViewModel @Inject constructor( fun onRefreshClick() { aapsLogger.debug(LTag.PUMP, "Clicked connect to pump") diaconnG8Pump.lastConnection = 0 - commandQueue.readStatus(rh.gs(app.aaps.core.ui.R.string.clicked_connect_to_pump), null) + commandQueue.readStatus(rh.gs(CoreUiR.string.clicked_connect_to_pump), null) } fun onHistoryClick() = _events.tryEmit(DiaconnOverviewEvent.StartHistory) @@ -216,10 +217,7 @@ class DiaconnOverviewViewModel @Inject constructor( // Last bolus val lastBolus = if (lastBolusTime != null && lastBolusAmount != null) { - val agoHours = (System.currentTimeMillis() - lastBolusTime).toDouble() / 3_600_000.0 - if (agoHours < 6.0) { - ch.insulinAmountAgoString(PumpInsulin(lastBolusAmount), dateUtil.sinceString(lastBolusTime, rh)) - } else null + ch.insulinAmountAgoString(PumpInsulin(lastBolusAmount), lastBolusTime) } else null // Daily units @@ -267,24 +265,24 @@ class DiaconnOverviewViewModel @Inject constructor( // Info rows val infoRows = if (!isConfigured) emptyList() else buildList { - add(PumpInfoRow(label = rh.gs(app.aaps.core.ui.R.string.serial_number), value = pump.serialNo.toString())) + add(PumpInfoRow(label = rh.gs(CoreUiR.string.serial_number), value = pump.serialNo.toString())) batteryText?.let { - add(PumpInfoRow(label = rh.gs(app.aaps.core.ui.R.string.battery_label), value = it, level = batteryLevel)) + add(PumpInfoRow(label = rh.gs(CoreUiR.string.battery_label), value = it, level = batteryLevel)) } if (lastConnection.isNotEmpty()) { - add(PumpInfoRow(label = rh.gs(app.aaps.core.ui.R.string.last_connection_label), value = lastConnection, level = lastConnectionLevel)) + add(PumpInfoRow(label = rh.gs(CoreUiR.string.last_connection_label), value = lastConnection, level = lastConnectionLevel)) } lastBolus?.let { - add(PumpInfoRow(label = rh.gs(app.aaps.core.ui.R.string.last_bolus_label), value = it)) + add(PumpInfoRow(label = rh.gs(CoreUiR.string.last_bolus_label), value = it)) } add( PumpInfoRow( - label = rh.gs(app.aaps.core.ui.R.string.daily_units), - value = rh.gs(app.aaps.core.ui.R.string.reservoir_value, todayInsulinAmount, todayInsulinLimitAmount), + label = rh.gs(CoreUiR.string.daily_units), + value = ch.insulinAmountString(PumpInsulin(todayInsulinAmount)), // "/ $todayInsulinLimitAmount U" removed level = when { todayInsulinAmount > todayInsulinLimitAmount * 0.9 -> StatusLevel.CRITICAL todayInsulinAmount > todayInsulinLimitAmount * 0.75 -> StatusLevel.WARNING @@ -292,11 +290,17 @@ class DiaconnOverviewViewModel @Inject constructor( } ) ) + add( + PumpInfoRow( + label = rh.gs(CoreUiR.string.max_daily_units), + value = ch.insulinAmountString(PumpInsulin(todayInsulinLimitAmount.toDouble())) + ) + ) - add(PumpInfoRow(label = rh.gs(app.aaps.core.ui.R.string.base_basal_rate_label), value = baseBasalRate)) - add(PumpInfoRow(label = rh.gs(app.aaps.core.ui.R.string.tempbasal_label), value = tempBasalText, visible = tempBasalText.isNotEmpty())) - add(PumpInfoRow(label = rh.gs(app.aaps.core.ui.R.string.extended_bolus_label), value = extendedBolusText, visible = extendedBolusText.isNotEmpty())) - add(PumpInfoRow(label = rh.gs(app.aaps.core.ui.R.string.reservoir_label), value = reservoirText, level = reservoirLevel)) + add(PumpInfoRow(label = rh.gs(CoreUiR.string.base_basal_rate_label), value = baseBasalRate)) + add(PumpInfoRow(label = rh.gs(CoreUiR.string.tempbasal_label), value = tempBasalText, visible = tempBasalText.isNotEmpty())) + add(PumpInfoRow(label = rh.gs(CoreUiR.string.extended_bolus_label), value = extendedBolusText, visible = extendedBolusText.isNotEmpty())) + add(PumpInfoRow(label = rh.gs(CoreUiR.string.reservoir_label), value = reservoirText, level = reservoirLevel)) add(PumpInfoRow(label = rh.gs(R.string.basal_step) + " / " + rh.gs(R.string.bolus_step), value = "${ch.fromPump(PumpInsulin(pump.basalStep))} / ${ch.fromPump(PumpInsulin(pump.bolusStep))}")) // Firmware @@ -305,20 +309,20 @@ class DiaconnOverviewViewModel @Inject constructor( "\nCountry: ${pump.country}" + "\nProductType: ${pump.productType}" + "\nManufacture: ${pump.makeYear}.${pump.makeMonth}.${pump.makeDay}" - add(PumpInfoRow(label = rh.gs(app.aaps.core.ui.R.string.firmware), value = firmware)) + add(PumpInfoRow(label = rh.gs(CoreUiR.string.firmware), value = firmware)) } // Actions val primaryActions = listOf( PumpAction( - label = rh.gs(app.aaps.core.ui.R.string.refresh), - iconRes = app.aaps.core.ui.R.drawable.ic_refresh, + label = rh.gs(CoreUiR.string.refresh), + iconRes = CoreUiR.drawable.ic_refresh, category = ActionCategory.PRIMARY, visible = isInitialized, onClick = { onRefreshClick() } ), PumpAction( - label = rh.gs(app.aaps.core.ui.R.string.pump_history), + label = rh.gs(CoreUiR.string.pump_history), icon = Icons.AutoMirrored.Filled.List, category = ActionCategory.PRIMARY, visible = isInitialized, @@ -340,7 +344,7 @@ class DiaconnOverviewViewModel @Inject constructor( if (isConfigured) { add( PumpAction( - label = rh.gs(app.aaps.core.ui.R.string.pump_unpair), + label = rh.gs(CoreUiR.string.pump_unpair), icon = Icons.Filled.Bluetooth, category = ActionCategory.MANAGEMENT, onClick = { onUnpairClick() } @@ -349,7 +353,7 @@ class DiaconnOverviewViewModel @Inject constructor( } else { add( PumpAction( - label = rh.gs(app.aaps.core.ui.R.string.pump_pair), + label = rh.gs(CoreUiR.string.pump_pair), icon = Icons.Filled.Bluetooth, category = ActionCategory.MANAGEMENT, onClick = { onPairClick() } diff --git a/pump/eopatch/src/main/kotlin/app/aaps/pump/eopatch/compose/EopatchOverviewViewModel.kt b/pump/eopatch/src/main/kotlin/app/aaps/pump/eopatch/compose/EopatchOverviewViewModel.kt index 260c816dff1..f8e38c1a8d1 100644 --- a/pump/eopatch/src/main/kotlin/app/aaps/pump/eopatch/compose/EopatchOverviewViewModel.kt +++ b/pump/eopatch/src/main/kotlin/app/aaps/pump/eopatch/compose/EopatchOverviewViewModel.kt @@ -6,7 +6,9 @@ import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import app.aaps.core.data.pump.defs.PumpType import app.aaps.core.data.time.T +import app.aaps.core.interfaces.insulin.ConcentrationHelper import app.aaps.core.interfaces.profile.ProfileFunction +import app.aaps.core.interfaces.pump.PumpInsulin import app.aaps.core.interfaces.pump.PumpRate import app.aaps.core.interfaces.pump.PumpSync import app.aaps.core.interfaces.queue.CommandQueue @@ -14,6 +16,7 @@ import app.aaps.core.interfaces.resources.ResourceHelper import app.aaps.core.interfaces.rx.AapsSchedulers import app.aaps.core.interfaces.rx.bus.RxBus import app.aaps.core.interfaces.utils.DateUtil +import app.aaps.core.ui.R as CoreUiR import app.aaps.core.ui.compose.StatusLevel import app.aaps.core.ui.compose.pump.ActionCategory import app.aaps.core.ui.compose.pump.PumpAction @@ -81,6 +84,7 @@ class EopatchOverviewViewModel @Inject constructor( private val pumpSync: PumpSync, private val commandQueue: CommandQueue, private val rxBus: RxBus, + private val ch: ConcentrationHelper, @ApplicationContext private val context: Context ) : ViewModel() { @@ -261,8 +265,8 @@ class EopatchOverviewViewModel @Inject constructor( // Connection state — only show when not connected (error states shown in banner) if (connState != BleConnectionState.CONNECTED) { val connText = when (connState) { - BleConnectionState.DISCONNECTED -> rh.gs(app.aaps.core.ui.R.string.disconnected) - else -> rh.gs(app.aaps.core.ui.R.string.connecting) + BleConnectionState.DISCONNECTED -> rh.gs(CoreUiR.string.disconnected) + else -> rh.gs(CoreUiR.string.connecting) } add(PumpInfoRow(label = rh.gs(R.string.eopatch_ble_status), value = connText)) } @@ -274,34 +278,34 @@ class EopatchOverviewViewModel @Inject constructor( val remainTimeMillis = max(finishTimeMillis - System.currentTimeMillis(), 0L) val h = TimeUnit.MILLISECONDS.toHours(remainTimeMillis) val m = TimeUnit.MILLISECONDS.toMinutes(remainTimeMillis - TimeUnit.HOURS.toMillis(h)) - "${rh.gs(app.aaps.core.ui.R.string.pumpsuspended)}\n${rh.gs(R.string.string_temp_basal_remained_hhmm, h.toString(), m.toString())}" + "${rh.gs(CoreUiR.string.pumpsuspended)}\n${rh.gs(R.string.string_temp_basal_remained_hhmm, h.toString(), m.toString())}" } else { rh.gs(R.string.string_running) } - add(PumpInfoRow(label = rh.gs(app.aaps.core.ui.R.string.status), value = statusText)) + add(PumpInfoRow(label = rh.gs(CoreUiR.string.status), value = statusText)) // Basal rate if (preferenceManager.patchState.isNormalBasalRunning) { - val basalRate = rh.gs(app.aaps.core.ui.R.string.pump_base_basal_rate, normalBasalManager.normalBasal.currentSegmentDoseUnitPerHour) + val basalRate = ch.basalRateString(PumpRate(normalBasalManager.normalBasal.currentSegmentDoseUnitPerHour.toDouble()), true) add(PumpInfoRow(label = rh.gs(R.string.eopatch_base_basal_rate), value = basalRate)) } // Temp basal val tempBasal = tempBasalManager.startedBasal if (preferenceManager.patchState.isTempBasalActive && tempBasal != null) { - val tempRate = rh.gs(app.aaps.core.ui.R.string.pump_base_basal_rate, tempBasal.doseUnitPerHour) + val tempRate = ch.basalRateString(PumpRate(tempBasal.doseUnitPerHour.toDouble()), true) add(PumpInfoRow(label = rh.gs(R.string.eopatch_temp_basal_rate), value = tempRate)) } } // Remaining insulin val insulinText = when { - insulin > 50f -> "50+ U" - insulin < 1f -> "0 U" - else -> "${insulin.roundToInt()} U" + insulin > 50f -> rh.gs(CoreUiR.string.overview_reservoir_concentration_value_over, ch.insulinAmountString(PumpInsulin(50.0))) + insulin < 1f -> ch.insulinAmountString(PumpInsulin(0.0)) + else -> ch.insulinAmountString(PumpInsulin(insulin.roundToInt().toDouble())) } if (config.isActivated) { - add(PumpInfoRow(label = rh.gs(app.aaps.core.ui.R.string.reservoir_label), value = insulinText)) + add(PumpInfoRow(label = rh.gs(CoreUiR.string.reservoir_label), value = insulinText)) } // Serial number @@ -311,7 +315,7 @@ class EopatchOverviewViewModel @Inject constructor( // Last state update if (config.isActivated && stateUpdatedTimestamp > 0L) { - add(PumpInfoRow(label = rh.gs(app.aaps.core.ui.R.string.last_connection_label), value = dateUtil.minAgo(rh, stateUpdatedTimestamp))) + add(PumpInfoRow(label = rh.gs(CoreUiR.string.last_connection_label), value = dateUtil.minAgo(rh, stateUpdatedTimestamp))) } } @@ -322,7 +326,7 @@ class EopatchOverviewViewModel @Inject constructor( add( PumpAction( label = rh.gs(R.string.string_activate_patch), - iconRes = app.aaps.core.ui.R.drawable.ic_swap_horiz, + iconRes = CoreUiR.drawable.ic_swap_horiz, category = ActionCategory.PRIMARY, onClick = { onClickActivation() } ) @@ -331,8 +335,8 @@ class EopatchOverviewViewModel @Inject constructor( if (isActivated) { add( PumpAction( - label = if (isPaused) rh.gs(app.aaps.core.ui.R.string.pump_resume) else rh.gs(app.aaps.core.ui.R.string.pump_suspend), - iconRes = if (isPaused) app.aaps.core.ui.R.drawable.ic_loop_resume else app.aaps.core.ui.R.drawable.ic_loop_paused, + label = if (isPaused) rh.gs(CoreUiR.string.pump_resume) else rh.gs(CoreUiR.string.pump_suspend), + iconRes = if (isPaused) CoreUiR.drawable.ic_loop_resume else CoreUiR.drawable.ic_loop_paused, category = ActionCategory.PRIMARY, onClick = { } // Click handled in screen composable (needs dialog) ) @@ -345,7 +349,7 @@ class EopatchOverviewViewModel @Inject constructor( add( PumpAction( label = rh.gs(R.string.string_discard_patch), - iconRes = app.aaps.core.ui.R.drawable.ic_swap_horiz, + iconRes = CoreUiR.drawable.ic_swap_horiz, category = ActionCategory.MANAGEMENT, onClick = { onClickDeactivation() } ) @@ -364,9 +368,9 @@ class EopatchOverviewViewModel @Inject constructor( private fun buildStatusBanner(connState: BleConnectionState, isActivated: Boolean, isPaused: Boolean): StatusBanner? = when { !isActivated -> StatusBanner(text = rh.gs(R.string.eopatch_not_activated), level = StatusLevel.WARNING) - isPaused -> StatusBanner(text = rh.gs(app.aaps.core.ui.R.string.pumpsuspended), level = StatusLevel.WARNING) - connState == BleConnectionState.DISCONNECTED -> StatusBanner(text = rh.gs(app.aaps.core.ui.R.string.disconnected), level = StatusLevel.CRITICAL) - connState != BleConnectionState.CONNECTED -> StatusBanner(text = rh.gs(app.aaps.core.ui.R.string.connecting), level = StatusLevel.UNSPECIFIED) + isPaused -> StatusBanner(text = rh.gs(CoreUiR.string.pumpsuspended), level = StatusLevel.WARNING) + connState == BleConnectionState.DISCONNECTED -> StatusBanner(text = rh.gs(CoreUiR.string.disconnected), level = StatusLevel.CRITICAL) + connState != BleConnectionState.CONNECTED -> StatusBanner(text = rh.gs(CoreUiR.string.connecting), level = StatusLevel.UNSPECIFIED) else -> null // Connected, activated, running — no banner needed } } diff --git a/pump/equil/src/main/kotlin/app/aaps/pump/equil/compose/EquilOverviewViewModel.kt b/pump/equil/src/main/kotlin/app/aaps/pump/equil/compose/EquilOverviewViewModel.kt index 0716cd68492..513f95fc3e5 100644 --- a/pump/equil/src/main/kotlin/app/aaps/pump/equil/compose/EquilOverviewViewModel.kt +++ b/pump/equil/src/main/kotlin/app/aaps/pump/equil/compose/EquilOverviewViewModel.kt @@ -31,6 +31,7 @@ import app.aaps.pump.equil.events.EventEquilModeChanged import app.aaps.pump.equil.manager.EquilManager import app.aaps.pump.equil.manager.command.CmdModelSet import android.content.Context +import app.aaps.core.interfaces.pump.PumpRate import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.qualifiers.ApplicationContext import kotlinx.coroutines.flow.MutableSharedFlow @@ -44,6 +45,7 @@ import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.stateIn import java.time.Duration import javax.inject.Inject +import app.aaps.core.ui.R as CoreUiR sealed class EquilOverviewEvent { data class StartWizard(val workflow: EquilWorkflow) : EquilOverviewEvent() @@ -159,9 +161,9 @@ class EquilOverviewViewModel @Inject constructor( } ) ) - add(PumpInfoRow(label = rh.gs(app.aaps.core.ui.R.string.last_connection_label), value = dateUtil.dateAndTimeAndSecondsString(state.lastDataTime))) - add(PumpInfoRow(label = rh.gs(app.aaps.core.ui.R.string.battery_label), value = "${state.battery}%")) - add(PumpInfoRow(label = rh.gs(R.string.equil_insulin_reservoir), value = state.currentInsulin.toString())) + add(PumpInfoRow(label = rh.gs(CoreUiR.string.last_connection_label), value = dateUtil.dateAndTimeAndSecondsString(state.lastDataTime))) + add(PumpInfoRow(label = rh.gs(CoreUiR.string.battery_label), value = "${state.battery}%")) + add(PumpInfoRow(label = rh.gs(R.string.equil_insulin_reservoir), value = ch.insulinAmountString(PumpInsulin(state.currentInsulin.toDouble())))) add( PumpInfoRow( label = rh.gs(R.string.equil_basal_speed), @@ -175,23 +177,25 @@ class EquilOverviewViewModel @Inject constructor( val startTime = tempBasal.startTime val duration = tempBasal.duration / 60 / 1000 val minutesRunning = Duration.ofMillis(System.currentTimeMillis() - startTime).toMinutes() - rh.gs(R.string.equil_common_overview_temp_basal_value, tempBasal.rate, dateUtil.timeString(startTime), minutesRunning, duration) + rh.gs(R.string.equil_common_overview_tbr_value, ch.basalRateString(PumpRate(tempBasal.rate), true), dateUtil.timeString(startTime), minutesRunning, duration) } else "-" add(PumpInfoRow(label = rh.gs(R.string.equil_temp_basal_rate), value = tempBasalText)) // Total delivered val totalDelivered = if (state.startInsulin == -1) "-" - else rh.gs(R.string.equil_unit_u, (state.startInsulin - state.currentInsulin).toString()) + else ch.insulinAmountString(PumpInsulin((state.startInsulin - state.currentInsulin).toDouble())) add(PumpInfoRow(label = rh.gs(R.string.equil_total_delivered), value = totalDelivered)) // Last bolus (bolusRecord.amount is in cU from PumpWithConcentration) val lastBolusText = state.bolusRecord?.let { ch.insulinAmountAgoString( PumpInsulin(it.amount), - dateUtil.sinceString(it.startTime, rh) + it.startTime ) - } ?: "-" - add(PumpInfoRow(label = rh.gs(app.aaps.core.ui.R.string.last_bolus_label), value = lastBolusText)) + } + lastBolusText?.let { + add(PumpInfoRow(label = rh.gs(CoreUiR.string.last_bolus_label), value = it)) + } } private fun buildPrimaryActions(isPaired: Boolean): List = buildList { @@ -222,7 +226,7 @@ class EquilOverviewViewModel @Inject constructor( add( PumpAction( label = rh.gs(R.string.equil_pair), - iconRes = app.aaps.core.ui.R.drawable.ic_bluetooth_white_48dp, + iconRes = CoreUiR.drawable.ic_bluetooth_white_48dp, category = ActionCategory.MANAGEMENT, onClick = { _events.tryEmit(EquilOverviewEvent.StartWizard(EquilWorkflow.PAIR)) } )) @@ -230,21 +234,21 @@ class EquilOverviewViewModel @Inject constructor( add( PumpAction( label = rh.gs(R.string.equil_dressing), - iconRes = app.aaps.core.ui.R.drawable.ic_swap_horiz, + iconRes = CoreUiR.drawable.ic_swap_horiz, category = ActionCategory.MANAGEMENT, onClick = { _events.tryEmit(EquilOverviewEvent.StartWizard(EquilWorkflow.CHANGE_INSULIN)) } )) add( PumpAction( - label = rh.gs(app.aaps.core.ui.R.string.history), - iconRes = app.aaps.core.ui.R.drawable.ic_pump_history, + label = rh.gs(CoreUiR.string.history), + iconRes = CoreUiR.drawable.ic_pump_history, category = ActionCategory.MANAGEMENT, onClick = { _events.tryEmit(EquilOverviewEvent.StartHistory) } )) add( PumpAction( label = rh.gs(R.string.equil_unbind), - iconRes = app.aaps.core.ui.R.drawable.ic_bluetooth_white_48dp, + iconRes = CoreUiR.drawable.ic_bluetooth_white_48dp, category = ActionCategory.MANAGEMENT, onClick = { _events.tryEmit(EquilOverviewEvent.StartWizard(EquilWorkflow.UNPAIR)) } )) diff --git a/pump/equil/src/main/res/values/strings.xml b/pump/equil/src/main/res/values/strings.xml index 6d8e97a413b..fe6fed7540e 100644 --- a/pump/equil/src/main/res/values/strings.xml +++ b/pump/equil/src/main/res/values/strings.xml @@ -134,7 +134,7 @@ Suspend Resume delivery - %1$.2fU/h @%2$s (%3$d/%4$d min) + %1$s @%2$s (%3$d/%4$d min) Moments ago Less than a minute ago %1$s ago diff --git a/pump/insight/src/main/kotlin/app/aaps/pump/insight/InsightPlugin.kt b/pump/insight/src/main/kotlin/app/aaps/pump/insight/InsightPlugin.kt index 37270a39725..94d975de6a4 100644 --- a/pump/insight/src/main/kotlin/app/aaps/pump/insight/InsightPlugin.kt +++ b/pump/insight/src/main/kotlin/app/aaps/pump/insight/InsightPlugin.kt @@ -170,7 +170,8 @@ class InsightPlugin @Inject constructor( context = context, aapsSchedulers = aapsSchedulers, pumpSync = pumpSync, - blePreCheck = blePreCheck + blePreCheck = blePreCheck, + ch = ch ) }, ownPreferences = listOf( diff --git a/pump/insight/src/main/kotlin/app/aaps/pump/insight/compose/InsightComposeContent.kt b/pump/insight/src/main/kotlin/app/aaps/pump/insight/compose/InsightComposeContent.kt index 0f9b9f610f8..a46b1c4c967 100644 --- a/pump/insight/src/main/kotlin/app/aaps/pump/insight/compose/InsightComposeContent.kt +++ b/pump/insight/src/main/kotlin/app/aaps/pump/insight/compose/InsightComposeContent.kt @@ -20,7 +20,9 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource import androidx.lifecycle.compose.collectAsStateWithLifecycle +import app.aaps.core.interfaces.insulin.ConcentrationHelper import app.aaps.core.interfaces.pump.BlePreCheck +import app.aaps.core.interfaces.pump.PumpInsulin import app.aaps.core.interfaces.pump.PumpSync import app.aaps.core.interfaces.queue.Callback import app.aaps.core.interfaces.queue.CommandQueue @@ -49,6 +51,7 @@ import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharedFlow import kotlinx.coroutines.flow.StateFlow +import app.aaps.core.ui.R as CoreUiR private enum class InsightScreen { OVERVIEW, PAIR_WIZARD } @@ -61,7 +64,8 @@ class InsightComposeContent( private val context: Context, private val aapsSchedulers: AapsSchedulers, private val pumpSync: PumpSync, - private val blePreCheck: BlePreCheck + private val blePreCheck: BlePreCheck, + private val ch: ConcentrationHelper ) : ComposablePluginContent { @Composable @@ -78,7 +82,8 @@ class InsightComposeContent( dateUtil = dateUtil, commandQueue = commandQueue, context = context, - aapsSchedulers = aapsSchedulers + aapsSchedulers = aapsSchedulers, + ch = ch ) } @@ -95,7 +100,7 @@ class InsightComposeContent( IconButton(onClick = onNavigateBack) { Icon( imageVector = Icons.AutoMirrored.Filled.ArrowBack, - contentDescription = stringResource(id = app.aaps.core.ui.R.string.back) + contentDescription = stringResource(id = CoreUiR.string.back) ) } } @@ -103,7 +108,7 @@ class InsightComposeContent( IconButton(onClick = { currentScreen = InsightScreen.OVERVIEW }) { Icon( imageVector = Icons.AutoMirrored.Filled.ArrowBack, - contentDescription = stringResource(id = app.aaps.core.ui.R.string.back) + contentDescription = stringResource(id = CoreUiR.string.back) ) } } @@ -112,7 +117,7 @@ class InsightComposeContent( IconButton(onClick = action) { Icon( imageVector = Icons.Filled.Settings, - contentDescription = stringResource(id = app.aaps.core.ui.R.string.settings) + contentDescription = stringResource(id = CoreUiR.string.settings) ) } } @@ -237,7 +242,8 @@ internal class InsightOverviewState( private val dateUtil: DateUtil, private val commandQueue: CommandQueue, @Suppress("unused") private val context: Context, - private val aapsSchedulers: AapsSchedulers + private val aapsSchedulers: AapsSchedulers, + private val ch: ConcentrationHelper ) { private val disposable = CompositeDisposable() @@ -286,10 +292,10 @@ internal class InsightOverviewState( // Connection status val statusRes = when (service.state) { InsightState.NOT_PAIRED -> R.string.not_paired - InsightState.DISCONNECTED -> app.aaps.core.ui.R.string.disconnected + InsightState.DISCONNECTED -> CoreUiR.string.disconnected InsightState.CONNECTED -> app.aaps.core.interfaces.R.string.connected InsightState.RECOVERING -> R.string.recovering - else -> app.aaps.core.ui.R.string.connecting + else -> CoreUiR.string.connecting } add(PumpInfoRow(label = rh.gs(R.string.insight_status), value = rh.gs(statusRes))) @@ -297,7 +303,7 @@ internal class InsightOverviewState( add( PumpInfoRow( label = rh.gs(R.string.recovery_duration), - value = rh.gs(app.aaps.core.ui.R.string.secs, (service.recoveryDuration / 1000).toInt()) + value = rh.gs(CoreUiR.string.secs, (service.recoveryDuration / 1000).toInt()) ) ) } @@ -320,7 +326,7 @@ internal class InsightOverviewState( val modeText = when (mode) { OperatingMode.STARTED -> rh.gs(R.string.started) OperatingMode.STOPPED -> rh.gs(R.string.stopped) - OperatingMode.PAUSED -> rh.gs(app.aaps.core.ui.R.string.paused) + OperatingMode.PAUSED -> rh.gs(CoreUiR.string.paused) } add(PumpInfoRow(label = rh.gs(R.string.operating_mode), value = modeText)) } @@ -328,31 +334,31 @@ internal class InsightOverviewState( insightPlugin.batteryStatus?.let { battery -> add( PumpInfoRow( - label = rh.gs(app.aaps.core.ui.R.string.battery_label), - value = rh.gs(app.aaps.core.ui.R.string.format_percent, battery.batteryAmount) + label = rh.gs(CoreUiR.string.battery_label), + value = rh.gs(CoreUiR.string.format_percent, battery.batteryAmount) ) ) } insightPlugin.cartridgeStatus?.let { cartridge -> val status = if (cartridge.isInserted) - rh.gs(app.aaps.core.ui.R.string.format_insulin_units, cartridge.remainingAmount) + ch.insulinAmountString(PumpInsulin(cartridge.remainingAmount)) else rh.gs(R.string.not_inserted) add(PumpInfoRow(label = rh.gs(R.string.reservoir_level), value = status)) } insightPlugin.totalDailyDose?.let { tdd -> - add(PumpInfoRow(label = rh.gs(R.string.tdd_bolus), value = rh.gs(app.aaps.core.ui.R.string.format_insulin_units, tdd.bolus))) - add(PumpInfoRow(label = rh.gs(R.string.tdd_basal), value = rh.gs(app.aaps.core.ui.R.string.format_insulin_units, tdd.basal))) - add(PumpInfoRow(label = rh.gs(app.aaps.core.ui.R.string.tdd_total), value = rh.gs(app.aaps.core.ui.R.string.format_insulin_units, tdd.bolusAndBasal))) + add(PumpInfoRow(label = rh.gs(R.string.tdd_bolus), value = ch.insulinAmountString(PumpInsulin(tdd.bolus)))) + add(PumpInfoRow(label = rh.gs(R.string.tdd_basal), value = ch.insulinAmountString(PumpInsulin(tdd.basal)))) + add(PumpInfoRow(label = rh.gs(CoreUiR.string.tdd_total), value = ch.insulinAmountString(PumpInsulin(tdd.bolusAndBasal)))) } insightPlugin.activeBasalRate?.let { basal -> add( PumpInfoRow( label = rh.gs(R.string.active_basal_rate), - value = rh.gs(app.aaps.core.ui.R.string.pump_base_basal_rate, basal.activeBasalRate) + " (${basal.activeBasalProfileName})" + value = rh.gs(CoreUiR.string.pump_base_basal_rate, basal.activeBasalRate) + " (${basal.activeBasalProfileName})" ) ) } @@ -366,25 +372,28 @@ internal class InsightOverviewState( ) } - val lastBolusCu = insightPlugin.lastBolusAmount.value?.cU ?: 0.0 - if (lastBolusCu != 0.0 && insightPlugin.lastBolusTimestamp != 0L) { - val minAgo = (System.currentTimeMillis() - insightPlugin.lastBolusTimestamp) / 60.0 / 1000.0 - val ago = if (minAgo < 60) dateUtil.minAgo(rh, insightPlugin.lastBolusTimestamp) - else dateUtil.hourAgo(insightPlugin.lastBolusTimestamp, rh) - val unit = rh.gs(app.aaps.core.ui.R.string.insulin_unit_shortname) - add( - PumpInfoRow( - label = rh.gs(app.aaps.core.ui.R.string.last_bolus_label), - value = rh.gs(R.string.insight_last_bolus_formater, lastBolusCu, unit, ago) + insightPlugin.lastBolusAmount.value?.let { lastBolus -> + if (lastBolus.cU != 0.0 && insightPlugin.lastBolusTimestamp != 0L) { + val text = ch.insulinAmountAgoString( + lastBolus, + insightPlugin.lastBolusTimestamp ) - ) + text?.let { + add( + PumpInfoRow( + label = rh.gs(CoreUiR.string.last_bolus_label), + value = it + ) + ) + } + } } insightPlugin.activeBoluses?.let { boluses -> boluses.take(2).forEach { bolus -> val label = when (bolus.bolusType) { BolusType.MULTIWAVE -> rh.gs(R.string.multiwave_bolus) - BolusType.EXTENDED -> rh.gs(app.aaps.core.ui.R.string.extended_bolus) + BolusType.EXTENDED -> rh.gs(CoreUiR.string.extended_bolus) else -> null } if (label != null) { @@ -403,7 +412,7 @@ internal class InsightOverviewState( if (service.isPaired) { service.pumpSystemIdentification?.let { sys -> if (sys.serialNumber.isNotEmpty()) { - add(PumpInfoRow(label = rh.gs(app.aaps.core.ui.R.string.serial_number), value = sys.serialNumber)) + add(PumpInfoRow(label = rh.gs(CoreUiR.string.serial_number), value = sys.serialNumber)) } sys.manufacturingDate?.let { date -> add(PumpInfoRow(label = rh.gs(R.string.manufacturing_date), value = date)) @@ -423,8 +432,8 @@ internal class InsightOverviewState( add( PumpAction( - label = rh.gs(app.aaps.core.ui.R.string.refresh), - iconRes = app.aaps.core.ui.R.drawable.ic_refresh, + label = rh.gs(CoreUiR.string.refresh), + iconRes = CoreUiR.drawable.ic_refresh, category = ActionCategory.PRIMARY, enabled = !refreshPending, onClick = { @@ -469,7 +478,7 @@ internal class InsightOverviewState( add( PumpAction( label = rh.gs(R.string.unpair), - iconRes = app.aaps.core.ui.R.drawable.ic_bluetooth_white_48dp, + iconRes = CoreUiR.drawable.ic_bluetooth_white_48dp, category = ActionCategory.MANAGEMENT, onClick = { _events.tryEmit(InsightOverviewEvent.RequestUnpair) } ) @@ -478,7 +487,7 @@ internal class InsightOverviewState( add( PumpAction( label = rh.gs(R.string.insight_pairing), - iconRes = app.aaps.core.ui.R.drawable.ic_bluetooth_white_48dp, + iconRes = CoreUiR.drawable.ic_bluetooth_white_48dp, category = ActionCategory.MANAGEMENT, onClick = { _events.tryEmit(InsightOverviewEvent.StartPairing) } ) diff --git a/pump/medtronic/src/main/kotlin/app/aaps/pump/medtronic/compose/MedtronicOverviewViewModel.kt b/pump/medtronic/src/main/kotlin/app/aaps/pump/medtronic/compose/MedtronicOverviewViewModel.kt index 4a7ecbb2f81..c5bf93dff08 100644 --- a/pump/medtronic/src/main/kotlin/app/aaps/pump/medtronic/compose/MedtronicOverviewViewModel.kt +++ b/pump/medtronic/src/main/kotlin/app/aaps/pump/medtronic/compose/MedtronicOverviewViewModel.kt @@ -12,8 +12,11 @@ import androidx.compose.material.icons.filled.Timeline import androidx.compose.runtime.Stable import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope +import app.aaps.core.interfaces.insulin.ConcentrationHelper import app.aaps.core.interfaces.logging.AAPSLogger import app.aaps.core.interfaces.logging.LTag +import app.aaps.core.interfaces.pump.PumpInsulin +import app.aaps.core.interfaces.pump.PumpRate import app.aaps.core.interfaces.queue.Callback import app.aaps.core.interfaces.queue.CommandQueue import app.aaps.core.interfaces.resources.ResourceHelper @@ -56,6 +59,7 @@ import java.util.Locale import javax.inject.Inject import javax.inject.Provider import app.aaps.pump.common.hw.rileylink.R as RileyLinkR +import app.aaps.core.ui.R as CoreUiR sealed class MedtronicOverviewEvent { data object ShowHistory : MedtronicOverviewEvent() @@ -69,6 +73,7 @@ sealed class MedtronicOverviewEvent { @HiltViewModel class MedtronicOverviewViewModel @Inject constructor( private val rh: ResourceHelper, + private val ch: ConcentrationHelper, private val medtronicPumpPlugin: MedtronicPumpPlugin, private val medtronicPumpStatus: MedtronicPumpStatus, private val medtronicUtil: MedtronicUtil, @@ -158,32 +163,34 @@ class MedtronicOverviewViewModel @Inject constructor( // Last connection val (lastConnText, lastConnLevel) = buildLastConnection() - add(PumpInfoRow(label = rh.gs(app.aaps.core.ui.R.string.last_connection_label), value = lastConnText, level = lastConnLevel)) + add(PumpInfoRow(label = rh.gs(CoreUiR.string.last_connection_label), value = lastConnText, level = lastConnLevel)) // Last bolus - add(PumpInfoRow(label = rh.gs(app.aaps.core.ui.R.string.last_bolus_label), value = buildLastBolus())) + buildLastBolus()?.let { + add(PumpInfoRow(label = rh.gs(CoreUiR.string.last_bolus_label), value = it)) + } // Base basal rate val basalText = "(" + medtronicPumpStatus.activeProfileName + ") " + - rh.gs(app.aaps.core.ui.R.string.pump_base_basal_rate, medtronicPumpPlugin.baseBasalRate.cU) - add(PumpInfoRow(label = rh.gs(app.aaps.core.ui.R.string.base_basal_rate_label), value = basalText)) + ch.basalRateString(medtronicPumpPlugin.baseBasalRate, true) + add(PumpInfoRow(label = rh.gs(CoreUiR.string.base_basal_rate_label), value = basalText)) // Temp basal val tbrText = buildTempBasal() - add(PumpInfoRow(label = rh.gs(app.aaps.core.ui.R.string.tempbasal_label), value = tbrText, visible = tbrText.isNotEmpty())) + add(PumpInfoRow(label = rh.gs(CoreUiR.string.tempbasal_label), value = tbrText, visible = tbrText.isNotEmpty())) // Battery val (batteryText, batteryLevel) = buildBattery() - add(PumpInfoRow(label = rh.gs(app.aaps.core.ui.R.string.battery_label), value = batteryText, level = batteryLevel)) + add(PumpInfoRow(label = rh.gs(CoreUiR.string.battery_label), value = batteryText, level = batteryLevel)) // Reservoir val (reservoirText, reservoirLevel) = buildReservoir() - add(PumpInfoRow(label = rh.gs(app.aaps.core.ui.R.string.reservoir_label), value = reservoirText, level = reservoirLevel)) + add(PumpInfoRow(label = rh.gs(CoreUiR.string.reservoir_label), value = reservoirText, level = reservoirLevel)) // Errors val errorsText = medtronicPumpStatus.errorInfo val errorsLevel = if (errorsText != PLACEHOLDER) StatusLevel.CRITICAL else StatusLevel.NORMAL - add(PumpInfoRow(label = rh.gs(app.aaps.core.ui.R.string.errors), value = errorsText, level = errorsLevel)) + add(PumpInfoRow(label = rh.gs(CoreUiR.string.errors), value = errorsText, level = errorsLevel)) } private fun buildPumpStatusText(): String { @@ -248,31 +255,24 @@ class MedtronicOverviewViewModel @Inject constructor( } } - private fun buildLastBolus(): String { - val bolus = medtronicPumpStatus.lastBolusAmount + private fun buildLastBolus(): String? { + val bolus = medtronicPumpStatus.lastBolusAmount?.let { PumpInsulin(it) } val bolusTime = medtronicPumpStatus.lastBolusTime - if (bolus == null || bolusTime == null) return "" - - val agoMsc = System.currentTimeMillis() - bolusTime.time - val bolusMinAgo = agoMsc.toDouble() / 60.0 / 1000.0 - val unit = rh.gs(app.aaps.core.ui.R.string.insulin_unit_shortname) - val ago = when { - agoMsc < 60 * 1000 -> rh.gs(R.string.medtronic_pump_connected_now) - bolusMinAgo < 60 -> dateUtil.minAgo(rh, bolusTime.time) - else -> dateUtil.hourAgo(bolusTime.time, rh) - } - return rh.gs(R.string.mdt_last_bolus, bolus, unit, ago) + if (bolus == null || bolusTime == null) + return null + return ch.insulinAmountAgoString(bolus, bolusTime.time) } private fun buildTempBasal(): String { val tbrRemainingTime = medtronicPumpStatus.tbrRemainingTime ?: return "" - return rh.gs(R.string.mdt_tbr_remaining, medtronicPumpStatus.tempBasalAmount, tbrRemainingTime) + val tempBasalAmount = medtronicPumpStatus.tempBasalAmount?.let { PumpRate(it) } ?: return "" + return rh.gs(R.string.medtronic_tbr_remaining, ch.basalRateString(tempBasalAmount, true), tbrRemainingTime) } private fun buildBattery(): Pair { val remaining = medtronicPumpStatus.batteryRemaining val text = if (medtronicPumpStatus.batteryType == BatteryType.None || medtronicPumpStatus.batteryVoltage == null) { - remaining?.let { "$it%" } ?: rh.gs(app.aaps.core.ui.R.string.unknown) + remaining?.let { "$it%" } ?: rh.gs(CoreUiR.string.unknown) } else { (remaining?.let { "$it% " } ?: "") + String.format(Locale.getDefault(), "(%.2f V)", medtronicPumpStatus.batteryVoltage) @@ -287,12 +287,12 @@ class MedtronicOverviewViewModel @Inject constructor( } private fun buildReservoir(): Pair { - val remaining = medtronicPumpStatus.reservoirRemainingUnits - val full = medtronicPumpStatus.reservoirFullUnits - val text = rh.gs(app.aaps.core.ui.R.string.reservoir_value, remaining, full) + val remaining = PumpInsulin(medtronicPumpStatus.reservoirRemainingUnits) + //val full = ch.fromPump(PumpInsulin(medtronicPumpStatus.reservoirFullUnits.toDouble())).toInt() + val text = ch.insulinAmountString(remaining) // "/ $full U" removed val level = when { - remaining <= 20.0 -> StatusLevel.CRITICAL - remaining <= 50.0 -> StatusLevel.WARNING + ch.fromPump(remaining) <= 20.0 -> StatusLevel.CRITICAL + ch.fromPump(remaining) <= 50.0 -> StatusLevel.WARNING else -> StatusLevel.NORMAL } return text to level @@ -305,7 +305,7 @@ class MedtronicOverviewViewModel @Inject constructor( private fun buildPrimaryActions(): List { return listOf( PumpAction( - label = rh.gs(app.aaps.core.ui.R.string.refresh), + label = rh.gs(CoreUiR.string.refresh), icon = Icons.Filled.Refresh, onClick = { onRefreshClicked() } ) @@ -323,7 +323,7 @@ class MedtronicOverviewViewModel @Inject constructor( onClick = { _events.tryEmit(MedtronicOverviewEvent.ShowRileyLinkPairWizard) } ), PumpAction( - label = rh.gs(app.aaps.core.ui.R.string.pump_history), + label = rh.gs(CoreUiR.string.pump_history), icon = Icons.Filled.History, category = ActionCategory.MANAGEMENT, onClick = { _events.tryEmit(MedtronicOverviewEvent.ShowHistory) } @@ -394,7 +394,7 @@ class MedtronicOverviewViewModel @Inject constructor( private fun emitNotConfiguredDialog() { _events.tryEmit( MedtronicOverviewEvent.ShowDialog( - rh.gs(app.aaps.core.ui.R.string.warning), + rh.gs(CoreUiR.string.warning), rh.gs(R.string.medtronic_error_operation_not_possible_no_configuration) ) ) diff --git a/pump/medtronic/src/main/res/values/strings.xml b/pump/medtronic/src/main/res/values/strings.xml index 148c0335494..15307e50aa8 100644 --- a/pump/medtronic/src/main/res/values/strings.xml +++ b/pump/medtronic/src/main/res/values/strings.xml @@ -104,6 +104,8 @@ %1$.1f %2$s (%3$s) Set neutral temp basals If enabled, it will cancel a temporary basal before the end of each hour. This method can help stop some pumps beeping/vibrating on the hour. + %1$s (%2$d min remaining) + ^\\d{6} %1$.1f U/h (%2$d min remaining) Invalid pump history data detected. Open new issue and provide logs. RL Stats diff --git a/pump/medtrum/src/main/kotlin/app/aaps/pump/medtrum/compose/MedtrumOverviewViewModel.kt b/pump/medtrum/src/main/kotlin/app/aaps/pump/medtrum/compose/MedtrumOverviewViewModel.kt index dd528fbff5e..5936baf14e3 100644 --- a/pump/medtrum/src/main/kotlin/app/aaps/pump/medtrum/compose/MedtrumOverviewViewModel.kt +++ b/pump/medtrum/src/main/kotlin/app/aaps/pump/medtrum/compose/MedtrumOverviewViewModel.kt @@ -47,6 +47,7 @@ import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch import java.util.Locale import javax.inject.Inject +import app.aaps.core.ui.R as CoreUiR sealed class MedtrumOverviewEvent { data class StartPatchWorkflow(val startStep: PatchStep) : MedtrumOverviewEvent() @@ -127,7 +128,7 @@ class MedtrumOverviewViewModel @Inject constructor( if (profile == null) { _events.tryEmit( MedtrumOverviewEvent.ShowDialog( - title = rh.gs(app.aaps.core.ui.R.string.message), + title = rh.gs(CoreUiR.string.message), message = rh.gs(R.string.no_profile_selected) ) ) @@ -191,13 +192,10 @@ class MedtrumOverviewViewModel @Inject constructor( // Last bolus val lastBolus = if (lastBolusTime != null && lastBolusAmount != null) { - val agoHours = (System.currentTimeMillis() - lastBolusTime).toDouble() / 1000.0 / 60.0 / 60.0 - if (agoHours < 6.0) { - ch.insulinAmountAgoString( - PumpInsulin(lastBolusAmount), - dateUtil.sinceString(lastBolusTime, rh) - ) - } else null + ch.insulinAmountAgoString( + PumpInsulin(lastBolusAmount), + lastBolusTime + ) } else null // Active bolus @@ -205,7 +203,7 @@ class MedtrumOverviewViewModel @Inject constructor( dateUtil.timeString(medtrumPump.bolusStartTime) + " " + dateUtil.sinceString(medtrumPump.bolusStartTime, rh) + " " + ch.bolusProgressString(PumpInsulin(bolusDelivered), ch.fromPump(PumpInsulin(medtrumPump.bolusAmountToBeDelivered))) + - " (" + rh.gs(app.aaps.core.ui.R.string.bolus_delivered_CU, bolusDelivered, medtrumPump.bolusAmountToBeDelivered) + ")" + " (" + rh.gs(CoreUiR.string.bolus_delivered_CU, bolusDelivered, medtrumPump.bolusAmountToBeDelivered) + ")" } else null // Battery voltage @@ -266,15 +264,15 @@ class MedtrumOverviewViewModel @Inject constructor( // Primary actions val primaryActions = listOf( PumpAction( - label = rh.gs(app.aaps.core.ui.R.string.refresh), - iconRes = app.aaps.core.ui.R.drawable.ic_refresh, + label = rh.gs(CoreUiR.string.refresh), + iconRes = CoreUiR.drawable.ic_refresh, category = ActionCategory.PRIMARY, enabled = canRefresh, onClick = { onClickRefresh() } ), PumpAction( label = rh.gs(R.string.reset_alarms_label), - iconRes = app.aaps.core.ui.R.drawable.ic_loop_resume, + iconRes = CoreUiR.drawable.ic_loop_resume, category = ActionCategory.PRIMARY, enabled = pumpState.isSuspendedByPump(), visible = pumpState.isSuspendedByPump(), @@ -286,7 +284,7 @@ class MedtrumOverviewViewModel @Inject constructor( val managementActions = listOf( PumpAction( label = rh.gs(R.string.change_patch_label), - iconRes = app.aaps.core.ui.R.drawable.ic_swap_horiz, + iconRes = CoreUiR.drawable.ic_swap_horiz, category = ActionCategory.MANAGEMENT, onClick = { onClickChangePatch() } ) diff --git a/pump/omnipod/common/src/main/res/values/strings.xml b/pump/omnipod/common/src/main/res/values/strings.xml index 9ff1f637116..aac8a0d80b8 100644 --- a/pump/omnipod/common/src/main/res/values/strings.xml +++ b/pump/omnipod/common/src/main/res/values/strings.xml @@ -54,7 +54,6 @@ Firmware Version Time on Pod %1$s @%2$s (%3$d/%4$d minutes) - Over %1$s left uncertain diff --git a/pump/omnipod/dash/src/main/kotlin/app/aaps/pump/omnipod/dash/ui/compose/DashOverviewViewModel.kt b/pump/omnipod/dash/src/main/kotlin/app/aaps/pump/omnipod/dash/ui/compose/DashOverviewViewModel.kt index 986cec4c066..ee4ed83aacf 100644 --- a/pump/omnipod/dash/src/main/kotlin/app/aaps/pump/omnipod/dash/ui/compose/DashOverviewViewModel.kt +++ b/pump/omnipod/dash/src/main/kotlin/app/aaps/pump/omnipod/dash/ui/compose/DashOverviewViewModel.kt @@ -248,13 +248,15 @@ class DashOverviewViewModel @Inject constructor( // Last bolus val (lastBolusText, lastBolusLevel) = buildLastBolus() - add(PumpInfoRow(label = rh.gs(CommonR.string.omnipod_common_overview_last_bolus), value = lastBolusText, level = lastBolusLevel)) + lastBolusText?.let { + add(PumpInfoRow(label = rh.gs(CoreUiR.string.last_bolus_label), value = it, level = lastBolusLevel)) + } // Base basal rate val basalText = if (podStateManager.basalProgram != null && !podStateManager.isSuspended) { - rh.gs( - app.aaps.core.ui.R.string.pump_base_basal_rate, - omnipodDashPumpPlugin.model().determineCorrectBasalSize(podStateManager.basalProgram!!.rateAt(System.currentTimeMillis())) + ch.basalRateString( + rate = PumpRate(omnipodDashPumpPlugin.model().determineCorrectBasalSize(podStateManager.basalProgram!!.rateAt(System.currentTimeMillis()))), + isAbsolute = true ) } else PLACEHOLDER add(PumpInfoRow(label = rh.gs(CommonR.string.omnipod_common_overview_base_basal_rate), value = basalText)) @@ -269,7 +271,7 @@ class DashOverviewViewModel @Inject constructor( // Total delivered val totalDelivered = if (podStateManager.isActivationCompleted && podStateManager.pulsesDelivered != null) { - rh.gs(CommonR.string.omnipod_common_overview_total_delivered_value, podStateManager.pulsesDelivered!! * PodConstants.POD_PULSE_BOLUS_UNITS) + ch.insulinAmountString(PumpInsulin(podStateManager.pulsesDelivered!! * PodConstants.POD_PULSE_BOLUS_UNITS)) } else PLACEHOLDER add(PumpInfoRow(label = rh.gs(CommonR.string.omnipod_common_overview_total_delivered), value = totalDelivered)) @@ -300,11 +302,11 @@ class DashOverviewViewModel @Inject constructor( return listOf( PumpAction( - label = rh.gs(app.aaps.core.ui.R.string.refresh), + label = rh.gs(CoreUiR.string.refresh), icon = Icons.Filled.Refresh, enabled = podStateManager.isUniqueIdSet && queueEmpty, onClick = { - commandQueue.readStatus(rh.gs(app.aaps.core.ui.R.string.refresh), object : Callback() { + commandQueue.readStatus(rh.gs(CoreUiR.string.refresh), object : Callback() { override fun run() {} }) } @@ -457,30 +459,28 @@ class DashOverviewViewModel @Inject constructor( else -> StatusLevel.NORMAL } - private fun buildLastBolus(): Pair { + private fun buildLastBolus(): Pair { podStateManager.activeCommand?.let { val requestedBolus = it.requestedBolus if (requestedBolus != null) { var text = ch.insulinAmountAgoString( PumpInsulin(omnipodDashPumpPlugin.model().determineCorrectBolusSize(requestedBolus)), - readableDuration(Duration.ofMillis(SystemClock.elapsedRealtime() - it.createdRealtime)) + it.createdRealtime ) text += " (${rh.gs(CommonR.string.omnipod_common_uncertain)})" return text to StatusLevel.CRITICAL } } - podStateManager.lastBolus?.let { val bolusSize = it.deliveredUnits() ?: it.requestedUnits val text = ch.insulinAmountAgoString( PumpInsulin(omnipodDashPumpPlugin.model().determineCorrectBolusSize(bolusSize)), - readableDuration(Duration.ofMillis(System.currentTimeMillis() - it.startTime)) + it.startTime ) val level = if (!it.deliveryComplete) StatusLevel.WARNING else StatusLevel.NORMAL return text to level } - - return PLACEHOLDER to StatusLevel.NORMAL + return null to StatusLevel.NORMAL } private fun buildTempBasalText(): String { @@ -499,13 +499,13 @@ class DashOverviewViewModel @Inject constructor( } private fun buildReservoir(): Pair { - if (podStateManager.pulsesRemaining == null) { - return rh.gs(CommonR.string.omnipod_common_overview_reservoir_concentration_value_over50, ch.insulinAmountString(PumpInsulin(50.0))) to StatusLevel.NORMAL - } - val lowThreshold: Short = PodConstants.DEFAULT_MAX_RESERVOIR_ALERT_THRESHOLD - val text = ch.insulinAmountString(PumpInsulin(podStateManager.pulsesRemaining!! * PodConstants.POD_PULSE_BOLUS_UNITS)) - val level = if (ch.fromPump(PumpInsulin(podStateManager.pulsesRemaining!! * PodConstants.POD_PULSE_BOLUS_UNITS)) < lowThreshold.toDouble()) StatusLevel.CRITICAL else StatusLevel.NORMAL - return text to level + val reservoirLevel = podStateManager.pulsesRemaining?.let { PumpInsulin(it * PodConstants.POD_PULSE_BOLUS_UNITS) } + return reservoirLevel?.let { + val lowThreshold = PodConstants.DEFAULT_MAX_RESERVOIR_ALERT_THRESHOLD.toDouble() + val text = ch.insulinAmountString(it) + val level = if (ch.fromPump(it) < lowThreshold) StatusLevel.CRITICAL else StatusLevel.NORMAL + text to level + } ?: rh.gs(CoreUiR.string.overview_reservoir_concentration_value_over, ch.insulinAmountString(PumpInsulin(50.0))) to StatusLevel.NORMAL } private fun translatedActiveAlert(alert: AlertType): String { diff --git a/pump/omnipod/eros/src/main/java/app/aaps/pump/omnipod/eros/ui/compose/ErosOverviewViewModel.kt b/pump/omnipod/eros/src/main/java/app/aaps/pump/omnipod/eros/ui/compose/ErosOverviewViewModel.kt index 284f9c21bcd..d2ed1fdc387 100644 --- a/pump/omnipod/eros/src/main/java/app/aaps/pump/omnipod/eros/ui/compose/ErosOverviewViewModel.kt +++ b/pump/omnipod/eros/src/main/java/app/aaps/pump/omnipod/eros/ui/compose/ErosOverviewViewModel.kt @@ -45,6 +45,7 @@ import app.aaps.pump.common.hw.rileylink.defs.RileyLinkTargetDevice import app.aaps.pump.common.hw.rileylink.service.RileyLinkServiceData import app.aaps.pump.common.hw.rileylink.service.tasks.ResetRileyLinkConfigurationTask import app.aaps.pump.common.hw.rileylink.service.tasks.ServiceTaskExecutor +import app.aaps.pump.omnipod.common.bledriver.pod.definition.PodConstants import app.aaps.pump.omnipod.common.queue.command.CommandHandleTimeChange import app.aaps.pump.omnipod.common.queue.command.CommandPlayTestBeep import app.aaps.pump.omnipod.common.queue.command.CommandResumeDelivery @@ -218,11 +219,16 @@ class ErosOverviewViewModel @Inject constructor( // Last bolus val (lastBolusText, lastBolusLevel) = buildLastBolus() - add(PumpInfoRow(label = rh.gs(CommonR.string.omnipod_common_overview_last_bolus), value = lastBolusText, level = lastBolusLevel)) + lastBolusText?.let { + add(PumpInfoRow(label = rh.gs(CoreUiR.string.last_bolus_label), value = it, level = lastBolusLevel)) + } // Base basal rate val basalText = if (podStateManager.isPodActivationCompleted) { - rh.gs(app.aaps.core.ui.R.string.pump_base_basal_rate, omnipodErosPumpPlugin.model().determineCorrectBasalSize(podStateManager.basalSchedule.rateAt(TimeUtil.toDuration(DateTime.now())))) + ch.basalRateString( + rate = PumpRate(omnipodErosPumpPlugin.model().determineCorrectBasalSize(podStateManager.basalSchedule.rateAt(TimeUtil.toDuration(DateTime.now())))), + isAbsolute = true + ) } else PLACEHOLDER add(PumpInfoRow(label = rh.gs(CommonR.string.omnipod_common_overview_base_basal_rate), value = basalText)) @@ -236,7 +242,7 @@ class ErosOverviewViewModel @Inject constructor( // Total delivered val totalDelivered = if (podStateManager.isPodActivationCompleted && podStateManager.totalInsulinDelivered != null) { - rh.gs(CommonR.string.omnipod_common_overview_total_delivered_value, podStateManager.totalInsulinDelivered - OmnipodConstants.POD_SETUP_UNITS) + ch.insulinAmountString(PumpInsulin(podStateManager.totalInsulinDelivered - OmnipodConstants.POD_SETUP_UNITS)) } else PLACEHOLDER add(PumpInfoRow(label = rh.gs(CommonR.string.omnipod_common_overview_total_delivered), value = totalDelivered)) @@ -270,7 +276,7 @@ class ErosOverviewViewModel @Inject constructor( return listOf( PumpAction( - label = rh.gs(app.aaps.core.ui.R.string.refresh), + label = rh.gs(CoreUiR.string.refresh), icon = Icons.Filled.Refresh, enabled = podStateManager.isPodInitialized && podStateManager.activationProgress.isAtLeast(ActivationProgress.PAIRING_COMPLETED) && rlReady && queueEmpty, onClick = { commandQueue.customCommand(CommandGetPodStatus(), DisplayResultDialogCallback(rh.gs(CommonR.string.omnipod_common_error_failed_to_refresh_status), false)) } @@ -470,19 +476,21 @@ class ErosOverviewViewModel @Inject constructor( return PLACEHOLDER to StatusLevel.NORMAL } - private fun buildLastBolus(): Pair { + private fun buildLastBolus(): Pair { if (podStateManager.isPodActivationCompleted && podStateManager.hasLastBolus()) { var text = ch.insulinAmountAgoString( PumpInsulin(omnipodErosPumpPlugin.model().determineCorrectBolusSize(podStateManager.lastBolusAmount)), - readableDuration(podStateManager.lastBolusStartTime) + podStateManager.lastBolusStartTime.millis ) - if (!podStateManager.isLastBolusCertain) { - text += " (${rh.gs(CommonR.string.omnipod_common_uncertain)})" - return text to StatusLevel.CRITICAL + text?.let { + if (!podStateManager.isLastBolusCertain) { + text += " (${rh.gs(CommonR.string.omnipod_common_uncertain)})" + return text to StatusLevel.CRITICAL + } + return text to StatusLevel.NORMAL } - return text to StatusLevel.NORMAL } - return PLACEHOLDER to StatusLevel.NORMAL + return null to StatusLevel.NORMAL } private fun buildTempBasal(): Pair { @@ -515,11 +523,12 @@ class ErosOverviewViewModel @Inject constructor( private fun buildReservoir(): Pair { if (podStateManager.reservoirLevel == null) { - return rh.gs(CommonR.string.omnipod_common_overview_reservoir_concentration_value_over50, ch.insulinAmountString(PumpInsulin(50.0))) to StatusLevel.NORMAL + return rh.gs(CoreUiR.string.overview_reservoir_concentration_value_over, ch.insulinAmountString(PumpInsulin(50.0))) to StatusLevel.NORMAL } + val reservoirLevel = PumpInsulin(podStateManager.reservoirLevel) val lowThreshold = (omnipodAlertUtil.lowReservoirAlertUnits ?: OmnipodConstants.DEFAULT_MAX_RESERVOIR_ALERT_THRESHOLD).toDouble() - val text = ch.insulinAmountString(PumpInsulin(podStateManager.reservoirLevel)) - val level = if (ch.fromPump(PumpInsulin(podStateManager.reservoirLevel)) < lowThreshold) StatusLevel.CRITICAL else StatusLevel.NORMAL + val text = ch.insulinAmountString(reservoirLevel) + val level = if (ch.fromPump(reservoirLevel) < lowThreshold) StatusLevel.CRITICAL else StatusLevel.NORMAL return text to level } diff --git a/pump/virtual/src/main/kotlin/app/aaps/pump/virtual/VirtualPumpViewModel.kt b/pump/virtual/src/main/kotlin/app/aaps/pump/virtual/VirtualPumpViewModel.kt index f70a51b617e..ff6c98e9c45 100644 --- a/pump/virtual/src/main/kotlin/app/aaps/pump/virtual/VirtualPumpViewModel.kt +++ b/pump/virtual/src/main/kotlin/app/aaps/pump/virtual/VirtualPumpViewModel.kt @@ -36,6 +36,7 @@ import kotlinx.coroutines.flow.merge import kotlinx.coroutines.flow.onStart import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.runBlocking +import app.aaps.core.ui.R as CoreUiR class VirtualPumpViewModel( private val virtualPumpPlugin: VirtualPumpPlugin, @@ -94,11 +95,11 @@ class VirtualPumpViewModel( val tempBasalText = profile?.let { runBlocking { persistenceLayer.getTemporaryBasalActiveAt(now) } - ?.toStringFull(it, dateUtil, rh) + ?.toStringFull(it, dateUtil, ch) } ?: "" val extendedBolusText = runBlocking { persistenceLayer.getExtendedBolusActiveAt(now) } - ?.toStringFull(dateUtil, rh) ?: "" + ?.toStringFull(dateUtil, ch) ?: "" // Format values for the shared builder val lastConnection = virtualPumpPlugin.lastDataTime.value.takeIf { it != 0L } @@ -106,7 +107,7 @@ class VirtualPumpViewModel( val lastBolus = virtualPumpPlugin.lastBolusAmount.value?.let { amount -> virtualPumpPlugin.lastBolusTime.value?.takeIf { it != 0L }?.let { time -> - ch.insulinAmountAgoString(amount, dateUtil.sinceString(time, rh)) + ch.insulinAmountAgoString(amount, time) } } @@ -115,7 +116,7 @@ class VirtualPumpViewModel( } val battery = virtualPumpPlugin.batteryLevel.value?.let { level -> - rh.gs(app.aaps.core.ui.R.string.format_percent, level) + rh.gs(CoreUiR.string.format_percent, level) } val reservoir = ch.insulinAmountString(virtualPumpPlugin.reservoirLevel.value) @@ -152,15 +153,15 @@ class VirtualPumpViewModel( val managementActions = listOf( PumpAction( - label = rh.gs(app.aaps.core.ui.R.string.pump_suspend), - iconRes = app.aaps.core.ui.R.drawable.ic_loop_paused, + label = rh.gs(CoreUiR.string.pump_suspend), + iconRes = CoreUiR.drawable.ic_loop_paused, category = ActionCategory.MANAGEMENT, visible = !isSuspended, onClick = { onSuspendToggle(true) } ), PumpAction( - label = rh.gs(app.aaps.core.ui.R.string.pump_resume), - iconRes = app.aaps.core.ui.R.drawable.ic_loop_resume, + label = rh.gs(CoreUiR.string.pump_resume), + iconRes = CoreUiR.drawable.ic_loop_resume, category = ActionCategory.MANAGEMENT, visible = isSuspended, onClick = { onSuspendToggle(false) }