InsertCannulaView.swift 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. //
  2. // InsertCannulaView.swift
  3. // OmniKit
  4. //
  5. // Created by Pete Schwamb on 2/5/20.
  6. // Copyright © 2021 LoopKit Authors. All rights reserved.
  7. //
  8. import SwiftUI
  9. import LoopKitUI
  10. import SlideButton
  11. import OmniKit
  12. struct InsertCannulaView: View {
  13. @ObservedObject var viewModel: InsertCannulaViewModel
  14. @Environment(\.verticalSizeClass) var verticalSizeClass
  15. @State private var cancelModalIsPresented: Bool = false
  16. var body: some View {
  17. GuidePage(content: {
  18. VStack {
  19. LeadingImage("Pod")
  20. HStack {
  21. InstructionList(instructions: [
  22. LocalizedString("Slide the switch below to start cannula insertion.", comment: "Label text for step one of insert cannula instructions"),
  23. LocalizedString("Wait until insertion is completed.", comment: "Label text for step two of insert cannula instructions"),
  24. ])
  25. .disabled(viewModel.state.instructionsDisabled)
  26. }
  27. .padding(.bottom, 8)
  28. }
  29. .accessibility(sortPriority: 1)
  30. }) {
  31. VStack {
  32. if self.viewModel.state.showProgressDetail {
  33. self.viewModel.error.map {
  34. ErrorView($0, errorClass: $0.recoverable ? .normal : .critical)
  35. .accessibility(sortPriority: 0)
  36. }
  37. if self.viewModel.error == nil {
  38. VStack {
  39. ProgressIndicatorView(state: self.viewModel.state.progressState)
  40. if self.viewModel.state.isFinished {
  41. FrameworkLocalText("Inserted", comment: "Label text indicating insertion finished.")
  42. .bold()
  43. .padding(.top)
  44. }
  45. }
  46. .padding(.bottom, 8)
  47. }
  48. }
  49. if self.viewModel.error != nil {
  50. Button(action: {
  51. self.viewModel.didRequestDeactivation?()
  52. }) {
  53. Text(LocalizedString("Deactivate Pod", comment: "Button text for deactivate pod button"))
  54. .accessibility(identifier: "button_deactivate_pod")
  55. .actionButtonStyle(.secondary)
  56. }
  57. .disabled(self.viewModel.state.isProcessing)
  58. }
  59. if (self.viewModel.error == nil || self.viewModel.error?.recoverable == true) {
  60. actionButton
  61. .disabled(self.viewModel.state.isProcessing)
  62. .zIndex(1)
  63. }
  64. }
  65. .transition(AnyTransition.opacity.combined(with: .move(edge: .bottom)))
  66. .padding()
  67. }
  68. .alert(isPresented: $cancelModalIsPresented) { cancelPairingModal }
  69. .navigationBarTitle(LocalizedString("Insert Cannula", comment: "navigation bar title for insert cannula"), displayMode: .automatic)
  70. .navigationBarBackButtonHidden(true)
  71. .navigationBarItems(trailing: cancelButton)
  72. }
  73. var actionText : some View {
  74. Text(self.viewModel.state.nextActionButtonDescription)
  75. .accessibility(identifier: "button_next_action")
  76. .accessibility(label: Text(self.viewModel.state.actionButtonAccessibilityLabel))
  77. .font(.headline)
  78. }
  79. @ViewBuilder
  80. var actionButton: some View {
  81. if self.viewModel.stateNeedsDeliberateUserAcceptance {
  82. SlideButton(action: {
  83. self.viewModel.continueButtonTapped()
  84. }) {
  85. actionText
  86. }
  87. } else {
  88. Button(action: {
  89. self.viewModel.continueButtonTapped()
  90. }) {
  91. actionText
  92. .actionButtonStyle(.primary)
  93. }
  94. }
  95. }
  96. var cancelButton: some View {
  97. Button(LocalizedString("Cancel", comment: "Cancel button text in navigation bar on insert cannula screen")) {
  98. cancelModalIsPresented = true
  99. }
  100. .accessibility(identifier: "button_cancel")
  101. }
  102. var cancelPairingModal: Alert {
  103. return Alert(
  104. title: FrameworkLocalText("Are you sure you want to cancel Pod setup?", comment: "Alert title for cancel pairing modal"),
  105. message: FrameworkLocalText("If you cancel Pod setup, the current Pod will be deactivated and will be unusable.", comment: "Alert message body for confirm pod attachment"),
  106. primaryButton: .destructive(FrameworkLocalText("Yes, Deactivate Pod", comment: "Button title for confirm deactivation option"), action: { viewModel.didRequestDeactivation?() } ),
  107. secondaryButton: .default(FrameworkLocalText("No, Continue With Pod", comment: "Continue pairing button title of in pairing cancel modal"))
  108. )
  109. }
  110. }
  111. class MockCannulaInserter: CannulaInserter {
  112. func insertCannula(completion: @escaping (Result<TimeInterval,OmnipodPumpManagerError>) -> Void) {
  113. let mockDelay = TimeInterval(seconds: 3)
  114. let result :Result<TimeInterval, OmnipodPumpManagerError> = .success(mockDelay)
  115. completion(result)
  116. }
  117. func checkCannulaInsertionFinished(completion: @escaping (OmnipodPumpManagerError?) -> Void) {
  118. completion(nil)
  119. }
  120. var cannulaInsertionSuccessfullyStarted: Bool = false
  121. }
  122. struct InsertCannulaView_Previews: PreviewProvider {
  123. static var mockInserter = MockCannulaInserter()
  124. static var model = InsertCannulaViewModel(cannulaInserter: mockInserter)
  125. static var previews: some View {
  126. InsertCannulaView(viewModel: model)
  127. }
  128. }