DeactivatePodViewModel.swift 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. //
  2. // DeactivatePodViewModel.swift
  3. // OmniKit
  4. //
  5. // Created by Pete Schwamb on 3/9/20.
  6. // Copyright © 2021 LoopKit Authors. All rights reserved.
  7. //
  8. import Foundation
  9. import LoopKitUI
  10. import OmniKit
  11. public protocol PodDeactivater {
  12. func deactivatePod(completion: @escaping (OmnipodPumpManagerError?) -> Void)
  13. func forgetPod(completion: @escaping () -> Void)
  14. }
  15. extension OmnipodPumpManager: PodDeactivater {}
  16. class DeactivatePodViewModel: ObservableObject, Identifiable {
  17. enum DeactivatePodViewModelState {
  18. case active
  19. case deactivating
  20. case resultError(DeactivationError)
  21. case finished
  22. var actionButtonAccessibilityLabel: String {
  23. switch self {
  24. case .active:
  25. return LocalizedString("Deactivate Pod", comment: "Deactivate pod action button accessibility label while ready to deactivate")
  26. case .deactivating:
  27. return LocalizedString("Deactivating.", comment: "Deactivate pod action button accessibility label while deactivating")
  28. case .resultError(let error):
  29. return String(format: "%@ %@", error.errorDescription ?? "", error.recoverySuggestion ?? "")
  30. case .finished:
  31. return LocalizedString("Pod deactivated successfully. Continue.", comment: "Deactivate pod action button accessibility label when deactivation complete")
  32. }
  33. }
  34. var actionButtonDescription: String {
  35. switch self {
  36. case .active:
  37. return LocalizedString("Deactivate Pod", comment: "Action button description for deactivate while pod still active")
  38. case .resultError:
  39. return LocalizedString("Retry", comment: "Action button description for deactivate after failed attempt")
  40. case .deactivating:
  41. return LocalizedString("Deactivating...", comment: "Action button description while deactivating")
  42. case .finished:
  43. return LocalizedString("Continue", comment: "Action button description when deactivated")
  44. }
  45. }
  46. var actionButtonStyle: ActionButton.ButtonType {
  47. switch self {
  48. case .active:
  49. return .destructive
  50. default:
  51. return .primary
  52. }
  53. }
  54. var progressState: ProgressIndicatorState {
  55. switch self {
  56. case .active, .resultError:
  57. return .hidden
  58. case .deactivating:
  59. return .indeterminantProgress
  60. case .finished:
  61. return .completed
  62. }
  63. }
  64. var showProgressDetail: Bool {
  65. switch self {
  66. case .active:
  67. return false
  68. default:
  69. return true
  70. }
  71. }
  72. var isProcessing: Bool {
  73. switch self {
  74. case .deactivating:
  75. return true
  76. default:
  77. return false
  78. }
  79. }
  80. var isFinished: Bool {
  81. if case .finished = self {
  82. return true
  83. }
  84. return false
  85. }
  86. }
  87. @Published var state: DeactivatePodViewModelState = .active
  88. var error: DeactivationError? {
  89. if case .resultError(let error) = self.state {
  90. return error
  91. }
  92. return nil
  93. }
  94. var didFinish: (() -> Void)?
  95. var didCancel: (() -> Void)?
  96. var podDeactivator: PodDeactivater
  97. var podAttachedToBody: Bool
  98. var instructionText: String
  99. init(podDeactivator: PodDeactivater, podAttachedToBody: Bool, fault: DetailedStatus?) {
  100. var text: String = ""
  101. if let faultEventCode = fault?.faultEventCode {
  102. let notificationString = faultEventCode.notificationTitle
  103. switch faultEventCode.faultType {
  104. case .exceededMaximumPodLife80Hrs, .reservoirEmpty, .occluded:
  105. // Just prepend a simple sentence with the notification string for these faults.
  106. // Other occluded related 0x6? faults will be treated as a general pod error as per the PDM.
  107. text = String(format: "%@. ", notificationString)
  108. default:
  109. // Display the fault code in decimal and hex, the fault description and the pdmRef string for other errors.
  110. text = String(format: "⚠️ %1$@ (0x%2$02X)\n%3$@\n", notificationString, faultEventCode.rawValue, faultEventCode.faultDescription)
  111. if let pdmRef = fault?.pdmRef {
  112. text += LocalizedString("Ref: ", comment: "PDM Ref string line") + pdmRef + "\n\n"
  113. }
  114. }
  115. }
  116. if podAttachedToBody {
  117. text += LocalizedString("Please deactivate the pod. When deactivation is complete, you may remove it and pair a new pod.", comment: "Instructions for deactivate pod when pod is on body")
  118. } else {
  119. text += LocalizedString("Please deactivate the pod. When deactivation is complete, you may pair a new pod.", comment: "Instructions for deactivate pod when pod not on body")
  120. }
  121. self.podDeactivator = podDeactivator
  122. self.podAttachedToBody = podAttachedToBody
  123. self.instructionText = text
  124. }
  125. public func continueButtonTapped() {
  126. if case .finished = state {
  127. didFinish?()
  128. } else {
  129. self.state = .deactivating
  130. podDeactivator.deactivatePod { (error) in
  131. DispatchQueue.main.async {
  132. if let error = error {
  133. self.state = .resultError(DeactivationError.OmnipodPumpManagerError(error))
  134. } else {
  135. self.discardPod(navigateOnCompletion: false)
  136. }
  137. }
  138. }
  139. }
  140. }
  141. public func discardPod(navigateOnCompletion: Bool = true) {
  142. podDeactivator.forgetPod {
  143. DispatchQueue.main.async {
  144. if navigateOnCompletion {
  145. self.didFinish?()
  146. } else {
  147. self.state = .finished
  148. }
  149. }
  150. }
  151. }
  152. }
  153. enum DeactivationError : LocalizedError {
  154. case OmnipodPumpManagerError(OmnipodPumpManagerError)
  155. var recoverySuggestion: String? {
  156. switch self {
  157. case .OmnipodPumpManagerError:
  158. return LocalizedString("There was a problem communicating with the pod. If this problem persists, tap Discard Pod. You can then activate a new Pod.", comment: "Format string for recovery suggestion during deactivate pod.")
  159. }
  160. }
  161. var errorDescription: String? {
  162. switch self {
  163. case .OmnipodPumpManagerError(let error):
  164. return error.errorDescription
  165. }
  166. }
  167. }