Add saved instances to new sidebar

This commit is contained in:
Shadowfacts 2024-08-21 17:10:01 -04:00
parent 0d9eed73dd
commit 1817247077
2 changed files with 76 additions and 5 deletions

View File

@ -371,7 +371,7 @@ extension MainSidebarViewController {
case let .savedInstance(url): case let .savedInstance(url):
return url.host! return url.host!
case .addSavedInstance: case .addSavedInstance:
return "Find An Instance..." return "Find an Instance..."
} }
} }

View File

@ -25,6 +25,7 @@ final class NewMainTabBarViewController: BaseMainTabBarViewController {
private var myProfileTab: UITab! private var myProfileTab: UITab!
private var listsGroup: UITabGroup! private var listsGroup: UITabGroup!
private var hashtagsGroup: UITabGroup! private var hashtagsGroup: UITabGroup!
private var instancesGroup: UITabGroup!
private var cancellables = Set<AnyCancellable>() private var cancellables = Set<AnyCancellable>()
@ -79,6 +80,17 @@ final class NewMainTabBarViewController: BaseMainTabBarViewController {
] ]
reloadHashtags() reloadHashtags()
instancesGroup = UITabGroup(title: "Instance Timelines", image: nil, identifier: Tab.instances.rawValue, children: []) { _ in
return AdaptableNavigationController()
}
instancesGroup.preferredPlacement = .sidebarOnly
instancesGroup.sidebarActions = [
UIAction(title: "Find an Instance…", image: UIImage(systemName: "plus"), handler: { [unowned self] _ in
self.showAddSavedInstance()
})
]
reloadSavedInstances()
if UIDevice.current.userInterfaceIdiom == .phone { if UIDevice.current.userInterfaceIdiom == .phone {
self.tabs = [ self.tabs = [
homeTab, homeTab,
@ -105,6 +117,8 @@ final class NewMainTabBarViewController: BaseMainTabBarViewController {
.merge(with: NotificationCenter.default.publisher(for: .savedHashtagsChanged).map { _ in () }) .merge(with: NotificationCenter.default.publisher(for: .savedHashtagsChanged).map { _ in () })
.sink { [unowned self] in self.reloadHashtags() } .sink { [unowned self] in self.reloadHashtags() }
.store(in: &cancellables) .store(in: &cancellables)
NotificationCenter.default.addObserver(self, selector: #selector(reloadSavedInstances), name: .savedInstancesChanged, object: nil)
} }
setupFastAccountSwitcher() setupFastAccountSwitcher()
@ -118,7 +132,7 @@ final class NewMainTabBarViewController: BaseMainTabBarViewController {
var exploreNavStack: [UIViewController]? = nil var exploreNavStack: [UIViewController]? = nil
if let parent = selectedTab?.parent, if let parent = selectedTab?.parent,
parent === listsGroup || parent === hashtagsGroup { parent === listsGroup || parent === hashtagsGroup || parent === instancesGroup {
let nav = parent.viewController as! any NavigationControllerProtocol let nav = parent.viewController as! any NavigationControllerProtocol
exploreNavStack = nav.viewControllers exploreNavStack = nav.viewControllers
nav.viewControllers = [] nav.viewControllers = []
@ -180,6 +194,7 @@ final class NewMainTabBarViewController: BaseMainTabBarViewController {
composeTab, composeTab,
listsGroup, listsGroup,
hashtagsGroup, hashtagsGroup,
instancesGroup,
] ]
if let (tab, navStack) = newTabAndNavigationStack { if let (tab, navStack) = newTabAndNavigationStack {
@ -222,7 +237,7 @@ final class NewMainTabBarViewController: BaseMainTabBarViewController {
root = FavoritesViewController(mastodonController: mastodonController) root = FavoritesViewController(mastodonController: mastodonController)
case .myProfile: case .myProfile:
root = MyProfileViewController(mastodonController: mastodonController) root = MyProfileViewController(mastodonController: mastodonController)
case .lists, .hashtags: case .lists, .hashtags, .instances:
fatalError("unreachable") fatalError("unreachable")
} }
return embedInNavigationController(root) return embedInNavigationController(root)
@ -279,6 +294,19 @@ final class NewMainTabBarViewController: BaseMainTabBarViewController {
hashtagsGroup.children = tabs hashtagsGroup.children = tabs
} }
@objc private func reloadSavedInstances() {
let viewControllerProvider = { [unowned self] (tab: UITab) in
let tab = tab as! InstanceTab
return InstanceTimelineViewController(for: tab.instance.url, parentMastodonController: self.mastodonController)
}
let req = SavedInstance.fetchRequest(account: mastodonController.accountInfo!)
req.sortDescriptors = [NSSortDescriptor(key: "url.host", ascending: true)]
let instances = (try? mastodonController.persistentContainer.viewContext.fetch(req).uniques(by: \.url)) ?? []
instancesGroup.children = instances.map {
InstanceTab(instance: $0, viewControllerProvider: viewControllerProvider)
}
}
@objc func handleComposeKeyCommand() { @objc func handleComposeKeyCommand() {
compose(editing: nil) compose(editing: nil)
} }
@ -305,6 +333,13 @@ final class NewMainTabBarViewController: BaseMainTabBarViewController {
present(nav, animated: true) present(nav, animated: true)
} }
private func showAddSavedInstance() {
let findController = FindInstanceViewController(parentMastodonController: mastodonController)
findController.instanceTimelineDelegate = self
let nav = EnhancedNavigationViewController(rootViewController: findController)
present(nav, animated: true)
}
fileprivate func updateViewControllerSafeAreaInsets(_ vc: UIViewController) { fileprivate func updateViewControllerSafeAreaInsets(_ vc: UIViewController) {
guard vc is MultiColumnNavigationController || (vc as? AdaptableNavigationController)?.current is MultiColumnNavigationController else { guard vc is MultiColumnNavigationController || (vc as? AdaptableNavigationController)?.current is MultiColumnNavigationController else {
return return
@ -379,6 +414,7 @@ extension NewMainTabBarViewController {
case lists case lists
case hashtags case hashtags
case instances
} }
} }
@ -418,7 +454,7 @@ extension NewMainTabBarViewController: UITabBarControllerDelegate {
// get the new transition animation. // get the new transition animation.
// This would be much less complicated if the controller just used the individual VCs of items in a group. // This would be much less complicated if the controller just used the individual VCs of items in a group.
if let group = newTab.parent, if let group = newTab.parent,
group === listsGroup || group === hashtagsGroup, group === listsGroup || group === hashtagsGroup || group === instancesGroup,
let nav = group.viewController as? any NavigationControllerProtocol { let nav = group.viewController as? any NavigationControllerProtocol {
updateViewControllerSafeAreaInsets(nav) updateViewControllerSafeAreaInsets(nav)
@ -499,6 +535,9 @@ extension NewMainTabBarViewController: UITabBarController.Sidebar.Delegate {
} else { } else {
return nil return nil
} }
} else if tab is InstanceTab {
// don't currently have a scene type for this
return nil
} else if let tabID = Tab(rawValue: tab.identifier) { } else if let tabID = Tab(rawValue: tab.identifier) {
switch tabID { switch tabID {
case .home: case .home:
@ -517,7 +556,7 @@ extension NewMainTabBarViewController: UITabBarController.Sidebar.Delegate {
return nil return nil
case .compose: case .compose:
activity = UserActivityManager.newPostActivity(accountID: id) activity = UserActivityManager.newPostActivity(accountID: id)
case .lists, .hashtags: case .lists, .hashtags, .instances:
return nil return nil
} }
} else { } else {
@ -638,6 +677,20 @@ extension NewMainTabBarViewController: AccountSwitchableViewController {
} }
} }
@available(iOS 18.0, *)
extension NewMainTabBarViewController: InstanceTimelineViewControllerDelegate {
func didSaveInstance(url: URL) {
dismiss(animated: true) {
let tab = self.instancesGroup.tab(forIdentifier: InstanceTab.identifier(for: url))!
self.selectedTab = tab
}
}
func didUnsaveInstance(url: URL) {
dismiss(animated: true)
}
}
private struct MyProfileContentConfiguration: UIContentConfiguration { private struct MyProfileContentConfiguration: UIContentConfiguration {
let wrapped: any UIContentConfiguration let wrapped: any UIContentConfiguration
@Box var view: UIView? @Box var view: UIView?
@ -754,3 +807,21 @@ private class HashtagTab: UITab {
"hashtag:\(name)" "hashtag:\(name)"
} }
} }
@available(iOS 18.0, *)
private class InstanceTab: UITab {
let instance: SavedInstance
init(instance: SavedInstance, viewControllerProvider: @escaping (UITab) -> UIViewController) {
self.instance = instance
super.init(title: instance.url.host!, image: UIImage(systemName: "globe"), identifier: Self.identifier(for: instance), viewControllerProvider: viewControllerProvider)
}
static func identifier(for instance: SavedInstance) -> String {
"instance:\(instance.url.host!)"
}
static func identifier(for instanceURL: URL) -> String {
"instance:\(instanceURL.host!)"
}
}