diff --git a/Loop/DerivedAssetsBase.xcassets/Pre-Meal Selected.imageset/Pre-Meal Selected.pdf b/Loop/DerivedAssetsBase.xcassets/Pre-Meal Selected.imageset/Pre-Meal Selected.pdf index 8c285da0df..a55a507ca2 100644 Binary files a/Loop/DerivedAssetsBase.xcassets/Pre-Meal Selected.imageset/Pre-Meal Selected.pdf and b/Loop/DerivedAssetsBase.xcassets/Pre-Meal Selected.imageset/Pre-Meal Selected.pdf differ diff --git a/Loop/DerivedAssetsBase.xcassets/Pre-Meal.imageset/Pre-Meal.pdf b/Loop/DerivedAssetsBase.xcassets/Pre-Meal.imageset/Pre-Meal.pdf index 0992a4a286..76620abf02 100644 Binary files a/Loop/DerivedAssetsBase.xcassets/Pre-Meal.imageset/Pre-Meal.pdf and b/Loop/DerivedAssetsBase.xcassets/Pre-Meal.imageset/Pre-Meal.pdf differ diff --git a/Loop/DerivedAssetsBase.xcassets/bolus.imageset/bolus.pdf b/Loop/DerivedAssetsBase.xcassets/bolus.imageset/bolus.pdf index c9e69b5cfc..2b83db1d1e 100644 Binary files a/Loop/DerivedAssetsBase.xcassets/bolus.imageset/bolus.pdf and b/Loop/DerivedAssetsBase.xcassets/bolus.imageset/bolus.pdf differ diff --git a/Loop/DerivedAssetsBase.xcassets/carbs.imageset/Meal.pdf b/Loop/DerivedAssetsBase.xcassets/carbs.imageset/Meal.pdf index 5e1c948dad..40d01e73b2 100644 Binary files a/Loop/DerivedAssetsBase.xcassets/carbs.imageset/Meal.pdf and b/Loop/DerivedAssetsBase.xcassets/carbs.imageset/Meal.pdf differ diff --git a/Loop/DerivedAssetsBase.xcassets/settings.imageset/Contents.json b/Loop/DerivedAssetsBase.xcassets/settings.imageset/Contents.json index d5ccdb99c9..6444f236f9 100644 --- a/Loop/DerivedAssetsBase.xcassets/settings.imageset/Contents.json +++ b/Loop/DerivedAssetsBase.xcassets/settings.imageset/Contents.json @@ -1,40 +1,23 @@ { - "images" : [ + "images": [ { - "idiom" : "universal", - "filename" : "settings.png", - "scale" : "1x" + "idiom": "universal", + "filename": "settings.png", + "scale": "1x" }, { - "idiom" : "universal", - "filename" : "settings@2x.png", - "scale" : "2x" + "idiom": "universal", + "filename": "settings@2x.png", + "scale": "2x" }, { - "idiom" : "universal", - "filename" : "settings@3x.png", - "scale" : "3x" - }, - { - "idiom" : "universal", - "scale" : "1x", - "height-class" : "compact" - }, - { - "idiom" : "universal", - "filename" : "settings_compact@2x.png", - "height-class" : "compact", - "scale" : "2x" - }, - { - "idiom" : "universal", - "filename" : "settings_compact@3x.png", - "height-class" : "compact", - "scale" : "3x" + "idiom": "universal", + "filename": "settings@3x.png", + "scale": "3x" } ], - "info" : { - "version" : 1, - "author" : "xcode" + "info": { + "version": 1, + "author": "xcode" } } \ No newline at end of file diff --git a/Loop/DerivedAssetsBase.xcassets/settings.imageset/settings.png b/Loop/DerivedAssetsBase.xcassets/settings.imageset/settings.png index 14fc3623db..1f2e2d2dcf 100644 Binary files a/Loop/DerivedAssetsBase.xcassets/settings.imageset/settings.png and b/Loop/DerivedAssetsBase.xcassets/settings.imageset/settings.png differ diff --git a/Loop/DerivedAssetsBase.xcassets/settings.imageset/settings@2x.png b/Loop/DerivedAssetsBase.xcassets/settings.imageset/settings@2x.png index 2ed1757720..78e785a1ce 100644 Binary files a/Loop/DerivedAssetsBase.xcassets/settings.imageset/settings@2x.png and b/Loop/DerivedAssetsBase.xcassets/settings.imageset/settings@2x.png differ diff --git a/Loop/DerivedAssetsBase.xcassets/settings.imageset/settings@3x.png b/Loop/DerivedAssetsBase.xcassets/settings.imageset/settings@3x.png index 6ee011f3c9..4cea84a027 100644 Binary files a/Loop/DerivedAssetsBase.xcassets/settings.imageset/settings@3x.png and b/Loop/DerivedAssetsBase.xcassets/settings.imageset/settings@3x.png differ diff --git a/Loop/DerivedAssetsBase.xcassets/settings.imageset/settings_compact@2x.png b/Loop/DerivedAssetsBase.xcassets/settings.imageset/settings_compact@2x.png deleted file mode 100644 index ccac27347e..0000000000 Binary files a/Loop/DerivedAssetsBase.xcassets/settings.imageset/settings_compact@2x.png and /dev/null differ diff --git a/Loop/DerivedAssetsBase.xcassets/settings.imageset/settings_compact@3x.png b/Loop/DerivedAssetsBase.xcassets/settings.imageset/settings_compact@3x.png deleted file mode 100644 index 07fe7deb7a..0000000000 Binary files a/Loop/DerivedAssetsBase.xcassets/settings.imageset/settings_compact@3x.png and /dev/null differ diff --git a/Loop/DerivedAssetsBase.xcassets/workout-selected.imageset/workout-selected.pdf b/Loop/DerivedAssetsBase.xcassets/workout-selected.imageset/workout-selected.pdf index a340acb01d..d509265a86 100644 Binary files a/Loop/DerivedAssetsBase.xcassets/workout-selected.imageset/workout-selected.pdf and b/Loop/DerivedAssetsBase.xcassets/workout-selected.imageset/workout-selected.pdf differ diff --git a/Loop/DerivedAssetsBase.xcassets/workout.imageset/workout.pdf b/Loop/DerivedAssetsBase.xcassets/workout.imageset/workout.pdf index 251c7b3b3c..8a8f0023e2 100644 Binary files a/Loop/DerivedAssetsBase.xcassets/workout.imageset/workout.pdf and b/Loop/DerivedAssetsBase.xcassets/workout.imageset/workout.pdf differ diff --git a/Loop/View Controllers/StatusTableViewController.swift b/Loop/View Controllers/StatusTableViewController.swift index 37751e093b..a9d99f04f9 100644 --- a/Loop/View Controllers/StatusTableViewController.swift +++ b/Loop/View Controllers/StatusTableViewController.swift @@ -287,13 +287,30 @@ final class StatusTableViewController: LoopChartsTableViewController { private func makeToolbarButton(imageNamed name: String, tintColor: UIColor, action: Selector) -> UIButton { let button = UIButton(type: .system) - button.setImage(UIImage(named: name), for: .normal) + button.setImage(UIImage(named: name)?.toolbarIcon(), for: .normal) button.tintColor = tintColor button.addTarget(self, action: action, for: .touchUpInside) button.constrainToToolbarIconSize() return button } + /// Layout of the items in the bottom toolbar. + /// + /// The icon assets are all drawn on a 40x40pt canvas with their artwork 30pt tall, so + /// nothing here sizes them. The one thing left to do is pad each item out to the 44pt + /// minimum tap target, with horizontal room between items: on iOS 26 the items share one + /// Liquid Glass background and a space item between them would split it, so the gap is + /// transparent padding on the image itself. + /// + /// `fileprivate` so the UIImage helper at the bottom of this file can read it. + fileprivate enum ToolbarLayout { + static let itemSize = CGSize(width: 60, height: 44) + } + + /// Position of the pre-meal item within `toolbarItems`, recorded at setup + /// because it differs between the iOS 26 and legacy layouts. + private var preMealItemIndex: Int = 1 + private func setupToolbarItems() { let carbs = UIBarButtonItem(customView: carbEntryButton) let bolus = UIBarButtonItem(customView: bolusButton) @@ -308,7 +325,7 @@ final class StatusTableViewController: LoopChartsTableViewController { func flexibleSpace() -> UIBarButtonItem { UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil) } - + if #available(iOS 26, *) { toolbarItems = [carbs, preMeal, bolus, workout, settings] } else { @@ -324,6 +341,10 @@ final class StatusTableViewController: LoopChartsTableViewController { settings ] } + + // The two layouts put pre-meal at different indices, so record where it + // actually landed rather than hardcoding it. + preMealItemIndex = toolbarItems?.firstIndex { $0 === preMeal } ?? 1 } private func updateToolbarItems() { @@ -335,13 +356,7 @@ final class StatusTableViewController: LoopChartsTableViewController { bolusButton.isEnabled = isPumpOnboarded settingsButton.accessibilityLabel = NSLocalizedString("Settings", comment: "The label of the settings button") - let preMealIndex: Int - if #available(iOS 26, *) { - preMealIndex = 1 - } else { - preMealIndex = 2 - } - toolbarItems![preMealIndex] = createPreMealButtonItem(selected: preMealMode == true && preMealModeAllowed, isEnabled: preMealModeAllowed) + toolbarItems![preMealItemIndex] = createPreMealButtonItem(selected: preMealMode == true && preMealModeAllowed, isEnabled: preMealModeAllowed) updateWorkoutButton(selected: workoutMode == true && workoutModeAllowed, isEnabled: workoutModeAllowed) } @@ -1478,7 +1493,7 @@ final class StatusTableViewController: LoopChartsTableViewController { } private func createPreMealButtonItem(selected: Bool, isEnabled: Bool) -> UIBarButtonItem { - let item = UIBarButtonItem(image: UIImage.preMealImage(selected: selected), style: .plain, target: self, action: #selector(premealButtonTapped(_:))) + let item = UIBarButtonItem(image: UIImage.preMealImage(selected: selected)?.toolbarIcon(), style: .plain, target: self, action: #selector(premealButtonTapped(_:))) item.accessibilityLabel = NSLocalizedString("Pre-Meal Targets", comment: "The label of the pre-meal mode toggle button") if selected { @@ -1495,7 +1510,7 @@ final class StatusTableViewController: LoopChartsTableViewController { } private func updateWorkoutButton(selected: Bool, isEnabled: Bool) { - workoutButton.setImage(UIImage.workoutImage(selected: selected), for: .normal) + workoutButton.setImage(UIImage.workoutImage(selected: selected)?.toolbarIcon(), for: .normal) workoutButton.accessibilityLabel = NSLocalizedString("Workout Targets", comment: "The label of the workout mode toggle button") if selected { @@ -2093,6 +2108,19 @@ private extension UIButton { } } +private extension UIImage { + /// Centers the icon on a transparent canvas of the toolbar item size. See `ToolbarLayout`. + func toolbarIcon() -> UIImage { + let canvas = StatusTableViewController.ToolbarLayout.itemSize + let origin = CGPoint(x: (canvas.width - size.width) / 2, y: (canvas.height - size.height) / 2) + let format = UIGraphicsImageRendererFormat.preferred() + format.opaque = false + return UIGraphicsImageRenderer(size: canvas, format: format).image { _ in + draw(in: CGRect(origin: origin, size: size)) + }.withRenderingMode(.alwaysTemplate) + } +} + extension UIAlertController { func addActivityIndicator() { let frame = CGRect(x: 0, y: 0, width: 40, height: 40)