feat: add floating transcription panel with auto-scroll and copy

This commit is contained in:
Carsten Abele 2026-04-07 19:42:57 +02:00
parent 285b833ba9
commit b26995b15b

View file

@ -0,0 +1,78 @@
import SwiftUI
import AppKit
struct TranscriptionContentView: View {
@ObservedObject var manager: TranscriptionManager
var body: some View {
VStack(alignment: .leading, spacing: 8) {
HStack {
Circle()
.fill(manager.isRecording ? .red : .gray)
.frame(width: 8, height: 8)
Text(manager.isRecording ? "Recording..." : "Idle")
.font(.caption)
.foregroundStyle(.secondary)
Spacer()
Button {
NSPasteboard.general.clearContents()
NSPasteboard.general.setString(manager.currentText, forType: .string)
} label: {
Image(systemName: "doc.on.doc")
}
.buttonStyle(.borderless)
.disabled(manager.currentText.isEmpty)
}
ScrollViewReader { proxy in
ScrollView {
Text(manager.currentText.isEmpty ? "Transcription will appear here..." : manager.currentText)
.frame(maxWidth: .infinity, alignment: .leading)
.foregroundStyle(manager.currentText.isEmpty ? .secondary : .primary)
.textSelection(.enabled)
.id("bottom")
}
.onChange(of: manager.currentText) {
proxy.scrollTo("bottom", anchor: .bottom)
}
}
}
.padding()
.frame(width: 320, height: 200)
}
}
final class TranscriptionPanel {
private var panel: NSPanel?
private let manager: TranscriptionManager
init(manager: TranscriptionManager) {
self.manager = manager
}
func show() {
if panel == nil {
let panel = NSPanel(
contentRect: NSRect(x: 0, y: 0, width: 320, height: 200),
styleMask: [.titled, .closable, .resizable, .nonactivatingPanel, .utilityWindow],
backing: .buffered,
defer: false
)
panel.title = "MyVoxtral"
panel.isFloatingPanel = true
panel.level = .floating
panel.contentView = NSHostingView(rootView: TranscriptionContentView(manager: manager))
panel.center()
self.panel = panel
}
panel?.orderFront(nil)
}
func hide() {
panel?.orderOut(nil)
}
var isVisible: Bool {
panel?.isVisible ?? false
}
}