Merge pull request #1552 from Heap-Hop/master

Update Android
This commit is contained in:
RustDesk 2022-09-16 22:06:29 +08:00 committed by GitHub
commit 6ed1c8beb1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 430 additions and 281 deletions

View File

@ -0,0 +1,74 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import '../../common.dart';
import '../../models/platform_model.dart';
void changeIdDialog() {
var newId = "";
var msg = "";
var isInProgress = false;
TextEditingController controller = TextEditingController();
gFFI.dialogManager.show((setState, close) {
submit() async {
debugPrint("onSubmit");
newId = controller.text.trim();
setState(() {
msg = "";
isInProgress = true;
bind.mainChangeId(newId: newId);
});
var status = await bind.mainGetAsyncStatus();
while (status == " ") {
await Future.delayed(const Duration(milliseconds: 100));
status = await bind.mainGetAsyncStatus();
}
if (status.isEmpty) {
// ok
close();
return;
}
setState(() {
isInProgress = false;
msg = translate(status);
});
}
return CustomAlertDialog(
title: Text(translate("Change ID")),
content: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(translate("id_change_tip")),
const SizedBox(
height: 12.0,
),
TextField(
decoration: InputDecoration(
border: const OutlineInputBorder(),
errorText: msg.isEmpty ? null : translate(msg)),
inputFormatters: [
LengthLimitingTextInputFormatter(16),
// FilteringTextInputFormatter(RegExp(r"[a-zA-z][a-zA-z0-9\_]*"), allow: true)
],
maxLength: 16,
controller: controller,
focusNode: FocusNode()..requestFocus(),
),
const SizedBox(
height: 4.0,
),
Offstage(
offstage: !isInProgress, child: const LinearProgressIndicator())
],
),
actions: [
TextButton(onPressed: close, child: Text(translate("Cancel"))),
TextButton(onPressed: submit, child: Text(translate("OK"))),
],
onSubmit: submit,
onCancel: close,
);
});
}

View File

@ -19,6 +19,8 @@ import 'package:tray_manager/tray_manager.dart';
import 'package:url_launcher/url_launcher_string.dart'; import 'package:url_launcher/url_launcher_string.dart';
import 'package:window_manager/window_manager.dart'; import 'package:window_manager/window_manager.dart';
import '../../common/widgets/dialog.dart';
class _MenubarTheme { class _MenubarTheme {
static const Color commonColor = MyTheme.accent; static const Color commonColor = MyTheme.accent;
// kMinInteractiveDimension // kMinInteractiveDimension

View File

@ -11,6 +11,8 @@ import 'package:get/get.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:url_launcher/url_launcher_string.dart'; import 'package:url_launcher/url_launcher_string.dart';
import '../../common/widgets/dialog.dart';
const double _kTabWidth = 235; const double _kTabWidth = 235;
const double _kTabHeight = 42; const double _kTabHeight = 42;
const double _kCardFixedWidth = 560; const double _kCardFixedWidth = 560;
@ -219,17 +221,12 @@ class _GeneralState extends State<_General> {
} }
Widget hwcodec() { Widget hwcodec() {
return _futureBuilder( return Offstage(
future: bind.mainHasHwcodec(), offstage: !bind.mainHasHwcodec(),
hasData: (data) { child: _Card(title: 'Hardware Codec', children: [
return Offstage( _OptionCheckBox(context, 'Enable hardware codec', 'enable-hwcodec'),
offstage: !(data as bool), ]),
child: _Card(title: 'Hardware Codec', children: [ );
_OptionCheckBox(
context, 'Enable hardware codec', 'enable-hwcodec'),
]),
);
});
} }
Widget audio(BuildContext context) { Widget audio(BuildContext context) {
@ -1501,82 +1498,4 @@ void changeSocks5Proxy() async {
}); });
} }
void changeIdDialog() {
var newId = "";
var msg = "";
var isInProgress = false;
TextEditingController controller = TextEditingController();
gFFI.dialogManager.show((setState, close) {
submit() async {
newId = controller.text.trim();
setState(() {
msg = "";
isInProgress = true;
bind.mainChangeId(newId: newId);
});
var status = await bind.mainGetAsyncStatus();
while (status == " ") {
await Future.delayed(const Duration(milliseconds: 100));
status = await bind.mainGetAsyncStatus();
}
if (status.isEmpty) {
// ok
close();
return;
}
setState(() {
isInProgress = false;
msg = translate(status);
});
}
return CustomAlertDialog(
title: Text(translate("Change ID")),
content: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(translate("id_change_tip")),
const SizedBox(
height: 8.0,
),
Row(
children: [
const Text("ID:").marginOnly(bottom: 16.0),
const SizedBox(
width: 24.0,
),
Expanded(
child: TextField(
decoration: InputDecoration(
border: const OutlineInputBorder(),
errorText: msg.isEmpty ? null : translate(msg)),
inputFormatters: [
LengthLimitingTextInputFormatter(16),
// FilteringTextInputFormatter(RegExp(r"[a-zA-z][a-zA-z0-9\_]*"), allow: true)
],
maxLength: 16,
controller: controller,
focusNode: FocusNode()..requestFocus(),
),
),
],
),
const SizedBox(
height: 4.0,
),
Offstage(
offstage: !isInProgress, child: const LinearProgressIndicator())
],
),
actions: [
TextButton(onPressed: close, child: Text(translate("Cancel"))),
TextButton(onPressed: submit, child: Text(translate("OK"))),
],
onSubmit: submit,
onCancel: close,
);
});
}
//#endregion //#endregion

View File

