Skip to content
Open
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
17 changes: 15 additions & 2 deletions Loop/View Controllers/StatusTableViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -73,10 +73,23 @@ final class StatusTableViewController: LoopChartsTableViewController {

var statusBarBackgroundView: UIView?

var tableBottomContentInset: CGFloat = 0 {
didSet {
applyTableBottomContentInset()
}
}

private func applyTableBottomContentInset() {
guard isViewLoaded, tableView.contentInset.bottom != tableBottomContentInset else { return }
tableView.contentInset.bottom = tableBottomContentInset
}

override func viewDidLoad() {

super.viewDidLoad()

applyTableBottomContentInset()

statusTableViewModel.settingsViewModel.delegate = self
statusTableViewModel.settingsViewModel.servicesViewModel.delegate = self
statusTableViewModel.settingsViewModel.pumpManagerSettingsViewModel.didTap = { [weak self] in
Expand Down Expand Up @@ -643,8 +656,8 @@ final class StatusTableViewController: LoopChartsTableViewController {
let statusRowMode = self.determineStatusRowMode()

updateBannerAndHUDandStatusRows(statusRowMode: statusRowMode, newSize: currentContext.newSize, animated: animated)
tableView.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: ActionTabBarMetrics.tableContentInset, right: 0)
applyTableBottomContentInset()

redrawCharts()

reloading = false
Expand Down
70 changes: 31 additions & 39 deletions Loop/Views/StatusTableView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -125,9 +125,12 @@ struct StatusTableView: View {
}

var body: some View {
ActionTabView {
ActionTabView { tableBottomContentInset in
wrappedView
.ignoresSafeArea(edges: .bottom)
.onChange(of: tableBottomContentInset, initial: true) { _, newValue in
viewController.tableBottomContentInset = newValue
}
.onChange(of: viewModel.temporaryPresetsManager.activeOverride) { _, _ in
Task {
await viewController.reloadData(animated: true)
Expand Down Expand Up @@ -215,6 +218,7 @@ struct ActionTabBar: UIViewRepresentable {
tag: idx
)
}
uiView.setNeedsLayout()
}

func makeCoordinator() -> Coordinator { Coordinator() }
Expand Down Expand Up @@ -259,24 +263,8 @@ enum ActionTabBarMetrics {

static let barHeight: CGFloat = 49

static var bottomSafeAreaInset: CGFloat {
UIApplication.shared.connectedScenes
.compactMap { $0 as? UIWindowScene }
.flatMap { $0.windows }
.first { $0.isKeyWindow }?
.safeAreaInsets.bottom ?? 0
}

static var interfaceOrientation: UIInterfaceOrientation {
let scenes = UIApplication.shared.connectedScenes.compactMap { $0 as? UIWindowScene }
let scene = scenes.first { $0.windows.contains { $0.isKeyWindow } }
?? scenes.first { $0.activationState == .foregroundActive }
?? scenes.first
return scene?.interfaceOrientation ?? .portrait
}

static var tableContentInset: CGFloat {
guard !interfaceOrientation.isLandscape else { return 0 }
static func tableContentInset(isPortrait: Bool, bottomSafeAreaInset: CGFloat) -> CGFloat {
guard isPortrait else { return 0 }
if #available(iOS 26.0, *), bottomSafeAreaInset == 0 {
return barHeight + 40
}
Expand All @@ -287,13 +275,14 @@ enum ActionTabBarMetrics {
struct LegacyTabBarBackground: ViewModifier {

var isVisible: Bool = true
var bottomSafeAreaInset: CGFloat = 0

func body(content: Content) -> some View {
if !isVisible {
content
.frame(height: 0)
} else if #available(iOS 26.0, *) {
if ActionTabBarMetrics.bottomSafeAreaInset == 0 {
if bottomSafeAreaInset == 0 {
content
.frame(height: ActionTabBarMetrics.barHeight)
.padding(.bottom, 16)
Expand All @@ -315,35 +304,38 @@ struct LegacyTabBarBackground: ViewModifier {

struct ActionTabView<Content: View>: View {

@State private var orientation: UIInterfaceOrientation
@Environment(\.verticalSizeClass) private var verticalSizeClass

private let content: Content
private let content: (CGFloat) -> Content
private let tabs: [ActionTab]

init(
@ViewBuilder content: @escaping () -> Content,
@ViewBuilder content: @escaping (CGFloat) -> Content,
@ActionTabBuilder tabs: @escaping () -> [ActionTab],
) {
self.content = content()
self.content = content
self.tabs = tabs()
self.orientation = ActionTabBarMetrics.interfaceOrientation
}

var body: some View {
content
GeometryReader { geometry in
let isPortrait = verticalSizeClass != .compact
let bottomSafeAreaInset = geometry.safeAreaInsets.bottom

content(
ActionTabBarMetrics.tableContentInset(
isPortrait: isPortrait,
bottomSafeAreaInset: bottomSafeAreaInset
)
)
.safeAreaInset(edge: .bottom, spacing: 0) {
ActionTabBar(items: tabs, isHidden: !orientation.isPortrait)
.modifier(LegacyTabBarBackground(isVisible: orientation.isPortrait))
}
.onAppear {
UIDevice.current.beginGeneratingDeviceOrientationNotifications()
orientation = ActionTabBarMetrics.interfaceOrientation
}
.onDisappear {
UIDevice.current.endGeneratingDeviceOrientationNotifications()
}
.onReceive(NotificationCenter.default.publisher(for: UIDevice.orientationDidChangeNotification)) { _ in
orientation = ActionTabBarMetrics.interfaceOrientation
ActionTabBar(items: tabs, isHidden: !isPortrait)
.modifier(LegacyTabBarBackground(
isVisible: isPortrait,
bottomSafeAreaInset: bottomSafeAreaInset
))
}
}
.ignoresSafeArea(.keyboard)
}
}