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 + } + } +}