cross server notifications
This commit is contained in:
@@ -458,28 +458,62 @@ struct ServerWindow: View {
|
||||
struct ServerPicker: View {
|
||||
var body: some View {
|
||||
let servers = Servers.shared
|
||||
Menu {
|
||||
HStack(spacing: 4) {
|
||||
ForEach(servers.origins, id: \.self) { origin in
|
||||
Button(serverName(origin)) {
|
||||
servers.current = origin
|
||||
}
|
||||
ServerChip(origin: origin)
|
||||
}
|
||||
Divider()
|
||||
Button("Add Server…") {
|
||||
Button("+") {
|
||||
servers.current = nil
|
||||
}
|
||||
} label: {
|
||||
HStack(spacing: 6) {
|
||||
if let current = servers.current {
|
||||
Circle()
|
||||
.fill(servers.color(current))
|
||||
.frame(width: 8, height: 8)
|
||||
Text(serverName(current))
|
||||
} else {
|
||||
Text("Add Server")
|
||||
}
|
||||
}
|
||||
.font(Fonts.font(13))
|
||||
.buttonStyle(.plain)
|
||||
.foregroundStyle(servers.current == nil ? Palette.text : Palette.muted)
|
||||
.padding(.horizontal, 8)
|
||||
.padding(.vertical, 3)
|
||||
.help("Add Server")
|
||||
}
|
||||
.font(Fonts.font(13))
|
||||
}
|
||||
}
|
||||
|
||||
private struct ServerChip: View {
|
||||
let origin: String
|
||||
@ViewState private var hover = false
|
||||
|
||||
var body: some View {
|
||||
let servers = Servers.shared
|
||||
let store = servers.connections[origin]?.store
|
||||
let questions = store?.inbox.count ?? 0
|
||||
let summaries = store?.unreadSummaries ?? 0
|
||||
let current = servers.current == origin
|
||||
Button {
|
||||
servers.current = origin
|
||||
} label: {
|
||||
HStack(spacing: 6) {
|
||||
Circle()
|
||||
.fill(store == nil ? .clear : servers.color(origin))
|
||||
.stroke(servers.color(origin))
|
||||
.frame(width: 8, height: 8)
|
||||
Text(serverName(origin))
|
||||
.fontWeight(current || questions > 0 ? .bold : .regular)
|
||||
if questions > 0 {
|
||||
Badge(count: questions)
|
||||
.help("open questions")
|
||||
}
|
||||
if summaries > 0 {
|
||||
Text("\(summaries) new")
|
||||
.font(Fonts.font(11, weight: 700))
|
||||
.foregroundStyle(Palette.accent)
|
||||
.help("Turn summaries you haven't read")
|
||||
}
|
||||
}
|
||||
.foregroundStyle(hover || current ? Palette.text : questions > 0 ? Palette.warn : Palette.muted)
|
||||
.padding(.horizontal, 8)
|
||||
.padding(.vertical, 3)
|
||||
.background(questions > 0 ? Palette.warnTint : current ? Palette.surface : .clear, in: RoundedRectangle(cornerRadius: 6))
|
||||
.contentShape(Rectangle())
|
||||
}
|
||||
.buttonStyle(.plain)
|
||||
.help(store == nil ? "\(serverName(origin)): not connected" : serverName(origin))
|
||||
.onHover { hover = $0 }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -482,6 +482,10 @@ final class Store {
|
||||
task.workflow == nil && task.summarySeq > (summaryReads[task.id] ?? 0)
|
||||
}
|
||||
|
||||
var unreadSummaries: Int {
|
||||
tasks.values.joined().filter { $0.status == .active && unreadSummary($0) }.count
|
||||
}
|
||||
|
||||
private func noteSummaryRead(_ taskId: String, _ seq: Int64) -> Bool {
|
||||
if (summaryReads[taskId] ?? 0) >= seq {
|
||||
return false
|
||||
|
||||
Reference in New Issue
Block a user