add open with handling
This commit is contained in:
parent
8422d07a05
commit
f74bbd7f5a
@ -49,4 +49,31 @@ class AppDelegate: NSObject, NSApplicationDelegate {
|
||||
defaults.removeObject(forKey: "defaultPowerModeConfigV2")
|
||||
defaults.removeObject(forKey: "isPowerModeEnabled")
|
||||
}
|
||||
|
||||
// Keep in sync with AudioTranscribeView.supportedExtensions
|
||||
private let supportedExtensions = ["wav", "mp3", "m4a", "aiff", "mp4", "mov", "aac", "flac", "caf"]
|
||||
|
||||
// Stash URL when app cold-starts to avoid spawning a new window/tab
|
||||
var pendingOpenFileURL: URL?
|
||||
|
||||
func application(_ application: NSApplication, open urls: [URL]) {
|
||||
guard let url = urls.first(where: { supportedExtensions.contains($0.pathExtension.lowercased()) }) else {
|
||||
return
|
||||
}
|
||||
|
||||
NSApp.activate(ignoringOtherApps: true)
|
||||
|
||||
if NSApp.windows.isEmpty {
|
||||
// Cold start: do NOT create a window here to avoid extra window/tab.
|
||||
// Defer to SwiftUI’s WindowGroup-created ContentView and let it process this later.
|
||||
pendingOpenFileURL = url
|
||||
} else {
|
||||
// Running: focus current window and route in-place to Transcribe Audio
|
||||
NSApp.windows.first?.makeKeyAndOrderFront(nil)
|
||||
NotificationCenter.default.post(name: .navigateToDestination, object: nil, userInfo: ["destination": "Transcribe Audio"])
|
||||
DispatchQueue.main.async {
|
||||
NotificationCenter.default.post(name: .openFileForTranscription, object: nil, userInfo: ["url": url])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -18,5 +18,64 @@
|
||||
<string>VoiceInk needs to interact with your browser to detect the current website for applying website-specific configurations.</string>
|
||||
<key>NSScreenCaptureUsageDescription</key>
|
||||
<string>VoiceInk needs screen recording access to understand context from your screen for improved transcription accuracy.</string>
|
||||
<key>CFBundleDocumentTypes</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>CFBundleTypeName</key>
|
||||
<string>Audio/Video File</string>
|
||||
<key>CFBundleTypeRole</key>
|
||||
<string>Viewer</string>
|
||||
<key>LSHandlerRank</key>
|
||||
<string>Alternate</string>
|
||||
<key>LSItemContentTypes</key>
|
||||
<array>
|
||||
<string>public.audio</string>
|
||||
<string>public.movie</string>
|
||||
</array>
|
||||
<key>CFBundleTypeExtensions</key>
|
||||
<array>
|
||||
<string>wav</string>
|
||||
<string>mp3</string>
|
||||
<string>m4a</string>
|
||||
<string>aiff</string>
|
||||
<string>mp4</string>
|
||||
<string>mov</string>
|
||||
<string>aac</string>
|
||||
<string>flac</string>
|
||||
<string>caf</string>
|
||||
</array>
|
||||
</dict>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
<!-- Somewhere near the existing keys -->
|
||||
<key>CFBundleDocumentTypes</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>CFBundleTypeName</key>
|
||||
<string>Audio/Video File</string>
|
||||
<key>CFBundleTypeRole</key>
|
||||
<string>Viewer</string>
|
||||
<key>LSHandlerRank</key>
|
||||
<string>Alternate</string>
|
||||
<key>LSItemContentTypes</key>
|
||||
<array>
|
||||
<string>public.audio</string>
|
||||
<string>public.movie</string>
|
||||
</array>
|
||||
<key>CFBundleTypeExtensions</key>
|
||||
<array>
|
||||
<string>wav</string>
|
||||
<string>mp3</string>
|
||||
<string>m4a</string>
|
||||
<string>aiff</string>
|
||||
<string>mp4</string>
|
||||
<string>mov</string>
|
||||
<string>aac</string>
|
||||
<string>flac</string>
|
||||
<string>caf</string>
|
||||
</array>
|
||||
</dict>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
|
||||
@ -14,4 +14,5 @@ extension Notification.Name {
|
||||
static let powerModeConfigurationApplied = Notification.Name("powerModeConfigurationApplied")
|
||||
static let transcriptionCreated = Notification.Name("transcriptionCreated")
|
||||
static let enhancementToggleChanged = Notification.Name("enhancementToggleChanged")
|
||||
static let openFileForTranscription = Notification.Name("openFileForTranscription")
|
||||
}
|
||||
|
||||
@ -112,6 +112,12 @@ struct AudioTranscribeView: View {
|
||||
Text(errorMessage)
|
||||
}
|
||||
}
|
||||
.onReceive(NotificationCenter.default.publisher(for: .openFileForTranscription)) { notification in
|
||||
if let url = notification.userInfo?["url"] as? URL {
|
||||
// Do not auto-start; only select file for manual transcription
|
||||
validateAndSetAudioFile(url)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private var dropZoneView: some View {
|
||||
@ -381,4 +387,4 @@ struct AudioTranscribeView: View {
|
||||
let seconds = Int(duration) % 60
|
||||
return String(format: "%d:%02d", minutes, seconds)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -164,6 +164,8 @@ struct ContentView: View {
|
||||
@State private var hasLoadedData = false
|
||||
let appVersion = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String ?? "1.0.0"
|
||||
@StateObject private var licenseViewModel = LicenseViewModel()
|
||||
// Capture the hosting window to update tab/window title dynamically
|
||||
@State private var hostingWindow: NSWindow?
|
||||
|
||||
private var isSetupComplete: Bool {
|
||||
hasLoadedData &&
|
||||
@ -189,9 +191,17 @@ struct ContentView: View {
|
||||
}
|
||||
.navigationSplitViewStyle(.balanced)
|
||||
.frame(minWidth: 940, minHeight: 730)
|
||||
// Resolve hosting NSWindow and set initial title
|
||||
.background(
|
||||
WindowTitleAccessor { window in
|
||||
self.hostingWindow = window
|
||||
self.hostingWindow?.title = selectedView.rawValue
|
||||
}
|
||||
)
|
||||
.onAppear {
|
||||
hasLoadedData = true
|
||||
}
|
||||
// inside ContentView body:
|
||||
.onReceive(NotificationCenter.default.publisher(for: .navigateToDestination)) { notification in
|
||||
print("ContentView: Received navigation notification")
|
||||
if let destination = notification.userInfo?["destination"] as? String {
|
||||
@ -215,6 +225,10 @@ struct ContentView: View {
|
||||
case "Enhancement":
|
||||
print("ContentView: Navigating to Enhancement")
|
||||
selectedView = .enhancement
|
||||
case "Transcribe Audio":
|
||||
// Ensure we switch to the Transcribe Audio view in-place
|
||||
print("ContentView: Navigating to Transcribe Audio")
|
||||
selectedView = .transcribeAudio
|
||||
default:
|
||||
print("ContentView: No matching destination found for: \(destination)")
|
||||
break
|
||||
@ -223,6 +237,10 @@ struct ContentView: View {
|
||||
print("ContentView: No destination in notification")
|
||||
}
|
||||
}
|
||||
// Update the tab/window title whenever the active view changes
|
||||
.onChange(of: selectedView) { newValue in
|
||||
hostingWindow?.title = newValue.rawValue
|
||||
}
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
@ -259,3 +277,21 @@ struct ContentView: View {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct WindowTitleAccessor: NSViewRepresentable {
|
||||
var onResolve: (NSWindow?) -> Void
|
||||
|
||||
func makeNSView(context: Context) -> NSView {
|
||||
let view = NSView()
|
||||
DispatchQueue.main.async { [weak view] in
|
||||
onResolve(view?.window)
|
||||
}
|
||||
return view
|
||||
}
|
||||
|
||||
func updateNSView(_ nsView: NSView, context: Context) {
|
||||
DispatchQueue.main.async { [weak nsView] in
|
||||
onResolve(nsView?.window)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -114,6 +114,15 @@ struct VoiceInkApp: App {
|
||||
if !UserDefaults.standard.bool(forKey: "IsTranscriptionCleanupEnabled") {
|
||||
audioCleanupManager.startAutomaticCleanup(modelContext: container.mainContext)
|
||||
}
|
||||
|
||||
// Process any pending open-file request now that the main ContentView is ready.
|
||||
if let pendingURL = appDelegate.pendingOpenFileURL {
|
||||
NotificationCenter.default.post(name: .navigateToDestination, object: nil, userInfo: ["destination": "Transcribe Audio"])
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) {
|
||||
NotificationCenter.default.post(name: .openFileForTranscription, object: nil, userInfo: ["url": pendingURL])
|
||||
}
|
||||
appDelegate.pendingOpenFileURL = nil
|
||||
}
|
||||
}
|
||||
.background(WindowAccessor { window in
|
||||
WindowManager.shared.configureWindow(window)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user