CarbsInputView.swift 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. import Foundation
  2. import SwiftUI
  3. // MARK: - Carbs Input View
  4. struct CarbsInputView: View {
  5. @Binding var navigationPath: NavigationPath
  6. @State private var carbsAmount: Double = 0.0 // Needs to be Double due to .digitalCrownRotation() stride
  7. @FocusState private var isCrownFocused: Bool // Manage crown focus
  8. let state: WatchState
  9. let continueToBolus: Bool
  10. private var effectiveCarbsLimit: Double {
  11. Double(truncating: state.maxCarbs as NSNumber)
  12. }
  13. var trioBackgroundColor = LinearGradient(
  14. gradient: Gradient(colors: [Color.bgDarkBlue, Color.bgDarkerDarkBlue]),
  15. startPoint: .top,
  16. endPoint: .bottom
  17. )
  18. var body: some View {
  19. let buttonLabel = continueToBolus ? "Proceed" : "Log Carbs"
  20. // TODO: introduce meal setting fpu enablement to conditional handle FPU
  21. VStack {
  22. Spacer()
  23. HStack {
  24. // "-" Button
  25. Button(action: {
  26. if carbsAmount > 0 {
  27. carbsAmount < 5 ? carbsAmount = 0 : (carbsAmount -= 5)
  28. }
  29. }) {
  30. Image(systemName: "minus.circle.fill")
  31. .font(.title3)
  32. .tint(.orange)
  33. }
  34. .buttonStyle(.borderless)
  35. .disabled(carbsAmount <= 0)
  36. Spacer()
  37. // Display the current carb amount
  38. Text(String(format: "%.0f g", carbsAmount))
  39. .fontWeight(.bold)
  40. .font(.system(.title2, design: .rounded))
  41. .foregroundColor(carbsAmount > 0.0 && carbsAmount >= effectiveCarbsLimit ? .loopRed : .primary)
  42. .focusable(true)
  43. .focused($isCrownFocused)
  44. .digitalCrownRotation(
  45. $carbsAmount,
  46. from: 0,
  47. through: effectiveCarbsLimit,
  48. by: 1,
  49. sensitivity: .medium,
  50. isContinuous: false,
  51. isHapticFeedbackEnabled: true
  52. )
  53. Spacer()
  54. // "+" Button
  55. Button(action: {
  56. carbsAmount = min(effectiveCarbsLimit, carbsAmount + 5)
  57. }) {
  58. Image(systemName: "plus.circle.fill")
  59. .font(.title3)
  60. .tint(.orange)
  61. }
  62. .buttonStyle(.borderless)
  63. .disabled(carbsAmount >= effectiveCarbsLimit)
  64. }.padding(.horizontal)
  65. Text("Carbohydrates")
  66. .font(.subheadline)
  67. .foregroundColor(.secondary)
  68. .padding(.bottom)
  69. Spacer()
  70. if carbsAmount > 0.0 && carbsAmount >= effectiveCarbsLimit {
  71. Text("Carbs Limit Reached!")
  72. .font(.footnote)
  73. .foregroundColor(.loopRed)
  74. }
  75. Button(buttonLabel) {
  76. if continueToBolus {
  77. state.carbsAmount = Int(min(carbsAmount, effectiveCarbsLimit))
  78. navigationPath.append(NavigationDestinations.bolusInput)
  79. } else {
  80. state.sendCarbsRequest(Int(min(carbsAmount, effectiveCarbsLimit)))
  81. navigationPath.append(NavigationDestinations.acknowledgmentPending)
  82. }
  83. }
  84. .buttonStyle(.bordered)
  85. .tint(.orange)
  86. .disabled(!(carbsAmount > 0.0) || carbsAmount > effectiveCarbsLimit)
  87. }
  88. .background(trioBackgroundColor)
  89. .toolbar {
  90. ToolbarItem(placement: .topBarTrailing) {
  91. Image(systemName: "fork.knife")
  92. .resizable()
  93. .aspectRatio(contentMode: .fit)
  94. .frame(width: 14, height: 14)
  95. .padding()
  96. .background(Color.orange)
  97. .foregroundStyle(.white)
  98. .clipShape(Circle())
  99. }
  100. }
  101. }
  102. }