@ -1,3 +1,4 @@
import 'dart:convert';
import 'dart:io'; import 'dart:io';
import 'dart:math' as math; import 'dart:math' as math;
@ -298,25 +299,35 @@ class _RemoteMenubarState extends State<RemoteMenubar> {
} }
Widget _buildDisplay(BuildContext context) { Widget _buildDisplay(BuildContext context) {
return mod_menu.PopupMenuButton( return FutureBuilder(future: () async {
padding: EdgeInsets.zero, final supportedHwcodec =
icon: const Icon( await bind.sessionSupportedHwcodec(id: widget.id);
Icons.tv, return {'supportedHwcodec': supportedHwcodec};
color: _MenubarTheme.commonColor, }(), builder: (context, snapshot) {
), if (snapshot.hasData) {
tooltip: translate('Display Settings'), return mod_menu.PopupMenuButton(
position: mod_menu.PopupMenuPosition.under, padding: EdgeInsets.zero,
itemBuilder: (BuildContext context) => _getDisplayMenu() icon: const Icon(
.map((entry) => entry.build( Icons.tv,
context, color: _MenubarTheme.commonColor,
const MenuConfig( ),
commonColor: _MenubarTheme.commonColor, tooltip: translate('Display Settings'),
height: _MenubarTheme.height, position: mod_menu.PopupMenuPosition.under,
dividerHeight: _MenubarTheme.dividerHeight, itemBuilder: (BuildContext context) => _getDisplayMenu(snapshot.data!)
))) .map((entry) => entry.build(
.expand((i) => i) context,
.toList(), const MenuConfig(
); commonColor: _MenubarTheme.commonColor,
height: _MenubarTheme.height,
dividerHeight: _MenubarTheme.dividerHeight,
)))
.expand((i) => i)
.toList(),
);
} else {
return const Offstage();
}
});
} }
Widget _buildKeyboard(BuildContext context) { Widget _buildKeyboard(BuildContext context) {
@ -532,7 +543,7 @@ class _RemoteMenubarState extends State<RemoteMenubar> {
return displayMenu; return displayMenu;
} }
List<MenuEntryBase<String>> _getDisplayMenu() { List<MenuEntryBase<String>> _getDisplayMenu(dynamic futureData) {
final displayMenu = [ final displayMenu = [
MenuEntryRadios<String>( MenuEntryRadios<String>(
text: translate('Ratio'), text: translate('Ratio'),
@ -653,33 +664,74 @@ class _RemoteMenubarState extends State<RemoteMenubar> {
} }
}), }),
MenuEntryDivider<String>(), MenuEntryDivider<String>(),
// {show_codec ? <div> ];
// MenuEntryDivider<String>(),
() { /// Show Codec Preference
final state = ShowRemoteCursorState.find(widget.id); if (bind.mainHasHwcodec()) {
return MenuEntrySwitch2<String>( final List<bool> codecs = [];
text: translate('Show remote cursor'), try {
getter: () { final Map codecsJson = jsonDecode(futureData['supportedHwcodec']);
return state; final h264 = codecsJson['h264'] ?? false;
final h265 = codecsJson['h265'] ?? false;
codecs.add(h264);
codecs.add(h265);
} finally {}
if (codecs.length == 2 && (codecs[0] || codecs[1])) {
displayMenu.add(MenuEntryRadios<String>(
text: translate('Codec Preference'),
optionsGetter: () {
final list = [
MenuEntryRadioOption(text: translate('Auto'), value: 'auto'),
MenuEntryRadioOption(text: 'VP9', value: 'vp9'),
];
if (codecs[0]) {
list.add(MenuEntryRadioOption(text: 'H264', value: 'h264'));
}
if (codecs[1]) {
list.add(MenuEntryRadioOption(text: 'H265', value: 'h265'));
}
return list;
}, },
setter: (bool v) async { curOptionGetter: () async {
state.value = v; return await bind.sessionGetOption(
await bind.sessionToggleOption( id: widget.id, arg: 'codec-preference') ??
id: widget.id, value: 'show-remote-cursor'); 'auto';
}); },
}(), optionSetter: (String oldValue, String newValue) async {
MenuEntrySwitch<String>( await bind.sessionPeerOption(
text: translate('Show quality monitor'), id: widget.id, name: "codec-preference", value: newValue);
getter: () async { bind.sessionChangePreferCodec(id: widget.id);
return bind.sessionGetToggleOptionSync( }));
id: widget.id, arg: 'show-quality-monitor'); }
}
/// Show remote cursor
displayMenu.add(() {
final state = ShowRemoteCursorState.find(widget.id);
return MenuEntrySwitch2<String>(
text: translate('Show remote cursor'),
getter: () {
return state;
}, },
setter: (bool v) async { setter: (bool v) async {
state.value = v;
await bind.sessionToggleOption( await bind.sessionToggleOption(
id: widget.id, value: 'show-quality-monitor'); id: widget.id, value: 'show-remote-cursor');
widget.ffi.qualityMonitorModel.checkShowQualityMonitor(widget.id); });
}), }());
];
/// Show quality monitor
displayMenu.add(MenuEntrySwitch<String>(
text: translate('Show quality monitor'),
getter: () async {
return bind.sessionGetToggleOptionSync(
id: widget.id, arg: 'show-quality-monitor');
},
setter: (bool v) async {
await bind.sessionToggleOption(
id: widget.id, value: 'show-quality-monitor');
widget.ffi.qualityMonitorModel.checkShowQualityMonitor(widget.id);
}));
final perms = widget.ffi.ffiModel.permissions; final perms = widget.ffi.ffiModel.permissions;
final pi = widget.ffi.ffiModel.pi; final pi = widget.ffi.ffiModel.pi;

View File

@ -1,4 +1,5 @@
import 'dart:async'; import 'dart:async';
import 'dart:convert';
import 'dart:ui' as ui; import 'dart:ui' as ui;
import 'package:flutter/gestures.dart'; import 'package:flutter/gestures.dart';
@ -1011,17 +1012,22 @@ class QualityMonitor extends StatelessWidget {
void showOptions(String id, OverlayDialogManager dialogManager) async { void showOptions(String id, OverlayDialogManager dialogManager) async {
String quality = await bind.sessionGetImageQuality(id: id) ?? 'balanced'; String quality = await bind.sessionGetImageQuality(id: id) ?? 'balanced';
if (quality == '') quality = 'balanced'; if (quality == '') quality = 'balanced';
String codec =
await bind.sessionGetOption(id: id, arg: 'codec-preference') ?? 'auto';
if (codec == '') codec = 'auto';
String viewStyle = String viewStyle =
await bind.sessionGetOption(id: id, arg: 'view-style') ?? ''; await bind.sessionGetOption(id: id, arg: 'view-style') ?? '';
var displays = <Widget>[]; var displays = <Widget>[];
final pi = gFFI.ffiModel.pi; final pi = gFFI.ffiModel.pi;
final image = gFFI.ffiModel.getConnectionImage(); final image = gFFI.ffiModel.getConnectionImage();
if (image != null) if (image != null) {
displays.add(Padding(padding: const EdgeInsets.only(top: 8), child: image)); displays.add(Padding(padding: const EdgeInsets.only(top: 8), child: image));
}
if (pi.displays.length > 1) { if (pi.displays.length > 1) {
final cur = pi.currentDisplay; final cur = pi.currentDisplay;
final children = <Widget>[]; final children = <Widget>[];
for (var i = 0; i < pi.displays.length; ++i) for (var i = 0; i < pi.displays.length; ++i) {
children.add(InkWell( children.add(InkWell(
onTap: () { onTap: () {
if (i == cur) return; if (i == cur) return;
@ -1038,6 +1044,7 @@ void showOptions(String id, OverlayDialogManager dialogManager) async {
child: Text((i + 1).toString(), child: Text((i + 1).toString(),
style: TextStyle( style: TextStyle(
color: i == cur ? Colors.white : Colors.black87)))))); color: i == cur ? Colors.white : Colors.black87))))));
}
displays.add(Padding( displays.add(Padding(
padding: const EdgeInsets.only(top: 8), padding: const EdgeInsets.only(top: 8),
child: Wrap( child: Wrap(
@ -1047,9 +1054,21 @@ void showOptions(String id, OverlayDialogManager dialogManager) async {
))); )));
} }
if (displays.isNotEmpty) { if (displays.isNotEmpty) {
displays.add(Divider(color: MyTheme.border)); displays.add(const Divider(color: MyTheme.border));
} }
final perms = gFFI.ffiModel.permissions; final perms = gFFI.ffiModel.permissions;
final hasHwcodec = bind.mainHasHwcodec();
final List<bool> codecs = [];
if (hasHwcodec) {
try {
final Map codecsJson =
jsonDecode(await bind.sessionSupportedHwcodec(id: id));
final h264 = codecsJson['h264'] ?? false;
final h265 = codecsJson['h265'] ?? false;
codecs.add(h264);
codecs.add(h265);
} finally {}
}
dialogManager.show((setState, close) { dialogManager.show((setState, close) {
final more = <Widget>[]; final more = <Widget>[];
@ -1057,50 +1076,77 @@ void showOptions(String id, OverlayDialogManager dialogManager) async {
more.add(getToggle(id, setState, 'disable-audio', 'Mute')); more.add(getToggle(id, setState, 'disable-audio', 'Mute'));
} }
if (perms['keyboard'] != false) { if (perms['keyboard'] != false) {
if (perms['clipboard'] != false) if (perms['clipboard'] != false) {
more.add( more.add(
getToggle(id, setState, 'disable-clipboard', 'Disable clipboard')); getToggle(id, setState, 'disable-clipboard', 'Disable clipboard'));
}
more.add(getToggle( more.add(getToggle(
id, setState, 'lock-after-session-end', 'Lock after session end')); id, setState, 'lock-after-session-end', 'Lock after session end'));
if (pi.platform == 'Windows') { if (pi.platform == 'Windows') {
more.add(getToggle(id, setState, 'privacy-mode', 'Privacy mode')); more.add(getToggle(id, setState, 'privacy-mode', 'Privacy mode'));
} }
} }
var setQuality = (String? value) { setQuality(String? value) {
if (value == null) return; if (value == null) return;
setState(() { setState(() {
quality = value; quality = value;
bind.sessionSetImageQuality(id: id, value: value); bind.sessionSetImageQuality(id: id, value: value);
}); });
}; }
var setViewStyle = (String? value) {
setViewStyle(String? value) {
if (value == null) return; if (value == null) return;
setState(() { setState(() {
viewStyle = value; viewStyle = value;
bind.sessionPeerOption(id: id, name: "view-style", value: value); bind
gFFI.canvasModel.updateViewStyle(); .sessionPeerOption(id: id, name: "view-style", value: value)
.then((_) => gFFI.canvasModel.updateViewStyle());
}); });
}; }
setCodec(String? value) {
if (value == null) return;
setState(() {
codec = value;
bind
.sessionPeerOption(id: id, name: "codec-preference", value: value)
.then((_) => bind.sessionChangePreferCodec(id: id));
});
}
final radios = [
getRadio('Scale original', 'original', viewStyle, setViewStyle),
getRadio('Scale adaptive', 'adaptive', viewStyle, setViewStyle),
const Divider(color: MyTheme.border),
getRadio('Good image quality', 'best', quality, setQuality),
getRadio('Balanced', 'balanced', quality, setQuality),
getRadio('Optimize reaction time', 'low', quality, setQuality),
const Divider(color: MyTheme.border)
];
if (hasHwcodec && codecs.length == 2 && (codecs[0] || codecs[1])) {
radios.addAll([
getRadio(translate('Auto'), 'auto', codec, setCodec),
getRadio('VP9', 'vp9', codec, setCodec),
]);
if (codecs[0]) {
radios.add(getRadio('H264', 'h264', codec, setCodec));
}
if (codecs[1]) {
radios.add(getRadio('H265', 'h265', codec, setCodec));
}
radios.add(const Divider(color: MyTheme.border));
}
final toggles = [
getToggle(id, setState, 'show-remote-cursor', 'Show remote cursor'),
getToggle(id, setState, 'show-quality-monitor', 'Show quality monitor'),
];
return CustomAlertDialog( return CustomAlertDialog(
title: SizedBox.shrink(),
content: Column( content: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: displays + children: displays + radios + toggles + more),
<Widget>[
getRadio('Scale Original', 'original', viewStyle, setViewStyle),
getRadio('Scale adaptive', 'adaptive', viewStyle, setViewStyle),
Divider(color: MyTheme.border),
getRadio('Good image quality', 'best', quality, setQuality),
getRadio('Balanced', 'balanced', quality, setQuality),
getRadio('Optimize reaction time', 'low', quality, setQuality),
Divider(color: MyTheme.border),
getToggle(
id, setState, 'show-remote-cursor', 'Show remote cursor'),
getToggle(id, setState, 'show-quality-monitor',
'Show quality monitor'),
] +
more),
actions: [],
contentPadding: 0, contentPadding: 0,
); );
}, clickMaskDismiss: true, backDismiss: true); }, clickMaskDismiss: true, backDismiss: true);

View File

@ -3,6 +3,7 @@ import 'package:flutter_hbb/mobile/widgets/dialog.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import '../../common.dart'; import '../../common.dart';
import '../../common/widgets/dialog.dart';
import '../../models/platform_model.dart'; import '../../models/platform_model.dart';
import '../../models/server_model.dart'; import '../../models/server_model.dart';
import 'home_page.dart'; import 'home_page.dart';
@ -12,51 +13,49 @@ class ServerPage extends StatefulWidget implements PageShape {
final title = translate("Share Screen"); final title = translate("Share Screen");
@override @override
final icon = Icon(Icons.mobile_screen_share); final icon = const Icon(Icons.mobile_screen_share);
@override @override
final appBarActions = [ final appBarActions = [
PopupMenuButton<String>( PopupMenuButton<String>(
icon: Icon(Icons.more_vert), icon: const Icon(Icons.more_vert),
itemBuilder: (context) { itemBuilder: (context) {
return [ return [
PopupMenuItem( PopupMenuItem(
child: Text(translate("Change ID")), padding: const EdgeInsets.symmetric(horizontal: 16.0),
padding: EdgeInsets.symmetric(horizontal: 16.0),
value: "changeID", value: "changeID",
enabled: false, child: Text(translate("Change ID")),
), ),
PopupMenuItem( PopupMenuItem(
child: Text(translate("Set permanent password")), padding: const 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,
child: Text(translate("Set permanent password")),
), ),
PopupMenuItem( PopupMenuItem(
child: Text(translate("Set temporary password length")), padding: const 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,
child: Text(translate("Set temporary password length")),
), ),
const PopupMenuDivider(), const PopupMenuDivider(),
PopupMenuItem( PopupMenuItem(
padding: EdgeInsets.symmetric(horizontal: 0.0), padding: const EdgeInsets.symmetric(horizontal: 0.0),
value: kUseTemporaryPassword, value: kUseTemporaryPassword,
child: Container( child: ListTile(
child: ListTile( title: Text(translate("Use temporary password")),
title: Text(translate("Use temporary password")), trailing: Icon(
trailing: Icon( Icons.check,
Icons.check, color: gFFI.serverModel.verificationMethod ==
color: gFFI.serverModel.verificationMethod == kUseTemporaryPassword
kUseTemporaryPassword ? null
? null : Colors.transparent,
: Color(0xFFFFFFFF), )),
))),
), ),
PopupMenuItem( PopupMenuItem(
padding: EdgeInsets.symmetric(horizontal: 0.0), padding: const EdgeInsets.symmetric(horizontal: 0.0),
value: kUsePermanentPassword, value: kUsePermanentPassword,
child: ListTile( child: ListTile(
title: Text(translate("Use permanent password")), title: Text(translate("Use permanent password")),
@ -65,11 +64,11 @@ class ServerPage extends StatefulWidget implements PageShape {
color: gFFI.serverModel.verificationMethod == color: gFFI.serverModel.verificationMethod ==
kUsePermanentPassword kUsePermanentPassword
? null ? null
: Color(0xFFFFFFFF), : Colors.transparent,
)), )),
), ),
PopupMenuItem( PopupMenuItem(
padding: EdgeInsets.symmetric(horizontal: 0.0), padding: const EdgeInsets.symmetric(horizontal: 0.0),
value: kUseBothPasswords, value: kUseBothPasswords,
child: ListTile( child: ListTile(
title: Text(translate("Use both passwords")), title: Text(translate("Use both passwords")),
@ -80,14 +79,14 @@ class ServerPage extends StatefulWidget implements PageShape {
gFFI.serverModel.verificationMethod != gFFI.serverModel.verificationMethod !=
kUsePermanentPassword kUsePermanentPassword
? null ? null
: Color(0xFFFFFFFF), : Colors.transparent,
)), )),
), ),
]; ];
}, },
onSelected: (value) { onSelected: (value) {
if (value == "changeID") { if (value == "changeID") {
// TODO changeIdDialog();
} else if (value == "setPermanentPassword") { } else if (value == "setPermanentPassword") {
setPermanentPasswordDialog(gFFI.dialogManager); setPermanentPasswordDialog(gFFI.dialogManager);
} else if (value == "setTemporaryPasswordLength") { } else if (value == "setTemporaryPasswordLength") {
@ -101,6 +100,8 @@ class ServerPage extends StatefulWidget implements PageShape {
}) })
]; ];
ServerPage({Key? key}) : super(key: key);
@override @override
State<StatefulWidget> createState() => _ServerPageState(); State<StatefulWidget> createState() => _ServerPageState();
} }
@ -125,9 +126,9 @@ class _ServerPageState extends State<ServerPage> {
mainAxisAlignment: MainAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start,
children: [ children: [
ServerInfo(), ServerInfo(),
PermissionChecker(), const PermissionChecker(),
ConnectionManager(), const ConnectionManager(),
SizedBox.fromSize(size: Size(0, 15.0)), SizedBox.fromSize(size: const Size(0, 15.0)),
], ],
), ),
), ),
@ -148,6 +149,8 @@ class ServerInfo extends StatelessWidget {
final model = gFFI.serverModel; final model = gFFI.serverModel;
final emptyController = TextEditingController(text: "-"); final emptyController = TextEditingController(text: "-");
ServerInfo({Key? key}) : super(key: key);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final isPermanent = model.verificationMethod == kUsePermanentPassword; final isPermanent = model.verificationMethod == kUsePermanentPassword;
@ -158,7 +161,7 @@ class ServerInfo extends StatelessWidget {
children: [ children: [
TextFormField( TextFormField(
readOnly: true, readOnly: true,
style: TextStyle( style: const TextStyle(
fontSize: 25.0, fontSize: 25.0,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
color: MyTheme.accent), color: MyTheme.accent),
@ -166,14 +169,14 @@ class ServerInfo extends StatelessWidget {
decoration: InputDecoration( decoration: InputDecoration(
icon: const Icon(Icons.perm_identity), icon: const Icon(Icons.perm_identity),
labelText: translate("ID"), labelText: translate("ID"),
labelStyle: TextStyle( labelStyle: const TextStyle(
fontWeight: FontWeight.bold, color: MyTheme.accent50), fontWeight: FontWeight.bold, color: MyTheme.accent50),
), ),
onSaved: (String? value) {}, onSaved: (String? value) {},
), ),
TextFormField( TextFormField(
readOnly: true, readOnly: true,
style: TextStyle( style: const TextStyle(
fontSize: 25.0, fontSize: 25.0,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
color: MyTheme.accent), color: MyTheme.accent),
@ -181,7 +184,7 @@ class ServerInfo extends StatelessWidget {
decoration: InputDecoration( decoration: InputDecoration(
icon: const Icon(Icons.lock), icon: const Icon(Icons.lock),
labelText: translate("Password"), labelText: translate("Password"),
labelStyle: TextStyle( labelStyle: const TextStyle(
fontWeight: FontWeight.bold, color: MyTheme.accent50), fontWeight: FontWeight.bold, color: MyTheme.accent50),
suffix: isPermanent suffix: isPermanent
? null ? null
@ -200,13 +203,13 @@ class ServerInfo extends StatelessWidget {
Center( Center(
child: Row( child: Row(
children: [ children: [
Icon(Icons.warning_amber_sharp, const Icon(Icons.warning_amber_sharp,
color: Colors.redAccent, size: 24), color: Colors.redAccent, size: 24),
SizedBox(width: 10), const SizedBox(width: 10),
Expanded( Expanded(
child: Text( child: Text(
translate("Service is not running"), translate("Service is not running"),
style: TextStyle( style: const TextStyle(
fontFamily: 'WorkSans', fontFamily: 'WorkSans',
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
fontSize: 18, fontSize: 18,
@ -215,11 +218,11 @@ class ServerInfo extends StatelessWidget {
)) ))
], ],
)), )),
SizedBox(height: 5), const SizedBox(height: 5),
Center( Center(
child: Text( child: Text(
translate("android_start_service_tip"), translate("android_start_service_tip"),
style: TextStyle(fontSize: 12, color: MyTheme.darkGray), style: const TextStyle(fontSize: 12, color: MyTheme.darkGray),
)) ))
], ],
)); ));
@ -227,8 +230,10 @@ class ServerInfo extends StatelessWidget {
} }
class PermissionChecker extends StatefulWidget { class PermissionChecker extends StatefulWidget {
const PermissionChecker({Key? key}) : super(key: key);
@override @override
_PermissionCheckerState createState() => _PermissionCheckerState(); State<PermissionChecker> createState() => _PermissionCheckerState();
} }
class _PermissionCheckerState extends State<PermissionChecker> { class _PermissionCheckerState extends State<PermissionChecker> {
@ -236,7 +241,7 @@ class _PermissionCheckerState extends State<PermissionChecker> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
final serverModel = Provider.of<ServerModel>(context); final serverModel = Provider.of<ServerModel>(context);
final hasAudioPermission = androidVersion >= 30; final hasAudioPermission = androidVersion >= 30;
final status; final String status;
if (serverModel.connectStatus == -1) { if (serverModel.connectStatus == -1) {
status = 'not_ready_status'; status = 'not_ready_status';
} else if (serverModel.connectStatus == 0) { } else if (serverModel.connectStatus == 0) {
@ -260,9 +265,9 @@ class _PermissionCheckerState extends State<PermissionChecker> {
serverModel.toggleAudio) serverModel.toggleAudio)
: Text( : Text(
"* ${translate("android_version_audio_tip")}", "* ${translate("android_version_audio_tip")}",
style: TextStyle(color: MyTheme.darkGray), style: const TextStyle(color: MyTheme.darkGray),
), ),
SizedBox(height: 8), const SizedBox(height: 8),
Row( Row(
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center,
children: [ children: [
@ -273,11 +278,11 @@ class _PermissionCheckerState extends State<PermissionChecker> {
style: ButtonStyle( style: ButtonStyle(
backgroundColor: backgroundColor:
MaterialStateProperty.all(Colors.red)), MaterialStateProperty.all(Colors.red)),
icon: Icon(Icons.stop), icon: const Icon(Icons.stop),
onPressed: serverModel.toggleService, onPressed: serverModel.toggleService,
label: Text(translate("Stop service"))) label: Text(translate("Stop service")))
: ElevatedButton.icon( : ElevatedButton.icon(
icon: Icon(Icons.play_arrow), icon: const Icon(Icons.play_arrow),
onPressed: serverModel.toggleService, onPressed: serverModel.toggleService,
label: Text(translate("Start Service")))), label: Text(translate("Start Service")))),
Expanded( Expanded(
@ -287,8 +292,8 @@ class _PermissionCheckerState extends State<PermissionChecker> {
Expanded( Expanded(
flex: 0, flex: 0,
child: Padding( child: Padding(
padding: padding: const EdgeInsets.only(
EdgeInsets.only(left: 20, right: 5), left: 20, right: 5),
child: Icon(Icons.circle, child: Icon(Icons.circle,
color: serverModel.connectStatus > 0 color: serverModel.connectStatus > 0
? Colors.greenAccent ? Colors.greenAccent
@ -297,12 +302,12 @@ class _PermissionCheckerState extends State<PermissionChecker> {
Expanded( Expanded(
child: Text(translate(status), child: Text(translate(status),
softWrap: true, softWrap: true,
style: TextStyle( style: const TextStyle(
fontSize: 14.0, fontSize: 14.0,
color: MyTheme.accent50))) color: MyTheme.accent50)))
], ],
) )
: SizedBox.shrink()) : const SizedBox.shrink())
], ],
), ),
], ],
@ -311,7 +316,8 @@ class _PermissionCheckerState extends State<PermissionChecker> {
} }
class PermissionRow extends StatelessWidget { class PermissionRow extends StatelessWidget {
PermissionRow(this.name, this.isOk, this.onPressed); const PermissionRow(this.name, this.isOk, this.onPressed, {Key? key})
: super(key: key);
final String name; final String name;
final bool isOk; final bool isOk;
@ -327,8 +333,8 @@ class PermissionRow extends StatelessWidget {
fit: BoxFit.scaleDown, fit: BoxFit.scaleDown,
alignment: Alignment.centerLeft, alignment: Alignment.centerLeft,
child: Text(name, child: Text(name,
style: style: const TextStyle(
TextStyle(fontSize: 16.0, color: MyTheme.accent50)))), fontSize: 16.0, color: MyTheme.accent50)))),
Expanded( Expanded(
flex: 2, flex: 2,
child: FittedBox( child: FittedBox(
@ -347,7 +353,7 @@ class PermissionRow extends StatelessWidget {
onPressed: onPressed, onPressed: onPressed,
child: Text( child: Text(
translate(isOk ? "CLOSE" : "OPEN"), translate(isOk ? "CLOSE" : "OPEN"),
style: TextStyle(fontWeight: FontWeight.bold), style: const TextStyle(fontWeight: FontWeight.bold),
)))), )))),
], ],
); );
@ -355,6 +361,8 @@ class PermissionRow extends StatelessWidget {
} }
class ConnectionManager extends StatelessWidget { class ConnectionManager extends StatelessWidget {
const ConnectionManager({Key? key}) : super(key: key);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final serverModel = Provider.of<ServerModel>(context); final serverModel = Provider.of<ServerModel>(context);
@ -377,7 +385,7 @@ class ConnectionManager extends StatelessWidget {
Expanded( Expanded(
flex: -1, flex: -1,
child: client.isFileTransfer || !client.authorized child: client.isFileTransfer || !client.authorized
? SizedBox.shrink() ? const SizedBox.shrink()
: IconButton( : IconButton(
onPressed: () { onPressed: () {
gFFI.chatModel.changeCurrentID(client.id); gFFI.chatModel.changeCurrentID(client.id);
@ -388,24 +396,24 @@ class ConnectionManager extends StatelessWidget {
bar.onTap!(1); bar.onTap!(1);
} }
}, },
icon: Icon( icon: const Icon(
Icons.chat, Icons.chat,
color: MyTheme.accent80, color: MyTheme.accent80,
))) )))
], ],
), ),
client.authorized client.authorized
? SizedBox.shrink() ? const SizedBox.shrink()
: Text( : Text(
translate("android_new_connection_tip"), translate("android_new_connection_tip"),
style: TextStyle(color: Colors.black54), style: const TextStyle(color: Colors.black54),
), ),
client.authorized client.authorized
? ElevatedButton.icon( ? ElevatedButton.icon(
style: ButtonStyle( style: ButtonStyle(
backgroundColor: backgroundColor:
MaterialStateProperty.all(Colors.red)), MaterialStateProperty.all(Colors.red)),
icon: Icon(Icons.close), icon: const Icon(Icons.close),
onPressed: () { onPressed: () {
bind.cmCloseConnection(connId: client.id); bind.cmCloseConnection(connId: client.id);
gFFI.invokeMethod( gFFI.invokeMethod(
@ -418,7 +426,7 @@ class ConnectionManager extends StatelessWidget {
onPressed: () { onPressed: () {
serverModel.sendLoginResponse(client, false); serverModel.sendLoginResponse(client, false);
}), }),
SizedBox(width: 20), const SizedBox(width: 20),
ElevatedButton( ElevatedButton(
child: Text(translate("Accept")), child: Text(translate("Accept")),
onPressed: () { onPressed: () {
@ -432,7 +440,8 @@ class ConnectionManager extends StatelessWidget {
} }
class PaddingCard extends StatelessWidget { class PaddingCard extends StatelessWidget {
PaddingCard({required this.child, this.title, this.titleIcon}); const PaddingCard({Key? key, required this.child, this.title, this.titleIcon})
: super(key: key);
final String? title; final String? title;
final IconData? titleIcon; final IconData? titleIcon;
@ -445,18 +454,18 @@ class PaddingCard extends StatelessWidget {
children.insert( children.insert(
0, 0,
Padding( Padding(
padding: EdgeInsets.symmetric(vertical: 5.0), padding: const EdgeInsets.symmetric(vertical: 5.0),
child: Row( child: Row(
children: [ children: [
titleIcon != null titleIcon != null
? Padding( ? Padding(
padding: EdgeInsets.only(right: 10), padding: const EdgeInsets.only(right: 10),
child: Icon(titleIcon, child: Icon(titleIcon,
color: MyTheme.accent80, size: 30)) color: MyTheme.accent80, size: 30))
: SizedBox.shrink(), : const SizedBox.shrink(),
Text( Text(
title!, title!,
style: TextStyle( style: const TextStyle(
fontFamily: 'WorkSans', fontFamily: 'WorkSans',
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
fontSize: 20, fontSize: 20,
@ -466,12 +475,13 @@ class PaddingCard extends StatelessWidget {
], ],
))); )));
} }
return Container( return SizedBox(
width: double.maxFinite, width: double.maxFinite,
child: Card( child: Card(
margin: EdgeInsets.fromLTRB(15.0, 15.0, 15.0, 0), margin: const EdgeInsets.fromLTRB(15.0, 15.0, 15.0, 0),
child: Padding( child: Padding(
padding: EdgeInsets.symmetric(vertical: 15.0, horizontal: 30.0), padding:
const EdgeInsets.symmetric(vertical: 15.0, horizontal: 30.0),
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: children, children: children,
@ -483,27 +493,29 @@ class PaddingCard extends StatelessWidget {
Widget clientInfo(Client client) { Widget clientInfo(Client client) {
return Padding( return Padding(
padding: EdgeInsets.symmetric(vertical: 8), padding: const EdgeInsets.symmetric(vertical: 8),
child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
Row( Row(
children: [ children: [
Expanded( Expanded(
flex: -1, flex: -1,
child: Padding( child: Padding(
padding: EdgeInsets.only(right: 12), padding: const EdgeInsets.only(right: 12),
child: CircleAvatar( child: CircleAvatar(
child: Text(client.name[0]), backgroundColor: MyTheme.border,
backgroundColor: MyTheme.border))), child: Text(client.name[0])))),
Expanded( Expanded(
child: Column( child: Column(
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: const TextStyle(
SizedBox(width: 8), color: MyTheme.idColor, fontSize: 18)),
const SizedBox(width: 8),
Text(client.peerId, Text(client.peerId,
style: TextStyle(color: MyTheme.idColor, fontSize: 10)) style:
const TextStyle(color: MyTheme.idColor, fontSize: 10))
])) ]))
], ],
), ),

View File

@ -50,6 +50,7 @@ lazy_static::lazy_static! {
pub static ref PROD_RENDEZVOUS_SERVER: Arc<RwLock<String>> = Default::default(); pub static ref PROD_RENDEZVOUS_SERVER: Arc<RwLock<String>> = Default::default();
pub static ref APP_NAME: Arc<RwLock<String>> = Arc::new(RwLock::new("RustDesk".to_owned())); pub static ref APP_NAME: Arc<RwLock<String>> = Arc::new(RwLock::new("RustDesk".to_owned()));
static ref KEY_PAIR: Arc<Mutex<Option<(Vec<u8>, Vec<u8>)>>> = Default::default(); static ref KEY_PAIR: Arc<Mutex<Option<(Vec<u8>, Vec<u8>)>>> = Default::default();
static ref HW_CODEC_CONFIG: Arc<RwLock<HwCodecConfig>> = Arc::new(RwLock::new(HwCodecConfig::load()));
} }
// #[cfg(any(target_os = "android", target_os = "ios"))] // #[cfg(any(target_os = "android", target_os = "ios"))]
@ -1023,6 +1024,16 @@ impl HwCodecConfig {
pub fn remove() { pub fn remove() {
std::fs::remove_file(Config::file_("_hwcodec")).ok(); std::fs::remove_file(Config::file_("_hwcodec")).ok();
} }
/// refresh current global HW_CODEC_CONFIG, usually uesd after HwCodecConfig::remove()
pub fn refresh() {
*HW_CODEC_CONFIG.write().unwrap() = HwCodecConfig::load();
log::debug!("HW_CODEC_CONFIG refreshed successfully");
}
pub fn get() -> HwCodecConfig {
return HW_CODEC_CONFIG.read().unwrap().clone();
}
} }
#[cfg(test)] #[cfg(test)]

View File

@ -267,7 +267,7 @@ impl HwDecoderImage<'_> {
} }
fn get_config(k: &str) -> ResultType<CodecInfos> { fn get_config(k: &str) -> ResultType<CodecInfos> {
let v = HwCodecConfig::load() let v = HwCodecConfig::get()
.options .options
.get(k) .get(k)
.unwrap_or(&"".to_owned()) .unwrap_or(&"".to_owned())
@ -323,7 +323,8 @@ pub fn check_config_process(force_reset: bool) {
std::process::Command::new(exe) std::process::Command::new(exe)
.arg("--check-hwcodec-config") .arg("--check-hwcodec-config")
.status() .status()
.ok() .ok();
HwCodecConfig::refresh();
}); });
}; };
} }

View File

@ -17,15 +17,15 @@ use crate::flutter::{self, SESSIONS};
use crate::start_server; use crate::start_server;
use crate::ui_interface; use crate::ui_interface;
#[cfg(not(any(target_os = "android", target_os = "ios")))] #[cfg(not(any(target_os = "android", target_os = "ios")))]
use crate::ui_interface::{change_id, get_sound_inputs}; use crate::ui_interface::get_sound_inputs;
use crate::ui_interface::{ use crate::ui_interface::{
check_mouse_time, check_super_user_permission, discover, forget_password, get_api_server, change_id, check_mouse_time, check_super_user_permission, discover, forget_password,
get_app_name, get_async_job_status, get_connect_status, get_fav, get_id, get_lan_peers, get_api_server, get_app_name, get_async_job_status, get_connect_status, get_fav, get_id,
get_langs, get_license, get_local_option, get_mouse_time, get_option, get_options, get_peer, get_lan_peers, get_langs, get_license, get_local_option, get_mouse_time, get_option,
get_peer_option, get_socks, get_uuid, get_version, has_hwcodec, has_rendezvous_service, get_options, get_peer, get_peer_option, get_socks, get_uuid, get_version, has_hwcodec,
post_request, send_to_cm, set_local_option, set_option, set_options, set_peer_option, has_rendezvous_service, post_request, send_to_cm, set_local_option, set_option, set_options,
set_permanent_password, set_socks, store_fav, test_if_valid_server, update_temporary_password, set_peer_option, set_permanent_password, set_socks, store_fav, test_if_valid_server,
using_public_server, update_temporary_password, using_public_server,
}; };
use crate::{ use crate::{
client::file_trait::FileManager, client::file_trait::FileManager,
@ -426,7 +426,6 @@ pub fn main_get_sound_inputs() -> Vec<String> {
} }
pub fn main_change_id(new_id: String) { pub fn main_change_id(new_id: String) {
#[cfg(not(any(target_os = "android", target_os = "ios")))]
change_id(new_id) change_id(new_id)
} }
@ -754,8 +753,8 @@ pub fn main_remove_peer(id: String) {
PeerConfig::remove(&id); PeerConfig::remove(&id);
} }
pub fn main_has_hwcodec() -> bool { pub fn main_has_hwcodec() -> SyncReturn<bool> {
has_hwcodec() SyncReturn(has_hwcodec())
} }
pub fn session_send_mouse(id: String, msg: String) { pub fn session_send_mouse(id: String, msg: String) {
@ -816,6 +815,22 @@ pub fn session_send_note(id: String, note: String) {
} }
} }
pub fn session_supported_hwcodec(id: String) -> String {
if let Some(session) = SESSIONS.read().unwrap().get(&id) {
let (h264, h265) = session.supported_hwcodec();
let msg = HashMap::from([("h264", h264), ("h265", h265)]);
serde_json::ser::to_string(&msg).unwrap_or("".to_owned())
} else {
String::new()
}
}
pub fn session_change_prefer_codec(id: String) {
if let Some(session) = SESSIONS.read().unwrap().get(&id) {
session.change_prefer_codec();
}
}
pub fn main_set_home_dir(home: String) { pub fn main_set_home_dir(home: String) {
*config::APP_HOME_DIR.write().unwrap() = home; *config::APP_HOME_DIR.write().unwrap() = home;
} }

View File

@ -28,6 +28,7 @@ use hbb_common::{
use crate::clipboard_file::*; use crate::clipboard_file::*;
use crate::{ use crate::{
client::*, client::*,
ui_interface::has_hwcodec,
ui_session_interface::{InvokeUiSession, Session}, ui_session_interface::{InvokeUiSession, Session},
}; };
@ -440,6 +441,10 @@ impl SciterSession {
v v
} }
fn has_hwcodec(&self) -> bool {
has_hwcodec()
}
pub fn t(&self, name: String) -> String { pub fn t(&self, name: String) -> String {
crate::client::translate(name) crate::client::translate(name)
} }
@ -449,27 +454,11 @@ impl SciterSession {
} }
fn supported_hwcodec(&self) -> Value { fn supported_hwcodec(&self) -> Value {
#[cfg(feature = "hwcodec")] let (h264, h265) = self.0.supported_hwcodec();
{ let mut v = Value::array(0);
let mut v = Value::array(0); v.push(h264);
let decoder = scrap::codec::Decoder::video_codec_state(&self.id); v.push(h265);
let mut h264 = decoder.score_h264 > 0; v
let mut h265 = decoder.score_h265 > 0;
if let Some((encoding_264, encoding_265)) = self.lc.read().unwrap().supported_encoding {
h264 = h264 && encoding_264;
h265 = h265 && encoding_265;
}
v.push(h264);
v.push(h265);
v
}
#[cfg(not(feature = "hwcodec"))]
{
let mut v = Value::array(0);
v.push(false);
v.push(false);
v
}
} }
fn save_size(&mut self, x: i32, y: i32, w: i32, h: i32) { fn save_size(&mut self, x: i32, y: i32, w: i32, h: i32) {
@ -721,4 +710,4 @@ pub fn make_fd(id: i32, entries: &Vec<FileEntry>, only_count: bool) -> Value {
m.set_item("num_entries", entries.len() as i32); m.set_item("num_entries", entries.len() as i32);
m.set_item("total_size", n as f64); m.set_item("total_size", n as f64);
m m
} }

View File

@ -687,7 +687,6 @@ pub fn open_url(url: String) {
} }
#[inline] #[inline]
#[cfg(not(any(target_os = "android", target_os = "ios")))]
pub fn change_id(id: String) { pub fn change_id(id: String) {
*ASYNC_JOB_STATUS.lock().unwrap() = " ".to_owned(); *ASYNC_JOB_STATUS.lock().unwrap() = " ".to_owned();
let old_id = get_id(); let old_id = get_id();
@ -744,9 +743,9 @@ pub fn get_api_server() -> String {
#[inline] #[inline]
pub fn has_hwcodec() -> bool { pub fn has_hwcodec() -> bool {
#[cfg(not(feature = "hwcodec"))] #[cfg(not(any(feature = "hwcodec", feature = "mediacodec")))]
return false; return false;
#[cfg(feature = "hwcodec")] #[cfg(any(feature = "hwcodec", feature = "mediacodec"))]
return true; return true;
} }
@ -864,17 +863,27 @@ pub(crate) async fn send_to_cm(data: &ipc::Data) {
const INVALID_FORMAT: &'static str = "Invalid format"; const INVALID_FORMAT: &'static str = "Invalid format";
const UNKNOWN_ERROR: &'static str = "Unknown error"; const UNKNOWN_ERROR: &'static str = "Unknown error";
#[cfg(not(any(target_os = "android", target_os = "ios")))]
#[tokio::main(flavor = "current_thread")] #[tokio::main(flavor = "current_thread")]
async fn change_id_(id: String, old_id: String) -> &'static str { async fn change_id_(id: String, old_id: String) -> &'static str {
if !hbb_common::is_valid_custom_id(&id) { if !hbb_common::is_valid_custom_id(&id) {
return INVALID_FORMAT; return INVALID_FORMAT;
} }
#[cfg(not(any(target_os = "android", target_os = "ios")))]
let uuid = machine_uid::get().unwrap_or("".to_owned()); let uuid = machine_uid::get().unwrap_or("".to_owned());
#[cfg(any(target_os = "android", target_os = "ios"))]
let uuid = base64::encode(hbb_common::get_uuid());
if uuid.is_empty() { if uuid.is_empty() {
log::error!("Failed to change id, uuid is_empty");
return UNKNOWN_ERROR; return UNKNOWN_ERROR;
} }
#[cfg(not(any(target_os = "android", target_os = "ios")))]
let rendezvous_servers = crate::ipc::get_rendezvous_servers(1_000).await; let rendezvous_servers = crate::ipc::get_rendezvous_servers(1_000).await;
#[cfg(any(target_os = "android", target_os = "ios"))]
let rendezvous_servers = Config::get_rendezvous_servers();
let mut futs = Vec::new(); let mut futs = Vec::new();
let err: Arc<Mutex<&str>> = Default::default(); let err: Arc<Mutex<&str>> = Default::default();
for rendezvous_server in rendezvous_servers { for rendezvous_server in rendezvous_servers {
@ -892,7 +901,13 @@ async fn change_id_(id: String, old_id: String) -> &'static str {
join_all(futs).await; join_all(futs).await;
let err = *err.lock().unwrap(); let err = *err.lock().unwrap();
if err.is_empty() { if err.is_empty() {
#[cfg(not(any(target_os = "android", target_os = "ios")))]
crate::ipc::set_config_async("id", id.to_owned()).await.ok(); crate::ipc::set_config_async("id", id.to_owned()).await.ok();
#[cfg(any(target_os = "android", target_os = "ios"))]
{
Config::set_key_confirmed(false);
Config::set_id(&id);
}
} }
err err
} }
@ -937,6 +952,9 @@ async fn check_id(
register_pk_response::Result::NOT_SUPPORT => { register_pk_response::Result::NOT_SUPPORT => {
return "server_not_support"; return "server_not_support";
} }
register_pk_response::Result::SERVER_ERROR => {
return "Server error";
}
register_pk_response::Result::INVALID_ID_FORMAT => { register_pk_response::Result::INVALID_ID_FORMAT => {
return INVALID_FORMAT; return INVALID_FORMAT;
} }

View File

@ -11,9 +11,9 @@ use async_trait::async_trait;
use hbb_common::config::{Config, LocalConfig, PeerConfig}; use hbb_common::config::{Config, LocalConfig, PeerConfig};
use hbb_common::rendezvous_proto::ConnType; use hbb_common::rendezvous_proto::ConnType;
use hbb_common::tokio::{self, sync::mpsc}; use hbb_common::tokio::{self, sync::mpsc};
use rdev::{Event, EventType::*, Key as RdevKey, KeyboardState};
#[cfg(not(any(target_os = "android", target_os = "ios")))] #[cfg(not(any(target_os = "android", target_os = "ios")))]
use rdev::Keyboard as RdevKeyboard; use rdev::Keyboard as RdevKeyboard;
use rdev::{Event, EventType::*, Key as RdevKey, KeyboardState};
use hbb_common::{allow_err, message_proto::*}; use hbb_common::{allow_err, message_proto::*};
use hbb_common::{fs, get_version_number, log, Stream}; use hbb_common::{fs, get_version_number, log, Stream};
@ -136,11 +136,19 @@ impl<T: InvokeUiSession> Session<T> {
true true
} }
pub fn has_hwcodec(&self) -> bool { pub fn supported_hwcodec(&self) -> (bool, bool) {
#[cfg(not(feature = "hwcodec"))] #[cfg(any(feature = "hwcodec", feature = "mediacodec"))]
return false; {
#[cfg(feature = "hwcodec")] let decoder = scrap::codec::Decoder::video_codec_state(&self.id);
return true; let mut h264 = decoder.score_h264 > 0;
let mut h265 = decoder.score_h265 > 0;
if let Some((encoding_264, encoding_265)) = self.lc.read().unwrap().supported_encoding {
h264 = h264 && encoding_264;
h265 = h265 && encoding_265;
}
return (h264, h265);
}
(false, false)
} }
pub fn change_prefer_codec(&self) { pub fn change_prefer_codec(&self) {
@ -658,18 +666,20 @@ impl<T: InvokeUiSession> Session<T> {
} }
self.map_keyboard_mode(down_or_up, key, Some(evt)); self.map_keyboard_mode(down_or_up, key, Some(evt));
} }
KeyboardMode::Legacy => { KeyboardMode::Legacy =>
{
#[cfg(not(any(target_os = "android", target_os = "ios")))] #[cfg(not(any(target_os = "android", target_os = "ios")))]
self.legacy_keyboard_mode(down_or_up, key, evt) self.legacy_keyboard_mode(down_or_up, key, evt)
}, }
KeyboardMode::Translate => { KeyboardMode::Translate => {
#[cfg(not(any(target_os = "android", target_os = "ios")))] #[cfg(not(any(target_os = "android", target_os = "ios")))]
self.translate_keyboard_mode(down_or_up, key, evt); self.translate_keyboard_mode(down_or_up, key, evt);
} }
_ => { _ =>
{
#[cfg(not(any(target_os = "android", target_os = "ios")))] #[cfg(not(any(target_os = "android", target_os = "ios")))]
self.legacy_keyboard_mode(down_or_up, key, evt) self.legacy_keyboard_mode(down_or_up, key, evt)
}, }
} }
} }
@ -1178,7 +1188,7 @@ impl<T: InvokeUiSession> Session<T> {
if self.is_port_forward() || self.is_file_transfer() { if self.is_port_forward() || self.is_file_transfer() {
return; return;
} }
if !KEYBOARD_HOOKED.load(Ordering::SeqCst){ if !KEYBOARD_HOOKED.load(Ordering::SeqCst) {
return; return;
} }
log::info!("keyboard hooked"); log::info!("keyboard hooked");