fix mobile features

This commit is contained in:
csf 2022-08-05 20:29:43 +08:00
parent a22daccb0c
commit 0ef1659b87
6 changed files with 89 additions and 114 deletions

View File

@ -352,6 +352,23 @@ RadioListTile<T> getRadio<T>(
); );
} }
CheckboxListTile getToggle(
String id, void Function(void Function()) setState, option, name) {
final opt = bind.getSessionToggleOptionSync(id: id, arg: option);
return CheckboxListTile(
value: opt,
onChanged: (v) {
setState(() {
bind.sessionToggleOption(id: id, value: option);
});
if (option == "show-quality-monitor") {
gFFI.qualityMonitorModel.checkShowQualityMonitor(id);
}
},
dense: true,
title: Text(translate(name)));
}
/// find ffi, tag is Remote ID /// find ffi, tag is Remote ID
/// for session specific usage /// for session specific usage
FFI ffi(String? tag) { FFI ffi(String? tag) {

View File

@ -887,32 +887,6 @@ class ImagePainter extends CustomPainter {
} }
} }
CheckboxListTile getToggle(
String id, void Function(void Function()) setState, option, name) {
final opt = bind.getSessionToggleOptionSync(id: id, arg: option);
return CheckboxListTile(
value: opt,
onChanged: (v) {
setState(() {
bind.sessionToggleOption(id: id, value: option);
});
},
dense: true,
title: Text(translate(name)));
}
RadioListTile<String> getRadio(String name, String toValue, String curValue,
void Function(String?) onChange) {
return RadioListTile<String>(
controlAffinity: ListTileControlAffinity.trailing,
title: Text(translate(name)),
value: toValue,
groupValue: curValue,
onChanged: onChange,
dense: true,
);
}
void showOptions(String id) async { void showOptions(String id) async {
String quality = await bind.getSessionImageQuality(id: id) ?? 'balanced'; String quality = await bind.getSessionImageQuality(id: id) ?? 'balanced';
if (quality == '') quality = 'balanced'; if (quality == '') quality = 'balanced';

View File

@ -12,10 +12,10 @@ abstract class PageShape extends Widget {
final List<Widget> appBarActions = []; final List<Widget> appBarActions = [];
} }
final homeKey = GlobalKey<_HomePageState>();
class HomePage extends StatefulWidget { class HomePage extends StatefulWidget {
HomePage({Key? key}) : super(key: key); static final homeKey = GlobalKey<_HomePageState>();
HomePage() : super(key: homeKey);
@override @override
_HomePageState createState() => _HomePageState(); _HomePageState createState() => _HomePageState();

View File

@ -12,6 +12,7 @@ import 'package:wakelock/wakelock.dart';
import '../../common.dart'; import '../../common.dart';
import '../../models/model.dart'; import '../../models/model.dart';
import '../../models/platform_model.dart';
import '../widgets/dialog.dart'; import '../widgets/dialog.dart';
import '../widgets/gestures.dart'; import '../widgets/gestures.dart';
import '../widgets/overlay.dart'; import '../widgets/overlay.dart';
@ -135,7 +136,7 @@ class _RemotePageState extends State<RemotePage> {
if (newValue.length > common) { if (newValue.length > common) {
var s = newValue.substring(common); var s = newValue.substring(common);
if (s.length > 1) { if (s.length > 1) {
gFFI.setByName('input_string', s); bind.sessionInputString(id: widget.id, value: s);
} else { } else {
inputChar(s); inputChar(s);
} }
@ -169,11 +170,11 @@ class _RemotePageState extends State<RemotePage> {
content == '' || content == '' ||
content == '【】')) { content == '【】')) {
// can not only input content[0], because when input ], [ are also auo insert, which cause ] never be input // can not only input content[0], because when input ], [ are also auo insert, which cause ] never be input
gFFI.setByName('input_string', content); bind.sessionInputString(id: widget.id, value: content);
openKeyboard(); openKeyboard();
return; return;
} }
gFFI.setByName('input_string', content); bind.sessionInputString(id: widget.id, value: content);
} else { } else {
inputChar(content); inputChar(content);
} }
@ -409,7 +410,7 @@ class _RemotePageState extends State<RemotePage> {
icon: Icon(Icons.tv), icon: Icon(Icons.tv),
onPressed: () { onPressed: () {
setState(() => _showEdit = false); setState(() => _showEdit = false);
showOptions(); showOptions(widget.id);
}, },
) )
] + ] +
@ -461,7 +462,7 @@ class _RemotePageState extends State<RemotePage> {
icon: Icon(Icons.more_vert), icon: Icon(Icons.more_vert),
onPressed: () { onPressed: () {
setState(() => _showEdit = false); setState(() => _showEdit = false);
showActions(); showActions(widget.id);
}, },
), ),
]), ]),
@ -573,7 +574,7 @@ class _RemotePageState extends State<RemotePage> {
}, },
onTwoFingerScaleEnd: (d) { onTwoFingerScaleEnd: (d) {
_scale = 1; _scale = 1;
gFFI.setByName('peer_option', '{"name": "view-style", "value": ""}'); bind.sessionPeerOption(id: widget.id, name: "view-style", value: "");
}, },
onThreeFingerVerticalDragUpdate: gFFI.ffiModel.isPeerAndroid onThreeFingerVerticalDragUpdate: gFFI.ffiModel.isPeerAndroid
? null ? null
@ -620,8 +621,9 @@ class _RemotePageState extends State<RemotePage> {
Widget getBodyForDesktopWithListener(bool keyboard) { Widget getBodyForDesktopWithListener(bool keyboard) {
var paints = <Widget>[ImagePaint()]; var paints = <Widget>[ImagePaint()];
if (keyboard || final cursor = bind.getSessionToggleOptionSync(
gFFI.getByName('toggle_option', 'show-remote-cursor') == 'true') { id: widget.id, arg: 'show-remote-cursor');
if (keyboard || cursor) {
paints.add(CursorPaint()); paints.add(CursorPaint());
} }
return Container( return Container(
@ -649,7 +651,7 @@ class _RemotePageState extends State<RemotePage> {
return out; return out;
} }
void showActions() { void showActions(String id) async {
final size = MediaQuery.of(context).size; final size = MediaQuery.of(context).size;
final x = 120.0; final x = 120.0;
final y = size.height; final y = size.height;
@ -668,7 +670,7 @@ class _RemotePageState extends State<RemotePage> {
style: flatButtonStyle, style: flatButtonStyle,
onPressed: () { onPressed: () {
Navigator.pop(context); Navigator.pop(context);
showSetOSPassword(false); showSetOSPassword(id, false);
}, },
child: Icon(Icons.edit, color: MyTheme.accent), child: Icon(Icons.edit, color: MyTheme.accent),
) )
@ -691,7 +693,8 @@ class _RemotePageState extends State<RemotePage> {
more.add(PopupMenuItem<String>( more.add(PopupMenuItem<String>(
child: Text(translate('Insert Lock')), value: 'lock')); child: Text(translate('Insert Lock')), value: 'lock'));
if (pi.platform == 'Windows' && if (pi.platform == 'Windows' &&
gFFI.getByName('toggle_option', 'privacy-mode') != 'true') { await bind.getSessionToggleOption(id: id, arg: 'privacy-mode') !=
true) {
more.add(PopupMenuItem<String>( more.add(PopupMenuItem<String>(
child: Text(translate((gFFI.ffiModel.inputBlocked ? 'Unb' : 'B') + child: Text(translate((gFFI.ffiModel.inputBlocked ? 'Unb' : 'B') +
'lock user input')), 'lock user input')),
@ -713,28 +716,29 @@ class _RemotePageState extends State<RemotePage> {
elevation: 8, elevation: 8,
); );
if (value == 'cad') { if (value == 'cad') {
gFFI.setByName('ctrl_alt_del'); bind.sessionCtrlAltDel(id: widget.id);
} else if (value == 'lock') { } else if (value == 'lock') {
gFFI.setByName('lock_screen'); bind.sessionLockScreen(id: widget.id);
} else if (value == 'block-input') { } else if (value == 'block-input') {
gFFI.setByName('toggle_option', bind.sessionToggleOption(
(gFFI.ffiModel.inputBlocked ? 'un' : '') + 'block-input'); id: widget.id,
value: (gFFI.ffiModel.inputBlocked ? 'un' : '') + 'block-input');
gFFI.ffiModel.inputBlocked = !gFFI.ffiModel.inputBlocked; gFFI.ffiModel.inputBlocked = !gFFI.ffiModel.inputBlocked;
} else if (value == 'refresh') { } else if (value == 'refresh') {
gFFI.setByName('refresh'); bind.sessionRefresh(id: widget.id);
} else if (value == 'paste') { } else if (value == 'paste') {
() async { () async {
ClipboardData? data = await Clipboard.getData(Clipboard.kTextPlain); ClipboardData? data = await Clipboard.getData(Clipboard.kTextPlain);
if (data != null && data.text != null) { if (data != null && data.text != null) {
gFFI.setByName('input_string', '${data.text}'); bind.sessionInputString(id: widget.id, value: data.text ?? "");
} }
}(); }();
} else if (value == 'enter_os_password') { } else if (value == 'enter_os_password') {
var password = gFFI.getByName('peer_option', "os-password"); var password = await bind.getSessionOption(id: id, arg: "os-password");
if (password != "") { if (password != null) {
gFFI.setByName('input_os_password', password); bind.sessionInputOsPassword(id: widget.id, value: password);
} else { } else {
showSetOSPassword(true); showSetOSPassword(id, true);
} }
} else if (value == 'reset_canvas') { } else if (value == 'reset_canvas') {
gFFI.cursorModel.reset(); gFFI.cursorModel.reset();
@ -762,8 +766,8 @@ class _RemotePageState extends State<RemotePage> {
onTouchModeChange: (t) { onTouchModeChange: (t) {
gFFI.ffiModel.toggleTouchMode(); gFFI.ffiModel.toggleTouchMode();
final v = gFFI.ffiModel.touchMode ? 'Y' : ''; final v = gFFI.ffiModel.touchMode ? 'Y' : '';
gFFI.setByName('peer_option', bind.sessionPeerOption(
'{"name": "touch-mode", "value": "$v"}'); id: widget.id, name: "touch", value: v);
})); }));
})); }));
} }
@ -978,23 +982,23 @@ class QualityMonitor extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text( Text(
"Speed: ${qualityMonitorModel.data.speed}", "Speed: ${qualityMonitorModel.data.speed ?? ''}",
style: TextStyle(color: MyTheme.grayBg), style: TextStyle(color: MyTheme.grayBg),
), ),
Text( Text(
"FPS: ${qualityMonitorModel.data.fps}", "FPS: ${qualityMonitorModel.data.fps ?? ''}",
style: TextStyle(color: MyTheme.grayBg), style: TextStyle(color: MyTheme.grayBg),
), ),
Text( Text(
"Delay: ${qualityMonitorModel.data.delay} ms", "Delay: ${qualityMonitorModel.data.delay ?? ''} ms",
style: TextStyle(color: MyTheme.grayBg), style: TextStyle(color: MyTheme.grayBg),
), ),
Text( Text(
"Target Bitrate: ${qualityMonitorModel.data.targetBitrate}kb", "Target Bitrate: ${qualityMonitorModel.data.targetBitrate ?? ''}kb",
style: TextStyle(color: MyTheme.grayBg), style: TextStyle(color: MyTheme.grayBg),
), ),
Text( Text(
"Codec: ${qualityMonitorModel.data.codecFormat}", "Codec: ${qualityMonitorModel.data.codecFormat ?? ''}",
style: TextStyle(color: MyTheme.grayBg), style: TextStyle(color: MyTheme.grayBg),
), ),
], ],
@ -1003,26 +1007,11 @@ class QualityMonitor extends StatelessWidget {
: SizedBox.shrink()))); : SizedBox.shrink())));
} }
CheckboxListTile getToggle( void showOptions(String id) async {
void Function(void Function()) setState, option, name) { String quality = await bind.getSessionImageQuality(id: id) ?? 'balanced';
return CheckboxListTile(
value: gFFI.getByName('toggle_option', option) == 'true',
onChanged: (v) {
setState(() {
gFFI.setByName('toggle_option', option);
});
if (option == "show-quality-monitor") {
gFFI.qualityMonitorModel.checkShowQualityMonitor();
}
},
dense: true,
title: Text(translate(name)));
}
void showOptions() {
String quality = gFFI.getByName('image_quality');
if (quality == '') quality = 'balanced'; if (quality == '') quality = 'balanced';
String viewStyle = gFFI.getByName('peer_option', 'view-style'); String viewStyle =
await bind.getSessionOption(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();
@ -1035,7 +1024,7 @@ void showOptions() {
children.add(InkWell( children.add(InkWell(
onTap: () { onTap: () {
if (i == cur) return; if (i == cur) return;
gFFI.setByName('switch_display', i.toString()); bind.sessionSwitchDisplay(id: id, value: i);
SmartDialog.dismiss(); SmartDialog.dismiss();
}, },
child: Ink( child: Ink(
@ -1064,30 +1053,30 @@ void showOptions() {
DialogManager.show((setState, close) { DialogManager.show((setState, close) {
final more = <Widget>[]; final more = <Widget>[];
if (perms['audio'] != false) { if (perms['audio'] != false) {
more.add(getToggle(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(getToggle(setState, 'disable-clipboard', 'Disable clipboard')); more.add(
getToggle(id, setState, 'disable-clipboard', 'Disable clipboard'));
more.add(getToggle( more.add(getToggle(
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(setState, 'privacy-mode', 'Privacy mode')); more.add(getToggle(id, setState, 'privacy-mode', 'Privacy mode'));
} }
} }
var setQuality = (String? value) { var setQuality = (String? value) {
if (value == null) return; if (value == null) return;
setState(() { setState(() {
quality = value; quality = value;
gFFI.setByName('image_quality', value); bind.sessionSetImageQuality(id: id, value: value);
}); });
}; };
var setViewStyle = (String? value) { var setViewStyle = (String? value) {
if (value == null) return; if (value == null) return;
setState(() { setState(() {
viewStyle = value; viewStyle = value;
gFFI.setByName( bind.sessionPeerOption(id: id, name: "view-style", value: value);
'peer_option', '{"name": "view-style", "value": "$value"}');
gFFI.canvasModel.updateViewStyle(); gFFI.canvasModel.updateViewStyle();
}); });
}; };
@ -1105,9 +1094,10 @@ void showOptions() {
getRadio('Balanced', 'balanced', quality, setQuality), getRadio('Balanced', 'balanced', quality, setQuality),
getRadio('Optimize reaction time', 'low', quality, setQuality), getRadio('Optimize reaction time', 'low', quality, setQuality),
Divider(color: MyTheme.border), Divider(color: MyTheme.border),
getToggle(setState, 'show-remote-cursor', 'Show remote cursor'),
getToggle( getToggle(
setState, 'show-quality-monitor', 'Show quality monitor'), id, setState, 'show-remote-cursor', 'Show remote cursor'),
getToggle(id, setState, 'show-quality-monitor',
'Show quality monitor'),
] + ] +
more), more),
actions: [], actions: [],
@ -1137,10 +1127,10 @@ void showRestartRemoteDevice(PeerInfo pi, String id) async {
if (res == true) gFFI.setByName('restart_remote_device'); if (res == true) gFFI.setByName('restart_remote_device');
} }
void showSetOSPassword(bool login) { void showSetOSPassword(String id, bool login) async {
final controller = TextEditingController(); final controller = TextEditingController();
var password = gFFI.getByName('peer_option', "os-password"); var password = await bind.getSessionOption(id: id, arg: "os-password") ?? "";
var autoLogin = gFFI.getByName('peer_option', "auto-login") != ""; var autoLogin = await bind.getSessionOption(id: id, arg: "auto-login") != "";
controller.text = password; controller.text = password;
DialogManager.show((setState, close) { DialogManager.show((setState, close) {
return CustomAlertDialog( return CustomAlertDialog(
@ -1173,12 +1163,11 @@ void showSetOSPassword(bool login) {
style: flatButtonStyle, style: flatButtonStyle,
onPressed: () { onPressed: () {
var text = controller.text.trim(); var text = controller.text.trim();
gFFI.setByName( bind.sessionPeerOption(id: id, name: "os-password", value: text);
'peer_option', '{"name": "os-password", "value": "$text"}'); bind.sessionPeerOption(
gFFI.setByName('peer_option', id: id, name: "auto-login", value: autoLogin ? 'Y' : '');
'{"name": "auto-login", "value": "${autoLogin ? 'Y' : ''}"}');
if (text != "" && login) { if (text != "" && login) {
gFFI.setByName('input_os_password', text); bind.sessionInputOsPassword(id: id, value: text);
} }
close(); close();
}, },

View File

@ -9,6 +9,7 @@ import 'package:url_launcher/url_launcher.dart';
import '../../common.dart'; import '../../common.dart';
import '../../models/model.dart'; import '../../models/model.dart';
import '../../models/platform_model.dart';
import '../widgets/dialog.dart'; import '../widgets/dialog.dart';
import 'home_page.dart'; import 'home_page.dart';
import 'scan_page.dart'; import 'scan_page.dart';
@ -192,21 +193,18 @@ void showServerSettings() {
showServerSettingsWithValue(id, relay, key, api); showServerSettingsWithValue(id, relay, key, api);
} }
void showLanguageSettings() { void showLanguageSettings() async {
try { try {
final langs = json.decode(gFFI.getByName('langs')) as List<dynamic>; final langs = json.decode(gFFI.getByName('langs')) as List<dynamic>;
var lang = gFFI.getByName('local_option', 'lang'); var lang = await bind.mainGetLocalOption(key: "lang");
DialogManager.show((setState, close) { DialogManager.show((setState, close) {
final setLang = (v) { final setLang = (v) {
if (lang != v) { if (lang != v) {
setState(() { setState(() {
lang = v; lang = v;
}); });
final msg = Map() bind.mainSetLocalOption(key: "lang", value: v);
..['name'] = 'lang' HomePage.homeKey.currentState?.refreshPages();
..['value'] = v;
gFFI.setByName('local_option', json.encode(msg));
homeKey.currentState?.refreshPages();
Future.delayed(Duration(milliseconds: 200), close); Future.delayed(Duration(milliseconds: 200), close);
} }
}; };
@ -277,8 +275,8 @@ fetch('http://localhost:21114/api/login', {
final body = { final body = {
'username': name, 'username': name,
'password': pass, 'password': pass,
'id': gFFI.getByName('server_id'), 'id': bind.mainGetMyId(),
'uuid': gFFI.getByName('uuid') 'uuid': bind.mainGetUuid()
}; };
try { try {
final response = await http.post(Uri.parse('$url/api/login'), final response = await http.post(Uri.parse('$url/api/login'),
@ -314,10 +312,7 @@ void refreshCurrentUser() async {
final token = gFFI.getByName("option", "access_token"); final token = gFFI.getByName("option", "access_token");
if (token == '') return; if (token == '') return;
final url = getUrl(); final url = getUrl();
final body = { final body = {'id': bind.mainGetMyId(), 'uuid': bind.mainGetUuid()};
'id': gFFI.getByName('server_id'),
'uuid': gFFI.getByName('uuid')
};
try { try {
final response = await http.post(Uri.parse('$url/api/currentUser'), final response = await http.post(Uri.parse('$url/api/currentUser'),
headers: { headers: {
@ -340,10 +335,7 @@ void logout() async {
final token = gFFI.getByName("option", "access_token"); final token = gFFI.getByName("option", "access_token");
if (token == '') return; if (token == '') return;
final url = getUrl(); final url = getUrl();
final body = { final body = {'id': bind.mainGetMyId(), 'uuid': bind.mainGetUuid()};
'id': gFFI.getByName('server_id'),
'uuid': gFFI.getByName('uuid')
};
try { try {
await http.post(Uri.parse('$url/api/logout'), await http.post(Uri.parse('$url/api/logout'),
headers: { headers: {

View File

@ -171,6 +171,8 @@ class FfiModel with ChangeNotifier {
parent.target?.serverModel.onClientAuthorized(evt); parent.target?.serverModel.onClientAuthorized(evt);
} else if (name == 'on_client_remove') { } else if (name == 'on_client_remove') {
parent.target?.serverModel.onClientRemove(evt); parent.target?.serverModel.onClientRemove(evt);
} else if (name == 'update_quality_status') {
parent.target?.qualityMonitorModel.updateQualityStatus(evt);
} }
}; };
} }
@ -807,9 +809,10 @@ class QualityMonitorModel with ChangeNotifier {
bool get show => _show; bool get show => _show;
QualityMonitorData get data => _data; QualityMonitorData get data => _data;
checkShowQualityMonitor() { checkShowQualityMonitor(String id) async {
final show = final show = await bind.getSessionToggleOption(
gFFI.getByName('toggle_option', 'show-quality-monitor') == 'true'; id: id, arg: 'show-quality-monitor') ==
true;
if (_show != show) { if (_show != show) {
_show = show; _show = show;
notifyListeners(); notifyListeners();