From 96b7d7cc79014aae30294e642a5f4870a3495cea Mon Sep 17 00:00:00 2001 From: Andrew Blakeslee Moore Date: Sat, 4 Jul 2026 23:40:29 -0700 Subject: [PATCH] Live Activity Content Density Nucleic-Session: B3643133-163C-4C5D-BE20-1A6B7FB83DA9 Co-authored-by: Nucleic --- .../Shared/SessionActivityAttributes.swift | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/NucleicRemote/Shared/SessionActivityAttributes.swift b/NucleicRemote/Shared/SessionActivityAttributes.swift index 0d29361..281d720 100644 --- a/NucleicRemote/Shared/SessionActivityAttributes.swift +++ b/NucleicRemote/Shared/SessionActivityAttributes.swift @@ -75,3 +75,53 @@ struct NucleicSessionAttributes: ActivityAttributes { /// The paired Mac's name (static for the Activity's lifetime). var hostName: String } + +extension NucleicSessionAttributes.ContentState { + /// Where a tap on the whole activity should go (UX_IOS §5.3): a session waiting on the user + /// opens straight into that session; otherwise (work running, nothing waiting) the sessions + /// list. `lines` is attention-first, so any waiting session is `lines.first` — and always in + /// the capped list, since waiting outranks running in the sort. + var tapURL: URL? { + if let waiting = lines.first(where: { $0.kind == .approval || $0.kind == .needsInput }) { + return NucleicDeepLink.session(waiting.id) + } + return NucleicDeepLink.sessionsList + } +} + +/// The `nucleic://` deep links the Live Activity emits and the app consumes. Kept in the shared +/// file so the widget that *builds* a URL and the app that *parses* one can't drift. +enum NucleicDeepLink { + static let scheme = "nucleic" + + /// Open a specific session's detail: `nucleic://session/`. + static func session(_ id: String) -> URL? { + var c = URLComponents() + c.scheme = scheme + c.host = "session" + c.path = "/\(id)" + return c.url + } + + /// Surface the sessions list, no specific session: `nucleic://sessions`. + static var sessionsList: URL? { URL(string: "\(scheme)://sessions") } + + /// What an incoming link asks the app to do. + enum Route: Equatable { + case session(String) + case sessionsList + } + + static func route(for url: URL) -> Route? { + guard url.scheme == scheme else { return nil } + switch url.host { + case "session": + let id = url.path.trimmingCharacters(in: CharacterSet(charactersIn: "/")) + return id.isEmpty ? nil : .session(id) + case "sessions": + return .sessionsList + default: + return nil + } + } +}