Improve auto-probe UX: auto-connect after finding device
- Auto-probe now automatically connects after finding a VU meter - Add connection status indicator (green/red dot) on each dial - Add animation to dial value changes - Show minimum arc value for better visibility at low values - Display error messages in hardware panel - Show "No USB serial devices" message when none found - Improved status display with port name in green when connected
This commit is contained in:
@@ -91,7 +91,7 @@ struct HardwarePanelView: View {
|
|||||||
.disabled(serialManager.isProbing)
|
.disabled(serialManager.isProbing)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stats / Device info
|
// Stats / Device info / Errors
|
||||||
if serialManager.isConnected {
|
if serialManager.isConnected {
|
||||||
HStack {
|
HStack {
|
||||||
Text("TX: \(formatBytes(serialManager.bytesSent))")
|
Text("TX: \(formatBytes(serialManager.bytesSent))")
|
||||||
@@ -102,7 +102,20 @@ struct HardwarePanelView: View {
|
|||||||
|
|
||||||
Text(serialManager.selectedPortPath.components(separatedBy: "/").last ?? "")
|
Text(serialManager.selectedPortPath.components(separatedBy: "/").last ?? "")
|
||||||
.font(.system(size: 9, design: .monospaced))
|
.font(.system(size: 9, design: .monospaced))
|
||||||
.foregroundColor(.gray)
|
.foregroundColor(.green)
|
||||||
|
}
|
||||||
|
} else if let error = serialManager.lastError {
|
||||||
|
HStack {
|
||||||
|
Image(systemName: "exclamationmark.triangle.fill")
|
||||||
|
.foregroundColor(.red)
|
||||||
|
.font(.system(size: 10))
|
||||||
|
|
||||||
|
Text(error)
|
||||||
|
.font(.system(size: 9, design: .monospaced))
|
||||||
|
.foregroundColor(.red)
|
||||||
|
.lineLimit(2)
|
||||||
|
|
||||||
|
Spacer()
|
||||||
}
|
}
|
||||||
} else if let detected = serialManager.detectedDevice {
|
} else if let detected = serialManager.detectedDevice {
|
||||||
HStack {
|
HStack {
|
||||||
@@ -122,6 +135,18 @@ struct HardwarePanelView: View {
|
|||||||
.foregroundColor(.gray)
|
.foregroundColor(.gray)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else if serialManager.availablePorts.isEmpty {
|
||||||
|
HStack {
|
||||||
|
Image(systemName: "usb")
|
||||||
|
.foregroundColor(.orange)
|
||||||
|
.font(.system(size: 10))
|
||||||
|
|
||||||
|
Text("No USB serial devices detected")
|
||||||
|
.font(.system(size: 9, design: .monospaced))
|
||||||
|
.foregroundColor(.orange)
|
||||||
|
|
||||||
|
Spacer()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.padding()
|
.padding()
|
||||||
@@ -183,29 +208,35 @@ struct DialIndicatorView: View {
|
|||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
VStack(spacing: 4) {
|
VStack(spacing: 4) {
|
||||||
// Dial number
|
// Dial number with connection indicator
|
||||||
|
HStack(spacing: 2) {
|
||||||
|
Circle()
|
||||||
|
.fill(isConnected ? Color.green : Color.red)
|
||||||
|
.frame(width: 5, height: 5)
|
||||||
Text("D\(dialNumber)")
|
Text("D\(dialNumber)")
|
||||||
.font(.system(size: 10, weight: .bold, design: .monospaced))
|
.font(.system(size: 10, weight: .bold, design: .monospaced))
|
||||||
.foregroundColor(.white.opacity(0.7))
|
.foregroundColor(.white.opacity(0.7))
|
||||||
|
}
|
||||||
|
|
||||||
// Value arc
|
// Value arc
|
||||||
ZStack {
|
ZStack {
|
||||||
// Background arc
|
// Background arc
|
||||||
Circle()
|
Circle()
|
||||||
.trim(from: 0.25, to: 0.75)
|
.trim(from: 0.25, to: 0.75)
|
||||||
.stroke(Color.gray.opacity(0.2), lineWidth: 4)
|
.stroke(Color.gray.opacity(0.3), lineWidth: 4)
|
||||||
.frame(width: 50, height: 50)
|
.frame(width: 50, height: 50)
|
||||||
.rotationEffect(.degrees(180))
|
.rotationEffect(.degrees(180))
|
||||||
|
|
||||||
// Value arc
|
// Value arc - always show with minimum visibility
|
||||||
Circle()
|
Circle()
|
||||||
.trim(from: 0.25, to: 0.25 + (Double(value) / 255.0) * 0.5)
|
.trim(from: 0.25, to: 0.25 + max(0.02, (Double(value) / 255.0) * 0.5))
|
||||||
.stroke(
|
.stroke(
|
||||||
isConnected ? dialColor(for: value) : Color.gray,
|
dialColor(for: value, connected: isConnected),
|
||||||
style: StrokeStyle(lineWidth: 4, lineCap: .round)
|
style: StrokeStyle(lineWidth: 4, lineCap: .round)
|
||||||
)
|
)
|
||||||
.frame(width: 50, height: 50)
|
.frame(width: 50, height: 50)
|
||||||
.rotationEffect(.degrees(180))
|
.rotationEffect(.degrees(180))
|
||||||
|
.animation(.easeOut(duration: 0.1), value: value)
|
||||||
|
|
||||||
// Value text
|
// Value text
|
||||||
VStack(spacing: 0) {
|
VStack(spacing: 0) {
|
||||||
@@ -222,7 +253,10 @@ struct DialIndicatorView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func dialColor(for value: Int) -> Color {
|
private func dialColor(for value: Int, connected: Bool) -> Color {
|
||||||
|
if !connected {
|
||||||
|
return Color.gray.opacity(0.5)
|
||||||
|
}
|
||||||
let ratio = Double(value) / 255.0
|
let ratio = Double(value) / 255.0
|
||||||
if ratio > 0.9 { return .red }
|
if ratio > 0.9 { return .red }
|
||||||
if ratio > 0.75 { return .orange }
|
if ratio > 0.75 { return .orange }
|
||||||
|
|||||||
@@ -424,13 +424,17 @@ class SerialManager: ObservableObject {
|
|||||||
self.selectedProtocol = best.protocol_
|
self.selectedProtocol = best.protocol_
|
||||||
self.baudRate = best.baudRate
|
self.baudRate = best.baudRate
|
||||||
self.probeStatus = "Found: \(best.port.name)"
|
self.probeStatus = "Found: \(best.port.name)"
|
||||||
|
// Auto-connect after successful probe
|
||||||
|
self.connect()
|
||||||
} else if let firstWorking = workingPorts.first {
|
} else if let firstWorking = workingPorts.first {
|
||||||
// No response but port works - use it anyway
|
// No response but port works - use it anyway
|
||||||
self.detectedDevice = firstWorking.port
|
self.detectedDevice = firstWorking.port
|
||||||
self.selectedPortPath = firstWorking.port.path
|
self.selectedPortPath = firstWorking.port.path
|
||||||
self.selectedProtocol = .vuServer
|
self.selectedProtocol = .vuServer
|
||||||
self.baudRate = firstWorking.baudRate
|
self.baudRate = firstWorking.baudRate
|
||||||
self.probeStatus = "Using: \(firstWorking.port.name) (no response)"
|
self.probeStatus = "Using: \(firstWorking.port.name)"
|
||||||
|
// Auto-connect
|
||||||
|
self.connect()
|
||||||
} else {
|
} else {
|
||||||
self.probeStatus = "No serial devices found"
|
self.probeStatus = "No serial devices found"
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user