Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(cat-voices): registration transaction summary #921

Merged
merged 4 commits into from
Oct 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 11 additions & 9 deletions catalyst_voices/lib/pages/account/account_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import 'package:catalyst_voices/pages/account/delete_keychain_dialog.dart';
import 'package:catalyst_voices/pages/account/keychain_deleted_dialog.dart';
import 'package:catalyst_voices/widgets/buttons/voices_icon_button.dart';
import 'package:catalyst_voices/widgets/buttons/voices_text_button.dart';
import 'package:catalyst_voices/widgets/list/bullet_list.dart';
import 'package:catalyst_voices/widgets/modals/voices_dialog.dart';
import 'package:catalyst_voices_assets/catalyst_voices_assets.dart';
import 'package:catalyst_voices_brands/catalyst_voices_brands.dart';
Expand Down Expand Up @@ -239,11 +240,14 @@ class _KeychainCard extends StatelessWidget {
),
),
if (roles.isNotEmpty)
Text(
roles
.map((e) => _formatRoleBullet(e, defaultRole, context))
.join('\n'),
style: Theme.of(context).textTheme.bodyLarge,
Padding(
padding: const EdgeInsets.only(left: 4),
child: BulletList(
items: roles
.map((e) => _formatRoleBullet(e, defaultRole, context))
.toList(),
style: Theme.of(context).textTheme.bodyLarge,
),
),
],
),
Expand All @@ -255,12 +259,10 @@ class _KeychainCard extends StatelessWidget {
AccountRole? defaultRole,
BuildContext context,
) {
String label;
if (role == defaultRole) {
label = '${role.getName(context)} (${context.l10n.defaultRole})';
return '${role.getName(context)} (${context.l10n.defaultRole})';
} else {
label = role.getName(context);
return role.getName(context);
}
return ' • $label';
}
}
Original file line number Diff line number Diff line change
@@ -1,32 +1,161 @@
import 'package:catalyst_voices/widgets/buttons/voices_filled_button.dart';
import 'package:catalyst_cardano_serialization/catalyst_cardano_serialization.dart';
import 'package:catalyst_voices/common/ext/account_role_ext.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_brands/catalyst_voices_brands.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';

// TODO(dtscalac): define content
class RbacTransactionPanel extends StatelessWidget {
const RbacTransactionPanel({super.key});
final List<AccountRole> roles;
final Coin transactionFee;

const RbacTransactionPanel({
super.key,
required this.roles,
required this.transactionFee,
});

@override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
const SizedBox(height: 24),
Text(
context.l10n.walletLinkTransactionTitle,
style: Theme.of(context).textTheme.titleMedium,
),
const SizedBox(height: 12),
_Summary(
roles: roles,
transactionFee: transactionFee,
),
const SizedBox(height: 18),
const _PositiveSmallPrint(),
const Spacer(),
const _Navigation(),
],
);
}
}

class _Summary extends StatelessWidget {
final List<AccountRole> roles;
final Coin transactionFee;

const _Summary({
required this.roles,
required this.transactionFee,
});

@override
Widget build(BuildContext context) {
return Container(
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8),
border: Border.all(
width: 1.5,
color: Theme.of(context).colors.outlineBorderVariant!,
),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
context.l10n.walletLinkTransactionAccountCompletion,
style: Theme.of(context).textTheme.titleSmall,
),
for (final role in roles) ...[
const SizedBox(height: 12),
Text(
context.l10n.walletLinkTransactionRoleItem(
role.getName(context).toLowerCase(),
),
style: Theme.of(context).textTheme.bodySmall,
),
],
const Divider(height: 24),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
context.l10n.total,
style: Theme.of(context)
.textTheme
.titleSmall
?.copyWith(fontWeight: FontWeight.bold),
),
Text(
CryptocurrencyFormatter.formatAmount(transactionFee),
style: Theme.of(context).textTheme.bodySmall,
),
],
),
],
),
);
}
}

class _PositiveSmallPrint extends StatelessWidget {
const _PositiveSmallPrint();

@override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Text(
context.l10n.walletLinkTransactionPositiveSmallPrint,
style: Theme.of(context)
.textTheme
.titleSmall
?.copyWith(fontWeight: FontWeight.bold),
),
const SizedBox(height: 12),
Padding(
padding: const EdgeInsets.only(left: 4),
child: BulletList(
items: [
context.l10n.walletLinkTransactionPositiveSmallPrintItem1,
context.l10n.walletLinkTransactionPositiveSmallPrintItem2,
context.l10n.walletLinkTransactionPositiveSmallPrintItem3,
],
spacing: 4,
),
),
],
);
}
}

