This commit is contained in:
Alessandro Autiero
2023-08-24 19:28:31 +02:00
parent cd7db4cf71
commit 69f2dcd527
70 changed files with 677 additions and 1087 deletions

View File

@@ -1,45 +0,0 @@
## 0.1.5
- Runs on Windows 7
## 0.1.4
- Updated win32 to 3.0.0
## 0.1.3
- Updated ffi to 2.0.0
## 0.1.2
- Flutter 3.0 support
## 0.1.1+1
- Added Linux usage instructions
## 0.1.1
- Linux support now stable
## 0.1.0+1
- Fix gtk library name on Linux
## 0.1.0
- Added null safety support
## 0.0.9
- Linux support added
## 0.0.8
- Added macOS readme instructions
## 0.0.7
- macOS support added
## 0.0.6
- Works with latest Flutter version (master channel)
## 0.0.5
- Works with latest Flutter version (dev channel)
## 0.0.4
- Better integration with other plugins
## 0.0.3
- Using dpi-aware values for title bar and buttons dimensions
- Dynamically calculating default button padding instead of fixed one
## 0.0.2
- Added video tutorial link
## 0.0.1
* Initial release
- Custom window frame - remove standard Windows titlebar and buttons
- Hide window on startup
- Show/hide window
- Minimize/Maximize/Restore/Close window
- Move window using Flutter widget
- Set window size, minimum size and maximum size
- Set window position
- Set window alignment on screen (center/topLeft/topRight/bottomLeft/bottomRight)
- Set window title

View File

