Skip to content

Commit

Permalink
refactor(cat-voices): user and wallet model (#999)
Browse files Browse the repository at this point in the history
* 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 <[email protected]>

---------

Co-authored-by: Dominik Toton <[email protected]>
  • Loading branch information
damian-molinski and dtscalac authored Oct 15, 2024
1 parent ba12cd3 commit 9acbf86
Show file tree
Hide file tree
Showing 23 changed files with 232 additions and 102 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,11 @@ class AccountCompletedPanel extends StatelessWidget {
info: context.l10n.registrationCompletedKeychainInfo,
),
BlocSelector<RegistrationCubit, RegistrationState, String>(
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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ class _BlocSummary extends StatelessWidget {
RegistrationState,
({
Set<AccountRole> roles,
CardanoWalletDetails selectedWallet,
WalletInfo selectedWallet,
Coin transactionFee,
})?>(
selector: (state) {
Expand All @@ -125,7 +125,7 @@ class _BlocSummary extends StatelessWidget {

return _Summary(
roles: state.roles,
walletDetails: state.selectedWallet,
walletInfo: state.selectedWallet,
transactionFee: state.transactionFee,
);
},
Expand All @@ -135,17 +135,19 @@ class _BlocSummary extends StatelessWidget {

class _Summary extends StatelessWidget {
final Set<AccountRole> 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(
Expand All @@ -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) ...[
Expand Down
Original file line number Diff line number Diff line change
@@ -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<void> Function(CardanoWallet wallet);
typedef _OnSelectWallet = Future<void> Function(WalletMetadata wallet);

class SelectWalletPanel extends StatefulWidget {
const SelectWalletPanel({
Expand Down Expand Up @@ -67,7 +67,7 @@ class _SelectWalletPanelState extends State<SelectWalletPanel> {
unawaited(RegistrationCubit.of(context).walletLink.refreshWallets());
}

Future<void> _onSelectWallet(CardanoWallet wallet) async {
Future<void> _onSelectWallet(WalletMetadata wallet) async {
final registration = RegistrationCubit.of(context);

final success = await registration.walletLink.selectWallet(wallet);
Expand All @@ -88,7 +88,7 @@ class _BlocWallets extends StatelessWidget {

@override
Widget build(BuildContext context) {
return BlocWalletLinkBuilder<Result<List<CardanoWallet>, Exception>?>(
return BlocWalletLinkBuilder<Result<List<WalletMetadata>, Exception>?>(
selector: (state) => state.wallets,
builder: (context, state) {
return _Wallets(
Expand All @@ -102,7 +102,7 @@ class _BlocWallets extends StatelessWidget {
}

class _Wallets extends StatelessWidget {
final Result<List<CardanoWallet>, Exception>? result;
final Result<List<WalletMetadata>, Exception>? result;
final _OnSelectWallet onSelectWallet;
final VoidCallback onRefreshTap;

Expand All @@ -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<CardanoWallet> wallets;
final List<WalletMetadata> wallets;
final _OnSelectWallet onSelectWallet;

const _WalletsList({
Expand All @@ -148,7 +150,7 @@ class _WalletsList extends StatelessWidget {
}

class _WalletTile extends StatefulWidget {
final CardanoWallet wallet;
final WalletMetadata wallet;
final _OnSelectWallet onSelectWallet;

const _WalletTile({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ class _BlocWalletDetailsText extends StatelessWidget {
@override
Widget build(BuildContext context) {
return BlocWalletLinkBuilder<String?>(
selector: (state) => state.selectedWallet?.wallet.name,
selector: (state) => state.selectedWallet?.metadata.name,
builder: (context, state) {
return Text(
context.l10n.walletLinkWalletDetailsContent(state ?? ''),
Expand Down Expand Up @@ -101,7 +101,7 @@ class _BlocNavigation extends StatelessWidget {
@override
Widget build(BuildContext context) {
return BlocWalletLinkBuilder<bool>(
selector: (state) => state.selectedWallet?.hasEnoughBalance ?? false,
selector: (state) => state.hasEnoughBalance,
builder: (context, state) {
if (state) {
return const RegistrationBackNextNavigation();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<void>(context),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,18 +76,18 @@ final class RecoverCubit extends Cubit<RecoverStateData>
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,
),
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand All @@ -14,7 +15,7 @@ final _logger = Logger('WalletLinkCubit');
abstract interface class WalletLinkManager {
Future<void> refreshWallets();

Future<bool> selectWallet(CardanoWallet wallet);
Future<bool> selectWallet(WalletMetadata meta);

void selectRoles(Set<AccountRole> roles);
}
Expand All @@ -24,45 +25,72 @@ final class WalletLinkCubit extends Cubit<WalletLinkStateData>
implements WalletLinkManager {
final RegistrationService registrationService;

final _wallets = <CardanoWallet>[];
CardanoWallet? _selectedWallet;

WalletLinkCubit({required this.registrationService})
: super(const WalletLinkStateData());

CardanoWallet? get selectedWallet => _selectedWallet;

@override
Future<void> 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<bool> selectWallet(CardanoWallet wallet) async {
Future<bool> 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),
);
Expand All @@ -73,6 +101,8 @@ final class WalletLinkCubit extends Cubit<WalletLinkStateData>
} catch (error, stackTrace) {
_logger.severe('selectWallet', error, stackTrace);

_selectedWallet = null;

emit(
state.copyWith(
selectedWallet: const Optional.empty(),
Expand All @@ -81,6 +111,8 @@ final class WalletLinkCubit extends Cubit<WalletLinkStateData>
),
);

emitError(error);

return false;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ final class RegistrationCubit extends Cubit<RegistrationState>
);

final unsignedTx = await registrationService.prepareRegistration(
wallet: _walletLinkState.selectedCardanoWallet!,
wallet: _walletLinkCubit.selectedWallet!,
// TODO(dtscalac): inject the networkId
networkId: NetworkId.testnet,
seedPhrase: _keychainState.seedPhrase!,
Expand Down Expand Up @@ -163,7 +163,7 @@ final class RegistrationCubit extends Cubit<RegistrationState>
);

final signedTx = await registrationService.submitRegistration(
wallet: _walletLinkState.selectedCardanoWallet!,
wallet: _walletLinkCubit.selectedWallet!,
unsignedTx: _registrationState.unsignedTx!.success,
);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,21 @@
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';
import 'package:equatable/equatable.dart';
import 'package:result_type/result_type.dart';

final class WalletLinkStateData extends Equatable {
final Result<List<CardanoWallet>, Exception>? wallets;
final CardanoWalletDetails? selectedWallet;
final Result<List<WalletMetadata>, Exception>? wallets;
final WalletInfo? selectedWallet;
final bool hasEnoughBalance;
final WalletConnectionData? walletConnection;
final WalletSummaryData? walletSummary;
final Set<AccountRole>? selectedRoles;

const WalletLinkStateData({
this.wallets,
this.selectedWallet,
this.hasEnoughBalance = false,
this.walletConnection,
this.walletSummary,
this.selectedRoles,
Expand All @@ -26,19 +27,18 @@ final class WalletLinkStateData extends Equatable {
/// Returns the default roles every account will have.
Set<AccountRole> get defaultRoles => {AccountRole.voter};

/// Returns the selected & enabled cardano wallet.
CardanoWallet? get selectedCardanoWallet => selectedWallet?.wallet;

WalletLinkStateData copyWith({
Optional<Result<List<CardanoWallet>, Exception>>? wallets,
Optional<CardanoWalletDetails>? selectedWallet,
Optional<Result<List<WalletMetadata>, Exception>>? wallets,
Optional<WalletInfo>? selectedWallet,
bool? hasEnoughBalance,
Optional<WalletConnectionData>? walletConnection,
Optional<WalletSummaryData>? walletSummary,
Optional<Set<AccountRole>>? selectedRoles,
}) {
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),
Expand All @@ -49,6 +49,7 @@ final class WalletLinkStateData extends Equatable {
List<Object?> get props => [
wallets,
selectedWallet,
hasEnoughBalance,
walletConnection,
walletSummary,
selectedRoles,
Expand Down
Loading

0 comments on commit 9acbf86

Please sign in to comment.