Merge pull request #1304 from Kingtous/flutter_desktop
feat: custom titlebar support & more window functions implementations
This commit is contained in:
commit
e02e88f0ee
@ -2,9 +2,9 @@ import 'dart:async';
|
|||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
|
|
||||||
// import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
// import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
import 'package:window_manager/window_manager.dart';
|
||||||
|
|
||||||
import '../../common.dart';
|
import '../../common.dart';
|
||||||
import '../../mobile/pages/home_page.dart';
|
import '../../mobile/pages/home_page.dart';
|
||||||
@ -143,8 +143,15 @@ class ConnectionManager extends StatelessWidget {
|
|||||||
// serverModel.clients[0] = Client(
|
// serverModel.clients[0] = Client(
|
||||||
// false, false, "Readmi-M21sdfsdf", "123123123", true, false, false);
|
// false, false, "Readmi-M21sdfsdf", "123123123", true, false, false);
|
||||||
return serverModel.clients.isEmpty
|
return serverModel.clients.isEmpty
|
||||||
? Center(
|
? Column(
|
||||||
|
children: [
|
||||||
|
buildTitleBar(Offstage()),
|
||||||
|
Expanded(
|
||||||
|
child: Center(
|
||||||
child: Text(translate("Waiting")),
|
child: Text(translate("Waiting")),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
)
|
)
|
||||||
: DefaultTabController(
|
: DefaultTabController(
|
||||||
length: serverModel.clients.length,
|
length: serverModel.clients.length,
|
||||||
@ -153,11 +160,11 @@ class ConnectionManager extends StatelessWidget {
|
|||||||
children: [
|
children: [
|
||||||
SizedBox(
|
SizedBox(
|
||||||
height: kTextTabBarHeight,
|
height: kTextTabBarHeight,
|
||||||
child: TabBar(
|
child: buildTitleBar(TabBar(
|
||||||
isScrollable: true,
|
isScrollable: true,
|
||||||
tabs: serverModel.clients.entries
|
tabs: serverModel.clients.entries
|
||||||
.map((entry) => buildTab(entry))
|
.map((entry) => buildTab(entry))
|
||||||
.toList(growable: false)),
|
.toList(growable: false))),
|
||||||
),
|
),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: TabBarView(
|
child: TabBarView(
|
||||||
@ -170,6 +177,25 @@ class ConnectionManager extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Widget buildTitleBar(Widget middle) {
|
||||||
|
return GestureDetector(
|
||||||
|
onPanDown: (d) {
|
||||||
|
windowManager.startDragging();
|
||||||
|
},
|
||||||
|
child: Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
_AppIcon(),
|
||||||
|
Expanded(child: middle),
|
||||||
|
const SizedBox(
|
||||||
|
width: 4.0,
|
||||||
|
),
|
||||||
|
_CloseButton()
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
Widget buildConnectionCard(MapEntry<int, Client> entry) {
|
Widget buildConnectionCard(MapEntry<int, Client> entry) {
|
||||||
final client = entry.value;
|
final client = entry.value;
|
||||||
return Column(
|
return Column(
|
||||||
@ -204,6 +230,40 @@ class ConnectionManager extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class _AppIcon extends StatelessWidget {
|
||||||
|
const _AppIcon({Key? key}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Container(
|
||||||
|
margin: EdgeInsets.symmetric(horizontal: 4.0),
|
||||||
|
child: Image.asset(
|
||||||
|
'assets/logo.ico',
|
||||||
|
width: 30,
|
||||||
|
height: 30,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _CloseButton extends StatelessWidget {
|
||||||
|
const _CloseButton({Key? key}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Ink(
|
||||||
|
child: InkWell(
|
||||||
|
onTap: () {
|
||||||
|
windowManager.close();
|
||||||
|
},
|
||||||
|
child: Icon(
|
||||||
|
Icons.close,
|
||||||
|
size: 30,
|
||||||
|
)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class _CmHeader extends StatefulWidget {
|
class _CmHeader extends StatefulWidget {
|
||||||
final Client client;
|
final Client client;
|
||||||
|
|
||||||
|
@ -1,10 +1,13 @@
|
|||||||
import 'dart:math';
|
import 'dart:math';
|
||||||
|
|
||||||
|
import 'package:desktop_multi_window/desktop_multi_window.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_hbb/common.dart';
|
import 'package:flutter_hbb/common.dart';
|
||||||
import 'package:flutter_hbb/consts.dart';
|
import 'package:flutter_hbb/consts.dart';
|
||||||
|
import 'package:flutter_hbb/main.dart';
|
||||||
import 'package:flutter_hbb/utils/multi_window_manager.dart';
|
import 'package:flutter_hbb/utils/multi_window_manager.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
|
import 'package:window_manager/window_manager.dart';
|
||||||
|
|
||||||
const double _kTabBarHeight = kDesktopRemoteTabBarHeight;
|
const double _kTabBarHeight = kDesktopRemoteTabBarHeight;
|
||||||
const double _kIconSize = 18;
|
const double _kIconSize = 18;
|
||||||
@ -76,7 +79,16 @@ class DesktopTabBar extends StatelessWidget {
|
|||||||
Text("RustDesk").paddingOnly(left: 5),
|
Text("RustDesk").paddingOnly(left: 5),
|
||||||
]).paddingSymmetric(horizontal: 12, vertical: 5),
|
]).paddingSymmetric(horizontal: 12, vertical: 5),
|
||||||
),
|
),
|
||||||
Flexible(
|
Expanded(
|
||||||
|
child: GestureDetector(
|
||||||
|
onPanStart: (_) {
|
||||||
|
if (mainTab) {
|
||||||
|
windowManager.startDragging();
|
||||||
|
} else {
|
||||||
|
WindowController.fromWindowId(windowId!)
|
||||||
|
.startDragging();
|
||||||
|
}
|
||||||
|
},
|
||||||
child: Obx(() => TabBar(
|
child: Obx(() => TabBar(
|
||||||
key: tabBarKey,
|
key: tabBarKey,
|
||||||
indicatorColor: _theme.indicatorColor,
|
indicatorColor: _theme.indicatorColor,
|
||||||
@ -113,6 +125,7 @@ class DesktopTabBar extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
}).toList())),
|
}).toList())),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
Offstage(
|
Offstage(
|
||||||
offstage: mainTab,
|
offstage: mainTab,
|
||||||
child: _AddButton(
|
child: _AddButton(
|
||||||
@ -134,6 +147,10 @@ class DesktopTabBar extends StatelessWidget {
|
|||||||
onTap: () => onAddSetting?.call(),
|
onTap: () => onAddSetting?.call(),
|
||||||
).paddingOnly(right: 10),
|
).paddingOnly(right: 10),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
|
WindowActionPanel(
|
||||||
|
mainTab: mainTab,
|
||||||
|
color: _theme.unSelectedIconColor,
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@ -169,6 +186,85 @@ class DesktopTabBar extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class WindowActionPanel extends StatelessWidget {
|
||||||
|
final bool mainTab;
|
||||||
|
final Color color;
|
||||||
|
|
||||||
|
const WindowActionPanel(
|
||||||
|
{Key? key, required this.mainTab, required this.color})
|
||||||
|
: super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Row(
|
||||||
|
children: [
|
||||||
|
Tooltip(
|
||||||
|
message: translate("Minimize"),
|
||||||
|
child: InkWell(
|
||||||
|
child: Icon(
|
||||||
|
Icons.minimize,
|
||||||
|
color: color,
|
||||||
|
).paddingSymmetric(horizontal: 5),
|
||||||
|
onTap: () {
|
||||||
|
if (mainTab) {
|
||||||
|
windowManager.minimize();
|
||||||
|
} else {
|
||||||
|
WindowController.fromWindowId(windowId!).minimize();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Tooltip(
|
||||||
|
message: translate("Maximize"),
|
||||||
|
child: InkWell(
|
||||||
|
child: Icon(
|
||||||
|
Icons.rectangle_outlined,
|
||||||
|
color: color,
|
||||||
|
size: 20,
|
||||||
|
).paddingSymmetric(horizontal: 5),
|
||||||
|
onTap: () {
|
||||||
|
if (mainTab) {
|
||||||
|
windowManager.isMaximized().then((maximized) {
|
||||||
|
if (maximized) {
|
||||||
|
windowManager.unmaximize();
|
||||||
|
} else {
|
||||||
|
windowManager.maximize();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
final wc = WindowController.fromWindowId(windowId!);
|
||||||
|
wc.isMaximized().then((maximized) {
|
||||||
|
if (maximized) {
|
||||||
|
wc.unmaximize();
|
||||||
|
} else {
|
||||||
|
wc.maximize();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Tooltip(
|
||||||
|
message: translate("Close"),
|
||||||
|
child: InkWell(
|
||||||
|
child: Icon(
|
||||||
|
Icons.close,
|
||||||
|
color: color,
|
||||||
|
).paddingSymmetric(horizontal: 5),
|
||||||
|
onTap: () {
|
||||||
|
if (mainTab) {
|
||||||
|
windowManager.close();
|
||||||
|
} else {
|
||||||
|
WindowController.fromWindowId(windowId!).close();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class _Tab extends StatelessWidget {
|
class _Tab extends StatelessWidget {
|
||||||
late final int index;
|
late final int index;
|
||||||
late final String label;
|
late final String label;
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
|
||||||
|
import 'package:desktop_multi_window/desktop_multi_window.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_hbb/desktop/pages/desktop_tab_page.dart';
|
import 'package:flutter_hbb/desktop/pages/desktop_tab_page.dart';
|
||||||
import 'package:flutter_hbb/desktop/pages/server_page.dart';
|
import 'package:flutter_hbb/desktop/pages/server_page.dart';
|
||||||
@ -32,6 +33,7 @@ Future<Null> main(List<String> args) async {
|
|||||||
// main window
|
// main window
|
||||||
if (args.isNotEmpty && args.first == 'multi_window') {
|
if (args.isNotEmpty && args.first == 'multi_window') {
|
||||||
windowId = int.parse(args[1]);
|
windowId = int.parse(args[1]);
|
||||||
|
WindowController.fromWindowId(windowId!).showTitleBar(false);
|
||||||
final argument = args[2].isEmpty
|
final argument = args[2].isEmpty
|
||||||
? Map<String, dynamic>()
|
? Map<String, dynamic>()
|
||||||
: jsonDecode(args[2]) as Map<String, dynamic>;
|
: jsonDecode(args[2]) as Map<String, dynamic>;
|
||||||
@ -77,7 +79,14 @@ Future<void> initEnv(String appType) async {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void runMainApp(bool startService) async {
|
void runMainApp(bool startService) async {
|
||||||
await initEnv(kAppTypeMain);
|
WindowOptions windowOptions = getHiddenTitleBarWindowOptions(Size(1280, 720));
|
||||||
|
await Future.wait([
|
||||||
|
initEnv(kAppTypeMain),
|
||||||
|
windowManager.waitUntilReadyToShow(windowOptions, () async {
|
||||||
|
await windowManager.show();
|
||||||
|
await windowManager.focus();
|
||||||
|
})
|
||||||
|
]);
|
||||||
if (startService) {
|
if (startService) {
|
||||||
// await windowManager.ensureInitialized();
|
// await windowManager.ensureInitialized();
|
||||||
// disable tray
|
// disable tray
|
||||||
@ -118,13 +127,7 @@ void runFileTransferScreen(Map<String, dynamic> argument) async {
|
|||||||
|
|
||||||
void runConnectionManagerScreen() async {
|
void runConnectionManagerScreen() async {
|
||||||
// initialize window
|
// initialize window
|
||||||
WindowOptions windowOptions = WindowOptions(
|
WindowOptions windowOptions = getHiddenTitleBarWindowOptions(Size(300, 400));
|
||||||
size: Size(300, 400),
|
|
||||||
center: true,
|
|
||||||
backgroundColor: Colors.transparent,
|
|
||||||
skipTaskbar: false,
|
|
||||||
titleBarStyle: TitleBarStyle.normal,
|
|
||||||
);
|
|
||||||
await Future.wait([
|
await Future.wait([
|
||||||
initEnv(kAppTypeConnectionManager),
|
initEnv(kAppTypeConnectionManager),
|
||||||
windowManager.waitUntilReadyToShow(windowOptions, () async {
|
windowManager.waitUntilReadyToShow(windowOptions, () async {
|
||||||
@ -133,8 +136,20 @@ void runConnectionManagerScreen() async {
|
|||||||
await windowManager.focus();
|
await windowManager.focus();
|
||||||
})
|
})
|
||||||
]);
|
]);
|
||||||
;
|
runApp(GetMaterialApp(
|
||||||
runApp(GetMaterialApp(theme: getCurrentTheme(), home: DesktopServerPage()));
|
debugShowCheckedModeBanner: false,
|
||||||
|
theme: getCurrentTheme(),
|
||||||
|
home: DesktopServerPage()));
|
||||||
|
}
|
||||||
|
|
||||||
|
WindowOptions getHiddenTitleBarWindowOptions(Size size) {
|
||||||
|
return WindowOptions(
|
||||||
|
size: size,
|
||||||
|
center: true,
|
||||||
|
backgroundColor: Colors.transparent,
|
||||||
|
skipTaskbar: false,
|
||||||
|
titleBarStyle: TitleBarStyle.hidden,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
class App extends StatelessWidget {
|
class App extends StatelessWidget {
|
||||||
|
@ -250,8 +250,8 @@ packages:
|
|||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
path: "."
|
path: "."
|
||||||
ref: "2b1176d53f195cc55e8d37151bb3d9f6bd52fad3"
|
ref: bf670217de03f4866177a9793284f4db99271c51
|
||||||
resolved-ref: "2b1176d53f195cc55e8d37151bb3d9f6bd52fad3"
|
resolved-ref: bf670217de03f4866177a9793284f4db99271c51
|
||||||
url: "https://github.com/Kingtous/rustdesk_desktop_multi_window"
|
url: "https://github.com/Kingtous/rustdesk_desktop_multi_window"
|
||||||
source: git
|
source: git
|
||||||
version: "0.1.0"
|
version: "0.1.0"
|
||||||
|
@ -63,11 +63,15 @@ dependencies:
|
|||||||
url: https://github.com/Kingtous/rustdesk_window_manager
|
url: https://github.com/Kingtous/rustdesk_window_manager
|
||||||
ref: 028a7f6
|
ref: 028a7f6
|
||||||
desktop_multi_window:
|
desktop_multi_window:
|
||||||
|
# path: ../../rustdesk_desktop_multi_window
|
||||||
git:
|
git:
|
||||||
url: https://github.com/Kingtous/rustdesk_desktop_multi_window
|
url: https://github.com/Kingtous/rustdesk_desktop_multi_window
|
||||||
ref: 2b1176d53f195cc55e8d37151bb3d9f6bd52fad3
|
ref: bf670217de03f4866177a9793284f4db99271c51
|
||||||
freezed_annotation: ^2.0.3
|
freezed_annotation: ^2.0.3
|
||||||
tray_manager: 0.1.7
|
tray_manager:
|
||||||
|
git:
|
||||||
|
url: https://github.com/Kingtous/rustdesk_tray_manager
|
||||||
|
ref: 3aa37c86e47ea748e7b5507cbe59f2c54ebdb23a
|
||||||
get: ^4.6.5
|
get: ^4.6.5
|
||||||
visibility_detector: ^0.3.3
|
visibility_detector: ^0.3.3
|
||||||
contextmenu: ^3.0.0
|
contextmenu: ^3.0.0
|
||||||
|
Loading…
x
Reference in New Issue
Block a user