| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234 |
- import Charts
- import SwiftUI
- class NavigationState: ObservableObject {
- @Published var path = NavigationPath() // Tracks the navigation stack
- func resetToRoot() {
- path.removeLast(path.count) // Clears the navigation stack to return to root
- }
- }
- enum NavigationDestinations: String {
- case carbInput
- case bolusInput
- case bolusConfirm
- }
- struct TrioMainWatchView: View {
- @StateObject private var navigationState = NavigationState() // Shared navigation state
- @State private var state = WatchState()
- // misc
- @State private var currentPage: Int = 0
- @State private var rotationDegrees: Double = 0.0
- @State private var showingTempTargetSheet = false
- // view visbility
- @State private var showingTreatmentMenuSheet: Bool = false
- @State private var showingOverrideSheet: Bool = false
- // navigation flag for meal bolus combo
- @State private var continueToBolus = false
- // treatments
- @State private var selectedTreatment: TreatmentOption?
- private var trioBackgroundColor = LinearGradient(
- gradient: Gradient(colors: [Color.bgDarkBlue, Color.bgDarkerDarkBlue]),
- startPoint: .top,
- endPoint: .bottom
- )
- var body: some View {
- NavigationStack(path: $navigationState.path) {
- TabView(selection: $currentPage) {
- // Page 1: Current glucose trend in "BG bobble"
- GlucoseTrendView(state: state, rotationDegrees: rotationDegrees)
- .tag(0)
- // Page 2: Glucose chart
- GlucoseChartView(glucoseValues: state.glucoseValues)
- .tag(1)
- }
- .background(trioBackgroundColor)
- .tabViewStyle(.verticalPage)
- .digitalCrownRotation($currentPage.doubleBinding(), from: 0, through: 1, by: 1)
- .onChange(of: state.trend) { _, newTrend in
- withAnimation {
- updateRotation(for: newTrend)
- }
- }
- .onAppear {
- state.confirmationProgress = 0 // reset auth progress
- }
- .toolbar {
- ToolbarItem(placement: .topBarLeading) {
- HStack {
- Image(systemName: "syringe.fill")
- .foregroundStyle(.blue)
- Text(state.iob ?? "--")
- .foregroundStyle(.white)
- }.font(.caption)
- }
- ToolbarItem(placement: .topBarTrailing) {
- HStack {
- Text(state.cob ?? "--")
- .foregroundStyle(.white)
- Image(systemName: "fork.knife")
- .foregroundStyle(.orange)
- }.font(.caption)
- }
- ToolbarItemGroup(placement: .bottomBar) {
- Button {
- showingOverrideSheet = true
- } label: {
- Image(systemName: "clock.arrow.2.circlepath")
- .foregroundStyle(Color.primary, Color.purple)
- }
- Button {
- showingTreatmentMenuSheet = true
- } label: {
- Image(systemName: "plus")
- .foregroundStyle(Color.bgDarkerDarkBlue)
- }
- .controlSize(.large)
- .buttonStyle(WatchOSButtonStyle())
- Button {
- showingTempTargetSheet = true
- } label: {
- Image(systemName: "target")
- .foregroundStyle(.green.opacity(0.75))
- }
- }
- }
- .sheet(isPresented: $showingTreatmentMenuSheet) {
- TreatmentMenuView(selectedTreatment: $selectedTreatment) {
- handleTreatmentSelection()
- }
- .onAppear {
- continueToBolus = false
- }
- }
- .sheet(isPresented: $showingOverrideSheet) {
- OverridePresetsView(
- overridePresets: state.overridePresets,
- state: state
- )
- }
- .sheet(isPresented: $showingTempTargetSheet) {
- TempTargetPresetsView(
- tempTargetPresets: state.tempTargetPresets,
- state: state
- )
- }
- .navigationDestination(for: NavigationDestinations.self) { destination in
- switch destination {
- case .carbInput:
- CarbsInputView(
- navigationState: navigationState,
- state: state,
- continueToBolus: selectedTreatment == .mealBolusCombo
- )
- case .bolusInput:
- BolusInputView(navigationState: navigationState, state: state)
- case .bolusConfirm:
- BolusConfirmationView(
- navigationState: navigationState,
- state: state,
- bolusAmount: $state.bolusAmount,
- confirmationProgress: $state.confirmationProgress
- )
- }
- }
- .overlay(
- BolusProgressOverlay(state: state, navigationState: navigationState)
- )
- }
- }
- struct WatchOSButtonStyle: ButtonStyle {
- var backgroundGradient = LinearGradient(colors: [
- Color(red: 0.721, green: 0.341, blue: 1),
- Color(red: 0.486, green: 0.545, blue: 0.953),
- Color(red: 0.262, green: 0.733, blue: 0.914)
- ], startPoint: .topLeading, endPoint: .bottomTrailing)
- var foregroundColor: Color = .white
- var fontSize: Font = .title2
- private var is40mm: Bool {
- let size = WKInterfaceDevice.current().screenBounds.size
- return size.height < 225 && size.width < 185
- }
- func makeBody(configuration: Configuration) -> some View {
- configuration.label
- .font(fontSize)
- .fontWeight(is40mm ? .medium : .semibold)
- .padding(is40mm ? 6 : 8)
- .background(
- backgroundGradient.opacity(configuration.isPressed ? 0.8 : 1.0)
- )
- .clipShape(Circle())
- .animation(.easeInOut(duration: 0.1), value: configuration.isPressed)
- }
- }
- private func updateRotation(for trend: String?) {
- switch trend {
- case "DoubleUp",
- "SingleUp":
- rotationDegrees = -90
- case "FortyFiveUp":
- rotationDegrees = -45
- case "Flat":
- rotationDegrees = 0
- case "FortyFiveDown":
- rotationDegrees = 45
- case "DoubleDown",
- "SingleDown":
- rotationDegrees = 90
- default:
- rotationDegrees = 0
- }
- }
- private func handleTreatmentSelection() {
- showingTreatmentMenuSheet = false // Dismiss the sheet
- guard let treatment = selectedTreatment else { return }
- switch treatment {
- case .meal:
- navigationState.path.append(NavigationDestinations.carbInput)
- case .bolus:
- navigationState.path.append(NavigationDestinations.bolusInput)
- case .mealBolusCombo:
- navigationState.path.append(NavigationDestinations.carbInput)
- }
- }
- }
- extension Binding where Value == Int {
- func doubleBinding() -> Binding<Double> {
- Binding<Double>(
- get: { Double(self.wrappedValue) },
- set: { self.wrappedValue = Int($0) }
- )
- }
- }
- extension Color {
- static let bgDarkBlue = Color("Background_DarkBlue")
- static let bgDarkerDarkBlue = Color("Background_DarkerDarkBlue")
- }
- #Preview {
- TrioMainWatchView()
- }
|