61 lines
2.2 KiB
Swift
61 lines
2.2 KiB
Swift
import SwiftUI
|
|
import TermindDomain
|
|
|
|
/// The shared visual vocabulary for connection state.
|
|
///
|
|
/// Sidebar rows, workspace items, and the status bar all render the same dot, so a
|
|
/// color means one thing everywhere in the window.
|
|
extension ConnectionStatus {
|
|
var tint: Color {
|
|
switch self {
|
|
case .disconnected: .secondary
|
|
case .connecting, .reconnecting: TermindColor.warning
|
|
case .connected: TermindColor.success
|
|
case .failed: TermindColor.danger
|
|
}
|
|
}
|
|
|
|
var label: String {
|
|
switch self {
|
|
case .disconnected: String(localized: "Not connected")
|
|
case .connecting: String(localized: "Connecting")
|
|
case .connected: String(localized: "Connected")
|
|
case .reconnecting: String(localized: "Reconnecting")
|
|
case .failed(let message): message
|
|
}
|
|
}
|
|
}
|
|
|
|
/// A connection-state dot. Pulses while a connection is being established, and
|
|
/// turns blue when a background workspace has produced output the user has not seen.
|
|
struct StatusDot: View {
|
|
let status: ConnectionStatus
|
|
var hasUnread: Bool = false
|
|
var size: CGFloat = Metrics.Sidebar.statusDot
|
|
|
|
@Environment(\.accessibilityReduceMotion) private var reduceMotion
|
|
@State private var isPulsing = false
|
|
|
|
var body: some View {
|
|
let animatesPulse = isPulsing && !reduceMotion
|
|
|
|
Circle()
|
|
.fill(fill)
|
|
.frame(width: size, height: size)
|
|
.opacity(animatesPulse ? 0.3 : 1)
|
|
// A repeating animation must disappear when the status settles.
|
|
// Reusing it for the transition back to `false` leaves SwiftUI's
|
|
// display link running even though the dot looks stationary.
|
|
.animation(animatesPulse ? Motion.statusPulse : nil, value: animatesPulse)
|
|
.onAppear { isPulsing = status.isBusy }
|
|
.onChange(of: status.isBusy) { _, busy in isPulsing = busy }
|
|
.accessibilityLabel(Text(status.label))
|
|
}
|
|
|
|
/// Unread output only shows once the connection has settled — while
|
|
/// connecting, the connection state is the more useful thing to signal.
|
|
private var fill: Color {
|
|
hasUnread && !status.isBusy ? TermindColor.accent : status.tint
|
|
}
|
|
}
|