From c188a6f93f57ca5dd91a413a3913b84e4885b410 Mon Sep 17 00:00:00 2001 From: csf Date: Tue, 26 Apr 2022 21:21:08 +0800 Subject: [PATCH] fix:reconnect time,enter password focus,wrong gesture tap-up;ctrl soft keyboard --- .../com/carriez/flutter_hbb/MainActivity.kt | 13 +++ lib/models/model.dart | 1 + lib/pages/chat_page.dart | 1 + lib/pages/remote_page.dart | 97 ++++++++++--------- lib/widgets/dialog.dart | 47 ++++++--- lib/widgets/gestures.dart | 10 +- 6 files changed, 106 insertions(+), 63 deletions(-) diff --git a/android/app/src/main/kotlin/com/carriez/flutter_hbb/MainActivity.kt b/android/app/src/main/kotlin/com/carriez/flutter_hbb/MainActivity.kt index b08604ca3..bb4e85c89 100644 --- a/android/app/src/main/kotlin/com/carriez/flutter_hbb/MainActivity.kt +++ b/android/app/src/main/kotlin/com/carriez/flutter_hbb/MainActivity.kt @@ -10,6 +10,7 @@ import android.os.Build import android.os.IBinder import android.provider.Settings import android.util.Log +import android.view.WindowManager import androidx.annotation.RequiresApi import io.flutter.embedding.android.FlutterActivity import io.flutter.embedding.engine.FlutterEngine @@ -125,6 +126,18 @@ class MainActivity : FlutterActivity() { result.success(true) } } + "enable_soft_keyboard" -> { + // https://blog.csdn.net/hanye2020/article/details/105553780 + try { + if (call.arguments as Boolean) { + window.clearFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM) + } else { + window.addFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM) + } + } finally { + result.success(true) + } + } else -> { result.error("-1", "No such method", null) } diff --git a/lib/models/model.dart b/lib/models/model.dart index cb5001c24..b24c2c761 100644 --- a/lib/models/model.dart +++ b/lib/models/model.dart @@ -249,6 +249,7 @@ class FfiModel with ChangeNotifier { if (displays.length > 0) { showLoading(translate('Connected, waiting for image...')); _waitForImage = true; + _reconnects = 1; } } notifyListeners(); diff --git a/lib/pages/chat_page.dart b/lib/pages/chat_page.dart index 7316ae2bf..218ac365c 100644 --- a/lib/pages/chat_page.dart +++ b/lib/pages/chat_page.dart @@ -148,6 +148,7 @@ hideChatWindowOverlay() { toggleChatOverlay() { if (iconOverlayEntry == null || windowOverlayEntry == null) { + FFI.invokeMethod("enable_soft_keyboard", true); showChatIconOverlay(); showChatWindowOverlay(); } else { diff --git a/lib/pages/remote_page.dart b/lib/pages/remote_page.dart index 47e23469e..d26246ae9 100644 --- a/lib/pages/remote_page.dart +++ b/lib/pages/remote_page.dart @@ -60,6 +60,7 @@ class _RemotePageState extends State { @override void dispose() { FFI.listenToMouse(false); + FFI.invokeMethod("enable_soft_keyboard", true); _mobileFocusNode.dispose(); _physicalFocusNode.dispose(); FFI.close(); @@ -90,6 +91,7 @@ class _RemotePageState extends State { if (v < 100) { SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: []); + FFI.invokeMethod("enable_soft_keyboard", false); } }); } @@ -181,6 +183,7 @@ class _RemotePageState extends State { } void openKeyboard() { + FFI.invokeMethod("enable_soft_keyboard", true); // destroy first, so that our _value trick can work _value = initText; setState(() => _showEdit = false); @@ -193,7 +196,6 @@ class _RemotePageState extends State { _timer = Timer(Duration(milliseconds: 30), () { SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: SystemUiOverlay.values); - SystemChannels.textInput.invokeMethod('TextInput.show'); _mobileFocusNode.requestFocus(); }); }); @@ -211,48 +213,59 @@ class _RemotePageState extends State { final pi = Provider.of(context).pi; final hideKeyboard = isKeyboardShown() && _showEdit; final showActionButton = !_showBar || hideKeyboard; + final keyboard = FFI.ffiModel.permissions['keyboard'] != false; + return WillPopScope( onWillPop: () async { clientClose(); return false; }, - child: Scaffold( - // resizeToAvoidBottomInset: true, - floatingActionButton: !showActionButton - ? null - : FloatingActionButton( - mini: !hideKeyboard, - child: Icon( - hideKeyboard ? Icons.expand_more : Icons.expand_less), - backgroundColor: MyTheme.accent, - onPressed: () { - setState(() { - if (hideKeyboard) { - _showEdit = false; - _mobileFocusNode.unfocus(); - SystemChannels.textInput.invokeMethod('TextInput.hide'); - _physicalFocusNode.requestFocus(); - } else { - _showBar = !_showBar; - } - }); - }), - bottomNavigationBar: - _showBar && pi.displays != null ? getBottomAppBar() : null, - body: Overlay( - initialEntries: [ - OverlayEntry(builder: (context) { - final keyboard = FFI.ffiModel.permissions['keyboard'] != false; - return Container( - color: Colors.black, - child: getRawPointerAndKeyBody(keyboard)); - }) - ], - )), + child: getRawPointerAndKeyBody( + keyboard, + Scaffold( + // resizeToAvoidBottomInset: true, + floatingActionButton: !showActionButton + ? null + : FloatingActionButton( + mini: !hideKeyboard, + child: Icon( + hideKeyboard ? Icons.expand_more : Icons.expand_less), + backgroundColor: MyTheme.accent, + onPressed: () { + setState(() { + if (hideKeyboard) { + _showEdit = false; + FFI.invokeMethod("enable_soft_keyboard", false); + _mobileFocusNode.unfocus(); + _physicalFocusNode.requestFocus(); + } else { + _showBar = !_showBar; + } + }); + }), + bottomNavigationBar: + _showBar && pi.displays != null ? getBottomAppBar() : null, + body: Overlay( + initialEntries: [ + OverlayEntry(builder: (context) { + return Container( + color: Colors.black, + // child: getRawPointerAndKeyBody(keyboard)); + child: isDesktop + ? getBodyForDesktopWithListener(keyboard) + : SafeArea( + child: Container( + color: MyTheme.canvasColor, + child: _isPhysicalKeyboard + ? getBodyForMobile() + : getBodyForMobileWithGesture()))); + }) + ], + ))), ); } - Widget getRawPointerAndKeyBody(bool keyboard) { + Widget getRawPointerAndKeyBody(bool keyboard, Widget child) { return Listener( onPointerHover: (e) { if (e.kind != ui.PointerDeviceKind.mouse) return; @@ -351,14 +364,7 @@ class _RemotePageState extends State { } return KeyEventResult.handled; }, - child: isDesktop - ? getBodyForDesktopWithListener(keyboard) - : SafeArea( - child: Container( - color: MyTheme.canvasColor, - child: _isPhysicalKeyboard - ? getBodyForMobile() - : getBodyForMobileWithGesture())))))); + child: child)))); } Widget getBottomAppBar() { @@ -490,7 +496,7 @@ class _RemotePageState extends State { FFI.cursorModel.updatePan(d.delta.dx, d.delta.dy, _touchMode); } }, - onHoldDragCancel: () { + onHoldDragEnd: (_) { if (!_touchMode) { FFI.sendMouse('up', MouseButtons.left); } @@ -499,8 +505,6 @@ class _RemotePageState extends State { if (_touchMode) { FFI.cursorModel.move(d.localPosition.dx, d.localPosition.dy); FFI.sendMouse('down', MouseButtons.left); - } else { - FFI.sendMouse('up', MouseButtons.left); } }, onOneFingerPanUpdate: (d) { @@ -543,6 +547,7 @@ class _RemotePageState extends State { textInputAction: TextInputAction.newline, autocorrect: false, enableSuggestions: false, + autofocus: true, focusNode: _mobileFocusNode, maxLines: null, initialValue: _value, diff --git a/lib/widgets/dialog.dart b/lib/widgets/dialog.dart index e37a030b7..7781cfe40 100644 --- a/lib/widgets/dialog.dart +++ b/lib/widgets/dialog.dart @@ -1,3 +1,5 @@ +import 'dart:async'; + import 'package:flutter/material.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import '../common.dart'; @@ -10,15 +12,15 @@ void clientClose() { const SEC1 = Duration(seconds: 1); void showSuccess({Duration duration = SEC1}) { SmartDialog.dismiss(); - showToast(translate("Successful"),duration:SEC1); + showToast(translate("Successful"), duration: SEC1); } -void showError({Duration duration = SEC1}){ +void showError({Duration duration = SEC1}) { SmartDialog.dismiss(); - showToast(translate("Error"),duration:SEC1); + showToast(translate("Error"), duration: SEC1); } -void updatePasswordDialog(){ +void updatePasswordDialog() { final p0 = TextEditingController(); final p1 = TextEditingController(); var validateLength = false; @@ -43,7 +45,7 @@ void updatePasswordDialog(){ if (validateLength != val) { // use delay to make setState success Future.delayed(Duration(microseconds: 1), - () => setState(() => validateLength = val)); + () => setState(() => validateLength = val)); } return val ? null @@ -62,7 +64,7 @@ void updatePasswordDialog(){ final val = p0.text == v; if (validateSame != val) { Future.delayed(Duration(microseconds: 1), - () => setState(() => validateSame = val)); + () => setState(() => validateSame = val)); } return val ? null @@ -82,14 +84,14 @@ void updatePasswordDialog(){ style: flatButtonStyle, onPressed: (validateLength && validateSame) ? () async { - close(); - showLoading(translate("Waiting")); - if(await FFI.serverModel.updatePassword(p0.text)){ - showSuccess(); - }else{ - showError(); - } - } + close(); + showLoading(translate("Waiting")); + if (await FFI.serverModel.updatePassword(p0.text)) { + showSuccess(); + } else { + showError(); + } + } : null, child: Text(translate('OK')), ), @@ -115,7 +117,6 @@ void enterPasswordDialog(String id) { ), value: remember, onChanged: (v) { - debugPrint("onChanged"); if (v != null) { setState(() => remember = v); } @@ -181,11 +182,25 @@ class PasswordWidget extends StatefulWidget { class _PasswordWidgetState extends State { bool _passwordVisible = false; + final _focusNode = FocusNode(); + + @override + void initState() { + super.initState(); + Timer(Duration(milliseconds: 50), () => _focusNode.requestFocus()); + } + + @override + void dispose() { + _focusNode.unfocus(); + _focusNode.dispose(); + super.dispose(); + } @override Widget build(BuildContext context) { return TextField( - autofocus: true, + focusNode: _focusNode, controller: widget.controller, obscureText: !_passwordVisible, //This will obscure text dynamically diff --git a/lib/widgets/gestures.dart b/lib/widgets/gestures.dart index 444d76784..9c4b28316 100644 --- a/lib/widgets/gestures.dart +++ b/lib/widgets/gestures.dart @@ -236,6 +236,7 @@ class HoldTapMoveGestureRecognizer extends GestureRecognizer { GestureDragUpdateCallback? onHoldDragUpdate; GestureDragDownCallback? onHoldDragDown; GestureDragCancelCallback? onHoldDragCancel; + GestureDragEndCallback? onHoldDragEnd; bool _isStart = false; @@ -253,7 +254,8 @@ class HoldTapMoveGestureRecognizer extends GestureRecognizer { case kPrimaryButton: if (onHoldDragStart == null && onHoldDragUpdate == null && - onHoldDragCancel == null) { + onHoldDragCancel == null && + onHoldDragEnd == null) { return false; } break; @@ -305,6 +307,10 @@ class HoldTapMoveGestureRecognizer extends GestureRecognizer { if (event is PointerUpEvent) { if (_firstTap == null && _secondTap == null) { _registerFirstTap(tracker); + } else if (_secondTap != null) { + if (event.pointer == _secondTap!.pointer) { + if (onHoldDragEnd != null) onHoldDragEnd!(DragEndDetails()); + } } else { _reject(tracker); } @@ -739,6 +745,7 @@ RawGestureDetector getMixinGestureDetector({ GestureDragStartCallback? onHoldDragStart, GestureDragUpdateCallback? onHoldDragUpdate, GestureDragCancelCallback? onHoldDragCancel, + GestureDragEndCallback? onHoldDragEnd, GestureTapDownCallback? onDoubleFinerTap, GestureDragStartCallback? onOneFingerPanStart, GestureDragUpdateCallback? onOneFingerPanUpdate, @@ -782,6 +789,7 @@ RawGestureDetector getMixinGestureDetector({ ..onHoldDragStart = onHoldDragStart ..onHoldDragUpdate = onHoldDragUpdate ..onHoldDragCancel = onHoldDragCancel + ..onHoldDragEnd = onHoldDragEnd }), DoubleFinerTapGestureRecognizer: GestureRecognizerFactoryWithHandlers< DoubleFinerTapGestureRecognizer>(