Phase 0: menu-bar scaffold, permissions, backend health check
Native SwiftUI menu-bar app (LSUIElement, macOS 13+), generated from project.yml via XcodeGen. Includes: - PermissionsManager (Microphone / Screen Recording / Accessibility) + UI - SparkControlHealth: GET /api/status over self-signed TLS (InsecureTrustDelegate) - AppSettings persistence (host, TLS-skip, output folder, adapter toggles) - Menu-bar panel + Settings, app sandbox & hardened runtime off (LAN tool)
This commit is contained in:
@@ -0,0 +1,54 @@
|
||||
import SwiftUI
|
||||
|
||||
/// Small status indicator dot.
|
||||
struct StatusDot: View {
|
||||
let color: Color
|
||||
var body: some View {
|
||||
Circle().fill(color).frame(width: 9, height: 9)
|
||||
}
|
||||
}
|
||||
|
||||
/// One permission line: status dot, label, and a context-appropriate action.
|
||||
struct PermissionRow: View {
|
||||
let title: String
|
||||
let state: PermissionState
|
||||
let onGrant: () -> Void
|
||||
let onOpenSettings: () -> Void
|
||||
|
||||
var body: some View {
|
||||
HStack(spacing: 8) {
|
||||
StatusDot(color: dotColor)
|
||||
Text(title)
|
||||
Spacer()
|
||||
actionButton
|
||||
}
|
||||
}
|
||||
|
||||
private var dotColor: Color {
|
||||
switch state {
|
||||
case .granted: return .green
|
||||
case .denied: return .red
|
||||
case .notDetermined: return .orange
|
||||
}
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
private var actionButton: some View {
|
||||
switch state {
|
||||
case .granted:
|
||||
Image(systemName: "checkmark.circle.fill").foregroundStyle(.green)
|
||||
case .notDetermined:
|
||||
// Native prompt (Microphone). The request also registers the app.
|
||||
Button("Grant", action: onGrant)
|
||||
case .denied:
|
||||
// Screen Recording / Accessibility report binary granted/denied, so
|
||||
// "not yet asked" looks like denied. "Grant" calls the request API,
|
||||
// which registers the app in the relevant list and shows the system
|
||||
// prompt the first time; "Open Settings" is the manual fallback.
|
||||
HStack(spacing: 6) {
|
||||
Button("Grant", action: onGrant)
|
||||
Button("Open Settings", action: onOpenSettings)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user