Skip to content

Commit

Permalink
refactor(cat-voices): registration dialog (#942)
Browse files Browse the repository at this point in the history
* refactor: Use smaller BlocBuilders in RegistrationDialog

* refactor: Introduce specialized bloc builders

* refactor: move WalletLink methods to WalletLinkCubit

* chore: missing buildWhen + fix finish account setup progress

* chore: OptionalExt tests

* chore: fix analyzer

* refactor: Replace custom BlocBuilderSelector with prebuild BlocSelector

* chore: PR-review fixes
  • Loading branch information
damian-molinski authored Oct 4, 2024
1 parent 56690ec commit 5ffdfe2
Show file tree
Hide file tree
Showing 34 changed files with 1,142 additions and 739 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import 'package:catalyst_voices_blocs/catalyst_voices_blocs.dart';
import 'package:flutter_bloc/flutter_bloc.dart';

class BlocSeedPhraseBuilder<T>
extends BlocSelector<RegistrationCubit, RegistrationState, T> {
BlocSeedPhraseBuilder({
super.key,
required BlocWidgetSelector<SeedPhraseStateData, T> selector,
required super.builder,
super.bloc,
}) : super(
selector: (state) {
return selector(state.keychainStateData.seedPhraseStateData);
},
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import 'package:catalyst_voices_blocs/catalyst_voices_blocs.dart';
import 'package:flutter_bloc/flutter_bloc.dart';

class BlocUnlockPasswordBuilder<T>
extends BlocSelector<RegistrationCubit, RegistrationState, T> {
BlocUnlockPasswordBuilder({
super.key,
required BlocWidgetSelector<UnlockPasswordState, T> selector,
required super.builder,
super.bloc,
}) : super(
selector: (state) {
return selector(state.keychainStateData.unlockPasswordState);
},
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,45 +6,31 @@ import 'package:catalyst_voices/pages/registration/create_keychain/stage/seed_ph
import 'package:catalyst_voices/pages/registration/create_keychain/stage/splash_panel.dart';
import 'package:catalyst_voices/pages/registration/create_keychain/stage/unlock_password_instructions_panel.dart';
import 'package:catalyst_voices/pages/registration/create_keychain/stage/unlock_password_panel.dart';
import 'package:catalyst_voices_blocs/catalyst_voices_blocs.dart';
import 'package:catalyst_voices_models/catalyst_voices_models.dart';
import 'package:flutter/material.dart';

class CreateKeychainPanel extends StatelessWidget {
final CreateKeychainStage stage;
final SeedPhraseState seedPhraseState;
final UnlockPasswordState unlockPasswordState;

const CreateKeychainPanel({
super.key,
required this.stage,
required this.seedPhraseState,
required this.unlockPasswordState,
});

@override
Widget build(BuildContext context) {
return switch (stage) {
CreateKeychainStage.splash => const SplashPanel(),
CreateKeychainStage.instructions => const InstructionsPanel(),
CreateKeychainStage.seedPhrase => SeedPhrasePanel(
seedPhrase: seedPhraseState.seedPhrase,
isStoreSeedPhraseConfirmed: seedPhraseState.isStoredConfirmed,
isNextEnabled: seedPhraseState.isStoredConfirmed,
),
CreateKeychainStage.seedPhrase => const SeedPhrasePanel(),
CreateKeychainStage.checkSeedPhraseInstructions =>
const SeedPhraseCheckInstructionsPanel(),
CreateKeychainStage.checkSeedPhrase => SeedPhraseCheckPanel(
seedPhrase: seedPhraseState.seedPhrase,
),
CreateKeychainStage.checkSeedPhraseResult => SeedPhraseCheckResultPanel(
isCheckConfirmed: seedPhraseState.isCheckConfirmed,
),
CreateKeychainStage.checkSeedPhrase => const SeedPhraseCheckPanel(),
CreateKeychainStage.checkSeedPhraseResult =>
const SeedPhraseCheckResultPanel(),
CreateKeychainStage.unlockPasswordInstructions =>
const UnlockPasswordInstructionsPanel(),
CreateKeychainStage.unlockPasswordCreate => UnlockPasswordPanel(
data: unlockPasswordState,
),
CreateKeychainStage.unlockPasswordCreate => const UnlockPasswordPanel(),
};
}
}
Original file line number Diff line number Diff line change
@@ -1,81 +1,37 @@
import 'package:catalyst_voices/pages/registration/create_keychain/bloc_seed_phrase_builder.dart';
import 'package:catalyst_voices/pages/registration/registration_stage_navigation.dart';
import 'package:catalyst_voices/widgets/widgets.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:flutter/foundation.dart';
import 'package:flutter/material.dart';

class SeedPhraseCheckPanel extends StatefulWidget {
final SeedPhrase? seedPhrase;

const SeedPhraseCheckPanel({
super.key,
this.seedPhrase,
});

@override
State<SeedPhraseCheckPanel> createState() => _SeedPhraseCheckPanelState();
}

class _SeedPhraseCheckPanelState extends State<SeedPhraseCheckPanel> {
final _seedPhraseWords = <String>[];
final _shuffledSeedPhraseWords = <String>[];
final _userWords = <String>[];

bool get _hasSeedPhraseWords => _seedPhraseWords.isNotEmpty;

bool get _completedWordsSequence {
return _hasSeedPhraseWords && _userWords.length == _seedPhraseWords.length;
}

bool get _completedCorrectlyWordsSequence {
return _hasSeedPhraseWords && listEquals(_userWords, _seedPhraseWords);
}

@override
void initState() {
super.initState();

_updateSeedPhraseWords();
// Note. In debug mode we're prefilling correct seed phrase words
// so its faster to test screens
_updateUserWords(kDebugMode ? _seedPhraseWords : const []);
}

@override
void didUpdateWidget(covariant SeedPhraseCheckPanel oldWidget) {
super.didUpdateWidget(oldWidget);

if (widget.seedPhrase != oldWidget.seedPhrase) {
_updateSeedPhraseWords();
// Note. In debug mode we're prefilling correct seed phrase words
// so its faster to test screens
_updateUserWords(kDebugMode ? _seedPhraseWords : const []);
}
}

@override
Widget build(BuildContext context) {
return Column(
children: [
Expanded(
child: VoicesLoadable(
isLoading: _seedPhraseWords.isEmpty,
child: _BlocLoadable(
builder: (context) {
return _SeedPhraseWords(
words: _shuffledSeedPhraseWords,
userWords: _userWords,
return _BlocSeedPhraseWords(
onUserWordsChanged: _onWordsSequenceChanged,
onUploadTap: _uploadSeedPhrase,
onResetTap: _clearUserWords,
isResetEnabled: _userWords.isNotEmpty,
);
},
),
),
const SizedBox(height: 10),
RegistrationBackNextNavigation(isNextEnabled: _completedWordsSequence),
const _BlocNavigation(),
],
);
}
Expand All @@ -85,40 +41,72 @@ class _SeedPhraseCheckPanelState extends State<SeedPhraseCheckPanel> {
}

void _clearUserWords() {
setState(_updateUserWords);
RegistrationCubit.of(context).keychainCreation.setUserSeedPhraseWords([]);
}

void _onWordsSequenceChanged(List<String> words) {
setState(() {
_updateUserWords(words);
});
RegistrationCubit.of(context)
.keychainCreation
.setUserSeedPhraseWords(words);
}
}

void _updateSeedPhraseWords() {
final seedPhrase = widget.seedPhrase;
final words = seedPhrase?.mnemonicWords ?? <String>[];
final shuffledWords = seedPhrase?.shuffledMnemonicWords ?? <String>[];
class _BlocLoadable extends StatelessWidget {
final WidgetBuilder builder;

_seedPhraseWords
..clear()
..addAll(words);
const _BlocLoadable({
required this.builder,
});

_shuffledSeedPhraseWords
..clear()
..addAll(shuffledWords);
@override
Widget build(BuildContext context) {
return BlocSeedPhraseBuilder<bool>(
selector: (state) => state.isLoading,
builder: (context, state) {
return VoicesLoadable(
isLoading: state,
builder: builder,
);
},
);
}
}

void _updateUserWords([
List<String> words = const [],
]) {
_userWords
..clear()
..addAll(words);
class _BlocSeedPhraseWords extends StatelessWidget {
const _BlocSeedPhraseWords({
required this.onUserWordsChanged,
this.onUploadTap,
this.onResetTap,
});

final isConfirmed = _completedCorrectlyWordsSequence;
final ValueChanged<List<String>> onUserWordsChanged;
final VoidCallback? onUploadTap;
final VoidCallback? onResetTap;

RegistrationCubit.of(context)
.setSeedPhraseCheckConfirmed(isConfirmed: isConfirmed);
@override
Widget build(BuildContext context) {
return BlocSeedPhraseBuilder<
({
List<String> shuffledWords,
List<String> words,
bool isResetWordsEnabled,
})>(
selector: (state) => (
shuffledWords: state.shuffledWords,
words: state.userWords,
isResetWordsEnabled: state.isResetWordsEnabled,
),
builder: (context, state) {
return _SeedPhraseWords(
words: state.shuffledWords,
userWords: state.words,
onUserWordsChanged: onUserWordsChanged,
onUploadTap: onUploadTap,
onResetTap: onResetTap,
isResetEnabled: state.isResetWordsEnabled,
);
},
);
}
}

Expand Down Expand Up @@ -193,3 +181,19 @@ class _WordsActions extends StatelessWidget {
);
}
}

class _BlocNavigation extends StatelessWidget {
const _BlocNavigation();

@override
Widget build(BuildContext context) {
return BlocSeedPhraseBuilder<bool>(
selector: (state) => state.areUserWordsCorrect,
builder: (context, state) {
return RegistrationBackNextNavigation(
isNextEnabled: state,
);
},
);
}
}
Loading

0 comments on commit 5ffdfe2

Please sign in to comment.