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: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;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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 {
|
||||
|
@ -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"
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user