Overhaul native approval UX and add widget surfaces
CI / test (push) Has been cancelled

Bring the SwiftUI app in line with the Apple-native mock and keep pending approvals actionable from Live Activities and watch complications.
This commit is contained in:
2026-04-19 16:29:13 +02:00
parent a6939453f8
commit 61a0cc1f7d
63 changed files with 3496 additions and 1769 deletions
+17 -14
View File
@@ -2,28 +2,31 @@ import CryptoKit
import Foundation
enum AppSection: String, CaseIterable, Identifiable, Hashable, Codable {
case overview
case requests
case activity
case account
case inbox
case notifications
case devices
case identity
case settings
var id: String { rawValue }
var title: String {
switch self {
case .overview: "Passport"
case .requests: "Requests"
case .activity: "Activity"
case .account: "Account"
case .inbox: "Inbox"
case .notifications: "Notifications"
case .devices: "Devices"
case .identity: "Identity"
case .settings: "Settings"
}
}
var systemImage: String {
switch self {
case .overview: "person.crop.square.fill"
case .requests: "checklist.checked"
case .activity: "clock.arrow.trianglehead.counterclockwise.rotate.90"
case .account: "person.crop.circle.fill"
case .inbox: "tray.full.fill"
case .notifications: "bell.badge.fill"
case .devices: "desktopcomputer"
case .identity: "person.crop.rectangle.stack.fill"
case .settings: "gearshape.fill"
}
}
}
@@ -301,8 +304,8 @@ enum ApprovalStatus: String, Hashable, Codable {
var title: String {
switch self {
case .pending: "Pending"
case .approved: "Verified"
case .rejected: "Declined"
case .approved: "Approved"
case .rejected: "Denied"
}
}
@@ -0,0 +1,59 @@
import Foundation
#if canImport(ActivityKit) && os(iOS)
import ActivityKit
#endif
struct ApprovalActivityPayload: Codable, Hashable {
let requestID: String
let title: String
let appName: String
let source: String
let handle: String
let location: String
let createdAt: Date
}
extension ApprovalRequest {
var activityAppName: String {
source
.replacingOccurrences(of: "auth.", with: "")
.replacingOccurrences(of: ".idp.global", with: ".idp.global")
}
var activityLocation: String {
"Berlin, DE"
}
var activityExpiryDate: Date {
createdAt.addingTimeInterval(risk == .elevated ? 180 : 300)
}
func activityPayload(handle: String) -> ApprovalActivityPayload {
ApprovalActivityPayload(
requestID: id.uuidString,
title: title,
appName: activityAppName,
source: source,
handle: handle,
location: activityLocation,
createdAt: createdAt
)
}
}
#if canImport(ActivityKit) && os(iOS)
struct ApprovalActivityAttributes: ActivityAttributes {
struct ContentState: Codable, Hashable {
let requestID: String
let title: String
let appName: String
let source: String
let handle: String
let location: String
}
let requestID: String
let createdAt: Date
}
#endif