Live Activity Content Density

Nucleic-Session: B3643133-163C-4C5D-BE20-1A6B7FB83DA9
Co-authored-by: Nucleic <[email protected]>
This commit is contained in:
2026-07-04 23:40:29 -07:00
co-authored by Nucleic
parent efc7e4c7fb
commit 96b7d7cc79
@@ -75,3 +75,53 @@ struct NucleicSessionAttributes: ActivityAttributes {
/// The paired Mac's name (static for the Activity's lifetime). /// The paired Mac's name (static for the Activity's lifetime).
var hostName: String 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/<id>`.
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
}
}
}