feat: update navigation stack when transition from .regular to .compact
This commit is contained in:
parent
c30da6533e
commit
275cce88b2
|
@ -2536,6 +2536,8 @@
|
|||
isa = PBXGroup;
|
||||
children = (
|
||||
DB852D1B26FB021500FC9D81 /* RootSplitViewController.swift */,
|
||||
DB852D1A26FAED0100FC9D81 /* Sidebar */,
|
||||
DB8AF54E25C13703002E6C99 /* MainTab */,
|
||||
);
|
||||
path = Root;
|
||||
sourceTree = "<group>";
|
||||
|
@ -2652,8 +2654,6 @@
|
|||
2D7631A425C1532200929FB9 /* Share */,
|
||||
DB6180E426391A500018D199 /* Transition */,
|
||||
DB852D1D26FB021900FC9D81 /* Root */,
|
||||
DB852D1A26FAED0100FC9D81 /* Sidebar */,
|
||||
DB8AF54E25C13703002E6C99 /* MainTab */,
|
||||
DB01409B25C40BB600F9F3CF /* Onboarding */,
|
||||
DB9F58ED26EF435800E7BBE9 /* Account */,
|
||||
2D38F1D325CD463600561493 /* HomeTimeline */,
|
||||
|
|
|
@ -18,6 +18,8 @@ final public class SceneCoordinator {
|
|||
|
||||
let id = UUID().uuidString
|
||||
|
||||
weak var splitViewController: RootSplitViewController?
|
||||
|
||||
init(scene: UIScene, sceneDelegate: SceneDelegate, appContext: AppContext) {
|
||||
self.scene = scene
|
||||
self.sceneDelegate = sceneDelegate
|
||||
|
@ -119,6 +121,7 @@ extension SceneCoordinator {
|
|||
|
||||
func setup() {
|
||||
let splitViewController = RootSplitViewController(context: appContext, coordinator: self)
|
||||
self.splitViewController = splitViewController
|
||||
sceneDelegate.window?.rootViewController = splitViewController
|
||||
}
|
||||
|
||||
|
@ -172,8 +175,14 @@ extension SceneCoordinator {
|
|||
|
||||
switch transition {
|
||||
case .show:
|
||||
presentingViewController.show(viewController, sender: sender)
|
||||
|
||||
if let splitViewController = splitViewController, !splitViewController.isCollapsed,
|
||||
let supplementaryViewController = splitViewController.viewController(for: .supplementary) as? UINavigationController,
|
||||
(supplementaryViewController === presentingViewController || supplementaryViewController.viewControllers.contains(presentingViewController))
|
||||
{
|
||||
fallthrough
|
||||
} else {
|
||||
presentingViewController.show(viewController, sender: sender)
|
||||
}
|
||||
case .showDetail:
|
||||
let navigationController = AdaptiveStatusBarStyleNavigationController(rootViewController: viewController)
|
||||
presentingViewController.showDetailViewController(navigationController, sender: sender)
|
||||
|
|
|
@ -111,10 +111,10 @@ extension StatusProviderFacade {
|
|||
if provider.navigationController == nil {
|
||||
let from = provider.presentingViewController ?? provider
|
||||
provider.dismiss(animated: true) {
|
||||
provider.coordinator.present(scene: .thread(viewModel: threadViewModel), from: from, transition: .showDetail)
|
||||
provider.coordinator.present(scene: .thread(viewModel: threadViewModel), from: from, transition: .show)
|
||||
}
|
||||
} else {
|
||||
provider.coordinator.present(scene: .thread(viewModel: threadViewModel), from: provider, transition: .showDetail)
|
||||
provider.coordinator.present(scene: .thread(viewModel: threadViewModel), from: provider, transition: .show)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@ class MainTabBarController: UITabBarController {
|
|||
|
||||
let wizard = Wizard()
|
||||
|
||||
var currentTab = Tab.home
|
||||
var currentTab = CurrentValueSubject<Tab, Never>(.home)
|
||||
|
||||
enum Tab: Int, CaseIterable {
|
||||
case home
|
||||
|
@ -361,10 +361,10 @@ extension MainTabBarController: UITabBarControllerDelegate {
|
|||
os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s: select %s", ((#file as NSString).lastPathComponent), #line, #function, viewController.debugDescription)
|
||||
defer {
|
||||
if let tab = Tab(rawValue: tabBarController.selectedIndex) {
|
||||
currentTab = tab
|
||||
currentTab.value = tab
|
||||
}
|
||||
}
|
||||
guard currentTab.rawValue == tabBarController.selectedIndex,
|
||||
guard currentTab.value.rawValue == tabBarController.selectedIndex,
|
||||
let navigationController = viewController as? UINavigationController,
|
||||
navigationController.viewControllers.count == 1,
|
||||
let scrollViewContainer = navigationController.topViewController as? ScrollViewContainer else {
|
||||
|
@ -535,7 +535,7 @@ extension MainTabBarController {
|
|||
let previousTab = Tab(rawValue: selectedIndex)
|
||||
selectedIndex = index
|
||||
if let tab = Tab(rawValue: index) {
|
||||
currentTab = tab
|
||||
currentTab.value = tab
|
||||
}
|
||||
|
||||
if let previousTab = previousTab {
|
|
@ -7,9 +7,12 @@
|
|||
|
||||
import os.log
|
||||
import UIKit
|
||||
import Combine
|
||||
|
||||
final class RootSplitViewController: UISplitViewController, NeedsDependency {
|
||||
|
||||
var disposeBag = Set<AnyCancellable>()
|
||||
|
||||
weak var context: AppContext! { willSet { precondition(!isViewLoaded) } }
|
||||
weak var coordinator: SceneCoordinator! { willSet { precondition(!isViewLoaded) } }
|
||||
|
||||
|
@ -21,6 +24,13 @@ final class RootSplitViewController: UISplitViewController, NeedsDependency {
|
|||
sidebarViewController.delegate = self
|
||||
return sidebarViewController
|
||||
}()
|
||||
|
||||
var currentSupplementaryTab: MainTabBarController.Tab = .home
|
||||
private(set) lazy var supplementaryViewControllers: [UIViewController] = {
|
||||
return MainTabBarController.Tab.allCases.map { tab in
|
||||
tab.viewController(context: context, coordinator: coordinator)
|
||||
}
|
||||
}()
|
||||
|
||||
private(set) lazy var mainTabBarController = MainTabBarController(context: context, coordinator: coordinator)
|
||||
|
||||
|
@ -32,6 +42,7 @@ final class RootSplitViewController: UISplitViewController, NeedsDependency {
|
|||
primaryBackgroundStyle = .sidebar
|
||||
preferredDisplayMode = .oneBesideSecondary
|
||||
preferredSplitBehavior = .tile
|
||||
delegate = self
|
||||
|
||||
if #available(iOS 14.5, *) {
|
||||
displayModeButtonVisibility = .always
|
||||
|
@ -40,7 +51,7 @@ final class RootSplitViewController: UISplitViewController, NeedsDependency {
|
|||
}
|
||||
|
||||
setViewController(sidebarViewController, for: .primary)
|
||||
setViewController(mainTabBarController.viewControllers!.first, for: .supplementary)
|
||||
setViewController(supplementaryViewControllers[0], for: .supplementary)
|
||||
setViewController(UIViewController(), for: .secondary)
|
||||
setViewController(mainTabBarController, for: .compact)
|
||||
}
|
||||
|
@ -61,6 +72,18 @@ extension RootSplitViewController {
|
|||
super.viewDidLoad()
|
||||
|
||||
updateBehavior(size: view.frame.size)
|
||||
|
||||
mainTabBarController.currentTab
|
||||
.receive(on: DispatchQueue.main)
|
||||
.sink { [weak self] tab in
|
||||
guard let self = self else { return }
|
||||
guard tab != self.currentSupplementaryTab else { return }
|
||||
guard let index = MainTabBarController.Tab.allCases.firstIndex(of: tab) else { return }
|
||||
self.currentSupplementaryTab = tab
|
||||
self.setViewController(self.supplementaryViewControllers[index], for: .supplementary)
|
||||
|
||||
}
|
||||
.store(in: &disposeBag)
|
||||
}
|
||||
|
||||
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
|
||||
|
@ -86,16 +109,76 @@ extension RootSplitViewController {
|
|||
extension RootSplitViewController: SidebarViewControllerDelegate {
|
||||
func sidebarViewController(_ sidebarViewController: SidebarViewController, didSelectTab tab: MainTabBarController.Tab) {
|
||||
|
||||
// FIXME: remove hard code
|
||||
switch tab {
|
||||
case .home:
|
||||
setViewController(mainTabBarController._viewControllers[0], for: .supplementary)
|
||||
case .search:
|
||||
setViewController(mainTabBarController._viewControllers[1], for: .supplementary)
|
||||
case .notification:
|
||||
setViewController(mainTabBarController._viewControllers[2], for: .supplementary)
|
||||
case .me:
|
||||
setViewController(mainTabBarController._viewControllers[3], for: .supplementary)
|
||||
guard let index = MainTabBarController.Tab.allCases.firstIndex(of: tab) else {
|
||||
assertionFailure()
|
||||
return
|
||||
}
|
||||
currentSupplementaryTab = tab
|
||||
setViewController(supplementaryViewControllers[index], for: .supplementary)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - UISplitViewControllerDelegate
|
||||
extension RootSplitViewController: UISplitViewControllerDelegate {
|
||||
|
||||
// .regular to .compact
|
||||
// move navigation stack from .supplementary & .secondary to .compact
|
||||
func splitViewController(
|
||||
_ svc: UISplitViewController,
|
||||
topColumnForCollapsingToProposedTopColumn proposedTopColumn: UISplitViewController.Column
|
||||
) -> UISplitViewController.Column {
|
||||
switch proposedTopColumn {
|
||||
case .compact:
|
||||
guard let index = MainTabBarController.Tab.allCases.firstIndex(of: currentSupplementaryTab) else {
|
||||
assertionFailure()
|
||||
break
|
||||
}
|
||||
mainTabBarController.selectedIndex = index
|
||||
mainTabBarController.currentTab.value = currentSupplementaryTab
|
||||
|
||||
guard let navigationController = mainTabBarController.selectedViewController as? UINavigationController else { break }
|
||||
navigationController.popToRootViewController(animated: false)
|
||||
var viewControllers = navigationController.viewControllers // init navigation stack with topMost
|
||||
|
||||
if let supplementaryNavigationController = viewController(for: .supplementary) as? UINavigationController {
|
||||
// append supplementary
|
||||
viewControllers.append(contentsOf: supplementaryNavigationController.popToRootViewController(animated: true) ?? [])
|
||||
}
|
||||
if let secondaryNavigationController = viewController(for: .secondary) as? UINavigationController {
|
||||
// append secondary
|
||||
viewControllers.append(contentsOf: secondaryNavigationController.popToRootViewController(animated: true) ?? [])
|
||||
}
|
||||
// set navigation stack
|
||||
navigationController.setViewControllers(viewControllers, animated: false)
|
||||
|
||||
default:
|
||||
assertionFailure()
|
||||
}
|
||||
|
||||
return proposedTopColumn
|
||||
}
|
||||
|
||||
// .compact to .regular
|
||||
// restore navigation stack to .supplementary & .secondary
|
||||
func splitViewController(
|
||||
_ svc: UISplitViewController,
|
||||
displayModeForExpandingToProposedDisplayMode proposedDisplayMode: UISplitViewController.DisplayMode
|
||||
) -> UISplitViewController.DisplayMode {
|
||||
|
||||
return proposedDisplayMode
|
||||
}
|
||||
|
||||
func splitViewController(
|
||||
_ splitViewController: UISplitViewController,
|
||||
show vc: UIViewController,
|
||||
sender: Any?
|
||||
) -> Bool {
|
||||
if !splitViewController.isCollapsed {
|
||||
// display in .secondary when expand
|
||||
splitViewController.showDetailViewController(vc, sender: sender)
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue