From dbe3294201e15d234f9a4f6803e1af689d2d08aa Mon Sep 17 00:00:00 2001 From: Carsten Abele Date: Tue, 7 Apr 2026 19:43:14 +0200 Subject: [PATCH] feat: add SettingsView with API key, shortcut, mode, and latency --- MyVoxtral/MyVoxtral/Views/SettingsView.swift | 68 ++++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 MyVoxtral/MyVoxtral/Views/SettingsView.swift diff --git a/MyVoxtral/MyVoxtral/Views/SettingsView.swift b/MyVoxtral/MyVoxtral/Views/SettingsView.swift new file mode 100644 index 0000000..94c0e41 --- /dev/null +++ b/MyVoxtral/MyVoxtral/Views/SettingsView.swift @@ -0,0 +1,68 @@ +import SwiftUI + +struct SettingsView: View { + @ObservedObject var settings = AppSettings.shared + @State private var isRecordingShortcut = false + + var body: some View { + Form { + Section("API") { + SecureField("Mistral API Key", text: $settings.apiKey) + } + + Section("Output") { + Picker("Mode", selection: $settings.outputMode) { + ForEach(OutputMode.allCases, id: \.self) { mode in + Text(mode.rawValue).tag(mode) + } + } + .pickerStyle(.segmented) + + if settings.outputMode == .cursorInjection && !CursorInjector.isAccessibilityGranted { + HStack { + Image(systemName: "exclamationmark.triangle.fill") + .foregroundStyle(.yellow) + Text("Accessibility permission required") + .font(.caption) + Button("Grant") { + CursorInjector.promptAccessibilityPermission() + } + .font(.caption) + } + } + } + + Section("Shortcut") { + HStack { + Text("Toggle Recording:") + Spacer() + Button(isRecordingShortcut ? "Press keys..." : settings.shortcutDisplayString) { + isRecordingShortcut = true + } + } + } + + Section("Latency") { + VStack(alignment: .leading) { + Text("Streaming delay: \(settings.streamingDelayMs)ms") + .font(.caption) + Slider( + value: Binding( + get: { Double(settings.streamingDelayMs) }, + set: { settings.streamingDelayMs = Int($0) } + ), + in: 240...2400, + step: 120 + ) + HStack { + Text("Fast").font(.caption2).foregroundStyle(.secondary) + Spacer() + Text("Accurate").font(.caption2).foregroundStyle(.secondary) + } + } + } + } + .formStyle(.grouped) + .frame(width: 360, height: 340) + } +}