Detection now runs off the UI isolate and covers every platform where the answer can be trusted. Availability was a plain platform check, so Linux always listed VLC, mpv and Celluloid, macOS always listed VLC and IINA, and Windows always listed VLC and PotPlayer whether or not any of them existed. Each player now has a detector that asks exactly the question its launcher asks: `sh -c 'command -v'` for PATH launches so the kernel performs the executable check, NSWorkspace/Launch Services for `open -a`, `where.exe` plus the concrete install paths for Windows VLC, and the registered URL handler for PotPlayer and the iOS players. Detection is asynchronous and memoised behind KnownPlayers.probe rather than a Process.runSync in a static initialiser, which forked three shells on the UI isolate during ExternalPlayerScreen.build. It is prewarmed from startup, fails open when a probe throws, and keeps the selected player listed when a detector misses it so a false negative cannot leave the list with nothing selected. iOS and tvOS gained LSApplicationQueriesSchemes entries for vlc and infuse. Without them canOpenURL returns false for both schemes, so _launchUrlScheme was already refusing to hand off to either player. Android keeps the platform check: package visibility needs native declarations, and a wrong answer there hides a working player.
57 lines
2.1 KiB
Swift
57 lines
2.1 KiB
Swift
import Cocoa
|
|
import FlutterMacOS
|
|
|
|
class MainFlutterWindow: NSWindow {
|
|
override func awakeFromNib() {
|
|
let flutterViewController = FlutterViewController()
|
|
|
|
// Keep the window itself opaque so WindowServer does not have to blend the
|
|
// whole video window with the desktop every frame. Flutter stays clear so
|
|
// the native video layer behind it remains visible.
|
|
self.isOpaque = true
|
|
self.backgroundColor = NSColor.black
|
|
flutterViewController.backgroundColor = NSColor.clear
|
|
|
|
let windowFrame = self.frame
|
|
self.contentViewController = flutterViewController
|
|
self.setFrame(windowFrame, display: true)
|
|
|
|
// Apply initial window configuration BEFORE frame restoration
|
|
// This prevents the window from shrinking on launch
|
|
self.titlebarAppearsTransparent = true
|
|
self.titleVisibility = .hidden
|
|
self.styleMask.insert(.fullSizeContentView)
|
|
|
|
// Add forwarding toolbar for click-through in titlebar area
|
|
let toolbar = ForwardingToolbar(flutterViewController: flutterViewController)
|
|
self.toolbar = toolbar
|
|
|
|
// Register MPV player plugin for video playback
|
|
MpvPlayerPlugin.register(
|
|
with: flutterViewController.registrar(forPlugin: "MpvPlayerPlugin"))
|
|
|
|
// Register the audio-only MPV player plugin for music playback
|
|
MpvAudioPlayerPlugin.register(
|
|
with: flutterViewController.registrar(forPlugin: "MpvAudioPlayerPlugin"))
|
|
|
|
// Register window utils plugin for dynamic titlebar/fullscreen control from Dart
|
|
WindowUtilsPlugin.register(
|
|
with: flutterViewController.registrar(forPlugin: "WindowUtilsPlugin"))
|
|
WindowUtilsPlugin.setWindow(self)
|
|
WindowUtilsPlugin.installWindowDelegate()
|
|
WindowUtilsPlugin.syncWindowChrome()
|
|
|
|
// Register Launch Services lookups used to detect installed external players
|
|
AppLookupPlugin.register(
|
|
with: flutterViewController.registrar(forPlugin: "AppLookupPlugin"))
|
|
|
|
RegisterGeneratedPlugins(registry: flutterViewController)
|
|
|
|
// Enable window position/size persistence
|
|
self.setFrameAutosaveName("com.edde746.plezy.MainWindow")
|
|
WindowUtilsPlugin.syncWindowChrome()
|
|
|
|
super.awakeFromNib()
|
|
}
|
|
}
|