refactor(mac): split voice wake settings
This commit is contained in:
108
apps/macos/Sources/Clawdis/VoiceWakeForwardSection.swift
Normal file
108
apps/macos/Sources/Clawdis/VoiceWakeForwardSection.swift
Normal file
@@ -0,0 +1,108 @@
|
||||
import SwiftUI
|
||||
|
||||
enum VoiceWakeForwardStatus: Equatable {
|
||||
case idle
|
||||
case checking
|
||||
case ok
|
||||
case failed(String)
|
||||
}
|
||||
|
||||
struct VoiceWakeForwardSection: View {
|
||||
@Binding var enabled: Bool
|
||||
@Binding var target: String
|
||||
@Binding var identity: String
|
||||
@Binding var command: String
|
||||
@Binding var showAdvanced: Bool
|
||||
@Binding var status: VoiceWakeForwardStatus
|
||||
let onTest: () -> Void
|
||||
let onChange: () -> Void
|
||||
|
||||
var body: some View {
|
||||
VStack(alignment: .leading, spacing: 8) {
|
||||
Toggle(isOn: self.$enabled) {
|
||||
Text("Forward wake to host (SSH)")
|
||||
}
|
||||
|
||||
if self.enabled {
|
||||
VStack(alignment: .leading, spacing: 8) {
|
||||
HStack(spacing: 10) {
|
||||
Text("SSH")
|
||||
.font(.callout.weight(.semibold))
|
||||
.frame(width: 40, alignment: .leading)
|
||||
TextField("steipete@peters-mac-studio-1", text: self.$target)
|
||||
.textFieldStyle(.roundedBorder)
|
||||
.frame(maxWidth: .infinity)
|
||||
.onChange(of: self.target) { _, _ in
|
||||
self.onChange()
|
||||
}
|
||||
self.statusIcon
|
||||
.frame(width: 16, height: 16, alignment: .center)
|
||||
Button("Test") { self.onTest() }
|
||||
.disabled(self.target.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty)
|
||||
}
|
||||
|
||||
if case let .failed(message) = self.status {
|
||||
Text(message)
|
||||
.font(.caption)
|
||||
.foregroundStyle(.secondary)
|
||||
.lineLimit(5)
|
||||
}
|
||||
|
||||
DisclosureGroup(isExpanded: self.$showAdvanced) {
|
||||
VStack(alignment: .leading, spacing: 10) {
|
||||
LabeledContent("Identity file") {
|
||||
TextField(
|
||||
"/Users/you/.ssh/voicewake_ed25519",
|
||||
text: self.$identity)
|
||||
.textFieldStyle(.roundedBorder)
|
||||
.frame(width: 320)
|
||||
.onChange(of: self.identity) { _, _ in
|
||||
self.onChange()
|
||||
}
|
||||
}
|
||||
|
||||
VStack(alignment: .leading, spacing: 4) {
|
||||
Text("Remote command template")
|
||||
.font(.callout.weight(.semibold))
|
||||
TextField(
|
||||
"clawdis-mac agent --message \"${text}\" --thinking low",
|
||||
text: self.$command,
|
||||
axis: .vertical)
|
||||
.textFieldStyle(.roundedBorder)
|
||||
.onChange(of: self.command) { _, _ in
|
||||
self.onChange()
|
||||
}
|
||||
Text(
|
||||
"${text} is replaced with the transcript."
|
||||
+ "\nIt is also piped to stdin if you prefer $(cat).")
|
||||
.font(.footnote)
|
||||
.foregroundStyle(.secondary)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
}
|
||||
}
|
||||
.padding(.top, 4)
|
||||
} label: {
|
||||
Text("Advanced")
|
||||
.font(.callout.weight(.semibold))
|
||||
}
|
||||
}
|
||||
.transition(.opacity.combined(with: .move(edge: .top)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private var statusIcon: some View {
|
||||
Group {
|
||||
switch self.status {
|
||||
case .idle:
|
||||
Image(systemName: "circle.dashed").foregroundStyle(.secondary)
|
||||
case .checking:
|
||||
ProgressView().controlSize(.mini)
|
||||
case .ok:
|
||||
Image(systemName: "checkmark.circle.fill").foregroundStyle(.green)
|
||||
case .failed:
|
||||
Image(systemName: "exclamationmark.triangle.fill").foregroundStyle(.yellow)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user