Open With and title cleanup
This commit is contained in:
parent
8cc3b76972
commit
12c850f77b
@ -459,7 +459,7 @@
|
||||
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
CURRENT_PROJECT_VERSION = 152;
|
||||
CURRENT_PROJECT_VERSION = 153;
|
||||
DEVELOPMENT_ASSET_PATHS = "\"VoiceInk/Preview Content\"";
|
||||
DEVELOPMENT_TEAM = V6J6A3VWY2;
|
||||
ENABLE_HARDENED_RUNTIME = YES;
|
||||
@ -474,7 +474,7 @@
|
||||
"@executable_path/../Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 14.0;
|
||||
MARKETING_VERSION = 1.52;
|
||||
MARKETING_VERSION = 1.53;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.prakashjoshipax.VoiceInk;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG ENABLE_NATIVE_SPEECH_ANALYZER $(inherited)";
|
||||
@ -493,7 +493,7 @@
|
||||
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
CURRENT_PROJECT_VERSION = 152;
|
||||
CURRENT_PROJECT_VERSION = 153;
|
||||
DEVELOPMENT_ASSET_PATHS = "\"VoiceInk/Preview Content\"";
|
||||
DEVELOPMENT_TEAM = V6J6A3VWY2;
|
||||
ENABLE_HARDENED_RUNTIME = YES;
|
||||
@ -508,7 +508,7 @@
|
||||
"@executable_path/../Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 14.0;
|
||||
MARKETING_VERSION = 1.52;
|
||||
MARKETING_VERSION = 1.53;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.prakashjoshipax.VoiceInk;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "ENABLE_NATIVE_SPEECH_ANALYZER $(inherited)";
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
"location" : "https://github.com/FluidInference/FluidAudio",
|
||||
"state" : {
|
||||
"branch" : "main",
|
||||
"revision" : "abf7d9ef3f53a693e3721069071971eff84c002f"
|
||||
"revision" : "052cbb27cf073a9407251d74ef3459ea258e41b3"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import Cocoa
|
||||
import SwiftUI
|
||||
import UniformTypeIdentifiers
|
||||
|
||||
class AppDelegate: NSObject, NSApplicationDelegate {
|
||||
func applicationDidFinishLaunching(_ notification: Notification) {
|
||||
@ -50,14 +51,11 @@ class AppDelegate: NSObject, NSApplicationDelegate {
|
||||
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 {
|
||||
guard let url = urls.first(where: { SupportedMedia.isSupported(url: $0) }) else {
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@ -48,34 +48,3 @@
|
||||
</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>
|
||||
|
||||
28
VoiceInk/Services/SupportedMedia.swift
Normal file
28
VoiceInk/Services/SupportedMedia.swift
Normal file
@ -0,0 +1,28 @@
|
||||
import Foundation
|
||||
import UniformTypeIdentifiers
|
||||
|
||||
struct SupportedMedia {
|
||||
static let extensions: Set<String> = [
|
||||
"wav", "mp3", "m4a", "aiff", "mp4", "mov", "aac", "flac", "caf"
|
||||
]
|
||||
|
||||
static let contentTypes: [UTType] = [
|
||||
.audio, .movie
|
||||
]
|
||||
|
||||
static func isSupported(url: URL) -> Bool {
|
||||
let fileExtension = url.pathExtension.lowercased()
|
||||
if !fileExtension.isEmpty, extensions.contains(fileExtension) {
|
||||
return true
|
||||
}
|
||||
|
||||
if let resourceValues = try? url.resourceValues(forKeys: [.contentTypeKey]),
|
||||
let contentType = resourceValues.contentType {
|
||||
return contentTypes.contains(where: { contentType.conforms(to: $0) })
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -353,29 +353,8 @@ struct AudioTranscribeView: View {
|
||||
}
|
||||
}
|
||||
|
||||
// Validate file type by extension
|
||||
let supportedExtensions = ["wav", "mp3", "m4a", "aiff", "mp4", "mov", "aac", "flac", "caf"]
|
||||
let fileExtension = url.pathExtension.lowercased()
|
||||
|
||||
// Check file extension first
|
||||
if !fileExtension.isEmpty && supportedExtensions.contains(fileExtension) {
|
||||
print("File type validated by extension: \(fileExtension)")
|
||||
} else {
|
||||
print("Unsupported file extension: \(fileExtension)")
|
||||
// Try to validate by UTType as well
|
||||
if let resourceValues = try? url.resourceValues(forKeys: [.contentTypeKey]),
|
||||
let contentType = resourceValues.contentType {
|
||||
if contentType.conforms(to: .audio) || contentType.conforms(to: .movie) {
|
||||
print("File type validated by UTType: \(contentType.identifier)")
|
||||
} else {
|
||||
print("File does not conform to audio or movie type: \(contentType.identifier)")
|
||||
return
|
||||
}
|
||||
} else {
|
||||
print("Could not validate file type")
|
||||
return
|
||||
}
|
||||
}
|
||||
// Validate file type
|
||||
guard SupportedMedia.isSupported(url: url) else { return }
|
||||
|
||||
print("File validated successfully: \(url.lastPathComponent)")
|
||||
selectedAudioURL = url
|
||||
|
||||
@ -164,8 +164,7 @@ 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 &&
|
||||
@ -191,13 +190,6 @@ 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
|
||||
}
|
||||
@ -237,10 +229,6 @@ 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
|
||||
@ -278,20 +266,4 @@ 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user