Merge pull request #1302 from Kingtous/flutter_desktop
opt: optimize cm ui & prepare custom titlebar
This commit is contained in:
commit
58b471e26b
@ -10,8 +10,8 @@ import 'desktop/pages/server_page.dart';
|
|||||||
void main(List<String> args) async {
|
void main(List<String> args) async {
|
||||||
WidgetsFlutterBinding.ensureInitialized();
|
WidgetsFlutterBinding.ensureInitialized();
|
||||||
await windowManager.ensureInitialized();
|
await windowManager.ensureInitialized();
|
||||||
await initEnv(kAppTypeConnectionManager);
|
|
||||||
runApp(GetMaterialApp(theme: getCurrentTheme(), home: DesktopServerPage()));
|
|
||||||
await windowManager.setSize(Size(400, 600));
|
await windowManager.setSize(Size(400, 600));
|
||||||
await windowManager.setAlignment(Alignment.topRight);
|
await windowManager.setAlignment(Alignment.topRight);
|
||||||
|
await initEnv(kAppTypeConnectionManager);
|
||||||
|
runApp(GetMaterialApp(theme: getCurrentTheme(), home: DesktopServerPage()));
|
||||||
}
|
}
|
||||||
|
@ -79,6 +79,15 @@ final ButtonStyle flatButtonStyle = TextButton.styleFrom(
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
String formatDurationToTime(Duration duration) {
|
||||||
|
var totalTime = duration.inSeconds;
|
||||||
|
final secs = totalTime % 60;
|
||||||
|
totalTime = (totalTime - secs) ~/ 60;
|
||||||
|
final mins = totalTime % 60;
|
||||||
|
totalTime = (totalTime - mins) ~/ 60;
|
||||||
|
return "${totalTime.toString().padLeft(2, "0")}:${mins.toString().padLeft(2, "0")}:${secs.toString().padLeft(2, "0")}";
|
||||||
|
}
|
||||||
|
|
||||||
closeConnection({String? id}) {
|
closeConnection({String? id}) {
|
||||||
if (isAndroid || isIOS) {
|
if (isAndroid || isIOS) {
|
||||||
Navigator.popUntil(globalKey.currentContext!, ModalRoute.withName("/"));
|
Navigator.popUntil(globalKey.currentContext!, ModalRoute.withName("/"));
|
||||||
@ -440,12 +449,18 @@ class PermissionManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static Future<bool> check(String type) {
|
static Future<bool> check(String type) {
|
||||||
|
if (isDesktop) {
|
||||||
|
return Future.value(true);
|
||||||
|
}
|
||||||
if (!permissions.contains(type))
|
if (!permissions.contains(type))
|
||||||
return Future.error("Wrong permission!$type");
|
return Future.error("Wrong permission!$type");
|
||||||
return gFFI.invokeMethod("check_permission", type);
|
return gFFI.invokeMethod("check_permission", type);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Future<bool> request(String type) {
|
static Future<bool> request(String type) {
|
||||||
|
if (isDesktop) {
|
||||||
|
return Future.value(true);
|
||||||
|
}
|
||||||
if (!permissions.contains(type))
|
if (!permissions.contains(type))
|
||||||
return Future.error("Wrong permission!$type");
|
return Future.error("Wrong permission!$type");
|
||||||
|
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
|
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';
|
||||||
|
|
||||||
@ -32,14 +35,14 @@ class DesktopServerPage extends StatefulWidget implements PageShape {
|
|||||||
padding: EdgeInsets.symmetric(horizontal: 16.0),
|
padding: EdgeInsets.symmetric(horizontal: 16.0),
|
||||||
value: "setPermanentPassword",
|
value: "setPermanentPassword",
|
||||||
enabled:
|
enabled:
|
||||||
gFFI.serverModel.verificationMethod != kUseTemporaryPassword,
|
gFFI.serverModel.verificationMethod != kUseTemporaryPassword,
|
||||||
),
|
),
|
||||||
PopupMenuItem(
|
PopupMenuItem(
|
||||||
child: Text(translate("Set temporary password length")),
|
child: Text(translate("Set temporary password length")),
|
||||||
padding: EdgeInsets.symmetric(horizontal: 16.0),
|
padding: EdgeInsets.symmetric(horizontal: 16.0),
|
||||||
value: "setTemporaryPasswordLength",
|
value: "setTemporaryPasswordLength",
|
||||||
enabled:
|
enabled:
|
||||||
gFFI.serverModel.verificationMethod != kUsePermanentPassword,
|
gFFI.serverModel.verificationMethod != kUsePermanentPassword,
|
||||||
),
|
),
|
||||||
const PopupMenuDivider(),
|
const PopupMenuDivider(),
|
||||||
PopupMenuItem(
|
PopupMenuItem(
|
||||||
@ -51,7 +54,7 @@ class DesktopServerPage extends StatefulWidget implements PageShape {
|
|||||||
trailing: Icon(
|
trailing: Icon(
|
||||||
Icons.check,
|
Icons.check,
|
||||||
color: gFFI.serverModel.verificationMethod ==
|
color: gFFI.serverModel.verificationMethod ==
|
||||||
kUseTemporaryPassword
|
kUseTemporaryPassword
|
||||||
? null
|
? null
|
||||||
: Color(0xFFFFFFFF),
|
: Color(0xFFFFFFFF),
|
||||||
))),
|
))),
|
||||||
@ -64,7 +67,7 @@ class DesktopServerPage extends StatefulWidget implements PageShape {
|
|||||||
trailing: Icon(
|
trailing: Icon(
|
||||||
Icons.check,
|
Icons.check,
|
||||||
color: gFFI.serverModel.verificationMethod ==
|
color: gFFI.serverModel.verificationMethod ==
|
||||||
kUsePermanentPassword
|
kUsePermanentPassword
|
||||||
? null
|
? null
|
||||||
: Color(0xFFFFFFFF),
|
: Color(0xFFFFFFFF),
|
||||||
)),
|
)),
|
||||||
@ -77,9 +80,9 @@ class DesktopServerPage extends StatefulWidget implements PageShape {
|
|||||||
trailing: Icon(
|
trailing: Icon(
|
||||||
Icons.check,
|
Icons.check,
|
||||||
color: gFFI.serverModel.verificationMethod !=
|
color: gFFI.serverModel.verificationMethod !=
|
||||||
kUseTemporaryPassword &&
|
kUseTemporaryPassword &&
|
||||||
gFFI.serverModel.verificationMethod !=
|
gFFI.serverModel.verificationMethod !=
|
||||||
kUsePermanentPassword
|
kUsePermanentPassword
|
||||||
? null
|
? null
|
||||||
: Color(0xFFFFFFFF),
|
: Color(0xFFFFFFFF),
|
||||||
)),
|
)),
|
||||||
@ -115,16 +118,16 @@ class _DesktopServerPageState extends State<DesktopServerPage>
|
|||||||
value: gFFI.serverModel,
|
value: gFFI.serverModel,
|
||||||
child: Consumer<ServerModel>(
|
child: Consumer<ServerModel>(
|
||||||
builder: (context, serverModel, child) => Material(
|
builder: (context, serverModel, child) => Material(
|
||||||
child: Center(
|
child: Center(
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.start,
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Expanded(child: ConnectionManager()),
|
Expanded(child: ConnectionManager()),
|
||||||
SizedBox.fromSize(size: Size(0, 15.0)),
|
SizedBox.fromSize(size: Size(0, 15.0)),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -136,9 +139,9 @@ class ConnectionManager extends StatelessWidget {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final serverModel = Provider.of<ServerModel>(context);
|
final serverModel = Provider.of<ServerModel>(context);
|
||||||
// test case:
|
// test case:
|
||||||
serverModel.clients.clear();
|
// serverModel.clients.clear();
|
||||||
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(
|
? Center(
|
||||||
child: Text(translate("Waiting")),
|
child: Text(translate("Waiting")),
|
||||||
@ -150,11 +153,11 @@ class ConnectionManager extends StatelessWidget {
|
|||||||
children: [
|
children: [
|
||||||
SizedBox(
|
SizedBox(
|
||||||
height: kTextTabBarHeight,
|
height: kTextTabBarHeight,
|
||||||
child: TabBar(
|
child: 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,9 +173,10 @@ class ConnectionManager extends StatelessWidget {
|
|||||||
Widget buildConnectionCard(MapEntry<int, Client> entry) {
|
Widget buildConnectionCard(MapEntry<int, Client> entry) {
|
||||||
final client = entry.value;
|
final client = entry.value;
|
||||||
return Column(
|
return Column(
|
||||||
|
key: ValueKey(entry.key),
|
||||||
children: [
|
children: [
|
||||||
_CmHeader(client: client),
|
_CmHeader(client: client),
|
||||||
_PrivilegeBoard(client: client),
|
client.isFileTransfer ? Offstage() : _PrivilegeBoard(client: client),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Align(
|
child: Align(
|
||||||
alignment: Alignment.bottomCenter,
|
alignment: Alignment.bottomCenter,
|
||||||
@ -200,13 +204,39 @@ class ConnectionManager extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class _CmHeader extends StatelessWidget {
|
class _CmHeader extends StatefulWidget {
|
||||||
final Client client;
|
final Client client;
|
||||||
|
|
||||||
const _CmHeader({Key? key, required this.client}) : super(key: key);
|
const _CmHeader({Key? key, required this.client}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<_CmHeader> createState() => _CmHeaderState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _CmHeaderState extends State<_CmHeader>
|
||||||
|
with AutomaticKeepAliveClientMixin {
|
||||||
|
Client get client => widget.client;
|
||||||
|
|
||||||
|
var _time = 0.obs;
|
||||||
|
Timer? _timer;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
_timer = Timer.periodic(Duration(seconds: 1), (_) {
|
||||||
|
_time.value = _time.value + 1;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_timer?.cancel();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
super.build(context);
|
||||||
return Row(
|
return Row(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
@ -242,13 +272,13 @@ class _CmHeader extends StatelessWidget {
|
|||||||
SizedBox(
|
SizedBox(
|
||||||
height: 16.0,
|
height: 16.0,
|
||||||
),
|
),
|
||||||
Offstage(
|
Row(
|
||||||
offstage: !client.authorized,
|
children: [
|
||||||
child: Row(
|
Text("${translate("Connected")}").marginOnly(right: 8.0),
|
||||||
children: [
|
Obx(() => Text(
|
||||||
Text("${translate("Connected")}"),
|
"${formatDurationToTime(Duration(seconds: _time.value))}"))
|
||||||
],
|
],
|
||||||
))
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -264,6 +294,9 @@ class _CmHeader extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void handleSendMsg() {}
|
void handleSendMsg() {}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool get wantKeepAlive => true;
|
||||||
}
|
}
|
||||||
|
|
||||||
class _PrivilegeBoard extends StatelessWidget {
|
class _PrivilegeBoard extends StatelessWidget {
|
||||||
@ -277,7 +310,7 @@ class _PrivilegeBoard extends StatelessWidget {
|
|||||||
message: tooltip ?? "",
|
message: tooltip ?? "",
|
||||||
child: Ink(
|
child: Ink(
|
||||||
decoration:
|
decoration:
|
||||||
BoxDecoration(color: enabled ? MyTheme.accent80 : Colors.grey),
|
BoxDecoration(color: enabled ? MyTheme.accent80 : Colors.grey),
|
||||||
padding: EdgeInsets.all(4.0),
|
padding: EdgeInsets.all(4.0),
|
||||||
child: InkWell(
|
child: InkWell(
|
||||||
onTap: () => onTap?.call(!enabled),
|
onTap: () => onTap?.call(!enabled),
|
||||||
@ -437,9 +470,9 @@ class PaddingCard extends StatelessWidget {
|
|||||||
children: [
|
children: [
|
||||||
titleIcon != null
|
titleIcon != null
|
||||||
? Padding(
|
? Padding(
|
||||||
padding: EdgeInsets.only(right: 10),
|
padding: EdgeInsets.only(right: 10),
|
||||||
child: Icon(titleIcon,
|
child: Icon(titleIcon,
|
||||||
color: MyTheme.accent80, size: 30))
|
color: MyTheme.accent80, size: 30))
|
||||||
: SizedBox.shrink(),
|
: SizedBox.shrink(),
|
||||||
Text(
|
Text(
|
||||||
title!,
|
title!,
|
||||||
@ -486,12 +519,12 @@ Widget clientInfo(Client client) {
|
|||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
Text(client.name,
|
Text(client.name,
|
||||||
style: TextStyle(color: MyTheme.idColor, fontSize: 18)),
|
style: TextStyle(color: MyTheme.idColor, fontSize: 18)),
|
||||||
SizedBox(width: 8),
|
SizedBox(width: 8),
|
||||||
Text(client.peerId,
|
Text(client.peerId,
|
||||||
style: TextStyle(color: MyTheme.idColor, fontSize: 10))
|
style: TextStyle(color: MyTheme.idColor, fontSize: 10))
|
||||||
]))
|
]))
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
]));
|
]));
|
||||||
|
@ -117,9 +117,23 @@ void runFileTransferScreen(Map<String, dynamic> argument) async {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void runConnectionManagerScreen() async {
|
void runConnectionManagerScreen() async {
|
||||||
await initEnv(kAppTypeConnectionManager);
|
// initialize window
|
||||||
await windowManager.setSize(Size(400, 600));
|
WindowOptions windowOptions = WindowOptions(
|
||||||
await windowManager.setAlignment(Alignment.topRight);
|
size: Size(300, 400),
|
||||||
|
center: true,
|
||||||
|
backgroundColor: Colors.transparent,
|
||||||
|
skipTaskbar: false,
|
||||||
|
titleBarStyle: TitleBarStyle.normal,
|
||||||
|
);
|
||||||
|
await Future.wait([
|
||||||
|
initEnv(kAppTypeConnectionManager),
|
||||||
|
windowManager.waitUntilReadyToShow(windowOptions, () async {
|
||||||
|
await windowManager.setAlignment(Alignment.topRight);
|
||||||
|
await windowManager.show();
|
||||||
|
await windowManager.focus();
|
||||||
|
})
|
||||||
|
]);
|
||||||
|
;
|
||||||
runApp(GetMaterialApp(theme: getCurrentTheme(), home: DesktopServerPage()));
|
runApp(GetMaterialApp(theme: getCurrentTheme(), home: DesktopServerPage()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -342,6 +342,10 @@ class ServerModel with ChangeNotifier {
|
|||||||
var res = await bind.mainGetClientsState();
|
var res = await bind.mainGetClientsState();
|
||||||
try {
|
try {
|
||||||
final List clientsJson = jsonDecode(res);
|
final List clientsJson = jsonDecode(res);
|
||||||
|
if (isDesktop && clientsJson.isEmpty && _clients.isNotEmpty) {
|
||||||
|
// exit cm when >1 peers to no peers
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
_clients.clear();
|
_clients.clear();
|
||||||
for (var clientJson in clientsJson) {
|
for (var clientJson in clientsJson) {
|
||||||
final client = Client.fromJson(clientJson);
|
final client = Client.fromJson(clientJson);
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
#include "my_application.h"
|
#include "my_application.h"
|
||||||
|
|
||||||
#include <flutter_linux/flutter_linux.h>
|
#include <flutter_linux/flutter_linux.h>
|
||||||
// #include <bitsdojo_window_linux/bitsdojo_window_plugin.h>
|
|
||||||
#ifdef GDK_WINDOWING_X11
|
#ifdef GDK_WINDOWING_X11
|
||||||
#include <gdk/gdkx.h>
|
#include <gdk/gdkx.h>
|
||||||
#endif
|
#endif
|
||||||
@ -48,8 +47,8 @@ static void my_application_activate(GApplication* application) {
|
|||||||
gtk_window_set_title(window, "rustdesk");
|
gtk_window_set_title(window, "rustdesk");
|
||||||
}
|
}
|
||||||
|
|
||||||
// auto bdw = bitsdojo_window_from(window); // <--- add this line
|
// auto bdw = bitsdojo_window_from(window); // <--- add this line
|
||||||
// bdw->setCustomFrame(true); // <-- add this line
|
// bdw->setCustomFrame(true); // <-- add this line
|
||||||
gtk_window_set_default_size(window, 1280, 720); // <-- comment this line
|
gtk_window_set_default_size(window, 1280, 720); // <-- comment this line
|
||||||
gtk_widget_show(GTK_WIDGET(window));
|
gtk_widget_show(GTK_WIDGET(window));
|
||||||
|
|
||||||
|
@ -66,7 +66,6 @@ dependencies:
|
|||||||
git:
|
git:
|
||||||
url: https://github.com/Kingtous/rustdesk_desktop_multi_window
|
url: https://github.com/Kingtous/rustdesk_desktop_multi_window
|
||||||
ref: 2b1176d53f195cc55e8d37151bb3d9f6bd52fad3
|
ref: 2b1176d53f195cc55e8d37151bb3d9f6bd52fad3
|
||||||
# bitsdojo_window: ^0.1.2
|
|
||||||
freezed_annotation: ^2.0.3
|
freezed_annotation: ^2.0.3
|
||||||
tray_manager: 0.1.7
|
tray_manager: 0.1.7
|
||||||
get: ^4.6.5
|
get: ^4.6.5
|
||||||
|
Loading…
x
Reference in New Issue
Block a user