BolusInputView.swift 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. import Foundation
  2. import SwiftUI
  3. import WatchKit
  4. // MARK: - Bolus Input View
  5. struct BolusInputView: View {
  6. @Binding var navigationPath: NavigationPath
  7. @State private var bolusAmount = 0.0
  8. let state: WatchState
  9. @FocusState private var isCrownFocused: Bool
  10. private var effectiveBolusLimit: Double {
  11. // Extract current IOB from string and convert to Double
  12. let currentIOB = Double(state.iob?.replacingOccurrences(of: " U", with: "") ?? "0") ?? 0
  13. // Calculate available IOB
  14. let availableIOB = max(0, Double(truncating: state.maxIOB as NSNumber) - currentIOB)
  15. return min(
  16. Double(truncating: state.maxBolus as NSNumber),
  17. availableIOB
  18. )
  19. }
  20. var trioBackgroundColor = LinearGradient(
  21. gradient: Gradient(colors: [Color.bgDarkBlue, Color.bgDarkerDarkBlue]),
  22. startPoint: .top,
  23. endPoint: .bottom
  24. )
  25. var body: some View {
  26. VStack {
  27. if effectiveBolusLimit == 0 {
  28. VStack(spacing: 10) {
  29. Spacer()
  30. Text("Bolus limit cannot be fetched from phone!").font(.headline)
  31. Text("Check device settings, connect to phone, and try again.").font(.caption)
  32. Spacer()
  33. }
  34. .foregroundColor(.red)
  35. .scenePadding()
  36. } else {
  37. if state.carbsAmount > 0 {
  38. HStack {
  39. Text("Carbs:").bold().font(.subheadline).padding(.leading)
  40. Text("\(state.carbsAmount) g").font(.subheadline).foregroundStyle(Color.orange)
  41. Spacer()
  42. }
  43. }
  44. Spacer()
  45. HStack {
  46. // "-" Button
  47. Button(action: {
  48. if bolusAmount > 0 { bolusAmount -= 1 }
  49. }) {
  50. Image(systemName: "minus.circle.fill")
  51. .font(.title3)
  52. .foregroundColor(.blue)
  53. }
  54. .buttonStyle(.borderless)
  55. .disabled(bolusAmount < 1)
  56. Spacer()
  57. // Display the current carb amount
  58. Text(String(format: "%.2f U", bolusAmount))
  59. .fontWeight(.bold)
  60. .font(.system(.title2, design: .rounded))
  61. .foregroundColor(bolusAmount > 0.0 && bolusAmount >= effectiveBolusLimit ? .red : .primary)
  62. .focusable(true)
  63. .focused($isCrownFocused)
  64. .digitalCrownRotation(
  65. $bolusAmount,
  66. from: 0,
  67. through: effectiveBolusLimit,
  68. by: 1, // TODO: use pump increment here
  69. sensitivity: .medium,
  70. isContinuous: false,
  71. isHapticFeedbackEnabled: true
  72. )
  73. Spacer()
  74. // "+" Button
  75. Button(action: {
  76. bolusAmount += 0.5
  77. }) {
  78. Image(systemName: "plus.circle.fill")
  79. .font(.title3)
  80. .foregroundColor(.blue)
  81. }
  82. .buttonStyle(.borderless)
  83. .disabled(bolusAmount >= effectiveBolusLimit)
  84. }.padding(.horizontal)
  85. Text("Insulin")
  86. .font(.subheadline)
  87. .foregroundColor(.secondary)
  88. .padding(.bottom)
  89. Spacer()
  90. if bolusAmount > 0.0 && bolusAmount >= effectiveBolusLimit {
  91. Text("Bolus Limit Reached!")
  92. .font(.footnote)
  93. .foregroundColor(.red)
  94. }
  95. Button("Log Bolus") {
  96. state.bolusAmount = min(bolusAmount, effectiveBolusLimit)
  97. // navigationState.path.append(NavigationDestinations.bolusConfirm)
  98. navigationPath.append(NavigationDestinations.bolusConfirm)
  99. }
  100. .buttonStyle(.bordered)
  101. .tint(.blue)
  102. .disabled(!(bolusAmount > 0.0) || bolusAmount >= effectiveBolusLimit)
  103. }
  104. }
  105. .background(trioBackgroundColor)
  106. .toolbar {
  107. ToolbarItem(placement: .topBarTrailing) {
  108. Image(systemName: "syringe.fill")
  109. .resizable()
  110. .aspectRatio(contentMode: .fit)
  111. .frame(width: 14, height: 14)
  112. .padding()
  113. .background(Color.blue)
  114. .foregroundStyle(.white)
  115. .clipShape(Circle())
  116. }
  117. }
  118. .blur(radius: state.showBolusProgressOverlay ? 3 : 0)
  119. .overlay {
  120. if state.showBolusProgressOverlay {
  121. BolusProgressOverlay(state: state) {
  122. state.shouldNavigateToRoot = false
  123. navigationPath.append(NavigationDestinations.acknowledgmentPending)
  124. }.transition(.opacity)
  125. }
  126. }
  127. }
  128. }