Skip to content

Commit 980067a

Browse files
feat(cat-voices): seed phrase error result and unlock password instructions (#920)
* refactor: rename panel to be consistent with others * feat: allow wrong seed phrase order to go to results screen * feat: better error seed phrase messages * feat: unlock password instructions panel * feat: unlock password stages picture * refactor: scrollable panels content
1 parent ffba899 commit 980067a

12 files changed

+137
-37
lines changed

catalyst_voices/lib/pages/registration/create_keychain/create_keychain_panel.dart

+6-5
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
import 'package:catalyst_voices/pages/registration/create_keychain/stage/check_seed_phrase_instructions_panel.dart';
21
import 'package:catalyst_voices/pages/registration/create_keychain/stage/instructions_panel.dart';
2+
import 'package:catalyst_voices/pages/registration/create_keychain/stage/seed_phrase_check_instructions_panel.dart';
33
import 'package:catalyst_voices/pages/registration/create_keychain/stage/seed_phrase_check_panel.dart';
44
import 'package:catalyst_voices/pages/registration/create_keychain/stage/seed_phrase_check_result_panel.dart';
55
import 'package:catalyst_voices/pages/registration/create_keychain/stage/seed_phrase_panel.dart';
66
import 'package:catalyst_voices/pages/registration/create_keychain/stage/splash_panel.dart';
7+
import 'package:catalyst_voices/pages/registration/create_keychain/stage/unlock_password_instructions_panel.dart';
78
import 'package:catalyst_voices/pages/registration/placeholder_panel.dart';
89
import 'package:catalyst_voices_blocs/catalyst_voices_blocs.dart';
910
import 'package:catalyst_voices_models/catalyst_voices_models.dart';
@@ -30,16 +31,16 @@ class CreateKeychainPanel extends StatelessWidget {
3031
isNextEnabled: seedPhraseState.isStoredConfirmed,
3132
),
3233
CreateKeychainStage.checkSeedPhraseInstructions =>
33-
const CheckSeedPhraseInstructionsPanel(),
34+
const SeedPhraseCheckInstructionsPanel(),
3435
CreateKeychainStage.checkSeedPhrase => SeedPhraseCheckPanel(
3536
seedPhrase: seedPhraseState.seedPhrase,
3637
),
3738
CreateKeychainStage.checkSeedPhraseResult => SeedPhraseCheckResultPanel(
3839
isCheckConfirmed: seedPhraseState.isCheckConfirmed,
3940
),
40-
CreateKeychainStage.unlockPasswordInstructions ||
41-
CreateKeychainStage.unlockPasswordCreate =>
42-
const PlaceholderPanel(),
41+
CreateKeychainStage.unlockPasswordInstructions =>
42+
const UnlockPasswordInstructionsPanel(),
43+
CreateKeychainStage.unlockPasswordCreate => const PlaceholderPanel(),
4344
};
4445
}
4546
}

catalyst_voices/lib/pages/registration/create_keychain/stage/instructions_panel.dart

