BolusInputView.swift 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. import Foundation
  2. import SwiftUI
  3. import WatchKit
  4. // MARK: - Bolus Input View
  5. struct BolusInputView: View {
  6. @ObservedObject var navigationState: NavigationState
  7. @State private var bolusAmount = 0.0
  8. @State private var navigateToConfirmation = false
  9. let state: WatchState
  10. @FocusState private var isCrownFocused: Bool
  11. private var effectiveBolusLimit: Double {
  12. // Extract current IOB from string and convert to Double
  13. let currentIOB = Double(state.iob?.replacingOccurrences(of: " U", with: "") ?? "0") ?? 0
  14. // Calculate available IOB
  15. let availableIOB = max(0, Double(truncating: state.maxIOB as NSNumber) - currentIOB)
  16. return min(
  17. Double(truncating: state.maxBolus as NSNumber),
  18. availableIOB
  19. )
  20. }
  21. var body: some View {
  22. VStack {
  23. if state.carbsAmount > 0 {
  24. HStack {
  25. Text("Carbs:").bold().font(.subheadline).padding(.leading)
  26. Text("\(state.carbsAmount) g").font(.subheadline).foregroundStyle(Color.orange)
  27. Spacer()
  28. }
  29. }
  30. Spacer()
  31. HStack {
  32. // "-" Button
  33. Button(action: {
  34. if bolusAmount > 0 { bolusAmount -= 1 }
  35. }) {
  36. Image(systemName: "minus.circle.fill")
  37. .font(.title3)
  38. .foregroundColor(.blue)
  39. }
  40. .buttonStyle(.borderless)
  41. .disabled(bolusAmount < 1)
  42. Spacer()
  43. // Display the current carb amount
  44. Text(String(format: "%.2f U", bolusAmount))
  45. .fontWeight(.bold)
  46. .font(.system(.title2, design: .rounded))
  47. .foregroundColor(.primary)
  48. .focusable(true)
  49. .focused($isCrownFocused)
  50. .digitalCrownRotation(
  51. $bolusAmount,
  52. from: 0,
  53. through: effectiveBolusLimit,
  54. by: 1, // TODO: use pump increment here
  55. sensitivity: .medium,
  56. isContinuous: false,
  57. isHapticFeedbackEnabled: true
  58. )
  59. Spacer()
  60. // "+" Button
  61. Button(action: {
  62. bolusAmount += 0.5
  63. }) {
  64. Image(systemName: "plus.circle.fill")
  65. .font(.title3)
  66. .foregroundColor(.blue)
  67. }
  68. .buttonStyle(.borderless)
  69. .disabled(bolusAmount >= effectiveBolusLimit)
  70. }.padding(.horizontal)
  71. Text("Insulin")
  72. .font(.subheadline)
  73. .foregroundColor(.secondary)
  74. .padding(.bottom)
  75. Spacer()
  76. Button("Log Bolus") {
  77. state.bolusAmount = min(bolusAmount, effectiveBolusLimit)
  78. navigationState.path.append(NavigationDestinations.bolusConfirm)
  79. }
  80. .buttonStyle(.bordered)
  81. .tint(.blue)
  82. .disabled(!(bolusAmount > 0.0) || bolusAmount >= effectiveBolusLimit)
  83. }
  84. .toolbar {
  85. ToolbarItem(placement: .topBarTrailing) {
  86. Image(systemName: "syringe.fill")
  87. .resizable()
  88. .aspectRatio(contentMode: .fit)
  89. .frame(width: 14, height: 14)
  90. .padding()
  91. .background(Color.blue)
  92. .foregroundStyle(.white)
  93. .clipShape(Circle())
  94. }
  95. }
  96. }
  97. }
  98. #Preview {
  99. BolusInputView(navigationState: NavigationState(), state: WatchState())
  100. }