mac: tighten settings layout

main
Peter Steinberger 2025-12-06 00:42:41 +01:00
parent d031c5c7fa
commit a2604a36bc
1 changed files with 29 additions and 25 deletions

View File

@ -702,7 +702,8 @@ struct GeneralSettings: View {
} }
VStack(alignment: .leading, spacing: 10) { VStack(alignment: .leading, spacing: 10) {
Toggle(isOn: $state.isPaused) { Text("Pause Clawdis (disables notifications & privileged actions)") } Toggle(isOn: activeBinding) { Text(activeBinding.wrappedValue ? "Clawdis Active" : "Clawdis Paused") }
.help("Disable to stop Clawdis background helpers and notifications")
Toggle(isOn: $state.launchAtLogin) { Text("Launch at login") } Toggle(isOn: $state.launchAtLogin) { Text("Launch at login") }
#if DEBUG #if DEBUG
Toggle(isOn: $state.debugPaneEnabled) { Text("Enable debug tools") } Toggle(isOn: $state.debugPaneEnabled) { Text("Enable debug tools") }
@ -738,6 +739,13 @@ struct GeneralSettings: View {
.frame(maxWidth: .infinity, alignment: .leading) .frame(maxWidth: .infinity, alignment: .leading)
} }
private var activeBinding: Binding<Bool> {
Binding(
get: { !state.isPaused },
set: { state.isPaused = !$0 }
)
}
private var cliInstaller: some View { private var cliInstaller: some View {
VStack(alignment: .leading, spacing: 8) { VStack(alignment: .leading, spacing: 8) {
HStack(spacing: 10) { HStack(spacing: 10) {
@ -784,11 +792,14 @@ struct PermissionsSettings: View {
var body: some View { var body: some View {
VStack(alignment: .leading, spacing: 14) { VStack(alignment: .leading, spacing: 14) {
Text("Allow these so Clawdis can notify and capture when needed.") Text("Allow these so Clawdis can notify and capture when needed.")
.padding(.bottom, 2) .padding(.top, 4)
PermissionStatusList(status: status, refresh: refresh) PermissionStatusList(status: status, refresh: refresh)
.padding(14) .padding(14)
.background(RoundedRectangle(cornerRadius: 12).fill(Color(NSColor.controlBackgroundColor))) .background(RoundedRectangle(cornerRadius: 12).fill(Color(NSColor.controlBackgroundColor)))
Button("Show onboarding") { showOnboarding() } Button("Show onboarding") { showOnboarding() }
.buttonStyle(.bordered)
Spacer() Spacer()
} }
} }
@ -921,13 +932,11 @@ struct PermissionStatusList: View {
let refresh: () async -> Void let refresh: () async -> Void
var body: some View { var body: some View {
VStack(alignment: .leading, spacing: 10) { VStack(alignment: .leading, spacing: 12) {
row(label: "Notifications", cap: .notifications, action: requestNotifications) ForEach(Capability.allCases, id: \.self) { cap in
row(label: "Accessibility", cap: .accessibility) { PermissionRow(capability: cap, status: status[cap] ?? false) {
openSettings("x-apple.systempreferences:com.apple.preference.security?Privacy_Accessibility") Task { await handle(cap) }
} }
row(label: "Screen Recording", cap: .screenRecording) {
openSettings("x-apple.systempreferences:com.apple.preference.security?Privacy_ScreenRecording")
} }
Button("Refresh status") { Task { await refresh() } } Button("Refresh status") { Task { await refresh() } }
.font(.footnote) .font(.footnote)
@ -935,23 +944,18 @@ struct PermissionStatusList: View {
} }
} }
private func row(label: String, cap: Capability, action: @escaping () -> Void) -> some View { @MainActor
let ok = status[cap] ?? false private func handle(_ cap: Capability) async {
return HStack {
Circle()
.fill(ok ? Color.green : Color.red)
.frame(width: 10, height: 10)
Text(label)
Spacer()
Button(ok ? "Granted" : "Open Settings", action: action)
.disabled(ok)
}
}
private func requestNotifications() {
Task { Task {
let center = UNUserNotificationCenter.current() switch cap {
_ = try? await center.requestAuthorization(options: [.alert, .sound, .badge]) case .notifications:
let center = UNUserNotificationCenter.current()
_ = try? await center.requestAuthorization(options: [.alert, .sound, .badge])
case .accessibility:
openSettings("x-apple.systempreferences:com.apple.preference.security?Privacy_Accessibility")
case .screenRecording:
openSettings("x-apple.systempreferences:com.apple.preference.security?Privacy_ScreenRecording")
}
await refresh() await refresh()
} }
} }