feat: update navigation stack when transition from .regular to .compact

This commit is contained in:
CMK 2021-09-23 19:32:44 +08:00
parent c30da6533e
commit 275cce88b2
8 changed files with 113 additions and 21 deletions

View File

@ -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 */,

View File

@ -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)

View File

@ -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)
}
}
}

View File

@ -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 {

View File

@ -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
}
}
}