103 lines
4.2 KiB
Swift
103 lines
4.2 KiB
Swift
import SwiftUI
|
|
|
|
struct BuildToolbar: View {
|
|
let scheme: String
|
|
let devices: [ConnectedDevice]
|
|
@Binding var selectedDevice: ConnectedDevice?
|
|
let isBuilding: Bool
|
|
let buildService: BuildService
|
|
let onBuild: () -> Void
|
|
let onRun: () -> Void
|
|
let onRefreshDevices: () -> Void
|
|
var onFindInProject: (() -> Void)? = nil
|
|
|
|
@State private var showHistory = false
|
|
|
|
var body: some View {
|
|
HStack(spacing: 10) {
|
|
Label(scheme, systemImage: "hammer")
|
|
.font(.system(.subheadline, design: .monospaced))
|
|
.foregroundStyle(.secondary).lineLimit(1)
|
|
|
|
Spacer()
|
|
|
|
// Device picker
|
|
Menu {
|
|
Button {
|
|
selectedDevice = nil
|
|
} label: {
|
|
HStack {
|
|
Image(systemName: "hammer"); Text("Build Only (No Device)")
|
|
if selectedDevice == nil { Image(systemName: "checkmark") }
|
|
}
|
|
}
|
|
Divider()
|
|
if devices.isEmpty {
|
|
Label("No devices paired", systemImage: "exclamationmark.triangle")
|
|
.foregroundStyle(.secondary)
|
|
} else {
|
|
ForEach(devices) { device in
|
|
Button {
|
|
selectedDevice = device
|
|
} label: {
|
|
HStack {
|
|
Image(systemName: device.isNetworkConnected
|
|
? "iphone.radiowaves.left.and.right" : "iphone")
|
|
VStack(alignment: .leading) {
|
|
Text(device.name)
|
|
Text("\(device.model) · \(device.osVersion)").font(.caption)
|
|
}
|
|
if selectedDevice?.udid == device.udid { Image(systemName: "checkmark") }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
Divider()
|
|
Button(action: onRefreshDevices) { Label("Refresh Devices", systemImage: "arrow.clockwise") }
|
|
} label: {
|
|
if let d = selectedDevice {
|
|
Label(d.name, systemImage: d.isNetworkConnected ? "iphone.radiowaves.left.and.right" : "iphone")
|
|
.font(.subheadline)
|
|
} else {
|
|
Label("No Device", systemImage: "iphone.slash")
|
|
.font(.subheadline).foregroundStyle(.secondary)
|
|
}
|
|
}
|
|
|
|
Divider().frame(height: 20)
|
|
|
|
Button(action: onBuild) {
|
|
Label("Build", systemImage: "hammer.fill").font(.subheadline.bold())
|
|
}
|
|
.disabled(isBuilding).buttonStyle(.bordered)
|
|
.keyboardShortcut("b", modifiers: .command)
|
|
|
|
Button(action: onRun) {
|
|
HStack(spacing: 5) {
|
|
if isBuilding { ProgressView().scaleEffect(0.7).tint(.white) }
|
|
else { Image(systemName: "play.fill") }
|
|
Text(isBuilding ? "Building…" : "Run").font(.subheadline.bold())
|
|
}
|
|
}
|
|
.disabled(isBuilding || selectedDevice == nil)
|
|
.buttonStyle(.borderedProminent)
|
|
.tint(isBuilding || selectedDevice == nil ? .secondary : .green)
|
|
.keyboardShortcut("r", modifiers: .command)
|
|
|
|
Divider().frame(height: 20)
|
|
|
|
if let findAction = onFindInProject {
|
|
Button(action: findAction) { Image(systemName: "magnifyingglass") }
|
|
.buttonStyle(.plain).foregroundStyle(.secondary).help("Find in Project ⌘⇧F")
|
|
}
|
|
|
|
Button { showHistory = true } label: { Image(systemName: "clock.arrow.circlepath") }
|
|
.buttonStyle(.plain).foregroundStyle(.secondary).help("Build History")
|
|
.sheet(isPresented: $showHistory) { BuildHistoryView(historyStore: buildService.historyStore) }
|
|
|
|
DaemonStatusIndicator(monitor: buildService.healthMonitor)
|
|
}
|
|
.padding(.horizontal, 14).padding(.vertical, 8)
|
|
.background(.bar)
|
|
}
|
|
}
|