flutter_desktop: check remote menu, mid commit

Signed-off-by: fufesou <shuanglongchen@yeah.net>
This commit is contained in:
fufesou 2022-09-08 00:35:19 -07:00
parent f1bbe9ca5e
commit 21b277ea3f
4 changed files with 237 additions and 90 deletions

View File

@ -1,7 +1,6 @@
import 'package:contextmenu/contextmenu.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_hbb/utils/multi_window_manager.dart';
import 'package:get/get.dart';
import '../../common.dart';
@ -11,6 +10,7 @@ import '../../models/peer_model.dart';
import '../../models/platform_model.dart';
import './material_mod_popup_menu.dart' as mod_menu;
import './popup_menu.dart';
import './utils.dart';
class _PopupMenuTheme {
static const Color commonColor = MyTheme.accent;
@ -32,7 +32,7 @@ class _PeerCard extends StatefulWidget {
final Function(BuildContext, String) connect;
final PopupMenuEntryBuilder popupMenuEntryBuilder;
_PeerCard(
const _PeerCard(
{required this.peer,
required this.alias,
required this.connect,
@ -317,7 +317,7 @@ abstract class BasePeerCard extends StatelessWidget {
return _PeerCard(
peer: peer,
alias: alias,
connect: (BuildContext context, String id) => _connect(context, id),
connect: (BuildContext context, String id) => connect(context, id),
popupMenuEntryBuilder: _buildPopupMenuEntry,
);
}
@ -337,31 +337,6 @@ abstract class BasePeerCard extends StatelessWidget {
@protected
Future<List<MenuEntryBase<String>>> _buildMenuItems(BuildContext context);
/// Connect to a peer with [id].
/// If [isFileTransfer], starts a session only for file transfer.
/// If [isTcpTunneling], starts a session only for tcp tunneling.
/// If [isRDP], starts a session only for rdp.
void _connect(BuildContext context, String id,
{bool isFileTransfer = false,
bool isTcpTunneling = false,
bool isRDP = false}) async {
if (id == '') return;
id = id.replaceAll(' ', '');
assert(!(isFileTransfer && isTcpTunneling && isRDP),
"more than one connect type");
if (isFileTransfer) {
await rustDeskWinManager.newFileTransfer(id);
} else if (isTcpTunneling || isRDP) {
await rustDeskWinManager.newPortForward(id, isRDP);
} else {
await rustDeskWinManager.newRemoteDesktop(id);
}
FocusScopeNode currentFocus = FocusScope.of(context);
if (!currentFocus.hasPrimaryFocus) {
currentFocus.unfocus();
}
}
MenuEntryBase<String> _connectCommonAction(
BuildContext context, String id, String title,
{bool isFileTransfer = false,
@ -373,7 +348,7 @@ abstract class BasePeerCard extends StatelessWidget {
style: style,
),
proc: () {
_connect(
connect(
context,
peer.id,
isFileTransfer: isFileTransfer,
@ -434,7 +409,7 @@ abstract class BasePeerCard extends StatelessWidget {
],
)),
proc: () {
_connect(context, id, isRDP: true);
connect(context, id, isRDP: true);
},
dismissOnClicked: true,
);

View File

@ -11,6 +11,7 @@ import '../../models/platform_model.dart';
import '../../common/shared_state.dart';
import './popup_menu.dart';
import './material_mod_popup_menu.dart' as mod_menu;
import './utils.dart';
class _MenubarTheme {
static const Color commonColor = MyTheme.accent;
@ -225,7 +226,7 @@ class _RemoteMenubarState extends State<RemoteMenubar> {
),
tooltip: translate('Control Actions'),
position: mod_menu.PopupMenuPosition.under,
itemBuilder: (BuildContext context) => _getControlMenu()
itemBuilder: (BuildContext context) => _getControlMenu(context)
.map((entry) => entry.build(
context,
const MenuConfig(
@ -297,66 +298,76 @@ class _RemoteMenubarState extends State<RemoteMenubar> {
);
}
List<MenuEntryBase<String>> _getControlMenu() {
List<MenuEntryBase<String>> _getControlMenu(BuildContext context) {
final pi = widget.ffi.ffiModel.pi;
final perms = widget.ffi.ffiModel.permissions;
final List<MenuEntryBase<String>> displayMenu = [];
if (pi.version.isNotEmpty) {
displayMenu.add(MenuEntryButton<String>(
childBuilder: (TextStyle? style) => Text(
translate('Refresh'),
style: style,
displayMenu.addAll([
MenuEntryButton<String>(
childBuilder: (TextStyle? style) => Row(
children: [
Text(
translate('OS Password'),
style: style,
),
Expanded(
child: Align(
alignment: Alignment.centerRight,
child: IconButton(
padding: EdgeInsets.zero,
icon: const Icon(Icons.edit),
onPressed: () => showSetOSPassword(
widget.id, false, widget.ffi.dialogManager),
),
))
],
),
proc: () {
bind.sessionRefresh(id: widget.id);
showSetOSPassword(widget.id, false, widget.ffi.dialogManager);
},
dismissOnClicked: true,
));
}
displayMenu.add(MenuEntryButton<String>(
childBuilder: (TextStyle? style) => Text(
translate('OS Password'),
style: style,
),
proc: () {
showSetOSPassword(widget.id, false, widget.ffi.dialogManager);
},
dismissOnClicked: true,
));
if (!isWebDesktop) {
if (perms['keyboard'] != false && perms['clipboard'] != false) {
displayMenu.add(MenuEntryButton<String>(
childBuilder: (TextStyle? style) => Text(
translate('Paste'),
style: style,
),
proc: () {
() async {
ClipboardData? data =
await Clipboard.getData(Clipboard.kTextPlain);
if (data != null && data.text != null) {
bind.sessionInputString(id: widget.id, value: data.text ?? "");
}
}();
},
dismissOnClicked: true,
));
}
displayMenu.add(MenuEntryButton<String>(
MenuEntryButton<String>(
childBuilder: (TextStyle? style) => Text(
translate('Reset canvas'),
translate('Transfer File'),
style: style,
),
proc: () {
widget.ffi.cursorModel.reset();
connect(context, widget.id, isFileTransfer: true);
},
dismissOnClicked: true,
));
}
),
MenuEntryButton<String>(
childBuilder: (TextStyle? style) => Text(
translate('TCP Tunneling'),
style: style,
),
proc: () {
connect(context, widget.id, isTcpTunneling: true);
},
dismissOnClicked: true,
),
]);
// {handler.get_audit_server() && <li #note>{translate('Note')}</li>}
final auditServer = bind.sessionGetAuditServerSync(id: widget.id);
//if (auditServer.isNotEmpty) {
displayMenu.add(
MenuEntryButton<String>(
childBuilder: (TextStyle? style) => Text(
translate('Note'),
style: style,
),
proc: () {
showAuditDialog(widget.id, widget.ffi.dialogManager);
},
dismissOnClicked: true,
),
);
//}
displayMenu.add(MenuEntryDivider());
if (perms['keyboard'] != false) {
if (pi.platform == 'Linux' || pi.sasEnabled) {
@ -371,7 +382,24 @@ class _RemoteMenubarState extends State<RemoteMenubar> {
dismissOnClicked: true,
));
}
}
if (gFFI.ffiModel.permissions["restart"] != false &&
(pi.platform == "Linux" ||
pi.platform == "Windows" ||
pi.platform == "Mac OS")) {
displayMenu.add(MenuEntryButton<String>(
childBuilder: (TextStyle? style) => Text(
translate('Restart Remote Device'),
style: style,
),
proc: () {
showRestartRemoteDevice(pi, widget.id, gFFI.dialogManager);
},
dismissOnClicked: true,
));
}
if (perms['keyboard'] != false) {
displayMenu.add(MenuEntryButton<String>(
childBuilder: (TextStyle? style) => Text(
translate('Insert Lock'),
@ -402,17 +430,46 @@ class _RemoteMenubarState extends State<RemoteMenubar> {
}
}
if (gFFI.ffiModel.permissions["restart"] != false &&
(pi.platform == "Linux" ||
pi.platform == "Windows" ||
pi.platform == "Mac OS")) {
if (pi.version.isNotEmpty) {
displayMenu.add(MenuEntryButton<String>(
childBuilder: (TextStyle? style) => Text(
translate('Restart Remote Device'),
translate('Refresh'),
style: style,
),
proc: () {
showRestartRemoteDevice(pi, widget.id, gFFI.dialogManager);
bind.sessionRefresh(id: widget.id);
},
dismissOnClicked: true,
));
}
if (!isWebDesktop) {
// if (perms['keyboard'] != false && perms['clipboard'] != false) {
// displayMenu.add(MenuEntryButton<String>(
// childBuilder: (TextStyle? style) => Text(
// translate('Paste'),
// style: style,
// ),
// proc: () {
// () async {
// ClipboardData? data =
// await Clipboard.getData(Clipboard.kTextPlain);
// if (data != null && data.text != null) {
// bind.sessionInputString(id: widget.id, value: data.text ?? "");
// }
// }();
// },
// dismissOnClicked: true,
// ));
// }
displayMenu.add(MenuEntryButton<String>(
childBuilder: (TextStyle? style) => Text(
translate('Reset canvas'),
style: style,
),
proc: () {
widget.ffi.cursorModel.reset();
},
dismissOnClicked: true,
));
@ -684,3 +741,76 @@ void showSetOSPassword(
);
});
}
void showAuditDialog(String id, dialogManager) async {
final controller = TextEditingController();
dialogManager.show((setState, close) {
submit() {
var text = controller.text.trim();
if (text != "") {
bind.sessionSendNote(id: id, note: text);
}
close();
}
late final focusNode = FocusNode(
onKey: (FocusNode node, RawKeyEvent evt) {
if (evt.logicalKey.keyLabel == 'Enter') {
if (evt is RawKeyDownEvent) {
int pos = controller.selection.base.offset;
controller.text =
'${controller.text.substring(0, pos)}\n${controller.text.substring(pos)}';
controller.selection =
TextSelection.fromPosition(TextPosition(offset: pos + 1));
}
return KeyEventResult.handled;
}
if (evt.logicalKey.keyLabel == 'Esc') {
if (evt is RawKeyDownEvent) {
close();
}
return KeyEventResult.handled;
} else {
return KeyEventResult.ignored;
}
},
);
return CustomAlertDialog(
title: Text(translate('Note')),
content: SizedBox(
width: 250,
height: 120,
child: TextField(
autofocus: true,
keyboardType: TextInputType.multiline,
textInputAction: TextInputAction.newline,
decoration: const InputDecoration.collapsed(
hintText: "input note here",
),
// inputFormatters: [
// LengthLimitingTextInputFormatter(16),
// // FilteringTextInputFormatter(RegExp(r"[a-zA-z][a-zA-z0-9\_]*"), allow: true)
// ],
maxLines: null,
maxLength: 256,
controller: controller,
focusNode: focusNode,
)),
actions: [
TextButton(
style: flatButtonStyle,
onPressed: close,
child: Text(translate('Cancel')),
),
TextButton(
style: flatButtonStyle,
onPressed: submit,
child: Text(translate('OK')),
),
],
onSubmit: submit,
onCancel: close,
);
});
}

View File

@ -0,0 +1,28 @@
import 'package:flutter/material.dart';
import 'package:flutter_hbb/utils/multi_window_manager.dart';
/// Connect to a peer with [id].
/// If [isFileTransfer], starts a session only for file transfer.
/// If [isTcpTunneling], starts a session only for tcp tunneling.
/// If [isRDP], starts a session only for rdp.
void connect(BuildContext context, String id,
{bool isFileTransfer = false,
bool isTcpTunneling = false,
bool isRDP = false}) async {
if (id == '') return;
id = id.replaceAll(' ', '');
assert(!(isFileTransfer && isTcpTunneling && isRDP),
"more than one connect type");
FocusScopeNode currentFocus = FocusScope.of(context);
if (isFileTransfer) {
await rustDeskWinManager.newFileTransfer(id);
} else if (isTcpTunneling || isRDP) {
await rustDeskWinManager.newPortForward(id, isRDP);
} else {
await rustDeskWinManager.newRemoteDesktop(id);
}
if (!currentFocus.hasPrimaryFocus) {
currentFocus.unfocus();
}
}

View File

@ -17,15 +17,14 @@ use crate::flutter::{self, SESSIONS};
use crate::start_server;
use crate::ui_interface;
#[cfg(not(any(target_os = "android", target_os = "ios")))]
use crate::ui_interface::change_id;
use crate::ui_interface::{
check_mouse_time, check_super_user_permission, discover, forget_password, get_api_server,
get_app_name, get_async_job_status, get_connect_status, get_fav, get_id, get_lan_peers,
get_langs, get_license, get_local_option, get_mouse_time, get_option, get_options, get_peer,
get_peer_option, get_socks, get_sound_inputs, get_uuid, get_version, has_hwcodec,
has_rendezvous_service, post_request, send_to_cm, set_local_option, set_option, set_options,
set_peer_option, set_permanent_password, set_socks, store_fav, test_if_valid_server,
update_temporary_password, using_public_server,
change_id, check_mouse_time, check_super_user_permission, discover, forget_password,
get_api_server, get_app_name, get_async_job_status, get_connect_status, get_fav, get_id,
get_lan_peers, get_langs, get_license, get_local_option, get_mouse_time, get_option,
get_options, get_peer, get_peer_option, get_socks, get_sound_inputs, get_uuid, get_version,
has_hwcodec, has_rendezvous_service, post_request, send_to_cm, set_local_option, set_option,
set_options, set_peer_option, set_permanent_password, set_socks, store_fav,
test_if_valid_server, update_temporary_password, using_public_server,
};
use crate::{
client::file_trait::FileManager,
@ -810,6 +809,21 @@ pub fn session_restart_remote_device(id: String) {
}
}
pub fn session_get_audit_server_sync(id: String) -> SyncReturn<String> {
let res = if let Some(session) = SESSIONS.read().unwrap().get(&id) {
session.get_audit_server()
} else {
"".to_owned()
};
SyncReturn(res)
}
pub fn session_send_note(id: String, note: String) {
if let Some(session) = SESSIONS.read().unwrap().get(&id) {
session.send_note(note)
}
}
pub fn main_set_home_dir(home: String) {
*config::APP_HOME_DIR.write().unwrap() = home;
}