@@ -1,21 +0,0 @@
MIT License
Copyright (c) 2020-2021 Bogdan Hobeanu
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -1,262 +0,0 @@
# bitsdojo_window
A [Flutter package](https://pub.dev/packages/bitsdojo_window) that makes it easy to customize and work with your Flutter desktop app window **on Windows, macOS and Linux**.
Watch the tutorial to get started. Click the image below to watch the video:
[![IMAGE ALT TEXT](https://img.youtube.com/vi/bee2AHQpGK4/0.jpg)](https://www.youtube.com/watch?v=bee2AHQpGK4 "Click to open")
<img src="https://raw.githubusercontent.com/bitsdojo/bitsdojo_window/master/resources/screenshot.png">
**Features**:
- Custom window frame - remove standard Windows/macOS/Linux titlebar and buttons
- Hide window on startup
- Show/hide window
- Move window using Flutter widget
- Minimize/Maximize/Restore/Close window
- Set window size, minimum size and maximum size
- Set window position
- Set window alignment on screen (center/topLeft/topRight/bottomLeft/bottomRight)
- Set window title
# Getting Started
Install the package using `pubspec.yaml`
# For Windows apps
Inside your application folder, go to `windows\runner\main.cpp` and add these two lines at the beginning of the file:
```cpp
#include <bitsdojo_window_windows/bitsdojo_window_plugin.h>
auto bdw = bitsdojo_window_configure(BDW_CUSTOM_FRAME | BDW_HIDE_ON_STARTUP);
```
# For macOS apps
Inside your application folder, go to `macos\runner\MainFlutterWindow.swift` and add this line after the one saying `import FlutterMacOS` :
```swift
import FlutterMacOS
import bitsdojo_window_macos // Add this line
```
Then change this line from:
```swift
class MainFlutterWindow: NSWindow {
```
to this:
```swift
class MainFlutterWindow: BitsdojoWindow {
```
After changing `NSWindow` to `BitsdojoWindow` add these lines below the line you changed:
```swift
override func bitsdojo_window_configure() -> UInt {
return BDW_CUSTOM_FRAME | BDW_HIDE_ON_STARTUP
}
```
Your code should now look like this:
```swift
class MainFlutterWindow: BitsdojoWindow {
override func bitsdojo_window_configure() -> UInt {
return BDW_CUSTOM_FRAME | BDW_HIDE_ON_STARTUP
}
override func awakeFromNib() {
... //rest of your code
```
#
If you don't want to use a custom frame and prefer the standard window titlebar and buttons, you can remove the `BDW_CUSTOM_FRAME` flag from the code above.
If you don't want to hide the window on startup, you can remove the `BDW_HIDE_ON_STARTUP` flag from the code above.
# For Linux apps
Inside your application folder, go to `linux\my_application.cc` and add this line at the beginning of the file:
```cpp
#include <bitsdojo_window_linux/bitsdojo_window_plugin.h>
```
Then look for these two lines:
```cpp
gtk_window_set_default_size(window, 1280, 720);
gtk_widget_show(GTK_WIDGET(window));
```
and change them to this:
```cpp
auto bdw = bitsdojo_window_from(window); // <--- add this line
bdw->setCustomFrame(true); // <-- add this line
//gtk_window_set_default_size(window, 1280, 720); // <-- comment this line
gtk_widget_show(GTK_WIDGET(window));
```
As you can see, we commented the line calling `gtk_window_set_default_size` and added these two lines before `gtk_widget_show(GTK_WIDGET(window));`
```cpp
auto bdw = bitsdojo_window_from(window);
bdw->setCustomFrame(true);
```
# Flutter app integration
Now go to `lib\main.dart` and add this code in the `main` function right after `runApp(MyApp());` :
```dart
void main() {
runApp(MyApp());
// Add this code below
doWhenWindowReady(() {
const initialSize = Size(600, 450);
appWindow.minSize = initialSize;
appWindow.size = initialSize;
appWindow.alignment = Alignment.center;
appWindow.show();
});
}
```
This will set an initial size and a minimum size for your application window, center it on the screen and show it on the screen.
You can find examples in the `example` folder.
Here is an example that displays this window:
<details>
<summary>Click to expand</summary>
```dart
import 'package:flutter/material.dart';
import 'package:bitsdojo_window/bitsdojo_window.dart';
void main() {
runApp(const MyApp());
doWhenWindowReady(() {
final win = appWindow;
const initialSize = Size(600, 450);
win.minSize = initialSize;
win.size = initialSize;
win.alignment = Alignment.center;
win.title = "Custom window with Flutter";
win.show();
});
}
const borderColor = Color(0xFF805306);
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
body: WindowBorder(
color: borderColor,
width: 1,
child: Row(
children: const [LeftSide(), RightSide()],
),
),
),
);
}
}
const sidebarColor = Color(0xFFF6A00C);
class LeftSide extends StatelessWidget {
const LeftSide({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return SizedBox(
width: 200,
child: Container(
color: sidebarColor,
child: Column(
children: [
WindowTitleBarBox(child: MoveWindow()),
Expanded(child: Container())
],
)));
}
}
const backgroundStartColor = Color(0xFFFFD500);
const backgroundEndColor = Color(0xFFF6A00C);
class RightSide extends StatelessWidget {
const RightSide({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Expanded(
child: Container(
decoration: const BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [backgroundStartColor, backgroundEndColor],
stops: [0.0, 1.0]),
),
child: Column(children: [
WindowTitleBarBox(
child: Row(
children: [Expanded(child: MoveWindow()), const WindowButtons()],
),
)
]),
),
);
}
}
final buttonColors = WindowButtonColors(
iconNormal: const Color(0xFF805306),
mouseOver: const Color(0xFFF6A00C),
mouseDown: const Color(0xFF805306),
iconMouseOver: const Color(0xFF805306),
iconMouseDown: const Color(0xFFFFD500));
final closeButtonColors = WindowButtonColors(
mouseOver: const Color(0xFFD32F2F),
mouseDown: const Color(0xFFB71C1C),
iconNormal: const Color(0xFF805306),
iconMouseOver: Colors.white);
class WindowButtons extends StatelessWidget {
const WindowButtons({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Row(
children: [
MinimizeWindowButton(colors: buttonColors),
MaximizeWindowButton(colors: buttonColors),
CloseWindowButton(colors: closeButtonColors),
],
);
}
}
```
</details>
#
# ❤️ **Sponsors - friends helping this package**
I am developing this package in my spare time and any help is appreciated.
If you want to help you can [become a sponsor](https://github.com/sponsors/bitsdojo).
🙏 Thank you!
Want to help? [Become a sponsor](https://github.com/sponsors/bitsdojo)

View File

@@ -1,5 +0,0 @@
export 'src/widgets/window_border.dart';
export 'src/widgets/window_button.dart';
export 'src/widgets/window_caption.dart';
export 'src/icons/icons.dart';
export 'src/app_window.dart';

View File

@@ -1,43 +0,0 @@
import 'package:bitsdojo_window_platform_interface/bitsdojo_window_platform_interface.dart';
import 'package:bitsdojo_window_platform_interface/method_channel_bitsdojo_window.dart';
import 'package:bitsdojo_window_windows/bitsdojo_window_windows.dart';
import 'package:bitsdojo_window_macos/bitsdojo_window_macos.dart';
import 'package:bitsdojo_window_linux/bitsdojo_window_linux.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter/foundation.dart' show kIsWeb;
import 'dart:io' show Platform;
bool _platformInstanceNeedsInit = true;
void initPlatformInstance() {
if (!kIsWeb) {
if (BitsdojoWindowPlatform.instance is MethodChannelBitsdojoWindow) {
if (Platform.isWindows) {
BitsdojoWindowPlatform.instance = BitsdojoWindowWindows();
} else if (Platform.isMacOS) {
BitsdojoWindowPlatform.instance = BitsdojoWindowMacOS();
} else if (Platform.isLinux) {
BitsdojoWindowPlatform.instance = BitsdojoWindowLinux();
}
}
} else {
BitsdojoWindowPlatform.instance = BitsdojoWindowPlatformNotImplemented();
}
}
BitsdojoWindowPlatform get _platform {
var needsInit = _platformInstanceNeedsInit;
if (needsInit) {
initPlatformInstance();
_platformInstanceNeedsInit = false;
}
return BitsdojoWindowPlatform.instance;
}
void doWhenWindowReady(VoidCallback callback) {
_platform.doWhenWindowReady(callback);
}
DesktopWindow get appWindow {
return _platform.appWindow;
}

View File

@@ -1,114 +0,0 @@
import 'dart:math';
import 'package:flutter/widgets.dart';
// Switched to CustomPaint icons by https://github.com/esDotDev
/// Close
class CloseIcon extends StatelessWidget {
final Color color;
CloseIcon({Key? key, required this.color}) : super(key: key);
@override
Widget build(BuildContext context) => Align(
alignment: Alignment.topLeft,
child: Stack(children: [
// Use rotated containers instead of a painter because it renders slightly crisper than a painter for some reason.
Transform.rotate(
angle: pi * .25,
child:
Center(child: Container(width: 14, height: 1, color: color))),
Transform.rotate(
angle: pi * -.25,
child:
Center(child: Container(width: 14, height: 1, color: color))),
]),
);
}
/// Maximize
class MaximizeIcon extends StatelessWidget {
final Color color;
MaximizeIcon({Key? key, required this.color}) : super(key: key);
@override
Widget build(BuildContext context) => _AlignedPaint(_MaximizePainter(color));
}
class _MaximizePainter extends _IconPainter {
_MaximizePainter(Color color) : super(color);
@override
void paint(Canvas canvas, Size size) {
Paint p = getPaint(color);
canvas.drawRect(Rect.fromLTRB(0, 0, size.width - 1, size.height - 1), p);
}
}
/// Restore
class RestoreIcon extends StatelessWidget {
final Color color;
RestoreIcon({
Key? key,
required this.color,
}) : super(key: key);
@override
Widget build(BuildContext context) => _AlignedPaint(_RestorePainter(color));
}
class _RestorePainter extends _IconPainter {
_RestorePainter(Color color) : super(color);
@override
void paint(Canvas canvas, Size size) {
Paint p = getPaint(color);
canvas.drawRect(Rect.fromLTRB(0, 2, size.width - 2, size.height), p);
canvas.drawLine(Offset(2, 2), Offset(2, 0), p);
canvas.drawLine(Offset(2, 0), Offset(size.width, 0), p);
canvas.drawLine(
Offset(size.width, 0), Offset(size.width, size.height - 2), p);
canvas.drawLine(Offset(size.width, size.height - 2),
Offset(size.width - 2, size.height - 2), p);
}
}
/// Minimize
class MinimizeIcon extends StatelessWidget {
final Color color;
MinimizeIcon({Key? key, required this.color}) : super(key: key);
@override
Widget build(BuildContext context) => _AlignedPaint(_MinimizePainter(color));
}
class _MinimizePainter extends _IconPainter {
_MinimizePainter(Color color) : super(color);
@override
void paint(Canvas canvas, Size size) {
Paint p = getPaint(color);
canvas.drawLine(
Offset(0, size.height / 2), Offset(size.width, size.height / 2), p);
}
}
/// Helpers
abstract class _IconPainter extends CustomPainter {
_IconPainter(this.color);
final Color color;
@override
bool shouldRepaint(covariant CustomPainter oldDelegate) => false;
}
class _AlignedPaint extends StatelessWidget {
const _AlignedPaint(this.painter, {Key? key}) : super(key: key);
final CustomPainter painter;
@override
Widget build(BuildContext context) {
return Align(
alignment: Alignment.center,
child: CustomPaint(size: Size(10, 10), painter: painter));
}
}
Paint getPaint(Color color, [bool isAntiAlias = false]) => Paint()
..color = color
..style = PaintingStyle.stroke
..isAntiAlias = isAntiAlias
..strokeWidth = 1;

View File

@@ -1,71 +0,0 @@
import 'package:flutter/widgets.dart';
typedef MouseStateBuilderCB = Widget Function(
BuildContext context, MouseState mouseState);
class MouseState {
bool isMouseOver = false;
bool isMouseDown = false;
MouseState();
@override
String toString() {
return "isMouseDown: ${this.isMouseDown} - isMouseOver: ${this.isMouseOver}";
}
}
T? _ambiguate<T>(T? value) => value;
class MouseStateBuilder extends StatefulWidget {
final MouseStateBuilderCB builder;
final VoidCallback? onPressed;
MouseStateBuilder({Key? key, required this.builder, this.onPressed})
: super(key: key);
@override
_MouseStateBuilderState createState() => _MouseStateBuilderState();
}
class _MouseStateBuilderState extends State<MouseStateBuilder> {
late MouseState _mouseState;
_MouseStateBuilderState() {
_mouseState = MouseState();
}
@override
Widget build(BuildContext context) {
return MouseRegion(
onEnter: (event) {
setState(() {
_mouseState.isMouseOver = true;
});
},
onExit: (event) {
setState(() {
_mouseState.isMouseOver = false;
});
},
child: GestureDetector(
onTapDown: (_) {
setState(() {
_mouseState.isMouseDown = true;
});
},
onTapCancel: () {
setState(() {
_mouseState.isMouseDown = false;
});
},
onTap: () {
setState(() {
_mouseState.isMouseDown = false;
_mouseState.isMouseOver = false;
});
_ambiguate(WidgetsBinding.instance)!.addPostFrameCallback((_) {
if (widget.onPressed != null) {
widget.onPressed!();
}
});
},
onTapUp: (_) {},
child: widget.builder(context, _mouseState)));
}
}

View File

@@ -1,49 +0,0 @@
import 'package:bitsdojo_window_windows/bitsdojo_window_windows.dart'
show WinDesktopWindow;
import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart';
import '../app_window.dart';
class WindowBorder extends StatelessWidget {
final Widget child;
final Color color;
final double? width;
WindowBorder({Key? key, required this.child, required this.color, this.width})
: super(key: key);
@override
Widget build(BuildContext context) {
bool isWindowsApp =
(!kIsWeb) && (defaultTargetPlatform == TargetPlatform.windows);
bool isLinuxApp =
(!kIsWeb) && (defaultTargetPlatform == TargetPlatform.linux);
// Only show border on Windows and Linux
if (!(isWindowsApp || isLinuxApp)) {
return child;
}
var borderWidth = width ?? 1;
var topBorderWidth = width ?? 1;
if (appWindow is WinDesktopWindow) {
appWindow as WinDesktopWindow..setWindowCutOnMaximize(borderWidth.ceil());
}
if (isWindowsApp) {
topBorderWidth += 1 / appWindow.scaleFactor;
}
final topBorderSide = BorderSide(color: this.color, width: topBorderWidth);
final borderSide = BorderSide(color: this.color, width: borderWidth);
return Container(
child: child,
decoration: BoxDecoration(
border: Border(
top: topBorderSide,
left: borderSide,
right: borderSide,
bottom: borderSide)));
}
}

View File

@@ -1,203 +0,0 @@
import 'package:flutter/material.dart';
import './mouse_state_builder.dart';
import '../icons/icons.dart';
import '../app_window.dart';
import 'package:flutter/foundation.dart' show kIsWeb;
import 'dart:io' show Platform;
typedef WindowButtonIconBuilder = Widget Function(
WindowButtonContext buttonContext);
typedef WindowButtonBuilder = Widget Function(
WindowButtonContext buttonContext, Widget icon);
class WindowButtonContext {
BuildContext context;
MouseState mouseState;
Color? backgroundColor;
Color iconColor;
WindowButtonContext(
{required this.context,
required this.mouseState,
this.backgroundColor,
required this.iconColor});
}
class WindowButtonColors {
late Color normal;
late Color mouseOver;
late Color mouseDown;
late Color iconNormal;
late Color iconMouseOver;
late Color iconMouseDown;
WindowButtonColors(
{Color? normal,
Color? mouseOver,
Color? mouseDown,
Color? iconNormal,
Color? iconMouseOver,
Color? iconMouseDown}) {
this.normal = normal ?? _defaultButtonColors.normal;
this.mouseOver = mouseOver ?? _defaultButtonColors.mouseOver;
this.mouseDown = mouseDown ?? _defaultButtonColors.mouseDown;
this.iconNormal = iconNormal ?? _defaultButtonColors.iconNormal;
this.iconMouseOver = iconMouseOver ?? _defaultButtonColors.iconMouseOver;
this.iconMouseDown = iconMouseDown ?? _defaultButtonColors.iconMouseDown;
}
}
final _defaultButtonColors = WindowButtonColors(
normal: Colors.transparent,
iconNormal: Color(0xFF805306),
mouseOver: Color(0xFF404040),
mouseDown: Color(0xFF202020),
iconMouseOver: Color(0xFFFFFFFF),
iconMouseDown: Color(0xFFF0F0F0));
class WindowButton extends StatelessWidget {
final WindowButtonBuilder? builder;
final WindowButtonIconBuilder? iconBuilder;
late final WindowButtonColors colors;
final bool animate;
final EdgeInsets? padding;
final VoidCallback? onPressed;
WindowButton(
{Key? key,
WindowButtonColors? colors,
this.builder,
@required this.iconBuilder,
this.padding,
this.onPressed,
this.animate = false})
: super(key: key) {
this.colors = colors ?? _defaultButtonColors;
}
Color getBackgroundColor(MouseState mouseState) {
if (mouseState.isMouseDown) return colors.mouseDown;
if (mouseState.isMouseOver) return colors.mouseOver;
return colors.normal;
}
Color getIconColor(MouseState mouseState) {
if (mouseState.isMouseDown) return colors.iconMouseDown;
if (mouseState.isMouseOver) return colors.iconMouseOver;
return colors.iconNormal;
}
@override
Widget build(BuildContext context) {
if (kIsWeb) {
return Container();
} else {
// Don't show button on macOS
if (Platform.isMacOS) {
return Container();
}
}
final buttonSize = appWindow.titleBarButtonSize;
return MouseStateBuilder(
builder: (context, mouseState) {
WindowButtonContext buttonContext = WindowButtonContext(
mouseState: mouseState,
context: context,
backgroundColor: getBackgroundColor(mouseState),
iconColor: getIconColor(mouseState));
var icon = (this.iconBuilder != null)
? this.iconBuilder!(buttonContext)
: Container();
double borderSize = appWindow.borderSize;
double defaultPadding =
(appWindow.titleBarHeight - borderSize) / 3 - (borderSize / 2);
// Used when buttonContext.backgroundColor is null, allowing the AnimatedContainer to fade-out smoothly.
var fadeOutColor =
getBackgroundColor(MouseState()..isMouseOver = true).withOpacity(0);
var padding = this.padding ?? EdgeInsets.zero;
var animationMs =
mouseState.isMouseOver ? (animate ? 100 : 0) : (animate ? 200 : 0);
Widget iconWithPadding = Padding(padding: padding, child: icon);
iconWithPadding = AnimatedContainer(
curve: Curves.easeOut,
duration: Duration(milliseconds: animationMs),
color: buttonContext.backgroundColor ?? fadeOutColor,
child: iconWithPadding);
var button = (this.builder != null)
? this.builder!(buttonContext, icon)
: iconWithPadding;
return SizedBox(
width: 48, height: 48, child: button);
},
onPressed: () {
if (this.onPressed != null) this.onPressed!();
},
);
}
}
class MinimizeWindowButton extends WindowButton {
MinimizeWindowButton(
{Key? key,
WindowButtonColors? colors,
VoidCallback? onPressed,
bool? animate})
: super(
key: key,
colors: colors,
animate: animate ?? false,
iconBuilder: (buttonContext) =>
MinimizeIcon(color: buttonContext.iconColor),
onPressed: onPressed ?? () => appWindow.minimize());
}
class MaximizeWindowButton extends WindowButton {
MaximizeWindowButton(
{Key? key,
WindowButtonColors? colors,
VoidCallback? onPressed,
bool? animate})
: super(
key: key,
colors: colors,
animate: animate ?? false,
iconBuilder: (buttonContext) =>
MaximizeIcon(color: buttonContext.iconColor),
onPressed: onPressed ?? () => appWindow.maximizeOrRestore());
}
class RestoreWindowButton extends WindowButton {
RestoreWindowButton(
{Key? key,
WindowButtonColors? colors,
VoidCallback? onPressed,
bool? animate})
: super(
key: key,
colors: colors,
animate: animate ?? false,
iconBuilder: (buttonContext) =>
RestoreIcon(color: buttonContext.iconColor),
onPressed: onPressed ?? () => appWindow.maximizeOrRestore());
}
final _defaultCloseButtonColors = WindowButtonColors(
mouseOver: Color(0xFFD32F2F),
mouseDown: Color(0xFFB71C1C),
iconNormal: Color(0xFF805306),
iconMouseOver: Color(0xFFFFFFFF));
class CloseWindowButton extends WindowButton {
CloseWindowButton(
{Key? key,
WindowButtonColors? colors,
VoidCallback? onPressed,
bool? animate})
: super(
key: key,
colors: colors ?? _defaultCloseButtonColors,
animate: animate ?? false,
iconBuilder: (buttonContext) =>
CloseIcon(color: buttonContext.iconColor),
onPressed: onPressed ?? () => appWindow.close());
}

View File

@@ -1,48 +0,0 @@
import 'package:flutter/widgets.dart';
import '../app_window.dart';
import 'package:flutter/foundation.dart' show kIsWeb;
class _MoveWindow extends StatelessWidget {
_MoveWindow({Key? key, this.child, this.onDoubleTap}) : super(key: key);
final Widget? child;
final VoidCallback? onDoubleTap;
@override
Widget build(BuildContext context) {
return GestureDetector(
behavior: HitTestBehavior.translucent,
onPanStart: (details) {
appWindow.startDragging();
},
onDoubleTap: this.onDoubleTap ?? () => appWindow.maximizeOrRestore(),
child: this.child ?? Container());
}
}
class MoveWindow extends StatelessWidget {
final Widget? child;
final VoidCallback? onDoubleTap;
MoveWindow({Key? key, this.child, this.onDoubleTap}) : super(key: key);
@override
Widget build(BuildContext context) {
if (child == null) return _MoveWindow(onDoubleTap: this.onDoubleTap);
return _MoveWindow(
onDoubleTap: this.onDoubleTap,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [Expanded(child: this.child!)]),
);
}
}
class WindowTitleBarBox extends StatelessWidget {
final Widget? child;
WindowTitleBarBox({Key? key, this.child}) : super(key: key);
@override
Widget build(BuildContext context) {
if (kIsWeb) {
return Container();
}
final titlebarHeight = appWindow.titleBarHeight;
return SizedBox(height: titlebarHeight, child: this.child ?? Container());
}
}

View File

@@ -1,31 +0,0 @@
name: bitsdojo_window
description: A package to help with creating custom windows with Flutter desktop (custom border, titlebar and minimize/maximize/close buttons) and common desktop window operations (show/hide/position on screen) for Windows and macOS
version: 0.1.5
homepage: https://www.bitsdojo.com
repository: https://github.com/bitsdojo/bitsdojo_window
environment:
sdk: ">=2.17.0 <3.0.0"
flutter: ">=1.20.0"
flutter:
plugin:
platforms:
windows:
default_package: bitsdojo_window_windows
macos:
default_package: bitsdojo_window_macos
linux:
default_package: bitsdojo_window_linux
dependencies:
flutter:
sdk: flutter
bitsdojo_window_platform_interface: ^0.1.2
#path: ../bitsdojo_window_platform_interface
bitsdojo_window_windows: ^0.1.5
#path: ../bitsdojo_window_windows
bitsdojo_window_macos: ^0.1.3
#path: ../bitsdojo_window_macos
bitsdojo_window_linux: ^0.1.3
#path: ../bitsdojo_window_linux