commit
6ed1c8beb1
74
flutter/lib/common/widgets/dialog.dart
Normal file
74
flutter/lib/common/widgets/dialog.dart
Normal 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,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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;
|
||||||
|
@ -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);
|
||||||
|
@ -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))
|
||||||
]))
|
]))
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
@ -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)]
|
||||||
|
@ -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();
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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");
|
||||||
|
Loading…
x
Reference in New Issue
Block a user