feat(mac): show relay attention badge without dimming paused state

This commit is contained in:
Peter Steinberger
2025-12-06 23:54:56 +01:00
parent c9f5edbc1d
commit ff36375581

View File

@@ -592,9 +592,9 @@ enum ShellRunner {
struct ClawdisApp: App { struct ClawdisApp: App {
@NSApplicationDelegateAdaptor(AppDelegate.self) private var delegate @NSApplicationDelegateAdaptor(AppDelegate.self) private var delegate
@StateObject private var state: AppState @StateObject private var state: AppState
@StateObject private var relayManager = RelayProcessManager.shared
@State private var statusItem: NSStatusItem? @State private var statusItem: NSStatusItem?
@State private var isMenuPresented = false @State private var isMenuPresented = false
private let relayManager = RelayProcessManager.shared
init() { init() {
_state = StateObject(wrappedValue: AppStateStore.shared) _state = StateObject(wrappedValue: AppStateStore.shared)
@@ -605,7 +605,8 @@ struct ClawdisApp: App {
CritterStatusLabel( CritterStatusLabel(
isPaused: self.state.isPaused, isPaused: self.state.isPaused,
isWorking: self.state.isWorking, isWorking: self.state.isWorking,
earBoostActive: self.state.earBoostActive) earBoostActive: self.state.earBoostActive,
relayStatus: self.relayManager.status)
} }
.menuBarExtraStyle(.menu) .menuBarExtraStyle(.menu)
.menuBarExtraAccess(isPresented: self.$isMenuPresented) { item in .menuBarExtraAccess(isPresented: self.$isMenuPresented) { item in
@@ -708,6 +709,7 @@ private struct CritterStatusLabel: View {
var isPaused: Bool var isPaused: Bool
var isWorking: Bool var isWorking: Bool
var earBoostActive: Bool var earBoostActive: Bool
var relayStatus: RelayProcessManager.Status
@State private var blinkAmount: CGFloat = 0 @State private var blinkAmount: CGFloat = 0
@State private var nextBlink = Date().addingTimeInterval(Double.random(in: 3.5...8.5)) @State private var nextBlink = Date().addingTimeInterval(Double.random(in: 3.5...8.5))
@@ -721,6 +723,7 @@ private struct CritterStatusLabel: View {
private let ticker = Timer.publish(every: 0.35, on: .main, in: .common).autoconnect() private let ticker = Timer.publish(every: 0.35, on: .main, in: .common).autoconnect()
var body: some View { var body: some View {
ZStack(alignment: .bottomTrailing) {
Group { Group {
if self.isPaused { if self.isPaused {
Image(nsImage: CritterIconRenderer.makeIcon(blink: 0)) Image(nsImage: CritterIconRenderer.makeIcon(blink: 0))
@@ -762,6 +765,14 @@ private struct CritterStatusLabel: View {
.onChange(of: self.isPaused) { _, _ in self.resetMotion() } .onChange(of: self.isPaused) { _, _ in self.resetMotion() }
} }
} }
if self.relayNeedsAttention {
Circle()
.fill(self.relayBadgeColor)
.frame(width: 8, height: 8)
.offset(x: 4, y: 4)
}
}
} }
private func resetMotion() { private func resetMotion() {
@@ -827,6 +838,23 @@ private struct CritterStatusLabel: View {
withAnimation(.interpolatingSpring(stiffness: 260, damping: 19)) { self.earWiggle = 0 } withAnimation(.interpolatingSpring(stiffness: 260, damping: 19)) { self.earWiggle = 0 }
} }
} }
private var relayNeedsAttention: Bool {
switch self.relayStatus {
case .failed, .stopped:
return !self.isPaused
case .starting, .restarting, .running:
return false
}
}
private var relayBadgeColor: Color {
switch self.relayStatus {
case .failed: return .red
case .stopped: return .orange
default: return .clear
}
}
} }
enum CritterIconRenderer { enum CritterIconRenderer {