From 830be0e5966f74b59ca47e0d0c8bff65bdc9c564 Mon Sep 17 00:00:00 2001 From: redDwarf03 Date: Tue, 24 Dec 2024 15:59:06 +0100 Subject: [PATCH 1/8] fix: :bug: TokensListHiveDatasource is not cleared when logout --- lib/application/session/providers.dart | 1 + lib/application/session/session.dart | 1 + 2 files changed, 2 insertions(+) diff --git a/lib/application/session/providers.dart b/lib/application/session/providers.dart index 6b0c93a28..e13577c46 100644 --- a/lib/application/session/providers.dart +++ b/lib/application/session/providers.dart @@ -91,6 +91,7 @@ class SessionNotifier extends _$SessionNotifier with KeychainServiceMixin { await ref.read(SettingsProviders.settings.notifier).reset(); await AuthenticationProviders.reset(ref); await KeychainInfoVaultDatasource.clear(); + await TokensListHiveDatasource.clear(); await _appWalletDatasource.clearAppWallet(); await CacheManagerHive.clear(); await Vault.instance().clearSecureKey(); diff --git a/lib/application/session/session.dart b/lib/application/session/session.dart index 15ce44916..f6cbde0a1 100644 --- a/lib/application/session/session.dart +++ b/lib/application/session/session.dart @@ -11,6 +11,7 @@ import 'package:aewallet/domain/models/core/failures.dart'; import 'package:aewallet/domain/models/core/result.dart'; import 'package:aewallet/infrastructure/datasources/appwallet.hive.dart'; import 'package:aewallet/infrastructure/datasources/keychain_info.vault.dart'; +import 'package:aewallet/infrastructure/datasources/tokens_list.hive.dart'; import 'package:aewallet/infrastructure/datasources/vault/vault.dart'; import 'package:aewallet/model/data/hive_app_wallet_dto.dart'; import 'package:aewallet/util/cache_manager_hive.dart'; From aa7fddea8679694c6b2fbc2333ce5dcf79b0bcdd Mon Sep 17 00:00:00 2001 From: redDwarf03 Date: Wed, 8 Jan 2025 15:46:22 +0100 Subject: [PATCH 2/8] chore: :zap: Take in account https://github.com/archethic-foundation/archethic-node/issues/714 --- lib/domain/models/app_wallet.dart | 1 - .../repositories/nft/nft.repository.dart | 16 ++++------------ 2 files changed, 4 insertions(+), 13 deletions(-) diff --git a/lib/domain/models/app_wallet.dart b/lib/domain/models/app_wallet.dart index 649ea5755..659d6dd04 100644 --- a/lib/domain/models/app_wallet.dart +++ b/lib/domain/models/app_wallet.dart @@ -8,7 +8,6 @@ part 'app_wallet.freezed.dart'; class AppWallet with _$AppWallet { const factory AppWallet({ required String seed, - // TODO(redddwarf03): Mutualize keychain infos required AppKeychain appKeychain, required KeychainSecuredInfos keychainSecuredInfos, }) = _AppWallet; diff --git a/lib/infrastructure/repositories/nft/nft.repository.dart b/lib/infrastructure/repositories/nft/nft.repository.dart index 856d63178..5abc4c4f8 100644 --- a/lib/infrastructure/repositories/nft/nft.repository.dart +++ b/lib/infrastructure/repositories/nft/nft.repository.dart @@ -129,14 +129,6 @@ class NFTRepositoryImpl implements NFTRepository { tokenAddressList.toSet().toList(), ); - // TODO(reddwarf03): temporaly section -> need https://github.com/archethic-foundation/archethic-node/issues/714 - - final secretMap = await apiService.getTransaction( - tokenAddressList.toSet().toList(), - request: - 'data { ownerships { authorizedPublicKeys { encryptedSecretKey, publicKey } secret } }', - ); - for (final tokenBalance in balance.token) { final token = tokenMap[tokenBalance.address]; @@ -146,13 +138,13 @@ class NFTRepositoryImpl implements NFTRepository { final newProperties = {...token.properties}; - if (secretMap[tokenBalance.address] != null && - secretMap[tokenBalance.address]!.data != null && - secretMap[tokenBalance.address]!.data!.ownerships.isNotEmpty) { + if (tokenMap[tokenBalance.address] != null && + tokenMap[tokenBalance.address]!.ownerships != null && + tokenMap[tokenBalance.address]!.ownerships!.isNotEmpty) { newProperties.addAll( _tokenPropertiesDecryptedSecret( keypair: keychainSecuredInfos.services[nameAccount]!.keyPair!, - ownerships: secretMap[tokenBalance.address]!.data!.ownerships, + ownerships: tokenMap[tokenBalance.address]!.ownerships!, ), ); } From 396227ad186b7be67f77d075cd7a3a5d69d9dfd5 Mon Sep 17 00:00:00 2001 From: redDwarf03 Date: Mon, 13 Jan 2025 22:22:01 +0100 Subject: [PATCH 3/8] fix: :construction: Fix accounts dialog usage --- lib/ui/util/accounts_dialog.dart | 25 ++- lib/ui/util/formatters.dart | 58 ------ .../util/transfer_recipient_formatters.dart | 2 +- .../layouts/components/account_list_item.dart | 2 +- .../components/add_account_confirm_sheet.dart | 2 +- ...idity_add_settings_slippage_tolerance.dart | 3 +- .../swap_settings_slippage_tolerance.dart | 3 +- .../nft_search/layouts/nft_search_bar.dart | 50 +++-- .../token_selection_common_bases.dart | 3 +- lib/ui/views/transfer/bloc/provider.dart | 55 +++--- .../transfer_textfield_address.dart | 83 ++++++--- .../components/transfer_token_detail.dart | 4 +- .../transfer/layouts/transfer_sheet.dart | 2 +- lib/ui/widgets/dialogs/accounts_dialog.dart | 172 ------------------ lib/util/account_formatters.dart | 5 +- pubspec.lock | 32 ++-- pubspec.yaml | 7 +- 17 files changed, 157 insertions(+), 351 deletions(-) delete mode 100644 lib/ui/widgets/dialogs/accounts_dialog.dart diff --git a/lib/ui/util/accounts_dialog.dart b/lib/ui/util/accounts_dialog.dart index 2ac1f84b8..30ad8dc3d 100644 --- a/lib/ui/util/accounts_dialog.dart +++ b/lib/ui/util/accounts_dialog.dart @@ -3,7 +3,6 @@ import 'dart:async'; import 'dart:ui'; -import 'package:aewallet/application/account/accounts_notifier.dart'; import 'package:aewallet/model/data/account.dart'; import 'package:aewallet/ui/themes/archethic_theme.dart'; import 'package:aewallet/ui/themes/styles.dart'; @@ -16,31 +15,27 @@ import 'package:archethic_dapp_framework_flutter/archethic_dapp_framework_flutte import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/localizations.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:go_router/go_router.dart'; import 'package:modal_bottom_sheet/modal_bottom_sheet.dart'; class AccountsDialog { static Future selectSingleAccount({ required BuildContext context, - required WidgetRef ref, required List accounts, String? dialogTitle, Widget? header, bool? isModal = false, + double? heightFactor = 1, }) async { - final selection = await _showAccountsDialog( + return await _showAccountsDialog( context: context, accounts: accounts, multipleSelectionsAllowed: false, dialogTitle: dialogTitle, header: header, isModal: isModal, + heightFactor: heightFactor, ) as Account?; - if (selection != null) { - await ref - .read(accountsNotifierProvider.notifier) - .selectAccount(selection); - } - return selection; } static Future?> selectMultipleAccounts({ @@ -50,6 +45,7 @@ class AccountsDialog { String? dialogTitle, Widget? header, bool? isModal = false, + double? heightFactor = 1, }) async { return await _showAccountsDialog( context: context, @@ -59,6 +55,7 @@ class AccountsDialog { dialogTitle: dialogTitle, header: header, isModal: isModal, + heightFactor: heightFactor, ) as List?; } @@ -70,6 +67,7 @@ class AccountsDialog { String? dialogTitle, Widget? header, bool? isModal = false, + double? heightFactor = 1, }) async { final pickerItemsList = >[]; @@ -116,7 +114,7 @@ class AccountsDialog { context: context, builder: (BuildContext context) { return FractionallySizedBox( - heightFactor: 1, + heightFactor: heightFactor, child: Scaffold( backgroundColor: aedappfm.AppThemeBase.sheetBackground.withOpacity(0.2), @@ -204,7 +202,7 @@ class AccountsDialogContentState extends ConsumerState { scrollable: true, onSelected: (pickerItem) { if (!widget.multipleSelectionsAllowed) { - Navigator.of(context).pop(pickerItem.value); + context.pop(pickerItem.value); } }, onUnselected: (selectedIndexes) { @@ -255,8 +253,7 @@ class AccountsDialogContentState extends ConsumerState { final _accountsList = pickerItemsListSelected .map((item) => item.value) .toList(); - - Navigator.of(context).pop(_accountsList); + context.pop(_accountsList); }, disabled: pickerItemsListSelected.isEmpty, ), @@ -268,7 +265,7 @@ class AccountsDialogContentState extends ConsumerState { localizations.cancel, Dimens.buttonBottomDimens, onPressed: () { - Navigator.of(context).pop(); + context.pop(); }, ), ], diff --git a/lib/ui/util/formatters.dart b/lib/ui/util/formatters.dart index 5d8ce9263..63f097b13 100644 --- a/lib/ui/util/formatters.dart +++ b/lib/ui/util/formatters.dart @@ -4,64 +4,6 @@ import 'dart:math'; import 'package:flutter/services.dart'; -/// Input formatter that ensures text starts with @ -class ContactInputFormatter extends TextInputFormatter { - @override - TextEditingValue formatEditUpdate( - TextEditingValue oldValue, - TextEditingValue newValue, - ) { - if (newValue.selection.baseOffset == 0) { - return newValue; - } - - var workingText = newValue.text; - if (!workingText.startsWith('@')) { - workingText = '@$workingText'; - } - - final splitStr = workingText.split('@'); - // If this string contains more than 1 @, remove all but the first one - if (splitStr.length > 2) { - workingText = '@${workingText.replaceAll('@', '')}'; - } - - // If nothing changed, return original - if (workingText == newValue.text) { - return newValue; - } - - return newValue.copyWith( - text: workingText, - selection: TextSelection.collapsed(offset: workingText.length), - ); - } -} - -/// Input formatter that ensures only one space between words -class SingleSpaceInputFormatter extends TextInputFormatter { - @override - TextEditingValue formatEditUpdate( - TextEditingValue oldValue, - TextEditingValue newValue, - ) { - if (newValue.selection.baseOffset == 0) { - return newValue; - } - - // Don't allow first character to be a space - if (newValue.text.length < oldValue.text.length) { - return newValue; - } else if (oldValue.text.isEmpty && newValue.text == ' ') { - return oldValue; - } else if (oldValue.text.endsWith(' ') && newValue.text.endsWith(' ')) { - return oldValue; - } - - return newValue; - } -} - /// Ensures input is always uppercase class UpperCaseTextFormatter extends TextInputFormatter { @override diff --git a/lib/ui/util/transfer_recipient_formatters.dart b/lib/ui/util/transfer_recipient_formatters.dart index 7f99a8b1b..2909d5e84 100644 --- a/lib/ui/util/transfer_recipient_formatters.dart +++ b/lib/ui/util/transfer_recipient_formatters.dart @@ -10,6 +10,6 @@ extension TransferRecipientFormatters on TransferRecipient { ? localizations.burnAddressLbl : AddressFormatters(address.address!).getShortString(), account: (account) => account.format, - unknownContact: (name) => name.replaceFirst('@', ''), + unknownContact: (name) => name, ); } diff --git a/lib/ui/views/accounts/layouts/components/account_list_item.dart b/lib/ui/views/accounts/layouts/components/account_list_item.dart index 248e87747..5bf721e8c 100644 --- a/lib/ui/views/accounts/layouts/components/account_list_item.dart +++ b/lib/ui/views/accounts/layouts/components/account_list_item.dart @@ -165,7 +165,7 @@ class _AccountListItemState extends ConsumerState if (widget.selectedAccount?.nameDisplayed == widget.account.nameDisplayed) { - Navigator.of(context).pop(); + context.pop(); return; } context.loadingOverlay.show(); diff --git a/lib/ui/views/add_account/layouts/components/add_account_confirm_sheet.dart b/lib/ui/views/add_account/layouts/components/add_account_confirm_sheet.dart index d9b5e06dd..af1441ca1 100755 --- a/lib/ui/views/add_account/layouts/components/add_account_confirm_sheet.dart +++ b/lib/ui/views/add_account/layouts/components/add_account_confirm_sheet.dart @@ -67,7 +67,7 @@ class _AddAccountConfirmState extends ConsumerState icon: Symbols.info, ); context.loadingOverlay.hide(); - Navigator.of(context).pop(); + context.pop(); } Future _showSendSucceed( diff --git a/lib/ui/views/aeswap_liquidity_add/layouts/components/liquidity_add_settings_slippage_tolerance.dart b/lib/ui/views/aeswap_liquidity_add/layouts/components/liquidity_add_settings_slippage_tolerance.dart index c625a0386..aca26c27d 100644 --- a/lib/ui/views/aeswap_liquidity_add/layouts/components/liquidity_add_settings_slippage_tolerance.dart +++ b/lib/ui/views/aeswap_liquidity_add/layouts/components/liquidity_add_settings_slippage_tolerance.dart @@ -11,6 +11,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_gen/gen_l10n/localizations.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:go_router/go_router.dart'; class LiquiditySettingsSlippageTolerance extends ConsumerStatefulWidget { const LiquiditySettingsSlippageTolerance({ @@ -155,7 +156,7 @@ class LiquiditySettingsSlippageToleranceState double.tryParse(slippageToleranceController.text) ?? 0, ); if (!context.mounted) return; - Navigator.of(context).pop(); + context.pop(); }, isConnected: true, displayWalletConnectOnPressed: () {}, diff --git a/lib/ui/views/aeswap_swap/layouts/components/swap_settings_slippage_tolerance.dart b/lib/ui/views/aeswap_swap/layouts/components/swap_settings_slippage_tolerance.dart index 57160dffd..d9ff3cac8 100644 --- a/lib/ui/views/aeswap_swap/layouts/components/swap_settings_slippage_tolerance.dart +++ b/lib/ui/views/aeswap_swap/layouts/components/swap_settings_slippage_tolerance.dart @@ -9,6 +9,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_gen/gen_l10n/localizations.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:go_router/go_router.dart'; class SwapSettingsSlippageTolerance extends ConsumerStatefulWidget { const SwapSettingsSlippageTolerance({ @@ -155,7 +156,7 @@ class SwapSettingsSlippageToleranceState ); if (!context.mounted) return; - Navigator.of(context).pop(); + context.pop(); }, isConnected: true, displayWalletConnectOnPressed: () {}, diff --git a/lib/ui/views/nft_search/layouts/nft_search_bar.dart b/lib/ui/views/nft_search/layouts/nft_search_bar.dart index 826658e9f..9026d18bb 100644 --- a/lib/ui/views/nft_search/layouts/nft_search_bar.dart +++ b/lib/ui/views/nft_search/layouts/nft_search_bar.dart @@ -55,14 +55,10 @@ class _NFTSearchBarState extends ConsumerState { @override Widget build(BuildContext context) { final hasQRCode = ref.watch(DeviceAbilities.hasQRCodeProvider); - final session = ref.watch(sessionNotifierProvider).loggedIn!; final localizations = AppLocalizations.of(context)!; final nftSearchBar = ref.watch( NftSearchBarFormProvider.nftSearchBar, ); - final nftSearchBarNotifier = ref.watch( - NftSearchBarFormProvider.nftSearchBar.notifier, - ); final connectivityStatusProvider = ref.watch(connectivityStatusProviders); ref.listen( NftSearchBarFormProvider.nftSearchBar, @@ -83,7 +79,11 @@ class _NFTSearchBarState extends ConsumerState { }, ); - nftSearchBarNotifier.reset(); + ref + .read( + NftSearchBarFormProvider.nftSearchBar.notifier, + ) + .reset(); return; } @@ -98,7 +98,11 @@ class _NFTSearchBarState extends ConsumerState { duration: const Duration(seconds: 5), ); - nftSearchBarNotifier.setError(''); + ref + .read( + NftSearchBarFormProvider.nftSearchBar.notifier, + ) + .setError(''); }, ); @@ -151,7 +155,11 @@ class _NFTSearchBarState extends ConsumerState { return; } else { final address = Address(address: scanResult); - nftSearchBarNotifier + ref + .read( + NftSearchBarFormProvider + .nftSearchBar.notifier, + ) .setSearchCriteria(address.address!); _updateAdressTextController(); } @@ -167,7 +175,11 @@ class _NFTSearchBarState extends ConsumerState { ), suffixIcon: PasteIcon( onPaste: (String value) { - nftSearchBarNotifier.setSearchCriteria(value); + ref + .read( + NftSearchBarFormProvider.nftSearchBar.notifier, + ) + .setSearchCriteria(value); _updateAdressTextController(); }, ), @@ -205,15 +217,25 @@ class _NFTSearchBarState extends ConsumerState { ConnectivityStatus.isConnected ? null : () async { + final session = + ref.read(sessionNotifierProvider).loggedIn!; final selectedAccount = await session .wallet.appKeychain .getAccountSelected(); - await nftSearchBarNotifier.searchNFT( - searchController.text, - context, - session.wallet.keychainSecuredInfos - .services[selectedAccount!.name]!.keyPair!, - ); + await ref + .read( + NftSearchBarFormProvider + .nftSearchBar.notifier, + ) + .searchNFT( + searchController.text, + context, + session + .wallet + .keychainSecuredInfos + .services[selectedAccount!.name]! + .keyPair!, + ); }, child: Container( height: 30, diff --git a/lib/ui/views/token_selection/layouts/components/token_selection_common_bases.dart b/lib/ui/views/token_selection/layouts/components/token_selection_common_bases.dart index 7c345a3ba..1163fc8c5 100644 --- a/lib/ui/views/token_selection/layouts/components/token_selection_common_bases.dart +++ b/lib/ui/views/token_selection/layouts/components/token_selection_common_bases.dart @@ -8,6 +8,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/localizations.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_svg/svg.dart'; +import 'package:go_router/go_router.dart'; import 'package:gradient_borders/gradient_borders.dart'; class TokenSelectionCommonBases extends ConsumerWidget { @@ -76,7 +77,7 @@ class _TokenSelector extends StatelessWidget { ), child: InkWell( onTap: () { - Navigator.pop(context, token); + context.pop(token); }, child: Row( children: [ diff --git a/lib/ui/views/transfer/bloc/provider.dart b/lib/ui/views/transfer/bloc/provider.dart index 00cf11c3d..6025b7a2c 100644 --- a/lib/ui/views/transfer/bloc/provider.dart +++ b/lib/ui/views/transfer/bloc/provider.dart @@ -203,18 +203,28 @@ class TransferFormNotifier extends AutoDisposeNotifier { required String text, required archethic.ApiService apiService, }) async { - if (!text.startsWith('@')) { - if (!archethic.Address(address: text).isValid()) { + if (archethic.Address(address: text).isValid()) { + final account = await ref.read( + accountWithGenesisAddressProvider(text).future, + ); + if (account != null) { _setRecipient( - recipient: TransferRecipient.unknownContact( - name: text, + recipient: TransferRecipient.account( + account: account, ), ); - return; + } else { + _setRecipient( + recipient: TransferRecipient.address( + address: archethic.Address(address: text), + ), + ); + await _checkAddressType(context); } - - final account = - await ref.read(accountWithGenesisAddressProvider(text).future); + } else { + final account = await ref.read( + accountWithNameProvider(text).future, + ); if (account != null) { _setRecipient( recipient: TransferRecipient.account( @@ -223,38 +233,15 @@ class TransferFormNotifier extends AutoDisposeNotifier { ); } else { _setRecipient( - recipient: TransferRecipient.address( - address: archethic.Address(address: text), + recipient: TransferRecipient.unknownContact( + name: text, ), ); } - - if (await _checkAddressType(context) == false) { - return; - } - unawaited(_updateFees(context)); - return; } - try { - final account = await ref.read(accountWithNameProvider(text).future); - - _setRecipient( - recipient: TransferRecipient.account( - account: account!, - ), - ); - } catch (e) { - _setRecipient( - recipient: TransferRecipient.unknownContact( - name: text, - ), - ); - } - if (await _checkAddressType(context) == false) { - return; - } unawaited(_updateFees(context)); + return; } void setRecipient({ diff --git a/lib/ui/views/transfer/layouts/components/transfer_textfield_address.dart b/lib/ui/views/transfer/layouts/components/transfer_textfield_address.dart index fb312c984..0e2c57693 100644 --- a/lib/ui/views/transfer/layouts/components/transfer_textfield_address.dart +++ b/lib/ui/views/transfer/layouts/components/transfer_textfield_address.dart @@ -41,11 +41,15 @@ class _TransferTextFieldAddressState void _updateAdressTextController() { final recipient = ref.read(TransferFormProvider.transferForm).recipient; - sendAddressController.text = recipient.when( + final newText = recipient.when( address: (address) => address.address!, - account: (account) => account.format, + account: (account) => account.nameDisplayed, unknownContact: (name) => name, ); + + if (sendAddressController.text != newText) { + sendAddressController.text = newText; + } } @override @@ -53,10 +57,9 @@ class _TransferTextFieldAddressState BuildContext context, ) { final transfer = ref.watch(TransferFormProvider.transferForm); - final transferNotifier = - ref.watch(TransferFormProvider.transferForm.notifier); final hasQRCode = ref.watch(DeviceAbilities.hasQRCodeProvider); - final apiService = ref.watch(apiServiceProvider); + + final localizations = AppLocalizations.of(context)!; if (sendAddressController.text.isNotEmpty) { _updateAdressTextController(); @@ -114,12 +117,17 @@ class _TransferTextFieldAddressState autocorrect: false, controller: sendAddressController, onChanged: (text) async { - await transferNotifier + await ref + .read( + TransferFormProvider + .transferForm.notifier, + ) .setRecipientNameOrAddress( - context: context, - text: text, - apiService: apiService, - ); + context: context, + text: text, + apiService: + ref.read(apiServiceProvider), + ); }, focusNode: sendAddressFocusNode, textInputAction: TextInputAction.next, @@ -177,11 +185,13 @@ class _TransferTextFieldAddressState } else { // Is a URI final address = Address(address: scanResult); - await transferNotifier.setContactAddress( - context: context, - address: address, - apiService: apiService, - ); + await ref + .read(TransferFormProvider.transferForm.notifier) + .setContactAddress( + context: context, + address: address, + apiService: ref.read(apiServiceProvider), + ); _updateAdressTextController(); } }, @@ -189,26 +199,47 @@ class _TransferTextFieldAddressState PasteIcon( onPaste: (String value) { sendAddressController.text = value; - transferNotifier.setRecipientNameOrAddress( - context: context, - text: value, - apiService: apiService, - ); + ref + .read(TransferFormProvider.transferForm.notifier) + .setRecipientNameOrAddress( + context: context, + text: value, + apiService: ref.read(apiServiceProvider), + ); }, ), TextFieldButton( icon: Symbols.contacts, onPressed: () async { - final account = - await AccountsDialog.getDialog(context, ref); - if (account == null) return; + final accounts = + await ref.read(accountsNotifierProvider.future); + final accountSelected = await ref + .read(accountsNotifierProvider.future) + .selectedAccount; + final filteredAccounts = accounts + ..removeWhere( + (element) => + element.format.toUpperCase() == + accountSelected?.format.toUpperCase(), + ); - transferNotifier.setRecipient( + final account = await AccountsDialog.selectSingleAccount( context: context, - contact: TransferRecipient.account(account: account), + accounts: filteredAccounts, + dialogTitle: localizations.accountsHeader, + isModal: true, + heightFactor: 0.5, ); - _updateAdressTextController(); + if (account == null) return; + sendAddressController.text = account.nameDisplayed; + ref + .read(TransferFormProvider.transferForm.notifier) + .setRecipient( + context: context, + contact: + TransferRecipient.account(account: account), + ); }, ), ], diff --git a/lib/ui/views/transfer/layouts/components/transfer_token_detail.dart b/lib/ui/views/transfer/layouts/components/transfer_token_detail.dart index 24c1c2ae8..38dac70d4 100644 --- a/lib/ui/views/transfer/layouts/components/transfer_token_detail.dart +++ b/lib/ui/views/transfer/layouts/components/transfer_token_detail.dart @@ -10,7 +10,7 @@ import 'package:auto_size_text/auto_size_text.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_svg/flutter_svg.dart'; - +import 'package:go_router/go_router.dart'; import 'package:material_symbols_icons/symbols.dart'; class TransferTokenDetail extends ConsumerStatefulWidget { @@ -45,7 +45,7 @@ class _TransferTokenDetailState extends ConsumerState { padding: const EdgeInsets.only(bottom: 8), child: InkWell( onTap: () async { - Navigator.pop(context, widget.aeToken); + context.pop(widget.aeToken); }, child: aedappfm.BlockInfo( width: MediaQuery.of(context).size.width, diff --git a/lib/ui/views/transfer/layouts/transfer_sheet.dart b/lib/ui/views/transfer/layouts/transfer_sheet.dart index b2d03b472..07d466ef0 100755 --- a/lib/ui/views/transfer/layouts/transfer_sheet.dart +++ b/lib/ui/views/transfer/layouts/transfer_sheet.dart @@ -8,6 +8,7 @@ import 'package:aewallet/model/primary_currency.dart'; import 'package:aewallet/modules/aeswap/domain/models/dex_token.dart'; import 'package:aewallet/ui/themes/archethic_theme.dart'; import 'package:aewallet/ui/themes/styles.dart'; +import 'package:aewallet/ui/util/accounts_dialog.dart'; import 'package:aewallet/ui/util/amount_formatters.dart'; import 'package:aewallet/ui/util/formatters.dart'; import 'package:aewallet/ui/util/ui_util.dart'; @@ -18,7 +19,6 @@ import 'package:aewallet/ui/views/transfer/layouts/components/transfer_form_shee import 'package:aewallet/ui/views/transfer/layouts/components/transfer_token_selection.dart'; import 'package:aewallet/ui/widgets/components/app_text_field.dart'; import 'package:aewallet/ui/widgets/components/paste_icon.dart'; -import 'package:aewallet/ui/widgets/dialogs/accounts_dialog.dart'; import 'package:aewallet/ui/widgets/tokens/verified_token_icon.dart'; import 'package:aewallet/util/account_formatters.dart'; import 'package:aewallet/util/currency_util.dart'; diff --git a/lib/ui/widgets/dialogs/accounts_dialog.dart b/lib/ui/widgets/dialogs/accounts_dialog.dart deleted file mode 100644 index dfd7a4b66..000000000 --- a/lib/ui/widgets/dialogs/accounts_dialog.dart +++ /dev/null @@ -1,172 +0,0 @@ -/// SPDX-License-Identifier: AGPL-3.0-or-later - -import 'dart:ui'; - -import 'package:aewallet/application/account/accounts_notifier.dart'; -import 'package:aewallet/model/data/account.dart'; -import 'package:aewallet/ui/themes/archethic_theme.dart'; -import 'package:aewallet/ui/themes/styles.dart'; -import 'package:aewallet/ui/util/formatters.dart'; -import 'package:aewallet/ui/widgets/components/app_text_field.dart'; -import 'package:aewallet/ui/widgets/components/picker_item.dart'; -import 'package:aewallet/util/account_formatters.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; -import 'package:flutter_gen/gen_l10n/localizations.dart'; -import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:go_router/go_router.dart'; - -class AccountsDialog { - static Future getDialog( - BuildContext context, - WidgetRef ref, - ) async { - return showDialog( - context: context, - useRootNavigator: false, - builder: (BuildContext context) { - return AccountsDialogWidget(ref: ref); - }, - ); - } -} - -class AccountsDialogWidget extends StatefulWidget { - const AccountsDialogWidget({super.key, required this.ref}); - final WidgetRef ref; - - @override - AccountsDialogWidgetState createState() => AccountsDialogWidgetState(); -} - -class AccountsDialogWidgetState extends State { - late final FocusNode _searchNameFocusNode; - late final TextEditingController _searchNameController; - - List pickerItemsList = []; - late List accounts; - Account? accountSelected; - - @override - void initState() { - super.initState(); - _searchNameFocusNode = FocusNode(); - _searchNameController = TextEditingController(); - _initializeAccounts(); - } - - Future _initializeAccounts() async { - accounts = await widget.ref.read(accountsNotifierProvider.future); - accountSelected = - await widget.ref.read(accountsNotifierProvider.future).selectedAccount; - _filterAccounts('', accounts, accountSelected); - } - - @override - void dispose() { - _searchNameFocusNode.dispose(); - _searchNameController.dispose(); - super.dispose(); - } - - void _filterAccounts( - String text, - List accounts, - Account? accountSelected, - ) { - final filteredAccounts = accounts - ..removeWhere( - (element) => - element.format.toUpperCase() == - accountSelected?.nameDisplayed.toUpperCase(), - ); - - setState(() { - final matchingAccounts = filteredAccounts.where((account) { - return account.format.toUpperCase().contains(text.toUpperCase()); - }).toList(); - - pickerItemsList - ..clear() - ..addAll( - matchingAccounts.map( - (account) => PickerItem( - account.format, - null, - null, - null, - account, - true, - ), - ), - ); - }); - } - - @override - Widget build(BuildContext context) { - final localizations = AppLocalizations.of(context)!; - - return AlertDialog( - backgroundColor: Colors.transparent, - elevation: 0, - insetPadding: const EdgeInsets.only( - top: 100, - bottom: 100, - ), - alignment: Alignment.topCenter, - content: ClipRRect( - borderRadius: BorderRadius.circular(16), - child: BackdropFilter( - filter: ImageFilter.blur(sigmaX: 10, sigmaY: 10), - child: Container( - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - color: ArchethicTheme.sheetBackground.withOpacity(0.2), - border: Border.all( - color: ArchethicTheme.sheetBorder, - ), - ), - child: Column( - children: [ - Text( - localizations.accountsHeader, - style: ArchethicThemeStyles.textStyleSize24W700Primary, - ), - AppTextField( - focusNode: _searchNameFocusNode, - controller: _searchNameController, - autofocus: true, - autocorrect: false, - labelText: localizations.searchField, - keyboardType: TextInputType.text, - style: ArchethicThemeStyles.textStyleSize16W600Primary, - inputFormatters: [ - UpperCaseTextFormatter(), - LengthLimitingTextInputFormatter(20), - ], - onChanged: (text) { - _filterAccounts(text, accounts, accountSelected); - }, - ), - const SizedBox( - height: 20, - ), - Expanded( - child: SingleChildScrollView( - child: PickerWidget( - pickerItems: pickerItemsList, - onSelected: (value) { - context.pop(value.value); - }, - ), - ), - ), - ], - ), - ), - ), - ), - ); - } -} diff --git a/lib/util/account_formatters.dart b/lib/util/account_formatters.dart index 3827c1e5b..b8c2b9dab 100644 --- a/lib/util/account_formatters.dart +++ b/lib/util/account_formatters.dart @@ -3,10 +3,7 @@ import 'package:aewallet/model/data/account_token.dart'; extension AccountFormatters on Account { String get format { - final decodedName = Uri.decodeFull(name); - return decodedName.length > 1 && decodedName.startsWith('@') - ? decodedName.replaceFirst('@', '') - : decodedName; + return Uri.decodeFull(name); } String get nameDisplayed { diff --git a/pubspec.lock b/pubspec.lock index 6f5ea8f27..cad2d0d91 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -58,26 +58,26 @@ packages: dependency: "direct main" description: name: archethic_dapp_framework_flutter - sha256: "08d8d65ef4ff93ff911187a3afb7208c3a090d5fa711ad859ffe49145db02289" + sha256: "3444edd8a468772bd16f7a079fd72d07c183e40a4f32f837f4dcf482ed56b903" url: "https://pub.dev" source: hosted - version: "3.2.6" + version: "3.2.7" archethic_lib_dart: dependency: transitive description: name: archethic_lib_dart - sha256: "4265dd9010122891a52f3dbdae0bc5b18e9a0fa844c985f706085269a0837e1e" + sha256: "3b00033e9aa6c69f323ca68b044be2d7b7ad5f38063572cace069ff9ded032b1" url: "https://pub.dev" source: hosted - version: "7.0.0" + version: "7.1.0" archethic_wallet_client: dependency: "direct main" description: name: archethic_wallet_client - sha256: "9e3471f1b613b56bde7cf7c222a6f8ccc156611f70e8c40525ba5749a874afcc" + sha256: ccf5c210985621b440bee3c3a7f28ed0d9bb0311c999f775e35f529cdffeba09 url: "https://pub.dev" source: hosted - version: "2.1.8" + version: "2.1.9" archive: dependency: transitive description: @@ -692,10 +692,10 @@ packages: dependency: "direct main" description: name: flutter_secure_storage - sha256: "1913841ac4c7bf57cd2e05b717e1fbff7841b542962feff827b16525a781b3e4" + sha256: "9cad52d75ebc511adfae3d447d5d13da15a55a92c9410e50f67335b6d21d16ea" url: "https://pub.dev" source: hosted - version: "9.2.3" + version: "9.2.4" flutter_secure_storage_linux: dependency: transitive description: @@ -748,10 +748,10 @@ packages: dependency: "direct main" description: name: flutter_svg - sha256: "54900a1a1243f3c4a5506d853a2b5c2dbc38d5f27e52a52618a8054401431123" + sha256: c200fd79c918a40c5cd50ea0877fa13f81bdaf6f0a5d3dbcc2a13e3285d6aa1b url: "https://pub.dev" source: hosted - version: "2.0.16" + version: "2.0.17" flutter_test: dependency: "direct dev" description: flutter @@ -806,10 +806,10 @@ packages: dependency: "direct main" description: name: go_router - sha256: "2fd11229f59e23e967b0775df8d5948a519cd7e1e8b6e849729e010587b46539" + sha256: "7c2d40b59890a929824f30d442e810116caf5088482629c894b9e4478c67472d" url: "https://pub.dev" source: hosted - version: "14.6.2" + version: "14.6.3" gql: dependency: transitive description: @@ -1883,10 +1883,10 @@ packages: dependency: transitive description: name: url_launcher_windows - sha256: "44cf3aabcedde30f2dba119a9dea3b0f2672fbe6fa96e85536251d678216b3c4" + sha256: "3284b6d2ac454cf34f114e1d3319866fdd1e19cdc329999057e44ffe936cfa77" url: "https://pub.dev" source: hosted - version: "3.1.3" + version: "3.1.4" uuid: dependency: "direct main" description: @@ -1915,10 +1915,10 @@ packages: dependency: transitive description: name: vector_graphics_codec - sha256: "2430b973a4ca3c4dbc9999b62b8c719a160100dcbae5c819bae0cacce32c9cdb" + sha256: "99fd9fbd34d9f9a32efd7b6a6aae14125d8237b10403b422a6a6dfeac2806146" url: "https://pub.dev" source: hosted - version: "1.1.12" + version: "1.1.13" vector_graphics_compiler: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 2616757b7..ca6f1d710 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -13,7 +13,7 @@ dependencies: # Retrieve version and url for local app update against store app Android and iOS app_version_update: ^5.0.2 - archethic_dapp_framework_flutter: ^3.2.6 + archethic_dapp_framework_flutter: ^3.2.7 #archethic_dapp_framework_flutter: ^3.2.6-beta.3 #archethic_dapp_framework_flutter: # git: @@ -22,9 +22,8 @@ dependencies: #archethic_dapp_framework_flutter: # path: ../archethic-dapp-framework-flutter - # RPC datastructures. - archethic_wallet_client: ^2.1.8 - #archethic_wallet_client: ^2.1.8-beta.1 + # AWC + archethic_wallet_client: ^2.1.9 #archethic_wallet_client: # git: # url: https://github.com/archethic-foundation/archethic-wallet-client-dart.git From d37c6a440d76007ee207df365e72e540067ea053 Mon Sep 17 00:00:00 2001 From: Chralu Date: Tue, 14 Jan 2025 11:25:06 +0100 Subject: [PATCH 4/8] refactor(TokenRepository): :recycle: Rework dependency injection. --- lib/application/aeswap/dex_token.g.dart | 2 +- lib/application/session/session.g.dart | 2 +- lib/application/tokens/tokens.dart | 48 ++- lib/application/tokens/tokens.g.dart | 24 +- lib/domain/models/app_wallet.freezed.dart | 6 +- lib/domain/models/token_parser.dart | 7 +- .../tokens/tokens.repository.dart | 8 +- .../tokens/tokens.repository.dart | 28 +- .../aeswap/application/pool/dex_pool.g.dart | 2 +- .../views/add_custom_token/bloc/provider.dart | 2 +- .../add_custom_token/bloc/provider.g.dart | 2 +- lib/ui/views/main/bloc/providers.g.dart | 2 +- test/token_parser_test.dart | 16 +- test/token_parser_test.mocks.dart | 375 +++++++----------- 14 files changed, 214 insertions(+), 310 deletions(-) diff --git a/lib/application/aeswap/dex_token.g.dart b/lib/application/aeswap/dex_token.g.dart index 24b92bde8..563cb7155 100644 --- a/lib/application/aeswap/dex_token.g.dart +++ b/lib/application/aeswap/dex_token.g.dart @@ -609,7 +609,7 @@ class _EstimateTokenInFiatProviderElement (origin as _EstimateTokenInFiatProvider).tokenAddress; } -String _$getRemoveAmountsHash() => r'5ef17a0246ccf402c8cfa2334909514bb491625f'; +String _$getRemoveAmountsHash() => r'0a78339142692cd07c56e184c689b75f88b969de'; /// This provider is used to cache request result /// It ensures, for example, that an oracle update won't trigger a new `getRemoveAmounts` request diff --git a/lib/application/session/session.g.dart b/lib/application/session/session.g.dart index d71be8f8c..151db10fc 100644 --- a/lib/application/session/session.g.dart +++ b/lib/application/session/session.g.dart @@ -6,7 +6,7 @@ part of 'session.dart'; // RiverpodGenerator // ************************************************************************** -String _$sessionNotifierHash() => r'c481183dbfd6ba2ad8bd4cb5348347ad50252b48'; +String _$sessionNotifierHash() => r'e7290af2bd177469103e4cd27791a831f8ca1ed0'; /// See also [SessionNotifier]. @ProviderFor(SessionNotifier) diff --git a/lib/application/tokens/tokens.dart b/lib/application/tokens/tokens.dart index ac6d4c5f8..b1e3d9e83 100644 --- a/lib/application/tokens/tokens.dart +++ b/lib/application/tokens/tokens.dart @@ -3,6 +3,7 @@ import 'dart:developer'; import 'package:aewallet/application/account/accounts_notifier.dart'; import 'package:aewallet/application/aeswap/dex_token.dart'; import 'package:aewallet/application/api_service.dart'; +import 'package:aewallet/domain/repositories/tokens/tokens.repository.dart'; import 'package:aewallet/infrastructure/repositories/tokens/tokens.repository.dart'; import 'package:aewallet/modules/aeswap/application/pool/dex_pool.dart'; import 'package:aewallet/modules/aeswap/application/session/provider.dart'; @@ -16,27 +17,33 @@ import 'package:riverpod_annotation/riverpod_annotation.dart'; part 'tokens.g.dart'; @riverpod -TokensRepositoryImpl tokensRepositoryImpl( +TokensRepository tokensRepository( Ref ref, -) => - TokensRepositoryImpl(); +) { + final apiService = ref.watch(apiServiceProvider); + final environment = ref.watch(environmentProvider); + return TokensRepositoryImpl( + apiService: apiService, + defTokensRepository: aedappfm.DefTokensRepositoryImpl(), + verifiedTokensRepository: aedappfm.VerifiedTokensRepositoryImpl( + apiService: apiService, + environment: environment, + ), + ); +} @riverpod Future> tokensFromAddresses( Ref ref, List addresses, -) async { - final apiService = ref.watch(apiServiceProvider); - - return ref - .watch( - tokensRepositoryImplProvider, - ) - .getTokensFromAddresses( - addresses, - apiService, - ); -} +) => + ref + .watch( + tokensRepositoryProvider, + ) + .getTokensFromAddresses( + addresses, + ); @riverpod Future> tokensFromUserBalance( @@ -47,8 +54,6 @@ Future> tokensFromUserBalance( bool withNotVerified = true, bool withCustomToken = true, }) async { - final apiService = ref.watch(apiServiceProvider); - final environment = ref.watch(environmentProvider); final poolListRaw = await ref.watch(DexPoolProviders.getPoolListRaw.future); final selectedAccount = @@ -56,18 +61,13 @@ Future> tokensFromUserBalance( if (selectedAccount == null) return []; - final tokensRepository = ref.watch(tokensRepositoryImplProvider); - final defTokensRepository = - ref.watch(aedappfm.defTokensRepositoryImplProvider); - return ref .watch( - tokensRepositoryImplProvider, + tokensRepositoryProvider, ) .getTokensFromUserBalance( selectedAccount.genesisAddress, selectedAccount.customTokenAddressList ?? [], - apiService, poolListRaw, environment, withUCO: withUCO, @@ -75,8 +75,6 @@ Future> tokensFromUserBalance( withLPToken: withLPToken, withNotVerified: withNotVerified, withCustomToken: withCustomToken, - defTokensRepository, - tokensRepository, ); } diff --git a/lib/application/tokens/tokens.g.dart b/lib/application/tokens/tokens.g.dart index 6b1341525..c30f913ef 100644 --- a/lib/application/tokens/tokens.g.dart +++ b/lib/application/tokens/tokens.g.dart @@ -6,27 +6,25 @@ part of 'tokens.dart'; // RiverpodGenerator // ************************************************************************** -String _$tokensRepositoryImplHash() => - r'6d0639fff11793ccb691c0bdb8aa86b99078ee47'; - -/// See also [tokensRepositoryImpl]. -@ProviderFor(tokensRepositoryImpl) -final tokensRepositoryImplProvider = - AutoDisposeProvider.internal( - tokensRepositoryImpl, - name: r'tokensRepositoryImplProvider', +String _$tokensRepositoryHash() => r'6c84cd42aedf92b5acc058616f6cdb4e4052ffb7'; + +/// See also [tokensRepository]. +@ProviderFor(tokensRepository) +final tokensRepositoryProvider = AutoDisposeProvider.internal( + tokensRepository, + name: r'tokensRepositoryProvider', debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product') ? null - : _$tokensRepositoryImplHash, + : _$tokensRepositoryHash, dependencies: null, allTransitiveDependencies: null, ); @Deprecated('Will be removed in 3.0. Use Ref instead') // ignore: unused_element -typedef TokensRepositoryImplRef = AutoDisposeProviderRef; +typedef TokensRepositoryRef = AutoDisposeProviderRef; String _$tokensFromAddressesHash() => - r'3eb854cf86092bf7599a28a546924b3a2eb3bf14'; + r'7fc14a5559b66673be8758e145c675aaab127f00'; /// Copied from Dart SDK class _SystemHash { @@ -186,7 +184,7 @@ class _TokensFromAddressesProviderElement } String _$tokensFromUserBalanceHash() => - r'254d8d9be48aae28c96b9dcc1e1cbc98999ac8a6'; + r'c04c5f3beac60be756c1d1ed1773f96928deb5e5'; /// See also [tokensFromUserBalance]. @ProviderFor(tokensFromUserBalance) diff --git a/lib/domain/models/app_wallet.freezed.dart b/lib/domain/models/app_wallet.freezed.dart index 9aff8cf2b..4f67ad3d2 100644 --- a/lib/domain/models/app_wallet.freezed.dart +++ b/lib/domain/models/app_wallet.freezed.dart @@ -16,8 +16,7 @@ final _privateConstructorUsedError = UnsupportedError( /// @nodoc mixin _$AppWallet { - String get seed => - throw _privateConstructorUsedError; // TODO(redddwarf03): Mutualize keychain infos + String get seed => throw _privateConstructorUsedError; AppKeychain get appKeychain => throw _privateConstructorUsedError; KeychainSecuredInfos get keychainSecuredInfos => throw _privateConstructorUsedError; @@ -151,7 +150,6 @@ class _$AppWalletImpl extends _AppWallet { @override final String seed; -// TODO(redddwarf03): Mutualize keychain infos @override final AppKeychain appKeychain; @override @@ -196,7 +194,7 @@ abstract class _AppWallet extends AppWallet { const _AppWallet._() : super._(); @override - String get seed; // TODO(redddwarf03): Mutualize keychain infos + String get seed; @override AppKeychain get appKeychain; @override diff --git a/lib/domain/models/token_parser.dart b/lib/domain/models/token_parser.dart index 3d8014467..139efa202 100644 --- a/lib/domain/models/token_parser.dart +++ b/lib/domain/models/token_parser.dart @@ -1,4 +1,4 @@ -import 'package:aewallet/infrastructure/repositories/tokens/tokens.repository.dart'; +import 'package:aewallet/domain/repositories/tokens/tokens.repository.dart'; import 'package:aewallet/modules/aeswap/domain/models/dex_token.dart'; import 'package:aewallet/modules/aeswap/domain/models/util/get_pool_list_response.dart'; import 'package:archethic_dapp_framework_flutter/archethic_dapp_framework_flutter.dart' @@ -13,8 +13,8 @@ mixin TokenParser { List poolsListRaw, aedappfm.Environment environment, archethic.ApiService apiService, - aedappfm.DefTokensRepositoryImpl defTokensRepository, - TokensRepositoryImpl tokensRepository, + aedappfm.DefTokensRepositoryInterface defTokensRepository, + TokensRepository tokensRepository, ) async { String? pairSymbolToken1; String? pairSymbolToken2; @@ -46,7 +46,6 @@ mixin TokenParser { final tokensSymbolMap = await tokensRepository.getTokensFromAddresses( tokenSymbolSearch, - apiService, ); pairSymbolToken1 = token1Address != kUCOAddress ? tokensSymbolMap[token1Address]!.symbol diff --git a/lib/domain/repositories/tokens/tokens.repository.dart b/lib/domain/repositories/tokens/tokens.repository.dart index dccfe5647..210a6313b 100644 --- a/lib/domain/repositories/tokens/tokens.repository.dart +++ b/lib/domain/repositories/tokens/tokens.repository.dart @@ -1,4 +1,3 @@ -import 'package:aewallet/infrastructure/repositories/tokens/tokens.repository.dart'; import 'package:aewallet/modules/aeswap/domain/models/util/get_pool_list_response.dart'; import 'package:archethic_dapp_framework_flutter/archethic_dapp_framework_flutter.dart' as aedappfm; @@ -7,17 +6,14 @@ import 'package:archethic_lib_dart/archethic_lib_dart.dart' as archethic; abstract class TokensRepository { Future> getTokensFromAddresses( List addresses, - archethic.ApiService apiService, ); Future> getTokensFromUserBalance( String userGenesisAddress, List userTokenLocalAddresses, - archethic.ApiService apiService, List poolsListRaw, - aedappfm.Environment environment, - aedappfm.DefTokensRepositoryImpl defTokensRepositoryImpl, - TokensRepositoryImpl tokensRepositoryImpl, { + aedappfm.Environment environment, { + bool withUCO = true, bool withVerified = true, bool withLPToken = true, bool withNotVerified = true, diff --git a/lib/infrastructure/repositories/tokens/tokens.repository.dart b/lib/infrastructure/repositories/tokens/tokens.repository.dart index 3950bf73d..4d39638a6 100644 --- a/lib/infrastructure/repositories/tokens/tokens.repository.dart +++ b/lib/infrastructure/repositories/tokens/tokens.repository.dart @@ -9,10 +9,19 @@ import 'package:archethic_dapp_framework_flutter/archethic_dapp_framework_flutte import 'package:archethic_lib_dart/archethic_lib_dart.dart' as archethic; class TokensRepositoryImpl with TokenParser implements TokensRepository { + TokensRepositoryImpl({ + required this.defTokensRepository, + required this.apiService, + required this.verifiedTokensRepository, + }); + + final aedappfm.DefTokensRepositoryInterface defTokensRepository; + final archethic.ApiService apiService; + final aedappfm.VerifiedTokensRepositoryImpl verifiedTokensRepository; + @override Future> getTokensFromAddresses( List addresses, - archethic.ApiService apiService, ) async { final tokenMap = {}; @@ -62,11 +71,8 @@ class TokensRepositoryImpl with TokenParser implements TokensRepository { Future> getTokensFromUserBalance( String userGenesisAddress, List userTokenLocalAddresses, - archethic.ApiService apiService, List poolsListRaw, - aedappfm.Environment environment, - aedappfm.DefTokensRepositoryImpl defTokensRepositoryImpl, - TokensRepositoryImpl tokensRepositoryImpl, { + aedappfm.Environment environment, { bool withUCO = true, bool withVerified = true, bool withLPToken = true, @@ -80,7 +86,7 @@ class TokensRepositoryImpl with TokenParser implements TokensRepository { } if (withUCO) { final defUCOToken = - await defTokensRepositoryImpl.getDefToken(environment, kUCOAddress); + await defTokensRepository.getDefToken(environment, kUCOAddress); tokensList.add( aedappfm.ucoToken.copyWith( name: defUCOToken?.name ?? '', @@ -109,13 +115,9 @@ class TokensRepositoryImpl with TokenParser implements TokensRepository { if (tokenAddressList.isNotEmpty) { final tokenMap = await getTokensFromAddresses( tokenAddressList.toSet().toList(), - apiService, ); - final verifiedTokens = await aedappfm.VerifiedTokensRepositoryImpl( - apiService: apiService, - environment: environment, - ).getVerifiedTokens(); + final verifiedTokens = await verifiedTokensRepository.getVerifiedTokens(); final tokenBalances = balanceMap[userGenesisAddress]!.token; @@ -130,8 +132,8 @@ class TokensRepositoryImpl with TokenParser implements TokensRepository { poolsListRaw, environment, apiService, - defTokensRepositoryImpl, - tokensRepositoryImpl, + defTokensRepository, + this, ); final matchingBalances = tokenBalances.where( diff --git a/lib/modules/aeswap/application/pool/dex_pool.g.dart b/lib/modules/aeswap/application/pool/dex_pool.g.dart index e7e868acd..01700bdfe 100644 --- a/lib/modules/aeswap/application/pool/dex_pool.g.dart +++ b/lib/modules/aeswap/application/pool/dex_pool.g.dart @@ -714,7 +714,7 @@ class _PoolInfosProviderElement String get poolAddress => (origin as _PoolInfosProvider).poolAddress; } -String _$getPoolListHash() => r'c105fb2e6011358c360513fc7ad1d65ee2ef7520'; +String _$getPoolListHash() => r'2b9fa7f3aa2669e624a213bc4844b33356b87ecf'; /// See also [_getPoolList]. @ProviderFor(_getPoolList) diff --git a/lib/ui/views/add_custom_token/bloc/provider.dart b/lib/ui/views/add_custom_token/bloc/provider.dart index a7e88839b..2b4357097 100644 --- a/lib/ui/views/add_custom_token/bloc/provider.dart +++ b/lib/ui/views/add_custom_token/bloc/provider.dart @@ -50,7 +50,7 @@ class AddCustomTokenFormNotifier extends _$AddCustomTokenFormNotifier .read(verifiedTokensRepositoryProvider) .getVerifiedTokens(); final environment = ref.read(environmentProvider); - final tokensRepositoryImpl = ref.read(tokensRepositoryImplProvider); + final tokensRepositoryImpl = ref.read(tokensRepositoryProvider); final defTokensRepositoryImpl = ref.read(aedappfm.defTokensRepositoryImplProvider); diff --git a/lib/ui/views/add_custom_token/bloc/provider.g.dart b/lib/ui/views/add_custom_token/bloc/provider.g.dart index 088897558..f5f9d100a 100644 --- a/lib/ui/views/add_custom_token/bloc/provider.g.dart +++ b/lib/ui/views/add_custom_token/bloc/provider.g.dart @@ -7,7 +7,7 @@ part of 'provider.dart'; // ************************************************************************** String _$addCustomTokenFormNotifierHash() => - r'441e2c7fca977ae7ff3e496d5936db2f73f16fe1'; + r'da6d902ba2ae059d9503a9948fbca949435ba741'; /// See also [AddCustomTokenFormNotifier]. @ProviderFor(AddCustomTokenFormNotifier) diff --git a/lib/ui/views/main/bloc/providers.g.dart b/lib/ui/views/main/bloc/providers.g.dart index 81e64f758..5285c5df8 100644 --- a/lib/ui/views/main/bloc/providers.g.dart +++ b/lib/ui/views/main/bloc/providers.g.dart @@ -6,7 +6,7 @@ part of 'providers.dart'; // RiverpodGenerator // ************************************************************************** -String _$homePageHash() => r'75430f32f464429243926bd07a56a6036a7a17f0'; +String _$homePageHash() => r'b3a7e0d8b8465ba8f13decf492db4b8eeae87ec9'; /// Eagerly initializes providers (https://riverpod.dev/docs/essentials/eager_initialization). /// diff --git a/test/token_parser_test.dart b/test/token_parser_test.dart index 453e8aa6d..6b086f2bd 100644 --- a/test/token_parser_test.dart +++ b/test/token_parser_test.dart @@ -1,6 +1,7 @@ import 'dart:io'; + import 'package:aewallet/domain/models/token_parser.dart'; -import 'package:aewallet/infrastructure/repositories/tokens/tokens.repository.dart'; +import 'package:aewallet/domain/repositories/tokens/tokens.repository.dart'; import 'package:aewallet/modules/aeswap/domain/models/util/get_pool_list_response.dart'; import 'package:archethic_dapp_framework_flutter/archethic_dapp_framework_flutter.dart' as aedappfm; @@ -12,9 +13,9 @@ import 'package:mockito/mockito.dart'; @GenerateNiceMocks( [ - MockSpec(), + MockSpec(), MockSpec(), - MockSpec(), + MockSpec(), ], ) import 'token_parser_test.mocks.dart'; @@ -26,8 +27,8 @@ void main() { group('TokenParser - tokenModelToAETokenModel', () { late TokenParser tokenParser; - late MockTokensRepositoryImpl mockTokensRepository; - late MockDefTokensRepositoryImpl mockDefTokensRepository; + late MockTokensRepository mockTokensRepository; + late MockDefTokensRepositoryInterface mockDefTokensRepository; late MockApiService mockApiService; late aedappfm.Environment environment; late List verifiedTokens; @@ -35,8 +36,8 @@ void main() { setUp(() { Hive.init('${Directory.current.path}/test/tmp_data'); - mockTokensRepository = MockTokensRepositoryImpl(); - mockDefTokensRepository = MockDefTokensRepositoryImpl(); + mockTokensRepository = MockTokensRepository(); + mockDefTokensRepository = MockDefTokensRepositoryInterface(); mockApiService = MockApiService(); environment = aedappfm.Environment.testnet; tokenParser = _TokenParserImpl(); @@ -179,7 +180,6 @@ void main() { '00003DF600E329199BF3EE8FBE2B8223413D70BCDD97E15089E6A74D94DE3F1173B4', ]), ), - any, ), ).thenAnswer( (_) async => { diff --git a/test/token_parser_test.mocks.dart b/test/token_parser_test.mocks.dart index f25374041..22c54377b 100644 --- a/test/token_parser_test.mocks.dart +++ b/test/token_parser_test.mocks.dart @@ -3,37 +3,33 @@ // Do not manually edit this file. // ignore_for_file: no_leading_underscores_for_library_prefixes -import 'dart:async' as _i10; -import 'dart:typed_data' as _i18; +import 'dart:async' as _i9; +import 'dart:typed_data' as _i16; -import 'package:aewallet/infrastructure/repositories/tokens/tokens.repository.dart' - as _i23; +import 'package:aewallet/domain/repositories/tokens/tokens.repository.dart' + as _i21; import 'package:aewallet/modules/aeswap/domain/models/util/get_pool_list_response.dart' - as _i24; + as _i22; import 'package:archethic_dapp_framework_flutter/archethic_dapp_framework_flutter.dart' - as _i9; -import 'package:archethic_dapp_framework_flutter/src/domain/models/ae_token.dart' as _i8; -import 'package:archethic_dapp_framework_flutter/src/domain/models/environment.dart' - as _i11; -import 'package:archethic_lib_dart/archethic_lib_dart.dart' as _i12; +import 'package:archethic_lib_dart/archethic_lib_dart.dart' as _i10; import 'package:archethic_lib_dart/src/model/address.dart' as _i6; -import 'package:archethic_lib_dart/src/model/balance.dart' as _i14; +import 'package:archethic_lib_dart/src/model/balance.dart' as _i12; import 'package:archethic_lib_dart/src/model/blockchain_version.dart' as _i7; -import 'package:archethic_lib_dart/src/model/endpoint.dart' as _i20; +import 'package:archethic_lib_dart/src/model/endpoint.dart' as _i18; import 'package:archethic_lib_dart/src/model/keychain.dart' as _i5; -import 'package:archethic_lib_dart/src/model/node.dart' as _i15; -import 'package:archethic_lib_dart/src/model/ownership.dart' as _i17; +import 'package:archethic_lib_dart/src/model/node.dart' as _i13; +import 'package:archethic_lib_dart/src/model/ownership.dart' as _i15; import 'package:archethic_lib_dart/src/model/smart_contracts/sc_call_function_request.dart' - as _i21; -import 'package:archethic_lib_dart/src/model/token.dart' as _i19; + as _i19; +import 'package:archethic_lib_dart/src/model/token.dart' as _i17; import 'package:archethic_lib_dart/src/model/transaction.dart' as _i4; import 'package:archethic_lib_dart/src/model/transaction_fee.dart' as _i3; -import 'package:archethic_lib_dart/src/model/transaction_input.dart' as _i16; +import 'package:archethic_lib_dart/src/model/transaction_input.dart' as _i14; import 'package:archethic_lib_dart/src/model/transaction_status.dart' as _i2; -import 'package:graphql/client.dart' as _i22; +import 'package:graphql/client.dart' as _i20; import 'package:mockito/mockito.dart' as _i1; -import 'package:mockito/src/dummies.dart' as _i13; +import 'package:mockito/src/dummies.dart' as _i11; // ignore_for_file: type=lint // ignore_for_file: avoid_redundant_argument_values @@ -121,65 +117,55 @@ class _FakeBlockchainVersionModel_6 extends _i1.SmartFake ); } -class _FakeAEToken_7 extends _i1.SmartFake implements _i8.AEToken { - _FakeAEToken_7( - Object parent, - Invocation parentInvocation, - ) : super( - parent, - parentInvocation, - ); -} - -/// A class which mocks [DefTokensRepositoryImpl]. +/// A class which mocks [DefTokensRepositoryInterface]. /// /// See the documentation for Mockito's code generation for more information. -class MockDefTokensRepositoryImpl extends _i1.Mock - implements _i9.DefTokensRepositoryImpl { +class MockDefTokensRepositoryInterface extends _i1.Mock + implements _i8.DefTokensRepositoryInterface { @override - _i10.Future<_i8.AEToken?> getDefToken( - _i11.Environment? environment, + _i9.Future<_i8.AEToken?> getDefToken( + _i8.Environment? enviroment, String? address, ) => (super.noSuchMethod( Invocation.method( #getDefToken, [ - environment, + enviroment, address, ], ), - returnValue: _i10.Future<_i8.AEToken?>.value(), - returnValueForMissingStub: _i10.Future<_i8.AEToken?>.value(), - ) as _i10.Future<_i8.AEToken?>); + returnValue: _i9.Future<_i8.AEToken?>.value(), + returnValueForMissingStub: _i9.Future<_i8.AEToken?>.value(), + ) as _i9.Future<_i8.AEToken?>); } /// A class which mocks [ApiService]. /// /// See the documentation for Mockito's code generation for more information. -class MockApiService extends _i1.Mock implements _i12.ApiService { +class MockApiService extends _i1.Mock implements _i10.ApiService { @override String get endpoint => (super.noSuchMethod( Invocation.getter(#endpoint), - returnValue: _i13.dummyValue( + returnValue: _i11.dummyValue( this, Invocation.getter(#endpoint), ), - returnValueForMissingStub: _i13.dummyValue( + returnValueForMissingStub: _i11.dummyValue( this, Invocation.getter(#endpoint), ), ) as String); @override - _i10.Future<_i2.TransactionStatus> sendTx(_i4.Transaction? transaction) => + _i9.Future<_i2.TransactionStatus> sendTx(_i4.Transaction? transaction) => (super.noSuchMethod( Invocation.method( #sendTx, [transaction], ), returnValue: - _i10.Future<_i2.TransactionStatus>.value(_FakeTransactionStatus_0( + _i9.Future<_i2.TransactionStatus>.value(_FakeTransactionStatus_0( this, Invocation.method( #sendTx, @@ -187,17 +173,17 @@ class MockApiService extends _i1.Mock implements _i12.ApiService { ), )), returnValueForMissingStub: - _i10.Future<_i2.TransactionStatus>.value(_FakeTransactionStatus_0( + _i9.Future<_i2.TransactionStatus>.value(_FakeTransactionStatus_0( this, Invocation.method( #sendTx, [transaction], ), )), - ) as _i10.Future<_i2.TransactionStatus>); + ) as _i9.Future<_i2.TransactionStatus>); @override - _i10.Future> getLastTransaction( + _i9.Future> getLastTransaction( List? addresses, { String? request = r' address, balance { token { address, amount }, uco }, chainLength, crossValidationStamps { nodePublicKey, signature }, data { content, ownerships { authorizedPublicKeys { encryptedSecretKey, publicKey } secret } ledger { uco { transfers { amount, to } }, token { transfers { amount, to, tokenAddress, tokenId } } } recipients, actionRecipients { action address args } } inputs { amount, from, tokenAddress, spent, tokenId, timestamp, type, }, originSignature, previousAddress, previousPublicKey, previousSignature, type, validationStamp { proofOfIntegrity, proofOfWork, signature, timestamp, ledgerOperations { fee, unspentOutputs { state } } }, version', @@ -208,32 +194,32 @@ class MockApiService extends _i1.Mock implements _i12.ApiService { [addresses], {#request: request}, ), - returnValue: _i10.Future>.value( + returnValue: _i9.Future>.value( {}), returnValueForMissingStub: - _i10.Future>.value( + _i9.Future>.value( {}), - ) as _i10.Future>); + ) as _i9.Future>); @override - _i10.Future> getTransactionIndex(List? addresses) => + _i9.Future> getTransactionIndex(List? addresses) => (super.noSuchMethod( Invocation.method( #getTransactionIndex, [addresses], ), - returnValue: _i10.Future>.value({}), + returnValue: _i9.Future>.value({}), returnValueForMissingStub: - _i10.Future>.value({}), - ) as _i10.Future>); + _i9.Future>.value({}), + ) as _i9.Future>); @override - _i10.Future getStorageNoncePublicKey() => (super.noSuchMethod( + _i9.Future getStorageNoncePublicKey() => (super.noSuchMethod( Invocation.method( #getStorageNoncePublicKey, [], ), - returnValue: _i10.Future.value(_i13.dummyValue( + returnValue: _i9.Future.value(_i11.dummyValue( this, Invocation.method( #getStorageNoncePublicKey, @@ -241,17 +227,17 @@ class MockApiService extends _i1.Mock implements _i12.ApiService { ), )), returnValueForMissingStub: - _i10.Future.value(_i13.dummyValue( + _i9.Future.value(_i11.dummyValue( this, Invocation.method( #getStorageNoncePublicKey, [], ), )), - ) as _i10.Future); + ) as _i9.Future); @override - _i10.Future> fetchBalance( + _i9.Future> fetchBalance( List? addresses, { String? request = r' token { address, amount, tokenId }, uco ', }) => @@ -261,27 +247,27 @@ class MockApiService extends _i1.Mock implements _i12.ApiService { [addresses], {#request: request}, ), - returnValue: _i10.Future>.value( - {}), - returnValueForMissingStub: _i10.Future>.value( - {}), - ) as _i10.Future>); + returnValue: _i9.Future>.value( + {}), + returnValueForMissingStub: _i9.Future>.value( + {}), + ) as _i9.Future>); @override - _i10.Future> getTransactionContent( + _i9.Future> getTransactionContent( List? addresses) => (super.noSuchMethod( Invocation.method( #getTransactionContent, [addresses], ), - returnValue: _i10.Future>.value({}), + returnValue: _i9.Future>.value({}), returnValueForMissingStub: - _i10.Future>.value({}), - ) as _i10.Future>); + _i9.Future>.value({}), + ) as _i9.Future>); @override - _i10.Future>> getTransactionChain( + _i9.Future>> getTransactionChain( Map? addresses, { String? request = r' address, balance { token { address, amount }, uco }, chainLength, crossValidationStamps { nodePublicKey, signature }, data { content, ownerships { authorizedPublicKeys { encryptedSecretKey, publicKey } secret } ledger { uco { transfers { amount, to } }, token { transfers { amount, to, tokenAddress, tokenId } } } recipients, actionRecipients { action address args } } inputs { amount, from, tokenAddress, spent, tokenId, timestamp, type, }, originSignature, previousAddress, previousPublicKey, previousSignature, type, validationStamp { proofOfIntegrity, proofOfWork, signature, timestamp, ledgerOperations { fee, unspentOutputs { state } } }, version', @@ -298,26 +284,26 @@ class MockApiService extends _i1.Mock implements _i12.ApiService { #fromCriteria: fromCriteria, }, ), - returnValue: _i10.Future>>.value( + returnValue: _i9.Future>>.value( >{}), returnValueForMissingStub: - _i10.Future>>.value( + _i9.Future>>.value( >{}), - ) as _i10.Future>>); + ) as _i9.Future>>); @override - _i10.Future> getNodeList() => (super.noSuchMethod( + _i9.Future> getNodeList() => (super.noSuchMethod( Invocation.method( #getNodeList, [], ), - returnValue: _i10.Future>.value(<_i15.Node>[]), + returnValue: _i9.Future>.value(<_i13.Node>[]), returnValueForMissingStub: - _i10.Future>.value(<_i15.Node>[]), - ) as _i10.Future>); + _i9.Future>.value(<_i13.Node>[]), + ) as _i9.Future>); @override - _i10.Future> networkTransactions( + _i9.Future> networkTransactions( String? type, int? page, { String? request = @@ -333,13 +319,13 @@ class MockApiService extends _i1.Mock implements _i12.ApiService { {#request: request}, ), returnValue: - _i10.Future>.value(<_i4.Transaction>[]), + _i9.Future>.value(<_i4.Transaction>[]), returnValueForMissingStub: - _i10.Future>.value(<_i4.Transaction>[]), - ) as _i10.Future>); + _i9.Future>.value(<_i4.Transaction>[]), + ) as _i9.Future>); @override - _i10.Future>> getTransactionInputs( + _i9.Future>> getTransactionInputs( List? addresses, { String? request = r'amount, from, tokenAddress, spent, tokenId, timestamp, type', @@ -356,16 +342,15 @@ class MockApiService extends _i1.Mock implements _i12.ApiService { #pagingOffset: pagingOffset, }, ), - returnValue: - _i10.Future>>.value( - >{}), + returnValue: _i9.Future>>.value( + >{}), returnValueForMissingStub: - _i10.Future>>.value( - >{}), - ) as _i10.Future>>); + _i9.Future>>.value( + >{}), + ) as _i9.Future>>); @override - _i10.Future> getTransaction( + _i9.Future> getTransaction( List? addresses, { String? request = r' address, balance { token { address, amount }, uco }, chainLength, crossValidationStamps { nodePublicKey, signature }, data { content, ownerships { authorizedPublicKeys { encryptedSecretKey, publicKey } secret } ledger { uco { transfers { amount, to } }, token { transfers { amount, to, tokenAddress, tokenId } } } recipients, actionRecipients { action address args } } inputs { amount, from, tokenAddress, spent, tokenId, timestamp, type, }, originSignature, previousAddress, previousPublicKey, previousSignature, type, validationStamp { proofOfIntegrity, proofOfWork, signature, timestamp, ledgerOperations { fee, unspentOutputs { state } } }, version', @@ -376,23 +361,22 @@ class MockApiService extends _i1.Mock implements _i12.ApiService { [addresses], {#request: request}, ), - returnValue: _i10.Future>.value( + returnValue: _i9.Future>.value( {}), returnValueForMissingStub: - _i10.Future>.value( + _i9.Future>.value( {}), - ) as _i10.Future>); + ) as _i9.Future>); @override - _i10.Future<_i3.TransactionFee> getTransactionFee( + _i9.Future<_i3.TransactionFee> getTransactionFee( _i4.Transaction? transaction) => (super.noSuchMethod( Invocation.method( #getTransactionFee, [transaction], ), - returnValue: - _i10.Future<_i3.TransactionFee>.value(_FakeTransactionFee_1( + returnValue: _i9.Future<_i3.TransactionFee>.value(_FakeTransactionFee_1( this, Invocation.method( #getTransactionFee, @@ -400,35 +384,35 @@ class MockApiService extends _i1.Mock implements _i12.ApiService { ), )), returnValueForMissingStub: - _i10.Future<_i3.TransactionFee>.value(_FakeTransactionFee_1( + _i9.Future<_i3.TransactionFee>.value(_FakeTransactionFee_1( this, Invocation.method( #getTransactionFee, [transaction], ), )), - ) as _i10.Future<_i3.TransactionFee>); + ) as _i9.Future<_i3.TransactionFee>); @override - _i10.Future>> getTransactionOwnerships( + _i9.Future>> getTransactionOwnerships( List? addresses) => (super.noSuchMethod( Invocation.method( #getTransactionOwnerships, [addresses], ), - returnValue: _i10.Future>>.value( - >{}), + returnValue: _i9.Future>>.value( + >{}), returnValueForMissingStub: - _i10.Future>>.value( - >{}), - ) as _i10.Future>>); + _i9.Future>>.value( + >{}), + ) as _i9.Future>>); @override _i4.Transaction newKeychainTransaction( String? seed, List? authorizedPublicKeys, - _i18.Uint8List? originPrivateKey, + _i16.Uint8List? originPrivateKey, int? blockchainTxVersion, { Map? servicesMap, }) => @@ -474,8 +458,8 @@ class MockApiService extends _i1.Mock implements _i12.ApiService { @override _i4.Transaction newAccessKeychainTransaction( String? seed, - _i18.Uint8List? keychainAddress, - _i18.Uint8List? originPrivateKey, + _i16.Uint8List? keychainAddress, + _i16.Uint8List? originPrivateKey, int? blockchainTxVersion, ) => (super.noSuchMethod( @@ -515,12 +499,12 @@ class MockApiService extends _i1.Mock implements _i12.ApiService { ) as _i4.Transaction); @override - _i10.Future<_i5.Keychain> getKeychain(String? seed) => (super.noSuchMethod( + _i9.Future<_i5.Keychain> getKeychain(String? seed) => (super.noSuchMethod( Invocation.method( #getKeychain, [seed], ), - returnValue: _i10.Future<_i5.Keychain>.value(_FakeKeychain_3( + returnValue: _i9.Future<_i5.Keychain>.value(_FakeKeychain_3( this, Invocation.method( #getKeychain, @@ -528,14 +512,14 @@ class MockApiService extends _i1.Mock implements _i12.ApiService { ), )), returnValueForMissingStub: - _i10.Future<_i5.Keychain>.value(_FakeKeychain_3( + _i9.Future<_i5.Keychain>.value(_FakeKeychain_3( this, Invocation.method( #getKeychain, [seed], ), )), - ) as _i10.Future<_i5.Keychain>); + ) as _i9.Future<_i5.Keychain>); @override String getOriginKey() => (super.noSuchMethod( @@ -543,14 +527,14 @@ class MockApiService extends _i1.Mock implements _i12.ApiService { #getOriginKey, [], ), - returnValue: _i13.dummyValue( + returnValue: _i11.dummyValue( this, Invocation.method( #getOriginKey, [], ), ), - returnValueForMissingStub: _i13.dummyValue( + returnValueForMissingStub: _i11.dummyValue( this, Invocation.method( #getOriginKey, @@ -560,7 +544,7 @@ class MockApiService extends _i1.Mock implements _i12.ApiService { ) as String); @override - _i10.Future addOriginKey({ + _i9.Future addOriginKey({ String? originPublicKey, String? certificate, }) => @@ -573,7 +557,7 @@ class MockApiService extends _i1.Mock implements _i12.ApiService { #certificate: certificate, }, ), - returnValue: _i10.Future.value(_i13.dummyValue( + returnValue: _i9.Future.value(_i11.dummyValue( this, Invocation.method( #addOriginKey, @@ -585,7 +569,7 @@ class MockApiService extends _i1.Mock implements _i12.ApiService { ), )), returnValueForMissingStub: - _i10.Future.value(_i13.dummyValue( + _i9.Future.value(_i11.dummyValue( this, Invocation.method( #addOriginKey, @@ -596,10 +580,10 @@ class MockApiService extends _i1.Mock implements _i12.ApiService { }, ), )), - ) as _i10.Future); + ) as _i9.Future); @override - _i10.Future> getToken( + _i9.Future> getToken( List? addresses, { String? request = r'genesis, name, id, supply, symbol, type, properties, decimals, collection, ownerships { authorizedPublicKeys { encryptedSecretKey, publicKey }, secret }', @@ -611,63 +595,61 @@ class MockApiService extends _i1.Mock implements _i12.ApiService { {#request: request}, ), returnValue: - _i10.Future>.value({}), + _i9.Future>.value({}), returnValueForMissingStub: - _i10.Future>.value({}), - ) as _i10.Future>); + _i9.Future>.value({}), + ) as _i9.Future>); @override - _i10.Future> getNearestEndpoints() => (super.noSuchMethod( + _i9.Future> getNearestEndpoints() => (super.noSuchMethod( Invocation.method( #getNearestEndpoints, [], ), - returnValue: _i10.Future>.value(<_i20.Endpoint>[]), + returnValue: _i9.Future>.value(<_i18.Endpoint>[]), returnValueForMissingStub: - _i10.Future>.value(<_i20.Endpoint>[]), - ) as _i10.Future>); + _i9.Future>.value(<_i18.Endpoint>[]), + ) as _i9.Future>); @override - _i10.Future<_i6.Address> getGenesisAddress(String? address) => + _i9.Future<_i6.Address> getGenesisAddress(String? address) => (super.noSuchMethod( Invocation.method( #getGenesisAddress, [address], ), - returnValue: _i10.Future<_i6.Address>.value(_FakeAddress_4( + returnValue: _i9.Future<_i6.Address>.value(_FakeAddress_4( this, Invocation.method( #getGenesisAddress, [address], ), )), - returnValueForMissingStub: - _i10.Future<_i6.Address>.value(_FakeAddress_4( + returnValueForMissingStub: _i9.Future<_i6.Address>.value(_FakeAddress_4( this, Invocation.method( #getGenesisAddress, [address], ), )), - ) as _i10.Future<_i6.Address>); + ) as _i9.Future<_i6.Address>); @override - _i10.Future> callSCFunctionMulti( - {required List<_i21.SCCallFunctionRequest>? jsonRPCRequests}) => + _i9.Future> callSCFunctionMulti( + {required List<_i19.SCCallFunctionRequest>? jsonRPCRequests}) => (super.noSuchMethod( Invocation.method( #callSCFunctionMulti, [], {#jsonRPCRequests: jsonRPCRequests}, ), - returnValue: _i10.Future>.value([]), - returnValueForMissingStub: - _i10.Future>.value([]), - ) as _i10.Future>); + returnValue: _i9.Future>.value([]), + returnValueForMissingStub: _i9.Future>.value([]), + ) as _i9.Future>); @override - _i10.Future callSCFunction({ - required _i21.SCCallFunctionRequest? jsonRPCRequest, + _i9.Future callSCFunction({ + required _i19.SCCallFunctionRequest? jsonRPCRequest, bool? resultMap = false, }) => (super.noSuchMethod( @@ -679,7 +661,7 @@ class MockApiService extends _i1.Mock implements _i12.ApiService { #resultMap: resultMap, }, ), - returnValue: _i10.Future.value(_FakeObject_5( + returnValue: _i9.Future.value(_FakeObject_5( this, Invocation.method( #callSCFunction, @@ -690,7 +672,7 @@ class MockApiService extends _i1.Mock implements _i12.ApiService { }, ), )), - returnValueForMissingStub: _i10.Future.value(_FakeObject_5( + returnValueForMissingStub: _i9.Future.value(_FakeObject_5( this, Invocation.method( #callSCFunction, @@ -701,16 +683,16 @@ class MockApiService extends _i1.Mock implements _i12.ApiService { }, ), )), - ) as _i10.Future); + ) as _i9.Future); @override - _i10.Future<_i7.BlockchainVersionModel> getBlockchainVersion() => + _i9.Future<_i7.BlockchainVersionModel> getBlockchainVersion() => (super.noSuchMethod( Invocation.method( #getBlockchainVersion, [], ), - returnValue: _i10.Future<_i7.BlockchainVersionModel>.value( + returnValue: _i9.Future<_i7.BlockchainVersionModel>.value( _FakeBlockchainVersionModel_6( this, Invocation.method( @@ -718,19 +700,18 @@ class MockApiService extends _i1.Mock implements _i12.ApiService { [], ), )), - returnValueForMissingStub: - _i10.Future<_i7.BlockchainVersionModel>.value( - _FakeBlockchainVersionModel_6( + returnValueForMissingStub: _i9.Future<_i7.BlockchainVersionModel>.value( + _FakeBlockchainVersionModel_6( this, Invocation.method( #getBlockchainVersion, [], ), )), - ) as _i10.Future<_i7.BlockchainVersionModel>); + ) as _i9.Future<_i7.BlockchainVersionModel>); @override - void manageLinkException(_i22.QueryResult? result) => + void manageLinkException(_i20.QueryResult? result) => super.noSuchMethod( Invocation.method( #manageLinkException, @@ -754,7 +735,7 @@ class MockApiService extends _i1.Mock implements _i12.ApiService { ], {#id: id}, ), - returnValue: _i13.dummyValue( + returnValue: _i11.dummyValue( this, Invocation.method( #setJsonRPCRequest, @@ -765,7 +746,7 @@ class MockApiService extends _i1.Mock implements _i12.ApiService { {#id: id}, ), ), - returnValueForMissingStub: _i13.dummyValue( + returnValueForMissingStub: _i11.dummyValue( this, Invocation.method( #setJsonRPCRequest, @@ -793,14 +774,14 @@ class MockApiService extends _i1.Mock implements _i12.ApiService { #getJsonRPCResultString, [body], ), - returnValue: _i13.dummyValue( + returnValue: _i11.dummyValue( this, Invocation.method( #getJsonRPCResultString, [body], ), ), - returnValueForMissingStub: _i13.dummyValue( + returnValueForMissingStub: _i11.dummyValue( this, Invocation.method( #getJsonRPCResultString, @@ -810,39 +791,30 @@ class MockApiService extends _i1.Mock implements _i12.ApiService { ) as String); } -/// A class which mocks [TokensRepositoryImpl]. +/// A class which mocks [TokensRepository]. /// /// See the documentation for Mockito's code generation for more information. -class MockTokensRepositoryImpl extends _i1.Mock - implements _i23.TokensRepositoryImpl { +class MockTokensRepository extends _i1.Mock implements _i21.TokensRepository { @override - _i10.Future> getTokensFromAddresses( - List? addresses, - _i12.ApiService? apiService, - ) => + _i9.Future> getTokensFromAddresses( + List? addresses) => (super.noSuchMethod( Invocation.method( #getTokensFromAddresses, - [ - addresses, - apiService, - ], + [addresses], ), returnValue: - _i10.Future>.value({}), + _i9.Future>.value({}), returnValueForMissingStub: - _i10.Future>.value({}), - ) as _i10.Future>); + _i9.Future>.value({}), + ) as _i9.Future>); @override - _i10.Future> getTokensFromUserBalance( + _i9.Future> getTokensFromUserBalance( String? userGenesisAddress, List? userTokenLocalAddresses, - _i12.ApiService? apiService, - List<_i24.GetPoolListResponse>? poolsListRaw, - _i11.Environment? environment, - _i9.DefTokensRepositoryImpl? defTokensRepositoryImpl, - _i23.TokensRepositoryImpl? tokensRepositoryImpl, { + List<_i22.GetPoolListResponse>? poolsListRaw, + _i8.Environment? environment, { bool? withUCO = true, bool? withVerified = true, bool? withLPToken = true, @@ -855,11 +827,8 @@ class MockTokensRepositoryImpl extends _i1.Mock [ userGenesisAddress, userTokenLocalAddresses, - apiService, poolsListRaw, environment, - defTokensRepositoryImpl, - tokensRepositoryImpl, ], { #withUCO: withUCO, @@ -869,64 +838,8 @@ class MockTokensRepositoryImpl extends _i1.Mock #withCustomToken: withCustomToken, }, ), - returnValue: _i10.Future>.value(<_i8.AEToken>[]), + returnValue: _i9.Future>.value(<_i8.AEToken>[]), returnValueForMissingStub: - _i10.Future>.value(<_i8.AEToken>[]), - ) as _i10.Future>); - - @override - _i10.Future<_i8.AEToken> tokenModelToAETokenModel( - _i19.Token? token, - List? verifiedTokens, - List<_i24.GetPoolListResponse>? poolsListRaw, - _i11.Environment? environment, - _i12.ApiService? apiService, - _i9.DefTokensRepositoryImpl? defTokensRepository, - _i23.TokensRepositoryImpl? tokensRepository, - ) => - (super.noSuchMethod( - Invocation.method( - #tokenModelToAETokenModel, - [ - token, - verifiedTokens, - poolsListRaw, - environment, - apiService, - defTokensRepository, - tokensRepository, - ], - ), - returnValue: _i10.Future<_i8.AEToken>.value(_FakeAEToken_7( - this, - Invocation.method( - #tokenModelToAETokenModel, - [ - token, - verifiedTokens, - poolsListRaw, - environment, - apiService, - defTokensRepository, - tokensRepository, - ], - ), - )), - returnValueForMissingStub: - _i10.Future<_i8.AEToken>.value(_FakeAEToken_7( - this, - Invocation.method( - #tokenModelToAETokenModel, - [ - token, - verifiedTokens, - poolsListRaw, - environment, - apiService, - defTokensRepository, - tokensRepository, - ], - ), - )), - ) as _i10.Future<_i8.AEToken>); + _i9.Future>.value(<_i8.AEToken>[]), + ) as _i9.Future>); } From 96c093b2581b0430b867d32327478a57e40e6fd4 Mon Sep 17 00:00:00 2001 From: Chralu Date: Tue, 14 Jan 2025 13:17:26 +0100 Subject: [PATCH 5/8] fix(AccountsNotifier): :bug: Remove Accounts illegal modifications Account & AccountsNotifierState are now immutable. This prevent modifying the objects without the Notifier to know. --- lib/application/account/account_notifier.dart | 256 +++---- .../account/account_notifier.g.dart | 2 +- .../account/accounts_notifier.dart | 13 +- .../account/accounts_notifier.g.dart | 8 +- .../transaction/send_transaction.freezed.dart | 13 + .../datasources/account.hive.dart | 38 +- .../datasources/appdb.hive.dart | 2 +- .../repositories/local_account.dart | 2 +- lib/model/data/account.dart | 155 ++--- lib/model/data/account.freezed.dart | 626 ++++++++++++++++++ lib/model/data/account.g.dart | 22 +- lib/model/data/app_keychain.dart | 2 +- .../views/accounts/layouts/account_list.dart | 3 +- lib/ui/views/main/bloc/providers.dart | 30 +- lib/ui/views/main/bloc/providers.g.dart | 2 +- lib/ui/views/transfer/bloc/state.freezed.dart | 12 + .../transfer_textfield_address.dart | 11 +- lib/util/keychain_util.dart | 17 +- 18 files changed, 898 insertions(+), 316 deletions(-) create mode 100644 lib/model/data/account.freezed.dart diff --git a/lib/application/account/account_notifier.dart b/lib/application/account/account_notifier.dart index 7e1bb1f58..1c4363c2f 100644 --- a/lib/application/account/account_notifier.dart +++ b/lib/application/account/account_notifier.dart @@ -115,129 +115,131 @@ class AccountNotifier extends _$AccountNotifier { } Future updateBalance() async { - final account = await future; - if (account == null) return; - - var totalUSD = 0.0; + await _update((account) async { + var totalUSD = 0.0; - final balanceGetResponseMap = await ref - .read(appServiceProvider) - .getBalanceGetResponse([account.genesisAddress]); + final balanceGetResponseMap = await ref + .read(appServiceProvider) + .getBalanceGetResponse([account.genesisAddress]); - if (balanceGetResponseMap[account.genesisAddress] == null) { - return; - } + if (balanceGetResponseMap[account.genesisAddress] == null) { + return account; + } - final ucidsTokens = await ref.read( - aedappfm.UcidsTokensProviders.ucidsTokens( - environment: ref.read(environmentProvider), - ).future, - ); + final ucidsTokens = await ref.read( + aedappfm.UcidsTokensProviders.ucidsTokens( + environment: ref.read(environmentProvider), + ).future, + ); - final cryptoPrice = ref.read(aedappfm.CoinPriceProviders.coinPrices); + final cryptoPrice = ref.read(aedappfm.CoinPriceProviders.coinPrices); - final balanceGetResponse = balanceGetResponseMap[account.genesisAddress]!; - final ucoAmount = fromBigInt(balanceGetResponse.uco).toDouble(); - final accountBalance = AccountBalance( - nativeTokenName: AccountBalance.cryptoCurrencyLabel, - nativeTokenValue: ucoAmount, - ); + final balanceGetResponse = balanceGetResponseMap[account.genesisAddress]!; + final ucoAmount = fromBigInt(balanceGetResponse.uco).toDouble(); + final accountBalance = AccountBalance( + nativeTokenName: AccountBalance.cryptoCurrencyLabel, + nativeTokenValue: ucoAmount, + ); - if (balanceGetResponse.uco > 0) { - accountBalance.tokensFungiblesNb++; + if (balanceGetResponse.uco > 0) { + accountBalance.tokensFungiblesNb++; - final archethicOracleUCO = await ref.read( - aedappfm.ArchethicOracleUCOProviders.archethicOracleUCO.future, - ); - totalUSD = (Decimal.parse(totalUSD.toString()) + - Decimal.parse(ucoAmount.toString()) * - Decimal.parse(archethicOracleUCO.usd.toString())) - .toDouble(); - } + final archethicOracleUCO = await ref.read( + aedappfm.ArchethicOracleUCOProviders.archethicOracleUCO.future, + ); + totalUSD = (Decimal.parse(totalUSD.toString()) + + Decimal.parse(ucoAmount.toString()) * + Decimal.parse(archethicOracleUCO.usd.toString())) + .toDouble(); + } - for (final token in balanceGetResponse.token) { - if (token.tokenId != null) { - if (token.tokenId == 0) { - accountBalance.tokensFungiblesNb++; - - final ucidsToken = ucidsTokens[token.address]; - if (ucidsToken != null && ucidsToken != 0) { - final amountTokenUSD = - (Decimal.parse(fromBigInt(token.amount).toString()) * - Decimal.parse( - aedappfm.CoinPriceRepositoryImpl() - .getPriceFromUcid(ucidsToken, cryptoPrice) - .toString(), - )) - .toDouble(); - totalUSD = totalUSD + amountTokenUSD; + for (final token in balanceGetResponse.token) { + if (token.tokenId != null) { + if (token.tokenId == 0) { + accountBalance.tokensFungiblesNb++; + + final ucidsToken = ucidsTokens[token.address]; + if (ucidsToken != null && ucidsToken != 0) { + final amountTokenUSD = + (Decimal.parse(fromBigInt(token.amount).toString()) * + Decimal.parse( + aedappfm.CoinPriceRepositoryImpl() + .getPriceFromUcid(ucidsToken, cryptoPrice) + .toString(), + )) + .toDouble(); + totalUSD = totalUSD + amountTokenUSD; + } + } else { + accountBalance.nftNb++; } - } else { - accountBalance.nftNb++; } } - } - accountBalance.totalUSD = totalUSD; + accountBalance.totalUSD = totalUSD; - account.balance = accountBalance; - await updateAccount(); + return account.copyWith(balance: accountBalance); + }); } Future updateFungiblesTokens() async { - final account = await future; - if (account == null) { - return; - } - final appService = ref.read(appServiceProvider); - final poolsListRaw = await ref.read(DexPoolProviders.getPoolListRaw.future); - - account.accountTokens = await appService.getFungiblesTokensList( - account.genesisAddress, - poolsListRaw, - ); - await updateAccount(); + await _update((account) async { + final appService = ref.read(appServiceProvider); + final poolsListRaw = + await ref.read(DexPoolProviders.getPoolListRaw.future); + + return account.copyWith( + accountTokens: await appService.getFungiblesTokensList( + account.genesisAddress, + poolsListRaw, + ), + ); + }); } Future updateRecentTransactions() async { - final account = await future; - if (account == null) { - return; - } - final session = ref.read(sessionNotifierProvider).loggedIn!; - final appService = ref.read(appServiceProvider); - - account - ..recentTransactions = await appService.getAccountRecentTransactions( - account.genesisAddress, - account.name, - session.wallet.keychainSecuredInfos, - account.recentTransactions ?? [], - ) - ..lastLoadingTransactionInputs = DateTime.now().millisecondsSinceEpoch ~/ - Duration.millisecondsPerSecond; - await updateAccount(); + await _update((account) async { + final session = ref.read(sessionNotifierProvider).loggedIn!; + final appService = ref.read(appServiceProvider); + + return account.copyWith( + recentTransactions: await appService.getAccountRecentTransactions( + account.genesisAddress, + account.name, + session.wallet.keychainSecuredInfos, + account.recentTransactions ?? [], + ), + lastLoadingTransactionInputs: DateTime.now().millisecondsSinceEpoch ~/ + Duration.millisecondsPerSecond, + ); + }); } Future addCustomTokenAddress(String tokenAddress) async { - final account = await future; - if (account == null) { - return; - } - if (Address(address: tokenAddress).isValid() == false) return; - (account.customTokenAddressList ??= []).add(tokenAddress.toUpperCase()); - await updateAccount(); + await _update((account) async { + return account.copyWith( + customTokenAddressList: [ + ...account.customTokenAddressList ?? [], + tokenAddress.toUpperCase(), + ], + ); + }); } Future removeCustomTokenAddress(String tokenAddress) async { - final account = await future; - if (account == null) { - return; - } - if (Address(address: tokenAddress).isValid() == false) return; - (account.customTokenAddressList ??= []).remove(tokenAddress.toUpperCase()); - await updateAccount(); + await _update((account) async { + final customTokenAddressList = account.customTokenAddressList; + if (customTokenAddressList == null) return account; + + return account.copyWith( + customTokenAddressList: customTokenAddressList + .where( + (element) => element != tokenAddress.toUpperCase(), + ) + .toList(), + ); + }); } Future checkCustomTokenAddress(String tokenAddress) async { @@ -252,42 +254,42 @@ class AccountNotifier extends _$AccountNotifier { } Future updateNFT() async { - final account = await future; - if (account == null) { - return; - } - final session = ref.read(sessionNotifierProvider).loggedIn!; - final tokenInformation = await ref.read( - NFTProviders.getNFTList( - account.genesisAddress, - account.name, - session.wallet.keychainSecuredInfos, - ).future, - ); - - account - ..accountNFT = tokenInformation.$1 - ..accountNFTCollections = tokenInformation.$2; + await _update( + (account) async { + final session = ref.read(sessionNotifierProvider).loggedIn!; + final tokenInformation = await ref.read( + NFTProviders.getNFTList( + account.genesisAddress, + account.name, + session.wallet.keychainSecuredInfos, + ).future, + ); - await updateAccount(); + return account.copyWith( + accountNFT: tokenInformation.$1, + accountNFTCollections: tokenInformation.$2, + ); + }, + ); } Future clearRecentTransactionsFromCache() async { - final account = await future; - if (account == null) { - return; - } - - account.recentTransactions = []; - await updateAccount(); + await _update( + (account) => account.copyWith(recentTransactions: []), + ); } - Future updateAccount() async { - final account = await future; - if (account == null) { - return; - } + Future _update( + FutureOr Function(Account) doUpdate, + ) async { + await update( + (account) async { + if (account == null) return null; - await AccountHiveDatasource.instance().updateAccount(account); + final newState = await doUpdate(account); + await AccountHiveDatasource.instance().updateAccount(newState); + return newState; + }, + ); } } diff --git a/lib/application/account/account_notifier.g.dart b/lib/application/account/account_notifier.g.dart index 59baa3319..bba848c53 100644 --- a/lib/application/account/account_notifier.g.dart +++ b/lib/application/account/account_notifier.g.dart @@ -6,7 +6,7 @@ part of 'account_notifier.dart'; // RiverpodGenerator // ************************************************************************** -String _$accountNotifierHash() => r'e1fe68fac65b0f98a98bbe745d1608ff9e9cd990'; +String _$accountNotifierHash() => r'33410ce13c1065c8a2840153d20ff40456ac07cc'; /// Copied from Dart SDK class _SystemHash { diff --git a/lib/application/account/accounts_notifier.dart b/lib/application/account/accounts_notifier.dart index 8f7d0d84e..b3352ee6a 100644 --- a/lib/application/account/accounts_notifier.dart +++ b/lib/application/account/accounts_notifier.dart @@ -4,7 +4,6 @@ import 'dart:async'; import 'package:aewallet/application/account/account_notifier.dart'; import 'package:aewallet/application/session/session.dart'; -import 'package:aewallet/infrastructure/datasources/account.hive.dart'; import 'package:aewallet/infrastructure/repositories/local_account.dart'; import 'package:aewallet/model/data/account.dart'; import 'package:aewallet/util/account_formatters.dart'; @@ -16,7 +15,7 @@ part 'accounts_notifier.g.dart'; @riverpod class AccountsNotifier extends _$AccountsNotifier { @override - FutureOr> build() async { + FutureOr> build() async { final session = ref.watch(sessionNotifierProvider); if (session.isLoggedOut) { return []; @@ -55,16 +54,18 @@ class AccountsNotifier extends _$AccountsNotifier { return ref.read(accountNotifierProvider(accountName).notifier); } + // TODO(Chralu): check if this works Future clearRecentTransactionsFromCache() async { final accounts = await future; for (final account in accounts) { - account.recentTransactions = []; - await AccountHiveDatasource.instance().updateAccount(account); + await ref + .read(accountNotifierProvider(account.name).notifier) + .clearRecentTransactionsFromCache(); } } } -extension AccountsExt on List { +extension AccountsExt on Iterable { Account? get selectedAccount { for (final account in this) { if (account.selected == true) return account; @@ -91,7 +92,7 @@ extension AccountsExt on List { } } -extension FutureAccountsExt on Future> { +extension FutureAccountsExt on Future> { Future get selectedAccount async { return (await this).selectedAccount; } diff --git a/lib/application/account/accounts_notifier.g.dart b/lib/application/account/accounts_notifier.g.dart index f2380c8e3..e939ce1a9 100644 --- a/lib/application/account/accounts_notifier.g.dart +++ b/lib/application/account/accounts_notifier.g.dart @@ -6,12 +6,12 @@ part of 'accounts_notifier.dart'; // RiverpodGenerator // ************************************************************************** -String _$accountsNotifierHash() => r'83532736c884190fa4b4cb54a0ab4c43b0dcdd05'; +String _$accountsNotifierHash() => r'58f869b3689672b3bd919a0071e727e97feeeb67'; /// See also [AccountsNotifier]. @ProviderFor(AccountsNotifier) -final accountsNotifierProvider = - AutoDisposeAsyncNotifierProvider>.internal( +final accountsNotifierProvider = AutoDisposeAsyncNotifierProvider< + AccountsNotifier, Iterable>.internal( AccountsNotifier.new, name: r'accountsNotifierProvider', debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product') @@ -21,6 +21,6 @@ final accountsNotifierProvider = allTransitiveDependencies: null, ); -typedef _$AccountsNotifier = AutoDisposeAsyncNotifier>; +typedef _$AccountsNotifier = AutoDisposeAsyncNotifier>; // ignore_for_file: type=lint // ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package diff --git a/lib/domain/usecases/transaction/send_transaction.freezed.dart b/lib/domain/usecases/transaction/send_transaction.freezed.dart index 7f9ea7252..35d6036c1 100644 --- a/lib/domain/usecases/transaction/send_transaction.freezed.dart +++ b/lib/domain/usecases/transaction/send_transaction.freezed.dart @@ -42,6 +42,7 @@ abstract class $SendTransactionCommandCopyWith<$Res> { @useResult $Res call({Account senderAccount, Data data, String type, int version}); + $AccountCopyWith<$Res> get senderAccount; $DataCopyWith<$Res> get data; } @@ -86,6 +87,16 @@ class _$SendTransactionCommandCopyWithImpl<$Res, ) as $Val); } + /// Create a copy of SendTransactionCommand + /// with the given fields replaced by the non-null parameter values. + @override + @pragma('vm:prefer-inline') + $AccountCopyWith<$Res> get senderAccount { + return $AccountCopyWith<$Res>(_value.senderAccount, (value) { + return _then(_value.copyWith(senderAccount: value) as $Val); + }); + } + /// Create a copy of SendTransactionCommand /// with the given fields replaced by the non-null parameter values. @override @@ -108,6 +119,8 @@ abstract class _$$SendTransactionCommandImplCopyWith<$Res> @useResult $Res call({Account senderAccount, Data data, String type, int version}); + @override + $AccountCopyWith<$Res> get senderAccount; @override $DataCopyWith<$Res> get data; } diff --git a/lib/infrastructure/datasources/account.hive.dart b/lib/infrastructure/datasources/account.hive.dart index 762ebcc9f..f3c3d7896 100644 --- a/lib/infrastructure/datasources/account.hive.dart +++ b/lib/infrastructure/datasources/account.hive.dart @@ -1,5 +1,4 @@ import 'package:aewallet/model/data/account.dart'; -import 'package:aewallet/model/data/account_balance.dart'; import 'package:aewallet/model/data/hive_app_wallet_dto.dart'; import 'package:hive/hive.dart'; @@ -47,44 +46,23 @@ class AccountHiveDatasource { return _writeAppWallet(appWallet); } - Future clearAccount() async { - final appWallet = await _readAppWallet(); - appWallet.appKeychain.accounts.clear(); - return _writeAppWallet(appWallet); - } - - Future changeAccount(String accountName) async { + Future selectAccount(String accountName) async { final appWallet = await _readAppWallet(); for (var i = 0; i < appWallet.appKeychain.accounts.length; i++) { - if (appWallet.appKeychain.accounts[i].name == accountName) { - appWallet.appKeychain.accounts[i].selected = true; - } else { - appWallet.appKeychain.accounts[i].selected = false; - } + final account = appWallet.appKeychain.accounts[i]; + final updatedAccount = account.copyWith( + selected: account.name == accountName, + ); + appWallet.appKeychain.accounts[i] = updatedAccount; } return _writeAppWallet(appWallet); } - Future updateAccountBalance( - Account selectedAccount, - AccountBalance balance, - ) async { - final appWallet = await _readAppWallet(); - final accounts = appWallet.appKeychain.accounts; - for (final account in accounts) { - if (selectedAccount.name == account.name) { - account.balance = balance; - await _writeAppWallet(appWallet); - return; - } - } - } - - Future updateAccount(Account selectedAccount) async { + Future updateAccount(Account updatedAccount) async { final appWallet = await _readAppWallet(); appWallet.appKeychain.accounts = appWallet.appKeychain.accounts.map( (account) { - if (account.name == selectedAccount.name) return selectedAccount; + if (account.name == updatedAccount.name) return updatedAccount; return account; }, ).toList(); diff --git a/lib/infrastructure/datasources/appdb.hive.dart b/lib/infrastructure/datasources/appdb.hive.dart index a66551d37..411337260 100644 --- a/lib/infrastructure/datasources/appdb.hive.dart +++ b/lib/infrastructure/datasources/appdb.hive.dart @@ -54,7 +54,7 @@ class DBHelper { ..registerAdapter(ContactAdapter()) ..registerAdapter(HiveAppWalletDTOAdapter()) ..registerAdapter(AccountBalanceAdapter()) - ..registerAdapter(AccountAdapter()) + ..registerAdapter(AccountImplAdapter()) ..registerAdapter(AppKeychainAdapter()) ..registerAdapter(RecentTransactionAdapter()) ..registerAdapter(AccountTokenAdapter()) diff --git a/lib/infrastructure/repositories/local_account.dart b/lib/infrastructure/repositories/local_account.dart index 249df219e..9caf243f2 100644 --- a/lib/infrastructure/repositories/local_account.dart +++ b/lib/infrastructure/repositories/local_account.dart @@ -37,6 +37,6 @@ class AccountLocalRepository implements AccountLocalRepositoryInterface { @override Future selectAccount(String name) async { - await _accountDatasource.changeAccount(name); + await _accountDatasource.selectAccount(name); } } diff --git a/lib/model/data/account.dart b/lib/model/data/account.dart index 316d8eb4b..1036a5780 100644 --- a/lib/model/data/account.dart +++ b/lib/model/data/account.dart @@ -6,6 +6,7 @@ import 'package:aewallet/model/data/nft_infos_off_chain.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:hive/hive.dart'; +part 'account.freezed.dart'; part 'account.g.dart'; class AccountConverter implements JsonConverter> { @@ -28,109 +29,57 @@ class AccountConverter implements JsonConverter> { } } -@HiveType(typeId: HiveTypeIds.account) - /// Next field available : 16 -class Account extends HiveObject { - Account({ - required this.name, - required this.genesisAddress, - this.lastLoadingTransactionInputs, - this.selected = false, - this.balance, - this.recentTransactions, - this.accountTokens, - this.accountNFT, - this.accountNFTCollections, - this.serviceType, - this.customTokenAddressList, - }); - - Account copyWith({ - String? name, - String? genesisAddress, - int? lastLoadingTransactionInputs, - bool? selected, +@freezed +class Account extends HiveObject with _$Account { + @HiveType(typeId: HiveTypeIds.account) + factory Account({ + /// Account name - Primary Key + @HiveField(0) required String name, + + /// Genesis Address + @HiveField(1) required String genesisAddress, + + /// Last loading of transaction inputs + @HiveField(2) int? lastLoadingTransactionInputs, + + /// Whether this is the currently selected account + @HiveField(3) bool? selected, + + /// Last address + + @HiveField(4) + @Deprecated( + 'Genesis address should be preferred instead of last address after AEIP21', + ) String? lastAddress, - String? serviceType, - AccountBalance? balance, - List? recentTransactions, - List? accountTokens, - List? accountNFT, - List? accountNFTCollections, - List? customTokenAddressList, - }) => - Account( - name: name ?? this.name, - genesisAddress: genesisAddress ?? this.genesisAddress, - lastLoadingTransactionInputs: - lastLoadingTransactionInputs ?? this.lastLoadingTransactionInputs, - selected: selected ?? this.selected, - serviceType: serviceType ?? this.serviceType, - balance: balance ?? this.balance, - recentTransactions: recentTransactions ?? this.recentTransactions, - accountTokens: accountTokens ?? this.accountTokens, - accountNFT: accountNFT ?? this.accountNFT, - accountNFTCollections: - accountNFTCollections ?? this.accountNFTCollections, - customTokenAddressList: - customTokenAddressList ?? this.customTokenAddressList, - ); - - /// Account name - Primary Key - @HiveField(0) - final String name; - - /// Genesis Address - @HiveField(1) - final String genesisAddress; - - /// Last loading of transaction inputs - @HiveField(2) - int? lastLoadingTransactionInputs; - - /// Whether this is the currently selected account - @HiveField(3) - bool? selected; - - /// Last address - - @HiveField(4) - @Deprecated( - 'Genesis address should be preferred instead of last address after AEIP21', - ) - String? lastAddress; - - /// Balance - @HiveField(5) - AccountBalance? balance; - - /// Recent transactions - @HiveField(6) - List? recentTransactions; - - /// Tokens - @HiveField(7) - List? accountTokens; - - /// NFT - @HiveField(8) - List? accountNFT; - - /// NFT Info Off Chain - @Deprecated('Thanks to hive, we should keep this unused property...') - @HiveField(10) - List? nftInfosOffChainList; - - /// Service Type - @HiveField(13) - String? serviceType; - - /// NFT Collections - @HiveField(14) - List? accountNFTCollections; - - /// Custom Token Addresses - @HiveField(15) - List? customTokenAddressList; + + /// Balance + @HiveField(5) AccountBalance? balance, + + /// Recent transactions + @HiveField(6) List? recentTransactions, + + /// Tokens + @HiveField(7) List? accountTokens, + + /// NFT + @HiveField(8) List? accountNFT, + + /// NFT Info Off Chain + @Deprecated('Thanks to hive, we should keep this unused property...') + @HiveField(10) + List? nftInfosOffChainList, + + /// Service Type + @HiveField(13) String? serviceType, + + /// NFT Collections + @HiveField(14) List? accountNFTCollections, + + /// Custom Token Addresses + @HiveField(15) List? customTokenAddressList, + }) = _Account; + + Account._(); } diff --git a/lib/model/data/account.freezed.dart b/lib/model/data/account.freezed.dart new file mode 100644 index 000000000..c492aa3aa --- /dev/null +++ b/lib/model/data/account.freezed.dart @@ -0,0 +1,626 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'account.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models'); + +/// @nodoc +mixin _$Account { + /// Account name - Primary Key + @HiveField(0) + String get name => throw _privateConstructorUsedError; + + /// Genesis Address + @HiveField(1) + String get genesisAddress => throw _privateConstructorUsedError; + + /// Last loading of transaction inputs + @HiveField(2) + int? get lastLoadingTransactionInputs => throw _privateConstructorUsedError; + + /// Whether this is the currently selected account + @HiveField(3) + bool? get selected => throw _privateConstructorUsedError; + + /// Last address + @HiveField(4) + @Deprecated( + 'Genesis address should be preferred instead of last address after AEIP21') + String? get lastAddress => throw _privateConstructorUsedError; + + /// Balance + @HiveField(5) + AccountBalance? get balance => throw _privateConstructorUsedError; + + /// Recent transactions + @HiveField(6) + List? get recentTransactions => + throw _privateConstructorUsedError; + + /// Tokens + @HiveField(7) + List? get accountTokens => throw _privateConstructorUsedError; + + /// NFT + @HiveField(8) + List? get accountNFT => throw _privateConstructorUsedError; + + /// NFT Info Off Chain + @Deprecated('Thanks to hive, we should keep this unused property...') + @HiveField(10) + List? get nftInfosOffChainList => + throw _privateConstructorUsedError; + + /// Service Type + @HiveField(13) + String? get serviceType => throw _privateConstructorUsedError; + + /// NFT Collections + @HiveField(14) + List? get accountNFTCollections => + throw _privateConstructorUsedError; + + /// Custom Token Addresses + @HiveField(15) + List? get customTokenAddressList => + throw _privateConstructorUsedError; + + /// Create a copy of Account + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + $AccountCopyWith get copyWith => throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $AccountCopyWith<$Res> { + factory $AccountCopyWith(Account value, $Res Function(Account) then) = + _$AccountCopyWithImpl<$Res, Account>; + @useResult + $Res call( + {@HiveField(0) String name, + @HiveField(1) String genesisAddress, + @HiveField(2) int? lastLoadingTransactionInputs, + @HiveField(3) bool? selected, + @HiveField(4) + @Deprecated( + 'Genesis address should be preferred instead of last address after AEIP21') + String? lastAddress, + @HiveField(5) AccountBalance? balance, + @HiveField(6) List? recentTransactions, + @HiveField(7) List? accountTokens, + @HiveField(8) List? accountNFT, + @Deprecated('Thanks to hive, we should keep this unused property...') + @HiveField(10) + List? nftInfosOffChainList, + @HiveField(13) String? serviceType, + @HiveField(14) List? accountNFTCollections, + @HiveField(15) List? customTokenAddressList}); +} + +/// @nodoc +class _$AccountCopyWithImpl<$Res, $Val extends Account> + implements $AccountCopyWith<$Res> { + _$AccountCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + /// Create a copy of Account + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? name = null, + Object? genesisAddress = null, + Object? lastLoadingTransactionInputs = freezed, + Object? selected = freezed, + Object? lastAddress = freezed, + Object? balance = freezed, + Object? recentTransactions = freezed, + Object? accountTokens = freezed, + Object? accountNFT = freezed, + Object? nftInfosOffChainList = freezed, + Object? serviceType = freezed, + Object? accountNFTCollections = freezed, + Object? customTokenAddressList = freezed, + }) { + return _then(_value.copyWith( + name: null == name + ? _value.name + : name // ignore: cast_nullable_to_non_nullable + as String, + genesisAddress: null == genesisAddress + ? _value.genesisAddress + : genesisAddress // ignore: cast_nullable_to_non_nullable + as String, + lastLoadingTransactionInputs: freezed == lastLoadingTransactionInputs + ? _value.lastLoadingTransactionInputs + : lastLoadingTransactionInputs // ignore: cast_nullable_to_non_nullable + as int?, + selected: freezed == selected + ? _value.selected + : selected // ignore: cast_nullable_to_non_nullable + as bool?, + lastAddress: freezed == lastAddress + ? _value.lastAddress + : lastAddress // ignore: cast_nullable_to_non_nullable + as String?, + balance: freezed == balance + ? _value.balance + : balance // ignore: cast_nullable_to_non_nullable + as AccountBalance?, + recentTransactions: freezed == recentTransactions + ? _value.recentTransactions + : recentTransactions // ignore: cast_nullable_to_non_nullable + as List?, + accountTokens: freezed == accountTokens + ? _value.accountTokens + : accountTokens // ignore: cast_nullable_to_non_nullable + as List?, + accountNFT: freezed == accountNFT + ? _value.accountNFT + : accountNFT // ignore: cast_nullable_to_non_nullable + as List?, + nftInfosOffChainList: freezed == nftInfosOffChainList + ? _value.nftInfosOffChainList + : nftInfosOffChainList // ignore: cast_nullable_to_non_nullable + as List?, + serviceType: freezed == serviceType + ? _value.serviceType + : serviceType // ignore: cast_nullable_to_non_nullable + as String?, + accountNFTCollections: freezed == accountNFTCollections + ? _value.accountNFTCollections + : accountNFTCollections // ignore: cast_nullable_to_non_nullable + as List?, + customTokenAddressList: freezed == customTokenAddressList + ? _value.customTokenAddressList + : customTokenAddressList // ignore: cast_nullable_to_non_nullable + as List?, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$AccountImplCopyWith<$Res> implements $AccountCopyWith<$Res> { + factory _$$AccountImplCopyWith( + _$AccountImpl value, $Res Function(_$AccountImpl) then) = + __$$AccountImplCopyWithImpl<$Res>; + @override + @useResult + $Res call( + {@HiveField(0) String name, + @HiveField(1) String genesisAddress, + @HiveField(2) int? lastLoadingTransactionInputs, + @HiveField(3) bool? selected, + @HiveField(4) + @Deprecated( + 'Genesis address should be preferred instead of last address after AEIP21') + String? lastAddress, + @HiveField(5) AccountBalance? balance, + @HiveField(6) List? recentTransactions, + @HiveField(7) List? accountTokens, + @HiveField(8) List? accountNFT, + @Deprecated('Thanks to hive, we should keep this unused property...') + @HiveField(10) + List? nftInfosOffChainList, + @HiveField(13) String? serviceType, + @HiveField(14) List? accountNFTCollections, + @HiveField(15) List? customTokenAddressList}); +} + +/// @nodoc +class __$$AccountImplCopyWithImpl<$Res> + extends _$AccountCopyWithImpl<$Res, _$AccountImpl> + implements _$$AccountImplCopyWith<$Res> { + __$$AccountImplCopyWithImpl( + _$AccountImpl _value, $Res Function(_$AccountImpl) _then) + : super(_value, _then); + + /// Create a copy of Account + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? name = null, + Object? genesisAddress = null, + Object? lastLoadingTransactionInputs = freezed, + Object? selected = freezed, + Object? lastAddress = freezed, + Object? balance = freezed, + Object? recentTransactions = freezed, + Object? accountTokens = freezed, + Object? accountNFT = freezed, + Object? nftInfosOffChainList = freezed, + Object? serviceType = freezed, + Object? accountNFTCollections = freezed, + Object? customTokenAddressList = freezed, + }) { + return _then(_$AccountImpl( + name: null == name + ? _value.name + : name // ignore: cast_nullable_to_non_nullable + as String, + genesisAddress: null == genesisAddress + ? _value.genesisAddress + : genesisAddress // ignore: cast_nullable_to_non_nullable + as String, + lastLoadingTransactionInputs: freezed == lastLoadingTransactionInputs + ? _value.lastLoadingTransactionInputs + : lastLoadingTransactionInputs // ignore: cast_nullable_to_non_nullable + as int?, + selected: freezed == selected + ? _value.selected + : selected // ignore: cast_nullable_to_non_nullable + as bool?, + lastAddress: freezed == lastAddress + ? _value.lastAddress + : lastAddress // ignore: cast_nullable_to_non_nullable + as String?, + balance: freezed == balance + ? _value.balance + : balance // ignore: cast_nullable_to_non_nullable + as AccountBalance?, + recentTransactions: freezed == recentTransactions + ? _value._recentTransactions + : recentTransactions // ignore: cast_nullable_to_non_nullable + as List?, + accountTokens: freezed == accountTokens + ? _value._accountTokens + : accountTokens // ignore: cast_nullable_to_non_nullable + as List?, + accountNFT: freezed == accountNFT + ? _value._accountNFT + : accountNFT // ignore: cast_nullable_to_non_nullable + as List?, + nftInfosOffChainList: freezed == nftInfosOffChainList + ? _value._nftInfosOffChainList + : nftInfosOffChainList // ignore: cast_nullable_to_non_nullable + as List?, + serviceType: freezed == serviceType + ? _value.serviceType + : serviceType // ignore: cast_nullable_to_non_nullable + as String?, + accountNFTCollections: freezed == accountNFTCollections + ? _value._accountNFTCollections + : accountNFTCollections // ignore: cast_nullable_to_non_nullable + as List?, + customTokenAddressList: freezed == customTokenAddressList + ? _value._customTokenAddressList + : customTokenAddressList // ignore: cast_nullable_to_non_nullable + as List?, + )); + } +} + +/// @nodoc + +@HiveType(typeId: HiveTypeIds.account) +class _$AccountImpl extends _Account { + _$AccountImpl( + {@HiveField(0) required this.name, + @HiveField(1) required this.genesisAddress, + @HiveField(2) this.lastLoadingTransactionInputs, + @HiveField(3) this.selected, + @HiveField(4) + @Deprecated( + 'Genesis address should be preferred instead of last address after AEIP21') + this.lastAddress, + @HiveField(5) this.balance, + @HiveField(6) final List? recentTransactions, + @HiveField(7) final List? accountTokens, + @HiveField(8) final List? accountNFT, + @Deprecated('Thanks to hive, we should keep this unused property...') + @HiveField(10) + final List? nftInfosOffChainList, + @HiveField(13) this.serviceType, + @HiveField(14) final List? accountNFTCollections, + @HiveField(15) final List? customTokenAddressList}) + : _recentTransactions = recentTransactions, + _accountTokens = accountTokens, + _accountNFT = accountNFT, + _nftInfosOffChainList = nftInfosOffChainList, + _accountNFTCollections = accountNFTCollections, + _customTokenAddressList = customTokenAddressList, + super._(); + + /// Account name - Primary Key + @override + @HiveField(0) + final String name; + + /// Genesis Address + @override + @HiveField(1) + final String genesisAddress; + + /// Last loading of transaction inputs + @override + @HiveField(2) + final int? lastLoadingTransactionInputs; + + /// Whether this is the currently selected account + @override + @HiveField(3) + final bool? selected; + + /// Last address + @override + @HiveField(4) + @Deprecated( + 'Genesis address should be preferred instead of last address after AEIP21') + final String? lastAddress; + + /// Balance + @override + @HiveField(5) + final AccountBalance? balance; + + /// Recent transactions + final List? _recentTransactions; + + /// Recent transactions + @override + @HiveField(6) + List? get recentTransactions { + final value = _recentTransactions; + if (value == null) return null; + if (_recentTransactions is EqualUnmodifiableListView) + return _recentTransactions; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(value); + } + + /// Tokens + final List? _accountTokens; + + /// Tokens + @override + @HiveField(7) + List? get accountTokens { + final value = _accountTokens; + if (value == null) return null; + if (_accountTokens is EqualUnmodifiableListView) return _accountTokens; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(value); + } + + /// NFT + final List? _accountNFT; + + /// NFT + @override + @HiveField(8) + List? get accountNFT { + final value = _accountNFT; + if (value == null) return null; + if (_accountNFT is EqualUnmodifiableListView) return _accountNFT; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(value); + } + + /// NFT Info Off Chain + final List? _nftInfosOffChainList; + + /// NFT Info Off Chain + @override + @Deprecated('Thanks to hive, we should keep this unused property...') + @HiveField(10) + List? get nftInfosOffChainList { + final value = _nftInfosOffChainList; + if (value == null) return null; + if (_nftInfosOffChainList is EqualUnmodifiableListView) + return _nftInfosOffChainList; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(value); + } + + /// Service Type + @override + @HiveField(13) + final String? serviceType; + + /// NFT Collections + final List? _accountNFTCollections; + + /// NFT Collections + @override + @HiveField(14) + List? get accountNFTCollections { + final value = _accountNFTCollections; + if (value == null) return null; + if (_accountNFTCollections is EqualUnmodifiableListView) + return _accountNFTCollections; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(value); + } + + /// Custom Token Addresses + final List? _customTokenAddressList; + + /// Custom Token Addresses + @override + @HiveField(15) + List? get customTokenAddressList { + final value = _customTokenAddressList; + if (value == null) return null; + if (_customTokenAddressList is EqualUnmodifiableListView) + return _customTokenAddressList; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(value); + } + + @override + String toString() { + return 'Account(name: $name, genesisAddress: $genesisAddress, lastLoadingTransactionInputs: $lastLoadingTransactionInputs, selected: $selected, lastAddress: $lastAddress, balance: $balance, recentTransactions: $recentTransactions, accountTokens: $accountTokens, accountNFT: $accountNFT, nftInfosOffChainList: $nftInfosOffChainList, serviceType: $serviceType, accountNFTCollections: $accountNFTCollections, customTokenAddressList: $customTokenAddressList)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$AccountImpl && + (identical(other.name, name) || other.name == name) && + (identical(other.genesisAddress, genesisAddress) || + other.genesisAddress == genesisAddress) && + (identical(other.lastLoadingTransactionInputs, + lastLoadingTransactionInputs) || + other.lastLoadingTransactionInputs == + lastLoadingTransactionInputs) && + (identical(other.selected, selected) || + other.selected == selected) && + (identical(other.lastAddress, lastAddress) || + other.lastAddress == lastAddress) && + (identical(other.balance, balance) || other.balance == balance) && + const DeepCollectionEquality() + .equals(other._recentTransactions, _recentTransactions) && + const DeepCollectionEquality() + .equals(other._accountTokens, _accountTokens) && + const DeepCollectionEquality() + .equals(other._accountNFT, _accountNFT) && + const DeepCollectionEquality() + .equals(other._nftInfosOffChainList, _nftInfosOffChainList) && + (identical(other.serviceType, serviceType) || + other.serviceType == serviceType) && + const DeepCollectionEquality() + .equals(other._accountNFTCollections, _accountNFTCollections) && + const DeepCollectionEquality().equals( + other._customTokenAddressList, _customTokenAddressList)); + } + + @override + int get hashCode => Object.hash( + runtimeType, + name, + genesisAddress, + lastLoadingTransactionInputs, + selected, + lastAddress, + balance, + const DeepCollectionEquality().hash(_recentTransactions), + const DeepCollectionEquality().hash(_accountTokens), + const DeepCollectionEquality().hash(_accountNFT), + const DeepCollectionEquality().hash(_nftInfosOffChainList), + serviceType, + const DeepCollectionEquality().hash(_accountNFTCollections), + const DeepCollectionEquality().hash(_customTokenAddressList)); + + /// Create a copy of Account + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + @override + @pragma('vm:prefer-inline') + _$$AccountImplCopyWith<_$AccountImpl> get copyWith => + __$$AccountImplCopyWithImpl<_$AccountImpl>(this, _$identity); +} + +abstract class _Account extends Account { + factory _Account( + {@HiveField(0) required final String name, + @HiveField(1) required final String genesisAddress, + @HiveField(2) final int? lastLoadingTransactionInputs, + @HiveField(3) final bool? selected, + @HiveField(4) + @Deprecated( + 'Genesis address should be preferred instead of last address after AEIP21') + final String? lastAddress, + @HiveField(5) final AccountBalance? balance, + @HiveField(6) final List? recentTransactions, + @HiveField(7) final List? accountTokens, + @HiveField(8) final List? accountNFT, + @Deprecated('Thanks to hive, we should keep this unused property...') + @HiveField(10) + final List? nftInfosOffChainList, + @HiveField(13) final String? serviceType, + @HiveField(14) final List? accountNFTCollections, + @HiveField(15) + final List? customTokenAddressList}) = _$AccountImpl; + _Account._() : super._(); + + /// Account name - Primary Key + @override + @HiveField(0) + String get name; + + /// Genesis Address + @override + @HiveField(1) + String get genesisAddress; + + /// Last loading of transaction inputs + @override + @HiveField(2) + int? get lastLoadingTransactionInputs; + + /// Whether this is the currently selected account + @override + @HiveField(3) + bool? get selected; + + /// Last address + @override + @HiveField(4) + @Deprecated( + 'Genesis address should be preferred instead of last address after AEIP21') + String? get lastAddress; + + /// Balance + @override + @HiveField(5) + AccountBalance? get balance; + + /// Recent transactions + @override + @HiveField(6) + List? get recentTransactions; + + /// Tokens + @override + @HiveField(7) + List? get accountTokens; + + /// NFT + @override + @HiveField(8) + List? get accountNFT; + + /// NFT Info Off Chain + @override + @Deprecated('Thanks to hive, we should keep this unused property...') + @HiveField(10) + List? get nftInfosOffChainList; + + /// Service Type + @override + @HiveField(13) + String? get serviceType; + + /// NFT Collections + @override + @HiveField(14) + List? get accountNFTCollections; + + /// Custom Token Addresses + @override + @HiveField(15) + List? get customTokenAddressList; + + /// Create a copy of Account + /// with the given fields replaced by the non-null parameter values. + @override + @JsonKey(includeFromJson: false, includeToJson: false) + _$$AccountImplCopyWith<_$AccountImpl> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/lib/model/data/account.g.dart b/lib/model/data/account.g.dart index 4784c99e6..25fc00b26 100644 --- a/lib/model/data/account.g.dart +++ b/lib/model/data/account.g.dart @@ -6,35 +6,35 @@ part of 'account.dart'; // TypeAdapterGenerator // ************************************************************************** -class AccountAdapter extends TypeAdapter { +class AccountImplAdapter extends TypeAdapter<_$AccountImpl> { @override final int typeId = 1; @override - Account read(BinaryReader reader) { + _$AccountImpl read(BinaryReader reader) { final numOfFields = reader.readByte(); final fields = { for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(), }; - return Account( + return _$AccountImpl( name: fields[0] as String, genesisAddress: fields[1] as String, lastLoadingTransactionInputs: fields[2] as int?, selected: fields[3] as bool?, + lastAddress: fields[4] as String?, balance: fields[5] as AccountBalance?, recentTransactions: (fields[6] as List?)?.cast(), accountTokens: (fields[7] as List?)?.cast(), accountNFT: (fields[8] as List?)?.cast(), - accountNFTCollections: (fields[14] as List?)?.cast(), + nftInfosOffChainList: (fields[10] as List?)?.cast(), serviceType: fields[13] as String?, + accountNFTCollections: (fields[14] as List?)?.cast(), customTokenAddressList: (fields[15] as List?)?.cast(), - ) - ..lastAddress = fields[4] as String? - ..nftInfosOffChainList = (fields[10] as List?)?.cast(); + ); } @override - void write(BinaryWriter writer, Account obj) { + void write(BinaryWriter writer, _$AccountImpl obj) { writer ..writeByte(13) ..writeByte(0) @@ -49,6 +49,8 @@ class AccountAdapter extends TypeAdapter { ..write(obj.lastAddress) ..writeByte(5) ..write(obj.balance) + ..writeByte(13) + ..write(obj.serviceType) ..writeByte(6) ..write(obj.recentTransactions) ..writeByte(7) @@ -57,8 +59,6 @@ class AccountAdapter extends TypeAdapter { ..write(obj.accountNFT) ..writeByte(10) ..write(obj.nftInfosOffChainList) - ..writeByte(13) - ..write(obj.serviceType) ..writeByte(14) ..write(obj.accountNFTCollections) ..writeByte(15) @@ -71,7 +71,7 @@ class AccountAdapter extends TypeAdapter { @override bool operator ==(Object other) => identical(this, other) || - other is AccountAdapter && + other is AccountImplAdapter && runtimeType == other.runtimeType && typeId == other.typeId; } diff --git a/lib/model/data/app_keychain.dart b/lib/model/data/app_keychain.dart index 03b56f279..58b8cb6ed 100644 --- a/lib/model/data/app_keychain.dart +++ b/lib/model/data/app_keychain.dart @@ -34,7 +34,7 @@ class AppKeychain extends HiveObject { // To manage the migration of https://github.com/archethic-foundation/archethic-wallet/pull/759 for (final account in accounts) { if (account.serviceType == 'archethicWallet') { - await AccountHiveDatasource.instance().changeAccount(account.name); + await AccountHiveDatasource.instance().selectAccount(account.name); return account; } } diff --git a/lib/ui/views/accounts/layouts/account_list.dart b/lib/ui/views/accounts/layouts/account_list.dart index 228aef275..c83090932 100644 --- a/lib/ui/views/accounts/layouts/account_list.dart +++ b/lib/ui/views/accounts/layouts/account_list.dart @@ -31,7 +31,8 @@ class AccountsListState extends ConsumerState (accounts) => accounts.valueOrNull?.selectedAccount, ), ); - final accountsList = ref.watch(accountsNotifierProvider).valueOrNull ?? []; + final accountsList = + (ref.watch(accountsNotifierProvider).valueOrNull ?? []).toList(); if (accountsList.isNotEmpty) { accountsList.sort( (a, b) => a.nameDisplayed.compareTo(b.nameDisplayed), diff --git a/lib/ui/views/main/bloc/providers.dart b/lib/ui/views/main/bloc/providers.dart index 7dfb22368..010c0b768 100644 --- a/lib/ui/views/main/bloc/providers.dart +++ b/lib/ui/views/main/bloc/providers.dart @@ -32,10 +32,10 @@ class HomePage extends _$HomePage { ..watch(verifiedTokensProvider) ..watch(DexTokensProviders.tokensFromAccount) ..watch(farmLockFormFarmLockProvider) - ..watch( - aedappfm.ArchethicOracleUCOProviders.archethicOracleUCO, - ) - ..watch(aedappfm.CoinPriceProviders.coinPrices) + // ..watch( + // aedappfm.ArchethicOracleUCOProviders.archethicOracleUCO, + // ) + // ..watch(aedappfm.CoinPriceProviders.coinPrices) ..listen( connectivityStatusProviders, (previous, next) async { @@ -60,17 +60,17 @@ class HomePage extends _$HomePage { } Future startSubscriptions() async { - await ref - .read( - aedappfm.ArchethicOracleUCOProviders.archethicOracleUCO.notifier, - ) - .startSubscription(); - - await ref - .read( - aedappfm.CoinPriceProviders.coinPrices.notifier, - ) - .startTimer(); + // await ref + // .read( + // aedappfm.ArchethicOracleUCOProviders.archethicOracleUCO.notifier, + // ) + // .startSubscription(); + + // await ref + // .read( + // aedappfm.CoinPriceProviders.coinPrices.notifier, + // ) + // .startTimer(); } Future stopSubscriptions() async { diff --git a/lib/ui/views/main/bloc/providers.g.dart b/lib/ui/views/main/bloc/providers.g.dart index 5285c5df8..4257be341 100644 --- a/lib/ui/views/main/bloc/providers.g.dart +++ b/lib/ui/views/main/bloc/providers.g.dart @@ -6,7 +6,7 @@ part of 'providers.dart'; // RiverpodGenerator // ************************************************************************** -String _$homePageHash() => r'b3a7e0d8b8465ba8f13decf492db4b8eeae87ec9'; +String _$homePageHash() => r'048f93f65373efbed56acfe689b166b9f0aeea4d'; /// Eagerly initializes providers (https://riverpod.dev/docs/essentials/eager_initialization). /// diff --git a/lib/ui/views/transfer/bloc/state.freezed.dart b/lib/ui/views/transfer/bloc/state.freezed.dart index f8ce65470..a46c722bd 100644 --- a/lib/ui/views/transfer/bloc/state.freezed.dart +++ b/lib/ui/views/transfer/bloc/state.freezed.dart @@ -795,6 +795,8 @@ abstract class _$$TransferDestinationContactImplCopyWith<$Res> { __$$TransferDestinationContactImplCopyWithImpl<$Res>; @useResult $Res call({@AccountConverter() Account account}); + + $AccountCopyWith<$Res> get account; } /// @nodoc @@ -821,6 +823,16 @@ class __$$TransferDestinationContactImplCopyWithImpl<$Res> as Account, )); } + + /// Create a copy of TransferRecipient + /// with the given fields replaced by the non-null parameter values. + @override + @pragma('vm:prefer-inline') + $AccountCopyWith<$Res> get account { + return $AccountCopyWith<$Res>(_value.account, (value) { + return _then(_value.copyWith(account: value)); + }); + } } /// @nodoc diff --git a/lib/ui/views/transfer/layouts/components/transfer_textfield_address.dart b/lib/ui/views/transfer/layouts/components/transfer_textfield_address.dart index 0e2c57693..048b39048 100644 --- a/lib/ui/views/transfer/layouts/components/transfer_textfield_address.dart +++ b/lib/ui/views/transfer/layouts/components/transfer_textfield_address.dart @@ -217,11 +217,12 @@ class _TransferTextFieldAddressState .read(accountsNotifierProvider.future) .selectedAccount; final filteredAccounts = accounts - ..removeWhere( - (element) => - element.format.toUpperCase() == - accountSelected?.format.toUpperCase(), - ); + .where( + (element) => + element.format.toUpperCase() != + accountSelected?.format.toUpperCase(), + ) + .toList(); final account = await AccountsDialog.selectSingleAccount( context: context, diff --git a/lib/util/keychain_util.dart b/lib/util/keychain_util.dart index 632f46578..9eb47bd1c 100644 --- a/lib/util/keychain_util.dart +++ b/lib/util/keychain_util.dart @@ -166,6 +166,11 @@ mixin KeychainServiceMixin { genesisAddressAccountList.add( uint8ListToHex(genesisAddress), ); + + final isSelected = selectedAccount != null && + selectedAccount.name == name && + serviceType == 'archethicWallet'; + final account = Account( lastLoadingTransactionInputs: DateTime.now().millisecondsSinceEpoch ~/ Duration.millisecondsPerSecond, @@ -175,16 +180,10 @@ mixin KeychainServiceMixin { nativeTokenName: 'UCO', nativeTokenValue: 0, ), - recentTransactions: [], + recentTransactions: const [], serviceType: serviceType, + selected: isSelected, ); - if (selectedAccount != null && - selectedAccount.name == name && - serviceType == 'archethicWallet') { - account.selected = true; - } else { - account.selected = false; - } accounts.add(account); }); @@ -237,7 +236,7 @@ mixin KeychainServiceMixin { } } - accounts[i].balance = accountBalance; + accounts[i] = accounts[i].copyWith(balance: accountBalance); } } From 89169728df21c3ac2c11b4f7fc9bd720bac27652 Mon Sep 17 00:00:00 2001 From: redDwarf03 Date: Tue, 14 Jan 2025 23:43:09 +0100 Subject: [PATCH 6/8] Force blockchainTxVersion to version 3 --- lib/domain/usecases/new_keychain.usecase.dart | 6 +-- .../transaction/archethic_transaction.dart | 10 +--- .../transaction_keychain_builder.dart | 8 +-- .../contracts/archethic_contract.dart | 54 ++----------------- lib/service/app_service.dart | 20 ++++--- lib/util/keychain_util.dart | 4 +- 6 files changed, 25 insertions(+), 77 deletions(-) diff --git a/lib/domain/usecases/new_keychain.usecase.dart b/lib/domain/usecases/new_keychain.usecase.dart index a38436bc0..048e396e4 100644 --- a/lib/domain/usecases/new_keychain.usecase.dart +++ b/lib/domain/usecases/new_keychain.usecase.dart @@ -11,6 +11,8 @@ import 'package:logging/logging.dart'; final _logger = Logger('KeychainUtil'); +const blockchainTxVersion = 3; + class CreateNewAppWalletCase with aedappfm.TransactionMixin { CreateNewAppWalletCase({ required this.sessionNotifier, @@ -46,10 +48,6 @@ class CreateNewAppWalletCase with aedappfm.TransactionMixin { servicesMap[kServiceName] = kDerivationPath; } - final blockchainTxVersion = int.parse( - (await targetApiService.getBlockchainVersion()).version.transaction, - ); - final originPrivateKey = targetApiService.getOriginKey(); /// Create Keychain from keyChain seed and wallet public key to encrypt secret diff --git a/lib/infrastructure/repositories/transaction/archethic_transaction.dart b/lib/infrastructure/repositories/transaction/archethic_transaction.dart index b73ed9c51..f44367102 100644 --- a/lib/infrastructure/repositories/transaction/archethic_transaction.dart +++ b/lib/infrastructure/repositories/transaction/archethic_transaction.dart @@ -15,6 +15,8 @@ import 'package:aewallet/model/blockchain/keychain_secured_infos.dart'; import 'package:aewallet/util/keychain_util.dart'; import 'package:archethic_lib_dart/archethic_lib_dart.dart' as archethic; +const blockchainTxVersion = 3; + class ArchethicTransactionRepository implements TransactionRemoteRepositoryInterface { ArchethicTransactionRepository({ @@ -71,10 +73,6 @@ class ArchethicTransactionRepository final index = indexMap[transfer.genesisAddress] ?? 0; - final blockchainTxVersion = int.parse( - (await apiService.getBlockchainVersion()).version.transaction, - ); - var tokenTransferList = []; var ucoTransferList = []; @@ -134,10 +132,6 @@ class ArchethicTransactionRepository final index = indexMap[token.genesisAddress] ?? 0; - final blockchainTxVersion = int.parse( - (await apiService.getBlockchainVersion()).version.transaction, - ); - return AddTokenTransactionBuilder.build( tokenName: token.name, tokenSymbol: token.symbol, diff --git a/lib/infrastructure/repositories/transaction/transaction_keychain_builder.dart b/lib/infrastructure/repositories/transaction/transaction_keychain_builder.dart index 5e640f4ff..806be85c1 100644 --- a/lib/infrastructure/repositories/transaction/transaction_keychain_builder.dart +++ b/lib/infrastructure/repositories/transaction/transaction_keychain_builder.dart @@ -1,9 +1,13 @@ /// SPDX-License-Identifier: AGPL-3.0-or-later +// ignore_for_file: avoid_redundant_argument_values + import 'dart:convert'; import 'dart:math'; import 'package:archethic_lib_dart/archethic_lib_dart.dart' as archethic; import 'package:flutter/foundation.dart'; +const blockchainTxVersion = 3; + extension KeychainTransactionBuilder on archethic.Transaction { /// Builds a creation of keychain Transaction static Future build({ @@ -26,10 +30,6 @@ extension KeychainTransactionBuilder on archethic.Transaction { ), ); - final blockchainTxVersion = int.parse( - (await apiService.getBlockchainVersion()).version.transaction, - ); - final keychainTransaction = archethic.Transaction( type: 'keychain', version: blockchainTxVersion, diff --git a/lib/modules/aeswap/application/contracts/archethic_contract.dart b/lib/modules/aeswap/application/contracts/archethic_contract.dart index 76f856184..999e7bda4 100644 --- a/lib/modules/aeswap/application/contracts/archethic_contract.dart +++ b/lib/modules/aeswap/application/contracts/archethic_contract.dart @@ -1,4 +1,6 @@ /// SPDX-License-Identifier: AGPL-3.0-or-later +// ignore_for_file: avoid_redundant_argument_values + import 'dart:async'; import 'dart:math'; import 'dart:typed_data'; @@ -13,6 +15,8 @@ import 'package:archethic_dapp_framework_flutter/archethic_dapp_framework_flutte import 'package:archethic_lib_dart/archethic_lib_dart.dart' as archethic; import 'package:decimal/decimal.dart'; +const blockchainTxVersion = 3; + class ArchethicContract with aedappfm.TransactionMixin { const ArchethicContract({ required this.apiService, @@ -99,9 +103,6 @@ class ArchethicContract with aedappfm.TransactionMixin { publicKey: storageNoncePublicKey, ); - final blockchainTxVersion = int.parse( - (await apiService.getBlockchainVersion()).version.transaction, - ); final originPrivateKey = apiService.getOriginKey(); final transactionPool = archethic.Transaction( @@ -135,9 +136,6 @@ class ArchethicContract with aedappfm.TransactionMixin { transactionPool, apiService, ); - final blockchainTxVersion = int.parse( - (await apiService.getBlockchainVersion()).version.transaction, - ); final transactionTransfer = archethic.Transaction( type: 'transfer', @@ -192,10 +190,6 @@ class ArchethicContract with aedappfm.TransactionMixin { final token2minAmount = Decimal.parse('$token2AmountSorted') * slippagePourcent.toDecimal(); - final blockchainTxVersion = int.parse( - (await apiService.getBlockchainVersion()).version.transaction, - ); - final transactionAdd = archethic.Transaction( type: 'transfer', version: blockchainTxVersion, @@ -308,10 +302,6 @@ class ArchethicContract with aedappfm.TransactionMixin { final token2minAmount = Decimal.parse('$token2AmountSorted') * slippagePourcent.toDecimal(); - final blockchainTxVersion = int.parse( - (await apiService.getBlockchainVersion()).version.transaction, - ); - final transactionLiquidity = archethic.Transaction( type: 'transfer', version: blockchainTxVersion, @@ -363,10 +353,6 @@ class ArchethicContract with aedappfm.TransactionMixin { return aedappfm.Result.guard(() async { const burnAddress = '00000000000000000000000000000000000000000000000000000000000000000000'; - final blockchainTxVersion = int.parse( - (await apiService.getBlockchainVersion()).version.transaction, - ); - final transactionLiquidity = archethic.Transaction( type: 'transfer', version: blockchainTxVersion, @@ -423,10 +409,6 @@ class ArchethicContract with aedappfm.TransactionMixin { double outputAmount, ) async { return aedappfm.Result.guard(() async { - final blockchainTxVersion = int.parse( - (await apiService.getBlockchainVersion()).version.transaction, - ); - final minToReceive = (Decimal.parse(outputAmount.toString()) * (Decimal.parse('100') - Decimal.parse(slippage.toString())) / Decimal.parse('100')) @@ -468,10 +450,6 @@ class ArchethicContract with aedappfm.TransactionMixin { double amount, ) async { return aedappfm.Result.guard(() async { - final blockchainTxVersion = int.parse( - (await apiService.getBlockchainVersion()).version.transaction, - ); - final transaction = archethic.Transaction( type: 'transfer', version: blockchainTxVersion, @@ -498,10 +476,6 @@ class ArchethicContract with aedappfm.TransactionMixin { double amount, ) async { return aedappfm.Result.guard(() async { - final blockchainTxVersion = int.parse( - (await apiService.getBlockchainVersion()).version.transaction, - ); - final transaction = archethic.Transaction( type: 'transfer', version: blockchainTxVersion, @@ -525,10 +499,6 @@ class ArchethicContract with aedappfm.TransactionMixin { String level, ) async { return aedappfm.Result.guard(() async { - final blockchainTxVersion = int.parse( - (await apiService.getBlockchainVersion()).version.transaction, - ); - final transaction = archethic.Transaction( type: 'transfer', version: blockchainTxVersion, @@ -566,10 +536,6 @@ class ArchethicContract with aedappfm.TransactionMixin { String level, ) async { return aedappfm.Result.guard(() async { - final blockchainTxVersion = int.parse( - (await apiService.getBlockchainVersion()).version.transaction, - ); - final transaction = archethic.Transaction( type: 'transfer', version: blockchainTxVersion, @@ -597,10 +563,6 @@ class ArchethicContract with aedappfm.TransactionMixin { String farmGenesisAddress, ) async { return aedappfm.Result.guard(() async { - final blockchainTxVersion = int.parse( - (await apiService.getBlockchainVersion()).version.transaction, - ); - final transaction = archethic.Transaction( type: 'transfer', version: blockchainTxVersion, @@ -622,10 +584,6 @@ class ArchethicContract with aedappfm.TransactionMixin { String depositId, ) async { return aedappfm.Result.guard(() async { - final blockchainTxVersion = int.parse( - (await apiService.getBlockchainVersion()).version.transaction, - ); - final transaction = archethic.Transaction( type: 'transfer', version: blockchainTxVersion, @@ -649,10 +607,6 @@ class ArchethicContract with aedappfm.TransactionMixin { String depositId, ) async { return aedappfm.Result.guard(() async { - final blockchainTxVersion = int.parse( - (await apiService.getBlockchainVersion()).version.transaction, - ); - final transaction = archethic.Transaction( type: 'transfer', version: blockchainTxVersion, diff --git a/lib/service/app_service.dart b/lib/service/app_service.dart index 880e2c3fa..b3400b8fe 100644 --- a/lib/service/app_service.dart +++ b/lib/service/app_service.dart @@ -1,5 +1,7 @@ /// SPDX-License-Identifier: AGPL-3.0-or-later +// ignore_for_file: avoid_redundant_argument_values + import 'dart:async'; import 'dart:convert'; import 'dart:math'; @@ -24,6 +26,8 @@ import 'package:flutter/material.dart'; import 'package:intl/intl.dart'; import 'package:logging/logging.dart'; +const blockchainTxVersion = 3; + class AppService { AppService({ required this.apiService, @@ -347,13 +351,16 @@ class AppService { '>> START getRecentTransactions : ${DateTime.now()}', ); + final _localRecentTransactionList = + List.from(localRecentTransactionList); + // get the most recent movement in cache var mostRecentTimestamp = 0; - if (localRecentTransactionList.isNotEmpty) { - localRecentTransactionList.sort( + if (_localRecentTransactionList.isNotEmpty) { + _localRecentTransactionList.sort( (a, b) => b.timestamp!.compareTo(a.timestamp!), ); - mostRecentTimestamp = localRecentTransactionList.first.timestamp ?? 0; + mostRecentTimestamp = _localRecentTransactionList.first.timestamp ?? 0; } var recentTransactions = []; @@ -366,7 +373,7 @@ class AppService { var index = lastIndex[genesisAddress] ?? 0; String addressToSearch; var iterMax = 10; - recentTransactions.addAll(localRecentTransactionList); + recentTransactions.addAll(_localRecentTransactionList); while (index > 0 && iterMax > 0) { addressToSearch = uint8ListToHex( @@ -376,7 +383,7 @@ class AppService { ), ); _logger.info('addressToSearch : $addressToSearch'); - if (localRecentTransactionList.any( + if (_localRecentTransactionList.any( (element) => element.address!.toUpperCase() == addressToSearch.toUpperCase(), )) { @@ -951,9 +958,6 @@ class AppService { ) async { final lastTransactionMap = await apiService.getLastTransaction([address], request: 'chainLength'); - final blockchainTxVersion = int.parse( - (await apiService.getBlockchainVersion()).version.transaction, - ); final transaction = Transaction( type: 'transfer', diff --git a/lib/util/keychain_util.dart b/lib/util/keychain_util.dart index 9eb47bd1c..5d97a8efd 100644 --- a/lib/util/keychain_util.dart +++ b/lib/util/keychain_util.dart @@ -18,6 +18,7 @@ import 'package:archethic_lib_dart/archethic_lib_dart.dart'; import 'package:event_taxi/event_taxi.dart'; import 'package:logging/logging.dart'; +const blockchainTxVersion = 3; mixin KeychainServiceMixin { final kMainDerivation = "m/650'/"; @@ -48,9 +49,6 @@ mixin KeychainServiceMixin { ) async { final _logger = Logger('createKeyChainAccess'); - final blockchainTxVersion = int.parse( - (await apiService.getBlockchainVersion()).version.transaction, - ); final originPrivateKey = apiService.getOriginKey(); /// Create Keychain Access for wallet From c000bca5c86a290bf12edf3f4159052da80d606d Mon Sep 17 00:00:00 2001 From: redDwarf03 Date: Tue, 14 Jan 2025 23:43:29 +0100 Subject: [PATCH 7/8] Fix bugs --- lib/application/account/account_notifier.dart | 34 +++++++++---------- .../account/account_notifier.g.dart | 2 +- lib/application/account/selected_account.dart | 24 +++++++++++++ .../account/selected_account.g.dart | 20 +++++++++++ lib/ui/views/main/bloc/providers.dart | 30 ++++++++-------- lib/ui/views/main/bloc/providers.g.dart | 2 +- .../main/components/menu_widget_wallet.dart | 2 +- .../nft/layouts/components/nft_list.dart | 13 ++----- lib/util/account_formatters.dart | 15 +------- 9 files changed, 81 insertions(+), 61 deletions(-) diff --git a/lib/application/account/account_notifier.dart b/lib/application/account/account_notifier.dart index 1c4363c2f..bfcafe8d2 100644 --- a/lib/application/account/account_notifier.dart +++ b/lib/application/account/account_notifier.dart @@ -2,7 +2,6 @@ import 'dart:async'; -import 'package:aewallet/application/account/selected_account.dart'; import 'package:aewallet/application/app_service.dart'; import 'package:aewallet/application/nft/nft.dart'; import 'package:aewallet/application/refresh_in_progress.dart'; @@ -13,7 +12,6 @@ import 'package:aewallet/model/data/account.dart'; import 'package:aewallet/model/data/account_balance.dart'; import 'package:aewallet/modules/aeswap/application/pool/dex_pool.dart'; import 'package:aewallet/modules/aeswap/application/session/provider.dart'; -import 'package:aewallet/util/account_formatters.dart'; import 'package:archethic_dapp_framework_flutter/archethic_dapp_framework_flutter.dart' as aedappfm; import 'package:archethic_lib_dart/archethic_lib_dart.dart'; @@ -58,17 +56,9 @@ class AccountNotifier extends _$AccountNotifier { Future refreshRecentTransactions() async { await _refresh([ (account) async { - _logger.fine( - 'Start method refreshRecentTransactions for ${account.nameDisplayed}', - ); await updateRecentTransactions(); - _logger.fine( - 'End method refreshRecentTransactions for ${account.nameDisplayed}', - ); }, ]); - - ref.invalidate(selectedAccountRecentTransactionsProvider); } Future refreshFungibleTokens() async { @@ -79,6 +69,14 @@ class AccountNotifier extends _$AccountNotifier { ]); } + Future refreshNFT() async { + await _refresh([ + (account) async { + await updateNFT(); + }, + ]); + } + Future refreshBalance() async { await _refresh([ (account) async { @@ -91,30 +89,23 @@ class AccountNotifier extends _$AccountNotifier { await _refresh( [ (account) async { - _logger.fine('RefreshAll - Start Balance refresh'); await updateBalance(); - _logger.fine('RefreshAll - End Balance refresh'); }, (account) async { - _logger.fine('RefreshAll - Start recent transactions refresh'); await updateRecentTransactions(); - _logger.fine('RefreshAll - End recent transactions refresh'); }, (account) async { - _logger.fine('RefreshAll - Start Fungible Tokens refresh'); await updateFungiblesTokens(); - _logger.fine('RefreshAll - End Fungible Tokens refresh'); }, (account) async { - _logger.fine('RefreshAll - Start NFT refresh'); await updateNFT(); - _logger.fine('RefreshAll - End NFT refresh'); }, ], ); } Future updateBalance() async { + _logger.fine('RefreshAll - Start Balance refresh'); await _update((account) async { var totalUSD = 0.0; @@ -179,9 +170,11 @@ class AccountNotifier extends _$AccountNotifier { return account.copyWith(balance: accountBalance); }); + _logger.fine('RefreshAll - End Balance refresh'); } Future updateFungiblesTokens() async { + _logger.fine('RefreshAll - Start Fungible Tokens refresh'); await _update((account) async { final appService = ref.read(appServiceProvider); final poolsListRaw = @@ -194,9 +187,11 @@ class AccountNotifier extends _$AccountNotifier { ), ); }); + _logger.fine('RefreshAll - End Fungible Tokens refresh'); } Future updateRecentTransactions() async { + _logger.fine('RefreshAll - Start recent transactions refresh'); await _update((account) async { final session = ref.read(sessionNotifierProvider).loggedIn!; final appService = ref.read(appServiceProvider); @@ -212,6 +207,7 @@ class AccountNotifier extends _$AccountNotifier { Duration.millisecondsPerSecond, ); }); + _logger.fine('RefreshAll - End recent transactions refresh'); } Future addCustomTokenAddress(String tokenAddress) async { @@ -254,6 +250,7 @@ class AccountNotifier extends _$AccountNotifier { } Future updateNFT() async { + _logger.fine('RefreshAll - Start NFT refresh'); await _update( (account) async { final session = ref.read(sessionNotifierProvider).loggedIn!; @@ -271,6 +268,7 @@ class AccountNotifier extends _$AccountNotifier { ); }, ); + _logger.fine('RefreshAll - End NFT refresh'); } Future clearRecentTransactionsFromCache() async { diff --git a/lib/application/account/account_notifier.g.dart b/lib/application/account/account_notifier.g.dart index bba848c53..44cb5529c 100644 --- a/lib/application/account/account_notifier.g.dart +++ b/lib/application/account/account_notifier.g.dart @@ -6,7 +6,7 @@ part of 'account_notifier.dart'; // RiverpodGenerator // ************************************************************************** -String _$accountNotifierHash() => r'33410ce13c1065c8a2840153d20ff40456ac07cc'; +String _$accountNotifierHash() => r'de8963b79efec47c784a345e2fda8bed1be89951'; /// Copied from Dart SDK class _SystemHash { diff --git a/lib/application/account/selected_account.dart b/lib/application/account/selected_account.dart index 2b60525cc..3c857a095 100644 --- a/lib/application/account/selected_account.dart +++ b/lib/application/account/selected_account.dart @@ -4,6 +4,7 @@ import 'dart:async'; import 'package:aewallet/application/account/accounts_notifier.dart'; import 'package:aewallet/model/blockchain/recent_transaction.dart'; +import 'package:aewallet/model/data/account_token.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart'; @@ -21,3 +22,26 @@ Future?> selectedAccountRecentTransactions( ) ?.recentTransactions; } + +@riverpod +List selectedAccountNFTFiltered( + Ref ref, +) { + final selectedAccount = ref.watch( + accountsNotifierProvider.select( + (accounts) => accounts.valueOrNull?.selectedAccount, + ), + ); + if (selectedAccount == null) { + return []; + } + + return [ + ...selectedAccount.accountNFT ?? [], + // A collection of NFT has the same address for all the sub NFT, we only want to display one NFT in that case + ...(selectedAccount.accountNFTCollections?.where( + (e) => {}.add(e.tokenInformation?.address ?? ''), + ) ?? + []), + ]; +} diff --git a/lib/application/account/selected_account.g.dart b/lib/application/account/selected_account.g.dart index e07c4068e..4e7f04780 100644 --- a/lib/application/account/selected_account.g.dart +++ b/lib/application/account/selected_account.g.dart @@ -26,5 +26,25 @@ final selectedAccountRecentTransactionsProvider = // ignore: unused_element typedef SelectedAccountRecentTransactionsRef = AutoDisposeFutureProviderRef?>; +String _$selectedAccountNFTFilteredHash() => + r'5bab7f1eab6363f522fe9ee7b4f59dff7bb09acc'; + +/// See also [selectedAccountNFTFiltered]. +@ProviderFor(selectedAccountNFTFiltered) +final selectedAccountNFTFilteredProvider = + AutoDisposeProvider>.internal( + selectedAccountNFTFiltered, + name: r'selectedAccountNFTFilteredProvider', + debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product') + ? null + : _$selectedAccountNFTFilteredHash, + dependencies: null, + allTransitiveDependencies: null, +); + +@Deprecated('Will be removed in 3.0. Use Ref instead') +// ignore: unused_element +typedef SelectedAccountNFTFilteredRef + = AutoDisposeProviderRef>; // ignore_for_file: type=lint // ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package diff --git a/lib/ui/views/main/bloc/providers.dart b/lib/ui/views/main/bloc/providers.dart index 010c0b768..7dfb22368 100644 --- a/lib/ui/views/main/bloc/providers.dart +++ b/lib/ui/views/main/bloc/providers.dart @@ -32,10 +32,10 @@ class HomePage extends _$HomePage { ..watch(verifiedTokensProvider) ..watch(DexTokensProviders.tokensFromAccount) ..watch(farmLockFormFarmLockProvider) - // ..watch( - // aedappfm.ArchethicOracleUCOProviders.archethicOracleUCO, - // ) - // ..watch(aedappfm.CoinPriceProviders.coinPrices) + ..watch( + aedappfm.ArchethicOracleUCOProviders.archethicOracleUCO, + ) + ..watch(aedappfm.CoinPriceProviders.coinPrices) ..listen( connectivityStatusProviders, (previous, next) async { @@ -60,17 +60,17 @@ class HomePage extends _$HomePage { } Future startSubscriptions() async { - // await ref - // .read( - // aedappfm.ArchethicOracleUCOProviders.archethicOracleUCO.notifier, - // ) - // .startSubscription(); - - // await ref - // .read( - // aedappfm.CoinPriceProviders.coinPrices.notifier, - // ) - // .startTimer(); + await ref + .read( + aedappfm.ArchethicOracleUCOProviders.archethicOracleUCO.notifier, + ) + .startSubscription(); + + await ref + .read( + aedappfm.CoinPriceProviders.coinPrices.notifier, + ) + .startTimer(); } Future stopSubscriptions() async { diff --git a/lib/ui/views/main/bloc/providers.g.dart b/lib/ui/views/main/bloc/providers.g.dart index 4257be341..5285c5df8 100644 --- a/lib/ui/views/main/bloc/providers.g.dart +++ b/lib/ui/views/main/bloc/providers.g.dart @@ -6,7 +6,7 @@ part of 'providers.dart'; // RiverpodGenerator // ************************************************************************** -String _$homePageHash() => r'048f93f65373efbed56acfe689b166b9f0aeea4d'; +String _$homePageHash() => r'b3a7e0d8b8465ba8f13decf492db4b8eeae87ec9'; /// Eagerly initializes providers (https://riverpod.dev/docs/essentials/eager_initialization). /// diff --git a/lib/ui/views/main/components/menu_widget_wallet.dart b/lib/ui/views/main/components/menu_widget_wallet.dart index a0959a5d2..8a15ffae7 100644 --- a/lib/ui/views/main/components/menu_widget_wallet.dart +++ b/lib/ui/views/main/components/menu_widget_wallet.dart @@ -132,7 +132,7 @@ class MenuWidgetWallet extends ConsumerWidget { await (await ref .read(accountsNotifierProvider.notifier) .selectedAccountNotifier) - ?.refreshRecentTransactions(); + ?.refreshAll(); }, ) .animate() diff --git a/lib/ui/views/nft/layouts/components/nft_list.dart b/lib/ui/views/nft/layouts/components/nft_list.dart index 6c8b5c417..75f3bfc86 100644 --- a/lib/ui/views/nft/layouts/components/nft_list.dart +++ b/lib/ui/views/nft/layouts/components/nft_list.dart @@ -1,9 +1,8 @@ /// SPDX-License-Identifier: AGPL-3.0-or-later -import 'package:aewallet/application/account/accounts_notifier.dart'; +import 'package:aewallet/application/account/selected_account.dart'; import 'package:aewallet/ui/themes/styles.dart'; import 'package:aewallet/ui/views/nft/layouts/components/nft_list_detail.dart'; import 'package:aewallet/ui/widgets/components/dynamic_height_grid_view.dart'; -import 'package:aewallet/util/account_formatters.dart'; import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/localizations.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; @@ -24,15 +23,7 @@ class _NFTListState extends ConsumerState Widget build(BuildContext context) { super.build(context); - final accountSelected = ref.watch( - accountsNotifierProvider.select( - (accounts) => accounts.valueOrNull?.selectedAccount, - ), - ); - - if (accountSelected == null) return const _EmptyNFTList(); - - final accountTokenList = accountSelected.getAccountNFTFiltered(); + final accountTokenList = ref.watch(selectedAccountNFTFilteredProvider); if (accountTokenList.isEmpty) { return const _EmptyNFTList(); } diff --git a/lib/util/account_formatters.dart b/lib/util/account_formatters.dart index b8c2b9dab..cd0b97442 100644 --- a/lib/util/account_formatters.dart +++ b/lib/util/account_formatters.dart @@ -1,5 +1,4 @@ import 'package:aewallet/model/data/account.dart'; -import 'package:aewallet/model/data/account_token.dart'; extension AccountFormatters on Account { String get format { @@ -10,8 +9,7 @@ extension AccountFormatters on Account { var result = name; if (name.startsWith('archethic-wallet-')) { result = result.replaceFirst('archethic-wallet-', ''); - } - if (name.startsWith('aeweb-')) { + } else if (name.startsWith('aeweb-')) { result = result.replaceFirst('aeweb-', ''); } @@ -19,15 +17,4 @@ extension AccountFormatters on Account { result, ); } - - List getAccountNFTFiltered() { - return [ - ...accountNFT ?? [], - // A collection of NFT has the same address for all the sub NFT, we only want to display one NFT in that case - ...(accountNFTCollections?.where( - (e) => {}.add(e.tokenInformation?.address ?? ''), - ) ?? - []), - ]; - } } From b1eea6b3aa49cc14c0b240580003db48a1812212 Mon Sep 17 00:00:00 2001 From: redDwarf03 Date: Wed, 15 Jan 2025 14:50:51 +0100 Subject: [PATCH 8/8] chore: :zap: Just refresh tx in transactions tab --- lib/service/app_service.dart | 72 +++++-------------- .../main/components/menu_widget_wallet.dart | 16 +++-- lib/ui/views/main/transactions_tab.dart | 9 ++- 3 files changed, 35 insertions(+), 62 deletions(-) diff --git a/lib/service/app_service.dart b/lib/service/app_service.dart index b3400b8fe..32c47f889 100644 --- a/lib/service/app_service.dart +++ b/lib/service/app_service.dart @@ -388,11 +388,6 @@ class AppService { element.address!.toUpperCase() == addressToSearch.toUpperCase(), )) { _logger.info('addressToSearch exists in local -> break'); - recentTransactions = await _buildRecentTransactionFromTransaction( - recentTransactions, - addressToSearch, - mostRecentTimestamp, - ); break; } @@ -452,6 +447,7 @@ class AppService { for (final recentTransaction in recentTransactions) { if (recentTransaction.tokenAddress != null && recentTransaction.tokenAddress!.isNotEmpty && + recentTransaction.tokenInformation == null && recentTransaction.timestamp! >= mostRecentTimestamp) { tokensAddresses.add(recentTransaction.tokenAddress!); } @@ -469,16 +465,19 @@ class AppService { // Get token Information if (recentTransaction.tokenAddress != null && recentTransaction.tokenAddress!.isNotEmpty && + recentTransaction.tokenInformation == null && recentTransaction.timestamp! >= mostRecentTimestamp) { final token = tokensAddressMap[recentTransaction.tokenAddress]; if (token != null) { - recentTransaction.tokenInformation = TokenInformation( - address: token.address, - name: token.name, - supply: fromBigInt(token.supply).toDouble(), - symbol: token.symbol, - type: token.type, - ); + recentTransaction + ..tokenAddress = token.address + ..tokenInformation = TokenInformation( + address: token.address, + name: token.name, + supply: fromBigInt(token.supply).toDouble(), + symbol: token.symbol, + type: token.type, + ); } } @@ -486,7 +485,7 @@ class AppService { switch (recentTransaction.typeTx) { case RecentTransaction.transferInput: if (recentTransaction.from != null) { - if (recentTransaction.timestamp! >= mostRecentTimestamp) { + if (recentTransaction.timestamp! > mostRecentTimestamp) { ownershipsAddresses.add(recentTransaction.from!); } recentTransactionLastAddresses.add(recentTransaction.from!); @@ -494,7 +493,7 @@ class AppService { break; case RecentTransaction.transferOutput: if (recentTransaction.from != null) { - if (recentTransaction.timestamp! >= mostRecentTimestamp) { + if (recentTransaction.timestamp! > mostRecentTimestamp) { ownershipsAddresses.add(recentTransaction.from!); } recentTransactionLastAddresses.add(recentTransaction.from!); @@ -530,7 +529,7 @@ class AppService { switch (recentTransaction.typeTx) { case RecentTransaction.transferInput: if (recentTransaction.from != null && - recentTransaction.timestamp! >= mostRecentTimestamp) { + recentTransaction.timestamp! > mostRecentTimestamp) { recentTransaction = _decryptedSecret( keypair: keychainServiceKeyPair!, ownerships: ownershipsMap[recentTransaction.from!] ?? [], @@ -540,7 +539,7 @@ class AppService { break; case RecentTransaction.transferOutput: if (recentTransaction.address != null && - recentTransaction.timestamp! >= mostRecentTimestamp) { + recentTransaction.timestamp! > mostRecentTimestamp) { recentTransaction = _decryptedSecret( keypair: keychainServiceKeyPair!, ownerships: ownershipsMap[recentTransaction.address!] ?? [], @@ -551,45 +550,6 @@ class AppService { } } - // Get last transactions for all tx and contacts - final lastTransactionAddressesToSearch = [ - ...recentTransactionLastAddresses, - ]; - - final lastAddressesMap = {}; - - final getLastTransactions = await lastTransactionAddressesToSearch - .toSet() - .map( - (lastTransactionAddressToSearch) => Task( - name: - 'GetAccountRecentTransactions - lastTransactionAddressToSearch: $lastTransactionAddressToSearch', - logger: _logger, - action: () => apiService.getLastTransaction( - [lastTransactionAddressToSearch], - request: 'address', - ), - ), - ) - .autoRetry() - .batch(); - for (final getLastTransaction in getLastTransactions) { - lastAddressesMap.addAll(getLastTransaction); - } - - // We complete map with last address not found because no tx in the chain - for (final lastTransactionAddressToSearch - in lastTransactionAddressesToSearch) { - if (lastAddressesMap[lastTransactionAddressToSearch] == null) { - lastAddressesMap[lastTransactionAddressToSearch] = Transaction( - type: '', - data: Transaction.initData(), - address: - Address(address: lastTransactionAddressToSearch.toUpperCase()), - ); - } - } - _logger.info( '>> END getRecentTransactions : ${DateTime.now()}', ); @@ -602,10 +562,10 @@ class AppService { required List ownerships, required RecentTransaction recentTransaction, }) { - recentTransaction.decryptedSecret = List.empty(growable: true); if (ownerships.isEmpty) { return recentTransaction; } + recentTransaction.decryptedSecret = []; for (final ownership in ownerships) { final authorizedPublicKey = ownership.authorizedPublicKeys.firstWhere( (AuthorizedKey authKey) => diff --git a/lib/ui/views/main/components/menu_widget_wallet.dart b/lib/ui/views/main/components/menu_widget_wallet.dart index 8a15ffae7..b4167d871 100644 --- a/lib/ui/views/main/components/menu_widget_wallet.dart +++ b/lib/ui/views/main/components/menu_widget_wallet.dart @@ -20,7 +20,9 @@ import 'package:modal_bottom_sheet/modal_bottom_sheet.dart'; import 'package:url_launcher/url_launcher.dart'; class MenuWidgetWallet extends ConsumerWidget { - const MenuWidgetWallet({super.key}); + const MenuWidgetWallet({super.key, this.refreshFunction}); + + final Function()? refreshFunction; @override Widget build(BuildContext context, WidgetRef ref) { @@ -129,10 +131,14 @@ class MenuWidgetWallet extends ConsumerWidget { return; } - await (await ref - .read(accountsNotifierProvider.notifier) - .selectedAccountNotifier) - ?.refreshAll(); + if (refreshFunction == null) { + await (await ref + .read(accountsNotifierProvider.notifier) + .selectedAccountNotifier) + ?.refreshAll(); + } else { + refreshFunction!(); + } }, ) .animate() diff --git a/lib/ui/views/main/transactions_tab.dart b/lib/ui/views/main/transactions_tab.dart index 31cc0ad81..3450c445a 100644 --- a/lib/ui/views/main/transactions_tab.dart +++ b/lib/ui/views/main/transactions_tab.dart @@ -126,7 +126,14 @@ class _TransactionsList extends ConsumerWidget { const SizedBox( height: 10, ), - const MenuWidgetWallet(), + MenuWidgetWallet( + refreshFunction: () async { + await (await ref + .read(accountsNotifierProvider.notifier) + .selectedAccountNotifier) + ?.refreshRecentTransactions(); + }, + ), if (recentTransactions.isEmpty) Padding( padding: const EdgeInsets.only(top: 20),