forked from shadowfacts/Tusker
Lists in new sidebar
This commit is contained in:
parent
9891b601a8
commit
dffa5d8f75
|
@ -7,12 +7,20 @@
|
|||
//
|
||||
|
||||
import UIKit
|
||||
import Combine
|
||||
import Pachyderm
|
||||
|
||||
@available(iOS 18.0, *)
|
||||
class NewMainTabBarViewController: BaseMainTabBarViewController {
|
||||
|
||||
private let composePlaceholder = UIViewController()
|
||||
|
||||
private var listsGroup: UITabGroup!
|
||||
|
||||
private var cancellables = Set<AnyCancellable>()
|
||||
|
||||
private var navigationStacks = [String: [UIViewController]]()
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
|
@ -26,19 +34,54 @@ class NewMainTabBarViewController: BaseMainTabBarViewController {
|
|||
self.makeViewController(for: tab)
|
||||
}
|
||||
|
||||
let topLevelTabs = [
|
||||
Tab.home,
|
||||
.notifications,
|
||||
.compose,
|
||||
.explore,
|
||||
.myProfile
|
||||
].map {
|
||||
UITab(title: $0.title, image: UIImage(systemName: $0.imageName), identifier: $0.rawValue, viewControllerProvider: viewControllerProvider)
|
||||
let homeTab = UITab(title: "Home", image: UIImage(systemName: "house"), identifier: Tab.home.rawValue, viewControllerProvider: viewControllerProvider)
|
||||
let notificationsTab = UITab(title: "Notifications", image: UIImage(systemName: "bell"), identifier: Tab.notifications.rawValue, viewControllerProvider: viewControllerProvider)
|
||||
let composeTab = UITab(title: "Compose", image: UIImage(systemName: "pencil"), identifier: Tab.compose.rawValue, viewControllerProvider: viewControllerProvider)
|
||||
let exploreTab = UITab(title: "Explore", image: UIImage(systemName: "magnifyingglass"), identifier: Tab.explore.rawValue, viewControllerProvider: viewControllerProvider)
|
||||
let bookmarksTab = UITab(title: "Bookmarks", image: UIImage(systemName: "bookmark"), identifier: Tab.bookmarks.rawValue, viewControllerProvider: viewControllerProvider)
|
||||
bookmarksTab.preferredPlacement = .optional
|
||||
let favoritesTab = UITab(title: "Favorites", image: UIImage(systemName: "star"), identifier: Tab.favorites.rawValue, viewControllerProvider: viewControllerProvider)
|
||||
favoritesTab.preferredPlacement = .optional
|
||||
let myProfileTab = UITab(title: "My Profile", image: UIImage(systemName: "person"), identifier: Tab.myProfile.rawValue, viewControllerProvider: viewControllerProvider)
|
||||
|
||||
listsGroup = UITabGroup(title: "Lists", image: nil, identifier: Tab.lists.rawValue, children: []) { _ in
|
||||
// this closure is necessary to prevent UIKit from crashing (FB14860961)
|
||||
return MultiColumnNavigationController()
|
||||
}
|
||||
listsGroup.preferredPlacement = .sidebarOnly
|
||||
listsGroup.sidebarActions = [
|
||||
UIAction(title: "New List…", image: UIImage(systemName: "plus"), handler: { _ in
|
||||
fatalError("TODO")
|
||||
})
|
||||
]
|
||||
reloadLists(mastodonController.lists)
|
||||
|
||||
if UIDevice.current.userInterfaceIdiom == .phone {
|
||||
self.tabs = [
|
||||
homeTab,
|
||||
notificationsTab,
|
||||
composeTab,
|
||||
exploreTab,
|
||||
myProfileTab,
|
||||
]
|
||||
} else {
|
||||
self.tabs = [
|
||||
homeTab,
|
||||
notificationsTab,
|
||||
exploreTab,
|
||||
bookmarksTab,
|
||||
favoritesTab,
|
||||
myProfileTab,
|
||||
composeTab,
|
||||
listsGroup,
|
||||
]
|
||||
}
|
||||
|
||||
self.tabs = topLevelTabs
|
||||
|
||||
setupFastAccountSwitcher()
|
||||
|
||||
mastodonController.$lists
|
||||
.sink { [unowned self] in self.reloadLists($0) }
|
||||
.store(in: &cancellables)
|
||||
}
|
||||
|
||||
private func makeViewController(for tab: UITab) -> UIViewController {
|
||||
|
@ -55,9 +98,19 @@ class NewMainTabBarViewController: BaseMainTabBarViewController {
|
|||
return composePlaceholder
|
||||
case .explore:
|
||||
root = ExploreViewController(mastodonController: mastodonController)
|
||||
case .bookmarks:
|
||||
root = BookmarksViewController(mastodonController: mastodonController)
|
||||
case .favorites:
|
||||
root = FavoritesViewController(mastodonController: mastodonController)
|
||||
case .myProfile:
|
||||
root = MyProfileViewController(mastodonController: mastodonController)
|
||||
case .lists:
|
||||
fatalError("unreachable")
|
||||
}
|
||||
return NewMainTabBarViewController.embedInNavigationController(root)
|
||||
}
|
||||
|
||||
private static func embedInNavigationController(_ vc: UIViewController) -> UIViewController {
|
||||
let nav: any NavigationControllerProtocol
|
||||
if UIDevice.current.userInterfaceIdiom == .phone {
|
||||
nav = EnhancedNavigationViewController()
|
||||
|
@ -72,10 +125,18 @@ class NewMainTabBarViewController: BaseMainTabBarViewController {
|
|||
nav = MultiColumnNavigationController()
|
||||
}
|
||||
}
|
||||
nav.viewControllers = [root]
|
||||
nav.viewControllers = [vc]
|
||||
return nav
|
||||
}
|
||||
|
||||
private func reloadLists(_ lists: [List]) {
|
||||
listsGroup.children = lists.map { list in
|
||||
UITab(title: list.title, image: UIImage(systemName: "list.bullet"), identifier: "list:\(list.id)") { [unowned self] _ in
|
||||
NewMainTabBarViewController.embedInNavigationController(ListTimelineViewController(for: list, mastodonController: self.mastodonController))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@objc func handleComposeKeyCommand() {
|
||||
compose(editing: nil)
|
||||
}
|
||||
|
@ -94,37 +155,11 @@ extension NewMainTabBarViewController {
|
|||
case notifications
|
||||
case compose
|
||||
case explore
|
||||
case bookmarks
|
||||
case favorites
|
||||
case myProfile
|
||||
|
||||
var title: String {
|
||||
switch self {
|
||||
case .home:
|
||||
"Home"
|
||||
case .notifications:
|
||||
"Notifications"
|
||||
case .compose:
|
||||
"Compose"
|
||||
case .explore:
|
||||
"Explore"
|
||||
case .myProfile:
|
||||
"My Profile"
|
||||
}
|
||||
}
|
||||
|
||||
var imageName: String {
|
||||
switch self {
|
||||
case .home:
|
||||
"house"
|
||||
case .notifications:
|
||||
"bell"
|
||||
case .compose:
|
||||
"pencil"
|
||||
case .explore:
|
||||
"magnifyingglass"
|
||||
case .myProfile:
|
||||
"person"
|
||||
}
|
||||
}
|
||||
case lists
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -156,6 +191,34 @@ extension NewMainTabBarViewController: UITabBarControllerDelegate {
|
|||
if let vc = newTab.viewController as? MultiColumnNavigationController {
|
||||
self.updateViewControllerSafeAreaInsets(vc)
|
||||
}
|
||||
|
||||
// All tabs in a tab group deliberately share the same view controller, so we have to do this ourselves.
|
||||
// I think this is pretty unfortunate API design--half the time, the tab bar controller takes care of
|
||||
// this, but the rest of the time it's up to you.
|
||||
// The managingNavigationController API would theoretically solve this, but split-screen/multi-column
|
||||
// nav can't straightforwardly be implemented as UINavigationController subclasses.
|
||||
// Unfortunately this, in turn, means that when switching between tabs in the same group, we don't
|
||||
// get the new transition animation.
|
||||
// This would be much less complicated if the controller just used the individual VCs of items in a group.
|
||||
if let group = newTab.parent,
|
||||
group.identifier == Tab.lists.rawValue,
|
||||
let nav = group.viewController as? any NavigationControllerProtocol {
|
||||
if let multiColumn = nav as? MultiColumnNavigationController {
|
||||
updateViewControllerSafeAreaInsets(multiColumn)
|
||||
}
|
||||
|
||||
if let previousTab {
|
||||
navigationStacks[previousTab.identifier] = nav.viewControllers
|
||||
}
|
||||
|
||||
if let existing = navigationStacks[newTab.identifier] {
|
||||
nav.viewControllers = existing
|
||||
} else if let newNav = newTab.viewController as? any NavigationControllerProtocol {
|
||||
nav.viewControllers = newNav.viewControllers
|
||||
} else {
|
||||
fatalError("unreachable")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue