Watch: notification switches, a model list and Ask before acting on new threads, and Ask before acting on a thread

This commit is contained in:
gib committed 2026-11-02 12:10:48 -05:00
1 parent 3cc7e40852
commit 6bc9cac6ca
14 files changed
+623 -81

No files matched your search

+56 -2
View File
@@ -1,5 +1,6 @@
// Settings mock C: an overview that leads with what is wrong, an environment page with mock B's
// route ladder, and a notifications page with a test push and Unpair. Each screen loads
// route ladder, and a notifications page with a switch per kind of push, a test push and Unpair.
// Each screen loads
// `GET /v1/status` when it appears; nothing polls.
import SwiftUI
@@ -262,12 +263,16 @@ private struct RouteLadder: View {
}
}
/// Whether this watch gets pushes, the last push, a test push, the gateway, and Unpair.
/// Whether this watch gets pushes, the last push, which pushes it wants, a test push, the gateway,
/// and Unpair.
struct NotificationsView: View {
@Environment(AppModel.self) private var model
var status: StatusResponse?
var scrolls = true
@State private var reload = 0
/// The switches as last set here, ahead of the next status load.
@State private var prefs: NotificationPrefs?
@State private var prefsError: String?
@State private var sending = false
@State private var result: PushResult?
@State private var error: String?
@@ -335,6 +340,29 @@ struct NotificationsView: View {
}
}
if let current = prefs ?? device.notifications {
Text("Notify me when")
.font(.system(size: 11, weight: .semibold))
.foregroundStyle(Theme.secondaryText)
.padding(.horizontal, 6)
.padding(.top, 4)
ForEach(NotificationPrefs.Key.allCases, id: \.self) { key in
SwitchCard(title: Self.label(key), isOn: Binding(
get: { current[key] },
set: { set(key, $0, from: current) }))
}
Text("Host problems always notify.")
.font(.system(size: 11))
.foregroundStyle(Theme.secondaryText)
.padding(.horizontal, 6)
if let prefsError {
Text(prefsError)
.font(.system(size: 11))
.foregroundStyle(Theme.bad)
.padding(.horizontal, 6)
}
}
Button(sending ? "Sending" : "Send test") { sendTest() }
.buttonStyle(PillButtonStyle(fill: Theme.you))
.disabled(sending)
@@ -381,6 +409,32 @@ struct NotificationsView: View {
.buttonStyle(PillButtonStyle(fill: Theme.control, foreground: Theme.bad))
}
private static func label(_ key: NotificationPrefs.Key) -> String {
switch key {
case .needsMe: "Needs me"
case .finished: "Finished"
case .failed: "Failed"
case .subagents: "Subagents ask"
}
}
/// Flips the switch at once and sends just that key. If the gateway refuses, it flips back and
/// a line under the switches shows why.
private func set(_ key: NotificationPrefs.Key, _ on: Bool, from current: NotificationPrefs) {
var next = current
next[key] = on
prefs = next
prefsError = nil
Task {
do {
prefs = try await model.api.setNotification(key, on)
} catch {
prefs?[key] = !on
prefsError = model.message(for: error)
}
}
}
private func sendTest() {
sending = true
result = nil