diff --git a/assets/translations/en.json b/assets/translations/en.json index a4ee33d7a9..172bd94902 100644 --- a/assets/translations/en.json +++ b/assets/translations/en.json @@ -126,7 +126,9 @@ "walletCreationEmptySeedError": "Seed should not be empty", "walletCreationExistNameError": "Wallet name exists", "walletCreationNameLengthError": "Name length should be between 1 and 40", - "walletCreationNameCharactersError": "Name can contain only alphanumeric characters", + "walletCreationNameCharactersError": "Name can contain letters, numbers, underscores, and hyphens", + "renameWalletDescription": "Wallet name is invalid. Please enter a new name.", + "renameWalletConfirm": "Rename", "walletCreationFormatPasswordError": "Password must contain at least 8 characters, with at least one digit, one lower-case, one upper-case and one special symbol. The password can't contain the same character 3 times in a row. The password can't contain the word 'password'", "walletCreationConfirmPasswordError": "Your passwords do not match. Please try again.", "incorrectPassword": "Incorrect password", diff --git a/lib/blocs/wallets_repository.dart b/lib/blocs/wallets_repository.dart index e311fffc26..189febb33c 100644 --- a/lib/blocs/wallets_repository.dart +++ b/lib/blocs/wallets_repository.dart @@ -82,7 +82,7 @@ class WalletsRepository { return LocaleKeys.walletCreationExistNameError.tr(); } else if (name.isEmpty || name.length > 40) { return LocaleKeys.walletCreationNameLengthError.tr(); - } else if (!RegExp(r'^[a-zA-Z0-9]+$').hasMatch(name)) { + } else if (!RegExp(r'^[a-zA-Z0-9_-]+$').hasMatch(name)) { return LocaleKeys.walletCreationNameCharactersError.tr(); } diff --git a/lib/generated/codegen_loader.g.dart b/lib/generated/codegen_loader.g.dart index 9e87afb6c2..d8d5c09e1b 100644 --- a/lib/generated/codegen_loader.g.dart +++ b/lib/generated/codegen_loader.g.dart @@ -2,7 +2,7 @@ // ignore_for_file: constant_identifier_names -abstract class LocaleKeys { +abstract class LocaleKeys { static const plsActivateKmd = 'plsActivateKmd'; static const rewardClaiming = 'rewardClaiming'; static const noKmdAddress = 'noKmdAddress'; @@ -106,18 +106,23 @@ abstract class LocaleKeys { static const seedPhrase = 'seedPhrase'; static const assetNumber = 'assetNumber'; static const clipBoard = 'clipBoard'; - static const walletsManagerCreateWalletButton = 'walletsManagerCreateWalletButton'; - static const walletsManagerImportWalletButton = 'walletsManagerImportWalletButton'; - static const walletsManagerStepBuilderCreationWalletError = 'walletsManagerStepBuilderCreationWalletError'; + static const walletsManagerCreateWalletButton = + 'walletsManagerCreateWalletButton'; + static const walletsManagerImportWalletButton = + 'walletsManagerImportWalletButton'; + static const walletsManagerStepBuilderCreationWalletError = + 'walletsManagerStepBuilderCreationWalletError'; static const walletCreationTitle = 'walletCreationTitle'; static const walletImportTitle = 'walletImportTitle'; static const walletImportByFileTitle = 'walletImportByFileTitle'; - static const walletImportCreatePasswordTitle = 'walletImportCreatePasswordTitle'; + static const walletImportCreatePasswordTitle = + 'walletImportCreatePasswordTitle'; static const walletImportByFileDescription = 'walletImportByFileDescription'; static const walletLogInTitle = 'walletLogInTitle'; static const walletCreationNameHint = 'walletCreationNameHint'; static const walletCreationPasswordHint = 'walletCreationPasswordHint'; - static const walletCreationConfirmPasswordHint = 'walletCreationConfirmPasswordHint'; + static const walletCreationConfirmPasswordHint = + 'walletCreationConfirmPasswordHint'; static const walletCreationConfirmPassword = 'walletCreationConfirmPassword'; static const walletCreationUploadFile = 'walletCreationUploadFile'; static const walletCreationEmptySeedError = 'walletCreationEmptySeedError'; @@ -125,22 +130,30 @@ abstract class LocaleKeys { static const walletCreationNameLengthError = 'walletCreationNameLengthError'; static const walletCreationNameCharactersError = 'walletCreationNameCharactersError'; - static const walletCreationFormatPasswordError = 'walletCreationFormatPasswordError'; - static const walletCreationConfirmPasswordError = 'walletCreationConfirmPasswordError'; + static const renameWalletDescription = 'renameWalletDescription'; + static const renameWalletConfirm = 'renameWalletConfirm'; + static const walletCreationFormatPasswordError = + 'walletCreationFormatPasswordError'; + static const walletCreationConfirmPasswordError = + 'walletCreationConfirmPasswordError'; static const incorrectPassword = 'incorrectPassword'; static const importSeedEnterSeedPhraseHint = 'importSeedEnterSeedPhraseHint'; static const passphraseCheckingTitle = 'passphraseCheckingTitle'; static const passphraseCheckingDescription = 'passphraseCheckingDescription'; static const passphraseCheckingEnterWord = 'passphraseCheckingEnterWord'; - static const passphraseCheckingEnterWordHint = 'passphraseCheckingEnterWordHint'; + static const passphraseCheckingEnterWordHint = + 'passphraseCheckingEnterWordHint'; static const back = 'back'; static const settingsMenuGeneral = 'settingsMenuGeneral'; static const settingsMenuLanguage = 'settingsMenuLanguage'; static const settingsMenuSecurity = 'settingsMenuSecurity'; static const settingsMenuAbout = 'settingsMenuAbout'; - static const seedPhraseSettingControlsViewSeed = 'seedPhraseSettingControlsViewSeed'; - static const seedPhraseSettingControlsDownloadSeed = 'seedPhraseSettingControlsDownloadSeed'; - static const debugSettingsResetActivatedCoins = 'debugSettingsResetActivatedCoins'; + static const seedPhraseSettingControlsViewSeed = + 'seedPhraseSettingControlsViewSeed'; + static const seedPhraseSettingControlsDownloadSeed = + 'seedPhraseSettingControlsDownloadSeed'; + static const debugSettingsResetActivatedCoins = + 'debugSettingsResetActivatedCoins'; static const debugSettingsDownloadButton = 'debugSettingsDownloadButton'; static const or = 'or'; static const passwordTitle = 'passwordTitle'; @@ -150,16 +163,19 @@ abstract class LocaleKeys { static const changePasswordSpan1 = 'changePasswordSpan1'; static const updatePassword = 'updatePassword'; static const passwordHasChanged = 'passwordHasChanged'; - static const confirmationForShowingSeedPhraseTitle = 'confirmationForShowingSeedPhraseTitle'; + static const confirmationForShowingSeedPhraseTitle = + 'confirmationForShowingSeedPhraseTitle'; static const saveAndRemember = 'saveAndRemember'; static const seedPhraseShowingTitle = 'seedPhraseShowingTitle'; static const seedPhraseShowingWarning = 'seedPhraseShowingWarning'; static const seedPhraseShowingShowPhrase = 'seedPhraseShowingShowPhrase'; static const seedPhraseShowingCopySeed = 'seedPhraseShowingCopySeed'; - static const seedPhraseShowingSavedPhraseButton = 'seedPhraseShowingSavedPhraseButton'; + static const seedPhraseShowingSavedPhraseButton = + 'seedPhraseShowingSavedPhraseButton'; static const seedAccessSpan1 = 'seedAccessSpan1'; static const backupSeedNotificationTitle = 'backupSeedNotificationTitle'; - static const backupSeedNotificationDescription = 'backupSeedNotificationDescription'; + static const backupSeedNotificationDescription = + 'backupSeedNotificationDescription'; static const backupSeedNotificationButton = 'backupSeedNotificationButton'; static const swapConfirmationTitle = 'swapConfirmationTitle'; static const swapConfirmationYouReceive = 'swapConfirmationYouReceive'; @@ -167,41 +183,54 @@ abstract class LocaleKeys { static const tradingDetailsTitleFailed = 'tradingDetailsTitleFailed'; static const tradingDetailsTitleCompleted = 'tradingDetailsTitleCompleted'; static const tradingDetailsTitleInProgress = 'tradingDetailsTitleInProgress'; - static const tradingDetailsTitleOrderMatching = 'tradingDetailsTitleOrderMatching'; + static const tradingDetailsTitleOrderMatching = + 'tradingDetailsTitleOrderMatching'; static const tradingDetailsTotalSpentTime = 'tradingDetailsTotalSpentTime'; - static const tradingDetailsTotalSpentTimeWithHours = 'tradingDetailsTotalSpentTimeWithHours'; + static const tradingDetailsTotalSpentTimeWithHours = + 'tradingDetailsTotalSpentTimeWithHours'; static const swapRecoverButtonTitle = 'swapRecoverButtonTitle'; static const swapRecoverButtonText = 'swapRecoverButtonText'; static const swapRecoverButtonErrorMessage = 'swapRecoverButtonErrorMessage'; - static const swapRecoverButtonSuccessMessage = 'swapRecoverButtonSuccessMessage'; + static const swapRecoverButtonSuccessMessage = + 'swapRecoverButtonSuccessMessage'; static const swapProgressStatusFailed = 'swapProgressStatusFailed'; static const swapDetailsStepStatusFailed = 'swapDetailsStepStatusFailed'; static const disclaimerAcceptEulaCheckbox = 'disclaimerAcceptEulaCheckbox'; - static const disclaimerAcceptTermsAndConditionsCheckbox = 'disclaimerAcceptTermsAndConditionsCheckbox'; + static const disclaimerAcceptTermsAndConditionsCheckbox = + 'disclaimerAcceptTermsAndConditionsCheckbox'; static const disclaimerAcceptDescription = 'disclaimerAcceptDescription'; - static const swapDetailsStepStatusInProcess = 'swapDetailsStepStatusInProcess'; - static const swapDetailsStepStatusTimeSpent = 'swapDetailsStepStatusTimeSpent'; + static const swapDetailsStepStatusInProcess = + 'swapDetailsStepStatusInProcess'; + static const swapDetailsStepStatusTimeSpent = + 'swapDetailsStepStatusTimeSpent'; static const milliseconds = 'milliseconds'; static const seconds = 'seconds'; static const minutes = 'minutes'; static const hours = 'hours'; - static const coinAddressDetailsNotificationTitle = 'coinAddressDetailsNotificationTitle'; - static const coinAddressDetailsNotificationDescription = 'coinAddressDetailsNotificationDescription'; + static const coinAddressDetailsNotificationTitle = + 'coinAddressDetailsNotificationTitle'; + static const coinAddressDetailsNotificationDescription = + 'coinAddressDetailsNotificationDescription'; static const swapFeeDetailsPaidFromBalance = 'swapFeeDetailsPaidFromBalance'; static const swapFeeDetailsSendCoinTxFee = 'swapFeeDetailsSendCoinTxFee'; - static const swapFeeDetailsReceiveCoinTxFee = 'swapFeeDetailsReceiveCoinTxFee'; + static const swapFeeDetailsReceiveCoinTxFee = + 'swapFeeDetailsReceiveCoinTxFee'; static const swapFeeDetailsTradingFee = 'swapFeeDetailsTradingFee'; - static const swapFeeDetailsSendTradingFeeTxFee = 'swapFeeDetailsSendTradingFeeTxFee'; + static const swapFeeDetailsSendTradingFeeTxFee = + 'swapFeeDetailsSendTradingFeeTxFee'; static const swapFeeDetailsNone = 'swapFeeDetailsNone'; - static const swapFeeDetailsPaidFromReceivedVolume = 'swapFeeDetailsPaidFromReceivedVolume'; + static const swapFeeDetailsPaidFromReceivedVolume = + 'swapFeeDetailsPaidFromReceivedVolume'; static const logoutPopupTitle = 'logoutPopupTitle'; - static const logoutPopupDescriptionWalletOnly = 'logoutPopupDescriptionWalletOnly'; + static const logoutPopupDescriptionWalletOnly = + 'logoutPopupDescriptionWalletOnly'; static const logoutPopupDescription = 'logoutPopupDescription'; static const transactionDetailsTitle = 'transactionDetailsTitle'; static const customSeedWarningText = 'customSeedWarningText'; static const customSeedIUnderstand = 'customSeedIUnderstand'; static const walletCreationBip39SeedError = 'walletCreationBip39SeedError'; - static const walletCreationHdBip39SeedError = 'walletCreationHdBip39SeedError'; + static const walletCreationHdBip39SeedError = + 'walletCreationHdBip39SeedError'; static const walletPageNoSuchAsset = 'walletPageNoSuchAsset'; static const swapCoin = 'swapCoin'; static const fiatBalance = 'fiatBalance'; @@ -273,7 +302,8 @@ abstract class LocaleKeys { static const sellCryptoDescription = 'sellCryptoDescription'; static const buy = 'buy'; static const changingWalletPassword = 'changingWalletPassword'; - static const changingWalletPasswordDescription = 'changingWalletPasswordDescription'; + static const changingWalletPasswordDescription = + 'changingWalletPasswordDescription'; static const dark = 'dark'; static const darkMode = 'darkMode'; static const light = 'light'; @@ -296,7 +326,8 @@ abstract class LocaleKeys { static const email = 'email'; static const emailValidatorError = 'emailValidatorError'; static const feedbackValidatorEmptyError = 'feedbackValidatorEmptyError'; - static const feedbackValidatorMaxLengthError = 'feedbackValidatorMaxLengthError'; + static const feedbackValidatorMaxLengthError = + 'feedbackValidatorMaxLengthError'; static const yourFeedback = 'yourFeedback'; static const sendFeedback = 'sendFeedback'; static const sendFeedbackError = 'sendFeedbackError'; @@ -345,7 +376,8 @@ abstract class LocaleKeys { static const noSenderAddress = 'noSenderAddress'; static const confirmOnTrezor = 'confirmOnTrezor'; static const alphaVersionWarningTitle = 'alphaVersionWarningTitle'; - static const alphaVersionWarningDescription = 'alphaVersionWarningDescription'; + static const alphaVersionWarningDescription = + 'alphaVersionWarningDescription'; static const sendToAnalytics = 'sendToAnalytics'; static const backToWallet = 'backToWallet'; static const backToDex = 'backToDex'; @@ -367,12 +399,14 @@ abstract class LocaleKeys { static const currentPassword = 'currentPassword'; static const walletNotFound = 'walletNotFound'; static const passwordIsEmpty = 'passwordIsEmpty'; - static const passwordContainsTheWordPassword = 'passwordContainsTheWordPassword'; + static const passwordContainsTheWordPassword = + 'passwordContainsTheWordPassword'; static const passwordTooShort = 'passwordTooShort'; static const passwordMissingDigit = 'passwordMissingDigit'; static const passwordMissingLowercase = 'passwordMissingLowercase'; static const passwordMissingUppercase = 'passwordMissingUppercase'; - static const passwordMissingSpecialCharacter = 'passwordMissingSpecialCharacter'; + static const passwordMissingSpecialCharacter = + 'passwordMissingSpecialCharacter'; static const passwordConsecutiveCharacters = 'passwordConsecutiveCharacters'; static const passwordSecurity = 'passwordSecurity'; static const allowWeakPassword = 'allowWeakPassword'; @@ -401,13 +435,16 @@ abstract class LocaleKeys { static const bridgeMaxSendAmountError = 'bridgeMaxSendAmountError'; static const bridgeMinOrderAmountError = 'bridgeMinOrderAmountError'; static const bridgeMaxOrderAmountError = 'bridgeMaxOrderAmountError'; - static const bridgeInsufficientBalanceError = 'bridgeInsufficientBalanceError'; + static const bridgeInsufficientBalanceError = + 'bridgeInsufficientBalanceError'; static const lowTradeVolumeError = 'lowTradeVolumeError'; static const bridgeSelectReceiveCoinError = 'bridgeSelectReceiveCoinError'; static const withdrawNoParentCoinError = 'withdrawNoParentCoinError'; static const withdrawTopUpBalanceError = 'withdrawTopUpBalanceError'; - static const withdrawNotEnoughBalanceForGasError = 'withdrawNotEnoughBalanceForGasError'; - static const withdrawNotSufficientBalanceError = 'withdrawNotSufficientBalanceError'; + static const withdrawNotEnoughBalanceForGasError = + 'withdrawNotEnoughBalanceForGasError'; + static const withdrawNotSufficientBalanceError = + 'withdrawNotSufficientBalanceError'; static const withdrawZeroBalanceError = 'withdrawZeroBalanceError'; static const withdrawAmountTooLowError = 'withdrawAmountTooLowError'; static const withdrawNoSuchCoinError = 'withdrawNoSuchCoinError'; @@ -479,8 +516,10 @@ abstract class LocaleKeys { static const availableForSwaps = 'availableForSwaps'; static const swapNow = 'swapNow'; static const passphrase = 'passphrase'; - static const enterPassphraseHiddenWalletTitle = 'enterPassphraseHiddenWalletTitle'; - static const enterPassphraseHiddenWalletDescription = 'enterPassphraseHiddenWalletDescription'; + static const enterPassphraseHiddenWalletTitle = + 'enterPassphraseHiddenWalletTitle'; + static const enterPassphraseHiddenWalletDescription = + 'enterPassphraseHiddenWalletDescription'; static const skip = 'skip'; static const activateToSeeFunds = 'activateToSeeFunds'; static const allowCustomFee = 'allowCustomFee'; @@ -543,8 +582,10 @@ abstract class LocaleKeys { static const collectibles = 'collectibles'; static const sendingProcess = 'sendingProcess'; static const ercStandardDisclaimer = 'ercStandardDisclaimer'; - static const nftReceiveNonSwapAddressWarning = 'nftReceiveNonSwapAddressWarning'; - static const nftReceiveNonSwapWalletDetails = 'nftReceiveNonSwapWalletDetails'; + static const nftReceiveNonSwapAddressWarning = + 'nftReceiveNonSwapAddressWarning'; + static const nftReceiveNonSwapWalletDetails = + 'nftReceiveNonSwapWalletDetails'; static const nftMainLoggedOut = 'nftMainLoggedOut'; static const confirmLogoutOnAnotherTab = 'confirmLogoutOnAnotherTab'; static const refreshList = 'refreshList'; @@ -558,8 +599,10 @@ abstract class LocaleKeys { static const noWalletsAvailable = 'noWalletsAvailable'; static const selectWalletToReset = 'selectWalletToReset'; static const qrScannerTitle = 'qrScannerTitle'; - static const qrScannerErrorControllerUninitialized = 'qrScannerErrorControllerUninitialized'; - static const qrScannerErrorPermissionDenied = 'qrScannerErrorPermissionDenied'; + static const qrScannerErrorControllerUninitialized = + 'qrScannerErrorControllerUninitialized'; + static const qrScannerErrorPermissionDenied = + 'qrScannerErrorPermissionDenied'; static const qrScannerErrorGenericError = 'qrScannerErrorGenericError'; static const qrScannerErrorTitle = 'qrScannerErrorTitle'; static const spend = 'spend'; @@ -603,7 +646,8 @@ abstract class LocaleKeys { static const fiatPaymentInProgressMessage = 'fiatPaymentInProgressMessage'; static const pleaseWait = 'pleaseWait'; static const bitrefillPaymentSuccessfull = 'bitrefillPaymentSuccessfull'; - static const bitrefillPaymentSuccessfullInstruction = 'bitrefillPaymentSuccessfullInstruction'; + static const bitrefillPaymentSuccessfullInstruction = + 'bitrefillPaymentSuccessfullInstruction'; static const tradingBot = 'tradingBot'; static const margin = 'margin'; static const updateInterval = 'updateInterval'; @@ -679,5 +723,4 @@ abstract class LocaleKeys { static const chart = 'chart'; static const tradingDisabledTooltip = 'tradingDisabledTooltip'; static const tradingDisabled = 'tradingDisabled'; - } diff --git a/lib/views/wallets_manager/widgets/iguana_wallets_manager.dart b/lib/views/wallets_manager/widgets/iguana_wallets_manager.dart index c52dae10b7..6c70492408 100644 --- a/lib/views/wallets_manager/widgets/iguana_wallets_manager.dart +++ b/lib/views/wallets_manager/widgets/iguana_wallets_manager.dart @@ -19,6 +19,8 @@ import 'package:web_dex/views/wallets_manager/widgets/wallet_import_wrapper.dart import 'package:web_dex/views/wallets_manager/widgets/wallet_login.dart'; import 'package:web_dex/views/wallets_manager/widgets/wallets_list.dart'; import 'package:web_dex/views/wallets_manager/widgets/wallets_manager_controls.dart'; +import 'package:web_dex/views/wallets_manager/widgets/wallet_rename_dialog.dart'; +import 'package:web_dex/blocs/wallets_repository.dart'; class IguanaWalletsManager extends StatefulWidget { const IguanaWalletsManager({ @@ -237,6 +239,22 @@ class _IguanaWalletsManagerState extends State { _isLoading = true; }); + final walletsRepository = RepositoryProvider.of(context); + if (wallet.isLegacyWallet) { + final String? error = walletsRepository.validateWalletName(wallet.name); + if (error != null) { + final newName = await walletRenameDialog( + context, + initialName: wallet.name, + ); + if (newName == null) { + if (mounted) setState(() => _isLoading = false); + return; + } + wallet.name = newName; + } + } + final AnalyticsBloc analyticsBloc = context.read(); final analyticsEvent = walletsManagerEventsFactory.createEvent( widget.eventType, diff --git a/lib/views/wallets_manager/widgets/wallet_import_by_file.dart b/lib/views/wallets_manager/widgets/wallet_import_by_file.dart index a6db1852cf..b06c7b26c8 100644 --- a/lib/views/wallets_manager/widgets/wallet_import_by_file.dart +++ b/lib/views/wallets_manager/widgets/wallet_import_by_file.dart @@ -14,6 +14,7 @@ import 'package:web_dex/shared/widgets/disclaimer/eula_tos_checkboxes.dart'; import 'package:web_dex/shared/widgets/password_visibility_control.dart'; import 'package:web_dex/views/wallets_manager/widgets/custom_seed_checkbox.dart'; import 'package:web_dex/views/wallets_manager/widgets/hdwallet_mode_switch.dart'; +import 'package:web_dex/views/wallets_manager/widgets/wallet_rename_dialog.dart'; class WalletFileData { const WalletFileData({required this.content, required this.name}); @@ -219,7 +220,7 @@ class _WalletImportByFileState extends State { } walletConfig.seedPhrase = decryptedSeed; - final String name = widget.fileData.name.split('.').first; + String name = widget.fileData.name.split('.').first; // ignore: use_build_context_synchronously final walletsBloc = RepositoryProvider.of(context); final bool isNameExisted = @@ -230,6 +231,18 @@ class _WalletImportByFileState extends State { }); return; } + String? validationError = walletsBloc.validateWalletName(name); + if (validationError != null) { + // ignore: use_build_context_synchronously + final newName = await walletRenameDialog( + context, + initialName: name, + ); + if (newName == null) { + return; + } + name = newName; + } widget.onImport( name: name, password: _filePasswordController.text, diff --git a/lib/views/wallets_manager/widgets/wallet_rename_dialog.dart b/lib/views/wallets_manager/widgets/wallet_rename_dialog.dart new file mode 100644 index 0000000000..13bfc116b5 --- /dev/null +++ b/lib/views/wallets_manager/widgets/wallet_rename_dialog.dart @@ -0,0 +1,94 @@ +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:komodo_ui_kit/komodo_ui_kit.dart'; +import 'package:web_dex/blocs/wallets_repository.dart'; +import 'package:web_dex/generated/codegen_loader.g.dart'; +import 'package:web_dex/common/screen.dart'; + +Future walletRenameDialog( + BuildContext context, { + required String initialName, +}) async { + late PopupDispatcher popupManager; + bool isOpen = false; + final TextEditingController controller = + TextEditingController(text: initialName); + final walletsRepository = RepositoryProvider.of(context); + String? error; + + void close() { + popupManager.close(); + isOpen = false; + } + + popupManager = PopupDispatcher( + context: context, + popupContent: StatefulBuilder( + builder: (context, setState) { + return Container( + constraints: isMobile ? null : const BoxConstraints(maxWidth: 360), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + LocaleKeys.renameWalletDescription.tr(), + style: const TextStyle(fontSize: 14), + ), + const SizedBox(height: 20), + UiTextFormField( + controller: controller, + autofocus: true, + autocorrect: false, + inputFormatters: [LengthLimitingTextInputFormatter(40)], + errorText: error, + onChanged: (String text) { + setState(() { + error = walletsRepository.validateWalletName(text); + }); + }, + ), + const SizedBox(height: 20), + Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + Flexible( + child: UiUnderlineTextButton( + text: LocaleKeys.cancel.tr(), + onPressed: close, + ), + ), + const SizedBox(width: 12), + Flexible( + child: UiPrimaryButton( + text: LocaleKeys.renameWalletConfirm.tr(), + onPressed: error != null + ? null + : () { + close(); + }, + ), + ), + ], + ), + ], + ), + ); + }, + ), + ); + + isOpen = true; + popupManager.show(); + + while (isOpen) { + await Future.delayed(const Duration(milliseconds: 100)); + } + + final result = controller.text.trim(); + if (result.isEmpty || walletsRepository.validateWalletName(result) != null) { + return null; + } + return result; +}