import 'dart:io' show Platform; import 'package:flutter/services.dart'; import 'fullscreen_state_manager.dart'; /// Abstract class for receiving macOS window delegate callbacks. /// Extend this class and register with [MacOSWindowService] to receive /// fullscreen transition events. abstract class MacOSWindowDelegate { /// Called when the window is about to enter fullscreen mode. // ignore: no-empty-block - default no-op, subclasses override as needed void windowWillEnterFullScreen() {} /// Called when the window has entered fullscreen mode. // ignore: no-empty-block - default no-op, subclasses override as needed void windowDidEnterFullScreen() {} /// Called when the window is about to exit fullscreen mode. // ignore: no-empty-block - default no-op, subclasses override as needed void windowWillExitFullScreen() {} /// Called when the window has exited fullscreen mode. // ignore: no-empty-block - default no-op, subclasses override as needed void windowDidExitFullScreen() {} } /// Service for manipulating macOS window properties. /// This is a native implementation replacing the macos_window_utils package. /// /// Note: Titlebar, toolbar, and traffic light position management is now handled /// directly in Swift (WindowDelegate.swift) during fullscreen transitions. /// This service only exposes what's needed externally: /// - Traffic light visibility (for video controls) /// - Fullscreen enter/exit (for video controls) /// - Delegate registration (for FullscreenStateManager updates) class MacOSWindowService { static const _channel = MethodChannel('com.plezy/window_utils'); static bool _initialized = false; static bool _delegateEnabled = false; static final List _delegates = []; static final MacOSWindowDelegate _fullscreenDelegate = _FullscreenWindowDelegate(); static Future _invoke(String method, [Map? args]) async { if (!Platform.isMacOS) return; await _channel.invokeMethod(method, args); } static void _notifyDelegates(void Function(MacOSWindowDelegate) callback) { for (final delegate in _delegates) { callback(delegate); } } static Future _handleMethodCall(MethodCall call) async { switch (call.method) { case 'windowWillEnterFullScreen': _notifyDelegates((d) => d.windowWillEnterFullScreen()); case 'windowDidEnterFullScreen': _notifyDelegates((d) => d.windowDidEnterFullScreen()); case 'windowWillExitFullScreen': _notifyDelegates((d) => d.windowWillExitFullScreen()); case 'windowDidExitFullScreen': _notifyDelegates((d) => d.windowDidExitFullScreen()); } } /// Initialize the window service and set up the titlebar. /// /// Note: The initial window configuration (transparent titlebar, toolbar, /// button positions, fullscreen presentation options) is now applied in /// MainFlutterWindow.swift / WindowDelegate.swift BEFORE frame restoration /// to prevent the window from shrinking on launch. /// /// This method sets up the Dart-side callbacks for fullscreen state tracking. static Future setupCustomTitlebar() async { if (!Platform.isMacOS) return; if (_initialized && _delegateEnabled) { await syncWindowChrome(); FullscreenStateManager().setFullscreen(await isFullscreen()); return; } await initialize(enableWindowDelegate: true); addWindowDelegate(_fullscreenDelegate); await syncWindowChrome(); FullscreenStateManager().setFullscreen(await isFullscreen()); } /// Initialize the window service. /// Must be called before using other methods. /// Set [enableWindowDelegate] to true to receive fullscreen callbacks. static Future initialize({bool enableWindowDelegate = false}) async { if (!Platform.isMacOS) return; if (!_initialized || (enableWindowDelegate && !_delegateEnabled)) { await _channel.invokeMethod('initialize', {'enableWindowDelegate': enableWindowDelegate}); _initialized = true; } // Set up handler if not already done and delegate is requested if (enableWindowDelegate && !_delegateEnabled) { _channel.setMethodCallHandler(_handleMethodCall); _delegateEnabled = true; } } static void addWindowDelegate(MacOSWindowDelegate delegate) { if (!_delegates.contains(delegate)) { _delegates.add(delegate); } } static void removeWindowDelegate(MacOSWindowDelegate delegate) { _delegates.remove(delegate); } static Future setTrafficLightsVisible(bool visible) => _invoke('setTrafficLightsVisible', {'visible': visible}); static Future syncWindowChrome() => _invoke('syncWindowChrome'); static Future enterFullscreen() => _invoke('enterFullscreen'); static Future exitFullscreen() => _invoke('exitFullscreen'); static Future isFullscreen() async { if (!Platform.isMacOS) return false; return await _channel.invokeMethod('isFullscreen') ?? false; } } /// Internal window delegate that manages fullscreen state. /// Note: Window manipulation (toolbar, titlebar, traffic lights) is now handled /// directly in Swift's WindowDelegate. This class only updates Dart-side state. class _FullscreenWindowDelegate extends MacOSWindowDelegate { @override void windowWillEnterFullScreen() { FullscreenStateManager().setFullscreen(true); } @override void windowDidExitFullScreen() { FullscreenStateManager().setFullscreen(false); } }