+10-4
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,21 @@ class InstructionsPanel extends StatelessWidget {
88

99
@override
1010
Widget build(BuildContext context) {
11+
final l10n = context.l10n;
12+
1113
return Column(
1214
crossAxisAlignment: CrossAxisAlignment.stretch,
1315
children: [
1416
const SizedBox(height: 24),
15-
RegistrationStageMessage(
16-
title: context.l10n.accountInstructionsTitle,
17-
subtitle: context.l10n.accountInstructionsMessage,
17+
Expanded(
18+
child: SingleChildScrollView(
19+
child: RegistrationStageMessage(
20+
title: l10n.accountInstructionsTitle,
21+
subtitle: l10n.accountInstructionsMessage,
22+
),
23+
),
1824
),
19-
const Spacer(),
25+
const SizedBox(height: 10),
2026
const RegistrationBackNextNavigation(),
2127
],
2228
);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import 'package:catalyst_voices/pages/registration/registration_stage_message.dart';
2+
import 'package:catalyst_voices/pages/registration/registration_stage_navigation.dart';
3+
import 'package:catalyst_voices_localization/catalyst_voices_localization.dart';
4+
import 'package:flutter/material.dart';
5+
6+
class SeedPhraseCheckInstructionsPanel extends StatelessWidget {
7+
const SeedPhraseCheckInstructionsPanel({
8+
super.key,
9+
});
10+
11+
@override
12+
Widget build(BuildContext context) {
13+
final l10n = context.l10n;
14+
15+
return Column(
16+
crossAxisAlignment: CrossAxisAlignment.stretch,
17+
children: [
18+
const SizedBox(height: 24),
19+
Expanded(
20+
child: SingleChildScrollView(
21+
child: RegistrationStageMessage(
22+
title: l10n.createKeychainSeedPhraseCheckInstructionsTitle,
23+
subtitle: l10n.createKeychainSeedPhraseCheckInstructionsSubtitle,
24+
),
25+
),
26+
),
27+
const SizedBox(height: 10),
28+
const RegistrationBackNextNavigation(),
29+
],
30+
);
31+
}
32+
}

catalyst_voices/lib/pages/registration/create_keychain/stage/seed_phrase_check_panel.dart

+13-10
Original file line numberDiff line numberDiff line change
@@ -23,20 +23,22 @@ class _SeedPhraseCheckPanelState extends State<SeedPhraseCheckPanel> {
2323
final _shuffledSeedPhraseWords = <String>[];
2424
final _userWords = <String>[];
2525

26-
bool get _isStageValid {
27-
if (_seedPhraseWords.isEmpty) {
28-
return false;
29-
}
26+
bool get _hasSeedPhraseWords => _seedPhraseWords.isNotEmpty;
27+
28+
bool get _completedWordsSequence {
29+
return _hasSeedPhraseWords && _userWords.length == _seedPhraseWords.length;
30+
}
3031

31-
return listEquals(_seedPhraseWords, _userWords);
32+
bool get _completedCorrectlyWordsSequence {
33+
return _hasSeedPhraseWords && listEquals(_userWords, _seedPhraseWords);
3234
}
3335

3436
@override
3537
void initState() {
3638
super.initState();
3739

3840
_updateSeedPhraseWords();
39-
_updateUserWords(_seedPhraseWords);
41+
_updateUserWords();
4042
}
4143

4244
@override
@@ -69,7 +71,7 @@ class _SeedPhraseCheckPanelState extends State<SeedPhraseCheckPanel> {
6971
),
7072
),
7173
const SizedBox(height: 10),
72-
RegistrationBackNextNavigation(isNextEnabled: _isStageValid),
74+
RegistrationBackNextNavigation(isNextEnabled: _completedWordsSequence),
7375
],
7476
);
7577
}
@@ -109,9 +111,10 @@ class _SeedPhraseCheckPanelState extends State<SeedPhraseCheckPanel> {
109111
..clear()
110112
..addAll(words);
111113

112-
RegistrationCubit.of(context).setSeedPhraseCheckConfirmed(
113-
isConfirmed: _isStageValid,
114-
);
114+
final isConfirmed = _completedCorrectlyWordsSequence;
115+
116+
RegistrationCubit.of(context)
117+
.setSeedPhraseCheckConfirmed(isConfirmed: isConfirmed);
115118
}
116119
}
117120

catalyst_voices/lib/pages/registration/create_keychain/stage/seed_phrase_check_result_panel.dart

