Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue #45 #46

Merged
merged 14 commits into from
Feb 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ build/
# https://dart.dev/guides/libraries/private-files#pubspeclock.
pubspec.lock
.vscode/settings.json
.idea/workspace.xml
86 changes: 0 additions & 86 deletions .idea/workspace.xml

This file was deleted.

9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
## 1.5.0

- Add the following window methods:
- `preventWindowClosure`
- `allowWindowClosure`
- `isWindowClosureAllowed`
- `closeWindow`
- `performClose`

## 1.4.0

- Add methods to retrieve or manipulate the window’s size and position.
Expand Down
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ English | [简体中文](README_zh.md)
+ An abstract `NSWindowDelegate` class that can be used to detect `NSWindow` events, such as window resizing, moving, exposing, and minimizing.
+ An `NSAppPresentationOptions` class that allows modifications to the window's fullscreen presentation options.
+ Methods to get and set the positions of the window’s standard window buttons (such as the close, miniaturize, and zoom buttons).
+ Methods to control whether the window should be closable by the user, as well as methods to close the window programmatically.

Additionally, the package ships with an example project that showcases the plugin's features via an intuitive searchable user interface:

Expand All @@ -50,7 +51,7 @@ First, install the package via the following command:
flutter pub add macos_window_utils
```

Afterwards, open the `macos/Runner.xcworkspace` folder of your project using Xcode, press ⇧ + ⌘ + O and search for `Runner.xcodeproj`.
Afterward, open the `macos/Runner.xcworkspace` folder of your project using Xcode, press ⇧ + ⌘ + O and search for `Runner.xcodeproj`.

Go to `Info` > `Deployment Target` and set the `macOS Deployment Target` to `10.14.6` or above. Then, open your project's `Podfile` (if it doesn't show up in Xcode, you can find it in your project's `macos` directory via VS Code) and set the minimum deployment version in the first line to `10.14.6` or above:

Expand Down
1 change: 1 addition & 0 deletions README_zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
+ 一个抽象的 `NSWindowDelegate` 类,可用于检测 `NSWindow` 事件,例如窗口调整大小、移动、暴露和最小化。
+ 一个 `NSAppPresentationOptions` 类,允许修改窗口的全屏演示选项。
+ 获取和设置窗口标准窗口按钮(例如关闭、缩小和缩放按钮)位置的方法。
+ 控制窗口是否应关闭用户以及以编程方式关闭窗口的方法。

此外,该包还附带了一个示例项目,通过直观的可搜索用户界面展示了插件的功能:

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -636,6 +636,43 @@ class CommandListProvider {
const Offset(64, 32) & const Size(512, 512),
animate: true),
),
Command(
name: 'WindowManipulator.preventWindowClosure()',
description: 'Prevents the window from being closed by the user.\n\n'
'The window will still be closable programmatically by calling '
'`closeWindow`.',
function: () => WindowManipulator.preventWindowClosure(),
),
Command(
name: 'WindowManipulator.allowWindowClosure()',
description: 'Allows the window to be closed by the user.',
function: () => WindowManipulator.allowWindowClosure(),
),
Command(
name: 'WindowManipulator.isWindowClosureAllowed()',
description: 'Returns whether the window can be closed by the user.',
function: () async => debugPrint(
(await WindowManipulator.isWindowClosureAllowed()).toString()),
),
Command(
name: 'WindowManipulator.closeWindow()',
description: 'Removes the window from the screen. \n\n'
'The close method differs in two important ways from the '
'`performClose` method:\n'
' + It does not attempt to send a '
'`NSWindowDelegate.windowShouldClose` '
'message to its delegates.\n'
'+ It does not simulate the user clicking the close button by '
'momentarily highlighting the button.\n\n'
'Use `performClose` if you need these features.',
function: () => WindowManipulator.closeWindow(),
),
Command(
name: 'WindowManipulator.performClose()',
description: 'Simulates the user clicking the close button by '
'momentarily highlighting the button and then closing the window.',
function: () => WindowManipulator.performClose(),
),
];
}
}
5 changes: 2 additions & 3 deletions lib/widgets/titlebar_safe_area.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@ import 'package:macos_window_utils/macos_window_utils.dart';
class _MacOSTitlebarSafeArea extends StatefulWidget {
final Widget child;

const _MacOSTitlebarSafeArea({Key? key, required this.child})
: super(key: key);
const _MacOSTitlebarSafeArea({required this.child});

@override
State<_MacOSTitlebarSafeArea> createState() => _MacOSTitlebarSafeAreaState();
Expand Down Expand Up @@ -54,7 +53,7 @@ class TitlebarSafeArea extends StatelessWidget {
/// child: Text('Hello World'),
/// )
/// ```
const TitlebarSafeArea({Key? key, required this.child}) : super(key: key);
const TitlebarSafeArea({super.key, required this.child});