class _Navigation extends StatelessWidget {
const _Navigation();

@override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
VoicesFilledButton(
leading: VoicesAssets.icons.wallet.buildIcon(),
onTap: () {
RegistrationCubit.of(context).previousStep();
RegistrationCubit.of(context).submitRegistration();
},
child: const Text('Previous'),
child: Text(context.l10n.walletLinkTransactionSign),
),
const SizedBox(height: 12),
VoicesFilledButton(
const SizedBox(height: 10),
VoicesTextButton(
leading: VoicesAssets.icons.wallet.buildIcon(),
onTap: () {
RegistrationCubit.of(context).nextStep();
RegistrationCubit.of(context).changeRoleSetup();
},
child: const Text('Next'),
child: Text(context.l10n.walletLinkTransactionChangeRoles),
),
],
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,8 +133,10 @@ class _WalletSummary extends StatelessWidget {
),
),
const SizedBox(height: 6),
Text(
context.l10n.walletLinkWalletDetailsNoticeTopUpLink,
BulletList(
items: [
context.l10n.walletLinkWalletDetailsNoticeTopUpLink,
],
style: Theme.of(context).textTheme.labelSmall,
),
],
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import 'package:catalyst_cardano_serialization/catalyst_cardano_serialization.dart';
import 'package:catalyst_voices/pages/registration/wallet_link/stage/intro_panel.dart';
import 'package:catalyst_voices/pages/registration/wallet_link/stage/rbac_transaction_panel.dart';
import 'package:catalyst_voices/pages/registration/wallet_link/stage/roles_chooser_panel.dart';
Expand Down Expand Up @@ -31,7 +32,11 @@ class WalletLinkPanel extends StatelessWidget {
),
WalletLinkStage.rolesChooser => const RolesChooserPanel(),
WalletLinkStage.rolesSummary => const RolesSummaryPanel(),
WalletLinkStage.rbacTransaction => const RbacTransactionPanel(),
// TODO(dtscalac): pass valid parameters
WalletLinkStage.rbacTransaction => RbacTransactionPanel(
roles: AccountRole.values,
transactionFee: Coin.fromAda(0.9438),
),
};
}
}
65 changes: 65 additions & 0 deletions catalyst_voices/lib/widgets/list/bullet_list.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import 'package:catalyst_voices_shared/catalyst_voices_shared.dart';
import 'package:flutter/material.dart';

/// Displays a list of bulleted points. Similar to <ul><li></li></ul> in html.
class BulletList extends StatelessWidget {
/// The list of items without the bullet.
final List<String> items;

/// The text style applied to the bullet point and the [items].
///
/// Defaults to Theme.of(context).textTheme.bodySmall,
final TextStyle? style;

/// The amount of vertical space between the [items].
final double spacing;

const BulletList({
super.key,
required this.items,
this.style,
this.spacing = 4,
});

@override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
for (final item in items)
_BulletItem(
text: item,
style: style ?? Theme.of(context).textTheme.bodySmall,
),
].separatedBy(SizedBox(height: spacing)).toList(),
);
}
}

class _BulletItem extends StatelessWidget {
final String text;
final TextStyle? style;

const _BulletItem({
required this.text,
this.style,
});

@override
Widget build(BuildContext context) {
return Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'• ',
style: style,
),
Flexible(
child: Text(
text,
style: style,
),
),
],
);
}
}
1 change: 1 addition & 0 deletions catalyst_voices/lib/widgets/widgets.dart
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ export 'indicators/voices_linear_progress_indicator.dart';
export 'indicators/voices_no_internet_connection_banner.dart';
export 'indicators/voices_password_strength_indicator.dart';
export 'indicators/voices_status_indicator.dart';
export 'list/bullet_list.dart';
export 'menu/voices_list_tile.dart';
export 'menu/voices_menu.dart';
export 'menu/voices_node_menu.dart';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,10 @@ final class RegistrationCubit extends Cubit<RegistrationState> {
}
}

void changeRoleSetup() {
_goToStep(const WalletLinkStep(stage: WalletLinkStage.rolesChooser));
}

void nextStep() {
final nextStep = _nextStep();
if (nextStep != null) {
Expand Down Expand Up @@ -88,14 +92,6 @@ final class RegistrationCubit extends Cubit<RegistrationState> {
_keychainCreationCubit.setSeedPhraseStoredConfirmed(confirmed);
}

void refreshWallets() {
unawaited(_walletLinkCubit.refreshWallets());
}

Future<void> selectWallet(CardanoWallet wallet) {
return _walletLinkCubit.selectWallet(wallet);
}

Future<void> downloadSeedPhrase() {
return _keychainCreationCubit.downloadSeedPhrase();
}
Expand All @@ -108,6 +104,18 @@ final class RegistrationCubit extends Cubit<RegistrationState> {
);
}

void refreshWallets() {
unawaited(_walletLinkCubit.refreshWallets());
}

Future<void> selectWallet(CardanoWallet wallet) {
return _walletLinkCubit.selectWallet(wallet);
}

void submitRegistration() {
// TODO(dtscalac): submit RBAC transaction
}

RegistrationStep? _nextStep({RegistrationStep? from}) {
final step = from ?? state.step;

Expand Down
Loading
Loading