+16-7
Original file line numberDiff line numberDiff line change
@@ -14,18 +14,27 @@ class SeedPhraseCheckResultPanel extends StatelessWidget {
1414

1515
@override
1616
Widget build(BuildContext context) {
17+
final l10n = context.l10n;
18+
1719
return Column(
1820
crossAxisAlignment: CrossAxisAlignment.stretch,
1921
children: [
2022
const SizedBox(height: 24),
21-
RegistrationStageMessage(
22-
title: context.l10n.createKeychainSeedPhraseCheckSuccessTitle,
23-
subtitle: context.l10n.createKeychainSeedPhraseCheckSuccessSubtitle,
24-
),
25-
const Spacer(),
26-
NextStep(
27-
context.l10n.createKeychainSeedPhraseCheckSuccessNextStep,
23+
// TODO(damian-molinski): use correct strings when available.
24+
Expanded(
25+
child: SingleChildScrollView(
26+
child: RegistrationStageMessage(
27+
title: isCheckConfirmed
28+
? l10n.createKeychainSeedPhraseCheckSuccessTitle
29+
: 'Seed phrase words does not match!',
30+
subtitle: isCheckConfirmed
31+
? l10n.createKeychainSeedPhraseCheckSuccessSubtitle
32+
: 'Go back ana make sure order is correct',
33+
),
34+
),
2835
),
36+
if (isCheckConfirmed)
37+
NextStep(l10n.createKeychainSeedPhraseCheckSuccessNextStep),
2938
const SizedBox(height: 10),
3039
RegistrationBackNextNavigation(isNextEnabled: isCheckConfirmed),
3140
],

catalyst_voices/lib/pages/registration/create_keychain/stage/check_seed_phrase_instructions_panel.dart catalyst_voices/lib/pages/registration/create_keychain/stage/unlock_password_instructions_panel.dart

+12-7
Original file line numberDiff line numberDiff line change
@@ -3,23 +3,28 @@ import 'package:catalyst_voices/pages/registration/registration_stage_navigation
33
import 'package:catalyst_voices_localization/catalyst_voices_localization.dart';
44
import 'package:flutter/material.dart';
55

6-
class CheckSeedPhraseInstructionsPanel extends StatelessWidget {
7-
const CheckSeedPhraseInstructionsPanel({
6+
class UnlockPasswordInstructionsPanel extends StatelessWidget {
7+
const UnlockPasswordInstructionsPanel({
88
super.key,
99
});
1010

1111
@override
1212
Widget build(BuildContext context) {
13+
final l10n = context.l10n;
14+
1315
return Column(
1416
crossAxisAlignment: CrossAxisAlignment.stretch,
1517
children: [
1618
const SizedBox(height: 24),
17-
RegistrationStageMessage(
18-
title: context.l10n.createKeychainSeedPhraseCheckInstructionsTitle,
19-
subtitle:
20-
context.l10n.createKeychainSeedPhraseCheckInstructionsSubtitle,
19+
Expanded(
20+
child: SingleChildScrollView(
21+
child: RegistrationStageMessage(
22+
title: l10n.createKeychainUnlockPasswordInstructionsTitle,
23+
subtitle: l10n.createKeychainUnlockPasswordInstructionsSubtitle,
24+
),
25+
),
2126
),
22-
const Spacer(),
27+
const SizedBox(height: 10),
2328
const RegistrationBackNextNavigation(),
2429
],
2530
);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import 'package:catalyst_voices/pages/registration/pictures/task_picture.dart';
2+
import 'package:catalyst_voices_assets/catalyst_voices_assets.dart';
3+
import 'package:flutter/material.dart';
4+
5+
class PasswordPicture extends StatelessWidget {
6+
const PasswordPicture({super.key});
7+
8+
@override
9+
Widget build(BuildContext context) {
10+
return TaskPicture(
11+
child: TaskPictureIconBox(
12+
type: TaskPictureType.error,
13+
child: VoicesAssets.icons.lockClosed.buildIcon(size: 48),
14+
),
15+
);
16+
}
17+
}

catalyst_voices/lib/pages/registration/registration_info_panel.dart

+4-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import 'package:catalyst_voices/pages/registration/information_panel.dart';
22
import 'package:catalyst_voices/pages/registration/pictures/keychain_picture.dart';
3+
import 'package:catalyst_voices/pages/registration/pictures/password_picture.dart';
34
import 'package:catalyst_voices/pages/registration/pictures/seed_phrase_picture.dart';
45
import 'package:catalyst_voices/pages/registration/pictures/task_picture.dart';
56
import 'package:catalyst_voices_blocs/catalyst_voices_blocs.dart';
@@ -66,9 +67,9 @@ class RegistrationInfoPanel extends StatelessWidget {
6667
subtitle: context.l10n.createKeychainSeedPhraseCheckSubtitle,
6768
body: context.l10n.createKeychainSeedPhraseCheckBody,
6869
),
69-
CreateKeychainStage.checkSeedPhraseResult =>
70+
CreateKeychainStage.checkSeedPhraseResult ||
71+
CreateKeychainStage.unlockPasswordInstructions =>
7072
_HeaderStrings(title: context.l10n.catalystKeychain),
71-
CreateKeychainStage.unlockPasswordInstructions ||
7273
CreateKeychainStage.unlockPasswordCreate =>
7374
_HeaderStrings(title: 'TODO'),
7475
};
@@ -138,7 +139,7 @@ class _RegistrationPicture extends StatelessWidget {
138139
),
139140
CreateKeychainStage.unlockPasswordInstructions ||
140141
CreateKeychainStage.unlockPasswordCreate =>
141-
const KeychainPicture(),
142+
const PasswordPicture(),
142143
};
143144
}
144145

catalyst_voices/packages/catalyst_voices_localization/lib/generated/catalyst_voices_localizations.dart

+12
Original file line numberDiff line numberDiff line change
@@ -1113,6 +1113,18 @@ abstract class VoicesLocalizations {
11131113
/// In en, this message translates to:
11141114
/// **'Now let’s set your Unlock password for this device!'**
11151115
String get createKeychainSeedPhraseCheckSuccessNextStep;
1116+
1117+
/// No description provided for @createKeychainUnlockPasswordInstructionsTitle.
1118+
///
1119+
/// In en, this message translates to:
1120+
/// **'Set your Catalyst unlock password 
for this device'**
1121+
String get createKeychainUnlockPasswordInstructionsTitle;
1122+
1123+
/// No description provided for @createKeychainUnlockPasswordInstructionsSubtitle.
1124+
///
1125+
/// In en, this message translates to:
1126+
/// **'With over 300 trillion possible combinations, your 12 word seed phrase is great for keeping your account safe. 

But it can be a bit tedious to enter every single time you want to use the app. 

In this next step, you\'ll set your Unlock Password for your current device. It\'s like a shortcut for proving ownership of your Keychain. 

Whenever you recover your account for the first time on a new device, you\'ll need to use your Catalyst Keychain to get started. Every time after that, you can use your Unlock Password to quickly regain access.'**
1127+
String get createKeychainUnlockPasswordInstructionsSubtitle;
11161128
}
11171129

11181130
class _VoicesLocalizationsDelegate extends LocalizationsDelegate<VoicesLocalizations> {

catalyst_voices/packages/catalyst_voices_localization/lib/generated/catalyst_voices_localizations_en.dart

+6
Original file line numberDiff line numberDiff line change
@@ -572,4 +572,10 @@ class VoicesLocalizationsEn extends VoicesLocalizations {
572572

573573
@override
574574
String get createKeychainSeedPhraseCheckSuccessNextStep => 'Now let’s set your Unlock password for this device!';
575+
576+
@override
577+
String get createKeychainUnlockPasswordInstructionsTitle => 'Set your Catalyst unlock password 
for this device';
578+
579+
@override
580+
String get createKeychainUnlockPasswordInstructionsSubtitle => 'With over 300 trillion possible combinations, your 12 word seed phrase is great for keeping your account safe. 

But it can be a bit tedious to enter every single time you want to use the app. 

In this next step, you\'ll set your Unlock Password for your current device. It\'s like a shortcut for proving ownership of your Keychain. 

Whenever you recover your account for the first time on a new device, you\'ll need to use your Catalyst Keychain to get started. Every time after that, you can use your Unlock Password to quickly regain access.';
575581
}

catalyst_voices/packages/catalyst_voices_localization/lib/generated/catalyst_voices_localizations_es.dart

+6
Original file line numberDiff line numberDiff line change
@@ -572,4 +572,10 @@ class VoicesLocalizationsEs extends VoicesLocalizations {
572572

573573
@override
574574
String get createKeychainSeedPhraseCheckSuccessNextStep => 'Now let’s set your Unlock password for this device!';
575+
576+
@override
577+
String get createKeychainUnlockPasswordInstructionsTitle => 'Set your Catalyst unlock password 
for this device';
578+
579+
@override
580+
String get createKeychainUnlockPasswordInstructionsSubtitle => 'With over 300 trillion possible combinations, your 12 word seed phrase is great for keeping your account safe. 

But it can be a bit tedious to enter every single time you want to use the app. 

In this next step, you\'ll set your Unlock Password for your current device. It\'s like a shortcut for proving ownership of your Keychain. 

Whenever you recover your account for the first time on a new device, you\'ll need to use your Catalyst Keychain to get started. Every time after that, you can use your Unlock Password to quickly regain access.';
575581
}

catalyst_voices/packages/catalyst_voices_localization/lib/l10n/intl_en.arb

+3-1
Original file line numberDiff line numberDiff line change
@@ -649,5 +649,7 @@
649649
"createKeychainSeedPhraseCheckSuccessTitle": "Nice job! You've successfully verified the seed phrase for your keychain.",
650650
"createKeychainSeedPhraseCheckSuccessSubtitle": "Enter your seed phrase to recover your Catalyst Keychain on any device.\u2028\u2028It's kinda like your email and password all rolled into one, so keep it somewhere safe!\u2028\u2028In the next step we’ll add a password to your Catalyst Keychain, so you can lock/unlock access to Voices.",
651651
"yourNextStep": "Your next step",
652-
"createKeychainSeedPhraseCheckSuccessNextStep": "Now let’s set your Unlock password for this device!"
652+
"createKeychainSeedPhraseCheckSuccessNextStep": "Now let’s set your Unlock password for this device!",
653+
"createKeychainUnlockPasswordInstructionsTitle": "Set your Catalyst unlock password \u2028for this device",
654+
"createKeychainUnlockPasswordInstructionsSubtitle": "With over 300 trillion possible combinations, your 12 word seed phrase is great for keeping your account safe. \u2028\u2028But it can be a bit tedious to enter every single time you want to use the app. \u2028\u2028In this next step, you'll set your Unlock Password for your current device. It's like a shortcut for proving ownership of your Keychain. \u2028\u2028Whenever you recover your account for the first time on a new device, you'll need to use your Catalyst Keychain to get started. Every time after that, you can use your Unlock Password to quickly regain access."
653655
}

0 commit comments

Comments
 (0)