BolusInputView.swift 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. import Foundation
  2. import SwiftUI
  3. import WatchKit
  4. // MARK: - Bolus Input View
  5. struct BolusInputView: View {
  6. @Environment(\.dismiss) var dismiss
  7. @State private var bolusAmount = 0.0
  8. @State private var isExternalInsulin = false
  9. @State private var showingConfirmation = false
  10. @State private var confirmationProgress = 0.0
  11. let state: WatchState
  12. var body: some View {
  13. NavigationView {
  14. if showingConfirmation {
  15. BolusConfirmationView(
  16. amount: bolusAmount,
  17. isExternal: isExternalInsulin,
  18. progress: $confirmationProgress,
  19. state: state,
  20. dismiss: dismiss
  21. )
  22. } else {
  23. VStack {
  24. Picker("Bolus", selection: $bolusAmount) {
  25. ForEach(0 ... 100, id: \.self) { number in
  26. Text(String(format: "%.1f U", Double(number) / 10))
  27. .tag(Double(number) / 10)
  28. }
  29. }
  30. Toggle("External Insulin", isOn: $isExternalInsulin)
  31. .toggleStyle(.switch)
  32. .padding(.horizontal)
  33. Button(isExternalInsulin ? "Add External Insulin" : "Add Bolus") {
  34. showingConfirmation = true
  35. }
  36. .buttonStyle(.bordered)
  37. .tint(.blue)
  38. }
  39. .navigationTitle("Add Insulin")
  40. }
  41. }
  42. }
  43. }
  44. struct BolusConfirmationView: View {
  45. let amount: Double
  46. let isExternal: Bool
  47. @Binding var progress: Double
  48. let state: WatchState
  49. let dismiss: DismissAction
  50. @FocusState private var isCrownFocused: Bool
  51. var body: some View {
  52. VStack(spacing: 10) {
  53. Text("Confirm \(isExternal ? "External Insulin" : "Bolus")")
  54. .font(.headline)
  55. Text(String(format: "%.1f U", amount))
  56. .font(.title2)
  57. .bold()
  58. Text("Scroll crown down\nto confirm")
  59. .multilineTextAlignment(.center)
  60. .font(.caption2)
  61. .foregroundStyle(.secondary)
  62. ProgressView(value: progress, total: 1.0)
  63. .tint(progress >= 1.0 ? .green : .blue)
  64. .padding(.horizontal)
  65. Text("\(Int(progress * 100))%")
  66. .font(.caption2)
  67. .foregroundStyle(.secondary)
  68. }
  69. .navigationBarBackButtonHidden(true)
  70. .focusable(true)
  71. .focused($isCrownFocused)
  72. .digitalCrownRotation(
  73. $progress,
  74. from: 0.0,
  75. through: 1.0,
  76. by: 0.05,
  77. sensitivity: .medium,
  78. isContinuous: false,
  79. isHapticFeedbackEnabled: true
  80. )
  81. .onAppear {
  82. isCrownFocused = true
  83. }
  84. .onChange(of: progress) { _, newValue in
  85. if newValue >= 1.0 {
  86. WKInterfaceDevice.current().play(.success)
  87. DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
  88. state.sendBolusRequest(Decimal(amount), isExternal: isExternal)
  89. dismiss()
  90. }
  91. } else if newValue > 0 {
  92. WKInterfaceDevice.current().play(.click)
  93. }
  94. }
  95. }
  96. }
  97. #Preview {
  98. BolusInputView(state: WatchState())
  99. }