106 lines
3.6 KiB
Swift
106 lines
3.6 KiB
Swift
// StatusBar.swift
|
|
// T-2.8 — Session status bar with pi-state indicator and action buttons.
|
|
|
|
import Combine
|
|
import SwiftUI
|
|
|
|
@MainActor
|
|
struct StatusBar: View {
|
|
let sessionName: String
|
|
let connectionStatus: String // "Connecting…", "Connected", "Disconnected"
|
|
@Binding var piState: PiState?
|
|
var onSwitcher: (() -> Void)? = nil
|
|
var onUnpair: (() -> Void)? = nil
|
|
var onSettings: (() -> Void)? = nil
|
|
|
|
var body: some View {
|
|
VStack(spacing: 0) {
|
|
HStack {
|
|
// ── Left: session name ──────────────────────────────
|
|
Text(sessionName.isEmpty ? " " : sessionName)
|
|
.font(.caption.monospaced())
|
|
.foregroundStyle(.secondary)
|
|
.lineLimit(1)
|
|
.truncationMode(.middle)
|
|
|
|
Spacer()
|
|
|
|
// ── Center: pi state / connection status ────────────
|
|
stateIndicator
|
|
|
|
Spacer()
|
|
|
|
// ── Right: icon buttons ─────────────────────────────
|
|
HStack(spacing: 14) {
|
|
if onSwitcher != nil {
|
|
Button {
|
|
onSwitcher?()
|
|
} label: {
|
|
Image(systemName: "list.bullet")
|
|
.font(.caption)
|
|
}
|
|
.accessibilityLabel("Switcher")
|
|
.accessibilityIdentifier("statusbar.switcher")
|
|
}
|
|
|
|
if onSettings != nil {
|
|
Button {
|
|
onSettings?()
|
|
} label: {
|
|
Image(systemName: "gear")
|
|
.font(.caption)
|
|
}
|
|
.accessibilityLabel("Settings")
|
|
.accessibilityIdentifier("statusbar.settings")
|
|
}
|
|
|
|
if onUnpair != nil {
|
|
Button {
|
|
onUnpair?()
|
|
} label: {
|
|
Image(systemName: "x.circle")
|
|
.font(.caption)
|
|
.foregroundStyle(.red)
|
|
}
|
|
.accessibilityLabel("Unpair")
|
|
.accessibilityIdentifier("statusbar.unpair")
|
|
}
|
|
}
|
|
}
|
|
.padding(.horizontal, 12)
|
|
.padding(.vertical, 6)
|
|
.background(Color(uiColor: .systemBackground))
|
|
|
|
Divider()
|
|
}
|
|
}
|
|
|
|
// MARK: - State indicator
|
|
|
|
@ViewBuilder
|
|
private var stateIndicator: some View {
|
|
if let state = piState {
|
|
switch state {
|
|
case .thinking:
|
|
Text("● thinking")
|
|
.font(.caption.monospaced())
|
|
.foregroundStyle(.orange)
|
|
case .tool:
|
|
Text("▶ tool")
|
|
.font(.caption.monospaced())
|
|
.foregroundStyle(.blue)
|
|
case .awaitingInput:
|
|
Text("⏸ awaiting")
|
|
.font(.caption.monospaced())
|
|
.foregroundStyle(.yellow)
|
|
case .idle:
|
|
EmptyView()
|
|
}
|
|
} else {
|
|
Text(connectionStatus)
|
|
.font(.caption.monospaced())
|
|
.foregroundStyle(.secondary)
|
|
}
|
|
}
|
|
}
|