From 602f97253cf1f4c3398a4b157a4753b81bff60a6 Mon Sep 17 00:00:00 2001 From: Carsten Abele Date: Tue, 7 Apr 2026 19:44:07 +0200 Subject: [PATCH] feat: wire all components into app entry with menu bar, shortcut, and windows --- MyVoxtral/MyVoxtral/MyVoxtralApp.swift | 72 ++++++++++++++++++++++++-- 1 file changed, 67 insertions(+), 5 deletions(-) diff --git a/MyVoxtral/MyVoxtral/MyVoxtralApp.swift b/MyVoxtral/MyVoxtral/MyVoxtralApp.swift index 539a7ea..60fe270 100644 --- a/MyVoxtral/MyVoxtral/MyVoxtralApp.swift +++ b/MyVoxtral/MyVoxtral/MyVoxtralApp.swift @@ -2,13 +2,75 @@ import SwiftUI @main struct MyVoxtralApp: App { + @StateObject private var manager = TranscriptionManager() + @StateObject private var settings = AppSettings.shared + @State private var transcriptionPanel: TranscriptionPanel? + @State private var settingsWindow: NSWindow? + + private let globalShortcut = GlobalShortcut() + var body: some Scene { - MenuBarExtra("MyVoxtral", systemImage: "mic.fill") { - Text("MyVoxtral") - Divider() - Button("Quit") { - NSApplication.shared.terminate(nil) + MenuBarExtra { + MenuBarView( + manager: manager, + onShowTranscription: { showTranscriptionWindow() }, + onShowSettings: { showSettingsWindow() } + ) + .task { + if !settings.hasAPIKey { + showSettingsWindow() + } + registerShortcut() + } + .onChange(of: manager.isRecording) { + if manager.isRecording && settings.outputMode == .textBox { + showTranscriptionWindow() + } + } + } label: { + Image(systemName: manager.isRecording ? "mic.fill" : "mic") + .symbolRenderingMode(.palette) + .foregroundStyle(manager.isRecording ? .red : .primary) + } + .onChange(of: settings.shortcutKeyCode) { registerShortcut() } + .onChange(of: settings.shortcutModifiers) { registerShortcut() } + } + + private func registerShortcut() { + globalShortcut.register( + keyCode: settings.shortcutKeyCode, + modifiers: settings.shortcutModifiers + ) + globalShortcut.onTrigger = { [weak manager] in + Task { @MainActor in + manager?.toggle() } } } + + private func showTranscriptionWindow() { + if transcriptionPanel == nil { + transcriptionPanel = TranscriptionPanel(manager: manager) + } + transcriptionPanel?.show() + } + + private func showSettingsWindow() { + if let settingsWindow, settingsWindow.isVisible { + settingsWindow.makeKeyAndOrderFront(nil) + return + } + let window = NSWindow( + contentRect: NSRect(x: 0, y: 0, width: 360, height: 340), + styleMask: [.titled, .closable], + backing: .buffered, + defer: false + ) + window.title = "MyVoxtral Settings" + window.contentView = NSHostingView(rootView: SettingsView()) + window.center() + window.makeKeyAndOrderFront(nil) + NSApp.activate(ignoringOtherApps: true) + self.settingsWindow = window + } }