| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269 |
- //
- // PairPodViewModel.swift
- // OmniKit
- //
- // Created by Pete Schwamb on 3/2/20.
- // Copyright © 2021 LoopKit Authors. All rights reserved.
- //
- import SwiftUI
- import LoopKit
- import LoopKitUI
- import OmniKit
- class PairPodViewModel: ObservableObject, Identifiable {
-
- enum NavBarButtonAction {
- case cancel
- case discard
- var text: String {
- switch self {
- case .cancel:
- return LocalizedString("Cancel", comment: "Pairing interface navigation bar button text for cancel action")
- case .discard:
- return LocalizedString("Discard Pod", comment: "Pairing interface navigation bar button text for discard pod action")
- }
- }
- func color(using guidanceColors: GuidanceColors) -> Color? {
- switch self {
- case .discard:
- return guidanceColors.critical
- case .cancel:
- return nil
- }
- }
- }
-
- enum PairPodViewModelState {
- case ready
- case pairing
- case priming(finishTime: CFTimeInterval?)
- case error(OmnipodPairingError)
- case finished
-
- var instructionsDisabled: Bool {
- switch self {
- case .ready:
- return false
- case .error(let error):
- return !error.recoverable
- default:
- return true
- }
- }
-
- var actionButtonAccessibilityLabel: String {
- switch self {
- case .ready:
- return LocalizedString("Pair pod.", comment: "Pairing action button accessibility label while ready to pair")
- case .pairing:
- return LocalizedString("Pairing.", comment: "Pairing action button accessibility label while pairing")
- case .priming:
- return LocalizedString("Priming. Please wait.", comment: "Pairing action button accessibility label while priming")
- case .error(let error):
- return String(format: "%@ %@", error.errorDescription ?? "", error.recoverySuggestion ?? "")
- case .finished:
- return LocalizedString("Pod paired successfully. Continue.", comment: "Pairing action button accessibility label when pairing succeeded")
- }
- }
-
- var nextActionButtonDescription: String {
- switch self {
- case .ready:
- return LocalizedString("Pair Pod", comment: "Pod pairing action button text while ready to pair")
- case .error:
- return LocalizedString("Retry", comment: "Pod pairing action button text while showing error")
- case .pairing:
- return LocalizedString("Pairing...", comment: "Pod pairing action button text while pairing")
- case .priming:
- return LocalizedString("Priming...", comment: "Pod pairing action button text while priming")
- case .finished:
- return LocalizedString("Continue", comment: "Pod pairing action button text when paired")
- }
- }
-
- var navBarButtonAction: NavBarButtonAction {
- return .cancel
- }
-
- var navBarVisible: Bool {
- if case .error(let error) = self {
- return error.recoverable
- }
- return true
- }
-
- var showProgressDetail: Bool {
- switch self {
- case .ready:
- return false
- default:
- return true
- }
- }
-
- var progressState: ProgressIndicatorState {
- switch self {
- case .ready, .error:
- return .hidden
- case .pairing:
- return .indeterminantProgress
- case .priming(let finishTime):
- if let finishTime {
- return .timedProgress(finishTime: finishTime)
- } else {
- return .indeterminantProgress
- }
- case .finished:
- return .completed
- }
- }
-
- var isProcessing: Bool {
- switch self {
- case .pairing, .priming:
- return true
- default:
- return false
- }
- }
-
- var isFinished: Bool {
- if case .finished = self {
- return true
- }
- return false
- }
- }
-
- var error: OmnipodPairingError? {
- if case .error(let error) = state {
- return error
- }
- return nil
- }
- @Published var state: PairPodViewModelState = .ready
-
- var podIsActivated: Bool {
- return podPairer.podCommState != .noPod
- }
-
- var backButtonHidden: Bool {
- if case .pairing = state {
- return true
- }
- if podIsActivated {
- return true
- }
- return false
- }
-
- var didFinish: (() -> Void)?
-
- var didRequestDeactivation: (() -> Void)?
-
- var didCancelSetup: (() -> Void)?
- var podPairer: PodPairer
- init(podPairer: PodPairer) {
- self.podPairer = podPairer
- // If resuming, don't wait for the button action
- if podPairer.podCommState == .activating {
- pairAndPrime()
- }
- }
- private func pairAndPrime() {
- if podPairer.podCommState == .noPod {
- state = .pairing
- } else {
- // Already paired, so resume with the prime
- state = .priming(finishTime: nil)
- }
- podPairer.pairAndPrimePod { (status) in
- DispatchQueue.main.async {
- switch status {
- case .failure(let error):
- let pairingError = OmnipodPairingError.pumpManagerError(error)
- self.state = .error(pairingError)
- case .success(let duration):
-
- if duration > 0 {
- self.state = .priming(finishTime: CACurrentMediaTime() + duration)
- DispatchQueue.main.asyncAfter(deadline: .now() + duration) {
- self.state = .finished
- }
- } else {
- self.state = .finished
- }
- }
- }
- }
- }
-
- public func continueButtonTapped() {
- switch state {
- case .error(let error):
- if !error.recoverable {
- self.didRequestDeactivation?()
- } else {
- // Retry
- pairAndPrime()
- }
- case .finished:
- didFinish?()
- default:
- pairAndPrime()
- }
- }
- }
- // Pairing recovery suggestions
- enum OmnipodPairingError : LocalizedError {
- case pumpManagerError(PumpManagerError)
-
- var recoverySuggestion: String? {
- switch self {
- case .pumpManagerError(let error):
- return error.recoverySuggestion
- }
- }
-
- var errorDescription: String? {
- switch self {
- case .pumpManagerError(let error):
- return error.errorDescription
- }
- }
-
- var recoverable: Bool {
- // switch self {
- // case .pumpManagerError(let error):
- // TODO: check which errors are recoverable
- return true
- // }
- }
- }
- public protocol PodPairer {
- func pairAndPrimePod(completion: @escaping (PumpManagerResult<TimeInterval>) -> Void)
- func discardPod(completion: @escaping (Bool) -> ())
- var podCommState: PodCommState { get }
- }
- extension OmnipodPumpManager: PodPairer {
- public func discardPod(completion: @escaping (Bool) -> ()) {
- }
-
- public func pairAndPrimePod(completion: @escaping (PumpManagerResult<TimeInterval>) -> Void) {
- pairAndPrime(completion: completion)
- }
- }
|