Skip to content

Commit

Permalink
Merge pull request #46 from macosui/issue_10
Browse files Browse the repository at this point in the history
Issue #45
  • Loading branch information
Adrian-Samoticha authored Feb 18, 2024
2 parents 349b8b9 + 244b130 commit 385df0b
Show file tree
Hide file tree
Showing 16 changed files with 188 additions and 102 deletions.
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

0 comments on commit 385df0b

Please sign in to comment.