Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions Loop/View Controllers/StatusTableViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -380,6 +380,11 @@ final class StatusTableViewController: LoopChartsTableViewController {

override func reloadData(animated: Bool = false) {
dispatchPrecondition(condition: .onQueue(.main))

guard view.window != nil else {
return
}

// This should be kept up to date immediately
hudView?.loopCompletionHUD.lastLoopCompleted = deviceManager.loopManager.lastLoopCompleted

Expand Down
80 changes: 38 additions & 42 deletions Loop/Views/BolusEntryView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,45 +18,30 @@ struct BolusEntryView: View {
@EnvironmentObject private var displayGlucosePreference: DisplayGlucosePreference
@Environment(\.dismissAction) var dismiss
@Environment(\.appName) var appName

@Environment(\.dynamicTypeSize) private var dynamicTypeSize

@ObservedObject var viewModel: BolusEntryViewModel

@State private var enteredBolusString = ""
@State private var shouldBolusEntryBecomeFirstResponder = false

@State private var isInteractingWithChart = false
@State private var isKeyboardVisible = false
@State private var pickerShouldExpand = false
@State private var editedBolusAmount = false

@FocusState private var bolusFieldFocused: Bool

private var accessoryClearance: CGFloat {
dynamicTypeSize.isAccessibilitySize ? 72 : 52
}

var body: some View {
GeometryReader { geometry in
VStack(spacing: 0) {
List {
self.chartSection
self.summarySection
}
// As of iOS 13, we can't programmatically scroll to the Bolus entry text field. This ugly hack scoots the
// list up instead, so the summarySection is visible and the keyboard shows when you tap "Enter Bolus".
// Unfortunately, after entry, the field scoots back down and remains hidden. So this is not a great solution.
// TODO: Fix this in Xcode 12 when we're building for iOS 14.
.padding(.top, self.shouldAutoScroll(basedOn: geometry) ? -200 : -28)
.insetGroupedListStyle()

self.actionArea
.frame(height: self.isKeyboardVisible ? 0 : nil)
.opacity(self.isKeyboardVisible ? 0 : 1)
}
.onKeyboardStateChange { state in
self.isKeyboardVisible = state.height > 0

if state.height == 0 {
// Ensure tapping 'Enter Bolus' can make the text field the first responder again
self.shouldBolusEntryBecomeFirstResponder = false
}
}
.keyboardAware()
.edgesIgnoringSafeArea(self.isKeyboardVisible ? [] : .bottom)
.navigationBarTitle(self.title)
.supportedInterfaceOrientations(.portrait)
.alert(item: self.$viewModel.activeAlert, content: self.alert(for:))
Expand All @@ -73,6 +58,14 @@ struct BolusEntryView: View {
enteredBolusStringBinding.wrappedValue = newEnteredBolusString
}
}
.safeAreaInset(edge: .bottom, spacing: 0) {
if bolusFieldFocused {
// Reserve space so the toolbar doesn’t overlap the field
Color.clear.frame(height: accessoryClearance)
} else {
actionArea
}
}
}
}

Expand All @@ -83,12 +76,6 @@ struct BolusEntryView: View {
return Text("Meal Bolus", comment: "Title for bolus entry screen when also entering carbs")
}

private func shouldAutoScroll(basedOn geometry: GeometryProxy) -> Bool {
// Taking a guess of 640 to cover iPhone SE, iPod Touch, and other smaller devices.
// Devices such as the iPhone 11 Pro Max do not need to auto-scroll.
return shouldBolusEntryBecomeFirstResponder && geometry.size.height > 640
}

private var chartSection: some View {
Section {
VStack(spacing: 8) {
Expand Down Expand Up @@ -253,18 +240,27 @@ struct BolusEntryView: View {
Text("Bolus", comment: "Label for bolus entry row on bolus screen")
Spacer()
HStack(alignment: .firstTextBaseline) {
DismissibleKeyboardTextField(
text: enteredBolusStringBinding,
placeholder: viewModel.formatBolusAmount(0.0),
font: .preferredFont(forTextStyle: .title1),
textColor: .loopAccent,
textAlignment: .right,
keyboardType: .decimalPad,
shouldBecomeFirstResponder: shouldBolusEntryBecomeFirstResponder,
maxLength: 5,
doneButtonColor: .loopAccent,
textFieldDidBeginEditing: didBeginEditing
)
TextField(viewModel.formatBolusAmount(0.0), text: enteredBolusStringBinding)
.keyboardType(.decimalPad)
.textInputAutocapitalization(.never)
.disableAutocorrection(true)
.font(.title)
.multilineTextAlignment(.trailing)
.foregroundColor(.loopAccent)
.focused($bolusFieldFocused)
.onTapGesture { didBeginEditing() }
.onChange(of: enteredBolusString) { newValue in
if newValue.count > 5 {
enteredBolusString = String(newValue.prefix(5))
viewModel.updateEnteredBolus(enteredBolusString)
}
}
.toolbar {
ToolbarItemGroup(placement: .keyboard) {
Spacer()
Button("Done") { bolusFieldFocused = false }
}
}
bolusUnitsLabel
}
}
Expand Down Expand Up @@ -354,7 +350,7 @@ struct BolusEntryView: View {
Button<Text>(
action: {
if self.viewModel.actionButtonAction == .enterBolus {
self.shouldBolusEntryBecomeFirstResponder = true
self.bolusFieldFocused = true
} else {
Task {
if await self.viewModel.didPressActionButton() {
Expand Down
75 changes: 36 additions & 39 deletions Loop/Views/ManualEntryDoseView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,59 +15,47 @@ import LoopUI


struct ManualEntryDoseView: View {
@Environment(\.dynamicTypeSize) private var dynamicTypeSize

@ObservedObject var viewModel: ManualEntryDoseViewModel

@State private var enteredBolusString = ""
@State private var shouldBolusEntryBecomeFirstResponder = false

@State private var isInteractingWithChart = false
@State private var isKeyboardVisible = false

@FocusState private var bolusFieldFocused: Bool

@Environment(\.dismissAction) var dismiss

private var accessoryClearance: CGFloat {
dynamicTypeSize.isAccessibilitySize ? 72 : 52
}

var body: some View {
GeometryReader { geometry in
VStack(spacing: 0) {
List {
self.chartSection
self.summarySection
}
// As of iOS 13, we can't programmatically scroll to the Bolus entry text field. This ugly hack scoots the
// list up instead, so the summarySection is visible and the keyboard shows when you tap "Enter Bolus".
// Unfortunately, after entry, the field scoots back down and remains hidden. So this is not a great solution.
// TODO: Fix this in Xcode 12 when we're building for iOS 14.
.padding(.top, self.shouldAutoScroll(basedOn: geometry) ? -200 : -28)
.insetGroupedListStyle()

self.actionArea
.frame(height: self.isKeyboardVisible ? 0 : nil)
.opacity(self.isKeyboardVisible ? 0 : 1)
}
.onKeyboardStateChange { state in
self.isKeyboardVisible = state.height > 0

if state.height == 0 {
// Ensure tapping 'Enter Bolus' can make the text field the first responder again
self.shouldBolusEntryBecomeFirstResponder = false
}
}
.keyboardAware()
.edgesIgnoringSafeArea(self.isKeyboardVisible ? [] : .bottom)
.navigationBarTitle(self.title)
.supportedInterfaceOrientations(.portrait)
.safeAreaInset(edge: .bottom, spacing: 0) {
if bolusFieldFocused {
// Reserve space so the toolbar doesn’t overlap the field
Color.clear.frame(height: accessoryClearance)
} else {
actionArea
}
}
}
}

private var title: Text {
return Text("Log Dose", comment: "Title for dose logging screen")
}

private func shouldAutoScroll(basedOn geometry: GeometryProxy) -> Bool {
// Taking a guess of 640 to cover iPhone SE, iPod Touch, and other smaller devices.
// Devices such as the iPhone 11 Pro Max do not need to auto-scroll.
shouldBolusEntryBecomeFirstResponder && geometry.size.height < 640
}

private var chartSection: some View {
Section {
VStack(spacing: 8) {
Expand Down Expand Up @@ -189,16 +177,25 @@ struct ManualEntryDoseView: View {
Text("Bolus", comment: "Label for bolus entry row on bolus screen")
Spacer()
HStack(alignment: .firstTextBaseline) {
DismissibleKeyboardTextField(
text: typedBolusEntry,
placeholder: Self.doseAmountFormatter.string(from: 0.0)!,
font: .preferredFont(forTextStyle: .title1),
textColor: .loopAccent,
textAlignment: .right,
keyboardType: .decimalPad,
shouldBecomeFirstResponder: shouldBolusEntryBecomeFirstResponder,
maxLength: 5
)
TextField(Self.doseAmountFormatter.string(from: 0.0)!, text: typedBolusEntry)
.keyboardType(.decimalPad)
.textInputAutocapitalization(.never)
.disableAutocorrection(true)
.font(.title)
.multilineTextAlignment(.trailing)
.foregroundColor(.loopAccent)
.focused($bolusFieldFocused)
.onChange(of: enteredBolusString) { newValue in
if newValue.count > 5 {
enteredBolusString = String(newValue.prefix(5))
}
}
.toolbar {
ToolbarItemGroup(placement: .keyboard) {
Spacer()
Button("Done") { bolusFieldFocused = false }
}
}
bolusUnitsLabel
}
}
Expand Down Expand Up @@ -250,7 +247,7 @@ struct ManualEntryDoseView: View {
}
}

extension InsulinType: Labeled {
extension InsulinType: @retroactive Labeled {
public var label: String {
return title
}
Expand Down
4 changes: 2 additions & 2 deletions LoopUI/Views/DeviceStatusHUDView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ import LoopKitUI
// round the edges of the progress view
progressView.layer.cornerRadius = 2
progressView.clipsToBounds = true
progressView.layer.sublayers![1].cornerRadius = 2
progressView.subviews[1].clipsToBounds = true
progressView.layer.sublayers!.last!.cornerRadius = 2
progressView.subviews.last!.clipsToBounds = true
}
}

Expand Down