Merge pull request #53 from 0pen-dash/avereha/fixes-v2
Avereha/fixes v2
This commit is contained in:
commit
4755d749d1
9 changed files with 220 additions and 90 deletions
|
@ -1,6 +1,8 @@
|
||||||
package info.nightscout.androidaps.plugins.pump.omnipod.dash
|
package info.nightscout.androidaps.plugins.pump.omnipod.dash
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import android.os.Handler
|
||||||
|
import android.os.Looper
|
||||||
import dagger.android.HasAndroidInjector
|
import dagger.android.HasAndroidInjector
|
||||||
import info.nightscout.androidaps.activities.ErrorHelperActivity.Companion.runAlarm
|
import info.nightscout.androidaps.activities.ErrorHelperActivity.Companion.runAlarm
|
||||||
import info.nightscout.androidaps.data.DetailedBolusInfo
|
import info.nightscout.androidaps.data.DetailedBolusInfo
|
||||||
|
@ -19,6 +21,7 @@ import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotifi
|
||||||
import info.nightscout.androidaps.plugins.general.overview.events.EventOverviewBolusProgress
|
import info.nightscout.androidaps.plugins.general.overview.events.EventOverviewBolusProgress
|
||||||
import info.nightscout.androidaps.plugins.general.overview.notifications.Notification
|
import info.nightscout.androidaps.plugins.general.overview.notifications.Notification
|
||||||
import info.nightscout.androidaps.plugins.pump.common.defs.PumpType
|
import info.nightscout.androidaps.plugins.pump.common.defs.PumpType
|
||||||
|
import info.nightscout.androidaps.plugins.pump.common.utils.DateTimeUtil
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.common.definition.OmnipodCommandType
|
import info.nightscout.androidaps.plugins.pump.omnipod.common.definition.OmnipodCommandType
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.common.queue.command.*
|
import info.nightscout.androidaps.plugins.pump.omnipod.common.queue.command.*
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.OmnipodDashManager
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.OmnipodDashManager
|
||||||
|
@ -67,10 +70,14 @@ class OmnipodDashPumpPlugin @Inject constructor(
|
||||||
commandQueue: CommandQueueProvider
|
commandQueue: CommandQueueProvider
|
||||||
) : PumpPluginBase(pluginDescription, injector, aapsLogger, resourceHelper, commandQueue), Pump {
|
) : PumpPluginBase(pluginDescription, injector, aapsLogger, resourceHelper, commandQueue), Pump {
|
||||||
@Volatile var bolusCanceled = false
|
@Volatile var bolusCanceled = false
|
||||||
|
private val handler: Handler = Handler(Looper.getMainLooper())
|
||||||
|
lateinit private var statusChecker: Runnable
|
||||||
|
var nextPodWarningCheck : Long = 0
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val BOLUS_RETRY_INTERVAL_MS = 2000.toLong()
|
private const val BOLUS_RETRY_INTERVAL_MS = 2000.toLong()
|
||||||
private const val BOLUS_RETRIES = 5 // numer of retries for cancel/get bolus status
|
private const val BOLUS_RETRIES = 5 // number of retries for cancel/get bolus status
|
||||||
|
private const val STATUS_CHECK_INTERVAL_MS = (60L * 1000)
|
||||||
|
|
||||||
private val pluginDescription = PluginDescription()
|
private val pluginDescription = PluginDescription()
|
||||||
.mainType(PluginType.PUMP)
|
.mainType(PluginType.PUMP)
|
||||||
|
@ -84,6 +91,52 @@ class OmnipodDashPumpPlugin @Inject constructor(
|
||||||
private val pumpDescription = PumpDescription(PumpType.OMNIPOD_DASH)
|
private val pumpDescription = PumpDescription(PumpType.OMNIPOD_DASH)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
statusChecker = Runnable {
|
||||||
|
refreshStatusOnUnacknowledgedCommands()
|
||||||
|
updatePodWarnings()
|
||||||
|
handler.postDelayed(statusChecker, STATUS_CHECK_INTERVAL_MS)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun updatePodWarnings() {
|
||||||
|
if (System.currentTimeMillis() > nextPodWarningCheck) {
|
||||||
|
if (!podStateManager.isPodRunning) {
|
||||||
|
val notification =
|
||||||
|
Notification(
|
||||||
|
Notification.OMNIPOD_POD_NOT_ATTACHED,
|
||||||
|
"Pod not activated",
|
||||||
|
Notification.NORMAL
|
||||||
|
)
|
||||||
|
rxBus.send(EventNewNotification(notification))
|
||||||
|
} else {
|
||||||
|
rxBus.send(EventDismissNotification(Notification.OMNIPOD_POD_NOT_ATTACHED))
|
||||||
|
if (podStateManager.isSuspended) {
|
||||||
|
val notification =
|
||||||
|
Notification(
|
||||||
|
Notification.OMNIPOD_POD_SUSPENDED,
|
||||||
|
"Insulin delivery suspended",
|
||||||
|
Notification.NORMAL
|
||||||
|
)
|
||||||
|
rxBus.send(EventNewNotification(notification))
|
||||||
|
} else {
|
||||||
|
rxBus.send(EventDismissNotification(Notification.OMNIPOD_POD_SUSPENDED))
|
||||||
|
// TODO: time out of sync notification?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
nextPodWarningCheck = DateTimeUtil.getTimeInFutureFromMinutes(15)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun refreshStatusOnUnacknowledgedCommands() {
|
||||||
|
if (podStateManager.isPodRunning &&
|
||||||
|
podStateManager.activeCommand != null &&
|
||||||
|
commandQueue.size() == 0 &&
|
||||||
|
commandQueue.performing() == null) {
|
||||||
|
commandQueue.readStatus("Unconfirmed command", null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun isInitialized(): Boolean {
|
override fun isInitialized(): Boolean {
|
||||||
// TODO
|
// TODO
|
||||||
return true
|
return true
|
||||||
|
@ -129,8 +182,11 @@ class OmnipodDashPumpPlugin @Inject constructor(
|
||||||
// TODO
|
// TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
override fun getPumpStatus(reason: String) {
|
override fun getPumpStatus(reason: String) {
|
||||||
if (reason != "REQUESTED BY USER" && !podStateManager.isActivationCompleted) {
|
aapsLogger.debug(LTag.PUMP, "getPumpStatus reason=$reason")
|
||||||
|
if (reason != "REQUESTED BY USER" && !podStateManager.isActivationCompleted) {
|
||||||
// prevent races on BLE when the pod is not activated
|
// prevent races on BLE when the pod is not activated
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -140,6 +196,13 @@ class OmnipodDashPumpPlugin @Inject constructor(
|
||||||
aapsLogger.error(LTag.PUMP, "Error in getPumpStatus", throwable)
|
aapsLogger.error(LTag.PUMP, "Error in getPumpStatus", throwable)
|
||||||
} else {
|
} else {
|
||||||
aapsLogger.info(LTag.PUMP, "getPumpStatus executed with success")
|
aapsLogger.info(LTag.PUMP, "getPumpStatus executed with success")
|
||||||
|
if (!podStateManager.isActivationCompleted) {
|
||||||
|
val msg = podStateManager.recoverActivationFromPodStatus()
|
||||||
|
msg?.let {
|
||||||
|
// TODO: show dialog with "try again, the pod is busy now"
|
||||||
|
aapsLogger.info(LTag.PUMP, "recoverActivationFromPodStatus msg=$msg")
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -201,6 +264,7 @@ class OmnipodDashPumpPlugin @Inject constructor(
|
||||||
if (!podStateManager.isActivationCompleted) {
|
if (!podStateManager.isActivationCompleted) {
|
||||||
return PumpEnactResult(injector).success(true).enacted(true)
|
return PumpEnactResult(injector).success(true).enacted(true)
|
||||||
}
|
}
|
||||||
|
aapsLogger.debug(LTag.PUMP, "setNewBasalProfile profile=$profile")
|
||||||
val basalProgram = mapProfileToBasalProgram(profile)
|
val basalProgram = mapProfileToBasalProgram(profile)
|
||||||
var deliverySuspended = false
|
var deliverySuspended = false
|
||||||
return executeProgrammingCommand(
|
return executeProgrammingCommand(
|
||||||
|
@ -262,7 +326,7 @@ class OmnipodDashPumpPlugin @Inject constructor(
|
||||||
rxBus.send(EventTempBasalChange())
|
rxBus.send(EventTempBasalChange())
|
||||||
}
|
}
|
||||||
.ignoreElements()
|
.ignoreElements()
|
||||||
).doFinally {
|
).doOnComplete {
|
||||||
notifyOnUnconfirmed(
|
notifyOnUnconfirmed(
|
||||||
Notification.FAILED_UPDATE_PROFILE,
|
Notification.FAILED_UPDATE_PROFILE,
|
||||||
"Suspend delivery is unconfirmed! " +
|
"Suspend delivery is unconfirmed! " +
|
||||||
|
@ -272,16 +336,15 @@ class OmnipodDashPumpPlugin @Inject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* override fun onStop() {
|
|
||||||
super.onStop()
|
|
||||||
disposable.clear()
|
|
||||||
}
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
override fun onStart() {
|
override fun onStart() {
|
||||||
super.onStart()
|
super.onStart()
|
||||||
podStateManager.onStart()
|
podStateManager.onStart()
|
||||||
|
handler.postDelayed(statusChecker, STATUS_CHECK_INTERVAL_MS)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onStop() {
|
||||||
|
super.onStop()
|
||||||
|
handler.removeCallbacks(statusChecker)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun observeDeliverySuspended(): Completable = Completable.defer {
|
private fun observeDeliverySuspended(): Completable = Completable.defer {
|
||||||
|
@ -673,10 +736,11 @@ class OmnipodDashPumpPlugin @Inject constructor(
|
||||||
executeProgrammingCommand(
|
executeProgrammingCommand(
|
||||||
historyEntry = history.createRecord(OmnipodCommandType.CANCEL_TEMPORARY_BASAL),
|
historyEntry = history.createRecord(OmnipodCommandType.CANCEL_TEMPORARY_BASAL),
|
||||||
command = omnipodManager.stopTempBasal(hasTempBasalBeepEnabled()).ignoreElements()
|
command = omnipodManager.stopTempBasal(hasTempBasalBeepEnabled()).ignoreElements()
|
||||||
).doFinally {
|
).doOnComplete {
|
||||||
notifyOnUnconfirmed(
|
notifyOnUnconfirmed(
|
||||||
Notification.OMNIPOD_TBR_ALERTS,
|
Notification.OMNIPOD_TBR_ALERTS,
|
||||||
"Setting temp basal failed. If a temp basal was previously running, it might have been cancelled. " +
|
"Cancelling temp basal might have failed." +
|
||||||
|
"If a temp basal was previously running, it might have been cancelled." +
|
||||||
"Please manually refresh the Pod status from the Omnipod tab.", // TODO: i8n
|
"Please manually refresh the Pod status from the Omnipod tab.", // TODO: i8n
|
||||||
R.raw.boluserror,
|
R.raw.boluserror,
|
||||||
)
|
)
|
||||||
|
@ -734,6 +798,7 @@ class OmnipodDashPumpPlugin @Inject constructor(
|
||||||
|
|
||||||
private fun notifyOnUnconfirmed(notificationId: Int, msg: String, sound: Int?) {
|
private fun notifyOnUnconfirmed(notificationId: Int, msg: String, sound: Int?) {
|
||||||
if (podStateManager.activeCommand != null) {
|
if (podStateManager.activeCommand != null) {
|
||||||
|
aapsLogger.debug(LTag.PUMP, "Notification for active command: ${podStateManager.activeCommand}")
|
||||||
showNotification(notificationId, msg, Notification.URGENT, sound)
|
showNotification(notificationId, msg, Notification.URGENT, sound)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -877,7 +942,7 @@ class OmnipodDashPumpPlugin @Inject constructor(
|
||||||
.ignoreElements()
|
.ignoreElements()
|
||||||
).doFinally {
|
).doFinally {
|
||||||
notifyOnUnconfirmed(
|
notifyOnUnconfirmed(
|
||||||
Notification.PUMP_ERROR,
|
Notification.FAILED_UPDATE_PROFILE,
|
||||||
"Unconfirmed resumeDelivery command. Please refresh pod status",
|
"Unconfirmed resumeDelivery command. Please refresh pod status",
|
||||||
R.raw.boluserror
|
R.raw.boluserror
|
||||||
)
|
)
|
||||||
|
@ -972,7 +1037,18 @@ class OmnipodDashPumpPlugin @Inject constructor(
|
||||||
val historyEntry = history.getById(command.historyId)
|
val historyEntry = history.getById(command.historyId)
|
||||||
aapsLogger.debug(LTag.PUMPCOMM, "handling command confirmation: $confirmation")
|
aapsLogger.debug(LTag.PUMPCOMM, "handling command confirmation: $confirmation")
|
||||||
when (historyEntry.commandType) {
|
when (historyEntry.commandType) {
|
||||||
OmnipodCommandType.CANCEL_TEMPORARY_BASAL,
|
OmnipodCommandType.CANCEL_TEMPORARY_BASAL -> {
|
||||||
|
if (confirmation.success) {
|
||||||
|
pumpSync.syncStopTemporaryBasalWithPumpId(
|
||||||
|
historyEntry.createdAt,
|
||||||
|
historyEntry.pumpId(),
|
||||||
|
PumpType.OMNIPOD_DASH,
|
||||||
|
serialNumber()
|
||||||
|
)
|
||||||
|
podStateManager.tempBasal = null
|
||||||
|
}
|
||||||
|
rxBus.send(EventDismissNotification(Notification.OMNIPOD_TBR_ALERTS))
|
||||||
|
}
|
||||||
OmnipodCommandType.RESUME_DELIVERY -> {
|
OmnipodCommandType.RESUME_DELIVERY -> {
|
||||||
// We can't invalidate this command,
|
// We can't invalidate this command,
|
||||||
// and this is why it is pumpSync-ed at this point
|
// and this is why it is pumpSync-ed at this point
|
||||||
|
@ -984,6 +1060,7 @@ class OmnipodDashPumpPlugin @Inject constructor(
|
||||||
serialNumber()
|
serialNumber()
|
||||||
)
|
)
|
||||||
podStateManager.tempBasal = null
|
podStateManager.tempBasal = null
|
||||||
|
rxBus.send(EventDismissNotification(Notification.OMNIPOD_POD_SUSPENDED))
|
||||||
}
|
}
|
||||||
rxBus.send(EventDismissNotification(Notification.OMNIPOD_TBR_ALERTS))
|
rxBus.send(EventDismissNotification(Notification.OMNIPOD_TBR_ALERTS))
|
||||||
}
|
}
|
||||||
|
@ -1004,8 +1081,10 @@ class OmnipodDashPumpPlugin @Inject constructor(
|
||||||
PumpType.OMNIPOD_DASH,
|
PumpType.OMNIPOD_DASH,
|
||||||
serialNumber()
|
serialNumber()
|
||||||
)
|
)
|
||||||
|
rxBus.send(EventDismissNotification(Notification.OMNIPOD_POD_SUSPENDED))
|
||||||
|
rxBus.send(EventDismissNotification(Notification.FAILED_UPDATE_PROFILE))
|
||||||
|
rxBus.send(EventDismissNotification(Notification.OMNIPOD_TBR_ALERTS))
|
||||||
}
|
}
|
||||||
rxBus.send(EventDismissNotification(Notification.OMNIPOD_TBR_ALERTS))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
OmnipodCommandType.SET_TEMPORARY_BASAL -> {
|
OmnipodCommandType.SET_TEMPORARY_BASAL -> {
|
||||||
|
|
|
@ -173,8 +173,7 @@ class OmnipodDashManagerImpl @Inject constructor(
|
||||||
DefaultStatusResponse::class
|
DefaultStatusResponse::class
|
||||||
)
|
)
|
||||||
}.doOnComplete {
|
}.doOnComplete {
|
||||||
// TODO: remove podStateManager.basalProgram?
|
podStateManager.timeZone = TimeZone.getDefault()
|
||||||
podStateManager.basalProgram = basalProgram
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -246,6 +245,7 @@ class OmnipodDashManagerImpl @Inject constructor(
|
||||||
observeVerifyPrime.doOnComplete(ActivationProgressUpdater(ActivationProgress.PRIME_COMPLETED))
|
observeVerifyPrime.doOnComplete(ActivationProgressUpdater(ActivationProgress.PRIME_COMPLETED))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (podStateManager.activationProgress.isBefore(ActivationProgress.PRIMING)) {
|
if (podStateManager.activationProgress.isBefore(ActivationProgress.PRIMING)) {
|
||||||
observables.add(observeConnectToPod) // connection can time out while waiting
|
observables.add(observeConnectToPod) // connection can time out while waiting
|
||||||
observables.add(
|
observables.add(
|
||||||
|
@ -270,6 +270,7 @@ class OmnipodDashManagerImpl @Inject constructor(
|
||||||
}.doOnComplete(ActivationProgressUpdater(ActivationProgress.PRIMING))
|
}.doOnComplete(ActivationProgressUpdater(ActivationProgress.PRIMING))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (podStateManager.activationProgress.isBefore(ActivationProgress.REPROGRAMMED_LUMP_OF_COAL_ALERT)) {
|
if (podStateManager.activationProgress.isBefore(ActivationProgress.REPROGRAMMED_LUMP_OF_COAL_ALERT)) {
|
||||||
observables.add(
|
observables.add(
|
||||||
observeSendProgramAlertsCommand(
|
observeSendProgramAlertsCommand(
|
||||||
|
@ -304,6 +305,7 @@ class OmnipodDashManagerImpl @Inject constructor(
|
||||||
).doOnComplete(ActivationProgressUpdater(ActivationProgress.PROGRAMMED_LOW_RESERVOIR_ALERTS))
|
).doOnComplete(ActivationProgressUpdater(ActivationProgress.PROGRAMMED_LOW_RESERVOIR_ALERTS))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (podStateManager.activationProgress.isBefore(ActivationProgress.SET_UNIQUE_ID)) {
|
if (podStateManager.activationProgress.isBefore(ActivationProgress.SET_UNIQUE_ID)) {
|
||||||
observables.add(
|
observables.add(
|
||||||
observeSendSetUniqueIdCommand.doOnComplete(ActivationProgressUpdater(ActivationProgress.SET_UNIQUE_ID))
|
observeSendSetUniqueIdCommand.doOnComplete(ActivationProgressUpdater(ActivationProgress.SET_UNIQUE_ID))
|
||||||
|
|
|
@ -21,6 +21,7 @@ class ServiceDiscoverer(
|
||||||
*/
|
*/
|
||||||
fun discoverServices(): Map<CharacteristicType, BluetoothGattCharacteristic> {
|
fun discoverServices(): Map<CharacteristicType, BluetoothGattCharacteristic> {
|
||||||
logger.debug(LTag.PUMPBTCOMM, "Discovering services")
|
logger.debug(LTag.PUMPBTCOMM, "Discovering services")
|
||||||
|
bleCallbacks.startServiceDiscovery()
|
||||||
val discover = gatt.discoverServices()
|
val discover = gatt.discoverServices()
|
||||||
if (!discover) {
|
if (!discover) {
|
||||||
throw ConnectException("Could not start discovering services`")
|
throw ConnectException("Could not start discovering services`")
|
||||||
|
|
|
@ -61,6 +61,10 @@ class BleCommCallbacks(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun startServiceDiscovery() {
|
||||||
|
serviceDiscoveryComplete = CountDownLatch(1)
|
||||||
|
}
|
||||||
|
|
||||||
fun waitForServiceDiscovery(timeoutMs: Int) {
|
fun waitForServiceDiscovery(timeoutMs: Int) {
|
||||||
try {
|
try {
|
||||||
serviceDiscoveryComplete.await(timeoutMs.toLong(), TimeUnit.MILLISECONDS)
|
serviceDiscoveryComplete.await(timeoutMs.toLong(), TimeUnit.MILLISECONDS)
|
||||||
|
|
|
@ -35,11 +35,12 @@ interface OmnipodDashPodStateManager {
|
||||||
val isPodKaput: Boolean
|
val isPodKaput: Boolean
|
||||||
var bluetoothConnectionState: BluetoothConnectionState
|
var bluetoothConnectionState: BluetoothConnectionState
|
||||||
|
|
||||||
var timeZone: DateTimeZone
|
var timeZone: TimeZone
|
||||||
val lastUpdatedSystem: Long // System.currentTimeMillis()
|
val lastUpdatedSystem: Long // System.currentTimeMillis()
|
||||||
val lastStatusResponseReceived: Long
|
val lastStatusResponseReceived: Long
|
||||||
val time: DateTime?
|
val time: DateTime?
|
||||||
val timeBehind: Duration?
|
val timeDrift: Duration?
|
||||||
|
val expiry: DateTime?
|
||||||
|
|
||||||
val messageSequenceNumber: Short
|
val messageSequenceNumber: Short
|
||||||
val sequenceNumberOfLastProgrammingCommand: Short?
|
val sequenceNumberOfLastProgrammingCommand: Short?
|
||||||
|
@ -96,6 +97,12 @@ interface OmnipodDashPodStateManager {
|
||||||
fun createLastBolus(requestedUnits: Double, historyId: String, bolusType: DetailedBolusInfo.BolusType)
|
fun createLastBolus(requestedUnits: Double, historyId: String, bolusType: DetailedBolusInfo.BolusType)
|
||||||
fun markLastBolusComplete(): LastBolus?
|
fun markLastBolusComplete(): LastBolus?
|
||||||
fun onStart()
|
fun onStart()
|
||||||
|
/*
|
||||||
|
This is called only:. It overwrites activationStatus
|
||||||
|
- when activation was interrupted(application crash, killed, etc)
|
||||||
|
- after getPodStatus was successful(we have an up-to-date podStatus)
|
||||||
|
*/
|
||||||
|
fun recoverActivationFromPodStatus(): String?
|
||||||
|
|
||||||
data class ActiveCommand(
|
data class ActiveCommand(
|
||||||
val sequence: Short,
|
val sequence: Short,
|
||||||
|
|
|
@ -99,10 +99,10 @@ class OmnipodDashPodStateManagerImpl @Inject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override var timeZone: DateTimeZone
|
override var timeZone: TimeZone
|
||||||
get() = podState.timeZone
|
get() = TimeZone.getTimeZone(podState.timeZone)
|
||||||
set(tz) {
|
set(tz) {
|
||||||
podState.timeZone = tz
|
podState.timeZone = tz.getDisplayName(true, TimeZone.SHORT)
|
||||||
store()
|
store()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -189,16 +189,27 @@ class OmnipodDashPodStateManagerImpl @Inject constructor(
|
||||||
if ((activationTime != null) && (minutesSinceActivation != null)) {
|
if ((activationTime != null) && (minutesSinceActivation != null)) {
|
||||||
return DateTime(activationTime)
|
return DateTime(activationTime)
|
||||||
.plusMinutes(minutesSinceActivation.toInt())
|
.plusMinutes(minutesSinceActivation.toInt())
|
||||||
.plus(Duration(podState.lastStatusResponseReceived, System.currentTimeMillis()))
|
.plus(Duration(podState.lastUpdatedSystem, System.currentTimeMillis()))
|
||||||
}
|
}
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
override val timeBehind: Duration?
|
override val timeDrift: Duration?
|
||||||
get() {
|
get() {
|
||||||
return Duration(DateTime.now(), time)
|
return Duration(DateTime.now(), time)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override val expiry: DateTime?
|
||||||
|
// TODO: Consider storing expiry datetime in pod state saving continuously recalculating to the same value
|
||||||
|
get() {
|
||||||
|
val podLifeInHours = podLifeInHours
|
||||||
|
val activationTime = podState.activationTime
|
||||||
|
if (podLifeInHours != null && activationTime != null) {
|
||||||
|
return DateTime(podState.activationTime).plusHours(podLifeInHours.toInt())
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
override var bluetoothConnectionState: OmnipodDashPodStateManager.BluetoothConnectionState
|
override var bluetoothConnectionState: OmnipodDashPodStateManager.BluetoothConnectionState
|
||||||
get() = podState.bluetoothConnectionState
|
get() = podState.bluetoothConnectionState
|
||||||
set(bluetoothConnectionState) {
|
set(bluetoothConnectionState) {
|
||||||
|
@ -312,6 +323,29 @@ class OmnipodDashPodStateManagerImpl @Inject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun recoverActivationFromPodStatus(): String? {
|
||||||
|
val newActivationProgress = when (podState.podStatus) {
|
||||||
|
PodStatus.FILLED ->
|
||||||
|
ActivationProgress.NOT_STARTED
|
||||||
|
PodStatus.UID_SET ->
|
||||||
|
ActivationProgress.SET_UNIQUE_ID
|
||||||
|
PodStatus.ENGAGING_CLUTCH_DRIVE, PodStatus.PRIMING ->
|
||||||
|
return "Busy"
|
||||||
|
PodStatus.CLUTCH_DRIVE_ENGAGED ->
|
||||||
|
ActivationProgress.PRIME_COMPLETED
|
||||||
|
PodStatus.BASAL_PROGRAM_SET ->
|
||||||
|
ActivationProgress.PROGRAMMED_BASAL
|
||||||
|
PodStatus.RUNNING_ABOVE_MIN_VOLUME, PodStatus.RUNNING_BELOW_MIN_VOLUME ->
|
||||||
|
ActivationProgress.CANNULA_INSERTED
|
||||||
|
else ->
|
||||||
|
null
|
||||||
|
}
|
||||||
|
newActivationProgress?.let {
|
||||||
|
podState.activationProgress = it
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
@Synchronized
|
@Synchronized
|
||||||
override fun updateActiveCommand() = Maybe.create<CommandConfirmed> { source ->
|
override fun updateActiveCommand() = Maybe.create<CommandConfirmed> { source ->
|
||||||
val activeCommand = podState.activeCommand
|
val activeCommand = podState.activeCommand
|
||||||
|
@ -402,6 +436,7 @@ class OmnipodDashPodStateManagerImpl @Inject constructor(
|
||||||
podState.lastStatusResponseReceived = now + 2
|
podState.lastStatusResponseReceived = now + 2
|
||||||
podState.activeCommand = newCommand
|
podState.activeCommand = newCommand
|
||||||
}
|
}
|
||||||
|
|
||||||
CommandSendingNotConfirmed -> {
|
CommandSendingNotConfirmed -> {
|
||||||
val now = System.currentTimeMillis()
|
val now = System.currentTimeMillis()
|
||||||
val newCommand = podState.activeCommand?.copy(
|
val newCommand = podState.activeCommand?.copy(
|
||||||
|
@ -410,10 +445,10 @@ class OmnipodDashPodStateManagerImpl @Inject constructor(
|
||||||
)
|
)
|
||||||
podState.lastStatusResponseReceived = 0
|
podState.lastStatusResponseReceived = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
CommandSendingFailure, NoActiveCommand ->
|
CommandSendingFailure, NoActiveCommand ->
|
||||||
podState.activeCommand = null
|
podState.activeCommand = null
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun updateFromDefaultStatusResponse(response: DefaultStatusResponse) {
|
override fun updateFromDefaultStatusResponse(response: DefaultStatusResponse) {
|
||||||
|
@ -431,6 +466,9 @@ class OmnipodDashPodStateManagerImpl @Inject constructor(
|
||||||
podState.lastUpdatedSystem = System.currentTimeMillis()
|
podState.lastUpdatedSystem = System.currentTimeMillis()
|
||||||
podState.lastStatusResponseReceived = SystemClock.elapsedRealtime()
|
podState.lastStatusResponseReceived = SystemClock.elapsedRealtime()
|
||||||
updateLastBolusFromResponse(response.bolusPulsesRemaining)
|
updateLastBolusFromResponse(response.bolusPulsesRemaining)
|
||||||
|
if (podState.activationTime == null) {
|
||||||
|
podState.activationTime = System.currentTimeMillis() - (response.minutesSinceActivation * 60000)
|
||||||
|
}
|
||||||
|
|
||||||
store()
|
store()
|
||||||
rxBus.send(EventOmnipodDashPumpValuesChanged())
|
rxBus.send(EventOmnipodDashPumpValuesChanged())
|
||||||
|
@ -479,12 +517,6 @@ class OmnipodDashPodStateManagerImpl @Inject constructor(
|
||||||
podState.uniqueId = response.uniqueIdReceivedInCommand
|
podState.uniqueId = response.uniqueIdReceivedInCommand
|
||||||
|
|
||||||
podState.lastUpdatedSystem = System.currentTimeMillis()
|
podState.lastUpdatedSystem = System.currentTimeMillis()
|
||||||
// TODO: what is considered to be the pod activation time?
|
|
||||||
// LTK negotiation ?
|
|
||||||
// setUniqueId?
|
|
||||||
// compute it from the number of "minutesOnPod"?
|
|
||||||
podState.activationTime = System.currentTimeMillis()
|
|
||||||
|
|
||||||
store()
|
store()
|
||||||
rxBus.send(EventOmnipodDashPumpValuesChanged())
|
rxBus.send(EventOmnipodDashPumpValuesChanged())
|
||||||
}
|
}
|
||||||
|
@ -565,7 +597,7 @@ class OmnipodDashPodStateManagerImpl @Inject constructor(
|
||||||
var ltk: ByteArray? = null
|
var ltk: ByteArray? = null
|
||||||
var eapAkaSequenceNumber: Long = 1
|
var eapAkaSequenceNumber: Long = 1
|
||||||
var bolusPulsesRemaining: Short = 0
|
var bolusPulsesRemaining: Short = 0
|
||||||
var timeZone = DateTimeZone.getDefault()
|
var timeZone: String = "" // TimeZone ID (e.g. "Europe/Amsterdam")
|
||||||
|
|
||||||
var bleVersion: SoftwareVersion? = null
|
var bleVersion: SoftwareVersion? = null
|
||||||
var firmwareVersion: SoftwareVersion? = null
|
var firmwareVersion: SoftwareVersion? = null
|
||||||
|
|
|
@ -125,7 +125,7 @@ class DashPodManagementActivity : NoSplashAppCompatActivity() {
|
||||||
|
|
||||||
binding.buttonActivatePod.isEnabled = podStateManager.activationProgress.isBefore(ActivationProgress.COMPLETED)
|
binding.buttonActivatePod.isEnabled = podStateManager.activationProgress.isBefore(ActivationProgress.COMPLETED)
|
||||||
binding.buttonDeactivatePod.isEnabled =
|
binding.buttonDeactivatePod.isEnabled =
|
||||||
podStateManager.activationProgress.isAtLeast(ActivationProgress.SET_UNIQUE_ID) ||
|
podStateManager.ltk != null ||
|
||||||
podStateManager.podStatus == PodStatus.ALARM
|
podStateManager.podStatus == PodStatus.ALARM
|
||||||
|
|
||||||
if (podStateManager.activationProgress.isAtLeast(ActivationProgress.PHASE_1_COMPLETED)) {
|
if (podStateManager.activationProgress.isAtLeast(ActivationProgress.PHASE_1_COMPLETED)) {
|
||||||
|
|
|
@ -45,7 +45,6 @@ import io.reactivex.disposables.CompositeDisposable
|
||||||
import io.reactivex.rxkotlin.plusAssign
|
import io.reactivex.rxkotlin.plusAssign
|
||||||
import org.apache.commons.lang3.StringUtils
|
import org.apache.commons.lang3.StringUtils
|
||||||
import org.joda.time.DateTime
|
import org.joda.time.DateTime
|
||||||
import org.joda.time.DateTimeZone
|
|
||||||
import org.joda.time.Duration
|
import org.joda.time.Duration
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
@ -69,7 +68,7 @@ class OmnipodDashOverviewFragment : DaggerFragment() {
|
||||||
|
|
||||||
private const val REFRESH_INTERVAL_MILLIS = 15 * 1000L // 15 seconds
|
private const val REFRESH_INTERVAL_MILLIS = 15 * 1000L // 15 seconds
|
||||||
private const val PLACEHOLDER = "-"
|
private const val PLACEHOLDER = "-"
|
||||||
private const val MAX_TIME_DEVIATION_MINUTES = 15L
|
private const val MAX_TIME_DEVIATION_MINUTES = 10L
|
||||||
}
|
}
|
||||||
|
|
||||||
private var disposables: CompositeDisposable = CompositeDisposable()
|
private var disposables: CompositeDisposable = CompositeDisposable()
|
||||||
|
@ -237,31 +236,6 @@ class OmnipodDashOverviewFragment : DaggerFragment() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get time on pod from activation time and minutes since activation
|
|
||||||
private fun getTimeOnPod(): DateTime? {
|
|
||||||
var timeOnPod: DateTime? = null
|
|
||||||
val minutesSinceActivation = podStateManager.minutesSinceActivation
|
|
||||||
val activationTime = podStateManager.activationTime
|
|
||||||
if ((activationTime != null) && (minutesSinceActivation != null)) {
|
|
||||||
timeOnPod = DateTime(activationTime)
|
|
||||||
.plusMinutes(minutesSinceActivation.toInt())
|
|
||||||
.plus(Duration(podStateManager.lastStatusResponseReceived, System.currentTimeMillis()))
|
|
||||||
}
|
|
||||||
return timeOnPod
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Consider storing expiry datetime in pod state saving continuesly recalculating to the same value
|
|
||||||
private fun getExpiryAt(): DateTime? {
|
|
||||||
var expiresAt: DateTime? = null
|
|
||||||
val podLifeInHours = podStateManager.podLifeInHours
|
|
||||||
val minutesSinceActivation = podStateManager.minutesSinceActivation
|
|
||||||
if (podLifeInHours != null && minutesSinceActivation != null) {
|
|
||||||
val expiresInMinutes = podLifeInHours * 60 - minutesSinceActivation
|
|
||||||
expiresAt = DateTime().plusMinutes(expiresInMinutes)
|
|
||||||
}
|
|
||||||
return expiresAt
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun updateOmnipodStatus() {
|
private fun updateOmnipodStatus() {
|
||||||
updateLastConnection()
|
updateLastConnection()
|
||||||
updateLastBolus()
|
updateLastBolus()
|
||||||
|
@ -294,35 +268,34 @@ class OmnipodDashOverviewFragment : DaggerFragment() {
|
||||||
)
|
)
|
||||||
|
|
||||||
// Update time on Pod
|
// Update time on Pod
|
||||||
// TODO: For now: derive from podStateManager.minutesSinceActivation
|
podInfoBinding.timeOnPod.text = podStateManager.time?.let {
|
||||||
val timeOnPod = getTimeOnPod()
|
|
||||||
podInfoBinding.timeOnPod.text = podStateManager.time?.let{
|
|
||||||
readableZonedTime(it)
|
readableZonedTime(it)
|
||||||
} ?: PLACEHOLDER
|
} ?: PLACEHOLDER
|
||||||
|
|
||||||
podInfoBinding.timeOnPod.setTextColor(
|
podInfoBinding.timeOnPod.setTextColor(
|
||||||
podStateManager.timeBehind?.let {
|
podStateManager.timeDrift?.let {
|
||||||
if (it.abs().isLongerThan(Duration.standardMinutes(MAX_TIME_DEVIATION_MINUTES))) {
|
if (it.abs().isLongerThan(Duration.standardMinutes(MAX_TIME_DEVIATION_MINUTES))) {
|
||||||
Color.RED
|
Color.RED
|
||||||
}else {
|
} else {
|
||||||
Color.WHITE
|
Color.WHITE
|
||||||
}
|
}
|
||||||
} ?: Color.WHITE
|
} ?: Color.WHITE
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
// Update Pod expiry time
|
// Update Pod expiry time
|
||||||
val expiresAt = getExpiryAt()
|
val expiresAt = podStateManager.expiry
|
||||||
if (expiresAt == null) {
|
if (expiresAt == null) {
|
||||||
podInfoBinding.podExpiryDate.text = PLACEHOLDER
|
podInfoBinding.podExpiryDate.text = PLACEHOLDER
|
||||||
podInfoBinding.podExpiryDate.setTextColor(Color.WHITE)
|
podInfoBinding.podExpiryDate.setTextColor(Color.WHITE)
|
||||||
} else {
|
} else {
|
||||||
podInfoBinding.podExpiryDate.text = readableZonedTime(expiresAt)
|
podInfoBinding.podExpiryDate.text = readableZonedTime(expiresAt)
|
||||||
podInfoBinding.podExpiryDate.setTextColor(if (DateTime.now().isAfter(expiresAt)) {
|
podInfoBinding.podExpiryDate.setTextColor(
|
||||||
Color.RED
|
if (DateTime.now().isAfter(expiresAt)) {
|
||||||
} else {
|
Color.RED
|
||||||
Color.WHITE
|
} else {
|
||||||
})
|
Color.WHITE
|
||||||
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
podStateManager.alarmType?.let {
|
podStateManager.alarmType?.let {
|
||||||
|
@ -413,9 +386,7 @@ class OmnipodDashOverviewFragment : DaggerFragment() {
|
||||||
podInfoBinding.lastConnection.setTextColor(lastConnectionColor)
|
podInfoBinding.lastConnection.setTextColor(lastConnectionColor)
|
||||||
} else {
|
} else {
|
||||||
podInfoBinding.lastConnection.setTextColor(Color.WHITE)
|
podInfoBinding.lastConnection.setTextColor(Color.WHITE)
|
||||||
podInfoBinding.lastConnection.text = readableDuration(
|
podInfoBinding.lastConnection.text = PLACEHOLDER
|
||||||
Duration(podStateManager.lastUpdatedSystem, System.currentTimeMillis())
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -552,7 +523,6 @@ class OmnipodDashOverviewFragment : DaggerFragment() {
|
||||||
private fun updateRefreshStatusButton() {
|
private fun updateRefreshStatusButton() {
|
||||||
buttonBinding.buttonRefreshStatus.isEnabled =
|
buttonBinding.buttonRefreshStatus.isEnabled =
|
||||||
podStateManager.isUniqueIdSet &&
|
podStateManager.isUniqueIdSet &&
|
||||||
podStateManager.activationProgress.isAtLeast(ActivationProgress.PHASE_1_COMPLETED) &&
|
|
||||||
isQueueEmpty()
|
isQueueEmpty()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -630,25 +600,41 @@ class OmnipodDashOverviewFragment : DaggerFragment() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getTimeZone(): DateTimeZone {
|
// private fun getTimeZone(): DateTimeZone {
|
||||||
// TODO: Get timezone as configured/podState
|
// // return getSafe(() -> podState.getTimeZone());
|
||||||
// return getSafe(() -> podState.getTimeZone());
|
// return podStateManager.timeZone
|
||||||
return DateTimeZone.getDefault()
|
// }
|
||||||
|
private fun getTimeZone(): TimeZone {
|
||||||
|
// Return timezone ID (e.g "Europe/Amsterdam")
|
||||||
|
return podStateManager.timeZone
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun readableZonedTime(time: DateTime): String {
|
private fun readableZonedTime(time: DateTime): String {
|
||||||
val timeAsJavaData = time.toLocalDateTime().toDate()
|
val timeAsJavaData = time.toLocalDateTime().toDate()
|
||||||
|
return dateUtil.dateAndTimeString(timeAsJavaData.time)
|
||||||
|
|
||||||
val timeZone = getTimeZone().toTimeZone()
|
// // TODO: Handle timeZone ID
|
||||||
if (timeZone == TimeZone.getDefault()) {
|
// val timeZone = getTimeZone()
|
||||||
return dateUtil.dateAndTimeString(timeAsJavaData.time)
|
// if (timeZone == "") {
|
||||||
}
|
// // No timezone defined, use local time (default)
|
||||||
|
// return dateUtil.dateAndTimeString(timeAsJavaData.time)
|
||||||
// Get full timezoned time
|
// }
|
||||||
val isDaylightTime = timeZone.inDaylightTime(timeAsJavaData)
|
// else {
|
||||||
val locale = resources.configuration.locales.get(0)
|
// // Get full timezoned time
|
||||||
val timeZoneDisplayName = timeZone.getDisplayName(isDaylightTime, TimeZone.SHORT, locale) + " " + timeZone.getDisplayName(isDaylightTime, TimeZone.LONG, locale)
|
// val isDaylightTime = timeZone.inDaylightTime(timeAsJavaData)
|
||||||
return resourceHelper.gs(R.string.omnipod_common_time_with_timezone, dateUtil.dateAndTimeString(timeAsJavaData.time), timeZoneDisplayName)
|
// val locale = resources.configuration.locales.get(0)
|
||||||
|
// val timeZoneDisplayName =
|
||||||
|
// timeZone.getDisplayName(isDaylightTime, TimeZone.SHORT, locale) + " " + timeZone.getDisplayName(
|
||||||
|
// isDaylightTime,
|
||||||
|
// TimeZone.LONG,
|
||||||
|
// locale
|
||||||
|
// )
|
||||||
|
// return resourceHelper.gs(
|
||||||
|
// R.string.omnipod_common_time_with_timezone,
|
||||||
|
// dateUtil.dateAndTimeString(timeAsJavaData.time),
|
||||||
|
// timeZoneDisplayName
|
||||||
|
// )
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun readableDuration(duration: Duration): String {
|
private fun readableDuration(duration: Duration): String {
|
||||||
|
|
|
@ -2,13 +2,17 @@ package info.nightscout.androidaps.plugins.pump.omnipod.dash.ui.wizard.activatio
|
||||||
|
|
||||||
import androidx.annotation.StringRes
|
import androidx.annotation.StringRes
|
||||||
import dagger.android.HasAndroidInjector
|
import dagger.android.HasAndroidInjector
|
||||||
|
import info.nightscout.androidaps.data.DetailedBolusInfo
|
||||||
import info.nightscout.androidaps.data.PumpEnactResult
|
import info.nightscout.androidaps.data.PumpEnactResult
|
||||||
import info.nightscout.androidaps.interfaces.ProfileFunction
|
import info.nightscout.androidaps.interfaces.ProfileFunction
|
||||||
|
import info.nightscout.androidaps.interfaces.PumpSync
|
||||||
import info.nightscout.androidaps.logging.AAPSLogger
|
import info.nightscout.androidaps.logging.AAPSLogger
|
||||||
import info.nightscout.androidaps.logging.LTag
|
import info.nightscout.androidaps.logging.LTag
|
||||||
|
import info.nightscout.androidaps.plugins.pump.common.defs.PumpType
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.common.ui.wizard.activation.viewmodel.action.InsertCannulaViewModel
|
import info.nightscout.androidaps.plugins.pump.omnipod.common.ui.wizard.activation.viewmodel.action.InsertCannulaViewModel
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.R
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.R
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.OmnipodDashManager
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.OmnipodDashManager
|
||||||
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.state.OmnipodDashPodStateManager
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.util.mapProfileToBasalProgram
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.util.mapProfileToBasalProgram
|
||||||
import io.reactivex.Single
|
import io.reactivex.Single
|
||||||
import io.reactivex.rxkotlin.subscribeBy
|
import io.reactivex.rxkotlin.subscribeBy
|
||||||
|
@ -17,6 +21,8 @@ import javax.inject.Inject
|
||||||
class DashInsertCannulaViewModel @Inject constructor(
|
class DashInsertCannulaViewModel @Inject constructor(
|
||||||
private val omnipodManager: OmnipodDashManager,
|
private val omnipodManager: OmnipodDashManager,
|
||||||
private val profileFunction: ProfileFunction,
|
private val profileFunction: ProfileFunction,
|
||||||
|
private val pumpSync: PumpSync,
|
||||||
|
private val podStateManager: OmnipodDashPodStateManager,
|
||||||
injector: HasAndroidInjector,
|
injector: HasAndroidInjector,
|
||||||
logger: AAPSLogger
|
logger: AAPSLogger
|
||||||
) : InsertCannulaViewModel(injector, logger) {
|
) : InsertCannulaViewModel(injector, logger) {
|
||||||
|
@ -52,6 +58,19 @@ class DashInsertCannulaViewModel @Inject constructor(
|
||||||
},
|
},
|
||||||
onComplete = {
|
onComplete = {
|
||||||
logger.debug("Pod activation part 2 completed")
|
logger.debug("Pod activation part 2 completed")
|
||||||
|
pumpSync.connectNewPump()
|
||||||
|
pumpSync.insertTherapyEventIfNewWithTimestamp(
|
||||||
|
timestamp = System.currentTimeMillis(),
|
||||||
|
type = DetailedBolusInfo.EventType.CANNULA_CHANGE,
|
||||||
|
pumpType = PumpType.OMNIPOD_DASH,
|
||||||
|
pumpSerial = podStateManager.uniqueId?.toString() ?: "n/a"
|
||||||
|
)
|
||||||
|
pumpSync.insertTherapyEventIfNewWithTimestamp(
|
||||||
|
timestamp = System.currentTimeMillis(),
|
||||||
|
type = DetailedBolusInfo.EventType.INSULIN_CHANGE,
|
||||||
|
pumpType = PumpType.OMNIPOD_DASH,
|
||||||
|
pumpSerial = podStateManager.uniqueId?.toString() ?: "n/a"
|
||||||
|
)
|
||||||
source.onSuccess(PumpEnactResult(injector).success(true))
|
source.onSuccess(PumpEnactResult(injector).success(true))
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
Loading…
Reference in a new issue