Skip to content

Commit 47a48b6

Browse files
feat(cat-voices): add account role (#2110)
* chore: define different registration types * chore: typo fix * feat: more generic AccountRole-s in registration * feat: different exit confirm dialog for account update * feat: allow pass role selection when roles are different * feat: append new role only in reg transaction * refactor: fix imports * feat: dynamic registration transaction roles * chore: fix import * chore: emitting localized errors * chore: line max chars * fix: create correct key per role * refactor: ues pattern for materKey in registration * fix: rename correctly method from cert to publicKey * fix: pass dartCerts only in first registration transaction * fix: imports
1 parent 4e5e8f2 commit 47a48b6

File tree

35 files changed

+1147
-678
lines changed

35 files changed

+1147
-678
lines changed

catalyst_voices/apps/voices/lib/dependency/dependencies.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ final class Dependencies extends DependencyProvider {
7070
downloaderService: get<DownloaderService>(),
7171
userService: get<UserService>(),
7272
registrationService: get<RegistrationService>(),
73+
keyDerivationService: get<KeyDerivationService>(),
7374
progressNotifier: get<RegistrationProgressNotifier>(),
7475
blockchainConfig: get<AppConfig>().blockchain,
7576
);

catalyst_voices/apps/voices/lib/pages/account/unlock_keychain_dialog.dart

Lines changed: 89 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import 'dart:async';
33
import 'package:catalyst_voices/common/error_handler.dart';
44
import 'package:catalyst_voices/pages/registration/pictures/unlock_keychain_picture.dart';
55
import 'package:catalyst_voices/pages/registration/registration_dialog.dart';
6+
import 'package:catalyst_voices/pages/registration/registration_type.dart';
67
import 'package:catalyst_voices/pages/registration/widgets/information_panel.dart';
78
import 'package:catalyst_voices/pages/registration/widgets/registration_stage_message.dart';
89
import 'package:catalyst_voices/widgets/widgets.dart';
@@ -17,6 +18,9 @@ import 'package:flutter_bloc/flutter_bloc.dart';
1718
class UnlockKeychainDialog extends StatefulWidget {
1819
const UnlockKeychainDialog({super.key});
1920

21+
@override
22+
State<UnlockKeychainDialog> createState() => _UnlockKeychainDialogState();
23+
2024
static Future<void> show(BuildContext context) {
2125
return VoicesDialog.show(
2226
context: context,
@@ -25,16 +29,73 @@ class UnlockKeychainDialog extends StatefulWidget {
2529
barrierDismissible: false,
2630
);
2731
}
32+
}
33+
34+
class _Navigation extends StatelessWidget {
35+
final VoidCallback onUnlock;
36+
final VoidCallback onRecover;
37+
38+
const _Navigation({
39+
required this.onUnlock,
40+
required this.onRecover,
41+
});
2842

2943
@override
30-
State<UnlockKeychainDialog> createState() => _UnlockKeychainDialogState();
44+
Widget build(BuildContext context) {
45+
return Column(
46+
crossAxisAlignment: CrossAxisAlignment.stretch,
47+
children: [
48+
VoicesFilledButton(
49+
key: const Key('UnlockConfirmPasswordButton'),
50+
onTap: onUnlock,
51+
child: Text(context.l10n.confirmPassword),
52+
),
53+
const SizedBox(height: 10),
54+
Row(
55+
children: [
56+
Expanded(
57+
child: VoicesOutlinedButton(
58+
key: const Key('UnlockRecoverButton'),
59+
onTap: onRecover,
60+
child: Text(context.l10n.recoverAccount),
61+
),
62+
),
63+
const SizedBox(width: 10),
64+
Expanded(
65+
child: VoicesTextButton(
66+
key: const Key('UnlockContinueAsGuestButton'),
67+
onTap: () => Navigator.of(context).pop(),
68+
child: Text(context.l10n.continueAsGuest),
69+
),
70+
),
71+
],
72+
),
73+
],
74+
);
75+
}
3176
}
3277

3378
class _UnlockKeychainDialogState extends State<UnlockKeychainDialog>
3479
with ErrorHandlerStateMixin<SessionCubit, UnlockKeychainDialog> {
3580
final TextEditingController _passwordController = TextEditingController();
3681
LocalizedException? _error;
3782

83+
@override
84+
Widget build(BuildContext context) {
85+
return VoicesTwoPaneDialog(
86+
left: InformationPanel(
87+
title: context.l10n.unlockDialogHeader,
88+
picture: const UnlockKeychainPicture(),
89+
),
90+
right: _UnlockPasswordPanel(
91+
controller: _passwordController,
92+
error: _error,
93+
onUnlock: _onUnlock,
94+
onRecover: _onRecover,
95+
),
96+
);
97+
}
98+
3899
@override
39100
void dispose() {
40101
_passwordController.dispose();
@@ -50,18 +111,13 @@ class _UnlockKeychainDialogState extends State<UnlockKeychainDialog>
50111
});
51112
}
52113

53-
@override
54-
Widget build(BuildContext context) {
55-
return VoicesTwoPaneDialog(
56-
left: InformationPanel(
57-
title: context.l10n.unlockDialogHeader,
58-
picture: const UnlockKeychainPicture(),
59-
),
60-
right: _UnlockPasswordPanel(
61-
controller: _passwordController,
62-
error: _error,
63-
onUnlock: _onUnlock,
64-
onRecover: _onRecover,
114+
void _onRecover() {
115+
Navigator.of(context).pop();
116+
117+
unawaited(
118+
RegistrationDialog.show(
119+
context,
120+
type: const RecoverRegistration(),
65121
),
66122
);
67123
}
@@ -88,56 +144,6 @@ class _UnlockKeychainDialogState extends State<UnlockKeychainDialog>
88144
});
89145
}
90146
}
91-
92-
void _onRecover() {
93-
Navigator.of(context).pop();
94-
95-
unawaited(
96-
RegistrationDialog.show(
97-
context,
98-
step: const RecoverMethodStep(),
99-
),
100-
);
101-
}
102-
}
103-
104-
class _UnlockPasswordPanel extends StatelessWidget {
105-
final TextEditingController controller;
106-
final LocalizedException? error;
107-
final VoidCallback onUnlock;
108-
final VoidCallback onRecover;
109-
110-
const _UnlockPasswordPanel({
111-
required this.controller,
112-
required this.error,
113-
required this.onUnlock,
114-
required this.onRecover,
115-
});
116-
117-
@override
118-
Widget build(BuildContext context) {
119-
return Column(
120-
crossAxisAlignment: CrossAxisAlignment.stretch,
121-
children: [
122-
const SizedBox(height: 24),
123-
RegistrationStageMessage(
124-
title: Text(context.l10n.unlockDialogTitle),
125-
subtitle: Text(context.l10n.unlockDialogContent),
126-
),
127-
const SizedBox(height: 24),
128-
_UnlockPassword(
129-
controller: controller,
130-
error: error,
131-
onUnlock: onUnlock,
132-
),
133-
const Spacer(),
134-
_Navigation(
135-
onUnlock: onUnlock,
136-
onRecover: onRecover,
137-
),
138-
],
139-
);
140-
}
141147
}
142148

