away mode visibility

This commit is contained in:
Ian Gulliver
2026-10-20 11:19:06 -07:00
parent ef98b1179d
commit 6f3d92e4e2
2 changed files with 49 additions and 13 deletions
+48 -12
View File
@@ -496,6 +496,31 @@ struct ServerWindow: View {
adopt(new.filter { !old.contains($0) })
}
.onAppear(perform: appeared)
.onReceive(NotificationCenter.default.publisher(for: NSApplication.didBecomeActiveNotification)) { _ in
remindAway()
}
.onChange(of: Set(Servers.shared.origins.filter { Servers.shared.connections[$0]?.store != nil })) { old, new in
if !new.isSubset(of: old), NSApp.isActive {
remindAway()
}
}
}
private func remindAway() {
guard awayStores().contains(where: { $0.me?.away == true }), let overlays = connection?.overlays, overlays.modal == nil else {
return
}
Task {
let content = VStack(alignment: .leading, spacing: 12) {
Text("You're still away")
.foregroundStyle(Palette.warn)
ModalText(text: "byre is answering your agents' questions for you, telling them to pick the most likely answer. Are you back?")
}
let choice = await overlays.showModal(content, [ModalButton(label: "Stay away", value: "cancel"), ModalButton(label: "I'm back", value: "back", primary: true)])
if choice == "back" {
await setAway(false, awayStores())
}
}
}
private func appeared() {
@@ -544,22 +569,39 @@ struct ServerPicker: View {
}
}
@MainActor
private func awayStores() -> [Store] {
Servers.shared.origins.compactMap { Servers.shared.connections[$0]?.store }
}
@MainActor
private func setAway(_ away: Bool, _ stores: [Store]) async {
for store in stores {
do {
store.me = try await store.api.client.updateAway(body: .json(.init(away: away))).ok.body.json
} catch {
log.error("set away: \(errorText(error), privacy: .public)")
}
}
}
private struct AwayToggle: View {
@ViewState private var hover = false
@ViewState private var busy = false
var body: some View {
let stores = Servers.shared.origins.compactMap { Servers.shared.connections[$0]?.store }
let stores = awayStores()
let away = stores.contains { $0.me?.away == true }
if !stores.isEmpty {
Button {
set(!away, stores)
} label: {
Text("Away")
.foregroundStyle(away ? Palette.accent : hover ? Palette.text : Palette.muted)
.padding(.horizontal, 8)
Text(away ? "AWAY · click when back" : "Away")
.foregroundStyle(away ? Palette.warn : hover ? Palette.text : Palette.muted)
.padding(.horizontal, away ? 12 : 8)
.padding(.vertical, 3)
.background(away ? Palette.accentTint : .clear, in: RoundedRectangle(cornerRadius: 6))
.background(away ? Palette.warnTint : .clear, in: RoundedRectangle(cornerRadius: 6))
.overlay(RoundedRectangle(cornerRadius: 6).stroke(away ? Palette.warn : .clear))
.contentShape(Rectangle())
}
.buttonStyle(.plain)
@@ -575,13 +617,7 @@ private struct AwayToggle: View {
private func set(_ away: Bool, _ stores: [Store]) {
busy = true
Task {
for store in stores {
do {
store.me = try await store.api.client.updateAway(body: .json(.init(away: away))).ok.body.json
} catch {
log.error("set away: \(errorText(error), privacy: .public)")
}
}
await setAway(away, stores)
busy = false
}
}