From 7ad1045be43442676041f8faee5ff58f72457d50 Mon Sep 17 00:00:00 2001 From: Gabriel Brown Date: Sun, 1 Nov 2026 02:35:58 -0500 Subject: [PATCH] Watch: treat an empty threadId in a push as no thread The gateway sends threadId "" on host notifications; tapping one now opens the feed instead of a thread that does not exist. Co-Authored-By: Claude Opus 5.5 --- .../WristCode/Notifications/NotificationHandler.swift | 10 +++++++--- watch/WristCodeTests/ModelsTests.swift | 2 ++ 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/watch/WristCode/Notifications/NotificationHandler.swift b/watch/WristCode/Notifications/NotificationHandler.swift index 7bbc73c..2886dd2 100644 --- a/watch/WristCode/Notifications/NotificationHandler.swift +++ b/watch/WristCode/Notifications/NotificationHandler.swift @@ -20,9 +20,13 @@ enum NotificationCommand: Equatable, Sendable { /// `userInfo` holds the custom keys `hostId`, `threadId` and, for approvals, `requestId`. init(actionIdentifier: String, userInfo: [AnyHashable: Any], text: String?) { - let hostId = userInfo["hostId"] as? String - let threadId = userInfo["threadId"] as? String - let requestId = userInfo["requestId"] as? String + // The gateway sends `threadId: ""` on host notifications, so empty means absent. + func value(_ key: String) -> String? { + (userInfo[key] as? String).flatMap { $0.isEmpty ? nil : $0 } + } + let hostId = value("hostId") + let threadId = value("threadId") + let requestId = value("requestId") let thread: Route? = if let hostId, let threadId { .thread(hostId: hostId, threadId: threadId) } else { nil } switch actionIdentifier { diff --git a/watch/WristCodeTests/ModelsTests.swift b/watch/WristCodeTests/ModelsTests.swift index 6d9869a..b773ef3 100644 --- a/watch/WristCodeTests/ModelsTests.swift +++ b/watch/WristCodeTests/ModelsTests.swift @@ -198,6 +198,8 @@ private let feedItemJSON = """ // A host notification has no thread, so tapping it opens the feed. #expect(NotificationCommand(actionIdentifier: "com.apple.UNNotificationDefaultActionIdentifier", userInfo: [:], text: nil) == .open(nil)) + #expect(NotificationCommand(actionIdentifier: "com.apple.UNNotificationDefaultActionIdentifier", userInfo: ["hostId": "h", "threadId": ""], text: nil) + == .open(nil)) // Allow without a requestId cannot answer, so it opens the thread instead. #expect(NotificationCommand(actionIdentifier: "allow", userInfo: ["hostId": "h", "threadId": "t"], text: nil) == .open(.thread(hostId: "h", threadId: "t")))