Compare commits
3 Commits
a848f6e425
...
9e75f41e7b
Author | SHA1 | Date |
---|---|---|
Shadowfacts | 9e75f41e7b | |
Shadowfacts | 5e55ce75c2 | |
Shadowfacts | eec2adbfd9 |
|
@ -63,6 +63,7 @@ class NotificationService: UNNotificationServiceExtension {
|
||||||
mutableContent.body = notification.body
|
mutableContent.body = notification.body
|
||||||
mutableContent.userInfo["notificationID"] = notification.notificationID
|
mutableContent.userInfo["notificationID"] = notification.notificationID
|
||||||
mutableContent.userInfo["accountID"] = accountID
|
mutableContent.userInfo["accountID"] = accountID
|
||||||
|
mutableContent.targetContentIdentifier = accountID
|
||||||
|
|
||||||
let task = Task {
|
let task = Task {
|
||||||
await updateNotificationContent(mutableContent, account: account, push: notification)
|
await updateNotificationContent(mutableContent, account: account, push: notification)
|
||||||
|
|
|
@ -290,13 +290,19 @@ extension AppDelegate: UNUserNotificationCenterDelegate {
|
||||||
// if the scene is already active, then we animate the account switching if necessary
|
// if the scene is already active, then we animate the account switching if necessary
|
||||||
delegate.activateAccount(account, animated: scene.activationState == .foregroundActive)
|
delegate.activateAccount(account, animated: scene.activationState == .foregroundActive)
|
||||||
|
|
||||||
rootViewController.select(route: .notifications, animated: false)
|
rootViewController.select(route: .notifications, animated: false) {
|
||||||
let vc = NotificationLoadingViewController(notificationID: notificationID, mastodonController: mastodonController)
|
let vc = NotificationLoadingViewController(notificationID: notificationID, mastodonController: mastodonController)
|
||||||
rootViewController.getNavigationController().pushViewController(vc, animated: false)
|
rootViewController.getNavigationController().pushViewController(vc, animated: false)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
let activity = UserActivityManager.showNotificationActivity(id: notificationID, accountID: accountID)
|
let activity = UserActivityManager.showNotificationActivity(id: notificationID, accountID: accountID)
|
||||||
|
if #available(iOS 17.0, *) {
|
||||||
|
let request = UISceneSessionActivationRequest(userActivity: activity)
|
||||||
|
UIApplication.shared.activateSceneSession(for: request)
|
||||||
|
} else {
|
||||||
UIApplication.shared.requestSceneSessionActivation(nil, userActivity: activity, options: nil)
|
UIApplication.shared.requestSceneSessionActivation(nil, userActivity: activity, options: nil)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
completionHandler()
|
completionHandler()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,8 +32,9 @@ class AuxiliarySceneDelegate: UIResponder, UIWindowSceneDelegate, TuskerSceneDel
|
||||||
}
|
}
|
||||||
launchActivity = activity
|
launchActivity = activity
|
||||||
|
|
||||||
let account: UserAccountInfo
|
scene.activationConditions.canActivateForTargetContentIdentifierPredicate = NSPredicate(value: false)
|
||||||
|
|
||||||
|
let account: UserAccountInfo
|
||||||
if let activityAccount = UserActivityManager.getAccount(from: activity) {
|
if let activityAccount = UserActivityManager.getAccount(from: activity) {
|
||||||
account = activityAccount
|
account = activityAccount
|
||||||
} else if let mostRecent = UserAccountsManager.shared.getMostRecentAccount() {
|
} else if let mostRecent = UserAccountsManager.shared.getMostRecentAccount() {
|
||||||
|
|
|
@ -29,6 +29,8 @@ class ComposeSceneDelegate: UIResponder, UIWindowSceneDelegate, TuskerSceneDeleg
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
scene.activationConditions.canActivateForTargetContentIdentifierPredicate = NSPredicate(value: false)
|
||||||
|
|
||||||
let account: UserAccountInfo
|
let account: UserAccountInfo
|
||||||
let controller: MastodonController
|
let controller: MastodonController
|
||||||
let draft: Draft?
|
let draft: Draft?
|
||||||
|
|
|
@ -83,7 +83,9 @@ class MainSceneDelegate: UIResponder, UIWindowSceneDelegate, TuskerSceneDelegate
|
||||||
} else {
|
} else {
|
||||||
context = ActiveAccountUserActivityHandlingContext(isHandoff: true, root: rootViewController!)
|
context = ActiveAccountUserActivityHandlingContext(isHandoff: true, root: rootViewController!)
|
||||||
}
|
}
|
||||||
_ = userActivity.handleResume(manager: UserActivityManager(scene: scene as! UIWindowScene, context: context))
|
Task(priority: .userInitiated) {
|
||||||
|
_ = await userActivity.handleResume(manager: UserActivityManager(scene: scene as! UIWindowScene, context: context))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func windowScene(_ windowScene: UIWindowScene, performActionFor shortcutItem: UIApplicationShortcutItem, completionHandler: @escaping (Bool) -> Void) {
|
func windowScene(_ windowScene: UIWindowScene, performActionFor shortcutItem: UIApplicationShortcutItem, completionHandler: @escaping (Bool) -> Void) {
|
||||||
|
@ -191,9 +193,11 @@ class MainSceneDelegate: UIResponder, UIWindowSceneDelegate, TuskerSceneDelegate
|
||||||
|
|
||||||
if let activity = launchActivity {
|
if let activity = launchActivity {
|
||||||
func doRestoreActivity(context: UserActivityHandlingContext) {
|
func doRestoreActivity(context: UserActivityHandlingContext) {
|
||||||
_ = activity.handleResume(manager: UserActivityManager(scene: window!.windowScene!, context: context))
|
Task(priority: .userInitiated) {
|
||||||
|
_ = await activity.handleResume(manager: UserActivityManager(scene: window!.windowScene!, context: context))
|
||||||
context.finalize(activity: activity)
|
context.finalize(activity: activity)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if activity.isStateRestorationActivity {
|
if activity.isStateRestorationActivity {
|
||||||
doRestoreActivity(context: StateRestorationUserActivityHandlingContext(root: rootViewController!))
|
doRestoreActivity(context: StateRestorationUserActivityHandlingContext(root: rootViewController!))
|
||||||
} else if activity.activityType != UserActivityType.mainScene.rawValue {
|
} else if activity.activityType != UserActivityType.mainScene.rawValue {
|
||||||
|
@ -225,6 +229,8 @@ class MainSceneDelegate: UIResponder, UIWindowSceneDelegate, TuskerSceneDelegate
|
||||||
window!.windowScene!.title = account.instanceURL.host!
|
window!.windowScene!.title = account.instanceURL.host!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
window!.windowScene!.activationConditions.prefersToActivateForTargetContentIdentifierPredicate = NSPredicate(format: "self == %@", account.id)
|
||||||
|
|
||||||
if let container = window?.rootViewController as? AccountSwitchingContainerViewController {
|
if let container = window?.rootViewController as? AccountSwitchingContainerViewController {
|
||||||
let direction: AccountSwitchingContainerViewController.AnimationDirection
|
let direction: AccountSwitchingContainerViewController.AnimationDirection
|
||||||
if animated,
|
if animated,
|
||||||
|
|
|
@ -70,11 +70,13 @@ class AccountSwitchingContainerViewController: UIViewController {
|
||||||
stateRestorationLogger.debug("AccountSwitchingContainer: reusing existing VC for \(account.id, privacy: .public)")
|
stateRestorationLogger.debug("AccountSwitchingContainer: reusing existing VC for \(account.id, privacy: .public)")
|
||||||
} else {
|
} else {
|
||||||
newRoot = newRootProvider()
|
newRoot = newRootProvider()
|
||||||
|
Task(priority: .userInitiated) {
|
||||||
stateRestorationLogger.debug("AccountSwitchingContainer: restoring \(activity.activityType, privacy: .public) for \(account.id, privacy: .public)")
|
stateRestorationLogger.debug("AccountSwitchingContainer: restoring \(activity.activityType, privacy: .public) for \(account.id, privacy: .public)")
|
||||||
let context = StateRestorationUserActivityHandlingContext(root: newRoot)
|
let context = StateRestorationUserActivityHandlingContext(root: newRoot)
|
||||||
_ = activity.handleResume(manager: UserActivityManager(scene: view.window!.windowScene!, context: context))
|
_ = await activity.handleResume(manager: UserActivityManager(scene: view.window!.windowScene!, context: context))
|
||||||
context.finalize(activity: activity)
|
context.finalize(activity: activity)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
newRoot = newRootProvider()
|
newRoot = newRootProvider()
|
||||||
}
|
}
|
||||||
|
@ -150,9 +152,9 @@ extension AccountSwitchingContainerViewController: TuskerRootViewController {
|
||||||
root.compose(editing: draft, animated: animated, isDucked: isDucked)
|
root.compose(editing: draft, animated: animated, isDucked: isDucked)
|
||||||
}
|
}
|
||||||
|
|
||||||
func select(route: TuskerRoute, animated: Bool) {
|
func select(route: TuskerRoute, animated: Bool, completion: (() -> Void)?) {
|
||||||
loadViewIfNeeded()
|
loadViewIfNeeded()
|
||||||
root.select(route: route, animated: animated)
|
root.select(route: route, animated: animated, completion: completion)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getTabController(tab: MainTabBarViewController.Tab) -> UIViewController? {
|
func getTabController(tab: MainTabBarViewController.Tab) -> UIViewController? {
|
||||||
|
|
|
@ -35,8 +35,8 @@ extension DuckableContainerViewController: AccountSwitchableViewController {
|
||||||
(child as! TuskerRootViewController).getNavigationController()
|
(child as! TuskerRootViewController).getNavigationController()
|
||||||
}
|
}
|
||||||
|
|
||||||
func select(route: TuskerRoute, animated: Bool) {
|
func select(route: TuskerRoute, animated: Bool, completion: (() -> Void)?) {
|
||||||
(child as? TuskerRootViewController)?.select(route: route, animated: animated)
|
(child as? TuskerRootViewController)?.select(route: route, animated: animated, completion: completion)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getTabController(tab: MainTabBarViewController.Tab) -> UIViewController? {
|
func getTabController(tab: MainTabBarViewController.Tab) -> UIViewController? {
|
||||||
|
|
|
@ -13,8 +13,8 @@ import Combine
|
||||||
@MainActor
|
@MainActor
|
||||||
protocol MainSidebarViewControllerDelegate: AnyObject {
|
protocol MainSidebarViewControllerDelegate: AnyObject {
|
||||||
func sidebarRequestPresentCompose(_ sidebarViewController: MainSidebarViewController)
|
func sidebarRequestPresentCompose(_ sidebarViewController: MainSidebarViewController)
|
||||||
func sidebar(_ sidebarViewController: MainSidebarViewController, didSelectItem item: MainSidebarViewController.Item)
|
func sidebar(_ sidebarViewController: MainSidebarViewController, didSelectItem item: MainSidebarViewController.Item, previousItem: MainSidebarViewController.Item?)
|
||||||
func sidebar(_ sidebarViewController: MainSidebarViewController, showViewController viewController: UIViewController)
|
func sidebar(_ sidebarViewController: MainSidebarViewController, showViewController viewController: UIViewController, previousItem: MainSidebarViewController.Item?)
|
||||||
func sidebar(_ sidebarViewController: MainSidebarViewController, scrollToTopFor item: MainSidebarViewController.Item)
|
func sidebar(_ sidebarViewController: MainSidebarViewController, scrollToTopFor item: MainSidebarViewController.Item)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,7 +57,7 @@ class MainSidebarViewController: UIViewController {
|
||||||
return items
|
return items
|
||||||
}
|
}
|
||||||
|
|
||||||
private(set) var previouslySelectedItem: Item?
|
private var previouslySelectedItem: Item?
|
||||||
var selectedItem: Item? {
|
var selectedItem: Item? {
|
||||||
guard let indexPath = collectionView?.indexPathsForSelectedItems?.first else {
|
guard let indexPath = collectionView?.indexPathsForSelectedItems?.first else {
|
||||||
return nil
|
return nil
|
||||||
|
@ -261,19 +261,21 @@ class MainSidebarViewController: UIViewController {
|
||||||
}
|
}
|
||||||
|
|
||||||
private func returnToPreviousItem() {
|
private func returnToPreviousItem() {
|
||||||
let item = previouslySelectedItem ?? .tab(.timelines)
|
let oldItem = selectedItem
|
||||||
|
let newItem = previouslySelectedItem ?? .tab(.timelines)
|
||||||
previouslySelectedItem = nil
|
previouslySelectedItem = nil
|
||||||
select(item: item, animated: true)
|
select(item: newItem, animated: true)
|
||||||
sidebarDelegate?.sidebar(self, didSelectItem: item)
|
sidebarDelegate?.sidebar(self, didSelectItem: newItem, previousItem: oldItem)
|
||||||
}
|
}
|
||||||
|
|
||||||
private func showAddList() {
|
private func showAddList() {
|
||||||
let service = CreateListService(mastodonController: mastodonController, present: { self.present($0, animated: true
|
let service = CreateListService(mastodonController: mastodonController, present: { self.present($0, animated: true
|
||||||
) }) { list in
|
) }) { list in
|
||||||
|
let oldItem = self.selectedItem
|
||||||
self.select(item: .list(list), animated: false)
|
self.select(item: .list(list), animated: false)
|
||||||
let list = ListTimelineViewController(for: list, mastodonController: self.mastodonController)
|
let list = ListTimelineViewController(for: list, mastodonController: self.mastodonController)
|
||||||
list.presentEditOnAppear = true
|
list.presentEditOnAppear = true
|
||||||
self.sidebarDelegate?.sidebar(self, showViewController: list)
|
self.sidebarDelegate?.sidebar(self, showViewController: list, previousItem: oldItem)
|
||||||
}
|
}
|
||||||
service.run()
|
service.run()
|
||||||
}
|
}
|
||||||
|
@ -471,7 +473,7 @@ extension MainSidebarViewController: UICollectionViewDelegate {
|
||||||
fatalError("unreachable")
|
fatalError("unreachable")
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
sidebarDelegate?.sidebar(self, didSelectItem: item)
|
sidebarDelegate?.sidebar(self, didSelectItem: item, previousItem: previouslySelectedItem)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -540,8 +542,9 @@ extension MainSidebarViewController: UICollectionViewDragDelegate {
|
||||||
extension MainSidebarViewController: InstanceTimelineViewControllerDelegate {
|
extension MainSidebarViewController: InstanceTimelineViewControllerDelegate {
|
||||||
func didSaveInstance(url: URL) {
|
func didSaveInstance(url: URL) {
|
||||||
dismiss(animated: true) {
|
dismiss(animated: true) {
|
||||||
|
let oldItem = self.selectedItem
|
||||||
self.select(item: .savedInstance(url), animated: true)
|
self.select(item: .savedInstance(url), animated: true)
|
||||||
self.sidebarDelegate?.sidebar(self, didSelectItem: .savedInstance(url))
|
self.sidebarDelegate?.sidebar(self, didSelectItem: .savedInstance(url), previousItem: oldItem)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -86,7 +86,7 @@ class MainSplitViewController: UISplitViewController {
|
||||||
// don't unnecesarily construct a content VC unless the we're in actually split mode
|
// don't unnecesarily construct a content VC unless the we're in actually split mode
|
||||||
// when we change from compact -> split for the first time, the VC will be transferred anyways
|
// when we change from compact -> split for the first time, the VC will be transferred anyways
|
||||||
if traitCollection.horizontalSizeClass != .compact {
|
if traitCollection.horizontalSizeClass != .compact {
|
||||||
select(item: .tab(.timelines))
|
doSelect(item: .tab(.timelines))
|
||||||
}
|
}
|
||||||
|
|
||||||
if UIDevice.current.userInterfaceIdiom != .mac {
|
if UIDevice.current.userInterfaceIdiom != .mac {
|
||||||
|
@ -149,7 +149,15 @@ class MainSplitViewController: UISplitViewController {
|
||||||
self.setViewController(newNav, for: .secondary)
|
self.setViewController(newNav, for: .secondary)
|
||||||
}
|
}
|
||||||
|
|
||||||
func select(item: MainSidebarViewController.Item) {
|
private func select(newItem: MainSidebarViewController.Item, oldItem: MainSidebarViewController.Item?) {
|
||||||
|
if let oldItem,
|
||||||
|
newItem != oldItem {
|
||||||
|
navigationStacks[oldItem] = secondaryNavController.viewControllers
|
||||||
|
}
|
||||||
|
doSelect(item: newItem)
|
||||||
|
}
|
||||||
|
|
||||||
|
private func doSelect(item: MainSidebarViewController.Item) {
|
||||||
secondaryNavController.viewControllers = getOrCreateNavigationStack(item: item)
|
secondaryNavController.viewControllers = getOrCreateNavigationStack(item: item)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -180,43 +188,28 @@ class MainSplitViewController: UISplitViewController {
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc func handleSidebarCommandTimelines() {
|
@objc func handleSidebarCommandTimelines() {
|
||||||
if let previous = sidebar.selectedItem {
|
|
||||||
navigationStacks[previous] = secondaryNavController.viewControllers
|
|
||||||
}
|
|
||||||
sidebar.select(item: .tab(.timelines), animated: false)
|
sidebar.select(item: .tab(.timelines), animated: false)
|
||||||
select(item: .tab(.timelines))
|
select(newItem: .tab(.timelines), oldItem: sidebar.selectedItem)
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc func handleSidebarCommandNotifications() {
|
@objc func handleSidebarCommandNotifications() {
|
||||||
if let previous = sidebar.selectedItem {
|
|
||||||
navigationStacks[previous] = secondaryNavController.viewControllers
|
|
||||||
}
|
|
||||||
sidebar.select(item: .tab(.notifications), animated: false)
|
sidebar.select(item: .tab(.notifications), animated: false)
|
||||||
select(item: .tab(.notifications))
|
select(newItem: .tab(.notifications), oldItem: sidebar.selectedItem)
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc func handleSidebarCommandExplore() {
|
@objc func handleSidebarCommandExplore() {
|
||||||
if let previous = sidebar.selectedItem {
|
|
||||||
navigationStacks[previous] = secondaryNavController.viewControllers
|
|
||||||
}
|
|
||||||
sidebar.select(item: .tab(.explore), animated: false)
|
sidebar.select(item: .tab(.explore), animated: false)
|
||||||
select(item: .tab(.explore))
|
select(newItem: .tab(.explore), oldItem: sidebar.selectedItem)
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc func handleSidebarCommandBookmarks() {
|
@objc func handleSidebarCommandBookmarks() {
|
||||||
if let previous = sidebar.selectedItem {
|
|
||||||
navigationStacks[previous] = secondaryNavController.viewControllers
|
|
||||||
}
|
|
||||||
sidebar.select(item: .bookmarks, animated: false)
|
sidebar.select(item: .bookmarks, animated: false)
|
||||||
select(item: .bookmarks)
|
select(newItem: .bookmarks, oldItem: sidebar.selectedItem)
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc func handleSidebarCommandMyProfile() {
|
@objc func handleSidebarCommandMyProfile() {
|
||||||
if let previous = sidebar.selectedItem {
|
|
||||||
navigationStacks[previous] = secondaryNavController.viewControllers
|
|
||||||
}
|
|
||||||
sidebar.select(item: .tab(.myProfile), animated: false)
|
sidebar.select(item: .tab(.myProfile), animated: false)
|
||||||
select(item: .tab(.myProfile))
|
select(newItem: .tab(.myProfile), oldItem: sidebar.selectedItem)
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc private func sidebarTapped() {
|
@objc private func sidebarTapped() {
|
||||||
|
@ -459,12 +452,12 @@ extension MainSplitViewController: UISplitViewControllerDelegate {
|
||||||
// These tabs map 1 <-> 1 with sidebar items
|
// These tabs map 1 <-> 1 with sidebar items
|
||||||
let item = MainSidebarViewController.Item.tab(tabBarViewController.selectedTab)
|
let item = MainSidebarViewController.Item.tab(tabBarViewController.selectedTab)
|
||||||
sidebar.select(item: item, animated: false)
|
sidebar.select(item: item, animated: false)
|
||||||
select(item: item)
|
doSelect(item: item)
|
||||||
|
|
||||||
case .explore:
|
case .explore:
|
||||||
// If the explore tab is active, the sidebar item is determined above when transferring the explore VC's nav stack
|
// If the explore tab is active, the sidebar item is determined above when transferring the explore VC's nav stack
|
||||||
sidebar.select(item: exploreItem!, animated: false)
|
sidebar.select(item: exploreItem!, animated: false)
|
||||||
select(item: exploreItem!)
|
doSelect(item: exploreItem!)
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return
|
return
|
||||||
|
@ -489,16 +482,13 @@ extension MainSplitViewController: MainSidebarViewControllerDelegate {
|
||||||
compose(editing: nil)
|
compose(editing: nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func sidebar(_ sidebarViewController: MainSidebarViewController, didSelectItem item: MainSidebarViewController.Item) {
|
func sidebar(_ sidebarViewController: MainSidebarViewController, didSelectItem item: MainSidebarViewController.Item, previousItem: MainSidebarViewController.Item?) {
|
||||||
if let previous = sidebar.previouslySelectedItem {
|
select(newItem: item, oldItem: previousItem)
|
||||||
navigationStacks[previous] = secondaryNavController.viewControllers
|
|
||||||
}
|
|
||||||
select(item: item)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func sidebar(_ sidebarViewController: MainSidebarViewController, showViewController viewController: UIViewController) {
|
func sidebar(_ sidebarViewController: MainSidebarViewController, showViewController viewController: UIViewController, previousItem: MainSidebarViewController.Item?) {
|
||||||
if let previous = sidebar.previouslySelectedItem {
|
if let previousItem {
|
||||||
navigationStacks[previous] = secondaryNavController.viewControllers
|
navigationStacks[previousItem] = secondaryNavController.viewControllers
|
||||||
}
|
}
|
||||||
secondaryNavController.viewControllers = [viewController]
|
secondaryNavController.viewControllers = [viewController]
|
||||||
}
|
}
|
||||||
|
@ -552,14 +542,14 @@ extension MainSplitViewController: StateRestorableViewController {
|
||||||
}
|
}
|
||||||
|
|
||||||
extension MainSplitViewController: TuskerRootViewController {
|
extension MainSplitViewController: TuskerRootViewController {
|
||||||
func select(route: TuskerRoute, animated: Bool) {
|
func select(route: TuskerRoute, animated: Bool, completion: (() -> Void)?) {
|
||||||
guard traitCollection.horizontalSizeClass != .compact else {
|
guard traitCollection.horizontalSizeClass != .compact else {
|
||||||
tabBarViewController?.select(route: route, animated: animated)
|
tabBarViewController?.select(route: route, animated: animated, completion: completion)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
guard presentedViewController == nil else {
|
guard presentedViewController == nil else {
|
||||||
dismiss(animated: animated) {
|
dismiss(animated: animated) {
|
||||||
self.select(route: route, animated: animated)
|
self.select(route: route, animated: animated, completion: completion)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -582,8 +572,10 @@ extension MainSplitViewController: TuskerRootViewController {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
let oldItem = sidebar.selectedItem
|
||||||
sidebar.select(item: item, animated: false)
|
sidebar.select(item: item, animated: false)
|
||||||
select(item: item)
|
select(newItem: item, oldItem: oldItem)
|
||||||
|
completion?()
|
||||||
}
|
}
|
||||||
|
|
||||||
func getTabController(tab: MainTabBarViewController.Tab) -> UIViewController? {
|
func getTabController(tab: MainTabBarViewController.Tab) -> UIViewController? {
|
||||||
|
@ -625,7 +617,7 @@ extension MainSplitViewController: TuskerRootViewController {
|
||||||
}
|
}
|
||||||
|
|
||||||
if sidebar.selectedItem != .explore {
|
if sidebar.selectedItem != .explore {
|
||||||
select(item: .explore)
|
select(newItem: .explore, oldItem: sidebar.selectedItem)
|
||||||
}
|
}
|
||||||
|
|
||||||
guard let searchViewController = secondaryNavController.viewControllers.first as? InlineTrendsViewController else {
|
guard let searchViewController = secondaryNavController.viewControllers.first as? InlineTrendsViewController else {
|
||||||
|
|
|
@ -289,7 +289,7 @@ extension MainTabBarViewController: StateRestorableViewController {
|
||||||
}
|
}
|
||||||
|
|
||||||
extension MainTabBarViewController: TuskerRootViewController {
|
extension MainTabBarViewController: TuskerRootViewController {
|
||||||
func select(route: TuskerRoute, animated: Bool) {
|
func select(route: TuskerRoute, animated: Bool, completion: (() -> Void)?) {
|
||||||
switch route {
|
switch route {
|
||||||
case .timelines:
|
case .timelines:
|
||||||
select(tab: .timelines, dismissPresented: true)
|
select(tab: .timelines, dismissPresented: true)
|
||||||
|
@ -310,6 +310,7 @@ extension MainTabBarViewController: TuskerRootViewController {
|
||||||
nav.pushViewController(ListTimelineViewController(for: list, mastodonController: mastodonController), animated: animated)
|
nav.pushViewController(ListTimelineViewController(for: list, mastodonController: mastodonController), animated: animated)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
completion?()
|
||||||
}
|
}
|
||||||
|
|
||||||
func getNavigationDelegate() -> TuskerNavigationDelegate? {
|
func getNavigationDelegate() -> TuskerNavigationDelegate? {
|
||||||
|
|
|
@ -12,7 +12,7 @@ import ComposeUI
|
||||||
@MainActor
|
@MainActor
|
||||||
protocol TuskerRootViewController: UIViewController, StateRestorableViewController, StatusBarTappableViewController {
|
protocol TuskerRootViewController: UIViewController, StateRestorableViewController, StatusBarTappableViewController {
|
||||||
func compose(editing draft: Draft?, animated: Bool, isDucked: Bool)
|
func compose(editing draft: Draft?, animated: Bool, isDucked: Bool)
|
||||||
func select(route: TuskerRoute, animated: Bool)
|
func select(route: TuskerRoute, animated: Bool, completion: (() -> Void)?)
|
||||||
func getTabController(tab: MainTabBarViewController.Tab) -> UIViewController?
|
func getTabController(tab: MainTabBarViewController.Tab) -> UIViewController?
|
||||||
func getNavigationDelegate() -> TuskerNavigationDelegate?
|
func getNavigationDelegate() -> TuskerNavigationDelegate?
|
||||||
func getNavigationController() -> NavigationControllerProtocol
|
func getNavigationController() -> NavigationControllerProtocol
|
||||||
|
@ -21,33 +21,6 @@ protocol TuskerRootViewController: UIViewController, StateRestorableViewControll
|
||||||
func presentPreferences(completion: (() -> Void)?) -> PreferencesNavigationController?
|
func presentPreferences(completion: (() -> Void)?) -> PreferencesNavigationController?
|
||||||
}
|
}
|
||||||
|
|
||||||
//extension TuskerRootViewController {
|
|
||||||
// func select(route: NewRoute, animated: Bool) {
|
|
||||||
// doApply(components: route.components, animated: animated)
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// private func doApply(components: ArraySlice<RouteComponent>, animated: Bool) {
|
|
||||||
// guard let first = components.first else {
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
// doApply(component: first, animated: animated) {
|
|
||||||
// self.doApply(components: components.dropFirst(), animated: animated)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// private func doApply(component: RouteComponent, animated: Bool, completion: @escaping () -> Void) {
|
|
||||||
// switch component {
|
|
||||||
// case .topLevelItem(let rootRoute):
|
|
||||||
// select(route: rootRoute)
|
|
||||||
// completion()
|
|
||||||
// case .popToRoot:
|
|
||||||
// _ = getNavigationController().popToRootViewController(animated: animated)
|
|
||||||
// completion()
|
|
||||||
// case .push(<#T##(MastodonController) -> UIViewController#>)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
|
|
||||||
enum TuskerRoute {
|
enum TuskerRoute {
|
||||||
case timelines
|
case timelines
|
||||||
case notifications
|
case notifications
|
||||||
|
@ -57,33 +30,6 @@ enum TuskerRoute {
|
||||||
case list(id: String)
|
case list(id: String)
|
||||||
}
|
}
|
||||||
|
|
||||||
//struct NewRoute: ExpressibleByArrayLiteral {
|
|
||||||
// let components: [RouteComponent]
|
|
||||||
//
|
|
||||||
// init(arrayLiteral elements: RouteComponent...) {
|
|
||||||
// self.components = elements
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// static var timelines: Self { [.topLevelItem(.timelines)] }
|
|
||||||
// static var explore: Self { [.topLevelItem(.explore)] }
|
|
||||||
// static var myProfile: Self { [.topLevelItem(.myProfile)] }
|
|
||||||
// static var bookmarks: Self { [.topLevelItem(.explore), .push({ BookmarksViewController(mastodonController: $0) })] }
|
|
||||||
// static func profile(accountID: String) -> Self { [.topLevelItem(.timelines), .push({ ProfileViewController(accountID: accountID, mastodonController: $0) })] }
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//enum RouteComponent {
|
|
||||||
// case topLevelItem(RootRoute)
|
|
||||||
// case popToRoot
|
|
||||||
// case push((MastodonController) -> UIViewController)
|
|
||||||
// case present(UIViewController)
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//enum RootRoute {
|
|
||||||
// case timelines
|
|
||||||
// case explore
|
|
||||||
// case myProfile
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
@MainActor
|
@MainActor
|
||||||
protocol NavigationControllerProtocol: UIViewController {
|
protocol NavigationControllerProtocol: UIViewController {
|
||||||
var viewControllers: [UIViewController] { get set }
|
var viewControllers: [UIViewController] { get set }
|
||||||
|
|
|
@ -94,10 +94,14 @@ class NotificationLoadingViewController: UIViewController {
|
||||||
showLoadingError(Error.unknownType)
|
showLoadingError(Error.unknownType)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
guard let navigationController else {
|
// guard let navigationController else {
|
||||||
fatalError("Don't know how to show notification VC outside of navigation controller")
|
// fatalError("Don't know how to show notification VC outside of navigation controller")
|
||||||
}
|
// }
|
||||||
|
if let navigationController {
|
||||||
navigationController.viewControllers[navigationController.viewControllers.count - 1] = vc
|
navigationController.viewControllers[navigationController.viewControllers.count - 1] = vc
|
||||||
|
} else {
|
||||||
|
print("AAAAAAAAAA")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func showLoadingError(_ error: any Swift.Error) {
|
private func showLoadingError(_ error: any Swift.Error) {
|
||||||
|
|
|
@ -44,9 +44,9 @@ enum AppShortcutItem: String, CaseIterable {
|
||||||
}
|
}
|
||||||
switch self {
|
switch self {
|
||||||
case .showHomeTimeline:
|
case .showHomeTimeline:
|
||||||
root.select(route: .timelines, animated: false)
|
root.select(route: .timelines, animated: false, completion: nil)
|
||||||
case .showNotifications:
|
case .showNotifications:
|
||||||
root.select(route: .notifications, animated: false)
|
root.select(route: .notifications, animated: false, completion: nil)
|
||||||
case .composePost:
|
case .composePost:
|
||||||
root.compose(editing: nil, animated: false, isDucked: false)
|
root.compose(editing: nil, animated: false, isDucked: false)
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,12 +39,13 @@ extension NSUserActivity {
|
||||||
self.userInfo = [
|
self.userInfo = [
|
||||||
"accountID": accountID
|
"accountID": accountID
|
||||||
]
|
]
|
||||||
|
self.targetContentIdentifier = accountID
|
||||||
}
|
}
|
||||||
|
|
||||||
@MainActor
|
@MainActor
|
||||||
func handleResume(manager: UserActivityManager) -> Bool {
|
func handleResume(manager: UserActivityManager) async -> Bool {
|
||||||
guard let type = UserActivityType(rawValue: activityType) else { return false }
|
guard let type = UserActivityType(rawValue: activityType) else { return false }
|
||||||
type.handle(manager)(self)
|
await type.handle(manager)(self)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,8 @@ import ComposeUI
|
||||||
protocol UserActivityHandlingContext {
|
protocol UserActivityHandlingContext {
|
||||||
var isHandoff: Bool { get }
|
var isHandoff: Bool { get }
|
||||||
|
|
||||||
func select(route: TuskerRoute)
|
func select(route: TuskerRoute) async
|
||||||
|
func select(route: TuskerRoute, completion: (() -> Void)?)
|
||||||
func present(_ vc: UIViewController)
|
func present(_ vc: UIViewController)
|
||||||
|
|
||||||
var topViewController: UIViewController? { get }
|
var topViewController: UIViewController? { get }
|
||||||
|
@ -28,6 +29,16 @@ protocol UserActivityHandlingContext {
|
||||||
func finalize(activity: NSUserActivity)
|
func finalize(activity: NSUserActivity)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension UserActivityHandlingContext {
|
||||||
|
func select(route: TuskerRoute) async {
|
||||||
|
await withCheckedContinuation { continuation in
|
||||||
|
select(route: route) {
|
||||||
|
continuation.resume()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
struct ActiveAccountUserActivityHandlingContext: UserActivityHandlingContext {
|
struct ActiveAccountUserActivityHandlingContext: UserActivityHandlingContext {
|
||||||
let isHandoff: Bool
|
let isHandoff: Bool
|
||||||
let root: TuskerRootViewController
|
let root: TuskerRootViewController
|
||||||
|
@ -35,8 +46,8 @@ struct ActiveAccountUserActivityHandlingContext: UserActivityHandlingContext {
|
||||||
root.getNavigationDelegate()!
|
root.getNavigationDelegate()!
|
||||||
}
|
}
|
||||||
|
|
||||||
func select(route: TuskerRoute) {
|
func select(route: TuskerRoute, completion: (() -> Void)?) {
|
||||||
root.select(route: route, animated: true)
|
root.select(route: route, animated: true, completion: completion)
|
||||||
}
|
}
|
||||||
|
|
||||||
func present(_ vc: UIViewController) {
|
func present(_ vc: UIViewController) {
|
||||||
|
@ -71,9 +82,11 @@ class StateRestorationUserActivityHandlingContext: UserActivityHandlingContext {
|
||||||
|
|
||||||
var isHandoff: Bool { false }
|
var isHandoff: Bool { false }
|
||||||
|
|
||||||
func select(route: TuskerRoute) {
|
func select(route: TuskerRoute, completion: (() -> Void)?) {
|
||||||
root.select(route: route, animated: false)
|
root.select(route: route, animated: false) {
|
||||||
state = .selectedRoute
|
self.state = .selectedRoute
|
||||||
|
completion?()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var topViewController: UIViewController? { root.getNavigationController().topViewController }
|
var topViewController: UIViewController? { root.getNavigationController().topViewController }
|
||||||
|
|
|
@ -133,8 +133,8 @@ class UserActivityManager {
|
||||||
return activity
|
return activity
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleCheckNotifications(activity: NSUserActivity) {
|
func handleCheckNotifications(activity: NSUserActivity) async {
|
||||||
context.select(route: .notifications)
|
await context.select(route: .notifications)
|
||||||
context.popToRoot()
|
context.popToRoot()
|
||||||
if let notificationsPageController = context.topViewController as? NotificationsPageViewController {
|
if let notificationsPageController = context.topViewController as? NotificationsPageViewController {
|
||||||
notificationsPageController.loadViewIfNeeded()
|
notificationsPageController.loadViewIfNeeded()
|
||||||
|
@ -204,22 +204,22 @@ class UserActivityManager {
|
||||||
return (timeline, positionInfo)
|
return (timeline, positionInfo)
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleShowTimeline(activity: NSUserActivity) {
|
func handleShowTimeline(activity: NSUserActivity) async {
|
||||||
guard let (timeline, positionInfo) = Self.getTimeline(from: activity) else { return }
|
guard let (timeline, positionInfo) = Self.getTimeline(from: activity) else { return }
|
||||||
|
|
||||||
var timelineVC: TimelineViewController?
|
var timelineVC: TimelineViewController?
|
||||||
if let pinned = PinnedTimeline(timeline: timeline),
|
if let pinned = PinnedTimeline(timeline: timeline),
|
||||||
mastodonController.accountPreferences.pinnedTimelines.contains(pinned) {
|
mastodonController.accountPreferences.pinnedTimelines.contains(pinned) {
|
||||||
context.select(route: .timelines)
|
await context.select(route: .timelines)
|
||||||
context.popToRoot()
|
context.popToRoot()
|
||||||
let pageController = context.topViewController as! TimelinesPageViewController
|
let pageController = context.topViewController as! TimelinesPageViewController
|
||||||
pageController.selectTimeline(pinned, animated: false)
|
pageController.selectTimeline(pinned, animated: false)
|
||||||
timelineVC = pageController.currentViewController as? TimelineViewController
|
timelineVC = pageController.currentViewController as? TimelineViewController
|
||||||
} else if case .list(let id) = timeline {
|
} else if case .list(let id) = timeline {
|
||||||
context.select(route: .list(id: id))
|
await context.select(route: .list(id: id))
|
||||||
timelineVC = context.topViewController as? TimelineViewController
|
timelineVC = context.topViewController as? TimelineViewController
|
||||||
} else {
|
} else {
|
||||||
context.select(route: .explore)
|
await context.select(route: .explore)
|
||||||
context.popToRoot()
|
context.popToRoot()
|
||||||
timelineVC = TimelineViewController(for: timeline, mastodonController: mastodonController)
|
timelineVC = TimelineViewController(for: timeline, mastodonController: mastodonController)
|
||||||
context.push(timelineVC!)
|
context.push(timelineVC!)
|
||||||
|
@ -249,11 +249,11 @@ class UserActivityManager {
|
||||||
return activity.userInfo?["mainStatusID"] as? String
|
return activity.userInfo?["mainStatusID"] as? String
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleShowConversation(activity: NSUserActivity) {
|
func handleShowConversation(activity: NSUserActivity) async {
|
||||||
guard let mainStatusID = Self.getConversationStatus(from: activity) else {
|
guard let mainStatusID = Self.getConversationStatus(from: activity) else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
context.select(route: .timelines)
|
await context.select(route: .timelines)
|
||||||
context.push(ConversationViewController(for: mainStatusID, state: .unknown, mastodonController: mastodonController))
|
context.push(ConversationViewController(for: mainStatusID, state: .unknown, mastodonController: mastodonController))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -274,8 +274,8 @@ class UserActivityManager {
|
||||||
return activity.userInfo?["query"] as? String
|
return activity.userInfo?["query"] as? String
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleSearch(activity: NSUserActivity) {
|
func handleSearch(activity: NSUserActivity) async {
|
||||||
context.select(route: .explore)
|
await context.select(route: .explore)
|
||||||
context.popToRoot()
|
context.popToRoot()
|
||||||
|
|
||||||
let searchController: UISearchController
|
let searchController: UISearchController
|
||||||
|
@ -311,8 +311,8 @@ class UserActivityManager {
|
||||||
return activity
|
return activity
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleBookmarks(activity: NSUserActivity) {
|
func handleBookmarks(activity: NSUserActivity) async {
|
||||||
context.select(route: .bookmarks)
|
await context.select(route: .bookmarks)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - My Profile
|
// MARK: - My Profile
|
||||||
|
@ -325,8 +325,8 @@ class UserActivityManager {
|
||||||
return activity
|
return activity
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleMyProfile(activity: NSUserActivity) {
|
func handleMyProfile(activity: NSUserActivity) async {
|
||||||
context.select(route: .myProfile)
|
await context.select(route: .myProfile)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Show Profile
|
// MARK: - Show Profile
|
||||||
|
@ -344,11 +344,11 @@ class UserActivityManager {
|
||||||
return activity.userInfo?["profileID"] as? String
|
return activity.userInfo?["profileID"] as? String
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleShowProfile(activity: NSUserActivity) {
|
func handleShowProfile(activity: NSUserActivity) async {
|
||||||
guard let accountID = Self.getProfile(from: activity) else {
|
guard let accountID = Self.getProfile(from: activity) else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
context.select(route: .timelines)
|
await context.select(route: .timelines)
|
||||||
context.push(ProfileViewController(accountID: accountID, mastodonController: mastodonController))
|
context.push(ProfileViewController(accountID: accountID, mastodonController: mastodonController))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -361,11 +361,11 @@ class UserActivityManager {
|
||||||
return activity
|
return activity
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleShowNotification(activity: NSUserActivity) {
|
func handleShowNotification(activity: NSUserActivity) async {
|
||||||
guard let notificationID = activity.userInfo?["notificationID"] as? String else {
|
guard let notificationID = activity.userInfo?["notificationID"] as? String else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
context.select(route: .notifications)
|
await context.select(route: .notifications)
|
||||||
context.push(NotificationLoadingViewController(notificationID: notificationID, mastodonController: mastodonController))
|
context.push(NotificationLoadingViewController(notificationID: notificationID, mastodonController: mastodonController))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,7 @@ enum UserActivityType: String {
|
||||||
|
|
||||||
extension UserActivityType {
|
extension UserActivityType {
|
||||||
@MainActor
|
@MainActor
|
||||||
var handle: (UserActivityManager) -> @MainActor (NSUserActivity) -> Void {
|
var handle: (UserActivityManager) -> @MainActor (NSUserActivity) async -> Void {
|
||||||
switch self {
|
switch self {
|
||||||
case .mainScene:
|
case .mainScene:
|
||||||
fatalError("cannot handle main scene activity")
|
fatalError("cannot handle main scene activity")
|
||||||
|
|
Loading…
Reference in New Issue