Read App Intents Documentation
Nucleic-Session: 56C5F781-4444-466B-91CE-A7734A8E117F Co-authored-by: Nucleic <[email protected]>
This commit is contained in:
@@ -131,15 +131,42 @@ private struct LockScreenView: View {
|
||||
private struct SessionRow: View {
|
||||
let line: NucleicSessionAttributes.SessionLine
|
||||
|
||||
/// An approval this row can resolve inline: it's blocked on an approval, carries that approval's
|
||||
/// id, and isn't high-risk (§3.3 — high-risk keeps the plain tap-to-open row and is answered on
|
||||
/// the app's guarded card). `nil` until the producer populates `approvalID` — an older host, or
|
||||
/// today's summary that doesn't yet carry it, so the row stays a deep-link exactly as before.
|
||||
private var inlineApprovalID: String? {
|
||||
guard line.kind == .approval, (line.approvalIsHighRisk ?? false) == false else { return nil }
|
||||
return line.approvalID
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
if let url = NucleicDeepLink.session(line.id) {
|
||||
if let approvalID = inlineApprovalID {
|
||||
actionableRow(approvalID: approvalID)
|
||||
} else if let url = NucleicDeepLink.session(line.id) {
|
||||
Link(destination: url) { rowContent }
|
||||
} else {
|
||||
rowContent
|
||||
}
|
||||
}
|
||||
|
||||
private var rowContent: some View {
|
||||
/// An approval row with inline Allow/Deny. The identity still deep-links to the session; the
|
||||
/// buttons fire `ApproveFromActivityIntent`, which the system performs in the app's background
|
||||
/// process — allow/deny without unlocking (§4.1).
|
||||
private func actionableRow(approvalID: String) -> some View {
|
||||
HStack(spacing: 8) {
|
||||
if let url = NucleicDeepLink.session(line.id) {
|
||||
Link(destination: url) { rowIdentity }
|
||||
} else {
|
||||
rowIdentity
|
||||
}
|
||||
Spacer(minLength: 6)
|
||||
ApprovalButtons(sessionID: line.id, approvalID: approvalID)
|
||||
}
|
||||
}
|
||||
|
||||
/// The glyph + title + "project · Backend" — the row's identity, minus the trailing status.
|
||||
private var rowIdentity: some View {
|
||||
HStack(spacing: 8) {
|
||||
Image(systemName: ActivityPalette.glyph(line.kind))
|
||||
.font(.footnote)
|
||||
@@ -159,6 +186,12 @@ private struct SessionRow: View {
|
||||
.foregroundStyle(.secondary)
|
||||
.lineLimit(1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private var rowContent: some View {
|
||||
HStack(spacing: 8) {
|
||||
rowIdentity
|
||||
Spacer(minLength: 6)
|
||||
Text(line.detail)
|
||||
.font(.caption2.weight(.medium))
|
||||
@@ -169,6 +202,33 @@ private struct SessionRow: View {
|
||||
}
|
||||
}
|
||||
|
||||
/// The compact inline Allow/Deny pair for an actionable approval row. Each button fires
|
||||
/// `ApproveFromActivityIntent` (a low/medium-risk decision — high-risk never reaches here).
|
||||
private struct ApprovalButtons: View {
|
||||
let sessionID: String
|
||||
let approvalID: String
|
||||
|
||||
var body: some View {
|
||||
HStack(spacing: 6) {
|
||||
Button(intent: intent(allow: false)) {
|
||||
Image(systemName: "xmark").font(.caption2.bold())
|
||||
}
|
||||
.tint(ActivityPalette.danger)
|
||||
Button(intent: intent(allow: true)) {
|
||||
Image(systemName: "checkmark").font(.caption2.bold())
|
||||
}
|
||||
.tint(ActivityPalette.success)
|
||||
}
|
||||
.buttonStyle(.borderedProminent)
|
||||
.controlSize(.small)
|
||||
}
|
||||
|
||||
private func intent(allow: Bool) -> ApproveFromActivityIntent {
|
||||
ApproveFromActivityIntent(
|
||||
approvalID: approvalID, sessionID: sessionID, isHighRisk: false, allow: allow)
|
||||
}
|
||||
}
|
||||
|
||||
/// Headline count chips: running (blue), waiting (teal), approvals (amber). Only nonzero show.
|
||||
private struct CountChips: View {
|
||||
let state: NucleicSessionAttributes.ContentState
|
||||
|
||||
Reference in New Issue
Block a user