@override
Widget build(BuildContext context) {
Expand Down
5 changes: 2 additions & 3 deletions lib/widgets/transparent_macos_bottom_bar.dart
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,12 @@ class TransparentMacOSBottomBar extends StatelessWidget {
/// )
/// ```
const TransparentMacOSBottomBar(
{Key? key,
{super.key,
this.alphaValue = 1.0,
this.material = NSVisualEffectViewMaterial.sidebar,
this.state = NSVisualEffectViewState.followsWindowActiveState,
this.resizeEventRelay,
required this.child})
: super(key: key);
required this.child});

@override
Widget build(BuildContext context) {
Expand Down
5 changes: 2 additions & 3 deletions lib/widgets/transparent_macos_sidebar.dart
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,12 @@ class TransparentMacOSSidebar extends StatelessWidget {
/// )
/// ```
const TransparentMacOSSidebar(
{Key? key,
{super.key,
this.alphaValue = 1.0,
this.material = NSVisualEffectViewMaterial.sidebar,
this.state = NSVisualEffectViewState.followsWindowActiveState,
this.resizeEventRelay,
required this.child})
: super(key: key);
required this.child});

@override
Widget build(BuildContext context) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,16 +53,15 @@ class VisualEffectSubviewContainer extends StatefulWidget {
/// [VisualEffectSubviewContainerResizeEventRelay] through which its update
/// behavior can be controlled manually.
const VisualEffectSubviewContainer(
{Key? key,
{super.key,
required this.child,
this.alphaValue = 1.0,
this.cornerRadius,
this.cornerMask = 0xf,
required this.material,
this.state = NSVisualEffectViewState.followsWindowActiveState,
this.padding = EdgeInsets.zero,
this.resizeEventRelay})
: super(key: key);
this.resizeEventRelay});

@override
State<VisualEffectSubviewContainer> createState() =>
Expand Down
62 changes: 62 additions & 0 deletions lib/window_manipulator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -742,4 +742,66 @@ class WindowManipulator {
'animate': animate,
});
}

/// Prevents the window from being closed by the user.
///
/// Requires the window delegate to be enabled.
///
/// The window will still be closable programmatically by calling
/// [closeWindow].
static Future<void> preventWindowClosure() async {
await _completer.future;
final hasSucceeded = await _windowManipulatorMethodChannel
.invokeMethod('preventWindowClosure');

assert(
hasSucceeded,
'preventWindowClosure failed. Please make sure that '
'the `enableWindowDelegate` parameter is set to true in your '
'WindowManipulator.initialize call.');
}

/// Allows the window to be closed by the user.
///
/// Requires the window delegate to be enabled.
static Future<void> allowWindowClosure() async {
await _completer.future;
final hasSucceeded = await _windowManipulatorMethodChannel
.invokeMethod('allowWindowClosure');

assert(
hasSucceeded,
'allowWindowClosure failed. Please make sure that '
'the `enableWindowDelegate` parameter is set to true in your '
'WindowManipulator.initialize call.');
}

/// Returns whether the window can be closed by the user.
static Future<bool> isWindowClosureAllowed() async {
await _completer.future;
return await _windowManipulatorMethodChannel
.invokeMethod('isWindowClosureAllowed');
}

/// Removes the window from the screen.
///
/// The close method differs in two important ways from the [performClose]
/// method:
/// + It does not attempt to send a [NSWindowDelegate.windowShouldClose]
/// message to its delegates.
/// + It does not simulate the user clicking the close button by momentarily
/// highlighting the button.
///
/// Use [performClose] if you need these features.
static Future<void> closeWindow() async {
await _completer.future;
await _windowManipulatorMethodChannel.invokeMethod('closeWindow');
}

/// Simulates the user clicking the close button by momentarily highlighting
/// the button and then closing the window.
static Future<void> performClose() async {
await _completer.future;
await _windowManipulatorMethodChannel.invokeMethod('performClose');
}
}
4 changes: 3 additions & 1 deletion macos/Classes/FlutterWindowDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import FlutterMacOS
class FlutterWindowDelegate: NSObject, NSWindowDelegate {
private var methodChannel: FlutterMethodChannel?
private var fullScreenPresentationOptions: NSApplication.PresentationOptions?
public var windowShouldCloseReturnValue: Bool = true

public static func create(window: NSWindow, methodChannel: FlutterMethodChannel) -> FlutterWindowDelegate {
let newDelegate = FlutterWindowDelegate()
Expand Down Expand Up @@ -142,7 +143,8 @@ class FlutterWindowDelegate: NSObject, NSWindowDelegate {

func windowShouldClose(_ sender: NSWindow) -> Bool {
methodChannel!.invokeMethod("windowShouldClose", arguments: nil)
return true

return windowShouldCloseReturnValue
}

func windowWillClose(_ notification: Notification) {
Expand Down
22 changes: 22 additions & 0 deletions macos/Classes/MacOSWindowUtilsPlugin.swift
Original file line number Diff line number Diff line change
Expand Up @@ -484,6 +484,28 @@ public class MacOSWindowUtilsPlugin: NSObject, FlutterPlugin {
result(true)
break

case "preventWindowClosure":
result(MainFlutterWindowManipulator.preventWindowClosure())
break

case "allowWindowClosure":
result(MainFlutterWindowManipulator.allowWindowClosure())
break

case "isWindowClosureAllowed":
result(MainFlutterWindowManipulator.isWindowClosureAllowed())
break

case "closeWindow":
MainFlutterWindowManipulator.closeWindow()
result(true)
break

case "performClose":
MainFlutterWindowManipulator.performClose()
result(true)
break

default:
result(FlutterMethodNotImplemented)
break
Expand Down
Loading