Revert "Fix crash when opening push notification while VC modally presented"

This reverts commit 0f2a85b108.

This fixes state restoration happening asynchronously and causing the
new tab bar animation to run.
This commit is contained in:
Shadowfacts 2024-08-22 14:17:04 -04:00
parent b663335c6d
commit 2eead1f9de
12 changed files with 49 additions and 70 deletions

View File

@ -295,10 +295,9 @@ 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, *) { if #available(iOS 17.0, *) {

View File

@ -83,9 +83,7 @@ class MainSceneDelegate: UIResponder, UIWindowSceneDelegate, TuskerSceneDelegate
} else { } else {
context = ActiveAccountUserActivityHandlingContext(isHandoff: true, root: rootViewController!) context = ActiveAccountUserActivityHandlingContext(isHandoff: true, root: rootViewController!)
} }
Task(priority: .userInitiated) { _ = userActivity.handleResume(manager: UserActivityManager(scene: scene as! UIWindowScene, context: context))
_ = 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) {
@ -193,10 +191,8 @@ class MainSceneDelegate: UIResponder, UIWindowSceneDelegate, TuskerSceneDelegate
if let activity = launchActivity { if let activity = launchActivity {
func doRestoreActivity(context: UserActivityHandlingContext) { func doRestoreActivity(context: UserActivityHandlingContext) {
Task(priority: .userInitiated) { _ = activity.handleResume(manager: UserActivityManager(scene: window!.windowScene!, context: context))
_ = 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!))

View File

@ -79,12 +79,10 @@ 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()
@ -161,9 +159,9 @@ extension AccountSwitchingContainerViewController: TuskerRootViewController {
root.compose(editing: draft, animated: animated, isDucked: isDucked, completion: completion) root.compose(editing: draft, animated: animated, isDucked: isDucked, completion: completion)
} }
func select(route: TuskerRoute, animated: Bool, completion: (() -> Void)?) { func select(route: TuskerRoute, animated: Bool) {
loadViewIfNeeded() loadViewIfNeeded()
root.select(route: route, animated: animated, completion: completion) root.select(route: route, animated: animated)
} }
func getNavigationDelegate() -> TuskerNavigationDelegate? { func getNavigationDelegate() -> TuskerNavigationDelegate? {

View File

@ -35,8 +35,8 @@ extension DuckableContainerViewController: AccountSwitchableViewController {
(child as! TuskerRootViewController).getNavigationController() (child as! TuskerRootViewController).getNavigationController()
} }
func select(route: TuskerRoute, animated: Bool, completion: (() -> Void)?) { func select(route: TuskerRoute, animated: Bool) {
(child as? TuskerRootViewController)?.select(route: route, animated: animated, completion: completion) (child as? TuskerRootViewController)?.select(route: route, animated: animated)
} }
func performSearch(query: String) { func performSearch(query: String) {

View File

@ -546,14 +546,14 @@ extension MainSplitViewController: StateRestorableViewController {
} }
extension MainSplitViewController: TuskerRootViewController { extension MainSplitViewController: TuskerRootViewController {
func select(route: TuskerRoute, animated: Bool, completion: (() -> Void)?) { func select(route: TuskerRoute, animated: Bool) {
guard traitCollection.horizontalSizeClass != .compact else { guard traitCollection.horizontalSizeClass != .compact else {
tabBarViewController?.select(route: route, animated: animated, completion: completion) tabBarViewController?.select(route: route, animated: animated)
return return
} }
guard presentedViewController == nil else { guard presentedViewController == nil else {
dismiss(animated: animated) { dismiss(animated: animated) {
self.select(route: route, animated: animated, completion: completion) self.select(route: route, animated: animated)
} }
return return
} }
@ -579,7 +579,6 @@ extension MainSplitViewController: TuskerRootViewController {
let oldItem = sidebar.selectedItem let oldItem = sidebar.selectedItem
sidebar.select(item: item, animated: false) sidebar.select(item: item, animated: false)
select(newItem: item, oldItem: oldItem) select(newItem: item, oldItem: oldItem)
completion?()
} }
func getNavigationDelegate() -> TuskerNavigationDelegate? { func getNavigationDelegate() -> TuskerNavigationDelegate? {

View File

@ -148,7 +148,7 @@ extension MainTabBarViewController: UITabBarControllerDelegate {
} }
extension MainTabBarViewController: TuskerRootViewController { extension MainTabBarViewController: TuskerRootViewController {
func select(route: TuskerRoute, animated: Bool, completion: (() -> Void)?) { func select(route: TuskerRoute, animated: Bool) {
switch route { switch route {
case .timelines: case .timelines:
select(tab: .timelines, dismissPresented: true) select(tab: .timelines, dismissPresented: true)
@ -169,7 +169,6 @@ 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? {

View File

@ -12,7 +12,8 @@ import ComposeUI
@MainActor @MainActor
protocol TuskerRootViewController: UIViewController, StateRestorableViewController, StatusBarTappableViewController { protocol TuskerRootViewController: UIViewController, StateRestorableViewController, StatusBarTappableViewController {
func compose(editing draft: Draft?, animated: Bool, isDucked: Bool, completion: (() -> Void)?) func compose(editing draft: Draft?, animated: Bool, isDucked: Bool, completion: (() -> Void)?)
func select(route: TuskerRoute, animated: Bool, completion: (() -> Void)?) func select(route: TuskerRoute, animated: Bool)
func getTabController(tab: MainTabBarViewController.Tab) -> UIViewController?
func getNavigationDelegate() -> TuskerNavigationDelegate? func getNavigationDelegate() -> TuskerNavigationDelegate?
func getNavigationController() -> NavigationControllerProtocol func getNavigationController() -> NavigationControllerProtocol
func performSearch(query: String) func performSearch(query: String)

View File

@ -44,9 +44,9 @@ enum AppShortcutItem: String, CaseIterable {
} }
switch self { switch self {
case .showHomeTimeline: case .showHomeTimeline:
root.select(route: .timelines, animated: false, completion: nil) root.select(route: .timelines, animated: false)
case .showNotifications: case .showNotifications:
root.select(route: .notifications, animated: false, completion: nil) root.select(route: .notifications, animated: false)
case .composePost: case .composePost:
root.compose(editing: nil, animated: false, isDucked: false, completion: nil) root.compose(editing: nil, animated: false, isDucked: false, completion: nil)
} }

View File

@ -43,9 +43,9 @@ extension NSUserActivity {
} }
@MainActor @MainActor
func handleResume(manager: UserActivityManager) async -> Bool { func handleResume(manager: UserActivityManager) -> Bool {
guard let type = UserActivityType(rawValue: activityType) else { return false } guard let type = UserActivityType(rawValue: activityType) else { return false }
await type.handle(manager)(self) type.handle(manager)(self)
return true return true
} }

View File

@ -16,8 +16,7 @@ import ComposeUI
protocol UserActivityHandlingContext { protocol UserActivityHandlingContext {
var isHandoff: Bool { get } var isHandoff: Bool { get }
func select(route: TuskerRoute) async func select(route: TuskerRoute)
func select(route: TuskerRoute, completion: (() -> Void)?)
func present(_ vc: UIViewController) func present(_ vc: UIViewController)
var topViewController: UIViewController? { get } var topViewController: UIViewController? { get }
@ -29,16 +28,6 @@ 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
@ -46,8 +35,8 @@ struct ActiveAccountUserActivityHandlingContext: UserActivityHandlingContext {
root.getNavigationDelegate()! root.getNavigationDelegate()!
} }
func select(route: TuskerRoute, completion: (() -> Void)?) { func select(route: TuskerRoute) {
root.select(route: route, animated: true, completion: completion) root.select(route: route, animated: true)
} }
func present(_ vc: UIViewController) { func present(_ vc: UIViewController) {
@ -82,11 +71,9 @@ class StateRestorationUserActivityHandlingContext: UserActivityHandlingContext {
var isHandoff: Bool { false } var isHandoff: Bool { false }
func select(route: TuskerRoute, completion: (() -> Void)?) { func select(route: TuskerRoute) {
root.select(route: route, animated: false) { root.select(route: route, animated: false)
self.state = .selectedRoute state = .selectedRoute
completion?()
}
} }
var topViewController: UIViewController? { root.getNavigationController().topViewController } var topViewController: UIViewController? { root.getNavigationController().topViewController }

View File

@ -133,8 +133,8 @@ class UserActivityManager {
return activity return activity
} }
func handleCheckNotifications(activity: NSUserActivity) async { func handleCheckNotifications(activity: NSUserActivity) {
await context.select(route: .notifications) 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) async { func handleShowTimeline(activity: NSUserActivity) {
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) {
await context.select(route: .timelines) 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 {
await context.select(route: .list(id: id)) context.select(route: .list(id: id))
timelineVC = context.topViewController as? TimelineViewController timelineVC = context.topViewController as? TimelineViewController
} else { } else {
await context.select(route: .explore) 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) async { func handleShowConversation(activity: NSUserActivity) {
guard let mainStatusID = Self.getConversationStatus(from: activity) else { guard let mainStatusID = Self.getConversationStatus(from: activity) else {
return return
} }
await context.select(route: .timelines) 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) async { func handleSearch(activity: NSUserActivity) {
await context.select(route: .explore) 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) async { func handleBookmarks(activity: NSUserActivity) {
await context.select(route: .bookmarks) context.select(route: .bookmarks)
} }
// MARK: - My Profile // MARK: - My Profile
@ -325,8 +325,8 @@ class UserActivityManager {
return activity return activity
} }
func handleMyProfile(activity: NSUserActivity) async { func handleMyProfile(activity: NSUserActivity) {
await context.select(route: .myProfile) 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) async { func handleShowProfile(activity: NSUserActivity) {
guard let accountID = Self.getProfile(from: activity) else { guard let accountID = Self.getProfile(from: activity) else {
return return
} }
await context.select(route: .timelines) 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) async { func handleShowNotification(activity: NSUserActivity) {
guard let notificationID = activity.userInfo?["notificationID"] as? String else { guard let notificationID = activity.userInfo?["notificationID"] as? String else {
return return
} }
await context.select(route: .notifications) context.select(route: .notifications)
context.push(NotificationLoadingViewController(notificationID: notificationID, mastodonController: mastodonController)) context.push(NotificationLoadingViewController(notificationID: notificationID, mastodonController: mastodonController))
} }

View File

@ -23,7 +23,7 @@ enum UserActivityType: String {
extension UserActivityType { extension UserActivityType {
@MainActor @MainActor
var handle: (UserActivityManager) -> @MainActor (NSUserActivity) async -> Void { var handle: (UserActivityManager) -> @MainActor (NSUserActivity) -> Void {
switch self { switch self {
case .mainScene: case .mainScene:
fatalError("cannot handle main scene activity") fatalError("cannot handle main scene activity")