TrioMainWatchView.swift 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. import Charts
  2. import SwiftUI
  3. struct TrioMainWatchView: View {
  4. @State private var state = WatchState()
  5. // misc
  6. @State private var currentPage: Int = 0
  7. @State private var rotationDegrees: Double = 0.0
  8. @State private var showingTempTargetSheet = false
  9. // view visbility
  10. @State private var showingTreatmentMenuSheet: Bool = false
  11. @State private var showingCarbsInputView: Bool = false
  12. @State private var showingInsulinInputView: Bool = false
  13. @State private var showingOverrideSheet: Bool = false
  14. // treatments
  15. @State private var selectedTreatment: TreatmentOptions?
  16. private var trioBackgroundColor = LinearGradient(
  17. gradient: Gradient(colors: [Color.bgDarkBlue, Color.bgDarkerDarkBlue]),
  18. startPoint: .top,
  19. endPoint: .bottom
  20. )
  21. var body: some View {
  22. NavigationStack {
  23. TabView(selection: $currentPage) {
  24. // Page 1: Current glucose trend in "BG bobble"
  25. GlucoseTrendView(state: state, rotationDegrees: rotationDegrees)
  26. .tag(0)
  27. // Page 2: Glucose chart
  28. GlucoseChartView(glucoseValues: state.glucoseValues)
  29. .tag(1)
  30. }
  31. .background(trioBackgroundColor)
  32. .tabViewStyle(.verticalPage)
  33. .digitalCrownRotation($currentPage.doubleBinding(), from: 0, through: 1, by: 1)
  34. .onChange(of: state.trend) { _, newTrend in
  35. withAnimation {
  36. updateRotation(for: newTrend)
  37. }
  38. }
  39. .toolbar {
  40. ToolbarItem(placement: .topBarLeading) {
  41. HStack {
  42. Image(systemName: "syringe.fill")
  43. .foregroundStyle(.blue)
  44. Text(state.iob ?? "--")
  45. .foregroundStyle(.white)
  46. }.font(.caption)
  47. }
  48. ToolbarItem(placement: .topBarTrailing) {
  49. HStack {
  50. Text(state.cob ?? "--")
  51. .foregroundStyle(.white)
  52. Image(systemName: "fork.knife")
  53. .foregroundStyle(.orange)
  54. }.font(.caption)
  55. }
  56. ToolbarItemGroup(placement: .bottomBar) {
  57. Button {
  58. showingOverrideSheet = true
  59. } label: {
  60. Image(systemName: "clock.arrow.2.circlepath")
  61. .foregroundStyle(Color.primary, Color.purple)
  62. }
  63. Button {
  64. showingTreatmentMenuSheet.toggle()
  65. } label: {
  66. Image(systemName: "plus")
  67. .foregroundStyle(.black)
  68. }
  69. .controlSize(.large)
  70. .buttonStyle(WatchOSButtonStyle())
  71. Button {
  72. showingTempTargetSheet = true
  73. } label: {
  74. Image(systemName: "target")
  75. .foregroundStyle(.green.opacity(0.75))
  76. }
  77. }
  78. }
  79. .sheet(isPresented: $showingTreatmentMenuSheet) {
  80. TreatmentMenuView()
  81. }
  82. .sheet(isPresented: $showingOverrideSheet) {
  83. OverridePresetsView(
  84. overridePresets: state.overridePresets,
  85. state: state
  86. )
  87. }
  88. }
  89. .sheet(isPresented: $showingTempTargetSheet) {
  90. TempTargetPresetsView(
  91. tempTargetPresets: state.tempTargetPresets,
  92. state: state
  93. )
  94. }
  95. }
  96. struct WatchOSButtonStyle: ButtonStyle {
  97. var backgroundGradient = LinearGradient(colors: [
  98. Color(red: 0.721, green: 0.341, blue: 1),
  99. Color(red: 0.486, green: 0.545, blue: 0.953),
  100. Color(red: 0.262, green: 0.733, blue: 0.914)
  101. ], startPoint: .topLeading, endPoint: .bottomTrailing)
  102. var foregroundColor: Color = .white
  103. var fontSize: Font = .title2
  104. func makeBody(configuration: Configuration) -> some View {
  105. configuration.label
  106. .font(fontSize)
  107. .fontWeight(.semibold)
  108. .padding()
  109. .background(
  110. backgroundGradient.opacity(configuration.isPressed ? 0.8 : 1.0)
  111. )
  112. .clipShape(Circle())
  113. .scaleEffect(configuration.isPressed ? 0.95 : 1.0)
  114. .animation(.easeInOut(duration: 0.1), value: configuration.isPressed)
  115. }
  116. }
  117. private func updateRotation(for trend: String?) {
  118. switch trend {
  119. case "DoubleUp",
  120. "SingleUp":
  121. rotationDegrees = -90
  122. case "FortyFiveUp":
  123. rotationDegrees = -45
  124. case "Flat":
  125. rotationDegrees = 0
  126. case "FortyFiveDown":
  127. rotationDegrees = 45
  128. case "DoubleDown",
  129. "SingleDown":
  130. rotationDegrees = 90
  131. default:
  132. rotationDegrees = 0
  133. }
  134. }
  135. }
  136. extension Binding where Value == Int {
  137. func doubleBinding() -> Binding<Double> {
  138. Binding<Double>(
  139. get: { Double(self.wrappedValue) },
  140. set: { self.wrappedValue = Int($0) }
  141. )
  142. }
  143. }
  144. extension Color {
  145. static let bgDarkBlue = Color("Background_DarkBlue")
  146. static let bgDarkerDarkBlue = Color("Background_DarkerDarkBlue")
  147. }
  148. #Preview {
  149. TrioMainWatchView()
  150. }