commit 34f0d1b34a840e935be8e57da86f4c64d1ec3122
parent 8f191f2af629623a73ebd5d3f0a92b5c311f3610
Author: Michael Camilleri <[email protected]>
Date: Thu, 30 Apr 2026 12:55:53 +0900
Navigate to games from notification taps
This commit handles notification responses by extracting the related game ID
and routing it through the root NavigationStack. Taps that arrive before
SwiftUI navigation is ready are queued and then dismiss presented UI and open
the target game.
Co-Authored-By: Codex GPT 5.5 <[email protected]>
Diffstat:
1 file changed, 52 insertions(+), 0 deletions(-)
diff --git a/Crossmate/CrossmateApp.swift b/Crossmate/CrossmateApp.swift
@@ -65,6 +65,23 @@ final class AppDelegate: NSObject, UIApplicationDelegate, @preconcurrency UNUser
}
}
+ func userNotificationCenter(
+ _ center: UNUserNotificationCenter,
+ didReceive response: UNNotificationResponse,
+ withCompletionHandler completionHandler: @escaping () -> Void
+ ) {
+ let userInfo = response.notification.request.content.userInfo
+ guard let gameID = Self.gameID(from: userInfo) else {
+ completionHandler()
+ return
+ }
+
+ Task { @MainActor in
+ NotificationNavigationBroker.shared.openGame(gameID)
+ completionHandler()
+ }
+ }
+
private static func gameID(from userInfo: [AnyHashable: Any]) -> UUID? {
if let id = userInfo["crossmateGameID"] as? String {
return UUID(uuidString: id)
@@ -111,6 +128,36 @@ final class AppDelegate: NSObject, UIApplicationDelegate, @preconcurrency UNUser
}
@MainActor
+final class NotificationNavigationBroker {
+ static let shared = NotificationNavigationBroker()
+
+ var onOpenGame: ((UUID) -> Void)? {
+ didSet { flushPendingGameIDs() }
+ }
+
+ private var pendingGameIDs: [UUID] = []
+
+ private init() {}
+
+ func openGame(_ gameID: UUID) {
+ guard let onOpenGame else {
+ pendingGameIDs.append(gameID)
+ return
+ }
+ onOpenGame(gameID)
+ }
+
+ private func flushPendingGameIDs() {
+ guard let onOpenGame, !pendingGameIDs.isEmpty else { return }
+ let gameIDs = pendingGameIDs
+ pendingGameIDs.removeAll()
+ for gameID in gameIDs {
+ onOpenGame(gameID)
+ }
+ }
+}
+
+@MainActor
final class CloudShareAcceptanceBroker {
static let shared = CloudShareAcceptanceBroker()
@@ -176,6 +223,11 @@ struct RootView: View {
}
.environment(services.preferences)
.task {
+ NotificationNavigationBroker.shared.onOpenGame = { gameID in
+ UIApplication.shared.dismissPresentedViewControllers()
+ navigationPath = NavigationPath()
+ navigationPath.append(gameID)
+ }
await services.start(appDelegate: appDelegate)
}
.onOpenURL { url in