diff --git a/flutter/lib/common.dart b/flutter/lib/common.dart index 208897ed0397..7f978201ae21 100644 --- a/flutter/lib/common.dart +++ b/flutter/lib/common.dart @@ -3625,3 +3625,16 @@ void checkUpdate() { } } } + +// https://github.com/flutter/flutter/issues/153560#issuecomment-2497160535 +// For TextField, TextFormField +extension WorkaroundFreezeLinuxMint on Widget { + Widget workaroundFreezeLinuxMint() { + // No need to check if is Linux Mint, because this workaround is harmless on other platforms. + if (isLinux) { + return ExcludeSemantics(child: this); + } else { + return this; + } + } +} diff --git a/flutter/lib/common/widgets/address_book.dart b/flutter/lib/common/widgets/address_book.dart index ae07c1498cf1..deed97bb30bd 100644 --- a/flutter/lib/common/widgets/address_book.dart +++ b/flutter/lib/common/widgets/address_book.dart @@ -286,7 +286,7 @@ class _AddressBookState extends State { borderRadius: BorderRadius.circular(8), ), ), - ), + ).workaroundFreezeLinuxMint(), ), searchMatchFn: (item, searchValue) { return item.value @@ -556,7 +556,7 @@ class _AddressBookState extends State { : translate('ID'), errorText: errorMsg, errorMaxLines: 5), - ))), + ).workaroundFreezeLinuxMint())), row( lable: Text( translate('Alias'), @@ -569,7 +569,7 @@ class _AddressBookState extends State { ? null : translate('Alias'), ), - )), + ).workaroundFreezeLinuxMint()), ), if (isCurrentAbShared) row( @@ -598,7 +598,7 @@ class _AddressBookState extends State { }, ), ), - ), + ).workaroundFreezeLinuxMint(), )), if (gFFI.abModel.currentAbTags.isNotEmpty) Align( @@ -704,7 +704,7 @@ class _AddressBookState extends State { ), controller: controller, autofocus: true, - ), + ).workaroundFreezeLinuxMint(), ), ], ), diff --git a/flutter/lib/common/widgets/chat_page.dart b/flutter/lib/common/widgets/chat_page.dart index b6611d3ede39..4b0954d40b19 100644 --- a/flutter/lib/common/widgets/chat_page.dart +++ b/flutter/lib/common/widgets/chat_page.dart @@ -167,7 +167,7 @@ class ChatPage extends StatelessWidget implements PageShape { ); }, ), - ); + ).workaroundFreezeLinuxMint(); return SelectionArea(child: chat); }), ], diff --git a/flutter/lib/common/widgets/dialog.dart b/flutter/lib/common/widgets/dialog.dart index cc3e0613105b..0fb8d552d7ab 100644 --- a/flutter/lib/common/widgets/dialog.dart +++ b/flutter/lib/common/widgets/dialog.dart @@ -140,7 +140,7 @@ void changeIdDialog() { msg = ''; }); }, - ), + ).workaroundFreezeLinuxMint(), const SizedBox( height: 8.0, ), @@ -201,13 +201,14 @@ void changeWhiteList({Function()? callback}) async { children: [ Expanded( child: TextField( - maxLines: null, - decoration: InputDecoration( - errorText: msg.isEmpty ? null : translate(msg), - ), - controller: controller, - enabled: !isOptFixed, - autofocus: true), + maxLines: null, + decoration: InputDecoration( + errorText: msg.isEmpty ? null : translate(msg), + ), + controller: controller, + enabled: !isOptFixed, + autofocus: true) + .workaroundFreezeLinuxMint(), ), ], ), @@ -287,22 +288,23 @@ Future changeDirectAccessPort( children: [ Expanded( child: TextField( - maxLines: null, - keyboardType: TextInputType.number, - decoration: InputDecoration( - hintText: '21118', - isCollapsed: true, - prefix: Text('$currentIP : '), - suffix: IconButton( - padding: EdgeInsets.zero, - icon: const Icon(Icons.clear, size: 16), - onPressed: () => controller.clear())), - inputFormatters: [ - FilteringTextInputFormatter.allow(RegExp( - r'^([0-9]|[1-9]\d|[1-9]\d{2}|[1-9]\d{3}|[1-5]\d{4}|6[0-4]\d{3}|65[0-4]\d{2}|655[0-2]\d|6553[0-5])$')), - ], - controller: controller, - autofocus: true), + maxLines: null, + keyboardType: TextInputType.number, + decoration: InputDecoration( + hintText: '21118', + isCollapsed: true, + prefix: Text('$currentIP : '), + suffix: IconButton( + padding: EdgeInsets.zero, + icon: const Icon(Icons.clear, size: 16), + onPressed: () => controller.clear())), + inputFormatters: [ + FilteringTextInputFormatter.allow(RegExp( + r'^([0-9]|[1-9]\d|[1-9]\d{2}|[1-9]\d{3}|[1-5]\d{4}|6[0-4]\d{3}|65[0-4]\d{2}|655[0-2]\d|6553[0-5])$')), + ], + controller: controller, + autofocus: true) + .workaroundFreezeLinuxMint(), ), ], ), @@ -335,21 +337,22 @@ Future changeAutoDisconnectTimeout(String old) async { children: [ Expanded( child: TextField( - maxLines: null, - keyboardType: TextInputType.number, - decoration: InputDecoration( - hintText: '10', - isCollapsed: true, - suffix: IconButton( - padding: EdgeInsets.zero, - icon: const Icon(Icons.clear, size: 16), - onPressed: () => controller.clear())), - inputFormatters: [ - FilteringTextInputFormatter.allow(RegExp( - r'^([0-9]|[1-9]\d|[1-9]\d{2}|[1-9]\d{3}|[1-5]\d{4}|6[0-4]\d{3}|65[0-4]\d{2}|655[0-2]\d|6553[0-5])$')), - ], - controller: controller, - autofocus: true), + maxLines: null, + keyboardType: TextInputType.number, + decoration: InputDecoration( + hintText: '10', + isCollapsed: true, + suffix: IconButton( + padding: EdgeInsets.zero, + icon: const Icon(Icons.clear, size: 16), + onPressed: () => controller.clear())), + inputFormatters: [ + FilteringTextInputFormatter.allow(RegExp( + r'^([0-9]|[1-9]\d|[1-9]\d{2}|[1-9]\d{3}|[1-5]\d{4}|6[0-4]\d{3}|65[0-4]\d{2}|655[0-2]\d|6553[0-5])$')), + ], + controller: controller, + autofocus: true) + .workaroundFreezeLinuxMint(), ), ], ), @@ -427,7 +430,7 @@ class DialogTextField extends StatelessWidget { keyboardType: keyboardType, inputFormatters: inputFormatters, maxLength: maxLength, - ), + ).workaroundFreezeLinuxMint(), ), ], ).paddingSymmetric(vertical: 4.0); @@ -1501,7 +1504,7 @@ showAuditDialog(FFI ffi) async { maxLength: 256, controller: controller, focusNode: focusNode, - )), + ).workaroundFreezeLinuxMint()), actions: [ dialogButton('Cancel', onPressed: close, isOutline: true), dialogButton('OK', onPressed: submit) @@ -1748,7 +1751,7 @@ void renameDialog( autofocus: true, decoration: InputDecoration(labelText: translate('Name')), validator: validator, - ), + ).workaroundFreezeLinuxMint(), ), ), // NOT use Offstage to wrap LinearProgressIndicator @@ -1808,7 +1811,7 @@ void changeBot({Function()? callback}) async { decoration: InputDecoration( hintText: translate('Token'), ), - ); + ).workaroundFreezeLinuxMint(); return CustomAlertDialog( title: Text(translate("Telegram bot")), @@ -2178,7 +2181,7 @@ void setSharedAbPasswordDialog(String abName, Peer peer) { }, ), ), - ), + ).workaroundFreezeLinuxMint(), if (!gFFI.abModel.current.isPersonal()) Row(children: [ Icon(Icons.info, color: Colors.amber).marginOnly(right: 4), diff --git a/flutter/lib/common/widgets/login.dart b/flutter/lib/common/widgets/login.dart index 71f3dacc3b2c..50e05cde5881 100644 --- a/flutter/lib/common/widgets/login.dart +++ b/flutter/lib/common/widgets/login.dart @@ -678,7 +678,7 @@ Future verificationCodeDialog( labelText: "Email", prefixIcon: Icon(Icons.email)), readOnly: true, controller: TextEditingController(text: user?.email), - )), + ).workaroundFreezeLinuxMint()), isEmailVerification ? const SizedBox(height: 8) : const Offstage(), codeField, /* diff --git a/flutter/lib/common/widgets/my_group.dart b/flutter/lib/common/widgets/my_group.dart index 867d71dff2da..359fbc7f7212 100644 --- a/flutter/lib/common/widgets/my_group.dart +++ b/flutter/lib/common/widgets/my_group.dart @@ -145,7 +145,7 @@ class _MyGroupState extends State { border: InputBorder.none, isDense: true, ), - )), + ).workaroundFreezeLinuxMint()), ], ); } diff --git a/flutter/lib/common/widgets/peer_card.dart b/flutter/lib/common/widgets/peer_card.dart index 0a15eb45b880..b4bca12a9e67 100644 --- a/flutter/lib/common/widgets/peer_card.dart +++ b/flutter/lib/common/widgets/peer_card.dart @@ -1257,7 +1257,7 @@ void _rdpDialog(String id) async { hintText: '3389'), controller: portController, autofocus: true, - ), + ).workaroundFreezeLinuxMint(), ), ], ).marginOnly(bottom: isDesktop ? 8 : 0), @@ -1277,7 +1277,7 @@ void _rdpDialog(String id) async { labelText: isDesktop ? null : translate('Username')), controller: userController, - ), + ).workaroundFreezeLinuxMint(), ), ], ).marginOnly(bottom: stateGlobal.isPortrait.isFalse ? 8 : 0)), @@ -1305,7 +1305,7 @@ void _rdpDialog(String id) async { ? Icons.visibility_off : Icons.visibility))), controller: passwordController, - )), + ).workaroundFreezeLinuxMint()), ), ], )) diff --git a/flutter/lib/common/widgets/peer_tab_page.dart b/flutter/lib/common/widgets/peer_tab_page.dart index 359750788058..9d21ec6cd71d 100644 --- a/flutter/lib/common/widgets/peer_tab_page.dart +++ b/flutter/lib/common/widgets/peer_tab_page.dart @@ -743,7 +743,7 @@ class _PeerSearchBarState extends State { border: InputBorder.none, isDense: true, ), - ), + ).workaroundFreezeLinuxMint(), ), // Icon(Icons.close), IconButton( diff --git a/flutter/lib/desktop/pages/connection_page.dart b/flutter/lib/desktop/pages/connection_page.dart index f2c7121016e1..0ae7affbcf7e 100644 --- a/flutter/lib/desktop/pages/connection_page.dart +++ b/flutter/lib/desktop/pages/connection_page.dart @@ -424,7 +424,7 @@ class _ConnectionPageState extends State onSubmitted: (_) { onConnect(); }, - )); + ).workaroundFreezeLinuxMint()); }, onSelected: (option) { setState(() { diff --git a/flutter/lib/desktop/pages/desktop_home_page.dart b/flutter/lib/desktop/pages/desktop_home_page.dart index 10f5cc4fdbae..691bed75c9a5 100644 --- a/flutter/lib/desktop/pages/desktop_home_page.dart +++ b/flutter/lib/desktop/pages/desktop_home_page.dart @@ -237,7 +237,7 @@ class _DesktopHomePageState extends State style: TextStyle( fontSize: 22, ), - ), + ).workaroundFreezeLinuxMint(), ), ) ], @@ -333,7 +333,7 @@ class _DesktopHomePageState extends State EdgeInsets.only(top: 14, bottom: 10), ), style: TextStyle(fontSize: 15), - ), + ).workaroundFreezeLinuxMint(), ), ), if (showOneTime) @@ -940,7 +940,7 @@ void setPasswordDialog({VoidCallback? notEmptyCallback}) async { }); }, maxLength: maxLength, - ), + ).workaroundFreezeLinuxMint(), ), ], ), @@ -967,7 +967,7 @@ void setPasswordDialog({VoidCallback? notEmptyCallback}) async { }); }, maxLength: maxLength, - ), + ).workaroundFreezeLinuxMint(), ), ], ), diff --git a/flutter/lib/desktop/pages/desktop_setting_page.dart b/flutter/lib/desktop/pages/desktop_setting_page.dart index 56a99446c384..d978577ab85c 100644 --- a/flutter/lib/desktop/pages/desktop_setting_page.dart +++ b/flutter/lib/desktop/pages/desktop_setting_page.dart @@ -1189,7 +1189,7 @@ class _SafetyState extends State<_Safety> with AutomaticKeepAliveClientMixin { contentPadding: EdgeInsets.symmetric(vertical: 12, horizontal: 12), ), - ).marginOnly(right: 15), + ).workaroundFreezeLinuxMint().marginOnly(right: 15), ), Obx(() => ElevatedButton( onPressed: applyEnabled.value && @@ -1346,7 +1346,7 @@ class _SafetyState extends State<_Safety> with AutomaticKeepAliveClientMixin { contentPadding: EdgeInsets.symmetric(vertical: 12, horizontal: 12), ), - ).marginOnly(right: 15), + ).workaroundFreezeLinuxMint().marginOnly(right: 15), ), Obx(() => ElevatedButton( onPressed: @@ -2312,7 +2312,7 @@ _LabeledTextField( style: TextStyle( color: disabledTextColor(context, enabled), ), - ), + ).workaroundFreezeLinuxMint(), ], ), ], @@ -2491,7 +2491,7 @@ void changeSocks5Proxy() async { controller: proxyController, autofocus: true, enabled: !isOptFixed, - ), + ).workaroundFreezeLinuxMint(), ), ], ).marginOnly(bottom: 8), @@ -2511,7 +2511,7 @@ void changeSocks5Proxy() async { labelText: isMobile ? translate('Username') : null, ), enabled: !isOptFixed, - ), + ).workaroundFreezeLinuxMint(), ), ], ).marginOnly(bottom: 8), @@ -2537,7 +2537,7 @@ void changeSocks5Proxy() async { controller: pwdController, enabled: !isOptFixed, maxLength: bind.mainMaxEncryptLen(), - )), + ).workaroundFreezeLinuxMint()), ), ], ), diff --git a/flutter/lib/desktop/pages/file_manager_page.dart b/flutter/lib/desktop/pages/file_manager_page.dart index 90b8d7dcbf3c..3f555dcaa66e 100644 --- a/flutter/lib/desktop/pages/file_manager_page.dart +++ b/flutter/lib/desktop/pages/file_manager_page.dart @@ -768,7 +768,7 @@ class _FileManagerViewState extends State { ), controller: name, autofocus: true, - ), + ).workaroundFreezeLinuxMint(), ], ), actions: [ @@ -1657,7 +1657,7 @@ class _FileManagerViewState extends State { onChanged: _locationStatus.value == LocationStatus.fileSearchBar ? (searchText) => onSearchText(searchText, isLocal) : null, - ), + ).workaroundFreezeLinuxMint(), ) ], ); diff --git a/flutter/lib/desktop/pages/install_page.dart b/flutter/lib/desktop/pages/install_page.dart index 0ff04240b554..756367c21f1f 100644 --- a/flutter/lib/desktop/pages/install_page.dart +++ b/flutter/lib/desktop/pages/install_page.dart @@ -147,7 +147,7 @@ class _InstallPageBodyState extends State<_InstallPageBody> decoration: InputDecoration( contentPadding: EdgeInsets.all(0.75 * em), ), - ).marginOnly(right: 10), + ).workaroundFreezeLinuxMint().marginOnly(right: 10), ), Obx( () => OutlinedButton.icon( diff --git a/flutter/lib/desktop/pages/port_forward_page.dart b/flutter/lib/desktop/pages/port_forward_page.dart index d6d243c5026a..6671d041bbf5 100644 --- a/flutter/lib/desktop/pages/port_forward_page.dart +++ b/flutter/lib/desktop/pages/port_forward_page.dart @@ -238,7 +238,7 @@ class _PortForwardPageState extends State inputFormatters: inputFormatters, decoration: InputDecoration( hintText: hint, - ))), + )).workaroundFreezeLinuxMint()), ); } diff --git a/flutter/lib/desktop/widgets/remote_toolbar.dart b/flutter/lib/desktop/widgets/remote_toolbar.dart index 839ea1a81db2..d826ea8c6b60 100644 --- a/flutter/lib/desktop/widgets/remote_toolbar.dart +++ b/flutter/lib/desktop/widgets/remote_toolbar.dart @@ -1495,7 +1495,7 @@ class _ResolutionsMenuState extends State<_ResolutionsMenu> { ); } - TextField _resolutionInput(TextEditingController controller) { + Widget _resolutionInput(TextEditingController controller) { return TextField( decoration: InputDecoration( border: InputBorder.none, @@ -1509,7 +1509,7 @@ class _ResolutionsMenuState extends State<_ResolutionsMenu> { FilteringTextInputFormatter.allow(RegExp(r'[0-9]')), ], controller: controller, - ); + ).workaroundFreezeLinuxMint(); } List _supportedResolutionMenuButtons() => resolutions diff --git a/flutter/lib/mobile/pages/file_manager_page.dart b/flutter/lib/mobile/pages/file_manager_page.dart index e017b5b6faec..b837dc276e39 100644 --- a/flutter/lib/mobile/pages/file_manager_page.dart +++ b/flutter/lib/mobile/pages/file_manager_page.dart @@ -225,7 +225,7 @@ class _FileManagerPageState extends State { errorText: errorText, ), controller: name, - ), + ).workaroundFreezeLinuxMint(), ], ), actions: [ diff --git a/flutter/lib/mobile/pages/remote_page.dart b/flutter/lib/mobile/pages/remote_page.dart index 003640e05e1a..27ce22713803 100644 --- a/flutter/lib/mobile/pages/remote_page.dart +++ b/flutter/lib/mobile/pages/remote_page.dart @@ -604,7 +604,7 @@ class _RemotePageState extends State with WidgetsBindingObserver { // ko/zh/ja input method: the button will trigger `onKeyEvent` // and the event will not popup if `KeyEventResult.handled` is returned. onChanged: handleSoftKeyboardInput, - ), + ).workaroundFreezeLinuxMint(), ), ]; if (showCursorPaint) { diff --git a/flutter/lib/mobile/widgets/dialog.dart b/flutter/lib/mobile/widgets/dialog.dart index 1c8b4dd3d7b8..ebedd79d44fe 100644 --- a/flutter/lib/mobile/widgets/dialog.dart +++ b/flutter/lib/mobile/widgets/dialog.dart @@ -66,7 +66,7 @@ void setPermanentPasswordDialog(OverlayDialogManager dialogManager) async { ? null : translate('Too short, at least 6 characters.'); }, - ), + ).workaroundFreezeLinuxMint(), TextFormField( obscureText: true, keyboardType: TextInputType.visiblePassword, @@ -85,7 +85,7 @@ void setPermanentPasswordDialog(OverlayDialogManager dialogManager) async { ? null : translate('The confirmation is not identical.'); }, - ), + ).workaroundFreezeLinuxMint(), ])), onCancel: close, onSubmit: (validateLength && validateSame) ? submit : null, @@ -216,7 +216,7 @@ void showServerSettingsWithValue( ), validator: validator, autofocus: autofocus, - ), + ).workaroundFreezeLinuxMint(), ), ], ); @@ -229,7 +229,7 @@ void showServerSettingsWithValue( errorText: errorMsg.isEmpty ? null : errorMsg, ), validator: validator, - ); + ).workaroundFreezeLinuxMint(); } return CustomAlertDialog(