@@ -26,6 +26,7 @@ struct WatchBolusView: View {
2626 @State private var isError = false
2727 @State private var showCalcDetail = false
2828 @State private var showCelebration = false
29+ @State private var isRefreshing = true
2930
3031 /// The displayed amount, snapped to 0.05U increments
3132 private var amount : Double {
@@ -35,148 +36,158 @@ struct WatchBolusView: View {
3536 }
3637
3738 var body : some View {
38- VStack ( spacing: 0 ) {
39- if let result = resultMessage {
40- ZStack {
41- VStack {
42- Spacer ( )
43- Text ( result)
44- . font ( . system( size: 24 , weight: . bold) )
45- . foregroundColor ( isError ? . red : . green)
46- . multilineTextAlignment ( . center)
47- Spacer ( )
39+ ZStack {
40+ VStack ( spacing: 0 ) {
41+ if let result = resultMessage {
42+ ZStack {
43+ VStack {
44+ Spacer ( )
45+ Text ( result)
46+ . font ( . system( size: 24 , weight: . bold) )
47+ . foregroundColor ( isError ? . red : . green)
48+ . multilineTextAlignment ( . center)
49+ Spacer ( )
50+ }
51+ CelebrationOverlay ( isActive: $showCelebration)
4852 }
49- CelebrationOverlay ( isActive: $showCelebration)
50- }
51- } else if showConfirm {
52- confirmSummary
53- . padding ( . bottom, 12 )
53+ } else if showConfirm {
54+ confirmSummary
55+ . padding ( . bottom, 12 )
5456
55- CrownConfirmView ( label: confirmedAmount > 0 ? " to deliver " : " to send meal " ) {
56- sendBolusAndMeal ( )
57- }
58-
59- } else {
60- HStack {
61- Button {
62- rawCrown = max ( rawCrown - 1.0 , 0 )
63- WKInterfaceDevice . current ( ) . play ( . click)
64- } label: {
65- Text ( " − " )
66- . font ( . system( size: 16 , weight: . bold) )
67- . foregroundColor ( . blue)
68- . frame ( width: 32 , height: 32 )
69- . background ( Color . blue. opacity ( 0.3 ) )
70- . clipShape ( Circle ( ) )
57+ CrownConfirmView ( label: confirmedAmount > 0 ? " to deliver " : " to send meal " ) {
58+ sendBolusAndMeal ( )
7159 }
72- . buttonStyle ( . plain)
73- // Extra padding so the tap target doesn't bleed
74- // into the system back button zone on small watches.
75- . padding ( . leading, 8 )
7660
77- Spacer ( )
61+ } else {
62+ HStack {
63+ Button {
64+ rawCrown = max ( rawCrown - 1.0 , 0 )
65+ WKInterfaceDevice . current ( ) . play ( . click)
66+ } label: {
67+ Text ( " − " )
68+ . font ( . system( size: 16 , weight: . bold) )
69+ . foregroundColor ( . blue)
70+ . frame ( width: 32 , height: 32 )
71+ . background ( Color . blue. opacity ( 0.3 ) )
72+ . clipShape ( Circle ( ) )
73+ }
74+ . buttonStyle ( . plain)
75+ . padding ( . leading, 8 )
7876
79- Text ( " Bolus " )
80- . font ( . system( size: 16 , weight: . semibold) )
77+ Spacer ( )
8178
82- Spacer ( )
79+ Text ( " Bolus " )
80+ . font ( . system( size: 16 , weight: . semibold) )
8381
84- Button {
85- rawCrown = min ( rawCrown + 1.0 , config. maxBolus / 0.25 )
86- WKInterfaceDevice . current ( ) . play ( . click)
87- } label: {
88- Text ( " + " )
89- . font ( . system( size: 16 , weight: . bold) )
90- . foregroundColor ( . blue)
91- . frame ( width: 32 , height: 32 )
92- . background ( Color . blue. opacity ( 0.3 ) )
93- . clipShape ( Circle ( ) )
94- }
95- . buttonStyle ( . plain)
96- }
97- . padding ( . horizontal, 20 )
98- . padding ( . top, 16 )
82+ Spacer ( )
9983
100- Text ( String ( format: " %.2f U " , amount) )
101- . font ( . system( size: 60 , weight: . bold, design: . rounded) )
102- . foregroundColor ( . blue)
103- . lineLimit ( 1 )
104- . minimumScaleFactor ( 0.7 )
84+ Button {
85+ rawCrown = min ( rawCrown + 1.0 , config. maxBolus / 0.25 )
86+ WKInterfaceDevice . current ( ) . play ( . click)
87+ } label: {
88+ Text ( " + " )
89+ . font ( . system( size: 16 , weight: . bold) )
90+ . foregroundColor ( . blue)
91+ . frame ( width: 32 , height: 32 )
92+ . background ( Color . blue. opacity ( 0.3 ) )
93+ . clipShape ( Circle ( ) )
94+ }
95+ . buttonStyle ( . plain)
96+ }
97+ . padding ( . horizontal, 20 )
98+ . padding ( . top, 16 )
10599
106- HStack ( spacing: 6 ) {
107- Text ( " Calculated: \( String ( format: " %.2f " , bgFetcher. recommendedBolus) ) U " )
108- . font ( . system( size: 16 , weight: . medium) )
100+ Text ( String ( format: " %.2f U " , amount) )
101+ . font ( . system( size: 60 , weight: . bold, design: . rounded) )
109102 . foregroundColor ( . blue)
110103 . lineLimit ( 1 )
111104 . minimumScaleFactor ( 0.7 )
112- . onTapGesture {
113- rawCrown = min ( bgFetcher. recommendedBolus, config. maxBolus) / 0.25
114- }
115- if bgFetcher. bolusCalc != nil {
116- Button {
117- showCalcDetail = true
118- } label: {
119- Image ( systemName: " info.circle " )
120- . font ( . system( size: 20 ) )
121- . foregroundColor ( . blue. opacity ( 0.8 ) )
122- . frame ( width: 36 , height: 36 )
105+
106+ HStack ( spacing: 6 ) {
107+ Text ( " Calculated: \( String ( format: " %.2f " , bgFetcher. recommendedBolus) ) U " )
108+ . font ( . system( size: 16 , weight: . medium) )
109+ . foregroundColor ( . blue)
110+ . lineLimit ( 1 )
111+ . minimumScaleFactor ( 0.7 )
112+ . onTapGesture {
113+ rawCrown = min ( bgFetcher. recommendedBolus, config. maxBolus) / 0.25
114+ }
115+ if bgFetcher. bolusCalc != nil {
116+ Button {
117+ showCalcDetail = true
118+ } label: {
119+ Image ( systemName: " info.circle " )
120+ . font ( . system( size: 20 ) )
121+ . foregroundColor ( . blue. opacity ( 0.8 ) )
122+ . frame ( width: 36 , height: 36 )
123+ }
124+ . buttonStyle ( . plain)
123125 }
124- . buttonStyle ( . plain)
125126 }
126- }
127- . padding ( . leading, 8 )
128- . padding ( . top, - 8 )
127+ . padding ( . leading, 8 )
128+ . padding ( . top, - 8 )
129129
130- Button ( amount > 0 ? " Confirm " : ( pendingMeal != nil ? " Skip " : " Confirm " ) ) {
131- confirmedAmount = amount
132- showConfirm = true
130+ Button ( amount > 0 ? " Confirm " : ( pendingMeal != nil ? " Skip " : " Confirm " ) ) {
131+ confirmedAmount = amount
132+ showConfirm = true
133+ }
134+ . buttonStyle ( . borderedProminent)
135+ . tint ( . blue)
136+ . disabled ( amount <= 0 && pendingMeal == nil )
133137 }
134- . buttonStyle ( . borderedProminent)
135- . tint ( . blue)
136- . disabled ( amount <= 0 && pendingMeal == nil )
137138 }
138- }
139- . modifier ( CrownRotationModifier (
140- isActive : !showConfirm && resultMessage == nil ,
141- value : $rawCrown ,
142- from : 0 ,
143- through : config . maxBolus / 0.25 ,
144- by : 0.01 ,
145- sensitivity : . low
146- ) )
147- . onChange ( of : rawCrown ) { _ in
148- let current = amount
149- if current != lastHapticAmount {
150- lastHapticAmount = current
151- WKInterfaceDevice . current ( ) . play ( . click )
139+ . modifier ( CrownRotationModifier (
140+ isActive : !showConfirm && resultMessage == nil ,
141+ value : $rawCrown ,
142+ from : 0 ,
143+ through : config . maxBolus / 0.25 ,
144+ by : 0.01 ,
145+ sensitivity : . low
146+ ) )
147+ . onChange ( of : rawCrown ) { _ in
148+ let current = amount
149+ if current != lastHapticAmount {
150+ lastHapticAmount = current
151+ WKInterfaceDevice . current ( ) . play ( . click )
152+ }
152153 }
153- }
154- . sheet ( isPresented : $showCalcDetail ) {
155- if let calc = bgFetcher. bolusCalc {
156- BolusCalcDetailView ( calc : calc , recommended : bgFetcher . recommendedBolus )
154+ . sheet ( isPresented : $showCalcDetail ) {
155+ if let calc = bgFetcher . bolusCalc {
156+ BolusCalcDetailView ( calc: calc , recommended : bgFetcher. recommendedBolus )
157+ }
157158 }
158- }
159- . navigationBarBackButtonHidden ( showConfirm )
160- . toolbar {
161- if showConfirm {
162- ToolbarItem ( placement : . cancellationAction ) {
163- Button {
164- showConfirm = false
165- } label : {
166- Image ( systemName : " chevron.left " )
159+ . navigationBarBackButtonHidden ( showConfirm )
160+ . toolbar {
161+ if showConfirm {
162+ ToolbarItem ( placement : . cancellationAction ) {
163+ Button {
164+ showConfirm = false
165+ } label : {
166+ Image ( systemName : " chevron.left " )
167+ }
167168 }
168169 }
169170 }
170- }
171- . onAppear {
172- // If launched directly (not from meal entry), clear any stale pending carbs
173- if pendingMeal == nil {
171+ . onAppear {
172+ if pendingMeal == nil {
173+ bgFetcher. pendingCarbs = 0
174+ }
175+ isRefreshing = true
176+ bgFetcher. fetchDeviceStatus ( config: config) {
177+ bgFetcher. updateRecommendedBolus ( )
178+ isRefreshing = false
179+ }
180+ }
181+ . onDisappear {
174182 bgFetcher. pendingCarbs = 0
175183 }
176- bgFetcher. updateRecommendedBolus ( )
177- }
178- . onDisappear {
179- bgFetcher. pendingCarbs = 0
184+
185+ if isRefreshing {
186+ Color . black. opacity ( 0.6 )
187+ . ignoresSafeArea ( )
188+ ProgressView ( )
189+ . tint ( . blue)
190+ }
180191 }
181192 }
182193
0 commit comments