From c43443b1a1da920375de48d098d33ecf2eb85338 Mon Sep 17 00:00:00 2001 From: 21pages Date: Sun, 1 Nov 2026 11:50:57 +0800 Subject: [PATCH] refactor: unify request approval menus and naming --- flutter/lib/common.dart | 14 +- .../lib/common/widgets/login_method_menu.dart | 75 ------ flutter/lib/common/widgets/peer_card.dart | 209 +++++++---------- .../common/widgets/request_approval_menu.dart | 66 ++++++ .../lib/desktop/pages/connection_page.dart | 44 +++- flutter/lib/desktop/widgets/popup_menu.dart | 25 +- flutter/lib/mobile/pages/home_page.dart | 4 +- flutter/lib/models/model.dart | 4 +- flutter/test/login_method_menu_test.dart | 146 ------------ flutter/test/request_approval_menu_test.dart | 222 ++++++++++++++++++ flutter/test/uri_login_method_test.dart | 20 +- src/client.rs | 10 +- src/client/login_method.rs | 39 +-- src/core_main.rs | 4 +- src/lang/ar.rs | 4 +- src/lang/az.rs | 4 +- src/lang/be.rs | 4 +- src/lang/bg.rs | 4 +- src/lang/ca.rs | 4 +- src/lang/cn.rs | 4 +- src/lang/cs.rs | 4 +- src/lang/da.rs | 4 +- src/lang/de.rs | 4 +- src/lang/el.rs | 4 +- src/lang/eo.rs | 4 +- src/lang/es.rs | 4 +- src/lang/et.rs | 4 +- src/lang/eu.rs | 4 +- src/lang/fa.rs | 4 +- src/lang/fi.rs | 4 +- src/lang/fr.rs | 4 +- src/lang/ge.rs | 4 +- src/lang/gl.rs | 4 +- src/lang/gu.rs | 4 +- src/lang/he.rs | 4 +- src/lang/hi.rs | 4 +- src/lang/hr.rs | 4 +- src/lang/hu.rs | 4 +- src/lang/id.rs | 4 +- src/lang/it.rs | 4 +- src/lang/ja.rs | 4 +- src/lang/ko.rs | 4 +- src/lang/kz.rs | 4 +- src/lang/lt.rs | 4 +- src/lang/lv.rs | 4 +- src/lang/ml.rs | 4 +- src/lang/nb.rs | 4 +- src/lang/nl.rs | 4 +- src/lang/pl.rs | 4 +- src/lang/pt_BR.rs | 4 +- src/lang/pt_PT.rs | 4 +- src/lang/ro.rs | 4 +- src/lang/ru.rs | 4 +- src/lang/sc.rs | 4 +- src/lang/sk.rs | 4 +- src/lang/sl.rs | 4 +- src/lang/sq.rs | 4 +- src/lang/sr.rs | 4 +- src/lang/sv.rs | 4 +- src/lang/ta.rs | 4 +- src/lang/template.rs | 4 +- src/lang/th.rs | 4 +- src/lang/tr.rs | 4 +- src/lang/tw.rs | 4 +- src/lang/uk.rs | 4 +- src/lang/ur.rs | 4 +- src/lang/vi.rs | 4 +- 67 files changed, 535 insertions(+), 559 deletions(-) delete mode 100644 flutter/lib/common/widgets/login_method_menu.dart create mode 100644 flutter/lib/common/widgets/request_approval_menu.dart delete mode 100644 flutter/test/login_method_menu_test.dart create mode 100644 flutter/test/request_approval_menu_test.dart diff --git a/flutter/lib/common.dart b/flutter/lib/common.dart index ece2c500b..17dc0fcff 100644 --- a/flutter/lib/common.dart +++ b/flutter/lib/common.dart @@ -2330,8 +2330,8 @@ bool handleUriLink({List? cmdArgs, Uri? uri, String? uriString}) { password = args[i + 1]; i++; break; - case '--without-password': - loginMethod = 'consent'; + case '--request-approval': + loginMethod = 'request-approval'; break; case '--switch_uuid': switchUuid = args[i + 1]; @@ -2344,7 +2344,7 @@ bool handleUriLink({List? cmdArgs, Uri? uri, String? uriString}) { break; } } - if (loginMethod == 'consent') { + if (loginMethod == 'request-approval') { password = null; } if (type != null && id != null) { @@ -2486,8 +2486,8 @@ List? urlLinkToCmdArgs(Uri uri) { var queryParameters = uri.queryParameters.map((k, v) => MapEntry(k.toLowerCase(), v)); - final withoutPassword = queryParameters['without-password'] == 'true'; - if (withoutPassword) { + final requestApproval = queryParameters['request-approval'] == 'true'; + if (requestApproval) { queryParameters.remove('password'); } @@ -2501,7 +2501,7 @@ List? urlLinkToCmdArgs(Uri uri) { if (isMobile && id != null) { final forceRelay = queryParameters["relay"] != null; final password = queryParameters["password"]; - final loginMethod = withoutPassword ? 'consent' : ''; + final loginMethod = requestApproval ? 'request-approval' : ''; // Determine connection type based on command if (command == '--file-transfer') { @@ -2536,7 +2536,7 @@ List? urlLinkToCmdArgs(Uri uri) { var param = queryParameters; String? password = param["password"]; if (password != null) args.addAll(['--password', password]); - if (withoutPassword) args.add('--without-password'); + if (requestApproval) args.add('--request-approval'); String? switch_uuid = param["switch_uuid"]; if (switch_uuid != null) args.addAll(['--switch_uuid', switch_uuid]); if (param["relay"] != null) args.add("--relay"); diff --git a/flutter/lib/common/widgets/login_method_menu.dart b/flutter/lib/common/widgets/login_method_menu.dart deleted file mode 100644 index 97d97e32c..000000000 --- a/flutter/lib/common/widgets/login_method_menu.dart +++ /dev/null @@ -1,75 +0,0 @@ -import 'package:flutter/material.dart'; - -import '../../desktop/widgets/material_mod_popup_menu.dart' as mod_menu; -import '../../desktop/widgets/popup_menu.dart'; - -class LoginMethodMenu extends MenuEntryBase { - final MenuEntryButton defaultEntry; - final List> methods; - - LoginMethodMenu({required this.defaultEntry, required this.methods}); - - @override - List> build( - BuildContext context, MenuConfig conf) { - return [ - _LoginMethodMenuItem( - height: conf.height, - child: IntrinsicHeight( - child: - Row(crossAxisAlignment: CrossAxisAlignment.stretch, children: [ - Expanded( - child: MenuEntryButton( - padding: defaultEntry.padding, - enabled: defaultEntry.enabled, - dismissOnClicked: true, - proc: defaultEntry.proc, - childBuilder: defaultEntry.childBuilder, - ).build(context, conf).single), - PopupMenuChildrenItem( - height: conf.height, - padding: EdgeInsets.zero, - enabled: defaultEntry.enabled, - itemBuilder: (submenuContext) => methods - .expand((entry) => MenuEntryButton( - childBuilder: entry.childBuilder, - proc: entry.proc, - padding: entry.padding, - enabled: entry.enabled, - dismissOnClicked: true, - dismissCallback: () { - if (Navigator.canPop(context)) Navigator.pop(context); - }, - ).build(submenuContext, conf)) - .toList(), - child: SizedBox( - width: 56, - child: Icon(Icons.keyboard_arrow_right, color: conf.commonColor), - ), - ), - ])), - ) - ]; - } -} - -// PopupMenuItem adds a TextButton around its child; these actions need separate hit targets. -class _LoginMethodMenuItem extends mod_menu.PopupMenuEntry { - const _LoginMethodMenuItem({required this.height, required this.child}); - - final Widget child; - - @override - final double height; - - @override - bool represents(String? value) => false; - - @override - State<_LoginMethodMenuItem> createState() => _LoginMethodMenuItemState(); -} - -class _LoginMethodMenuItemState extends State<_LoginMethodMenuItem> { - @override - Widget build(BuildContext context) => widget.child; -} diff --git a/flutter/lib/common/widgets/peer_card.dart b/flutter/lib/common/widgets/peer_card.dart index 6e8e667b6..868eb1c5f 100644 --- a/flutter/lib/common/widgets/peer_card.dart +++ b/flutter/lib/common/widgets/peer_card.dart @@ -15,7 +15,7 @@ import '../../models/peer_model.dart'; import '../../models/platform_model.dart'; import '../../desktop/widgets/material_mod_popup_menu.dart' as mod_menu; import '../../desktop/widgets/popup_menu.dart'; -import 'login_method_menu.dart'; +import 'request_approval_menu.dart'; import 'dart:math' as math; typedef PopupMenuEntryBuilder = Future>> @@ -573,7 +573,36 @@ abstract class BasePeerCard extends StatelessWidget { @protected Future>> _buildMenuItems(BuildContext context); - MenuEntryBase _connectCommonAction( + @protected + Future>> _buildConnectionMenuItems( + BuildContext context) async { + final List> menuItems = [ + _connectAction(context), + _transferFileAction(context), + _viewCameraAction(context), + _terminalAction(context), + ]; + + if (peer.platform == kPeerPlatformWindows) { + menuItems.add(_terminalRunAsAdminAction(context)); + } + + if (isDesktop && peer.platform != kPeerPlatformAndroid) { + menuItems.add(_tcpTunnelingAction(context)); + } + if (isWindows && peer.platform == kPeerPlatformWindows) { + menuItems.add(_rdpAction(context, peer.id)); + } + menuItems.add(MenuEntryDivider()); + menuItems.add(_requestApprovalAction(context)); + // menuItems.add(await _openNewConnInOptAction(peer.id)); + if (!isWeb) { + menuItems.add(await _forceAlwaysRelayAction(peer.id)); + } + return menuItems; + } + + MenuEntryButton _connectCommonAction( BuildContext context, String title, { bool isFileTransfer = false, @@ -582,16 +611,10 @@ abstract class BasePeerCard extends StatelessWidget { bool isRDP = false, bool isTerminal = false, bool isTerminalRunAsAdmin = false, - MenuEntryButton? defaultEntry, + String loginMethod = '', }) { - action(String text, String loginMethod) => MenuEntryButton( - childBuilder: (TextStyle? style) => loginMethod == 'consent' - ? Tooltip( - message: translate( - 'Skip saved passwords and ask the remote user to accept the connection.'), - child: Text(text, style: style), - ) - : Text(text, style: style), + return MenuEntryButton( + childBuilder: (TextStyle? style) => Text(title, style: style), proc: () { if (isTerminalRunAsAdmin) { setEnvTerminalAdmin(); @@ -611,10 +634,44 @@ abstract class BasePeerCard extends StatelessWidget { padding: menuPadding, dismissOnClicked: true, ); - return LoginMethodMenu( - defaultEntry: defaultEntry ?? action(title, ''), - methods: [ - action(translate('Without password'), 'consent'), + } + + MenuEntryBase _requestApprovalAction(BuildContext context) { + MenuEntryButton action(String title, + {bool isFileTransfer = false, + bool isViewCamera = false, + bool isTcpTunneling = false, + bool isRDP = false, + bool isTerminal = false, + bool isTerminalRunAsAdmin = false}) => + _connectCommonAction( + context, + isTerminal || isTerminalRunAsAdmin + ? '${translate(title)} (beta)' + : translate(title), + isFileTransfer: isFileTransfer, + isViewCamera: isViewCamera, + isTcpTunneling: isTcpTunneling, + isRDP: isRDP, + isTerminal: isTerminal, + isTerminalRunAsAdmin: isTerminalRunAsAdmin, + loginMethod: 'request-approval', + ); + + return RequestApprovalMenu( + title: translate('Request approval'), + padding: menuPadding, + entries: [ + action('Connect'), + action('Transfer file', isFileTransfer: true), + action('View camera', isViewCamera: true), + action('Terminal', isTerminal: true), + if (peer.platform == kPeerPlatformWindows) + action('Terminal (Run as administrator)', isTerminalRunAsAdmin: true), + if (isDesktop && peer.platform != kPeerPlatformAndroid) + action('TCP tunneling', isTcpTunneling: true), + if (isWindows && peer.platform == kPeerPlatformWindows) + action('RDP', isRDP: true), ], ); } @@ -676,7 +733,7 @@ abstract class BasePeerCard extends StatelessWidget { @protected MenuEntryBase _rdpAction(BuildContext context, String id) { - final action = MenuEntryButton( + return MenuEntryButton( childBuilder: (TextStyle? style) => Container( alignment: AlignmentDirectional.center, height: CustomPopupMenuTheme.height, @@ -710,8 +767,6 @@ abstract class BasePeerCard extends StatelessWidget { padding: menuPadding, dismissOnClicked: true, ); - return _connectCommonAction(context, translate('RDP'), - isRDP: true, defaultEntry: action); } @protected @@ -1014,33 +1069,13 @@ class RecentPeerCard extends BasePeerCard { @override Future>> _buildMenuItems( BuildContext context) async { - final List> menuItems = [ - _connectAction(context), - _transferFileAction(context), - _viewCameraAction(context), - _terminalAction(context), - ]; - - if (peer.platform == kPeerPlatformWindows) { - menuItems.add(_terminalRunAsAdminAction(context)); - } - final List favs = (await bind.mainGetFav()).toList(); - if (isDesktop && peer.platform != kPeerPlatformAndroid) { - menuItems.add(_tcpTunnelingAction(context)); - } - // menuItems.add(await _openNewConnInOptAction(peer.id)); - if (!isWeb) { - menuItems.add(await _forceAlwaysRelayAction(peer.id)); - } - if (isWindows && peer.platform == kPeerPlatformWindows) { - menuItems.add(_rdpAction(context, peer.id)); - } + final menuItems = await _buildConnectionMenuItems(context); + menuItems.add(MenuEntryDivider()); if (isWindows) { menuItems.add(_createShortCutAction(peer.id)); } - menuItems.add(MenuEntryDivider()); if (isMobile || isDesktop || isWebDesktop) { menuItems.add(_renameAction(peer.id)); } @@ -1079,31 +1114,11 @@ class FavoritePeerCard extends BasePeerCard { @override Future>> _buildMenuItems( BuildContext context) async { - final List> menuItems = [ - _connectAction(context), - _transferFileAction(context), - _viewCameraAction(context), - _terminalAction(context), - ]; - - if (peer.platform == kPeerPlatformWindows) { - menuItems.add(_terminalRunAsAdminAction(context)); - } - - if (isDesktop && peer.platform != kPeerPlatformAndroid) { - menuItems.add(_tcpTunnelingAction(context)); - } - // menuItems.add(await _openNewConnInOptAction(peer.id)); - if (!isWeb) { - menuItems.add(await _forceAlwaysRelayAction(peer.id)); - } - if (isWindows && peer.platform == kPeerPlatformWindows) { - menuItems.add(_rdpAction(context, peer.id)); - } + final menuItems = await _buildConnectionMenuItems(context); + menuItems.add(MenuEntryDivider()); if (isWindows) { menuItems.add(_createShortCutAction(peer.id)); } - menuItems.add(MenuEntryDivider()); if (isMobile || isDesktop || isWebDesktop) { menuItems.add(_renameAction(peer.id)); } @@ -1139,29 +1154,10 @@ class DiscoveredPeerCard extends BasePeerCard { @override Future>> _buildMenuItems( BuildContext context) async { - final List> menuItems = [ - _connectAction(context), - _transferFileAction(context), - _viewCameraAction(context), - _terminalAction(context), - ]; - - if (peer.platform == kPeerPlatformWindows) { - menuItems.add(_terminalRunAsAdminAction(context)); - } - final List favs = (await bind.mainGetFav()).toList(); - if (isDesktop && peer.platform != kPeerPlatformAndroid) { - menuItems.add(_tcpTunnelingAction(context)); - } - // menuItems.add(await _openNewConnInOptAction(peer.id)); - if (!isWeb) { - menuItems.add(await _forceAlwaysRelayAction(peer.id)); - } - if (isWindows && peer.platform == kPeerPlatformWindows) { - menuItems.add(_rdpAction(context, peer.id)); - } + final menuItems = await _buildConnectionMenuItems(context); + menuItems.add(MenuEntryDivider()); menuItems.add(_wolAction(peer.id)); if (isWindows) { menuItems.add(_createShortCutAction(peer.id)); @@ -1198,32 +1194,12 @@ class AddressBookPeerCard extends BasePeerCard { @override Future>> _buildMenuItems( BuildContext context) async { - final List> menuItems = [ - _connectAction(context), - _transferFileAction(context), - _viewCameraAction(context), - _terminalAction(context), - ]; - - if (peer.platform == kPeerPlatformWindows) { - menuItems.add(_terminalRunAsAdminAction(context)); - } - - if (isDesktop && peer.platform != kPeerPlatformAndroid) { - menuItems.add(_tcpTunnelingAction(context)); - } - // menuItems.add(await _openNewConnInOptAction(peer.id)); - if (!isWeb) { - menuItems.add(await _forceAlwaysRelayAction(peer.id)); - } - if (isWindows && peer.platform == kPeerPlatformWindows) { - menuItems.add(_rdpAction(context, peer.id)); - } + final menuItems = await _buildConnectionMenuItems(context); + menuItems.add(MenuEntryDivider()); if (isWindows) { menuItems.add(_createShortCutAction(peer.id)); } if (gFFI.abModel.current.canWrite()) { - menuItems.add(MenuEntryDivider()); if (isMobile || isDesktop || isWebDesktop) { menuItems.add(_renameAction(peer.id)); } @@ -1355,26 +1331,9 @@ class MyGroupPeerCard extends BasePeerCard { @override Future>> _buildMenuItems( BuildContext context) async { - final List> menuItems = [ - _connectAction(context), - _transferFileAction(context), - _viewCameraAction(context), - _terminalAction(context), - ]; - - if (peer.platform == kPeerPlatformWindows) { - menuItems.add(_terminalRunAsAdminAction(context)); - } - - if (isDesktop && peer.platform != kPeerPlatformAndroid) { - menuItems.add(_tcpTunnelingAction(context)); - } - // menuItems.add(await _openNewConnInOptAction(peer.id)); - if (!isWeb) { - menuItems.add(await _forceAlwaysRelayAction(peer.id)); - } - if (isWindows && peer.platform == kPeerPlatformWindows) { - menuItems.add(_rdpAction(context, peer.id)); + final menuItems = await _buildConnectionMenuItems(context); + if (isWindows || gFFI.userModel.userName.isNotEmpty) { + menuItems.add(MenuEntryDivider()); } if (isWindows) { menuItems.add(_createShortCutAction(peer.id)); diff --git a/flutter/lib/common/widgets/request_approval_menu.dart b/flutter/lib/common/widgets/request_approval_menu.dart new file mode 100644 index 000000000..1049e5363 --- /dev/null +++ b/flutter/lib/common/widgets/request_approval_menu.dart @@ -0,0 +1,66 @@ +import 'package:flutter/material.dart'; + +import '../../desktop/widgets/material_mod_popup_menu.dart' as mod_menu; +import '../../desktop/widgets/popup_menu.dart'; + +class RequestApprovalMenu extends MenuEntryBase { + final String title; + final List> entries; + final EdgeInsets? padding; + + RequestApprovalMenu( + {required this.title, required this.entries, this.padding}); + + @override + List> build( + BuildContext context, MenuConfig conf) { + final theme = Theme.of(context); + final buttonPadding = + (TextButtonTheme.of(context).style?.padding?.resolve({}) ?? + ButtonStyleButton.scaledPadding( + theme.useMaterial3 + ? const EdgeInsets.symmetric(horizontal: 12, vertical: 8) + : const EdgeInsets.all(8), + const EdgeInsets.symmetric(horizontal: 8), + const EdgeInsets.symmetric(horizontal: 4), + MediaQuery.textScalerOf(context) + .scale(theme.textTheme.labelLarge?.fontSize ?? 14) / + 14, + )) + .resolve(Directionality.of(context)); + final checkboxTheme = CheckboxTheme.of(context); + final checkboxWidth = + ((checkboxTheme.materialTapTargetSize ?? theme.materialTapTargetSize) == + MaterialTapTargetSize.padded + ? kMinInteractiveDimension + : kMinInteractiveDimension - 8) + + (checkboxTheme.visualDensity ?? theme.visualDensity) + .baseSizeAdjustment + .dx; + final arrowInset = (checkboxWidth - (IconTheme.of(context).size ?? 24)) / 2; + return MenuEntrySubMenu( + text: title, + dismissParentOnCanceled: true, + // Normal entries contain two TextButtons; the submenu adds a leading gap. + padding: (padding ?? EdgeInsets.zero) + .add(EdgeInsets.only( + left: buttonPadding.left * 2, + right: buttonPadding.right * 2 + arrowInset)) + .subtract( + const EdgeInsetsDirectional.only(start: MenuConfig.midPadding)) + .resolve(Directionality.of(context)), + entries: entries + .map((entry) => MenuEntryButton( + childBuilder: entry.childBuilder, + proc: entry.proc, + padding: entry.padding, + enabled: entry.enabled, + dismissOnClicked: true, + dismissCallback: () { + if (Navigator.canPop(context)) Navigator.pop(context); + }, + )) + .toList(), + ).build(context, conf); + } +} diff --git a/flutter/lib/desktop/pages/connection_page.dart b/flutter/lib/desktop/pages/connection_page.dart index 303487f36..f3b516124 100644 --- a/flutter/lib/desktop/pages/connection_page.dart +++ b/flutter/lib/desktop/pages/connection_page.dart @@ -18,6 +18,7 @@ import '../../common.dart'; import '../../common/formatter/id_formatter.dart'; import '../../common/widgets/peer_tab_page.dart'; import '../../common/widgets/autocomplete.dart'; +import '../../common/widgets/request_approval_menu.dart'; import '../../models/platform_model.dart'; import '../../desktop/widgets/material_mod_popup_menu.dart' as mod_menu; @@ -340,6 +341,37 @@ class _ConnectionPageState extends State isTcpTunneling: isTcpTunneling); } + RequestApprovalMenu _requestApprovalMenu(BuildContext context) { + MenuEntryButton action(String title, + {bool isFileTransfer = false, + bool isViewCamera = false, + bool isTerminal = false, + bool isTcpTunneling = false}) => + MenuEntryButton( + childBuilder: (style) => Text(translate(title), style: style), + proc: () => connect(context, _idController.id, + loginMethod: 'request-approval', + isFileTransfer: isFileTransfer, + isViewCamera: isViewCamera, + isTerminal: isTerminal, + isTcpTunneling: isTcpTunneling), + padding: EdgeInsets.symmetric(horizontal: kDesktopMenuPadding.left), + dismissOnClicked: true, + ); + + return RequestApprovalMenu( + title: translate('Request approval'), + padding: EdgeInsets.symmetric(horizontal: kDesktopMenuPadding.left), + entries: [ + action('Connect'), + action('Transfer file', isFileTransfer: true), + action('View camera', isViewCamera: true), + action('${translate('Terminal')} (beta)', isTerminal: true), + if (isDesktop) action('TCP tunneling', isTcpTunneling: true), + ], + ); + } + /// UI for the remote ID TextField. /// Search for a peer. Widget _buildRemoteIDTextField(BuildContext context) { @@ -558,11 +590,6 @@ class _ConnectionPageState extends State context: context, position: RelativeRect.fromLTRB(x, y, x, y), items: [ - ( - 'Connect without password', - () => connect(context, _idController.id, - loginMethod: 'consent') - ), ( 'Transfer file', () => onConnect(isFileTransfer: true) @@ -584,7 +611,8 @@ class _ConnectionPageState extends State () => onConnect(isTcpTunneling: true) ), ] - .map((e) => MenuEntryButton( + .map>( + (e) => MenuEntryButton( childBuilder: (TextStyle? style) => Text( translate(e.$1), @@ -596,6 +624,10 @@ class _ConnectionPageState extends State kDesktopMenuPadding.left), dismissOnClicked: true, )) + .followedBy([ + MenuEntryDivider(), + _requestApprovalMenu(context), + ]) .map((e) => e.build( context, const MenuConfig( diff --git a/flutter/lib/desktop/widgets/popup_menu.dart b/flutter/lib/desktop/widgets/popup_menu.dart index 28432a978..d2a948d8c 100644 --- a/flutter/lib/desktop/widgets/popup_menu.dart +++ b/flutter/lib/desktop/widgets/popup_menu.dart @@ -15,6 +15,7 @@ class PopupMenuChildrenItem extends mod_menu.PopupMenuEntry { this.enabled, this.textStyle, this.onTap, + this.dismissParentOnCanceled = false, this.position = mod_menu.PopupMenuPosition.overSide, this.offset = Offset.zero, required this.itemBuilder, @@ -27,6 +28,7 @@ class PopupMenuChildrenItem extends mod_menu.PopupMenuEntry { final EdgeInsets? padding; final RxBool? enabled; final void Function()? onTap; + final bool dismissParentOnCanceled; final List> Function(BuildContext) itemBuilder; final Widget child; @@ -69,6 +71,13 @@ class MyPopupMenuItemState> position: widget.position, offset: widget.offset, onSelected: handleTap, + onCanceled: widget.dismissParentOnCanceled + ? () { + if (ModalRoute.of(context)?.isCurrent == true) { + Navigator.pop(context); + } + } + : null, itemBuilder: widget.itemBuilder, padding: EdgeInsets.zero, child: AnimatedDefaultTextStyle( @@ -645,11 +654,13 @@ class MenuEntrySubMenu extends MenuEntryBase { final String text; final List> entries; final EdgeInsets? padding; + final bool dismissParentOnCanceled; MenuEntrySubMenu({ required this.text, required this.entries, this.padding, + this.dismissParentOnCanceled = false, RxBool? enabled, }) : super(enabled: enabled); @@ -662,6 +673,7 @@ class MenuEntrySubMenu extends MenuEntryBase { enabled: super.enabled, height: conf.height, padding: padding, + dismissParentOnCanceled: dismissParentOnCanceled, position: mod_menu.PopupMenuPosition.overSide, itemBuilder: (BuildContext context) => entries .map((entry) => entry.build(context, conf)) @@ -678,10 +690,15 @@ class MenuEntrySubMenu extends MenuEntryBase { Expanded( child: Align( alignment: Alignment.centerRight, - child: Obx(() => Icon( - Icons.keyboard_arrow_right, - color: super.enabled!.value ? conf.commonColor : Colors.grey, - )), + child: Transform.scale( + scale: MenuConfig.iconScale, + child: Obx(() => Icon( + Icons.keyboard_arrow_right, + color: super.enabled!.value + ? Theme.of(context).unselectedWidgetColor + : disabledStyle().color, + )), + ), )) ]), ) diff --git a/flutter/lib/mobile/pages/home_page.dart b/flutter/lib/mobile/pages/home_page.dart index 37dc685d5..fbf882593 100644 --- a/flutter/lib/mobile/pages/home_page.dart +++ b/flutter/lib/mobile/pages/home_page.dart @@ -241,8 +241,8 @@ class WebHomePage extends StatelessWidget { password = args[i + 1]; i++; break; - case '--without-password': - loginMethod = 'consent'; + case '--request-approval': + loginMethod = 'request-approval'; break; default: break; diff --git a/flutter/lib/models/model.dart b/flutter/lib/models/model.dart index 5e41dac2e..c3e917b7c 100644 --- a/flutter/lib/models/model.dart +++ b/flutter/lib/models/model.dart @@ -921,9 +921,9 @@ class FfiModel with ChangeNotifier { } else if (type == 'input-password') { enterPasswordDialog(sessionId, dialogManager); } else if (type == 'terminal-admin-login' || - type == 'terminal-admin-login-consent') { + type == 'terminal-admin-login-request-approval') { enterUserLoginDialog(sessionId, dialogManager, 'terminal-admin-login-tip', - waitForAccept: type == 'terminal-admin-login-consent'); + waitForAccept: type == 'terminal-admin-login-request-approval'); } else if (type == 'terminal-admin-login-password') { enterUserLoginAndPasswordDialog( sessionId, dialogManager, 'terminal-admin-login-tip'); diff --git a/flutter/test/login_method_menu_test.dart b/flutter/test/login_method_menu_test.dart deleted file mode 100644 index 634674e39..000000000 --- a/flutter/test/login_method_menu_test.dart +++ /dev/null @@ -1,146 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:flutter_hbb/common/widgets/login_method_menu.dart'; -import 'package:flutter_hbb/desktop/widgets/material_mod_popup_menu.dart' - as mod_menu; -import 'package:flutter_hbb/desktop/widgets/popup_menu.dart'; - -Future openMenu(WidgetTester tester, List actions) async { - MenuEntryButton entry(String title) => MenuEntryButton( - childBuilder: (style) => Text(title, style: style), - proc: () => actions.add(title), - dismissOnClicked: true, - ); - - await tester.pumpWidget(MaterialApp( - home: Scaffold( - body: Builder(builder: (context) { - return TextButton( - onPressed: () => mod_menu.showMenu( - context: context, - position: const RelativeRect.fromLTRB(20, 20, 780, 580), - items: [ - LoginMethodMenu( - defaultEntry: entry('Connect'), - methods: [entry('Without password')], - ), - LoginMethodMenu( - defaultEntry: entry('View camera'), - methods: [entry('Without password')], - ), - LoginMethodMenu( - defaultEntry: MenuEntryButton( - childBuilder: (style) => Row(children: [ - Text('RDP', style: style), - const Spacer(), - IconButton( - icon: const Icon(Icons.edit), - onPressed: () { - Navigator.pop(context); - actions.add('Edit RDP'); - }, - ), - ]), - proc: () => actions.add('RDP'), - ), - methods: [entry('Without password')], - ), - entry('Rename'), - ] - .expand((entry) => entry.build(context, - const MenuConfig(commonColor: Colors.black, height: 20))) - .toList(), - ), - child: const Text('Open menu'), - ); - }), - ), - )); - await tester.tap(find.text('Open menu')); - await tester.pumpAndSettle(); -} - -void main() { - testWidgets('main rows align and clicking them connects by default', - (tester) async { - for (final title in ['Connect', 'View camera', 'RDP']) { - final actions = []; - await openMenu(tester, actions); - final left = tester.getTopLeft(find.text('Rename')).dx; - for (final row in ['Connect', 'View camera', 'RDP']) { - expect(tester.getTopLeft(find.text(row)).dx, left); - } - await tester.tap(find.text(title)); - await tester.pumpAndSettle(); - expect(actions, [title]); - expect(find.text('Without password'), findsNothing); - expect(find.text('Rename'), findsNothing); - } - }); - - testWidgets( - 'arrow offers connection without password and dismisses both menus', - (tester) async { - final actions = []; - await openMenu(tester, actions); - await tester.tap(find.byIcon(Icons.keyboard_arrow_right).first); - await tester.pumpAndSettle(); - expect(actions, isEmpty); - expect(find.text('Without password'), findsOneWidget); - expect(find.text('Enter password manually'), findsNothing); - await tester.tap(find.text('Without password')); - await tester.pumpAndSettle(); - expect(actions, ['Without password']); - expect(find.text('Without password'), findsNothing); - expect(find.text('Rename'), findsNothing); - }, - variant: TargetPlatformVariant({ - TargetPlatform.android, - TargetPlatform.iOS, - TargetPlatform.linux, - TargetPlatform.macOS, - TargetPlatform.windows, - })); - - testWidgets('RDP edit remains independent of the connection action', - (tester) async { - final actions = []; - await openMenu(tester, actions); - await tester.tap(find.byIcon(Icons.edit)); - await tester.pumpAndSettle(); - expect(actions, ['Edit RDP']); - expect(find.text('Rename'), findsNothing); - }); - - testWidgets('touches around the arrow open the submenu without connecting', - (tester) async { - tester.view.physicalSize = const Size(360, 640); - tester.view.devicePixelRatio = 1; - addTearDown(tester.view.resetPhysicalSize); - addTearDown(tester.view.resetDevicePixelRatio); - for (final corner in [ - Alignment.topLeft, - Alignment.topRight, - Alignment.bottomLeft, - Alignment.bottomRight, - ]) { - final actions = []; - await openMenu(tester, actions); - final arrow = find.byIcon(Icons.keyboard_arrow_right).first; - final row = tester - .getRect(find.ancestor(of: arrow, matching: find.byType(Row)).first); - final target = Rect.fromCenter( - center: tester.getCenter(arrow), width: 56, height: row.height); - await tester.tapAt(corner.withinRect(target.deflate(2))); - await tester.pumpAndSettle(); - expect(actions, isEmpty); - expect(find.text('Without password'), findsOneWidget); - await tester.tap(find.text('Without password')); - await tester.pumpAndSettle(); - expect(actions, ['Without password']); - expect(find.text('Rename'), findsNothing); - } - }, - variant: - TargetPlatformVariant({TargetPlatform.android, TargetPlatform.iOS})); -} diff --git a/flutter/test/request_approval_menu_test.dart b/flutter/test/request_approval_menu_test.dart new file mode 100644 index 000000000..9a4f02050 --- /dev/null +++ b/flutter/test/request_approval_menu_test.dart @@ -0,0 +1,222 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:flutter_hbb/common/widgets/request_approval_menu.dart'; +import 'package:flutter_hbb/desktop/widgets/material_mod_popup_menu.dart' + as mod_menu; +import 'package:flutter_hbb/desktop/widgets/popup_menu.dart'; + +const connectionTypes = [ + 'Connect', + 'Transfer file', + 'View camera', + 'Terminal', + 'Terminal (Run as administrator)', + 'TCP tunneling', + 'RDP', +]; + +Future openMenu(WidgetTester tester, List actions, + {ThemeData? theme, EdgeInsets? padding, bool includeRelay = false}) async { + MenuEntryButton entry(String title, {bool requestApproval = false}) => + MenuEntryButton( + childBuilder: (style) => Text(title, style: style), + proc: () => + actions.add(requestApproval ? '$title:request-approval' : title), + padding: padding, + dismissOnClicked: true, + ); + + await tester.pumpWidget(MaterialApp( + theme: theme, + home: Scaffold( + body: Builder(builder: (context) { + return TextButton( + onPressed: () => mod_menu.showMenu( + context: context, + position: const RelativeRect.fromLTRB(20, 20, 780, 580), + items: [ + entry('Connect'), + entry('Transfer file'), + entry('View camera'), + MenuEntryButton( + childBuilder: (style) => Row(children: [ + Text('RDP', style: style), + const Spacer(), + IconButton( + icon: const Icon(Icons.edit), + onPressed: () { + Navigator.pop(context); + actions.add('Edit RDP'); + }, + ), + ]), + proc: () => actions.add('RDP'), + padding: padding, + dismissOnClicked: true, + ), + RequestApprovalMenu( + title: 'Request approval', + padding: padding, + entries: [ + for (final title in connectionTypes) + entry(title, requestApproval: true), + ], + ), + if (includeRelay) + MenuEntrySwitchSync( + switchType: SwitchType.scheckbox, + text: 'Always connect via relay', + currentValue: false, + setter: (_) async {}, + padding: padding, + dismissOnClicked: true, + ), + entry('Rename'), + ] + .expand((entry) => entry.build(context, + const MenuConfig(commonColor: Colors.black, height: 20))) + .toList(), + ), + child: const Text('Open menu'), + ); + }), + ), + )); + await tester.pumpAndSettle(); + await tester.tap(find.text('Open menu')); + await tester.pumpAndSettle(); +} + +void main() { + testWidgets('tapping outside the approval submenu closes both menus', + (tester) async { + final actions = []; + await openMenu(tester, actions); + await tester.tap(find.text('Request approval')); + await tester.pumpAndSettle(); + await tester.tapAt(const Offset(2, 2)); + await tester.pumpAndSettle(); + expect(actions, isEmpty); + expect(find.text('Request approval'), findsNothing); + expect(find.text('Rename'), findsNothing); + expect(find.text('Open menu'), findsOneWidget); + }); + + testWidgets('approval text and arrow align with normal menu items', + (tester) async { + for (final (theme, padding) in [ + (ThemeData(), null), + ( + ThemeData( + useMaterial3: false, + platform: TargetPlatform.windows, + visualDensity: VisualDensity.compact), + const EdgeInsets.only(left: 12, right: 3) + ), + ( + ThemeData(useMaterial3: false), + const EdgeInsets.symmetric(horizontal: 12) + ), + ( + ThemeData( + useMaterial3: false, + textButtonTheme: TextButtonThemeData( + style: TextButton.styleFrom( + padding: const EdgeInsets.symmetric(horizontal: 20)), + )), + null + ), + ]) { + await openMenu(tester, [], + theme: theme, padding: padding, includeRelay: true); + expect(tester.getTopLeft(find.text('Request approval')).dx, + tester.getTopLeft(find.text('Connect')).dx); + expect(tester.getCenter(find.byIcon(Icons.keyboard_arrow_right)).dx, + closeTo(tester.getCenter(find.byType(Checkbox)).dx, 0.01)); + await tester.tap(find.text('Rename')); + await tester.pumpAndSettle(); + } + }); + + testWidgets('normal connections and RDP editing remain direct actions', + (tester) async { + for (final title in [ + 'Connect', + 'Transfer file', + 'View camera', + 'RDP', + 'Edit RDP' + ]) { + final actions = []; + await openMenu(tester, actions); + expect(find.byIcon(Icons.keyboard_arrow_right), findsOneWidget); + final left = tester.getTopLeft(find.text('Rename')).dx; + for (final row in ['Connect', 'Transfer file', 'View camera', 'RDP']) { + expect(tester.getTopLeft(find.text(row)).dx, left); + } + await tester.tap( + title == 'Edit RDP' ? find.byIcon(Icons.edit) : find.text(title)); + await tester.pumpAndSettle(); + expect(actions, [title]); + expect(find.text('Request approval'), findsNothing); + expect(find.text('Rename'), findsNothing); + } + }); + + testWidgets( + 'one approval menu offers all connection types and closes both menus', + (tester) async { + for (var i = 0; i < connectionTypes.length; i++) { + final actions = []; + await openMenu(tester, actions); + await tester.tap(i.isEven + ? find.text('Request approval') + : find.byIcon(Icons.keyboard_arrow_right)); + await tester.pumpAndSettle(); + expect(actions, isEmpty); + for (final title in connectionTypes) { + expect(find.text(title), findsWidgets); + } + await tester.tap(find.text(connectionTypes[i]).last); + await tester.pumpAndSettle(); + expect(actions, ['${connectionTypes[i]}:request-approval']); + expect(find.text('Request approval'), findsNothing); + expect(find.text('Rename'), findsNothing); + } + }, + variant: TargetPlatformVariant({ + TargetPlatform.android, + TargetPlatform.iOS, + TargetPlatform.linux, + TargetPlatform.macOS, + TargetPlatform.windows, + })); + + testWidgets('the whole approval row opens the submenu on a narrow screen', + (tester) async { + tester.view.physicalSize = const Size(360, 640); + tester.view.devicePixelRatio = 1; + addTearDown(tester.view.resetPhysicalSize); + addTearDown(tester.view.resetDevicePixelRatio); + for (final corner in [ + Alignment.topLeft, + Alignment.topRight, + Alignment.bottomLeft, + Alignment.bottomRight, + ]) { + final actions = []; + await openMenu(tester, actions); + final row = tester.getRect(find.byType(PopupMenuChildrenItem)); + await tester.tapAt(corner.withinRect(row.deflate(2))); + await tester.pumpAndSettle(); + expect(actions, isEmpty); + expect(find.text('Terminal (Run as administrator)'), findsOneWidget); + await tester.tap(find.text('Connect').last); + await tester.pumpAndSettle(); + expect(actions, ['Connect:request-approval']); + expect(find.text('Rename'), findsNothing); + } + }, + variant: + TargetPlatformVariant({TargetPlatform.android, TargetPlatform.iOS})); +} diff --git a/flutter/test/uri_login_method_test.dart b/flutter/test/uri_login_method_test.dart index 63d6e3f11..0601a39c1 100644 --- a/flutter/test/uri_login_method_test.dart +++ b/flutter/test/uri_login_method_test.dart @@ -2,7 +2,7 @@ import 'package:flutter_hbb/common.dart'; import 'package:flutter_test/flutter_test.dart'; void main() { - test('without-password links preserve their connection type', () { + test('request-approval links preserve their connection type', () { for (final type in [ 'connect', 'play', @@ -15,32 +15,32 @@ void main() { ]) { expect( urlLinkToCmdArgs( - Uri.parse('rustdesk://$type/123456789?without-password=true')), - ['--$type', '123456789', '--without-password'], + Uri.parse('rustdesk://$type/123456789?request-approval=true')), + ['--$type', '123456789', '--request-approval'], ); } expect( - urlLinkToCmdArgs(Uri.parse('rustdesk://123456789?without-password=true')), - ['--connect', '123456789', '--without-password'], + urlLinkToCmdArgs(Uri.parse('rustdesk://123456789?request-approval=true')), + ['--connect', '123456789', '--request-approval'], ); }); test('omitted and empty passwords retain automatic login', () { expect(urlLinkToCmdArgs(Uri.parse('rustdesk://123456789')), ['--connect', '123456789']); - for (final query in ['password=', 'password=&without-password=false']) { + for (final query in ['password=', 'password=&request-approval=false']) { expect(urlLinkToCmdArgs(Uri.parse('rustdesk://123456789?$query')), ['--connect', '123456789', '--password', '']); } }); - test('without-password ignores an explicit password in either order', () { + test('request-approval ignores an explicit password in either order', () { for (final query in [ - 'password=provided&without-password=true', - 'without-password=true&password=provided', + 'password=provided&request-approval=true', + 'request-approval=true&password=provided', ]) { expect(urlLinkToCmdArgs(Uri.parse('rustdesk://123456789?$query')), - ['--connect', '123456789', '--without-password']); + ['--connect', '123456789', '--request-approval']); } }); } diff --git a/src/client.rs b/src/client.rs index 5cb1e50da..30338df87 100644 --- a/src/client.rs +++ b/src/client.rs @@ -4745,13 +4745,13 @@ pub async fn handle_hash( lc.write().unwrap().password = password.clone(); - let request_consent = lc.read().unwrap().skips_saved_password(); + let request_approval = lc.read().unwrap().skips_saved_password(); let is_terminal_admin = lc.read().unwrap().is_terminal_admin; let is_terminal = lc.read().unwrap().conn_type.eq(&ConnType::TERMINAL); if is_terminal && is_terminal_admin { - if request_consent { - interface.msgbox("terminal-admin-login-consent", "", "", ""); + if request_approval { + interface.msgbox("terminal-admin-login-request-approval", "", "", ""); } else if password.is_empty() { interface.msgbox("terminal-admin-login-password", "", "", ""); } else { @@ -4763,7 +4763,7 @@ pub async fn handle_hash( let password = if password.is_empty() { // login without password, the remote side can click accept - if !request_consent { + if !request_approval { interface.msgbox("input-password", "Password Required", "", ""); } Vec::new() @@ -4774,7 +4774,7 @@ pub async fn handle_hash( hasher.finalize()[..].into() }; - if request_consent { + if request_approval { interface.msgbox( "wait-remote-accept-nook", "Prompt", diff --git a/src/client/login_method.rs b/src/client/login_method.rs index 1554ce7d5..4d74dc6f1 100644 --- a/src/client/login_method.rs +++ b/src/client/login_method.rs @@ -4,13 +4,13 @@ use super::LoginConfigHandler; pub(super) enum LoginMethod { #[default] Automatic, - Consent, + RequestApproval, } impl LoginConfigHandler { pub(crate) fn set_login_method(&mut self, method: &str) -> bool { self.login_method = match method { - "consent" => LoginMethod::Consent, + "request-approval" => LoginMethod::RequestApproval, _ => return false, }; true @@ -23,7 +23,7 @@ impl LoginConfigHandler { pub(crate) fn get_login_method(&self) -> &'static str { match self.login_method { LoginMethod::Automatic => "", - LoginMethod::Consent => "consent", + LoginMethod::RequestApproval => "request-approval", } } } @@ -60,7 +60,7 @@ mod tests { #[test] fn session_creation_initializes_login_method() { let remote_id = hbb_common::config::LocalConfig::get_remote_id(); - for method in ["", "consent"] { + for method in ["", "request-approval"] { let session_id = uuid::Uuid::new_v4(); let result = crate::flutter_ffi::session_add_sync( session_id, @@ -106,7 +106,7 @@ mod tests { .create_login_msg(String::new(), String::new(), vec![1; 32]); assert_eq!( request.login_request().password.is_empty(), - method == "consent" + method == "request-approval" ); } } @@ -132,7 +132,7 @@ mod tests { lc.shared_password = Some("shared password".into()); let token = lc.get_conn_token(); if skip { - assert!(lc.set_login_method("consent")); + assert!(lc.set_login_method("request-approval")); } assert_eq!(lc.get_conn_token(), token); let request = lc.create_login_msg(String::new(), String::new(), vec![4; 32]); @@ -161,13 +161,13 @@ mod tests { } #[tokio::test] - async fn admin_terminal_waits_for_os_credentials_before_requesting_consent() { + async fn admin_terminal_waits_for_os_credentials_before_requesting_approval() { let session = Session::::default(); { let mut lc = session.lc.write().unwrap(); lc.conn_type = ConnType::TERMINAL; lc.is_terminal_admin = true; - assert!(lc.set_login_method("consent")); + assert!(lc.set_login_method("request-approval")); } let (mut stream, mut peer) = connection().await; let mut trust = Default::default(); @@ -203,24 +203,31 @@ mod tests { } #[test] - fn consent_does_not_save_personal_ab_password() { - for consent in [false, true] { + fn request_approval_does_not_save_personal_ab_password() { + for request_approval in [false, true] { let mut lc = client::LoginConfigHandler::default(); - lc.id = format!("consent-ab-password-test-{}", uuid::Uuid::new_v4()); + lc.id = format!("request-approval-ab-password-test-{}", uuid::Uuid::new_v4()); lc.password = vec![3; 32]; lc.password_source = client::PasswordSource::PersonalAb(lc.password.clone()); - if consent { - assert!(lc.set_login_method("consent")); + if request_approval { + assert!(lc.set_login_method("request-approval")); } lc.handle_peer_info(&PeerInfo::default()); let saved = PeerConfig::load(&lc.id).password; PeerConfig::remove(&lc.id); - assert_eq!(saved, if consent { Vec::new() } else { lc.password }); + assert_eq!( + saved, + if request_approval { + Vec::new() + } else { + lc.password + } + ); } } #[tokio::test] - async fn consent_preserves_saved_password() { + async fn request_approval_preserves_saved_password() { let (mut stream, mut peer) = connection().await; let id = format!("skip-saved-password-test-{}", uuid::Uuid::new_v4()); let mut config = PeerConfig::default(); @@ -240,7 +247,7 @@ mod tests { "", ); assert!(!lc.set_login_method("password")); - assert!(lc.set_login_method("consent")); + assert!(lc.set_login_method("request-approval")); } assert!( client::handle_hash( diff --git a/src/core_main.rs b/src/core_main.rs index 9e964bcb9..0f62d1e59 100644 --- a/src/core_main.rs +++ b/src/core_main.rs @@ -776,8 +776,8 @@ fn core_main_invoke_new_connection(mut args: std::env::Args) -> Option { param_array.push(format!("relay=true")); } - "--without-password" => { - param_array.push("without-password=true".to_owned()); + "--request-approval" => { + param_array.push("request-approval=true".to_owned()); } // inner "--switch_uuid" => { diff --git a/src/lang/ar.rs b/src/lang/ar.rs index 7cc0055b6..be896959f 100644 --- a/src/lang/ar.rs +++ b/src/lang/ar.rs @@ -823,8 +823,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Please select Android → media.", "الرجاء اختيار Android → media."), ("Trust duration (days)", "مدة الثقة (بالأيام)"), ("Renew trust", "تجديد الثقة"), - ("Without password", ""), - ("Connect without password", ""), - ("Skip saved passwords and ask the remote user to accept the connection.", ""), + ("Request approval", ""), ].iter().cloned().collect(); } diff --git a/src/lang/az.rs b/src/lang/az.rs index 0004f3e7d..315d498ef 100644 --- a/src/lang/az.rs +++ b/src/lang/az.rs @@ -823,8 +823,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Please select Android → media.", "Zəhmət olmasa, Android → media seçin."), ("Trust duration (days)", "Etibar müddəti (gün)"), ("Renew trust", "Etibarı yenilə"), - ("Without password", ""), - ("Connect without password", ""), - ("Skip saved passwords and ask the remote user to accept the connection.", ""), + ("Request approval", ""), ].iter().cloned().collect(); } diff --git a/src/lang/be.rs b/src/lang/be.rs index f8f461582..442d4fd53 100644 --- a/src/lang/be.rs +++ b/src/lang/be.rs @@ -823,8 +823,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Please select Android → media.", "Выберыце Android → media."), ("Trust duration (days)", "Тэрмін даверу (у днях)"), ("Renew trust", "Падоўжыць давер"), - ("Without password", ""), - ("Connect without password", ""), - ("Skip saved passwords and ask the remote user to accept the connection.", ""), + ("Request approval", ""), ].iter().cloned().collect(); } diff --git a/src/lang/bg.rs b/src/lang/bg.rs index 7a01ef725..f13ffaaad 100644 --- a/src/lang/bg.rs +++ b/src/lang/bg.rs @@ -823,8 +823,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Please select Android → media.", "Моля, изберете Android → media."), ("Trust duration (days)", "Срок на доверие (дни)"), ("Renew trust", "Подновяване на доверието"), - ("Without password", ""), - ("Connect without password", ""), - ("Skip saved passwords and ask the remote user to accept the connection.", ""), + ("Request approval", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ca.rs b/src/lang/ca.rs index 7333f4799..3696f4fa5 100644 --- a/src/lang/ca.rs +++ b/src/lang/ca.rs @@ -823,8 +823,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Please select Android → media.", "Seleccioneu Android → media."), ("Trust duration (days)", "Durada de la confiança (dies)"), ("Renew trust", "Renova la confiança"), - ("Without password", ""), - ("Connect without password", ""), - ("Skip saved passwords and ask the remote user to accept the connection.", ""), + ("Request approval", ""), ].iter().cloned().collect(); } diff --git a/src/lang/cn.rs b/src/lang/cn.rs index 75f228976..7c8d90b2b 100644 --- a/src/lang/cn.rs +++ b/src/lang/cn.rs @@ -823,8 +823,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Please select Android → media.", "请选择 Android → media。"), ("Trust duration (days)", "信任有效期(天)"), ("Renew trust", "延长信任有效期"), - ("Without password", "不使用密码"), - ("Connect without password", "免密连接"), - ("Skip saved passwords and ask the remote user to accept the connection.", "不使用已保存的密码,请求对方接受连接。"), + ("Request approval", "请求批准"), ].iter().cloned().collect(); } diff --git a/src/lang/cs.rs b/src/lang/cs.rs index 4e59a31ab..86d2f0fb4 100644 --- a/src/lang/cs.rs +++ b/src/lang/cs.rs @@ -823,8 +823,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Please select Android → media.", "Vyberte prosím Android → media."), ("Trust duration (days)", "Doba důvěry (dny)"), ("Renew trust", "Obnovit důvěru"), - ("Without password", ""), - ("Connect without password", ""), - ("Skip saved passwords and ask the remote user to accept the connection.", ""), + ("Request approval", ""), ].iter().cloned().collect(); } diff --git a/src/lang/da.rs b/src/lang/da.rs index 0cc567cd5..71f3db823 100644 --- a/src/lang/da.rs +++ b/src/lang/da.rs @@ -823,8 +823,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Please select Android → media.", "Vælg Android → media."), ("Trust duration (days)", "Tillidsperiode (dage)"), ("Renew trust", "Forny tillid"), - ("Without password", ""), - ("Connect without password", ""), - ("Skip saved passwords and ask the remote user to accept the connection.", ""), + ("Request approval", ""), ].iter().cloned().collect(); } diff --git a/src/lang/de.rs b/src/lang/de.rs index 1e57e9f59..c3a945d35 100644 --- a/src/lang/de.rs +++ b/src/lang/de.rs @@ -823,8 +823,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Please select Android → media.", "Bitte wählen Sie Android → media."), ("Trust duration (days)", "Vertrauensdauer (Tage)"), ("Renew trust", "Vertrauen erneuern"), - ("Without password", ""), - ("Connect without password", ""), - ("Skip saved passwords and ask the remote user to accept the connection.", ""), + ("Request approval", ""), ].iter().cloned().collect(); } diff --git a/src/lang/el.rs b/src/lang/el.rs index d8b3a3d67..fbb422edd 100644 --- a/src/lang/el.rs +++ b/src/lang/el.rs @@ -823,8 +823,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Please select Android → media.", "Παρακαλώ επιλέξτε Android → media."), ("Trust duration (days)", "Διάρκεια εμπιστοσύνης (ημέρες)"), ("Renew trust", "Ανανέωση εμπιστοσύνης"), - ("Without password", ""), - ("Connect without password", ""), - ("Skip saved passwords and ask the remote user to accept the connection.", ""), + ("Request approval", ""), ].iter().cloned().collect(); } diff --git a/src/lang/eo.rs b/src/lang/eo.rs index 5fa74fd0e..849e816ac 100644 --- a/src/lang/eo.rs +++ b/src/lang/eo.rs @@ -823,8 +823,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Please select Android → media.", "Bonvolu elekti Android → media."), ("Trust duration (days)", "Daŭro de fido (tagoj)"), ("Renew trust", "Renovigi fidon"), - ("Without password", ""), - ("Connect without password", ""), - ("Skip saved passwords and ask the remote user to accept the connection.", ""), + ("Request approval", ""), ].iter().cloned().collect(); } diff --git a/src/lang/es.rs b/src/lang/es.rs index 30535c6b3..78514e687 100644 --- a/src/lang/es.rs +++ b/src/lang/es.rs @@ -823,8 +823,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Please select Android → media.", "Seleccione Android → media."), ("Trust duration (days)", "Duración de la confianza (días)"), ("Renew trust", "Renovar confianza"), - ("Without password", ""), - ("Connect without password", ""), - ("Skip saved passwords and ask the remote user to accept the connection.", ""), + ("Request approval", ""), ].iter().cloned().collect(); } diff --git a/src/lang/et.rs b/src/lang/et.rs index fab3053c8..2a75be6d9 100644 --- a/src/lang/et.rs +++ b/src/lang/et.rs @@ -823,8 +823,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Please select Android → media.", "Palun vali Android → media."), ("Trust duration (days)", "Usalduse kestus (päevades)"), ("Renew trust", "Uuenda usaldust"), - ("Without password", ""), - ("Connect without password", ""), - ("Skip saved passwords and ask the remote user to accept the connection.", ""), + ("Request approval", ""), ].iter().cloned().collect(); } diff --git a/src/lang/eu.rs b/src/lang/eu.rs index 3ccaf74e9..283e325cc 100644 --- a/src/lang/eu.rs +++ b/src/lang/eu.rs @@ -823,8 +823,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Please select Android → media.", "Hautatu Android → media."), ("Trust duration (days)", "Konfiantzaren iraupena (egunak)"), ("Renew trust", "Berritu konfiantza"), - ("Without password", ""), - ("Connect without password", ""), - ("Skip saved passwords and ask the remote user to accept the connection.", ""), + ("Request approval", ""), ].iter().cloned().collect(); } diff --git a/src/lang/fa.rs b/src/lang/fa.rs index d1e6b76d2..5064f50d3 100644 --- a/src/lang/fa.rs +++ b/src/lang/fa.rs @@ -823,8 +823,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Please select Android → media.", "لطفاً Android → media را انتخاب کنید."), ("Trust duration (days)", "مدت اعتماد (روز)"), ("Renew trust", "تمدید اعتماد"), - ("Without password", ""), - ("Connect without password", ""), - ("Skip saved passwords and ask the remote user to accept the connection.", ""), + ("Request approval", ""), ].iter().cloned().collect(); } diff --git a/src/lang/fi.rs b/src/lang/fi.rs index 70e5e76fe..0f2315a66 100644 --- a/src/lang/fi.rs +++ b/src/lang/fi.rs @@ -823,8 +823,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Please select Android → media.", "Valitse Android → media."), ("Trust duration (days)", "Luottamuksen kesto (päivää)"), ("Renew trust", "Jatka luottamusta"), - ("Without password", ""), - ("Connect without password", ""), - ("Skip saved passwords and ask the remote user to accept the connection.", ""), + ("Request approval", ""), ].iter().cloned().collect(); } diff --git a/src/lang/fr.rs b/src/lang/fr.rs index 75859046e..adc75a0f2 100644 --- a/src/lang/fr.rs +++ b/src/lang/fr.rs @@ -823,8 +823,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Please select Android → media.", "Veuillez sélectionner Android → media."), ("Trust duration (days)", "Durée de confiance (jours)"), ("Renew trust", "Renouveler la confiance"), - ("Without password", ""), - ("Connect without password", ""), - ("Skip saved passwords and ask the remote user to accept the connection.", ""), + ("Request approval", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ge.rs b/src/lang/ge.rs index 107b8f0a9..7085cf831 100644 --- a/src/lang/ge.rs +++ b/src/lang/ge.rs @@ -823,8 +823,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Please select Android → media.", "გთხოვთ, აირჩიოთ Android → media."), ("Trust duration (days)", "ნდობის ხანგრძლივობა (დღე)"), ("Renew trust", "ნდობის განახლება"), - ("Without password", ""), - ("Connect without password", ""), - ("Skip saved passwords and ask the remote user to accept the connection.", ""), + ("Request approval", ""), ].iter().cloned().collect(); } diff --git a/src/lang/gl.rs b/src/lang/gl.rs index 7448caacd..aa7563416 100644 --- a/src/lang/gl.rs +++ b/src/lang/gl.rs @@ -823,8 +823,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Please select Android → media.", "Selecciona Android → media."), ("Trust duration (days)", "Duración da confianza (días)"), ("Renew trust", "Renovar a confianza"), - ("Without password", ""), - ("Connect without password", ""), - ("Skip saved passwords and ask the remote user to accept the connection.", ""), + ("Request approval", ""), ].iter().cloned().collect(); } diff --git a/src/lang/gu.rs b/src/lang/gu.rs index ee58aad1c..59bcc5680 100644 --- a/src/lang/gu.rs +++ b/src/lang/gu.rs @@ -823,8 +823,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Please select Android → media.", "કૃપા કરીને Android → media પસંદ કરો."), ("Trust duration (days)", "વિશ્વાસ અવધિ (દિવસો)"), ("Renew trust", "વિશ્વાસ નવીકરણ કરો"), - ("Without password", ""), - ("Connect without password", ""), - ("Skip saved passwords and ask the remote user to accept the connection.", ""), + ("Request approval", ""), ].iter().cloned().collect(); } diff --git a/src/lang/he.rs b/src/lang/he.rs index 36cca3c9a..e71211e85 100644 --- a/src/lang/he.rs +++ b/src/lang/he.rs @@ -823,8 +823,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Please select Android → media.", "אנא בחר Android → media."), ("Trust duration (days)", "משך האמון (ימים)"), ("Renew trust", "חידוש אמון"), - ("Without password", ""), - ("Connect without password", ""), - ("Skip saved passwords and ask the remote user to accept the connection.", ""), + ("Request approval", ""), ].iter().cloned().collect(); } diff --git a/src/lang/hi.rs b/src/lang/hi.rs index 360962c4d..ebe6b1a35 100644 --- a/src/lang/hi.rs +++ b/src/lang/hi.rs @@ -823,8 +823,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Please select Android → media.", "कृपया Android → media चुनें।"), ("Trust duration (days)", "विश्वास अवधि (दिन)"), ("Renew trust", "विश्वास नवीनीकृत करें"), - ("Without password", ""), - ("Connect without password", ""), - ("Skip saved passwords and ask the remote user to accept the connection.", ""), + ("Request approval", ""), ].iter().cloned().collect(); } diff --git a/src/lang/hr.rs b/src/lang/hr.rs index ff4f0a8af..3d5dcac17 100644 --- a/src/lang/hr.rs +++ b/src/lang/hr.rs @@ -823,8 +823,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Please select Android → media.", "Odaberite Android → media."), ("Trust duration (days)", "Trajanje povjerenja (dani)"), ("Renew trust", "Obnovi povjerenje"), - ("Without password", ""), - ("Connect without password", ""), - ("Skip saved passwords and ask the remote user to accept the connection.", ""), + ("Request approval", ""), ].iter().cloned().collect(); } diff --git a/src/lang/hu.rs b/src/lang/hu.rs index ac4fb3185..9842052ab 100644 --- a/src/lang/hu.rs +++ b/src/lang/hu.rs @@ -823,8 +823,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Please select Android → media.", "Válassza az Android → media mappát."), ("Trust duration (days)", "Megbízhatóság időtartama (nap)"), ("Renew trust", "Megbízhatóság megújítása"), - ("Without password", ""), - ("Connect without password", ""), - ("Skip saved passwords and ask the remote user to accept the connection.", ""), + ("Request approval", ""), ].iter().cloned().collect(); } diff --git a/src/lang/id.rs b/src/lang/id.rs index 3e3577163..81d591f3a 100644 --- a/src/lang/id.rs +++ b/src/lang/id.rs @@ -823,8 +823,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Please select Android → media.", "Silakan pilih Android → media."), ("Trust duration (days)", "Durasi kepercayaan (hari)"), ("Renew trust", "Perbarui kepercayaan"), - ("Without password", ""), - ("Connect without password", ""), - ("Skip saved passwords and ask the remote user to accept the connection.", ""), + ("Request approval", ""), ].iter().cloned().collect(); } diff --git a/src/lang/it.rs b/src/lang/it.rs index 9f0944b2e..b382f1ee7 100644 --- a/src/lang/it.rs +++ b/src/lang/it.rs @@ -823,8 +823,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Please select Android → media.", "Seleziona Android → media."), ("Trust duration (days)", "Durata attendibilità (giorni)"), ("Renew trust", "Rinnova attendibilità"), - ("Without password", ""), - ("Connect without password", ""), - ("Skip saved passwords and ask the remote user to accept the connection.", ""), + ("Request approval", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ja.rs b/src/lang/ja.rs index 23e04d7cb..c7e0e029c 100644 --- a/src/lang/ja.rs +++ b/src/lang/ja.rs @@ -823,8 +823,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Please select Android → media.", "Android → media を選択してください。"), ("Trust duration (days)", "信頼期間 (日)"), ("Renew trust", "信頼を更新"), - ("Without password", ""), - ("Connect without password", ""), - ("Skip saved passwords and ask the remote user to accept the connection.", ""), + ("Request approval", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ko.rs b/src/lang/ko.rs index 371cfb1f3..ec44f4d50 100644 --- a/src/lang/ko.rs +++ b/src/lang/ko.rs @@ -823,8 +823,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Please select Android → media.", "Android → media를 선택해 주시기 바랍니다."), ("Trust duration (days)", "신뢰 유지 기간 (일)"), ("Renew trust", "신뢰 갱신"), - ("Without password", ""), - ("Connect without password", ""), - ("Skip saved passwords and ask the remote user to accept the connection.", ""), + ("Request approval", ""), ].iter().cloned().collect(); } diff --git a/src/lang/kz.rs b/src/lang/kz.rs index ff7a32c4a..1cb2c9a98 100644 --- a/src/lang/kz.rs +++ b/src/lang/kz.rs @@ -823,8 +823,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Please select Android → media.", "Android → media таңдаңыз."), ("Trust duration (days)", "Сенім мерзімі (күн)"), ("Renew trust", "Сенімді жаңарту"), - ("Without password", ""), - ("Connect without password", ""), - ("Skip saved passwords and ask the remote user to accept the connection.", ""), + ("Request approval", ""), ].iter().cloned().collect(); } diff --git a/src/lang/lt.rs b/src/lang/lt.rs index b529a0410..17cf13ad2 100644 --- a/src/lang/lt.rs +++ b/src/lang/lt.rs @@ -823,8 +823,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Please select Android → media.", "Pasirinkite Android → media."), ("Trust duration (days)", "Pasitikėjimo trukmė (dienomis)"), ("Renew trust", "Atnaujinti pasitikėjimą"), - ("Without password", ""), - ("Connect without password", ""), - ("Skip saved passwords and ask the remote user to accept the connection.", ""), + ("Request approval", ""), ].iter().cloned().collect(); } diff --git a/src/lang/lv.rs b/src/lang/lv.rs index 0b8c98948..d3cb2f47d 100644 --- a/src/lang/lv.rs +++ b/src/lang/lv.rs @@ -823,8 +823,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Please select Android → media.", "Lūdzu, atlasiet Android → media."), ("Trust duration (days)", "Uzticēšanās ilgums (dienas)"), ("Renew trust", "Atjaunot uzticēšanos"), - ("Without password", ""), - ("Connect without password", ""), - ("Skip saved passwords and ask the remote user to accept the connection.", ""), + ("Request approval", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ml.rs b/src/lang/ml.rs index 3134fab9a..dcc2191e7 100644 --- a/src/lang/ml.rs +++ b/src/lang/ml.rs @@ -823,8 +823,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Please select Android → media.", "ദയവായി Android → media തിരഞ്ഞെടുക്കുക."), ("Trust duration (days)", "വിശ്വാസ കാലാവധി (ദിവസം)"), ("Renew trust", "വിശ്വാസം പുതുക്കുക"), - ("Without password", ""), - ("Connect without password", ""), - ("Skip saved passwords and ask the remote user to accept the connection.", ""), + ("Request approval", ""), ].iter().cloned().collect(); } diff --git a/src/lang/nb.rs b/src/lang/nb.rs index cf0ab3f99..37e7a1724 100644 --- a/src/lang/nb.rs +++ b/src/lang/nb.rs @@ -823,8 +823,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Please select Android → media.", "Velg Android → media."), ("Trust duration (days)", "Klareringsperiode (dager)"), ("Renew trust", "Forny klarering"), - ("Without password", ""), - ("Connect without password", ""), - ("Skip saved passwords and ask the remote user to accept the connection.", ""), + ("Request approval", ""), ].iter().cloned().collect(); } diff --git a/src/lang/nl.rs b/src/lang/nl.rs index 10122e7b6..20be8aaff 100644 --- a/src/lang/nl.rs +++ b/src/lang/nl.rs @@ -823,8 +823,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Please select Android → media.", "Selecteer Android → media."), ("Trust duration (days)", "Vertrouwensperiode (dagen)"), ("Renew trust", "Vertrouwen hernieuwen"), - ("Without password", ""), - ("Connect without password", ""), - ("Skip saved passwords and ask the remote user to accept the connection.", ""), + ("Request approval", ""), ].iter().cloned().collect(); } diff --git a/src/lang/pl.rs b/src/lang/pl.rs index 986d35070..08e756a8b 100644 --- a/src/lang/pl.rs +++ b/src/lang/pl.rs @@ -823,8 +823,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Please select Android → media.", "Wybierz Android → media."), ("Trust duration (days)", "Okres zaufania (dni)"), ("Renew trust", "Odnów zaufanie"), - ("Without password", ""), - ("Connect without password", ""), - ("Skip saved passwords and ask the remote user to accept the connection.", ""), + ("Request approval", ""), ].iter().cloned().collect(); } diff --git a/src/lang/pt_BR.rs b/src/lang/pt_BR.rs index 4fd9ac507..ac739c1b2 100644 --- a/src/lang/pt_BR.rs +++ b/src/lang/pt_BR.rs @@ -823,8 +823,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Please select Android → media.", "Selecione Android → media."), ("Trust duration (days)", "Duração da confiança (dias)"), ("Renew trust", "Renovar confiança"), - ("Without password", ""), - ("Connect without password", ""), - ("Skip saved passwords and ask the remote user to accept the connection.", ""), + ("Request approval", ""), ].iter().cloned().collect(); } diff --git a/src/lang/pt_PT.rs b/src/lang/pt_PT.rs index af7a83aff..9e8b41eb4 100644 --- a/src/lang/pt_PT.rs +++ b/src/lang/pt_PT.rs @@ -823,8 +823,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Please select Android → media.", "Por favor selecione Android → media."), ("Trust duration (days)", "Duração da confiança (dias)"), ("Renew trust", "Renovar confiança"), - ("Without password", ""), - ("Connect without password", ""), - ("Skip saved passwords and ask the remote user to accept the connection.", ""), + ("Request approval", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ro.rs b/src/lang/ro.rs index 354c11430..f2c963535 100644 --- a/src/lang/ro.rs +++ b/src/lang/ro.rs @@ -823,8 +823,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Please select Android → media.", "Selectează Android → media."), ("Trust duration (days)", "Durata încrederii (zile)"), ("Renew trust", "Reînnoiește încrederea"), - ("Without password", ""), - ("Connect without password", ""), - ("Skip saved passwords and ask the remote user to accept the connection.", ""), + ("Request approval", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ru.rs b/src/lang/ru.rs index 444981948..e16940b67 100644 --- a/src/lang/ru.rs +++ b/src/lang/ru.rs @@ -823,8 +823,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Please select Android → media.", "Выберите Android → media."), ("Trust duration (days)", "Срок доверия (в днях)"), ("Renew trust", "Продлить доверие"), - ("Without password", ""), - ("Connect without password", ""), - ("Skip saved passwords and ask the remote user to accept the connection.", ""), + ("Request approval", ""), ].iter().cloned().collect(); } diff --git a/src/lang/sc.rs b/src/lang/sc.rs index 9a11b2cd8..07fa01e9f 100644 --- a/src/lang/sc.rs +++ b/src/lang/sc.rs @@ -823,8 +823,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Please select Android → media.", "Seletziona Android → media."), ("Trust duration (days)", "Durada de sa fidùtzia (dies)"), ("Renew trust", "Annoa sa fidùtzia"), - ("Without password", ""), - ("Connect without password", ""), - ("Skip saved passwords and ask the remote user to accept the connection.", ""), + ("Request approval", ""), ].iter().cloned().collect(); } diff --git a/src/lang/sk.rs b/src/lang/sk.rs index 75523c8a2..9647d69b4 100644 --- a/src/lang/sk.rs +++ b/src/lang/sk.rs @@ -823,8 +823,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Please select Android → media.", "Vyberte Android → media."), ("Trust duration (days)", "Doba dôvery (dni)"), ("Renew trust", "Obnoviť dôveru"), - ("Without password", ""), - ("Connect without password", ""), - ("Skip saved passwords and ask the remote user to accept the connection.", ""), + ("Request approval", ""), ].iter().cloned().collect(); } diff --git a/src/lang/sl.rs b/src/lang/sl.rs index 5f07f29c7..bd0162c0c 100644 --- a/src/lang/sl.rs +++ b/src/lang/sl.rs @@ -823,8 +823,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Please select Android → media.", "Izberite Android → media."), ("Trust duration (days)", "Trajanje zaupanja (dni)"), ("Renew trust", "Obnovi zaupanje"), - ("Without password", ""), - ("Connect without password", ""), - ("Skip saved passwords and ask the remote user to accept the connection.", ""), + ("Request approval", ""), ].iter().cloned().collect(); } diff --git a/src/lang/sq.rs b/src/lang/sq.rs index 3511599a3..588176f0e 100644 --- a/src/lang/sq.rs +++ b/src/lang/sq.rs @@ -823,8 +823,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Please select Android → media.", "Ju lutemi zgjidhni Android → media."), ("Trust duration (days)", "Kohëzgjatja e besimit (ditë)"), ("Renew trust", "Rinovo besimin"), - ("Without password", ""), - ("Connect without password", ""), - ("Skip saved passwords and ask the remote user to accept the connection.", ""), + ("Request approval", ""), ].iter().cloned().collect(); } diff --git a/src/lang/sr.rs b/src/lang/sr.rs index 3d93b2324..2316f64b4 100644 --- a/src/lang/sr.rs +++ b/src/lang/sr.rs @@ -823,8 +823,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Please select Android → media.", "Izaberite Android → media."), ("Trust duration (days)", "Trajanje poverenja (dani)"), ("Renew trust", "Obnovi poverenje"), - ("Without password", ""), - ("Connect without password", ""), - ("Skip saved passwords and ask the remote user to accept the connection.", ""), + ("Request approval", ""), ].iter().cloned().collect(); } diff --git a/src/lang/sv.rs b/src/lang/sv.rs index 290c477d9..a766a3847 100644 --- a/src/lang/sv.rs +++ b/src/lang/sv.rs @@ -823,8 +823,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Please select Android → media.", "Välj Android → media."), ("Trust duration (days)", "Förtroendeperiod (dagar)"), ("Renew trust", "Förnya förtroende"), - ("Without password", ""), - ("Connect without password", ""), - ("Skip saved passwords and ask the remote user to accept the connection.", ""), + ("Request approval", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ta.rs b/src/lang/ta.rs index e5c85717d..855a570bb 100644 --- a/src/lang/ta.rs +++ b/src/lang/ta.rs @@ -823,8 +823,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Please select Android → media.", "Android → media என்பதைத் தேர்ந்தெடுக்கவும்."), ("Trust duration (days)", "நம்பிக்கைக் காலம் (நாட்கள்)"), ("Renew trust", "நம்பிக்கையைப் புதுப்பி"), - ("Without password", ""), - ("Connect without password", ""), - ("Skip saved passwords and ask the remote user to accept the connection.", ""), + ("Request approval", ""), ].iter().cloned().collect(); } diff --git a/src/lang/template.rs b/src/lang/template.rs index a590cc67f..b5a6d96ce 100644 --- a/src/lang/template.rs +++ b/src/lang/template.rs @@ -823,8 +823,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Please select Android → media.", ""), ("Trust duration (days)", ""), ("Renew trust", ""), - ("Without password", ""), - ("Connect without password", ""), - ("Skip saved passwords and ask the remote user to accept the connection.", ""), + ("Request approval", ""), ].iter().cloned().collect(); } diff --git a/src/lang/th.rs b/src/lang/th.rs index 782783070..7c3831334 100644 --- a/src/lang/th.rs +++ b/src/lang/th.rs @@ -823,8 +823,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Please select Android → media.", "กรุณาเลือก Android → media"), ("Trust duration (days)", "ระยะเวลาการเชื่อถือ (วัน)"), ("Renew trust", "ต่ออายุการเชื่อถือ"), - ("Without password", ""), - ("Connect without password", ""), - ("Skip saved passwords and ask the remote user to accept the connection.", ""), + ("Request approval", ""), ].iter().cloned().collect(); } diff --git a/src/lang/tr.rs b/src/lang/tr.rs index bff3aadaf..f3c28860d 100644 --- a/src/lang/tr.rs +++ b/src/lang/tr.rs @@ -823,8 +823,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Please select Android → media.", "Lütfen Android → media konumunu seçin."), ("Trust duration (days)", "Güven süresi (gün)"), ("Renew trust", "Güveni yenile"), - ("Without password", ""), - ("Connect without password", ""), - ("Skip saved passwords and ask the remote user to accept the connection.", ""), + ("Request approval", ""), ].iter().cloned().collect(); } diff --git a/src/lang/tw.rs b/src/lang/tw.rs index 3f41aa044..fa745d923 100644 --- a/src/lang/tw.rs +++ b/src/lang/tw.rs @@ -823,8 +823,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Please select Android → media.", "請選擇 Android → media。"), ("Trust duration (days)", "信任有效期(天)"), ("Renew trust", "延長信任期限"), - ("Without password", "不使用密碼"), - ("Connect without password", "免密連線"), - ("Skip saved passwords and ask the remote user to accept the connection.", "不使用已儲存的密碼,請求對方接受連線。"), + ("Request approval", "請求批准"), ].iter().cloned().collect(); } diff --git a/src/lang/uk.rs b/src/lang/uk.rs index 2b41a902a..f61eff3c2 100644 --- a/src/lang/uk.rs +++ b/src/lang/uk.rs @@ -823,8 +823,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Please select Android → media.", "Будь ласка, виберіть Android → media."), ("Trust duration (days)", "Термін довіри (у днях)"), ("Renew trust", "Подовжити довіру"), - ("Without password", ""), - ("Connect without password", ""), - ("Skip saved passwords and ask the remote user to accept the connection.", ""), + ("Request approval", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ur.rs b/src/lang/ur.rs index 32f5fe20e..0ffd93df8 100644 --- a/src/lang/ur.rs +++ b/src/lang/ur.rs @@ -823,8 +823,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Please select Android → media.", "براہ کرم Android → media منتخب کریں۔"), ("Trust duration (days)", "اعتماد کی مدت (دن)"), ("Renew trust", "اعتماد کی تجدید کریں"), - ("Without password", ""), - ("Connect without password", ""), - ("Skip saved passwords and ask the remote user to accept the connection.", ""), + ("Request approval", ""), ].iter().cloned().collect(); } diff --git a/src/lang/vi.rs b/src/lang/vi.rs index a0af25460..ccd2a730f 100644 --- a/src/lang/vi.rs +++ b/src/lang/vi.rs @@ -823,8 +823,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Please select Android → media.", "Vui lòng chọn Android → media."), ("Trust duration (days)", "Thời hạn tin cậy (ngày)"), ("Renew trust", "Gia hạn tin cậy"), - ("Without password", ""), - ("Connect without password", ""), - ("Skip saved passwords and ask the remote user to accept the connection.", ""), + ("Request approval", ""), ].iter().cloned().collect(); }