mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
feat: frameless window for mac
This commit is contained in:
parent
ef0d59ff30
commit
c4db17f73c
67
frontend/app_flowy/lib/core/frameless_window.dart
Normal file
67
frontend/app_flowy/lib/core/frameless_window.dart
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
import 'package:flutter/services.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'dart:io' show Platform;
|
||||||
|
|
||||||
|
class CocoaWindowChannel {
|
||||||
|
CocoaWindowChannel._();
|
||||||
|
|
||||||
|
final MethodChannel _channel = const MethodChannel("flutter/cocoaWindow");
|
||||||
|
|
||||||
|
static final CocoaWindowChannel instance = CocoaWindowChannel._();
|
||||||
|
|
||||||
|
Future<void> setWindowPosition(Offset offset) async {
|
||||||
|
await _channel.invokeMethod("setWindowPosition", [offset.dx, offset.dy]);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<List<double>> getWindowPosition() async {
|
||||||
|
final raw = await _channel.invokeMethod("getWindowPosition");
|
||||||
|
final arr = raw as List<dynamic>;
|
||||||
|
final List<double> result = arr.map((s) => s as double).toList();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> zoom() async {
|
||||||
|
await _channel.invokeMethod("zoom");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class MoveWindowDetector extends StatefulWidget {
|
||||||
|
const MoveWindowDetector({Key? key, this.child}) : super(key: key);
|
||||||
|
|
||||||
|
final Widget? child;
|
||||||
|
|
||||||
|
@override
|
||||||
|
_MoveWindowDetectorState createState() => _MoveWindowDetectorState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _MoveWindowDetectorState extends State<MoveWindowDetector> {
|
||||||
|
double winX = 0;
|
||||||
|
double winY = 0;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
if (!Platform.isMacOS) {
|
||||||
|
return widget.child ?? Container();
|
||||||
|
}
|
||||||
|
return GestureDetector(
|
||||||
|
// https://stackoverflow.com/questions/52965799/flutter-gesturedetector-not-working-with-containers-in-stack
|
||||||
|
behavior: HitTestBehavior.translucent,
|
||||||
|
onDoubleTap: () async {
|
||||||
|
await CocoaWindowChannel.instance.zoom();
|
||||||
|
},
|
||||||
|
onPanStart: (DragStartDetails details) {
|
||||||
|
winX = details.globalPosition.dx;
|
||||||
|
winY = details.globalPosition.dy;
|
||||||
|
},
|
||||||
|
onPanUpdate: (DragUpdateDetails details) async {
|
||||||
|
final windowPos = await CocoaWindowChannel.instance.getWindowPosition();
|
||||||
|
final double dx = windowPos[0];
|
||||||
|
final double dy = windowPos[1];
|
||||||
|
final deltaX = details.globalPosition.dx - winX;
|
||||||
|
final deltaY = details.globalPosition.dy - winY;
|
||||||
|
await CocoaWindowChannel.instance.setWindowPosition(Offset(dx + deltaX, dy - deltaY));
|
||||||
|
},
|
||||||
|
child: widget.child,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -49,6 +49,9 @@ class HomeBloc extends Bloc<HomeEvent, HomeState> {
|
|||||||
unauthorized: (_Unauthorized value) {
|
unauthorized: (_Unauthorized value) {
|
||||||
emit(state.copyWith(unauthorized: true));
|
emit(state.copyWith(unauthorized: true));
|
||||||
},
|
},
|
||||||
|
collapseMenu: (e) {
|
||||||
|
emit(state.copyWith(isMenuCollapsed: !state.isMenuCollapsed));
|
||||||
|
},
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -77,6 +80,7 @@ class HomeEvent with _$HomeEvent {
|
|||||||
const factory HomeEvent.dismissEditPannel() = _DismissEditPannel;
|
const factory HomeEvent.dismissEditPannel() = _DismissEditPannel;
|
||||||
const factory HomeEvent.didReceiveWorkspaceSetting(CurrentWorkspaceSetting setting) = _DidReceiveWorkspaceSetting;
|
const factory HomeEvent.didReceiveWorkspaceSetting(CurrentWorkspaceSetting setting) = _DidReceiveWorkspaceSetting;
|
||||||
const factory HomeEvent.unauthorized(String msg) = _Unauthorized;
|
const factory HomeEvent.unauthorized(String msg) = _Unauthorized;
|
||||||
|
const factory HomeEvent.collapseMenu() = _CollapseMenu;
|
||||||
}
|
}
|
||||||
|
|
||||||
@freezed
|
@freezed
|
||||||
@ -87,6 +91,7 @@ class HomeState with _$HomeState {
|
|||||||
required Option<EditPannelContext> pannelContext,
|
required Option<EditPannelContext> pannelContext,
|
||||||
required CurrentWorkspaceSetting workspaceSetting,
|
required CurrentWorkspaceSetting workspaceSetting,
|
||||||
required bool unauthorized,
|
required bool unauthorized,
|
||||||
|
required bool isMenuCollapsed,
|
||||||
}) = _HomeState;
|
}) = _HomeState;
|
||||||
|
|
||||||
factory HomeState.initial(CurrentWorkspaceSetting workspaceSetting) => HomeState(
|
factory HomeState.initial(CurrentWorkspaceSetting workspaceSetting) => HomeState(
|
||||||
@ -95,5 +100,6 @@ class HomeState with _$HomeState {
|
|||||||
pannelContext: none(),
|
pannelContext: none(),
|
||||||
workspaceSetting: workspaceSetting,
|
workspaceSetting: workspaceSetting,
|
||||||
unauthorized: false,
|
unauthorized: false,
|
||||||
|
isMenuCollapsed: false,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -25,10 +25,6 @@ class MenuBloc extends Bloc<MenuEvent, MenuState> {
|
|||||||
listener.start(addAppCallback: _handleAppsOrFail);
|
listener.start(addAppCallback: _handleAppsOrFail);
|
||||||
await _fetchApps(emit);
|
await _fetchApps(emit);
|
||||||
},
|
},
|
||||||
collapse: (e) async {
|
|
||||||
final isCollapse = state.isCollapse;
|
|
||||||
emit(state.copyWith(isCollapse: !isCollapse));
|
|
||||||
},
|
|
||||||
openPage: (e) async {
|
openPage: (e) async {
|
||||||
emit(state.copyWith(plugin: e.plugin));
|
emit(state.copyWith(plugin: e.plugin));
|
||||||
},
|
},
|
||||||
@ -94,7 +90,6 @@ class MenuBloc extends Bloc<MenuEvent, MenuState> {
|
|||||||
@freezed
|
@freezed
|
||||||
class MenuEvent with _$MenuEvent {
|
class MenuEvent with _$MenuEvent {
|
||||||
const factory MenuEvent.initial() = _Initial;
|
const factory MenuEvent.initial() = _Initial;
|
||||||
const factory MenuEvent.collapse() = _Collapse;
|
|
||||||
const factory MenuEvent.openPage(Plugin plugin) = _OpenPage;
|
const factory MenuEvent.openPage(Plugin plugin) = _OpenPage;
|
||||||
const factory MenuEvent.createApp(String name, {String? desc}) = _CreateApp;
|
const factory MenuEvent.createApp(String name, {String? desc}) = _CreateApp;
|
||||||
const factory MenuEvent.moveApp(int fromIndex, int toIndex) = _MoveApp;
|
const factory MenuEvent.moveApp(int fromIndex, int toIndex) = _MoveApp;
|
||||||
@ -104,14 +99,12 @@ class MenuEvent with _$MenuEvent {
|
|||||||
@freezed
|
@freezed
|
||||||
class MenuState with _$MenuState {
|
class MenuState with _$MenuState {
|
||||||
const factory MenuState({
|
const factory MenuState({
|
||||||
required bool isCollapse,
|
|
||||||
required List<App> apps,
|
required List<App> apps,
|
||||||
required Either<Unit, FlowyError> successOrFailure,
|
required Either<Unit, FlowyError> successOrFailure,
|
||||||
required Plugin plugin,
|
required Plugin plugin,
|
||||||
}) = _MenuState;
|
}) = _MenuState;
|
||||||
|
|
||||||
factory MenuState.initial() => MenuState(
|
factory MenuState.initial() => MenuState(
|
||||||
isCollapse: false,
|
|
||||||
apps: [],
|
apps: [],
|
||||||
successOrFailure: left(unit),
|
successOrFailure: left(unit),
|
||||||
plugin: makePlugin(pluginType: DefaultPlugin.blank.type()),
|
plugin: makePlugin(pluginType: DefaultPlugin.blank.type()),
|
||||||
|
@ -1,8 +1,12 @@
|
|||||||
|
import 'dart:io' show Platform;
|
||||||
|
|
||||||
import 'package:app_flowy/startup/startup.dart';
|
import 'package:app_flowy/startup/startup.dart';
|
||||||
|
import 'package:app_flowy/workspace/application/home/home_bloc.dart';
|
||||||
import 'package:app_flowy/workspace/presentation/home/home_screen.dart';
|
import 'package:app_flowy/workspace/presentation/home/home_screen.dart';
|
||||||
import 'package:flowy_infra/theme.dart';
|
import 'package:flowy_infra/theme.dart';
|
||||||
import 'package:flowy_sdk/log.dart';
|
import 'package:flowy_sdk/log.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
import 'package:time/time.dart';
|
import 'package:time/time.dart';
|
||||||
import 'package:fluttertoast/fluttertoast.dart';
|
import 'package:fluttertoast/fluttertoast.dart';
|
||||||
@ -11,6 +15,7 @@ import 'package:app_flowy/plugin/plugin.dart';
|
|||||||
import 'package:app_flowy/workspace/presentation/plugins/blank/blank.dart';
|
import 'package:app_flowy/workspace/presentation/plugins/blank/blank.dart';
|
||||||
import 'package:app_flowy/workspace/presentation/home/home_sizes.dart';
|
import 'package:app_flowy/workspace/presentation/home/home_sizes.dart';
|
||||||
import 'package:app_flowy/workspace/presentation/home/navigation.dart';
|
import 'package:app_flowy/workspace/presentation/home/navigation.dart';
|
||||||
|
import 'package:app_flowy/core/frameless_window.dart';
|
||||||
import 'package:flowy_infra_ui/widget/spacing.dart';
|
import 'package:flowy_infra_ui/widget/spacing.dart';
|
||||||
import 'package:flowy_infra_ui/style_widget/extension.dart';
|
import 'package:flowy_infra_ui/style_widget/extension.dart';
|
||||||
import 'package:flowy_infra/notifier.dart';
|
import 'package:flowy_infra/notifier.dart';
|
||||||
@ -152,7 +157,7 @@ class HomeStackManager {
|
|||||||
child: Selector<HomeStackNotifier, Widget>(
|
child: Selector<HomeStackNotifier, Widget>(
|
||||||
selector: (context, notifier) => notifier.titleWidget,
|
selector: (context, notifier) => notifier.titleWidget,
|
||||||
builder: (context, widget, child) {
|
builder: (context, widget, child) {
|
||||||
return const HomeTopBar();
|
return const MoveWindowDetector(child: HomeTopBar());
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -191,6 +196,14 @@ class HomeTopBar extends StatelessWidget {
|
|||||||
child: Row(
|
child: Row(
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
|
BlocBuilder<HomeBloc, HomeState>(
|
||||||
|
buildWhen: ((previous, current) => previous.isMenuCollapsed != current.isMenuCollapsed),
|
||||||
|
builder: (context, state) {
|
||||||
|
if (state.isMenuCollapsed && Platform.isMacOS) {
|
||||||
|
return const HSpace(80);
|
||||||
|
}
|
||||||
|
return const HSpace(0);
|
||||||
|
}),
|
||||||
const FlowyNavigation(),
|
const FlowyNavigation(),
|
||||||
const HSpace(16),
|
const HSpace(16),
|
||||||
ChangeNotifierProvider.value(
|
ChangeNotifierProvider.value(
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
export './app/header/header.dart';
|
export './app/header/header.dart';
|
||||||
export './app/menu_app.dart';
|
export './app/menu_app.dart';
|
||||||
|
|
||||||
|
import 'dart:io' show Platform;
|
||||||
|
import 'package:app_flowy/workspace/presentation/home/home_sizes.dart';
|
||||||
import 'package:app_flowy/workspace/presentation/home/home_stack.dart';
|
import 'package:app_flowy/workspace/presentation/home/home_stack.dart';
|
||||||
import 'package:app_flowy/workspace/presentation/plugins/trash/menu.dart';
|
import 'package:app_flowy/workspace/presentation/plugins/trash/menu.dart';
|
||||||
import 'package:flowy_infra/notifier.dart';
|
import 'package:flowy_infra/notifier.dart';
|
||||||
@ -18,7 +20,9 @@ import 'package:expandable/expandable.dart';
|
|||||||
import 'package:flowy_infra/time/duration.dart';
|
import 'package:flowy_infra/time/duration.dart';
|
||||||
import 'package:app_flowy/startup/startup.dart';
|
import 'package:app_flowy/startup/startup.dart';
|
||||||
import 'package:app_flowy/workspace/application/menu/menu_bloc.dart';
|
import 'package:app_flowy/workspace/application/menu/menu_bloc.dart';
|
||||||
import 'package:app_flowy/workspace/presentation/home/home_sizes.dart';
|
import 'package:app_flowy/workspace/application/home/home_bloc.dart';
|
||||||
|
import 'package:app_flowy/core/frameless_window.dart';
|
||||||
|
// import 'package:app_flowy/workspace/presentation/home/home_sizes.dart';
|
||||||
import 'package:flowy_infra/image.dart';
|
import 'package:flowy_infra/image.dart';
|
||||||
import 'package:flowy_infra_ui/style_widget/icon_button.dart';
|
import 'package:flowy_infra_ui/style_widget/icon_button.dart';
|
||||||
|
|
||||||
@ -59,10 +63,10 @@ class HomeMenu extends StatelessWidget {
|
|||||||
getIt<HomeStackManager>().setPlugin(state.plugin);
|
getIt<HomeStackManager>().setPlugin(state.plugin);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
BlocListener<MenuBloc, MenuState>(
|
BlocListener<HomeBloc, HomeState>(
|
||||||
listenWhen: (p, c) => p.isCollapse != c.isCollapse,
|
listenWhen: (p, c) => p.isMenuCollapsed != c.isMenuCollapsed,
|
||||||
listener: (context, state) {
|
listener: (context, state) {
|
||||||
_collapsedNotifier.value = state.isCollapse;
|
_collapsedNotifier.value = state.isMenuCollapsed;
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
@ -179,6 +183,17 @@ class MenuSharedState {
|
|||||||
|
|
||||||
class MenuTopBar extends StatelessWidget {
|
class MenuTopBar extends StatelessWidget {
|
||||||
const MenuTopBar({Key? key}) : super(key: key);
|
const MenuTopBar({Key? key}) : super(key: key);
|
||||||
|
|
||||||
|
Widget renderIcon(BuildContext context) {
|
||||||
|
if (Platform.isMacOS) {
|
||||||
|
return Container();
|
||||||
|
}
|
||||||
|
final theme = context.watch<AppTheme>();
|
||||||
|
return (theme.isDark
|
||||||
|
? svgWithSize("flowy_logo_dark_mode", const Size(92, 17))
|
||||||
|
: svgWithSize("flowy_logo_with_text", const Size(92, 17)));
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final theme = context.watch<AppTheme>();
|
final theme = context.watch<AppTheme>();
|
||||||
@ -186,20 +201,19 @@ class MenuTopBar extends StatelessWidget {
|
|||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
return SizedBox(
|
return SizedBox(
|
||||||
height: HomeSizes.topBarHeight,
|
height: HomeSizes.topBarHeight,
|
||||||
|
child: MoveWindowDetector(
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
(theme.isDark
|
renderIcon(context),
|
||||||
? svgWithSize("flowy_logo_dark_mode", const Size(92, 17))
|
|
||||||
: svgWithSize("flowy_logo_with_text", const Size(92, 17))),
|
|
||||||
const Spacer(),
|
const Spacer(),
|
||||||
FlowyIconButton(
|
FlowyIconButton(
|
||||||
width: 28,
|
width: 28,
|
||||||
onPressed: () => context.read<MenuBloc>().add(const MenuEvent.collapse()),
|
onPressed: () => context.read<HomeBloc>().add(const HomeEvent.collapseMenu()),
|
||||||
iconPadding: const EdgeInsets.fromLTRB(4, 4, 4, 4),
|
iconPadding: const EdgeInsets.fromLTRB(4, 4, 4, 4),
|
||||||
icon: svgWidget("home/hide_menu", color: theme.iconColor),
|
icon: svgWidget("home/hide_menu", color: theme.iconColor),
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
),
|
)),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import 'package:app_flowy/workspace/application/home/home_bloc.dart';
|
||||||
import 'package:app_flowy/workspace/presentation/home/home_stack.dart';
|
import 'package:app_flowy/workspace/presentation/home/home_stack.dart';
|
||||||
import 'package:flowy_infra/image.dart';
|
import 'package:flowy_infra/image.dart';
|
||||||
import 'package:flowy_infra/notifier.dart';
|
import 'package:flowy_infra/notifier.dart';
|
||||||
@ -95,6 +96,7 @@ class FlowyNavigation extends StatelessWidget {
|
|||||||
width: 24,
|
width: 24,
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
notifier.value = false;
|
notifier.value = false;
|
||||||
|
ctx.read<HomeBloc>().add(const HomeEvent.collapseMenu());
|
||||||
},
|
},
|
||||||
iconPadding: const EdgeInsets.fromLTRB(2, 2, 2, 2),
|
iconPadding: const EdgeInsets.fromLTRB(2, 2, 2, 2),
|
||||||
icon: svgWidget("home/hide_menu", color: theme.iconColor),
|
icon: svgWidget("home/hide_menu", color: theme.iconColor),
|
||||||
|
@ -1,12 +1,82 @@
|
|||||||
import Cocoa
|
import Cocoa
|
||||||
import FlutterMacOS
|
import FlutterMacOS
|
||||||
|
|
||||||
|
private let kTrafficLightOffetTop = 22
|
||||||
|
|
||||||
class MainFlutterWindow: NSWindow {
|
class MainFlutterWindow: NSWindow {
|
||||||
|
func registerMethodChannel(flutterViewController: FlutterViewController) {
|
||||||
|
let cocoaWindowChannel = FlutterMethodChannel(name: "flutter/cocoaWindow", binaryMessenger: flutterViewController.engine.binaryMessenger)
|
||||||
|
cocoaWindowChannel.setMethodCallHandler({
|
||||||
|
(call: FlutterMethodCall, result: FlutterResult) -> Void in
|
||||||
|
if call.method == "setWindowPosition" {
|
||||||
|
guard let position = call.arguments as? NSArray else {
|
||||||
|
result(nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let nX = position[0] as! NSNumber
|
||||||
|
let nY = position[1] as! NSNumber
|
||||||
|
let x = nX.doubleValue
|
||||||
|
let y = nY.doubleValue
|
||||||
|
|
||||||
|
self.setFrameOrigin(NSPoint(x: x, y: y))
|
||||||
|
result(nil)
|
||||||
|
return
|
||||||
|
} else if call.method == "getWindowPosition" {
|
||||||
|
let frame = self.frame
|
||||||
|
result([frame.origin.x, frame.origin.y])
|
||||||
|
return
|
||||||
|
} else if call.method == "zoom" {
|
||||||
|
self.zoom(self)
|
||||||
|
result(nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
result(FlutterMethodNotImplemented)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func layoutTrafficLightButton(titlebarView: NSView, button: NSButton, offsetTop: CGFloat, offsetLeft: CGFloat) {
|
||||||
|
button.translatesAutoresizingMaskIntoConstraints = false;
|
||||||
|
titlebarView.addConstraint(NSLayoutConstraint.init(
|
||||||
|
item: button,
|
||||||
|
attribute: NSLayoutConstraint.Attribute.top, relatedBy: NSLayoutConstraint.Relation.equal, toItem: titlebarView, attribute: NSLayoutConstraint.Attribute.top, multiplier: 1, constant: offsetTop))
|
||||||
|
titlebarView.addConstraint(NSLayoutConstraint.init(
|
||||||
|
item: button,
|
||||||
|
attribute: NSLayoutConstraint.Attribute.left, relatedBy: NSLayoutConstraint.Relation.equal, toItem: titlebarView, attribute: NSLayoutConstraint.Attribute.left, multiplier: 1, constant: offsetLeft))
|
||||||
|
}
|
||||||
|
|
||||||
|
func layoutTrafficLights() {
|
||||||
|
let closeButton = self.standardWindowButton(ButtonType.closeButton)!
|
||||||
|
let minButton = self.standardWindowButton(ButtonType.miniaturizeButton)!
|
||||||
|
let zoomButton = self.standardWindowButton(ButtonType.zoomButton)!
|
||||||
|
let titlebarView = closeButton.superview!
|
||||||
|
|
||||||
|
self.layoutTrafficLightButton(titlebarView: titlebarView, button: closeButton, offsetTop: CGFloat(kTrafficLightOffetTop), offsetLeft: 20)
|
||||||
|
self.layoutTrafficLightButton(titlebarView: titlebarView, button: minButton, offsetTop: CGFloat(kTrafficLightOffetTop), offsetLeft: 38)
|
||||||
|
self.layoutTrafficLightButton(titlebarView: titlebarView, button: zoomButton, offsetTop: CGFloat(kTrafficLightOffetTop), offsetLeft: 56)
|
||||||
|
|
||||||
|
let customToolbar = NSTitlebarAccessoryViewController()
|
||||||
|
let newView = NSView()
|
||||||
|
newView.frame = NSRect(origin: CGPoint(), size: CGSize(width: 0, height: 40)) // only the height is cared
|
||||||
|
customToolbar.view = newView
|
||||||
|
self.addTitlebarAccessoryViewController(customToolbar)
|
||||||
|
}
|
||||||
|
|
||||||
override func awakeFromNib() {
|
override func awakeFromNib() {
|
||||||
let flutterViewController = FlutterViewController.init()
|
let flutterViewController = FlutterViewController.init()
|
||||||
let windowFrame = self.frame
|
let windowFrame = self.frame
|
||||||
self.contentViewController = flutterViewController
|
self.contentViewController = flutterViewController
|
||||||
|
|
||||||
|
self.registerMethodChannel(flutterViewController: flutterViewController)
|
||||||
|
|
||||||
self.setFrame(windowFrame, display: true)
|
self.setFrame(windowFrame, display: true)
|
||||||
|
self.titlebarAppearsTransparent = true
|
||||||
|
self.titleVisibility = .hidden
|
||||||
|
self.styleMask.insert(StyleMask.fullSizeContentView)
|
||||||
|
self.isMovableByWindowBackground = true
|
||||||
|
self.isMovable = false
|
||||||
|
|
||||||
|
self.layoutTrafficLights()
|
||||||
|
|
||||||
RegisterGeneratedPlugins(registry: flutterViewController)
|
RegisterGeneratedPlugins(registry: flutterViewController)
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user