From ce86d5a5d42afcdd247eb18a95fe1f1c45528398 Mon Sep 17 00:00:00 2001 From: Kingtous Date: Thu, 11 Aug 2022 18:59:26 +0800 Subject: [PATCH 1/3] add: cm page Signed-off-by: Kingtous --- flutter/lib/consts.dart | 1 + flutter/lib/desktop/pages/server_page.dart | 555 +++++++++++++++++++++ flutter/lib/main.dart | 16 +- src/core_main.rs | 12 +- 4 files changed, 582 insertions(+), 2 deletions(-) create mode 100644 flutter/lib/desktop/pages/server_page.dart diff --git a/flutter/lib/consts.dart b/flutter/lib/consts.dart index 466b4b74a..7b61c5b48 100644 --- a/flutter/lib/consts.dart +++ b/flutter/lib/consts.dart @@ -2,6 +2,7 @@ const double kDesktopRemoteTabBarHeight = 48.0; const String kAppTypeMain = "main"; const String kAppTypeDesktopRemote = "remote"; const String kAppTypeDesktopFileTransfer = "file transfer"; +const String kAppTypeConnectionManager = "connection manager"; const String kTabLabelHomePage = "Home"; const String kTabLabelSettingPage = "Settings"; diff --git a/flutter/lib/desktop/pages/server_page.dart b/flutter/lib/desktop/pages/server_page.dart new file mode 100644 index 000000000..7024e7258 --- /dev/null +++ b/flutter/lib/desktop/pages/server_page.dart @@ -0,0 +1,555 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_hbb/mobile/widgets/dialog.dart'; +import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; +import 'package:provider/provider.dart'; + +import '../../common.dart'; +import '../../mobile/pages/home_page.dart'; +import '../../models/platform_model.dart'; +import '../../models/server_model.dart'; + +class DesktopServerPage extends StatefulWidget implements PageShape { + @override + final title = translate("Share Screen"); + + @override + final icon = Icon(Icons.mobile_screen_share); + + @override + final appBarActions = [ + PopupMenuButton( + icon: Icon(Icons.more_vert), + itemBuilder: (context) { + return [ + PopupMenuItem( + child: Text(translate("Change ID")), + padding: EdgeInsets.symmetric(horizontal: 16.0), + value: "changeID", + enabled: false, + ), + PopupMenuItem( + child: Text(translate("Set permanent password")), + padding: EdgeInsets.symmetric(horizontal: 16.0), + value: "setPermanentPassword", + enabled: + gFFI.serverModel.verificationMethod != kUseTemporaryPassword, + ), + PopupMenuItem( + child: Text(translate("Set temporary password length")), + padding: EdgeInsets.symmetric(horizontal: 16.0), + value: "setTemporaryPasswordLength", + enabled: + gFFI.serverModel.verificationMethod != kUsePermanentPassword, + ), + const PopupMenuDivider(), + PopupMenuItem( + padding: EdgeInsets.symmetric(horizontal: 0.0), + value: kUseTemporaryPassword, + child: Container( + child: ListTile( + title: Text(translate("Use temporary password")), + trailing: Icon( + Icons.check, + color: gFFI.serverModel.verificationMethod == + kUseTemporaryPassword + ? null + : Color(0xFFFFFFFF), + ))), + ), + PopupMenuItem( + padding: EdgeInsets.symmetric(horizontal: 0.0), + value: kUsePermanentPassword, + child: ListTile( + title: Text(translate("Use permanent password")), + trailing: Icon( + Icons.check, + color: gFFI.serverModel.verificationMethod == + kUsePermanentPassword + ? null + : Color(0xFFFFFFFF), + )), + ), + PopupMenuItem( + padding: EdgeInsets.symmetric(horizontal: 0.0), + value: kUseBothPasswords, + child: ListTile( + title: Text(translate("Use both passwords")), + trailing: Icon( + Icons.check, + color: gFFI.serverModel.verificationMethod != + kUseTemporaryPassword && + gFFI.serverModel.verificationMethod != + kUsePermanentPassword + ? null + : Color(0xFFFFFFFF), + )), + ), + ]; + }, + onSelected: (value) { + if (value == "changeID") { + // TODO + } else if (value == "setPermanentPassword") { + setPermanentPasswordDialog(); + } else if (value == "setTemporaryPasswordLength") { + setTemporaryPasswordLengthDialog(); + } else if (value == kUsePermanentPassword || + value == kUseTemporaryPassword || + value == kUseBothPasswords) { + bind.mainSetOption(key: "verification-method", value: value); + gFFI.serverModel.updatePasswordModel(); + } + }) + ]; + + @override + State createState() => _DesktopServerPageState(); +} + +class _DesktopServerPageState extends State { + @override + void initState() { + super.initState(); + gFFI.serverModel.checkAndroidPermission(); + } + + @override + Widget build(BuildContext context) { + checkService(); + return ChangeNotifierProvider.value( + value: gFFI.serverModel, + child: Consumer( + builder: (context, serverModel, child) => SingleChildScrollView( + controller: gFFI.serverModel.controller, + child: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + ServerInfo(), + PermissionChecker(), + ConnectionManager(), + SizedBox.fromSize(size: Size(0, 15.0)), + ], + ), + ), + ))); + } +} + +void checkService() async { + gFFI.invokeMethod("check_service"); // jvm + // for Android 10/11,MANAGE_EXTERNAL_STORAGE permission from a system setting page + if (PermissionManager.isWaitingFile() && !gFFI.serverModel.fileOk) { + PermissionManager.complete("file", await PermissionManager.check("file")); + debugPrint("file permission finished"); + } +} + +class ServerInfo extends StatelessWidget { + final model = gFFI.serverModel; + final emptyController = TextEditingController(text: "-"); + + @override + Widget build(BuildContext context) { + final isPermanent = model.verificationMethod == kUsePermanentPassword; + return model.isStart + ? PaddingCard( + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + TextFormField( + readOnly: true, + style: TextStyle( + fontSize: 25.0, + fontWeight: FontWeight.bold, + color: MyTheme.accent), + controller: model.serverId, + decoration: InputDecoration( + icon: const Icon(Icons.perm_identity), + labelText: translate("ID"), + labelStyle: TextStyle( + fontWeight: FontWeight.bold, color: MyTheme.accent50), + ), + onSaved: (String? value) {}, + ), + TextFormField( + readOnly: true, + style: TextStyle( + fontSize: 25.0, + fontWeight: FontWeight.bold, + color: MyTheme.accent), + controller: isPermanent ? emptyController : model.serverPasswd, + decoration: InputDecoration( + icon: const Icon(Icons.lock), + labelText: translate("Password"), + labelStyle: TextStyle( + fontWeight: FontWeight.bold, color: MyTheme.accent50), + suffix: isPermanent + ? null + : IconButton( + icon: const Icon(Icons.refresh), + onPressed: () => + bind.mainUpdateTemporaryPassword())), + onSaved: (String? value) {}, + ), + ], + )) + : PaddingCard( + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Center( + child: Row( + children: [ + Icon(Icons.warning_amber_sharp, + color: Colors.redAccent, size: 24), + SizedBox(width: 10), + Expanded( + child: Text( + translate("Service is not running"), + style: TextStyle( + fontFamily: 'WorkSans', + fontWeight: FontWeight.bold, + fontSize: 18, + color: MyTheme.accent80, + ), + )) + ], + )), + SizedBox(height: 5), + Center( + child: Text( + translate("android_start_service_tip"), + style: TextStyle(fontSize: 12, color: MyTheme.darkGray), + )) + ], + )); + } +} + +class PermissionChecker extends StatefulWidget { + @override + _PermissionCheckerState createState() => _PermissionCheckerState(); +} + +class _PermissionCheckerState extends State { + @override + Widget build(BuildContext context) { + final serverModel = Provider.of(context); + final hasAudioPermission = androidVersion >= 30; + final status; + if (serverModel.connectStatus == -1) { + status = 'not_ready_status'; + } else if (serverModel.connectStatus == 0) { + status = 'connecting_status'; + } else { + status = 'Ready'; + } + return PaddingCard( + title: translate("Permissions"), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + PermissionRow(translate("Screen Capture"), serverModel.mediaOk, + serverModel.toggleService), + PermissionRow(translate("Input Control"), serverModel.inputOk, + serverModel.toggleInput), + PermissionRow(translate("Transfer File"), serverModel.fileOk, + serverModel.toggleFile), + hasAudioPermission + ? PermissionRow(translate("Audio Capture"), serverModel.audioOk, + serverModel.toggleAudio) + : Text( + "* ${translate("android_version_audio_tip")}", + style: TextStyle(color: MyTheme.darkGray), + ), + SizedBox(height: 8), + Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Expanded( + flex: 0, + child: serverModel.mediaOk + ? ElevatedButton.icon( + style: ButtonStyle( + backgroundColor: + MaterialStateProperty.all(Colors.red)), + icon: Icon(Icons.stop), + onPressed: serverModel.toggleService, + label: Text(translate("Stop service"))) + : ElevatedButton.icon( + icon: Icon(Icons.play_arrow), + onPressed: serverModel.toggleService, + label: Text(translate("Start Service")))), + Expanded( + child: serverModel.mediaOk + ? Row( + children: [ + Expanded( + flex: 0, + child: Padding( + padding: + EdgeInsets.only(left: 20, right: 5), + child: Icon(Icons.circle, + color: serverModel.connectStatus > 0 + ? Colors.greenAccent + : Colors.deepOrangeAccent, + size: 10))), + Expanded( + child: Text(translate(status), + softWrap: true, + style: TextStyle( + fontSize: 14.0, + color: MyTheme.accent50))) + ], + ) + : SizedBox.shrink()) + ], + ), + ], + )); + } +} + +class PermissionRow extends StatelessWidget { + PermissionRow(this.name, this.isOk, this.onPressed); + + final String name; + final bool isOk; + final VoidCallback onPressed; + + @override + Widget build(BuildContext context) { + return Row( + children: [ + Expanded( + flex: 5, + child: FittedBox( + fit: BoxFit.scaleDown, + alignment: Alignment.centerLeft, + child: Text(name, + style: + TextStyle(fontSize: 16.0, color: MyTheme.accent50)))), + Expanded( + flex: 2, + child: FittedBox( + fit: BoxFit.scaleDown, + child: Text(isOk ? translate("ON") : translate("OFF"), + style: TextStyle( + fontSize: 16.0, + color: isOk ? Colors.green : Colors.grey))), + ), + Expanded( + flex: 3, + child: FittedBox( + fit: BoxFit.scaleDown, + alignment: Alignment.centerRight, + child: TextButton( + onPressed: onPressed, + child: Text( + translate(isOk ? "CLOSE" : "OPEN"), + style: TextStyle(fontWeight: FontWeight.bold), + )))), + ], + ); + } +} + +class ConnectionManager extends StatelessWidget { + @override + Widget build(BuildContext context) { + final serverModel = Provider.of(context); + return Column( + children: serverModel.clients.entries + .map((entry) => PaddingCard( + title: translate(entry.value.isFileTransfer + ? "File Connection" + : "Screen Connection"), + titleIcon: entry.value.isFileTransfer + ? Icons.folder_outlined + : Icons.mobile_screen_share, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Expanded(child: clientInfo(entry.value)), + Expanded( + flex: -1, + child: entry.value.isFileTransfer || + !entry.value.authorized + ? SizedBox.shrink() + : IconButton( + onPressed: () { + gFFI.chatModel + .changeCurrentID(entry.value.id); + final bar = + navigationBarKey.currentWidget; + if (bar != null) { + bar as BottomNavigationBar; + bar.onTap!(1); + } + }, + icon: Icon( + Icons.chat, + color: MyTheme.accent80, + ))) + ], + ), + entry.value.authorized + ? SizedBox.shrink() + : Text( + translate("android_new_connection_tip"), + style: TextStyle(color: Colors.black54), + ), + entry.value.authorized + ? ElevatedButton.icon( + style: ButtonStyle( + backgroundColor: + MaterialStateProperty.all(Colors.red)), + icon: Icon(Icons.close), + onPressed: () { + bind.serverCloseConnection(connId: entry.key); + gFFI.invokeMethod( + "cancel_notification", entry.key); + }, + label: Text(translate("Close"))) + : Row(children: [ + TextButton( + child: Text(translate("Dismiss")), + onPressed: () { + serverModel.sendLoginResponse( + entry.value, false); + }), + SizedBox(width: 20), + ElevatedButton( + child: Text(translate("Accept")), + onPressed: () { + serverModel.sendLoginResponse( + entry.value, true); + }), + ]), + ], + ))) + .toList()); + } +} + +class PaddingCard extends StatelessWidget { + PaddingCard({required this.child, this.title, this.titleIcon}); + + final String? title; + final IconData? titleIcon; + final Widget child; + + @override + Widget build(BuildContext context) { + final children = [child]; + if (title != null) { + children.insert( + 0, + Padding( + padding: EdgeInsets.symmetric(vertical: 5.0), + child: Row( + children: [ + titleIcon != null + ? Padding( + padding: EdgeInsets.only(right: 10), + child: Icon(titleIcon, + color: MyTheme.accent80, size: 30)) + : SizedBox.shrink(), + Text( + title!, + style: TextStyle( + fontFamily: 'WorkSans', + fontWeight: FontWeight.bold, + fontSize: 20, + color: MyTheme.accent80, + ), + ) + ], + ))); + } + return Container( + width: double.maxFinite, + child: Card( + margin: EdgeInsets.fromLTRB(15.0, 15.0, 15.0, 0), + child: Padding( + padding: EdgeInsets.symmetric(vertical: 15.0, horizontal: 30.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: children, + ), + ), + )); + } +} + +Widget clientInfo(Client client) { + return Padding( + padding: EdgeInsets.symmetric(vertical: 8), + child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ + Row( + children: [ + Expanded( + flex: -1, + child: Padding( + padding: EdgeInsets.only(right: 12), + child: CircleAvatar( + child: Text(client.name[0]), + backgroundColor: MyTheme.border))), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text(client.name, + style: TextStyle(color: MyTheme.idColor, fontSize: 18)), + SizedBox(width: 8), + Text(client.peerId, + style: TextStyle(color: MyTheme.idColor, fontSize: 10)) + ])) + ], + ), + ])); +} + +void toAndroidChannelInit() { + gFFI.setMethodCallHandler((method, arguments) { + debugPrint("flutter got android msg,$method,$arguments"); + try { + switch (method) { + case "start_capture": + { + SmartDialog.dismiss(); + gFFI.serverModel.updateClientState(); + break; + } + case "on_state_changed": + { + var name = arguments["name"] as String; + var value = arguments["value"] as String == "true"; + debugPrint("from jvm:on_state_changed,$name:$value"); + gFFI.serverModel.changeStatue(name, value); + break; + } + case "on_android_permission_result": + { + var type = arguments["type"] as String; + var result = arguments["result"] as bool; + PermissionManager.complete(type, result); + break; + } + case "on_media_projection_canceled": + { + gFFI.serverModel.stopService(); + break; + } + } + } catch (e) { + debugPrint("MethodCallHandler err:$e"); + } + return ""; + }); +} diff --git a/flutter/lib/main.dart b/flutter/lib/main.dart index dd6ccd31d..2d738a383 100644 --- a/flutter/lib/main.dart +++ b/flutter/lib/main.dart @@ -1,12 +1,12 @@ import 'dart:convert'; import 'package:flutter/material.dart'; +import 'package:flutter_hbb/desktop/pages/cm.dart'; import 'package:flutter_hbb/desktop/pages/desktop_tab_page.dart'; import 'package:flutter_hbb/desktop/screen/desktop_file_transfer_screen.dart'; import 'package:flutter_hbb/desktop/screen/desktop_remote_screen.dart'; import 'package:flutter_hbb/utils/multi_window_manager.dart'; import 'package:get/get.dart'; -import 'package:get/route_manager.dart'; import 'package:provider/provider.dart'; import 'package:window_manager/window_manager.dart'; @@ -23,6 +23,7 @@ int? windowId; Future main(List args) async { WidgetsFlutterBinding.ensureInitialized(); + print("launch args: $args"); if (!isDesktop) { runMainApp(false); @@ -47,6 +48,9 @@ Future main(List args) async { default: break; } + } else if (args.isNotEmpty && args.first == '--cm') { + await windowManager.ensureInitialized(); + runConnectionManagerScreen(); } else { await windowManager.ensureInitialized(); windowManager.setPreventClose(true); @@ -111,6 +115,16 @@ void runFileTransferScreen(Map argument) async { ])); } +void runConnectionManagerScreen() async { + await initEnv(kAppTypeConnectionManager); + windowManager.setAlwaysOnTop(true); + windowManager.setSize(Size(400, 600)).then((_) { + windowManager.setAlignment(Alignment.topRight); + }); + runApp( + GetMaterialApp(theme: getCurrentTheme(), home: ConnectionManagerPage())); +} + class App extends StatelessWidget { @override Widget build(BuildContext context) { diff --git a/src/core_main.rs b/src/core_main.rs index c50bb0835..4e95f70ae 100644 --- a/src/core_main.rs +++ b/src/core_main.rs @@ -1,3 +1,7 @@ +use hbb_common::log; + +use crate::start_os_service; + /// Main entry of the RustDesk Core. /// Return true if the app should continue running with UI(possibly Flutter), false if the app should exit. pub fn core_main() -> bool { @@ -5,7 +9,13 @@ pub fn core_main() -> bool { // TODO: implement core_main() if args.len() > 1 { if args[1] == "--cm" { - // For test purpose only, this should stop any new window from popping up when a new connection is established. + // call connection manager to establish connections + // meanwhile, return true to call flutter window to show control panel + return true; + } + if args[1] == "--service" { + log::info!("start --service"); + start_os_service(); return false; } } From 07e54a0614c8ad3f419b67237a4b41c042bf1f0b Mon Sep 17 00:00:00 2001 From: Kingtous Date: Mon, 15 Aug 2022 12:35:10 +0800 Subject: [PATCH 2/3] add: connection manager page Signed-off-by: Kingtous --- flutter/lib/desktop/pages/server_page.dart | 273 +-------------------- flutter/lib/main.dart | 12 +- 2 files changed, 8 insertions(+), 277 deletions(-) diff --git a/flutter/lib/desktop/pages/server_page.dart b/flutter/lib/desktop/pages/server_page.dart index 7024e7258..bf80bfbe7 100644 --- a/flutter/lib/desktop/pages/server_page.dart +++ b/flutter/lib/desktop/pages/server_page.dart @@ -1,6 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:flutter_hbb/mobile/widgets/dialog.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 '../../common.dart'; @@ -90,9 +89,9 @@ class DesktopServerPage extends StatefulWidget implements PageShape { if (value == "changeID") { // TODO } else if (value == "setPermanentPassword") { - setPermanentPasswordDialog(); + // setPermanentPasswordDialog(); } else if (value == "setTemporaryPasswordLength") { - setTemporaryPasswordLengthDialog(); + // setTemporaryPasswordLengthDialog(); } else if (value == kUsePermanentPassword || value == kUseTemporaryPassword || value == kUseBothPasswords) { @@ -107,15 +106,9 @@ class DesktopServerPage extends StatefulWidget implements PageShape { } class _DesktopServerPageState extends State { - @override - void initState() { - super.initState(); - gFFI.serverModel.checkAndroidPermission(); - } @override Widget build(BuildContext context) { - checkService(); return ChangeNotifierProvider.value( value: gFFI.serverModel, child: Consumer( @@ -125,8 +118,6 @@ class _DesktopServerPageState extends State { child: Column( mainAxisAlignment: MainAxisAlignment.start, children: [ - ServerInfo(), - PermissionChecker(), ConnectionManager(), SizedBox.fromSize(size: Size(0, 15.0)), ], @@ -136,225 +127,6 @@ class _DesktopServerPageState extends State { } } -void checkService() async { - gFFI.invokeMethod("check_service"); // jvm - // for Android 10/11,MANAGE_EXTERNAL_STORAGE permission from a system setting page - if (PermissionManager.isWaitingFile() && !gFFI.serverModel.fileOk) { - PermissionManager.complete("file", await PermissionManager.check("file")); - debugPrint("file permission finished"); - } -} - -class ServerInfo extends StatelessWidget { - final model = gFFI.serverModel; - final emptyController = TextEditingController(text: "-"); - - @override - Widget build(BuildContext context) { - final isPermanent = model.verificationMethod == kUsePermanentPassword; - return model.isStart - ? PaddingCard( - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - TextFormField( - readOnly: true, - style: TextStyle( - fontSize: 25.0, - fontWeight: FontWeight.bold, - color: MyTheme.accent), - controller: model.serverId, - decoration: InputDecoration( - icon: const Icon(Icons.perm_identity), - labelText: translate("ID"), - labelStyle: TextStyle( - fontWeight: FontWeight.bold, color: MyTheme.accent50), - ), - onSaved: (String? value) {}, - ), - TextFormField( - readOnly: true, - style: TextStyle( - fontSize: 25.0, - fontWeight: FontWeight.bold, - color: MyTheme.accent), - controller: isPermanent ? emptyController : model.serverPasswd, - decoration: InputDecoration( - icon: const Icon(Icons.lock), - labelText: translate("Password"), - labelStyle: TextStyle( - fontWeight: FontWeight.bold, color: MyTheme.accent50), - suffix: isPermanent - ? null - : IconButton( - icon: const Icon(Icons.refresh), - onPressed: () => - bind.mainUpdateTemporaryPassword())), - onSaved: (String? value) {}, - ), - ], - )) - : PaddingCard( - child: Column( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Center( - child: Row( - children: [ - Icon(Icons.warning_amber_sharp, - color: Colors.redAccent, size: 24), - SizedBox(width: 10), - Expanded( - child: Text( - translate("Service is not running"), - style: TextStyle( - fontFamily: 'WorkSans', - fontWeight: FontWeight.bold, - fontSize: 18, - color: MyTheme.accent80, - ), - )) - ], - )), - SizedBox(height: 5), - Center( - child: Text( - translate("android_start_service_tip"), - style: TextStyle(fontSize: 12, color: MyTheme.darkGray), - )) - ], - )); - } -} - -class PermissionChecker extends StatefulWidget { - @override - _PermissionCheckerState createState() => _PermissionCheckerState(); -} - -class _PermissionCheckerState extends State { - @override - Widget build(BuildContext context) { - final serverModel = Provider.of(context); - final hasAudioPermission = androidVersion >= 30; - final status; - if (serverModel.connectStatus == -1) { - status = 'not_ready_status'; - } else if (serverModel.connectStatus == 0) { - status = 'connecting_status'; - } else { - status = 'Ready'; - } - return PaddingCard( - title: translate("Permissions"), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - PermissionRow(translate("Screen Capture"), serverModel.mediaOk, - serverModel.toggleService), - PermissionRow(translate("Input Control"), serverModel.inputOk, - serverModel.toggleInput), - PermissionRow(translate("Transfer File"), serverModel.fileOk, - serverModel.toggleFile), - hasAudioPermission - ? PermissionRow(translate("Audio Capture"), serverModel.audioOk, - serverModel.toggleAudio) - : Text( - "* ${translate("android_version_audio_tip")}", - style: TextStyle(color: MyTheme.darkGray), - ), - SizedBox(height: 8), - Row( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Expanded( - flex: 0, - child: serverModel.mediaOk - ? ElevatedButton.icon( - style: ButtonStyle( - backgroundColor: - MaterialStateProperty.all(Colors.red)), - icon: Icon(Icons.stop), - onPressed: serverModel.toggleService, - label: Text(translate("Stop service"))) - : ElevatedButton.icon( - icon: Icon(Icons.play_arrow), - onPressed: serverModel.toggleService, - label: Text(translate("Start Service")))), - Expanded( - child: serverModel.mediaOk - ? Row( - children: [ - Expanded( - flex: 0, - child: Padding( - padding: - EdgeInsets.only(left: 20, right: 5), - child: Icon(Icons.circle, - color: serverModel.connectStatus > 0 - ? Colors.greenAccent - : Colors.deepOrangeAccent, - size: 10))), - Expanded( - child: Text(translate(status), - softWrap: true, - style: TextStyle( - fontSize: 14.0, - color: MyTheme.accent50))) - ], - ) - : SizedBox.shrink()) - ], - ), - ], - )); - } -} - -class PermissionRow extends StatelessWidget { - PermissionRow(this.name, this.isOk, this.onPressed); - - final String name; - final bool isOk; - final VoidCallback onPressed; - - @override - Widget build(BuildContext context) { - return Row( - children: [ - Expanded( - flex: 5, - child: FittedBox( - fit: BoxFit.scaleDown, - alignment: Alignment.centerLeft, - child: Text(name, - style: - TextStyle(fontSize: 16.0, color: MyTheme.accent50)))), - Expanded( - flex: 2, - child: FittedBox( - fit: BoxFit.scaleDown, - child: Text(isOk ? translate("ON") : translate("OFF"), - style: TextStyle( - fontSize: 16.0, - color: isOk ? Colors.green : Colors.grey))), - ), - Expanded( - flex: 3, - child: FittedBox( - fit: BoxFit.scaleDown, - alignment: Alignment.centerRight, - child: TextButton( - onPressed: onPressed, - child: Text( - translate(isOk ? "CLOSE" : "OPEN"), - style: TextStyle(fontWeight: FontWeight.bold), - )))), - ], - ); - } -} - class ConnectionManager extends StatelessWidget { @override Widget build(BuildContext context) { @@ -514,42 +286,3 @@ Widget clientInfo(Client client) { ), ])); } - -void toAndroidChannelInit() { - gFFI.setMethodCallHandler((method, arguments) { - debugPrint("flutter got android msg,$method,$arguments"); - try { - switch (method) { - case "start_capture": - { - SmartDialog.dismiss(); - gFFI.serverModel.updateClientState(); - break; - } - case "on_state_changed": - { - var name = arguments["name"] as String; - var value = arguments["value"] as String == "true"; - debugPrint("from jvm:on_state_changed,$name:$value"); - gFFI.serverModel.changeStatue(name, value); - break; - } - case "on_android_permission_result": - { - var type = arguments["type"] as String; - var result = arguments["result"] as bool; - PermissionManager.complete(type, result); - break; - } - case "on_media_projection_canceled": - { - gFFI.serverModel.stopService(); - break; - } - } - } catch (e) { - debugPrint("MethodCallHandler err:$e"); - } - return ""; - }); -} diff --git a/flutter/lib/main.dart b/flutter/lib/main.dart index 2d738a383..d8586baad 100644 --- a/flutter/lib/main.dart +++ b/flutter/lib/main.dart @@ -1,8 +1,8 @@ import 'dart:convert'; import 'package:flutter/material.dart'; -import 'package:flutter_hbb/desktop/pages/cm.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/screen/desktop_file_transfer_screen.dart'; import 'package:flutter_hbb/desktop/screen/desktop_remote_screen.dart'; import 'package:flutter_hbb/utils/multi_window_manager.dart'; @@ -117,12 +117,10 @@ void runFileTransferScreen(Map argument) async { void runConnectionManagerScreen() async { await initEnv(kAppTypeConnectionManager); - windowManager.setAlwaysOnTop(true); - windowManager.setSize(Size(400, 600)).then((_) { - windowManager.setAlignment(Alignment.topRight); - }); - runApp( - GetMaterialApp(theme: getCurrentTheme(), home: ConnectionManagerPage())); + await windowManager.setAlwaysOnTop(true); + await windowManager.setSize(Size(400, 600)); + await windowManager.setAlignment(Alignment.topRight); + runApp(GetMaterialApp(theme: getCurrentTheme(), home: DesktopServerPage())); } class App extends StatelessWidget { From a6e2ad86397397b90700f014c18c61dcc2dcc880 Mon Sep 17 00:00:00 2001 From: Kingtous Date: Mon, 15 Aug 2022 14:04:08 +0800 Subject: [PATCH 3/3] add: fullscreen for sub windows Signed-off-by: Kingtous --- flutter/pubspec.lock | 4 ++-- flutter/pubspec.yaml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/flutter/pubspec.lock b/flutter/pubspec.lock index fcefcca82..695443f21 100644 --- a/flutter/pubspec.lock +++ b/flutter/pubspec.lock @@ -243,8 +243,8 @@ packages: dependency: "direct main" description: path: "." - ref: c53879e9ce4ed038af393a02bf2c7084ad4b53aa - resolved-ref: c53879e9ce4ed038af393a02bf2c7084ad4b53aa + ref: "2b1176d53f195cc55e8d37151bb3d9f6bd52fad3" + resolved-ref: "2b1176d53f195cc55e8d37151bb3d9f6bd52fad3" url: "https://github.com/Kingtous/rustdesk_desktop_multi_window" source: git version: "0.1.0" diff --git a/flutter/pubspec.yaml b/flutter/pubspec.yaml index b8b9580fb..a911903f8 100644 --- a/flutter/pubspec.yaml +++ b/flutter/pubspec.yaml @@ -62,7 +62,7 @@ dependencies: desktop_multi_window: git: url: https://github.com/Kingtous/rustdesk_desktop_multi_window - ref: c53879e9ce4ed038af393a02bf2c7084ad4b53aa + ref: 2b1176d53f195cc55e8d37151bb3d9f6bd52fad3 # bitsdojo_window: ^0.1.2 freezed_annotation: ^2.0.3 tray_manager: 0.1.7