Merge pull request #1304 from Kingtous/flutter_desktop

feat: custom titlebar support & more window functions implementations
This commit is contained in:
RustDesk 2022-08-18 17:39:26 +08:00 committed by GitHub
commit e02e88f0ee
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 238 additions and 63 deletions

View File

@ -2,9 +2,9 @@ import 'dart:async';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
// import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:provider/provider.dart';
import 'package:window_manager/window_manager.dart';
import '../../common.dart';
import '../../mobile/pages/home_page.dart';
@ -143,8 +143,15 @@ class ConnectionManager extends StatelessWidget {
// serverModel.clients[0] = Client(
// false, false, "Readmi-M21sdfsdf", "123123123", true, false, false);
return serverModel.clients.isEmpty
? Center(
child: Text(translate("Waiting")),
? Column(
children: [
buildTitleBar(Offstage()),
Expanded(
child: Center(
child: Text(translate("Waiting")),
),
),
],
)
: DefaultTabController(
length: serverModel.clients.length,
@ -153,18 +160,37 @@ class ConnectionManager extends StatelessWidget {
children: [
SizedBox(
height: kTextTabBarHeight,
child: TabBar(
isScrollable: true,
tabs: serverModel.clients.entries
.map((entry) => buildTab(entry))
.toList(growable: false)),
child: buildTitleBar(TabBar(
isScrollable: true,
tabs: serverModel.clients.entries
.map((entry) => buildTab(entry))
.toList(growable: false))),
),
Expanded(
child: TabBarView(
children: serverModel.clients.entries
.map((entry) => buildConnectionCard(entry))
.toList(growable: false)),
)
],
),
);
}
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,
),
Expanded(
child: TabBarView(
children: serverModel.clients.entries
.map((entry) => buildConnectionCard(entry))
.toList(growable: false)),
)
_CloseButton()
],
),
);
@ -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 {
final Client client;

View File

@ -1,10 +1,13 @@
import 'dart:math';
import 'package:desktop_multi_window/desktop_multi_window.dart';
import 'package:flutter/material.dart';
import 'package:flutter_hbb/common.dart';
import 'package:flutter_hbb/consts.dart';
import 'package:flutter_hbb/main.dart';
import 'package:flutter_hbb/utils/multi_window_manager.dart';
import 'package:get/get.dart';
import 'package:window_manager/window_manager.dart';
const double _kTabBarHeight = kDesktopRemoteTabBarHeight;
const double _kIconSize = 18;
@ -76,42 +79,52 @@ class DesktopTabBar extends StatelessWidget {
Text("RustDesk").paddingOnly(left: 5),
]).paddingSymmetric(horizontal: 12, vertical: 5),
),
Flexible(
child: Obx(() => TabBar(
key: tabBarKey,
indicatorColor: _theme.indicatorColor,
labelPadding: const EdgeInsets.symmetric(
vertical: 0, horizontal: 0),
isScrollable: true,
indicatorPadding: EdgeInsets.zero,
physics: BouncingScrollPhysics(),
controller: controller.value,
tabs: tabs.asMap().entries.map((e) {
int index = e.key;
String label = e.value.label;
Expanded(
child: GestureDetector(
onPanStart: (_) {
if (mainTab) {
windowManager.startDragging();
} else {
WindowController.fromWindowId(windowId!)
.startDragging();
}
},
child: Obx(() => TabBar(
key: tabBarKey,
indicatorColor: _theme.indicatorColor,
labelPadding: const EdgeInsets.symmetric(
vertical: 0, horizontal: 0),
isScrollable: true,
indicatorPadding: EdgeInsets.zero,
physics: BouncingScrollPhysics(),
controller: controller.value,
tabs: tabs.asMap().entries.map((e) {
int index = e.key;
String label = e.value.label;
return _Tab(
index: index,
label: label,
icon: e.value.icon,
closable: e.value.closable,
selected: selected.value,
onClose: () {
onTabClose(label);
if (index <= selected.value) {
selected.value = max(0, selected.value - 1);
}
controller.value.animateTo(selected.value,
duration: Duration.zero);
},
onSelected: () {
selected.value = index;
controller.value
.animateTo(index, duration: Duration.zero);
},
theme: _theme,
);
}).toList())),
return _Tab(
index: index,
label: label,
icon: e.value.icon,
closable: e.value.closable,
selected: selected.value,
onClose: () {
onTabClose(label);
if (index <= selected.value) {
selected.value = max(0, selected.value - 1);
}
controller.value.animateTo(selected.value,
duration: Duration.zero);
},
onSelected: () {
selected.value = index;
controller.value
.animateTo(index, duration: Duration.zero);
},
theme: _theme,
);
}).toList())),
),
),
Offstage(
offstage: mainTab,
@ -134,6 +147,10 @@ class DesktopTabBar extends StatelessWidget {
onTap: () => onAddSetting?.call(),
).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 {
late final int index;
late final String label;

View File

@ -1,5 +1,6 @@
import 'dart:convert';
import 'package:desktop_multi_window/desktop_multi_window.dart';
import 'package:flutter/material.dart';
import 'package:flutter_hbb/desktop/pages/desktop_tab_page.dart';
import 'package:flutter_hbb/desktop/pages/server_page.dart';
@ -32,6 +33,7 @@ Future<Null> main(List<String> args) async {
// main window
if (args.isNotEmpty && args.first == 'multi_window') {
windowId = int.parse(args[1]);
WindowController.fromWindowId(windowId!).showTitleBar(false);
final argument = args[2].isEmpty
? 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 {
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) {
// await windowManager.ensureInitialized();
// disable tray
@ -118,13 +127,7 @@ void runFileTransferScreen(Map<String, dynamic> argument) async {
void runConnectionManagerScreen() async {
// initialize window
WindowOptions windowOptions = WindowOptions(
size: Size(300, 400),
center: true,
backgroundColor: Colors.transparent,
skipTaskbar: false,
titleBarStyle: TitleBarStyle.normal,
);
WindowOptions windowOptions = getHiddenTitleBarWindowOptions(Size(300, 400));
await Future.wait([
initEnv(kAppTypeConnectionManager),
windowManager.waitUntilReadyToShow(windowOptions, () async {
@ -133,8 +136,20 @@ void runConnectionManagerScreen() async {
await windowManager.focus();
})
]);
;
runApp(GetMaterialApp(theme: getCurrentTheme(), home: DesktopServerPage()));
runApp(GetMaterialApp(
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 {

View File

@ -250,8 +250,8 @@ packages:
dependency: "direct main"
description:
path: "."
ref: "2b1176d53f195cc55e8d37151bb3d9f6bd52fad3"
resolved-ref: "2b1176d53f195cc55e8d37151bb3d9f6bd52fad3"
ref: bf670217de03f4866177a9793284f4db99271c51
resolved-ref: bf670217de03f4866177a9793284f4db99271c51
url: "https://github.com/Kingtous/rustdesk_desktop_multi_window"
source: git
version: "0.1.0"

View File

@ -63,11 +63,15 @@ dependencies:
url: https://github.com/Kingtous/rustdesk_window_manager
ref: 028a7f6
desktop_multi_window:
# path: ../../rustdesk_desktop_multi_window
git:
url: https://github.com/Kingtous/rustdesk_desktop_multi_window
ref: 2b1176d53f195cc55e8d37151bb3d9f6bd52fad3
ref: bf670217de03f4866177a9793284f4db99271c51
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
visibility_detector: ^0.3.3
contextmenu: ^3.0.0