From 9acbf861252b0f45c988ffae58d0e34ba0c4feed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damian=20Moli=C5=84ski?= <47773413+damian-molinski@users.noreply.github.com> Date: Tue, 15 Oct 2024 12:03:24 +0200 Subject: [PATCH] refactor(cat-voices): user and wallet model (#999) * refactor: introduce profile and walletHeader, walletMeta classes to avoid working directly with CardanoWallet * chore: delete DummyCardanoWallet * chore: cleanup wrong references * fix: updating wallets list * feat: delayed progress bar * refactor: rename wallet meta class * chore: more profile fields above constructor * refactor: Use shorter WalletInfo class name * Update catalyst_voices/packages/catalyst_voices_blocs/lib/src/registration/cubits/wallet_link_cubit.dart Co-authored-by: Dominik Toton <166132265+dtscalac@users.noreply.github.com> --------- Co-authored-by: Dominik Toton <166132265+dtscalac@users.noreply.github.com> --- .../account_completed_panel.dart | 9 ++-- .../stage/rbac_transaction_panel.dart | 13 ++--- .../stage/select_wallet_panel.dart | 18 ++++--- .../stage/wallet_details_panel.dart | 4 +- .../app_bar/session/session_state_header.dart | 2 +- .../registration/cubits/recover_cubit.dart | 12 ++--- .../cubits/wallet_link_cubit.dart | 54 +++++++++++++++---- .../src/registration/registration_cubit.dart | 4 +- .../state_data/wallet_link_state_data.dart | 17 +++--- .../lib/src/session/session_bloc.dart | 21 +++++++- .../catalyst_voices_localizations.dart | 6 +++ .../catalyst_voices_localizations_en.dart | 3 ++ .../catalyst_voices_localizations_es.dart | 3 ++ .../lib/l10n/intl_en.arb | 4 ++ .../lib/src/catalyst_voices_models.dart | 6 ++- .../src/{account => user}/account_role.dart | 0 .../lib/src/user/profile.dart | 18 +++++++ .../lib/src/user/user.dart | 27 ++++++---- .../lib/src/wallet/dummy_cardano_wallet.dart | 27 ---------- .../lib/src/wallet/wallet_info.dart | 29 ++++++++++ .../lib/src/wallet/wallet_metadata.dart | 25 +++++++++ .../registration/registration_service.dart | 23 +++----- .../localized_registration_exception.dart | 9 ++++ 23 files changed, 232 insertions(+), 102 deletions(-) rename catalyst_voices/packages/catalyst_voices_models/lib/src/{account => user}/account_role.dart (100%) create mode 100644 catalyst_voices/packages/catalyst_voices_models/lib/src/user/profile.dart delete mode 100644 catalyst_voices/packages/catalyst_voices_models/lib/src/wallet/dummy_cardano_wallet.dart create mode 100644 catalyst_voices/packages/catalyst_voices_models/lib/src/wallet/wallet_info.dart create mode 100644 catalyst_voices/packages/catalyst_voices_models/lib/src/wallet/wallet_metadata.dart diff --git a/catalyst_voices/lib/pages/registration/account_completed/account_completed_panel.dart b/catalyst_voices/lib/pages/registration/account_completed/account_completed_panel.dart index 1adb82fcdca..3eedcf4e5cf 100644 --- a/catalyst_voices/lib/pages/registration/account_completed/account_completed_panel.dart +++ b/catalyst_voices/lib/pages/registration/account_completed/account_completed_panel.dart @@ -37,10 +37,11 @@ class AccountCompletedPanel extends StatelessWidget { info: context.l10n.registrationCompletedKeychainInfo, ), BlocSelector( - selector: (state) => - state.walletLinkStateData.selectedWallet?.wallet.name - .capitalize() ?? - '', + selector: (state) { + final wallet = state.walletLinkStateData.selectedWallet; + final name = wallet?.metadata.name ?? ''; + return name.capitalize(); + }, builder: (context, walletName) { return _SummaryItem( image: VoicesAssets.images.registrationSummaryWallet, diff --git a/catalyst_voices/lib/pages/registration/wallet_link/stage/rbac_transaction_panel.dart b/catalyst_voices/lib/pages/registration/wallet_link/stage/rbac_transaction_panel.dart index 3faca7eb896..4573321ba65 100644 --- a/catalyst_voices/lib/pages/registration/wallet_link/stage/rbac_transaction_panel.dart +++ b/catalyst_voices/lib/pages/registration/wallet_link/stage/rbac_transaction_panel.dart @@ -100,7 +100,7 @@ class _BlocSummary extends StatelessWidget { RegistrationState, ({ Set roles, - CardanoWalletDetails selectedWallet, + WalletInfo selectedWallet, Coin transactionFee, })?>( selector: (state) { @@ -125,7 +125,7 @@ class _BlocSummary extends StatelessWidget { return _Summary( roles: state.roles, - walletDetails: state.selectedWallet, + walletInfo: state.selectedWallet, transactionFee: state.transactionFee, ); }, @@ -135,17 +135,19 @@ class _BlocSummary extends StatelessWidget { class _Summary extends StatelessWidget { final Set roles; - final CardanoWalletDetails walletDetails; + final WalletInfo walletInfo; final Coin transactionFee; const _Summary({ required this.roles, - required this.walletDetails, + required this.walletInfo, required this.transactionFee, }); @override Widget build(BuildContext context) { + final name = walletInfo.metadata.name; + return Container( padding: const EdgeInsets.all(12), decoration: BoxDecoration( @@ -164,8 +166,7 @@ class _Summary extends StatelessWidget { ), const SizedBox(height: 12), Text( - context.l10n - .walletLinkTransactionLinkItem(walletDetails.wallet.name), + context.l10n.walletLinkTransactionLinkItem(name), style: Theme.of(context).textTheme.bodySmall, ), for (final role in roles) ...[ diff --git a/catalyst_voices/lib/pages/registration/wallet_link/stage/select_wallet_panel.dart b/catalyst_voices/lib/pages/registration/wallet_link/stage/select_wallet_panel.dart index 13a1c01781d..3e642bcefe0 100644 --- a/catalyst_voices/lib/pages/registration/wallet_link/stage/select_wallet_panel.dart +++ b/catalyst_voices/lib/pages/registration/wallet_link/stage/select_wallet_panel.dart @@ -1,18 +1,18 @@ import 'dart:async'; -import 'package:catalyst_cardano/catalyst_cardano.dart'; import 'package:catalyst_voices/pages/registration/wallet_link/bloc_wallet_link_builder.dart'; import 'package:catalyst_voices/pages/registration/widgets/registration_stage_message.dart'; import 'package:catalyst_voices/widgets/widgets.dart'; import 'package:catalyst_voices_assets/catalyst_voices_assets.dart'; import 'package:catalyst_voices_blocs/catalyst_voices_blocs.dart'; import 'package:catalyst_voices_localization/catalyst_voices_localization.dart'; +import 'package:catalyst_voices_models/catalyst_voices_models.dart'; import 'package:catalyst_voices_shared/catalyst_voices_shared.dart'; import 'package:flutter/material.dart'; import 'package:result_type/result_type.dart'; /// Callback called when a [wallet] is selected. -typedef _OnSelectWallet = Future Function(CardanoWallet wallet); +typedef _OnSelectWallet = Future Function(WalletMetadata wallet); class SelectWalletPanel extends StatefulWidget { const SelectWalletPanel({ @@ -67,7 +67,7 @@ class _SelectWalletPanelState extends State { unawaited(RegistrationCubit.of(context).walletLink.refreshWallets()); } - Future _onSelectWallet(CardanoWallet wallet) async { + Future _onSelectWallet(WalletMetadata wallet) async { final registration = RegistrationCubit.of(context); final success = await registration.walletLink.selectWallet(wallet); @@ -88,7 +88,7 @@ class _BlocWallets extends StatelessWidget { @override Widget build(BuildContext context) { - return BlocWalletLinkBuilder, Exception>?>( + return BlocWalletLinkBuilder, Exception>?>( selector: (state) => state.wallets, builder: (context, state) { return _Wallets( @@ -102,7 +102,7 @@ class _BlocWallets extends StatelessWidget { } class _Wallets extends StatelessWidget { - final Result, Exception>? result; + final Result, Exception>? result; final _OnSelectWallet onSelectWallet; final VoidCallback onRefreshTap; @@ -119,13 +119,15 @@ class _Wallets extends StatelessWidget { ? _WalletsList(wallets: value, onSelectWallet: onSelectWallet) : _WalletsEmpty(onRetry: onRefreshTap), Failure() => _WalletsError(onRetry: onRefreshTap), - _ => const Center(child: VoicesCircularProgressIndicator()), + _ => const Center( + child: DelayedWidget(child: VoicesCircularProgressIndicator()), + ), }; } } class _WalletsList extends StatelessWidget { - final List wallets; + final List wallets; final _OnSelectWallet onSelectWallet; const _WalletsList({ @@ -148,7 +150,7 @@ class _WalletsList extends StatelessWidget { } class _WalletTile extends StatefulWidget { - final CardanoWallet wallet; + final WalletMetadata wallet; final _OnSelectWallet onSelectWallet; const _WalletTile({ diff --git a/catalyst_voices/lib/pages/registration/wallet_link/stage/wallet_details_panel.dart b/catalyst_voices/lib/pages/registration/wallet_link/stage/wallet_details_panel.dart index f3fea295335..0f665f30e58 100644 --- a/catalyst_voices/lib/pages/registration/wallet_link/stage/wallet_details_panel.dart +++ b/catalyst_voices/lib/pages/registration/wallet_link/stage/wallet_details_panel.dart @@ -61,7 +61,7 @@ class _BlocWalletDetailsText extends StatelessWidget { @override Widget build(BuildContext context) { return BlocWalletLinkBuilder( - selector: (state) => state.selectedWallet?.wallet.name, + selector: (state) => state.selectedWallet?.metadata.name, builder: (context, state) { return Text( context.l10n.walletLinkWalletDetailsContent(state ?? ''), @@ -101,7 +101,7 @@ class _BlocNavigation extends StatelessWidget { @override Widget build(BuildContext context) { return BlocWalletLinkBuilder( - selector: (state) => state.selectedWallet?.hasEnoughBalance ?? false, + selector: (state) => state.hasEnoughBalance, builder: (context, state) { if (state) { return const RegistrationBackNextNavigation(); diff --git a/catalyst_voices/lib/widgets/app_bar/session/session_state_header.dart b/catalyst_voices/lib/widgets/app_bar/session/session_state_header.dart index 79eb2e0fb08..79fad5e330e 100644 --- a/catalyst_voices/lib/widgets/app_bar/session/session_state_header.dart +++ b/catalyst_voices/lib/widgets/app_bar/session/session_state_header.dart @@ -20,7 +20,7 @@ class SessionStateHeader extends StatelessWidget { VisitorSessionState() => const _VisitorButton(), GuestSessionState() => const _GuestButton(), ActiveUserSessionState(:final user) => AccountPopup( - avatarLetter: user.acronym ?? 'A', + avatarLetter: user.acronym, onLockAccountTap: () => debugPrint('Lock account'), onProfileKeychainTap: () => unawaited( const AccountRoute().push(context), diff --git a/catalyst_voices/packages/catalyst_voices_blocs/lib/src/registration/cubits/recover_cubit.dart b/catalyst_voices/packages/catalyst_voices_blocs/lib/src/registration/cubits/recover_cubit.dart index c961b7e75eb..aef5d5c5c14 100644 --- a/catalyst_voices/packages/catalyst_voices_blocs/lib/src/registration/cubits/recover_cubit.dart +++ b/catalyst_voices/packages/catalyst_voices_blocs/lib/src/registration/cubits/recover_cubit.dart @@ -76,18 +76,18 @@ final class RecoverCubit extends Cubit return; } - final walletDetails = + final walletHeader = await _registrationService.recoverCardanoWalletDetails(seedPhrase); final accountDetails = AccountSummaryData( walletConnection: WalletConnectionData( - name: walletDetails.wallet.name, - icon: walletDetails.wallet.icon, + name: walletHeader.metadata.name, + icon: walletHeader.metadata.icon, ), walletSummary: WalletSummaryData( - balance: CryptocurrencyFormatter.formatAmount(walletDetails.balance), - address: WalletAddressFormatter.formatShort(walletDetails.address), - clipboardAddress: walletDetails.address.toBech32(), + balance: CryptocurrencyFormatter.formatAmount(walletHeader.balance), + address: WalletAddressFormatter.formatShort(walletHeader.address), + clipboardAddress: walletHeader.address.toBech32(), showLowBalance: false, ), ); diff --git a/catalyst_voices/packages/catalyst_voices_blocs/lib/src/registration/cubits/wallet_link_cubit.dart b/catalyst_voices/packages/catalyst_voices_blocs/lib/src/registration/cubits/wallet_link_cubit.dart index 1d65da571f0..f5862d4200c 100644 --- a/catalyst_voices/packages/catalyst_voices_blocs/lib/src/registration/cubits/wallet_link_cubit.dart +++ b/catalyst_voices/packages/catalyst_voices_blocs/lib/src/registration/cubits/wallet_link_cubit.dart @@ -6,6 +6,7 @@ import 'package:catalyst_voices_models/catalyst_voices_models.dart'; import 'package:catalyst_voices_services/catalyst_voices_services.dart'; import 'package:catalyst_voices_shared/catalyst_voices_shared.dart'; import 'package:catalyst_voices_view_models/catalyst_voices_view_models.dart'; +import 'package:collection/collection.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:result_type/result_type.dart'; @@ -14,7 +15,7 @@ final _logger = Logger('WalletLinkCubit'); abstract interface class WalletLinkManager { Future refreshWallets(); - Future selectWallet(CardanoWallet wallet); + Future selectWallet(WalletMetadata meta); void selectRoles(Set roles); } @@ -24,45 +25,72 @@ final class WalletLinkCubit extends Cubit implements WalletLinkManager { final RegistrationService registrationService; + final _wallets = []; + CardanoWallet? _selectedWallet; + WalletLinkCubit({required this.registrationService}) : super(const WalletLinkStateData()); + CardanoWallet? get selectedWallet => _selectedWallet; + @override Future refreshWallets() async { try { + _wallets.clear(); emit(state.copyWith(wallets: const Optional.empty())); final wallets = await registrationService.getCardanoWallets().withMinimumDelay(); - emit(state.copyWith(wallets: Optional(Success(wallets)))); + _wallets + ..clear() + ..addAll(wallets); + + final walletsMetaList = + wallets.map(WalletMetadata.fromCardanoWallet).toList(); + + emit(state.copyWith(wallets: Optional(Success(walletsMetaList)))); } on Exception catch (error, stackTrace) { _logger.severe('refreshWallets', error, stackTrace); + + _wallets.clear(); + emit(state.copyWith(wallets: Optional(Failure(error)))); } } @override - Future selectWallet(CardanoWallet wallet) async { + Future selectWallet(WalletMetadata meta) async { try { - final walletDetails = + final wallet = + _wallets.firstWhereOrNull((wallet) => wallet.name == meta.name); + + if (wallet == null) { + throw const LocalizedRegistrationWalletNotFoundException(); + } + + _selectedWallet = wallet; + + final walletHeader = await registrationService.getCardanoWalletDetails(wallet); final walletConnection = WalletConnectionData( - name: wallet.name, - icon: wallet.icon, + name: walletHeader.metadata.name, + icon: walletHeader.metadata.icon, isConnected: true, ); final walletSummary = WalletSummaryData( - balance: CryptocurrencyFormatter.formatAmount(walletDetails.balance), - address: WalletAddressFormatter.formatShort(walletDetails.address), - clipboardAddress: walletDetails.address.toBech32(), + balance: CryptocurrencyFormatter.formatAmount(walletHeader.balance), + address: WalletAddressFormatter.formatShort(walletHeader.address), + clipboardAddress: walletHeader.address.toBech32(), showLowBalance: - walletDetails.balance < CardanoWalletDetails.minAdaForRegistration, + walletHeader.balance < CardanoWalletDetails.minAdaForRegistration, ); final newState = state.copyWith( - selectedWallet: Optional(walletDetails), + selectedWallet: Optional(walletHeader), + hasEnoughBalance: + walletHeader.balance >= CardanoWalletDetails.minAdaForRegistration, walletConnection: Optional(walletConnection), walletSummary: Optional(walletSummary), ); @@ -73,6 +101,8 @@ final class WalletLinkCubit extends Cubit } catch (error, stackTrace) { _logger.severe('selectWallet', error, stackTrace); + _selectedWallet = null; + emit( state.copyWith( selectedWallet: const Optional.empty(), @@ -81,6 +111,8 @@ final class WalletLinkCubit extends Cubit ), ); + emitError(error); + return false; } } diff --git a/catalyst_voices/packages/catalyst_voices_blocs/lib/src/registration/registration_cubit.dart b/catalyst_voices/packages/catalyst_voices_blocs/lib/src/registration/registration_cubit.dart index 1fc3beb6053..2e286b750e8 100644 --- a/catalyst_voices/packages/catalyst_voices_blocs/lib/src/registration/registration_cubit.dart +++ b/catalyst_voices/packages/catalyst_voices_blocs/lib/src/registration/registration_cubit.dart @@ -129,7 +129,7 @@ final class RegistrationCubit extends Cubit ); final unsignedTx = await registrationService.prepareRegistration( - wallet: _walletLinkState.selectedCardanoWallet!, + wallet: _walletLinkCubit.selectedWallet!, // TODO(dtscalac): inject the networkId networkId: NetworkId.testnet, seedPhrase: _keychainState.seedPhrase!, @@ -163,7 +163,7 @@ final class RegistrationCubit extends Cubit ); final signedTx = await registrationService.submitRegistration( - wallet: _walletLinkState.selectedCardanoWallet!, + wallet: _walletLinkCubit.selectedWallet!, unsignedTx: _registrationState.unsignedTx!.success, ); diff --git a/catalyst_voices/packages/catalyst_voices_blocs/lib/src/registration/state_data/wallet_link_state_data.dart b/catalyst_voices/packages/catalyst_voices_blocs/lib/src/registration/state_data/wallet_link_state_data.dart index 4789d69544c..c29666059c6 100644 --- a/catalyst_voices/packages/catalyst_voices_blocs/lib/src/registration/state_data/wallet_link_state_data.dart +++ b/catalyst_voices/packages/catalyst_voices_blocs/lib/src/registration/state_data/wallet_link_state_data.dart @@ -1,4 +1,3 @@ -import 'package:catalyst_cardano/catalyst_cardano.dart'; import 'package:catalyst_cardano_serialization/catalyst_cardano_serialization.dart'; import 'package:catalyst_voices_models/catalyst_voices_models.dart'; import 'package:catalyst_voices_view_models/catalyst_voices_view_models.dart'; @@ -6,8 +5,9 @@ import 'package:equatable/equatable.dart'; import 'package:result_type/result_type.dart'; final class WalletLinkStateData extends Equatable { - final Result, Exception>? wallets; - final CardanoWalletDetails? selectedWallet; + final Result, Exception>? wallets; + final WalletInfo? selectedWallet; + final bool hasEnoughBalance; final WalletConnectionData? walletConnection; final WalletSummaryData? walletSummary; final Set? selectedRoles; @@ -15,6 +15,7 @@ final class WalletLinkStateData extends Equatable { const WalletLinkStateData({ this.wallets, this.selectedWallet, + this.hasEnoughBalance = false, this.walletConnection, this.walletSummary, this.selectedRoles, @@ -26,12 +27,10 @@ final class WalletLinkStateData extends Equatable { /// Returns the default roles every account will have. Set get defaultRoles => {AccountRole.voter}; - /// Returns the selected & enabled cardano wallet. - CardanoWallet? get selectedCardanoWallet => selectedWallet?.wallet; - WalletLinkStateData copyWith({ - Optional, Exception>>? wallets, - Optional? selectedWallet, + Optional, Exception>>? wallets, + Optional? selectedWallet, + bool? hasEnoughBalance, Optional? walletConnection, Optional? walletSummary, Optional>? selectedRoles, @@ -39,6 +38,7 @@ final class WalletLinkStateData extends Equatable { return WalletLinkStateData( wallets: wallets.dataOr(this.wallets), selectedWallet: selectedWallet.dataOr(this.selectedWallet), + hasEnoughBalance: hasEnoughBalance ?? this.hasEnoughBalance, walletConnection: walletConnection.dataOr(this.walletConnection), walletSummary: walletSummary.dataOr(this.walletSummary), selectedRoles: selectedRoles.dataOr(this.selectedRoles), @@ -49,6 +49,7 @@ final class WalletLinkStateData extends Equatable { List get props => [ wallets, selectedWallet, + hasEnoughBalance, walletConnection, walletSummary, selectedRoles, diff --git a/catalyst_voices/packages/catalyst_voices_blocs/lib/src/session/session_bloc.dart b/catalyst_voices/packages/catalyst_voices_blocs/lib/src/session/session_bloc.dart index 03aa41fde89..a5434019ad5 100644 --- a/catalyst_voices/packages/catalyst_voices_blocs/lib/src/session/session_bloc.dart +++ b/catalyst_voices/packages/catalyst_voices_blocs/lib/src/session/session_bloc.dart @@ -1,3 +1,4 @@ +import 'package:catalyst_cardano_serialization/catalyst_cardano_serialization.dart'; import 'package:catalyst_voices_blocs/src/session/session_event.dart'; import 'package:catalyst_voices_blocs/src/session/session_state.dart'; import 'package:catalyst_voices_models/catalyst_voices_models.dart'; @@ -88,7 +89,25 @@ final class SessionBloc extends Bloc { } /// Temporary implementation for testing purposes. - User get _dummyUser => const User(name: 'Account'); + User get _dummyUser { + /* cSpell:disable */ + return User( + profile: Profile( + walletInfo: WalletInfo( + metadata: const WalletMetadata( + name: 'Dummy Wallet', + icon: null, + ), + balance: Coin.fromAda(10), + address: ShelleyAddress.fromBech32( + 'addr_test1vzpwq95z3xyum8vqndgdd' + '9mdnmafh3djcxnc6jemlgdmswcve6tkw', + ), + ), + ), + ); + /* cSpell:enable */ + } /// Temporary implementation for testing purposes. SeedPhrase get _dummySeedPhrase => SeedPhrase.fromMnemonic( diff --git a/catalyst_voices/packages/catalyst_voices_localization/lib/generated/catalyst_voices_localizations.dart b/catalyst_voices/packages/catalyst_voices_localization/lib/generated/catalyst_voices_localizations.dart index c3c0f2037aa..b4724328399 100644 --- a/catalyst_voices/packages/catalyst_voices_localization/lib/generated/catalyst_voices_localizations.dart +++ b/catalyst_voices/packages/catalyst_voices_localization/lib/generated/catalyst_voices_localizations.dart @@ -844,6 +844,12 @@ abstract class VoicesLocalizations { /// **'Password was not found. Make sure valid password was created.'** String get registrationUnlockPasswordNotFound; + /// Error message shown when connect wallet but matching was not found + /// + /// In en, this message translates to: + /// **'Wallet not found'** + String get registrationWalletNotFound; + /// A title on the role chooser screen in registration. /// /// In en, this message translates to: diff --git a/catalyst_voices/packages/catalyst_voices_localization/lib/generated/catalyst_voices_localizations_en.dart b/catalyst_voices/packages/catalyst_voices_localization/lib/generated/catalyst_voices_localizations_en.dart index b3457c1ea51..bc75761b328 100644 --- a/catalyst_voices/packages/catalyst_voices_localization/lib/generated/catalyst_voices_localizations_en.dart +++ b/catalyst_voices/packages/catalyst_voices_localization/lib/generated/catalyst_voices_localizations_en.dart @@ -442,6 +442,9 @@ class VoicesLocalizationsEn extends VoicesLocalizations { @override String get registrationUnlockPasswordNotFound => 'Password was not found. Make sure valid password was created.'; + @override + String get registrationWalletNotFound => 'Wallet not found'; + @override String get walletLinkRoleChooserTitle => 'How do you want to participate in Catalyst?'; diff --git a/catalyst_voices/packages/catalyst_voices_localization/lib/generated/catalyst_voices_localizations_es.dart b/catalyst_voices/packages/catalyst_voices_localization/lib/generated/catalyst_voices_localizations_es.dart index 9c23eb5e9e6..edbee7bc558 100644 --- a/catalyst_voices/packages/catalyst_voices_localization/lib/generated/catalyst_voices_localizations_es.dart +++ b/catalyst_voices/packages/catalyst_voices_localization/lib/generated/catalyst_voices_localizations_es.dart @@ -442,6 +442,9 @@ class VoicesLocalizationsEs extends VoicesLocalizations { @override String get registrationUnlockPasswordNotFound => 'Password was not found. Make sure valid password was created.'; + @override + String get registrationWalletNotFound => 'Wallet not found'; + @override String get walletLinkRoleChooserTitle => 'How do you want to participate in Catalyst?'; diff --git a/catalyst_voices/packages/catalyst_voices_localization/lib/l10n/intl_en.arb b/catalyst_voices/packages/catalyst_voices_localization/lib/l10n/intl_en.arb index 9d49d04bbc9..e1c28f58de4 100644 --- a/catalyst_voices/packages/catalyst_voices_localization/lib/l10n/intl_en.arb +++ b/catalyst_voices/packages/catalyst_voices_localization/lib/l10n/intl_en.arb @@ -561,6 +561,10 @@ "@registrationUnlockPasswordNotFound": { "description": "Error message shown when attempting to register or recover account but password was not found" }, + "registrationWalletNotFound": "Wallet not found", + "@registrationWalletNotFound": { + "description": "Error message shown when connect wallet but matching was not found" + }, "walletLinkRoleChooserTitle": "How do you want to participate in Catalyst?", "@walletLinkRoleChooserTitle": { "description": "A title on the role chooser screen in registration." diff --git a/catalyst_voices/packages/catalyst_voices_models/lib/src/catalyst_voices_models.dart b/catalyst_voices/packages/catalyst_voices_models/lib/src/catalyst_voices_models.dart index 54d8223ba1c..870f119081c 100644 --- a/catalyst_voices/packages/catalyst_voices_models/lib/src/catalyst_voices_models.dart +++ b/catalyst_voices/packages/catalyst_voices_models/lib/src/catalyst_voices_models.dart @@ -1,6 +1,5 @@ library catalyst_voices_models; -export 'account/account_role.dart'; export 'auth/authentication_status.dart'; export 'auth/password_strength.dart'; export 'document/document_json.dart'; @@ -17,9 +16,12 @@ export 'space.dart'; export 'treasury/treasury_campaign_builder.dart'; export 'treasury/treasury_campaign_segment.dart'; export 'treasury/treasury_campaign_segment_step.dart'; +export 'user/account_role.dart'; +export 'user/profile.dart'; export 'user/user.dart'; export 'wallet/cardano_wallet_details.dart'; -export 'wallet/dummy_cardano_wallet.dart'; +export 'wallet/wallet_info.dart'; +export 'wallet/wallet_metadata.dart'; export 'workspace/workspace_proposal_navigation.dart'; export 'workspace/workspace_proposal_segment.dart'; export 'workspace/workspace_proposal_segment_step.dart'; diff --git a/catalyst_voices/packages/catalyst_voices_models/lib/src/account/account_role.dart b/catalyst_voices/packages/catalyst_voices_models/lib/src/user/account_role.dart similarity index 100% rename from catalyst_voices/packages/catalyst_voices_models/lib/src/account/account_role.dart rename to catalyst_voices/packages/catalyst_voices_models/lib/src/user/account_role.dart diff --git a/catalyst_voices/packages/catalyst_voices_models/lib/src/user/profile.dart b/catalyst_voices/packages/catalyst_voices_models/lib/src/user/profile.dart new file mode 100644 index 00000000000..74b8e08cb1e --- /dev/null +++ b/catalyst_voices/packages/catalyst_voices_models/lib/src/user/profile.dart @@ -0,0 +1,18 @@ +import 'package:catalyst_voices_models/src/user/user.dart'; +import 'package:catalyst_voices_models/src/wallet/wallet_info.dart'; +import 'package:equatable/equatable.dart'; + +/// Defines singular profile used by [User]. One [User] may have multiple +/// [Profile]'s. +final class Profile extends Equatable { + final WalletInfo walletInfo; + + const Profile({ + required this.walletInfo, + }); + + @override + List get props => [ + walletInfo, + ]; +} diff --git a/catalyst_voices/packages/catalyst_voices_models/lib/src/user/user.dart b/catalyst_voices/packages/catalyst_voices_models/lib/src/user/user.dart index e92c2025bed..d6200a6fe9e 100644 --- a/catalyst_voices/packages/catalyst_voices_models/lib/src/user/user.dart +++ b/catalyst_voices/packages/catalyst_voices_models/lib/src/user/user.dart @@ -1,17 +1,26 @@ +import 'package:catalyst_voices_models/src/user/profile.dart'; import 'package:equatable/equatable.dart'; -/// Defines the profile of the app user. +/// Defines user or the app. final class User extends Equatable { - final String name; + final List profiles; - const User({ - required this.name, - }); + User({ + required Profile profile, + }) : profiles = [profile]; - String? get acronym { - return name.isNotEmpty ? name.substring(0, 1).toUpperCase() : null; - } + /// Just syntax sugar for [activeProfile]. + Profile get profile => activeProfile; + + // Note. At the moment we support only single profile Users but later + // this may change and this implementation with it. + Profile get activeProfile => profiles.single; + + // Note. this is not defined yet what we will show here. + String get acronym => 'A'; @override - List get props => [name]; + List get props => [ + profiles, + ]; } diff --git a/catalyst_voices/packages/catalyst_voices_models/lib/src/wallet/dummy_cardano_wallet.dart b/catalyst_voices/packages/catalyst_voices_models/lib/src/wallet/dummy_cardano_wallet.dart deleted file mode 100644 index 3463f1d51c6..00000000000 --- a/catalyst_voices/packages/catalyst_voices_models/lib/src/wallet/dummy_cardano_wallet.dart +++ /dev/null @@ -1,27 +0,0 @@ -import 'package:catalyst_cardano/catalyst_cardano.dart'; - -final class DummyCardanoWallet implements CardanoWallet { - @override - final String name; - @override - final String icon; - @override - final String? apiVersion; - @override - final List supportedExtensions; - - DummyCardanoWallet({ - required this.name, - required this.icon, - this.apiVersion, - this.supportedExtensions = const [], - }); - - @override - Future isEnabled() => Future(() => true); - - @override - Future enable({List? extensions}) { - throw UnimplementedError(); - } -} diff --git a/catalyst_voices/packages/catalyst_voices_models/lib/src/wallet/wallet_info.dart b/catalyst_voices/packages/catalyst_voices_models/lib/src/wallet/wallet_info.dart new file mode 100644 index 00000000000..a488c9f24d4 --- /dev/null +++ b/catalyst_voices/packages/catalyst_voices_models/lib/src/wallet/wallet_info.dart @@ -0,0 +1,29 @@ +import 'package:catalyst_cardano/catalyst_cardano.dart'; +import 'package:catalyst_cardano_serialization/catalyst_cardano_serialization.dart'; +import 'package:catalyst_voices_models/src/wallet/wallet_metadata.dart'; +import 'package:equatable/equatable.dart'; + +/// This class represents basic information's about Wallet, +/// such as [CardanoWallet], but without specifying way to take action like +/// enable. +/// +/// Instance of this class can come from different places like backend +/// or user interacting with wallet extension. +final class WalletInfo extends Equatable { + final WalletMetadata metadata; + final Coin balance; + final ShelleyAddress address; + + const WalletInfo({ + required this.metadata, + required this.balance, + required this.address, + }); + + @override + List get props => [ + metadata, + balance.value, + address, + ]; +} diff --git a/catalyst_voices/packages/catalyst_voices_models/lib/src/wallet/wallet_metadata.dart b/catalyst_voices/packages/catalyst_voices_models/lib/src/wallet/wallet_metadata.dart new file mode 100644 index 00000000000..e31455a431c --- /dev/null +++ b/catalyst_voices/packages/catalyst_voices_models/lib/src/wallet/wallet_metadata.dart @@ -0,0 +1,25 @@ +import 'package:catalyst_cardano/catalyst_cardano.dart'; +import 'package:equatable/equatable.dart'; + +/// Basic information about wallet without any details. +final class WalletMetadata extends Equatable { + final String name; + final String? icon; + + const WalletMetadata({ + required this.name, + this.icon, + }); + + WalletMetadata.fromCardanoWallet(CardanoWallet wallet) + : this( + name: wallet.name, + icon: wallet.icon, + ); + + @override + List get props => [ + name, + icon, + ]; +} diff --git a/catalyst_voices/packages/catalyst_voices_services/lib/src/registration/registration_service.dart b/catalyst_voices/packages/catalyst_voices_services/lib/src/registration/registration_service.dart index 94b88704af2..ac4119f9253 100644 --- a/catalyst_voices/packages/catalyst_voices_services/lib/src/registration/registration_service.dart +++ b/catalyst_voices/packages/catalyst_voices_services/lib/src/registration/registration_service.dart @@ -48,15 +48,15 @@ final class RegistrationService { /// /// This will trigger a permission popup from the wallet extension. /// Afterwards the user must grant a permission inside the wallet extension. - Future getCardanoWalletDetails( + Future getCardanoWalletDetails( CardanoWallet wallet, ) async { final enabledWallet = await wallet.enable(); final balance = await enabledWallet.getBalance(); final address = await enabledWallet.getChangeAddress(); - return CardanoWalletDetails( - wallet: wallet, + return WalletInfo( + metadata: WalletMetadata.fromCardanoWallet(wallet), balance: balance.coin, address: address, ); @@ -66,7 +66,7 @@ final class RegistrationService { // Note. Returned type will be changed because we'll not be able to // get a wallet from backend just from seed phrase. // To be decided what data can we get from backend. - Future recoverCardanoWalletDetails( + Future recoverCardanoWalletDetails( SeedPhrase seedPhrase, ) async { await Future.delayed(const Duration(milliseconds: 200)); @@ -76,17 +76,10 @@ final class RegistrationService { throw const RegistrationUnknownException(); } - final wallet = DummyCardanoWallet( - name: 'Dummy Wallet', - icon: '', - ); - final balance = Coin.fromAda(10); - final address = _testNetAddress; - - return CardanoWalletDetails( - wallet: wallet, - balance: balance, - address: address, + return WalletInfo( + metadata: const WalletMetadata(name: 'Dummy Wallet'), + balance: Coin.fromAda(10), + address: _testNetAddress, ); } diff --git a/catalyst_voices/packages/catalyst_voices_view_models/lib/src/registration/exception/localized_registration_exception.dart b/catalyst_voices/packages/catalyst_voices_view_models/lib/src/registration/exception/localized_registration_exception.dart index 3c070a6953f..d39d048277b 100644 --- a/catalyst_voices/packages/catalyst_voices_view_models/lib/src/registration/exception/localized_registration_exception.dart +++ b/catalyst_voices/packages/catalyst_voices_view_models/lib/src/registration/exception/localized_registration_exception.dart @@ -65,6 +65,15 @@ final class LocalizedRegistrationUnlockPasswordNotFoundException context.l10n.registrationUnlockPasswordNotFound; } +final class LocalizedRegistrationWalletNotFoundException + extends LocalizedRegistrationException { + const LocalizedRegistrationWalletNotFoundException(); + + @override + String message(BuildContext context) => + context.l10n.registrationWalletNotFound; +} + /// A generic error for describing a failure during user registration. final class LocalizedRegistrationUnknownException extends LocalizedRegistrationException {