143149
class _UnlockPassword extends StatelessWidget {
@@ -167,11 +173,15 @@ class _UnlockPassword extends StatelessWidget {
167173
}
168174
}
169175

170-
class _Navigation extends StatelessWidget {
176+
class _UnlockPasswordPanel extends StatelessWidget {
177+
final TextEditingController controller;
178+
final LocalizedException? error;
171179
final VoidCallback onUnlock;
172180
final VoidCallback onRecover;
173181

174-
const _Navigation({
182+
const _UnlockPasswordPanel({
183+
required this.controller,
184+
required this.error,
175185
required this.onUnlock,
176186
required this.onRecover,
177187
});
@@ -181,30 +191,21 @@ class _Navigation extends StatelessWidget {
181191
return Column(
182192
crossAxisAlignment: CrossAxisAlignment.stretch,
183193
children: [
184-
VoicesFilledButton(
185-
key: const Key('UnlockConfirmPasswordButton'),
186-
onTap: onUnlock,
187-
child: Text(context.l10n.confirmPassword),
194+
const SizedBox(height: 24),
195+
RegistrationStageMessage(
196+
title: Text(context.l10n.unlockDialogTitle),
197+
subtitle: Text(context.l10n.unlockDialogContent),
188198
),
189-
const SizedBox(height: 10),
190-
Row(
191-
children: [
192-
Expanded(
193-
child: VoicesOutlinedButton(
194-
key: const Key('UnlockRecoverButton'),
195-
onTap: onRecover,
196-
child: Text(context.l10n.recoverAccount),
197-
),
198-
),
199-
const SizedBox(width: 10),
200-
Expanded(
201-
child: VoicesTextButton(
202-
key: const Key('UnlockContinueAsGuestButton'),
203-
onTap: () => Navigator.of(context).pop(),
204-
child: Text(context.l10n.continueAsGuest),
205-
),
206-
),
207-
],
199+
const SizedBox(height: 24),
200+
_UnlockPassword(
201+
controller: controller,
202+
error: error,
203+
onUnlock: onUnlock,
204+
),
205+
const Spacer(),
206+
_Navigation(
207+
onUnlock: onUnlock,
208+
onRecover: onRecover,
208209
),
209210
],
210211
);

catalyst_voices/apps/voices/lib/pages/account/widgets/account_roles_tile.dart

Lines changed: 31 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import 'package:catalyst_voices/common/ext/account_role_ext.dart';
22
import 'package:catalyst_voices/common/ext/build_context_ext.dart';
33
import 'package:catalyst_voices/pages/account/edit_roles_dialog.dart';
4+
import 'package:catalyst_voices/pages/registration/registration_dialog.dart';
5+
import 'package:catalyst_voices/pages/registration/registration_type.dart';
46
import 'package:catalyst_voices/widgets/common/affix_decorator.dart';
57
import 'package:catalyst_voices/widgets/widgets.dart';
68
import 'package:catalyst_voices_assets/catalyst_voices_assets.dart';
@@ -54,7 +56,15 @@ class _AccountRolesTileState extends State<_AccountRolesTile> {
5456
return;
5557
}
5658

57-
// TODO(damian-molinski): Registration dialog
59+
final accountId = context.read<SessionCubit>().state.account?.catalystId;
60+
if (accountId == null) {
61+
return;
62+
}
63+
64+
await RegistrationDialog.show(
65+
context,
66+
type: UpdateAccount(id: accountId),
67+
);
5868
}
5969
}
6070

@@ -78,20 +88,18 @@ class _EditButton extends StatelessWidget {
7888
}
7989
}
8090

81-
class _Roles extends StatelessWidget {
82-
final List<MyAccountRoleItem> items;
91+
class _IconColor implements WidgetStateProperty<Color> {
92+
final VoicesColorScheme colors;
8393

84-
const _Roles({
85-
required this.items,
86-
});
94+
const _IconColor(this.colors);
8795

8896
@override
89-
Widget build(BuildContext context) {
90-
return Wrap(
91-
spacing: 12,
92-
runSpacing: 12,
93-
children: items.map((item) => _RoleCell(item: item)).toList(),
94-
);
97+
Color resolve(Set<WidgetState> states) {
98+
if (states.contains(WidgetState.disabled)) {
99+
return colors.iconsDisabled;
100+
}
101+
102+
return colors.iconsForeground;
95103
}
96104
}
97105

@@ -150,18 +158,20 @@ class _RoleCellBorder implements WidgetStateProperty<Border> {
150158
}
151159
}
152160

153-
class _IconColor implements WidgetStateProperty<Color> {
154-
final VoicesColorScheme colors;
161+
class _Roles extends StatelessWidget {
162+
final List<MyAccountRoleItem> items;
155163

156-
const _IconColor(this.colors);
164+
const _Roles({
165+
required this.items,
166+
});
157167

158168
@override
159-
Color resolve(Set<WidgetState> states) {
160-
if (states.contains(WidgetState.disabled)) {
161-
return colors.iconsDisabled;
162-
}
163-
164-
return colors.iconsForeground;
169+
Widget build(BuildContext context) {
170+
return Wrap(
171+
spacing: 12,
172+
runSpacing: 12,
173+
children: items.map((item) => _RoleCell(item: item)).toList(),
174+
);
165175
}
166176
}
167177

catalyst_voices/apps/voices/lib/pages/registration/account_completed/account_completed_panel.dart

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ class _ReviewMyAccountButton extends StatelessWidget {
115115
}
116116

117117
class _RolesFooter extends StatelessWidget {
118-
final List<AccountRole> roles;
118+
final Set<AccountRole> roles;
119119

120120
const _RolesFooter(this.roles);
121121

@@ -169,7 +169,7 @@ class _RolesFooter extends StatelessWidget {
169169
}
170170

171171
class _RolesSelectedCard extends StatelessWidget {
172-
final List<AccountRole> roles;
172+
final Set<AccountRole> roles;
173173

174174
const _RolesSelectedCard({
175175
required this.roles,
@@ -193,12 +193,8 @@ class _RolesSelectedCardSelector extends StatelessWidget {
193193

194194
@override
195195
Widget build(BuildContext context) {
196-
return BlocSelector<RegistrationCubit, RegistrationState,
197-
List<AccountRole>>(
198-
selector: (state) {
199-
return state.walletLinkStateData.selectedRoles?.toList() ??
200-
state.walletLinkStateData.defaultRoles.toList();
201-
},
196+
return BlocSelector<RegistrationCubit, RegistrationState, Set<AccountRole>>(
197+
selector: (state) => state.walletLinkStateData.selectedRoleTypes,
202198
builder: (context, roles) {
203199
return _RolesSelectedCard(roles: roles);
204200
},

0 commit comments

Comments
 (0)