@@ -18,45 +18,30 @@ struct BolusEntryView: View {
1818 @EnvironmentObject private var displayGlucosePreference : DisplayGlucosePreference
1919 @Environment ( \. dismissAction) var dismiss
2020 @Environment ( \. appName) var appName
21-
21+ @Environment ( \. dynamicTypeSize) private var dynamicTypeSize
22+
2223 @ObservedObject var viewModel : BolusEntryViewModel
2324
2425 @State private var enteredBolusString = " "
25- @State private var shouldBolusEntryBecomeFirstResponder = false
26-
2726 @State private var isInteractingWithChart = false
28- @State private var isKeyboardVisible = false
29- @State private var pickerShouldExpand = false
3027 @State private var editedBolusAmount = false
3128
29+ @FocusState private var bolusFieldFocused : Bool
30+
31+ private var accessoryClearance : CGFloat {
32+ dynamicTypeSize. isAccessibilitySize ? 72 : 52
33+ }
34+
3235 var body : some View {
3336 GeometryReader { geometry in
3437 VStack ( spacing: 0 ) {
3538 List {
3639 self . chartSection
3740 self . summarySection
3841 }
39- // As of iOS 13, we can't programmatically scroll to the Bolus entry text field. This ugly hack scoots the
40- // list up instead, so the summarySection is visible and the keyboard shows when you tap "Enter Bolus".
41- // Unfortunately, after entry, the field scoots back down and remains hidden. So this is not a great solution.
42- // TODO: Fix this in Xcode 12 when we're building for iOS 14.
43- . padding ( . top, self . shouldAutoScroll ( basedOn: geometry) ? - 200 : - 28 )
4442 . insetGroupedListStyle ( )
4543
46- self . actionArea
47- . frame ( height: self . isKeyboardVisible ? 0 : nil )
48- . opacity ( self . isKeyboardVisible ? 0 : 1 )
4944 }
50- . onKeyboardStateChange { state in
51- self . isKeyboardVisible = state. height > 0
52-
53- if state. height == 0 {
54- // Ensure tapping 'Enter Bolus' can make the text field the first responder again
55- self . shouldBolusEntryBecomeFirstResponder = false
56- }
57- }
58- . keyboardAware ( )
59- . edgesIgnoringSafeArea ( self . isKeyboardVisible ? [ ] : . bottom)
6045 . navigationBarTitle ( self . title)
6146 . supportedInterfaceOrientations ( . portrait)
6247 . alert ( item: self . $viewModel. activeAlert, content: self . alert ( for: ) )
@@ -73,6 +58,14 @@ struct BolusEntryView: View {
7358 enteredBolusStringBinding. wrappedValue = newEnteredBolusString
7459 }
7560 }
61+ . safeAreaInset ( edge: . bottom, spacing: 0 ) {
62+ if bolusFieldFocused {
63+ // Reserve space so the toolbar doesn’t overlap the field
64+ Color . clear. frame ( height: accessoryClearance)
65+ } else {
66+ actionArea
67+ }
68+ }
7669 }
7770 }
7871
@@ -83,12 +76,6 @@ struct BolusEntryView: View {
8376 return Text ( " Meal Bolus " , comment: " Title for bolus entry screen when also entering carbs " )
8477 }
8578
86- private func shouldAutoScroll( basedOn geometry: GeometryProxy ) -> Bool {
87- // Taking a guess of 640 to cover iPhone SE, iPod Touch, and other smaller devices.
88- // Devices such as the iPhone 11 Pro Max do not need to auto-scroll.
89- return shouldBolusEntryBecomeFirstResponder && geometry. size. height > 640
90- }
91-
9279 private var chartSection : some View {
9380 Section {
9481 VStack ( spacing: 8 ) {
@@ -253,18 +240,27 @@ struct BolusEntryView: View {
253240 Text ( " Bolus " , comment: " Label for bolus entry row on bolus screen " )
254241 Spacer ( )
255242 HStack ( alignment: . firstTextBaseline) {
256- DismissibleKeyboardTextField (
257- text: enteredBolusStringBinding,
258- placeholder: viewModel. formatBolusAmount ( 0.0 ) ,
259- font: . preferredFont( forTextStyle: . title1) ,
260- textColor: . loopAccent,
261- textAlignment: . right,
262- keyboardType: . decimalPad,
263- shouldBecomeFirstResponder: shouldBolusEntryBecomeFirstResponder,
264- maxLength: 5 ,
265- doneButtonColor: . loopAccent,
266- textFieldDidBeginEditing: didBeginEditing
267- )
243+ TextField ( viewModel. formatBolusAmount ( 0.0 ) , text: enteredBolusStringBinding)
244+ . keyboardType ( . decimalPad)
245+ . textInputAutocapitalization ( . never)
246+ . disableAutocorrection ( true )
247+ . font ( . title)
248+ . multilineTextAlignment ( . trailing)
249+ . foregroundColor ( . loopAccent)
250+ . focused ( $bolusFieldFocused)
251+ . onTapGesture { didBeginEditing ( ) }
252+ . onChange ( of: enteredBolusString) { newValue in
253+ if newValue. count > 5 {
254+ enteredBolusString = String ( newValue. prefix ( 5 ) )
255+ viewModel. updateEnteredBolus ( enteredBolusString)
256+ }
257+ }
258+ . toolbar {
259+ ToolbarItemGroup ( placement: . keyboard) {
260+ Spacer ( )
261+ Button ( " Done " ) { bolusFieldFocused = false }
262+ }
263+ }
268264 bolusUnitsLabel
269265 }
270266 }
@@ -354,7 +350,7 @@ struct BolusEntryView: View {
354350 Button < Text > (
355351 action: {
356352 if self . viewModel. actionButtonAction == . enterBolus {
357- self . shouldBolusEntryBecomeFirstResponder = true
353+ self . bolusFieldFocused = true
358354 } else {
359355 Task {
360356 if await self . viewModel. didPressActionButton ( ) {
0 commit comments