From 9891b601a8dd18837763af281c3e405cf93cedf5 Mon Sep 17 00:00:00 2001 From: Shadowfacts Date: Mon, 19 Aug 2024 19:10:31 -0400 Subject: [PATCH] Initial tab bar/sidebar implementation --- .../Main/BaseMainTabBarViewController.swift | 5 +- .../Main/NewMainTabBarViewController.swift | 53 ++++++++++++++++--- .../MultiColumnNavigationController.swift | 7 ++- 3 files changed, 56 insertions(+), 9 deletions(-) diff --git a/Tusker/Screens/Main/BaseMainTabBarViewController.swift b/Tusker/Screens/Main/BaseMainTabBarViewController.swift index 59a94cf9..02ddc472 100644 --- a/Tusker/Screens/Main/BaseMainTabBarViewController.swift +++ b/Tusker/Screens/Main/BaseMainTabBarViewController.swift @@ -70,9 +70,12 @@ class BaseMainTabBarViewController: UITabBarController { } private func repositionFastSwitcherIndicator() { - guard let myProfileButton = findMyProfileTabBarButton() else { + guard let myProfileButton = findMyProfileTabBarButton(), + myProfileButton.window != nil else { + fastSwitcherIndicator?.isHidden = true return } + fastSwitcherIndicator?.isHidden = false NSLayoutConstraint.deactivate(fastSwitcherConstraints) let isPortrait = view.bounds.width < view.bounds.height if traitCollection.horizontalSizeClass == .compact && isPortrait { diff --git a/Tusker/Screens/Main/NewMainTabBarViewController.swift b/Tusker/Screens/Main/NewMainTabBarViewController.swift index 6ddce3f3..d3311cd6 100644 --- a/Tusker/Screens/Main/NewMainTabBarViewController.swift +++ b/Tusker/Screens/Main/NewMainTabBarViewController.swift @@ -18,6 +18,7 @@ class NewMainTabBarViewController: BaseMainTabBarViewController { mode = .tabSidebar delegate = self + sidebar.delegate = self tabBar.isSpringLoaded = true view.backgroundColor = .appBackground @@ -57,13 +58,33 @@ class NewMainTabBarViewController: BaseMainTabBarViewController { case .myProfile: root = MyProfileViewController(mastodonController: mastodonController) } - return EnhancedNavigationViewController(rootViewController: root) + let nav: any NavigationControllerProtocol + if UIDevice.current.userInterfaceIdiom == .phone { + nav = EnhancedNavigationViewController() + } else { + // TODO: need to figure out how to update the navigation controller if the pref changes + switch Preferences.shared.widescreenNavigationMode { + case .stack: + nav = EnhancedNavigationViewController() + case .splitScreen: + nav = SplitNavigationController() + case .multiColumn: + nav = MultiColumnNavigationController() + } + } + nav.viewControllers = [root] + return nav } @objc func handleComposeKeyCommand() { compose(editing: nil) } + fileprivate func updateViewControllerSafeAreaInsets(_ vc: MultiColumnNavigationController) { + // When in sidebar mode, for multi column mode, don't leave an inset for the floating tab bar, because it leaves a massive gap. + // The floating tab bar seems to always be 88pt tall, regardless of, e.g., Dynamic Type size. + vc.additionalSafeAreaInsets = UIEdgeInsets(top: sidebar.isHidden ? 0 : -88, left: 0, bottom: 0, right: 0) + } } @available(iOS 18.0, *) @@ -112,12 +133,12 @@ extension NewMainTabBarViewController: UITabBarControllerDelegate { func tabBarController(_ tabBarController: UITabBarController, shouldSelectTab tab: UITab) -> Bool { if tab.identifier == Tab.compose.rawValue { let currentTab = selectedTab - compose(editing: nil) { - // returning false for shouldSelectTab doesn't prevent the UITabBar from being updated (FB14857254) - // but we need it to change to _something_ so that we can change back to the current tab - self.selectedTab = tab - self.selectedTab = currentTab - } + // returning false for shouldSelectTab doesn't prevent the UITabBar from being updated (FB14857254) + // but we need it to change to _something_ so that we can change back to the current tab + self.selectedTab = tab + self.selectedTab = currentTab + + compose(editing: nil) return false } else if let selectedTab, selectedTab == tab, @@ -130,6 +151,24 @@ extension NewMainTabBarViewController: UITabBarControllerDelegate { return true } } + + func tabBarController(_ tabBarController: UITabBarController, didSelectTab newTab: UITab, previousTab: UITab?) { + if let vc = newTab.viewController as? MultiColumnNavigationController { + self.updateViewControllerSafeAreaInsets(vc) + } + } +} + +@available(iOS 18.0, *) +extension NewMainTabBarViewController: UITabBarController.Sidebar.Delegate { + func tabBarController(_ tabBarController: UITabBarController, sidebarVisibilityWillChange sidebar: UITabBarController.Sidebar, animator: any UITabBarController.Sidebar.Animating) { + if let vc = selectedViewController as? MultiColumnNavigationController { + animator.addAnimations { + self.updateViewControllerSafeAreaInsets(vc) + vc.view.layoutIfNeeded() + } + } + } } @available(iOS 18.0, *) diff --git a/Tusker/Screens/Utilities/MultiColumnNavigationController.swift b/Tusker/Screens/Utilities/MultiColumnNavigationController.swift index e43bd7f7..7292a553 100644 --- a/Tusker/Screens/Utilities/MultiColumnNavigationController.swift +++ b/Tusker/Screens/Utilities/MultiColumnNavigationController.swift @@ -155,7 +155,7 @@ class MultiColumnNavigationController: UIViewController { if columnFrame.maxX < scrollView.bounds.width - scrollView.adjustedTrailingContentInset { offset = -scrollView.adjustedLeadingContentInset } else { - offset = columnFrame.minX + scrollView.adjustedLeadingContentInset - (scrollView.bounds.width - columnFrame.width) + offset = scrollView.contentSize.width - scrollView.bounds.width + scrollView.adjustedTrailingContentInset } scrollView.setContentOffset(CGPoint(x: offset, y: -scrollView.adjustedContentInset.top), animated: animated) } @@ -185,6 +185,11 @@ class MultiColumnNavigationController: UIViewController { } animator.startAnimation() } + + // blergh, overriding private method on UIViewController + @objc func _shouldOverlayTabBar() -> Bool { + false + } } extension MultiColumnNavigationController: NavigationControllerProtocol {