From 6055b0a8d26675718f7a58e539b9d99dce402a44 Mon Sep 17 00:00:00 2001 From: knightforce Date: Wed, 28 Aug 2024 00:32:26 +0200 Subject: [PATCH 1/7] EWM-250. Fix add seed --- lib/app/router/routs/add_seed/add_seed.dart | 28 ++++++------------- .../cubit/create_seed_password_cubit.dart | 8 +++--- .../view/create_seed_password_page.dart | 4 +-- 3 files changed, 15 insertions(+), 25 deletions(-) diff --git a/lib/app/router/routs/add_seed/add_seed.dart b/lib/app/router/routs/add_seed/add_seed.dart index 266b98455..fee5171ce 100644 --- a/lib/app/router/routs/add_seed/add_seed.dart +++ b/lib/app/router/routs/add_seed/add_seed.dart @@ -116,10 +116,7 @@ GoRoute get createSeedNoNamedProfileRoute { GoRoute( path: AppRoute.createSeedPassword.path, builder: (_, state) => CreateSeedPasswordProfilePage( - phrase: (jsonDecode( - state.uri.queryParameters[addSeedPhraseQueryParam]!, - ) as List) - .cast(), + phrase: state.uri.queryParameters[addSeedPhraseQueryParam], name: state.pathParameters[enterSeedNameNamePathParam], ), ), @@ -132,10 +129,7 @@ GoRoute get enterSeedNoNamedProfileRoute { GoRoute( path: AppRoute.createSeedPassword.path, builder: (_, GoRouterState state) => CreateSeedPasswordProfilePage( - phrase: (jsonDecode( - state.uri.queryParameters[addSeedPhraseQueryParam]!, - ) as List) - .cast(), + phrase: state.uri.queryParameters[addSeedPhraseQueryParam], name: state.pathParameters[enterSeedNameNamePathParam], ), ), @@ -149,10 +143,7 @@ GoRoute get createSeedNamedProfileRoute { final passwordRoute = GoRoute( path: AppRoute.createSeedPassword.path, builder: (_, GoRouterState state) => CreateSeedPasswordProfilePage( - phrase: (jsonDecode( - state.uri.queryParameters[addSeedPhraseQueryParam]!, - ) as List) - .cast(), + phrase: state.uri.queryParameters[addSeedPhraseQueryParam], name: state.pathParameters[enterSeedNameNamePathParam], ), ); @@ -188,13 +179,12 @@ GoRoute get enterSeedNamedProfileRoute { routes: [ GoRoute( path: AppRoute.createSeedPassword.path, - builder: (_, GoRouterState state) => CreateSeedPasswordProfilePage( - phrase: (jsonDecode( - state.uri.queryParameters[addSeedPhraseQueryParam]!, - ) as List) - .cast(), - name: state.pathParameters[enterSeedNameNamePathParam], - ), + builder: (_, GoRouterState state) { + return CreateSeedPasswordProfilePage( + phrase: state.uri.queryParameters[addSeedPhraseQueryParam], + name: state.pathParameters[enterSeedNameNamePathParam], + ); + }, ), ], ); diff --git a/lib/feature/add_seed/create_password/cubit/create_seed_password_cubit.dart b/lib/feature/add_seed/create_password/cubit/create_seed_password_cubit.dart index e57e9c4aa..e1c636439 100644 --- a/lib/feature/add_seed/create_password/cubit/create_seed_password_cubit.dart +++ b/lib/feature/add_seed/create_password/cubit/create_seed_password_cubit.dart @@ -19,8 +19,8 @@ const _minPasswordLength = 8; class CreateSeedPasswordCubit extends Cubit with ConnectionMixin { CreateSeedPasswordCubit({ - required this.phrase, required this.completeCallback, + this.phrase, this.setCurrentKey = false, this.name, }) : super(CreateSeedPasswordState.initial()) { @@ -32,7 +32,7 @@ class CreateSeedPasswordCubit extends Cubit final VoidCallback completeCallback; /// Phrase that must be used to create seed - final List phrase; + final String? phrase; /// Name of seed phrase if provided final String? name; @@ -67,7 +67,7 @@ class CreateSeedPasswordCubit extends Cubit } Future nextAction() async { - if (!await checkConnection()) { + if (phrase == null || !await checkConnection()) { return; } @@ -76,7 +76,7 @@ class CreateSeedPasswordCubit extends Cubit final currentKeyService = inject(); try { final publicKey = await nekoton.addSeed( - phrase: phrase, + phrase: phrase!.split(' '), password: passwordController.text, name: name, ); diff --git a/lib/feature/add_seed/create_password/view/create_seed_password_page.dart b/lib/feature/add_seed/create_password/view/create_seed_password_page.dart index f297c1323..f9e455949 100644 --- a/lib/feature/add_seed/create_password/view/create_seed_password_page.dart +++ b/lib/feature/add_seed/create_password/view/create_seed_password_page.dart @@ -13,12 +13,12 @@ typedef _Cubit = CreateSeedPasswordCubit; class CreateSeedPasswordProfilePage extends StatelessWidget { /// {@macro create_seed_password_profile_page} const CreateSeedPasswordProfilePage({ - required this.phrase, required this.name, + this.phrase, super.key, }); - final List phrase; + final String? phrase; final String? name; @override From 14a184603634737ce1796508a3d513354d0d4410 Mon Sep 17 00:00:00 2001 From: knightforce Date: Sun, 8 Sep 2024 01:07:35 +0700 Subject: [PATCH 2/7] PopScope replace onPopInvoked -> onPopInvokedWithResult + addPostFrameCallback --- android/app/src/main/AndroidManifest.xml | 3 ++- .../create_password/view/create_seed_password_page.dart | 3 +-- .../lib/components/common/default_app_bar.dart | 7 +++++-- pubspec.yaml | 2 +- 4 files changed, 9 insertions(+), 6 deletions(-) diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index c1c7b41dc..c4cc9592f 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -2,7 +2,8 @@ package="com.broxus.sparx.app"> + android:icon="@mipmap/ic_launcher" + android:enableOnBackInvokedCallback="true"> - context.goNamed(AppRoute.manageSeedsAccounts.name), + completeCallback: () => context.pop(AppRoute.profile.name), ), child: GestureDetector( onTap: () => FocusScope.of(context).unfocus(), diff --git a/packages/ui_components_lib/lib/components/common/default_app_bar.dart b/packages/ui_components_lib/lib/components/common/default_app_bar.dart index 4b8de4190..7ca19bad7 100644 --- a/packages/ui_components_lib/lib/components/common/default_app_bar.dart +++ b/packages/ui_components_lib/lib/components/common/default_app_bar.dart @@ -162,8 +162,11 @@ class DefaultAppBar extends StatelessWidget implements PreferredSizeWidget { return PopScope( canPop: false, // TODO(knightforce): use onPopInvokedWithResult - // ignore: deprecated_member_use - onPopInvoked: (_) => _onPressedBack(context), + onPopInvokedWithResult: (_, __) { + WidgetsBinding.instance.addPostFrameCallback((_) { + _onPressedBack(context); + }); + }, child: Padding( padding: const EdgeInsets.symmetric(horizontal: DimensSizeV2.d16), child: AppBar( diff --git a/pubspec.yaml b/pubspec.yaml index 43310ed6d..ada5d9a3f 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -35,7 +35,7 @@ dependencies: freezed_annotation: ^2.4.1 frontend_server_client: ^4.0.0 get_it: ^7.7.0 - go_router: ^14.0.1 + go_router: ^14.2.7 hive_flutter: ^1.1.0 http: ^1.2.1 image_picker: ^1.0.4 From cf5c280327207a95680fe92191d5a9cf372c20f1 Mon Sep 17 00:00:00 2001 From: knightforce Date: Sun, 8 Sep 2024 01:09:42 +0700 Subject: [PATCH 3/7] Remove todo --- .../ui_components_lib/lib/components/common/default_app_bar.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/ui_components_lib/lib/components/common/default_app_bar.dart b/packages/ui_components_lib/lib/components/common/default_app_bar.dart index 7ca19bad7..57bad718a 100644 --- a/packages/ui_components_lib/lib/components/common/default_app_bar.dart +++ b/packages/ui_components_lib/lib/components/common/default_app_bar.dart @@ -161,7 +161,6 @@ class DefaultAppBar extends StatelessWidget implements PreferredSizeWidget { return PopScope( canPop: false, - // TODO(knightforce): use onPopInvokedWithResult onPopInvokedWithResult: (_, __) { WidgetsBinding.instance.addPostFrameCallback((_) { _onPressedBack(context); From c8e81a0cf6c835e52a0db78419855ceca751e423 Mon Sep 17 00:00:00 2001 From: knightforce Date: Sun, 8 Sep 2024 03:16:22 +0700 Subject: [PATCH 4/7] add check didPop in onPopInvokedWithResult --- .../lib/components/common/default_app_bar.dart | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/ui_components_lib/lib/components/common/default_app_bar.dart b/packages/ui_components_lib/lib/components/common/default_app_bar.dart index 57bad718a..4592e7923 100644 --- a/packages/ui_components_lib/lib/components/common/default_app_bar.dart +++ b/packages/ui_components_lib/lib/components/common/default_app_bar.dart @@ -161,7 +161,11 @@ class DefaultAppBar extends StatelessWidget implements PreferredSizeWidget { return PopScope( canPop: false, - onPopInvokedWithResult: (_, __) { + onPopInvokedWithResult: (didPop, result) { + if (didPop) { + return; + } + WidgetsBinding.instance.addPostFrameCallback((_) { _onPressedBack(context); }); From 7c8d66d9d8fe6856923f175b8161ba5db9570387 Mon Sep 17 00:00:00 2001 From: knightforce Date: Sun, 8 Sep 2024 03:16:26 +0700 Subject: [PATCH 5/7] Fix create new seed from profile --- lib/app/router/routs/add_seed/add_seed.dart | 14 +++----- .../view/create_seed_password_page.dart | 3 +- .../cubit/check_seed_phrase_cubit.dart | 35 +++++++++++++------ .../view/check_seed_phrase_page.dart | 15 +++++--- .../create_seed/view/create_seed_page.dart | 8 ++--- .../create_seed/view/create_seed_view.dart | 6 ++-- 6 files changed, 47 insertions(+), 34 deletions(-) diff --git a/lib/app/router/routs/add_seed/add_seed.dart b/lib/app/router/routs/add_seed/add_seed.dart index fee5171ce..4b9a02e24 100644 --- a/lib/app/router/routs/add_seed/add_seed.dart +++ b/lib/app/router/routs/add_seed/add_seed.dart @@ -1,5 +1,3 @@ -import 'dart:convert'; - import 'package:app/app/router/router.dart'; import 'package:app/feature/add_seed/add_existing_wallet/view/add_existing_wallet_page.dart'; import 'package:app/feature/add_seed/add_seed_enable_biometry/view/add_seed_enable_biometry_page.dart'; @@ -24,6 +22,8 @@ const enterSeedNameNamePathParam = 'nameParam'; /// Route that allows to create a seed phrase without entering name. /// This route may be used in onboarding or profile section, depends /// on [passwordRoute]. + +// TODO(knightforce): check is used @Deprecated('Use v2 version') GoRoute createSeedNoNamedRoute(GoRoute passwordRoute) { return GoRoute( @@ -33,10 +33,7 @@ GoRoute createSeedNoNamedRoute(GoRoute passwordRoute) { GoRoute( path: AppRoute.checkSeed.path, builder: (_, state) => CheckSeedPhrasePage( - phrase: (jsonDecode( - state.uri.queryParameters[addSeedPhraseQueryParam]!, - ) as List) - .cast(), + phrase: state.uri.queryParameters[addSeedPhraseQueryParam], ), routes: [ passwordRoute, @@ -155,10 +152,7 @@ GoRoute get createSeedNamedProfileRoute { GoRoute( path: AppRoute.checkSeed.path, builder: (_, state) => CheckSeedPhrasePage( - phrase: (jsonDecode( - state.uri.queryParameters[addSeedPhraseQueryParam]!, - ) as List) - .cast(), + phrase: state.uri.queryParameters[addSeedPhraseQueryParam], ), routes: [ passwordRoute, diff --git a/lib/feature/add_seed/create_password/view/create_seed_password_page.dart b/lib/feature/add_seed/create_password/view/create_seed_password_page.dart index 59058cbad..f9e455949 100644 --- a/lib/feature/add_seed/create_password/view/create_seed_password_page.dart +++ b/lib/feature/add_seed/create_password/view/create_seed_password_page.dart @@ -28,7 +28,8 @@ class CreateSeedPasswordProfilePage extends StatelessWidget { phrase: phrase, name: name, // When we do this flow from profile, navigate to profile root - completeCallback: () => context.pop(AppRoute.profile.name), + completeCallback: () => + context.goNamed(AppRoute.manageSeedsAccounts.name), ), child: GestureDetector( onTap: () => FocusScope.of(context).unfocus(), diff --git a/lib/v1/feature/add_seed/check_seed_phrase/cubit/check_seed_phrase_cubit.dart b/lib/v1/feature/add_seed/check_seed_phrase/cubit/check_seed_phrase_cubit.dart index e5a4d403d..995c89480 100644 --- a/lib/v1/feature/add_seed/check_seed_phrase/cubit/check_seed_phrase_cubit.dart +++ b/lib/v1/feature/add_seed/check_seed_phrase/cubit/check_seed_phrase_cubit.dart @@ -8,6 +8,7 @@ import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:nekoton_repository/nekoton_repository.dart'; part 'check_seed_phrase_cubit.freezed.dart'; + part 'check_seed_phrase_state.dart'; const defaultWordsToCheckAmount = 3; @@ -20,13 +21,15 @@ const delayBeforeCompleteChecking = Duration(seconds: 1); /// [availableAnswers] list. class CheckSeedPhraseCubit extends Cubit { factory CheckSeedPhraseCubit( - List originalPhrase, - VoidCallback completeChecking, + String? originalPhrase, + ValueChanged completeChecking, ) { - final correct = _selectCorrectAnswers(originalPhrase); + final words = originalPhrase?.split(' '); + + final correct = _selectCorrectAnswers(words); return CheckSeedPhraseCubit._( - originalPhrase, + words, completeChecking, correct, correct.map((e) => e.copyWith(word: '')).toList(), @@ -34,13 +37,13 @@ class CheckSeedPhraseCubit extends Cubit { } CheckSeedPhraseCubit._( - this.originalPhrase, + this.phraseWords, this.completeChecking, this._correctAnswers, this.userAnswers, ) : super(const CheckSeedPhraseCubitState.initial()); - final List originalPhrase; + final List? phraseWords; final List _correctAnswers; late final List availableAnswers; @@ -48,7 +51,7 @@ class CheckSeedPhraseCubit extends Cubit { final List userAnswers; /// Navigate to other screen - final VoidCallback completeChecking; + final ValueChanged completeChecking; /// if null - all words selected int? currentCheckIndex = 0; @@ -111,7 +114,9 @@ class CheckSeedPhraseCubit extends Cubit { List.of(userAnswers), ), ); - Future.delayed(delayBeforeCompleteChecking, completeChecking); + Future.delayed(delayBeforeCompleteChecking, () { + completeChecking(phraseWords?.join(' ')); + }); } } @@ -136,13 +141,17 @@ class CheckSeedPhraseCubit extends Cubit { /// Correct answers for internal checks static List _selectCorrectAnswers( - List phrase, + List? phraseWords, ) { + if (phraseWords == null) { + return []; + } + final rng = Random(); final indices = []; while (indices.length < defaultWordsToCheckAmount) { - final number = rng.nextInt(phrase.length); + final number = rng.nextInt(phraseWords.length); if (indices.contains(number)) { continue; @@ -154,7 +163,11 @@ class CheckSeedPhraseCubit extends Cubit { indices.sort(); return [ - for (final index in indices) CheckSeedCorrectAnswer(phrase[index], index), + for (final index in indices) + CheckSeedCorrectAnswer( + phraseWords[index], + index, + ), ]; } diff --git a/lib/v1/feature/add_seed/check_seed_phrase/view/check_seed_phrase_page.dart b/lib/v1/feature/add_seed/check_seed_phrase/view/check_seed_phrase_page.dart index dddf40470..83315f2a5 100644 --- a/lib/v1/feature/add_seed/check_seed_phrase/view/check_seed_phrase_page.dart +++ b/lib/v1/feature/add_seed/check_seed_phrase/view/check_seed_phrase_page.dart @@ -1,4 +1,5 @@ import 'package:app/app/router/app_route.dart'; +import 'package:app/app/router/routs/add_seed/add_seed.dart'; import 'package:app/generated/generated.dart'; import 'package:app/v1/feature/add_seed/check_seed_phrase/check_seed_phrase.dart'; import 'package:flutter/material.dart'; @@ -15,17 +16,21 @@ class CheckSeedPhrasePage extends StatelessWidget { super.key, }); - final List phrase; + final String? phrase; - void _navigateToPassword(BuildContext context) => - context.goFurther(AppRoute.createSeedPassword.path); + void _navigateToPassword(BuildContext context, String? phrase) => + context.goFurther(AppRoute.createSeedPassword.pathWithData( + queryParameters: { + if (phrase != null) addSeedPhraseQueryParam: phrase, + }, + )); @override Widget build(BuildContext context) { return BlocProvider( create: (context) => CheckSeedPhraseCubit( phrase, - () => _navigateToPassword(context), + (String? phrase) => _navigateToPassword(context, phrase), )..initAnswers(), child: Scaffold( appBar: DefaultAppBar( @@ -34,7 +39,7 @@ class CheckSeedPhrasePage extends StatelessWidget { CommonButton.ghost( padding: EdgeInsets.zero, text: LocaleKeys.skipWord.tr(), - onPressed: () => _navigateToPassword(context), + onPressed: () => _navigateToPassword(context, phrase), ), ], ), diff --git a/lib/v1/feature/add_seed/create_seed/view/create_seed_page.dart b/lib/v1/feature/add_seed/create_seed/view/create_seed_page.dart index 416865020..6ab799dba 100644 --- a/lib/v1/feature/add_seed/create_seed/view/create_seed_page.dart +++ b/lib/v1/feature/add_seed/create_seed/view/create_seed_page.dart @@ -22,19 +22,19 @@ class CreateSeedPage extends StatelessWidget { appBar: const DefaultAppBar(), body: CreateSeedView( // ignore: prefer-extracting-callbacks - checkCallback: (List phrase) { + checkCallback: (String phrase) { context.goFurther( AppRoute.checkSeed.pathWithData( - queryParameters: {addSeedPhraseQueryParam: jsonEncode(phrase)}, + queryParameters: {addSeedPhraseQueryParam: phrase}, ), preserveQueryParams: true, ); }, // ignore: prefer-extracting-callbacks - skipCallback: (List phrase) { + skipCallback: (String phrase) { context.goFurther( AppRoute.createSeedPassword.pathWithData( - queryParameters: {addSeedPhraseQueryParam: jsonEncode(phrase)}, + queryParameters: {addSeedPhraseQueryParam: phrase}, ), preserveQueryParams: true, ); diff --git a/lib/v1/feature/add_seed/create_seed/view/create_seed_view.dart b/lib/v1/feature/add_seed/create_seed/view/create_seed_view.dart index 0ed5dd04d..1b79f2c6a 100644 --- a/lib/v1/feature/add_seed/create_seed/view/create_seed_view.dart +++ b/lib/v1/feature/add_seed/create_seed/view/create_seed_view.dart @@ -8,7 +8,7 @@ import 'package:ui_components_lib/ui_components_lib.dart'; import 'package:ui_components_lib/v2/ui_components_lib_v2.dart'; /// Callback that calls if user taps skip checking or check phrase. -typedef CreateSeedCompleteCallback = void Function(List phrase); +typedef CreateSeedCompleteCallback = void Function(String phrase); /// {@template create_seed_view} /// Widget that allows user to create random seed phrase, copy it and check @@ -83,13 +83,13 @@ class CreateSeedView extends StatelessWidget { AccentButton( buttonShape: ButtonShape.pill, title: LocaleKeys.checkSeedPhrase.tr(), - onPressed: () => checkCallback(words), + onPressed: () => checkCallback(words.join(' ')), ), const SizedBox(height: DimensSizeV2.d8), PrimaryButton( buttonShape: ButtonShape.pill, title: LocaleKeys.skipTakeRisk.tr(), - onPressed: () => skipCallback(words), + onPressed: () => skipCallback(words.join(' ')), ), const SizedBox(height: DimensSizeV2.d12), ], From 5510a119b2f6630b779ce7337244677437f63865 Mon Sep 17 00:00:00 2001 From: knightforce Date: Sun, 8 Sep 2024 03:18:45 +0700 Subject: [PATCH 6/7] Fix analyzer issue --- lib/feature/profile/view/profile_view.dart | 1 - .../view/check_seed_phrase_page.dart | 12 +++++++----- .../add_seed/create_seed/view/create_seed_page.dart | 2 -- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/lib/feature/profile/view/profile_view.dart b/lib/feature/profile/view/profile_view.dart index 9ce75b3de..0a3426343 100644 --- a/lib/feature/profile/view/profile_view.dart +++ b/lib/feature/profile/view/profile_view.dart @@ -2,7 +2,6 @@ import 'package:app/app/router/app_route.dart'; import 'package:app/app/service/service.dart'; import 'package:app/di/di.dart'; import 'package:app/feature/contact_support/contact_support.dart'; -import 'package:app/feature/localization/localization.dart'; import 'package:app/feature/profile/profile.dart'; import 'package:app/generated/assets.gen.dart'; import 'package:app/generated/locale_keys.g.dart'; diff --git a/lib/v1/feature/add_seed/check_seed_phrase/view/check_seed_phrase_page.dart b/lib/v1/feature/add_seed/check_seed_phrase/view/check_seed_phrase_page.dart index 83315f2a5..9032a14aa 100644 --- a/lib/v1/feature/add_seed/check_seed_phrase/view/check_seed_phrase_page.dart +++ b/lib/v1/feature/add_seed/check_seed_phrase/view/check_seed_phrase_page.dart @@ -19,11 +19,13 @@ class CheckSeedPhrasePage extends StatelessWidget { final String? phrase; void _navigateToPassword(BuildContext context, String? phrase) => - context.goFurther(AppRoute.createSeedPassword.pathWithData( - queryParameters: { - if (phrase != null) addSeedPhraseQueryParam: phrase, - }, - )); + context.goFurther( + AppRoute.createSeedPassword.pathWithData( + queryParameters: { + if (phrase != null) addSeedPhraseQueryParam: phrase, + }, + ), + ); @override Widget build(BuildContext context) { diff --git a/lib/v1/feature/add_seed/create_seed/view/create_seed_page.dart b/lib/v1/feature/add_seed/create_seed/view/create_seed_page.dart index 6ab799dba..6f1e6ecff 100644 --- a/lib/v1/feature/add_seed/create_seed/view/create_seed_page.dart +++ b/lib/v1/feature/add_seed/create_seed/view/create_seed_page.dart @@ -1,5 +1,3 @@ -import 'dart:convert'; - import 'package:app/app/router/router.dart'; import 'package:app/v1/feature/add_seed/create_seed/create_seed.dart'; import 'package:flutter/material.dart'; From 26c6e193f910bfa8fe0cd3329dbc6dbcb095790a Mon Sep 17 00:00:00 2001 From: knightforce Date: Sun, 8 Sep 2024 04:46:26 +0700 Subject: [PATCH 7/7] SeedPhraseModel --- lib/app/router/routs/add_seed/add_seed.dart | 29 ++++++--- lib/data/models/seed/seed_phrase_model.dart | 22 +++++++ .../cubit/create_seed_password_cubit.dart | 9 +-- .../create_seed_password_screen.dart | 3 +- .../create_seed_password_screen_model.dart | 17 ++++-- .../create_seed_password_screen_wm.dart | 3 +- .../view/create_seed_password_page.dart | 7 ++- .../data/import_wallet_data.dart | 10 ++-- .../import_wallet_widget_model.dart | 40 +++++++------ .../cubit/check_seed_phrase_cubit.dart | 27 ++++----- .../view/check_seed_phrase_page.dart | 15 ++--- .../create_seed/cubit/create_seed_cubit.dart | 11 +++- .../cubit/create_seed_cubit.freezed.dart | 59 ++++++++----------- .../create_seed/cubit/create_seed_state.dart | 2 +- .../create_seed/view/create_seed_page.dart | 9 +-- .../create_seed/view/create_seed_view.dart | 27 +++++---- 16 files changed, 171 insertions(+), 119 deletions(-) create mode 100644 lib/data/models/seed/seed_phrase_model.dart diff --git a/lib/app/router/routs/add_seed/add_seed.dart b/lib/app/router/routs/add_seed/add_seed.dart index 4b9a02e24..caac421cf 100644 --- a/lib/app/router/routs/add_seed/add_seed.dart +++ b/lib/app/router/routs/add_seed/add_seed.dart @@ -1,4 +1,5 @@ import 'package:app/app/router/router.dart'; +import 'package:app/data/models/seed/seed_phrase_model.dart'; import 'package:app/feature/add_seed/add_existing_wallet/view/add_existing_wallet_page.dart'; import 'package:app/feature/add_seed/add_seed_enable_biometry/view/add_seed_enable_biometry_page.dart'; import 'package:app/feature/add_seed/create_password/screens/create_seed_password/create_seed_password_screen.dart'; @@ -33,7 +34,9 @@ GoRoute createSeedNoNamedRoute(GoRoute passwordRoute) { GoRoute( path: AppRoute.checkSeed.path, builder: (_, state) => CheckSeedPhrasePage( - phrase: state.uri.queryParameters[addSeedPhraseQueryParam], + seed: SeedPhraseModel( + state.uri.queryParameters[addSeedPhraseQueryParam], + ), ), routes: [ passwordRoute, @@ -90,7 +93,9 @@ GoRoute get createOnboardingSeedPasswordRoute { path: AppRoute.createSeedPassword.path, builder: (_, GoRouterState state) { return CreateSeedPasswordScreen( - phrase: state.uri.queryParameters[addSeedPhraseQueryParam], + phrase: SeedPhraseModel( + state.uri.queryParameters[addSeedPhraseQueryParam], + ), ); }, routes: [ @@ -113,7 +118,9 @@ GoRoute get createSeedNoNamedProfileRoute { GoRoute( path: AppRoute.createSeedPassword.path, builder: (_, state) => CreateSeedPasswordProfilePage( - phrase: state.uri.queryParameters[addSeedPhraseQueryParam], + seedPhrase: SeedPhraseModel( + state.uri.queryParameters[addSeedPhraseQueryParam], + ), name: state.pathParameters[enterSeedNameNamePathParam], ), ), @@ -126,7 +133,9 @@ GoRoute get enterSeedNoNamedProfileRoute { GoRoute( path: AppRoute.createSeedPassword.path, builder: (_, GoRouterState state) => CreateSeedPasswordProfilePage( - phrase: state.uri.queryParameters[addSeedPhraseQueryParam], + seedPhrase: SeedPhraseModel( + state.uri.queryParameters[addSeedPhraseQueryParam], + ), name: state.pathParameters[enterSeedNameNamePathParam], ), ), @@ -140,7 +149,9 @@ GoRoute get createSeedNamedProfileRoute { final passwordRoute = GoRoute( path: AppRoute.createSeedPassword.path, builder: (_, GoRouterState state) => CreateSeedPasswordProfilePage( - phrase: state.uri.queryParameters[addSeedPhraseQueryParam], + seedPhrase: SeedPhraseModel( + state.uri.queryParameters[addSeedPhraseQueryParam], + ), name: state.pathParameters[enterSeedNameNamePathParam], ), ); @@ -152,7 +163,9 @@ GoRoute get createSeedNamedProfileRoute { GoRoute( path: AppRoute.checkSeed.path, builder: (_, state) => CheckSeedPhrasePage( - phrase: state.uri.queryParameters[addSeedPhraseQueryParam], + seed: SeedPhraseModel( + state.uri.queryParameters[addSeedPhraseQueryParam], + ), ), routes: [ passwordRoute, @@ -175,7 +188,9 @@ GoRoute get enterSeedNamedProfileRoute { path: AppRoute.createSeedPassword.path, builder: (_, GoRouterState state) { return CreateSeedPasswordProfilePage( - phrase: state.uri.queryParameters[addSeedPhraseQueryParam], + seedPhrase: SeedPhraseModel( + state.uri.queryParameters[addSeedPhraseQueryParam], + ), name: state.pathParameters[enterSeedNameNamePathParam], ); }, diff --git a/lib/data/models/seed/seed_phrase_model.dart b/lib/data/models/seed/seed_phrase_model.dart new file mode 100644 index 000000000..6f495370b --- /dev/null +++ b/lib/data/models/seed/seed_phrase_model.dart @@ -0,0 +1,22 @@ +class SeedPhraseModel { + SeedPhraseModel(String? phrase) : phrase = phrase ?? '' { + _words = null; + } + + SeedPhraseModel.fromWords(List list) { + phrase = list.join(' '); + _words = list; + } + + SeedPhraseModel.empty() : this(null); + + late final String phrase; + late final List words = _words ?? phrase.split(' '); + + late final wordsCount = words.length; + + late final isEmpty = phrase.isEmpty; + late final isNotEmpty = !isEmpty; + + late final List? _words; +} diff --git a/lib/feature/add_seed/create_password/cubit/create_seed_password_cubit.dart b/lib/feature/add_seed/create_password/cubit/create_seed_password_cubit.dart index e1c636439..f1f2248ff 100644 --- a/lib/feature/add_seed/create_password/cubit/create_seed_password_cubit.dart +++ b/lib/feature/add_seed/create_password/cubit/create_seed_password_cubit.dart @@ -1,5 +1,6 @@ import 'package:app/app/service/network_connection/network_connection_service.dart'; import 'package:app/app/service/service.dart'; +import 'package:app/data/models/seed/seed_phrase_model.dart'; import 'package:app/di/di.dart'; import 'package:app/feature/add_seed/create_password/model/password_status.dart'; import 'package:app/utils/mixins/connection_mixin.dart'; @@ -20,7 +21,7 @@ class CreateSeedPasswordCubit extends Cubit with ConnectionMixin { CreateSeedPasswordCubit({ required this.completeCallback, - this.phrase, + required this.seedPhrase, this.setCurrentKey = false, this.name, }) : super(CreateSeedPasswordState.initial()) { @@ -32,7 +33,7 @@ class CreateSeedPasswordCubit extends Cubit final VoidCallback completeCallback; /// Phrase that must be used to create seed - final String? phrase; + final SeedPhraseModel seedPhrase; /// Name of seed phrase if provided final String? name; @@ -67,7 +68,7 @@ class CreateSeedPasswordCubit extends Cubit } Future nextAction() async { - if (phrase == null || !await checkConnection()) { + if (seedPhrase.isEmpty || !await checkConnection()) { return; } @@ -76,7 +77,7 @@ class CreateSeedPasswordCubit extends Cubit final currentKeyService = inject(); try { final publicKey = await nekoton.addSeed( - phrase: phrase!.split(' '), + phrase: seedPhrase.words, password: passwordController.text, name: name, ); diff --git a/lib/feature/add_seed/create_password/screens/create_seed_password/create_seed_password_screen.dart b/lib/feature/add_seed/create_password/screens/create_seed_password/create_seed_password_screen.dart index 76c254f4b..ab50eb825 100644 --- a/lib/feature/add_seed/create_password/screens/create_seed_password/create_seed_password_screen.dart +++ b/lib/feature/add_seed/create_password/screens/create_seed_password/create_seed_password_screen.dart @@ -1,3 +1,4 @@ +import 'package:app/data/models/seed/seed_phrase_model.dart'; import 'package:app/feature/add_seed/create_password/model/password_status.dart'; import 'package:app/feature/add_seed/create_password/screens/create_seed_password/create_seed_password_screen_wm.dart'; import 'package:app/feature/add_seed/create_password/view/create_seed_password_view.dart'; @@ -15,7 +16,7 @@ class CreateSeedPasswordScreen CreateSeedPasswordScreen({ Key? key, WidgetModelFactory? wmFactory, - String? phrase, + SeedPhraseModel? phrase, }) : super( wmFactory ?? (context) => defaultCreateSeedPasswordScreenWidgetModelFactory( diff --git a/lib/feature/add_seed/create_password/screens/create_seed_password/create_seed_password_screen_model.dart b/lib/feature/add_seed/create_password/screens/create_seed_password/create_seed_password_screen_model.dart index f52662bab..6e2dab9ce 100644 --- a/lib/feature/add_seed/create_password/screens/create_seed_password/create_seed_password_screen_model.dart +++ b/lib/feature/add_seed/create_password/screens/create_seed_password/create_seed_password_screen_model.dart @@ -2,6 +2,7 @@ import 'package:app/app/service/biometry_service.dart'; import 'package:app/app/service/messenger/message.dart'; import 'package:app/app/service/messenger/service/messenger_service.dart'; import 'package:app/app/service/nekoton_related/current_key_service.dart'; +import 'package:app/data/models/seed/seed_phrase_model.dart'; import 'package:app/feature/add_seed/create_password/screens/create_seed_password/create_seed_password_screen.dart'; import 'package:app/feature/constants.dart'; import 'package:elementary/elementary.dart'; @@ -23,16 +24,22 @@ class CreateSeedPasswordScreenModel extends ElementaryModel { final CurrentKeyService _currentKeyService; final MessengerService _messengerService; final NekotonRepository _nekotonRepository; - final String? _phrase; + final SeedPhraseModel? _phrase; Future next({ required String password, }) async { + late SeedPhraseModel seed; + try { - final phrase = _phrase?.split(' ') ?? await _createSeed(); + if (_phrase?.isNotEmpty ?? false) { + seed = _phrase!; + } else { + seed = await _createSeed(); + } final publicKey = await _nekotonRepository.addSeed( - phrase: phrase, + phrase: seed.words, password: password, ); @@ -48,8 +55,8 @@ class CreateSeedPasswordScreenModel extends ElementaryModel { } } - Future> _createSeed() async { + Future _createSeed() async { final seed = await generateKey(accountType: defaultMnemonicType); - return seed.words; + return SeedPhraseModel.fromWords(seed.words); } } diff --git a/lib/feature/add_seed/create_password/screens/create_seed_password/create_seed_password_screen_wm.dart b/lib/feature/add_seed/create_password/screens/create_seed_password/create_seed_password_screen_wm.dart index 8761af37b..4c5711a6a 100644 --- a/lib/feature/add_seed/create_password/screens/create_seed_password/create_seed_password_screen_wm.dart +++ b/lib/feature/add_seed/create_password/screens/create_seed_password/create_seed_password_screen_wm.dart @@ -2,6 +2,7 @@ import 'package:app/app/router/routs/add_seed/add_seed.dart'; import 'package:app/core/error_handler_factory.dart'; import 'package:app/core/wm/custom_wm.dart'; import 'package:app/core/wm/navigation_wm_mixin.dart'; +import 'package:app/data/models/seed/seed_phrase_model.dart'; import 'package:app/di/di.dart'; import 'package:app/feature/add_seed/create_password/model/password_status.dart'; import 'package:app/feature/add_seed/create_password/screens/create_seed_password/create_seed_password_screen.dart'; @@ -15,7 +16,7 @@ import 'package:ui_components_lib/v2/ui_components_lib_v2.dart'; CreateSeedPasswordScreenWidgetModel defaultCreateSeedPasswordScreenWidgetModelFactory( BuildContext context, { - String? phrase, + SeedPhraseModel? phrase, }) { return CreateSeedPasswordScreenWidgetModel( CreateSeedPasswordScreenModel( diff --git a/lib/feature/add_seed/create_password/view/create_seed_password_page.dart b/lib/feature/add_seed/create_password/view/create_seed_password_page.dart index f9e455949..060576853 100644 --- a/lib/feature/add_seed/create_password/view/create_seed_password_page.dart +++ b/lib/feature/add_seed/create_password/view/create_seed_password_page.dart @@ -1,4 +1,5 @@ import 'package:app/app/router/app_route.dart'; +import 'package:app/data/models/seed/seed_phrase_model.dart'; import 'package:app/feature/add_seed/create_password/create_password.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; @@ -14,18 +15,18 @@ class CreateSeedPasswordProfilePage extends StatelessWidget { /// {@macro create_seed_password_profile_page} const CreateSeedPasswordProfilePage({ required this.name, - this.phrase, + required this.seedPhrase, super.key, }); - final String? phrase; + final SeedPhraseModel seedPhrase; final String? name; @override Widget build(BuildContext context) { return BlocProvider( create: (context) => CreateSeedPasswordCubit( - phrase: phrase, + seedPhrase: seedPhrase, name: name, // When we do this flow from profile, navigate to profile root completeCallback: () => diff --git a/lib/feature/add_seed/import_wallet/data/import_wallet_data.dart b/lib/feature/add_seed/import_wallet/data/import_wallet_data.dart index 73183de98..59eea93c0 100644 --- a/lib/feature/add_seed/import_wallet/data/import_wallet_data.dart +++ b/lib/feature/add_seed/import_wallet/data/import_wallet_data.dart @@ -1,9 +1,11 @@ +import 'package:app/data/models/seed/seed_phrase_model.dart'; + class ImportWalletData { ImportWalletData({ this.isPasted, this.allowedData, this.selectedValue, - this.words, + this.seed, this.firstColumnWords, this.secondColumnWords, }); @@ -11,7 +13,7 @@ class ImportWalletData { final bool? isPasted; final List? allowedData; final int? selectedValue; - final List? words; + final SeedPhraseModel? seed; final List? firstColumnWords; final List? secondColumnWords; @@ -19,7 +21,7 @@ class ImportWalletData { bool? isPasted, List? allowedData, int? selectedValue, - List? words, + SeedPhraseModel? seed, List? firstColumnWords, List? secondColumnWords, }) { @@ -27,7 +29,7 @@ class ImportWalletData { isPasted: isPasted ?? this.isPasted, allowedData: allowedData ?? this.allowedData, selectedValue: selectedValue ?? this.selectedValue, - words: words, + seed: seed, firstColumnWords: firstColumnWords, secondColumnWords: secondColumnWords, ); diff --git a/lib/feature/add_seed/import_wallet/import_wallet_widget_model.dart b/lib/feature/add_seed/import_wallet/import_wallet_widget_model.dart index 4fe3f3f2b..082bd4e54 100644 --- a/lib/feature/add_seed/import_wallet/import_wallet_widget_model.dart +++ b/lib/feature/add_seed/import_wallet/import_wallet_widget_model.dart @@ -1,6 +1,7 @@ import 'package:app/app/router/app_route.dart'; import 'package:app/app/router/routs/add_seed/add_seed.dart'; import 'package:app/core/wm/custom_wm.dart'; +import 'package:app/data/models/seed/seed_phrase_model.dart'; import 'package:app/di/di.dart'; import 'package:app/feature/add_seed/import_wallet/data/import_wallet_data.dart'; import 'package:app/feature/add_seed/import_wallet/import_wallet_screen.dart'; @@ -49,10 +50,10 @@ class ImportWalletScreenWidgetModel try { FocusManager.instance.primaryFocus?.unfocus(); - final words = screenState.value.data?.words; + final seed = screenState.value.data?.seed; - if (words != null && words.isNotEmpty) { - final phrase = words.join(' '); + if (seed != null && seed.isNotEmpty) { + final phrase = seed.phrase; final mnemonicType = _currentValue == _legacySeedPhraseLength ? const MnemonicType.legacy() @@ -93,32 +94,33 @@ class ImportWalletScreenWidgetModel Future pasteWords() async { final clipboard = await Clipboard.getData(Clipboard.kTextPlain); - final words = clipboard?.text - ?.replaceAll(RegExp(r'\\s+'), ' ') - .split(seedSplitRegExp) ?? - []; - if (words.isNotEmpty) { - for (final word in words) { + var seed = SeedPhraseModel.fromWords( + clipboard?.text + ?.replaceAll(RegExp(r'\\s+'), ' ') + .split(seedSplitRegExp) ?? + [], + ); + + if (seed.isNotEmpty) { + for (final word in seed.words) { if (!await _isWordValid(word)) { - words.clear(); + seed = SeedPhraseModel.empty(); break; } } - } else { - words.clear(); } - if (words.isEmpty) { + if (seed.isEmpty) { model.showValidateError(LocaleKeys.incorrectWordsFormat.tr()); return; } else { - final halfLength = (words.length / 2).floor(); + final halfLength = (seed.wordsCount / 2).floor(); - final firstColumnWords = words.sublist(0, halfLength); - final secondColumnWords = words.sublist(halfLength); + final firstColumnWords = seed.words.sublist(0, halfLength); + final secondColumnWords = seed.words.sublist(halfLength); _updateState( isPasted: true, - words: words, + seed: seed, firstColumnWords: firstColumnWords, secondColumnWords: secondColumnWords, ); @@ -151,7 +153,7 @@ class ImportWalletScreenWidgetModel bool? isPasted, List? allowedValues, int? selectedValue, - List? words, + SeedPhraseModel? seed, List? firstColumnWords, List? secondColumnWords, }) { @@ -160,7 +162,7 @@ class ImportWalletScreenWidgetModel isPasted: isPasted, allowedData: allowedValues, selectedValue: selectedValue, - words: words, + seed: seed, firstColumnWords: firstColumnWords, secondColumnWords: secondColumnWords, ), diff --git a/lib/v1/feature/add_seed/check_seed_phrase/cubit/check_seed_phrase_cubit.dart b/lib/v1/feature/add_seed/check_seed_phrase/cubit/check_seed_phrase_cubit.dart index 995c89480..f45a518f1 100644 --- a/lib/v1/feature/add_seed/check_seed_phrase/cubit/check_seed_phrase_cubit.dart +++ b/lib/v1/feature/add_seed/check_seed_phrase/cubit/check_seed_phrase_cubit.dart @@ -1,5 +1,6 @@ import 'dart:math'; +import 'package:app/data/models/seed/seed_phrase_model.dart'; import 'package:app/v1/feature/add_seed/check_seed_phrase/cubit/cubit.dart'; import 'package:bloc/bloc.dart'; import 'package:collection/collection.dart'; @@ -21,15 +22,13 @@ const delayBeforeCompleteChecking = Duration(seconds: 1); /// [availableAnswers] list. class CheckSeedPhraseCubit extends Cubit { factory CheckSeedPhraseCubit( - String? originalPhrase, - ValueChanged completeChecking, + SeedPhraseModel seed, + ValueChanged completeChecking, ) { - final words = originalPhrase?.split(' '); - - final correct = _selectCorrectAnswers(words); + final correct = _selectCorrectAnswers(seed); return CheckSeedPhraseCubit._( - words, + seed, completeChecking, correct, correct.map((e) => e.copyWith(word: '')).toList(), @@ -37,13 +36,13 @@ class CheckSeedPhraseCubit extends Cubit { } CheckSeedPhraseCubit._( - this.phraseWords, + this.seed, this.completeChecking, this._correctAnswers, this.userAnswers, ) : super(const CheckSeedPhraseCubitState.initial()); - final List? phraseWords; + final SeedPhraseModel seed; final List _correctAnswers; late final List availableAnswers; @@ -51,7 +50,7 @@ class CheckSeedPhraseCubit extends Cubit { final List userAnswers; /// Navigate to other screen - final ValueChanged completeChecking; + final ValueChanged completeChecking; /// if null - all words selected int? currentCheckIndex = 0; @@ -115,7 +114,7 @@ class CheckSeedPhraseCubit extends Cubit { ), ); Future.delayed(delayBeforeCompleteChecking, () { - completeChecking(phraseWords?.join(' ')); + completeChecking(seed); }); } } @@ -141,9 +140,9 @@ class CheckSeedPhraseCubit extends Cubit { /// Correct answers for internal checks static List _selectCorrectAnswers( - List? phraseWords, + SeedPhraseModel seed, ) { - if (phraseWords == null) { + if (seed.isEmpty) { return []; } @@ -151,7 +150,7 @@ class CheckSeedPhraseCubit extends Cubit { final indices = []; while (indices.length < defaultWordsToCheckAmount) { - final number = rng.nextInt(phraseWords.length); + final number = rng.nextInt(seed.wordsCount); if (indices.contains(number)) { continue; @@ -165,7 +164,7 @@ class CheckSeedPhraseCubit extends Cubit { return [ for (final index in indices) CheckSeedCorrectAnswer( - phraseWords[index], + seed.words[index], index, ), ]; diff --git a/lib/v1/feature/add_seed/check_seed_phrase/view/check_seed_phrase_page.dart b/lib/v1/feature/add_seed/check_seed_phrase/view/check_seed_phrase_page.dart index 9032a14aa..7b79f6557 100644 --- a/lib/v1/feature/add_seed/check_seed_phrase/view/check_seed_phrase_page.dart +++ b/lib/v1/feature/add_seed/check_seed_phrase/view/check_seed_phrase_page.dart @@ -1,5 +1,6 @@ import 'package:app/app/router/app_route.dart'; import 'package:app/app/router/routs/add_seed/add_seed.dart'; +import 'package:app/data/models/seed/seed_phrase_model.dart'; import 'package:app/generated/generated.dart'; import 'package:app/v1/feature/add_seed/check_seed_phrase/check_seed_phrase.dart'; import 'package:flutter/material.dart'; @@ -12,17 +13,17 @@ import 'package:ui_components_lib/ui_components_lib.dart'; class CheckSeedPhrasePage extends StatelessWidget { /// {@macro check_seed_phrase_page} const CheckSeedPhrasePage({ - required this.phrase, + required this.seed, super.key, }); - final String? phrase; + final SeedPhraseModel seed; - void _navigateToPassword(BuildContext context, String? phrase) => + void _navigateToPassword(BuildContext context, SeedPhraseModel? seed) => context.goFurther( AppRoute.createSeedPassword.pathWithData( queryParameters: { - if (phrase != null) addSeedPhraseQueryParam: phrase, + if (seed != null) addSeedPhraseQueryParam: seed.phrase, }, ), ); @@ -31,8 +32,8 @@ class CheckSeedPhrasePage extends StatelessWidget { Widget build(BuildContext context) { return BlocProvider( create: (context) => CheckSeedPhraseCubit( - phrase, - (String? phrase) => _navigateToPassword(context, phrase), + seed, + (SeedPhraseModel seed) => _navigateToPassword(context, seed), )..initAnswers(), child: Scaffold( appBar: DefaultAppBar( @@ -41,7 +42,7 @@ class CheckSeedPhrasePage extends StatelessWidget { CommonButton.ghost( padding: EdgeInsets.zero, text: LocaleKeys.skipWord.tr(), - onPressed: () => _navigateToPassword(context, phrase), + onPressed: () => _navigateToPassword(context, seed), ), ], ), diff --git a/lib/v1/feature/add_seed/create_seed/cubit/create_seed_cubit.dart b/lib/v1/feature/add_seed/create_seed/cubit/create_seed_cubit.dart index 78b3afc7b..f395d2986 100644 --- a/lib/v1/feature/add_seed/create_seed/cubit/create_seed_cubit.dart +++ b/lib/v1/feature/add_seed/create_seed/cubit/create_seed_cubit.dart @@ -1,3 +1,4 @@ +import 'package:app/data/models/seed/seed_phrase_model.dart'; import 'package:app/v1/feature/add_seed/constants.dart'; import 'package:bloc/bloc.dart'; import 'package:flutter/services.dart'; @@ -5,6 +6,7 @@ import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:nekoton_repository/nekoton_repository.dart'; part 'create_seed_cubit.freezed.dart'; + part 'create_seed_state.dart'; /// Cubit that helps generating seed phrase. @@ -13,7 +15,12 @@ class CreateSeedCubit extends Cubit { Future init() async { final seed = await generateKey(accountType: defaultMnemonicType); - emit(CreateSeedCubitState.generated(words: seed.words, isCopied: false)); + emit( + CreateSeedCubitState.generated( + seed: SeedPhraseModel.fromWords(seed.words), + isCopied: false, + ), + ); } Future copySeed() async { @@ -21,7 +28,7 @@ class CreateSeedCubit extends Cubit { if (st is _$GeneratedImpl) { emit(st.copyWith(isCopied: true)); await Clipboard.setData( - ClipboardData(text: st.words.join(' ')), + ClipboardData(text: st.seed.phrase), ); Future.delayed(const Duration(seconds: 2), () { emit(st.copyWith(isCopied: false)); diff --git a/lib/v1/feature/add_seed/create_seed/cubit/create_seed_cubit.freezed.dart b/lib/v1/feature/add_seed/create_seed/cubit/create_seed_cubit.freezed.dart index e19833b87..f0887ad6b 100644 --- a/lib/v1/feature/add_seed/create_seed/cubit/create_seed_cubit.freezed.dart +++ b/lib/v1/feature/add_seed/create_seed/cubit/create_seed_cubit.freezed.dart @@ -19,19 +19,19 @@ mixin _$CreateSeedCubitState { @optionalTypeArgs TResult when({ required TResult Function() initial, - required TResult Function(List words, bool isCopied) generated, + required TResult Function(SeedPhraseModel seed, bool isCopied) generated, }) => throw _privateConstructorUsedError; @optionalTypeArgs TResult? whenOrNull({ TResult? Function()? initial, - TResult? Function(List words, bool isCopied)? generated, + TResult? Function(SeedPhraseModel seed, bool isCopied)? generated, }) => throw _privateConstructorUsedError; @optionalTypeArgs TResult maybeWhen({ TResult Function()? initial, - TResult Function(List words, bool isCopied)? generated, + TResult Function(SeedPhraseModel seed, bool isCopied)? generated, required TResult orElse(), }) => throw _privateConstructorUsedError; @@ -120,7 +120,7 @@ class _$InitialImpl implements _Initial { @optionalTypeArgs TResult when({ required TResult Function() initial, - required TResult Function(List words, bool isCopied) generated, + required TResult Function(SeedPhraseModel seed, bool isCopied) generated, }) { return initial(); } @@ -129,7 +129,7 @@ class _$InitialImpl implements _Initial { @optionalTypeArgs TResult? whenOrNull({ TResult? Function()? initial, - TResult? Function(List words, bool isCopied)? generated, + TResult? Function(SeedPhraseModel seed, bool isCopied)? generated, }) { return initial?.call(); } @@ -138,7 +138,7 @@ class _$InitialImpl implements _Initial { @optionalTypeArgs TResult maybeWhen({ TResult Function()? initial, - TResult Function(List words, bool isCopied)? generated, + TResult Function(SeedPhraseModel seed, bool isCopied)? generated, required TResult orElse(), }) { if (initial != null) { @@ -189,7 +189,7 @@ abstract class _$$GeneratedImplCopyWith<$Res> { _$GeneratedImpl value, $Res Function(_$GeneratedImpl) then) = __$$GeneratedImplCopyWithImpl<$Res>; @useResult - $Res call({List words, bool isCopied}); + $Res call({SeedPhraseModel seed, bool isCopied}); } /// @nodoc @@ -205,14 +205,14 @@ class __$$GeneratedImplCopyWithImpl<$Res> @pragma('vm:prefer-inline') @override $Res call({ - Object? words = null, + Object? seed = null, Object? isCopied = null, }) { return _then(_$GeneratedImpl( - words: null == words - ? _value._words - : words // ignore: cast_nullable_to_non_nullable - as List, + seed: null == seed + ? _value.seed + : seed // ignore: cast_nullable_to_non_nullable + as SeedPhraseModel, isCopied: null == isCopied ? _value.isCopied : isCopied // ignore: cast_nullable_to_non_nullable @@ -224,24 +224,16 @@ class __$$GeneratedImplCopyWithImpl<$Res> /// @nodoc class _$GeneratedImpl implements _Generated { - const _$GeneratedImpl( - {required final List words, required this.isCopied}) - : _words = words; + const _$GeneratedImpl({required this.seed, required this.isCopied}); - final List _words; @override - List get words { - if (_words is EqualUnmodifiableListView) return _words; - // ignore: implicit_dynamic_type - return EqualUnmodifiableListView(_words); - } - + final SeedPhraseModel seed; @override final bool isCopied; @override String toString() { - return 'CreateSeedCubitState.generated(words: $words, isCopied: $isCopied)'; + return 'CreateSeedCubitState.generated(seed: $seed, isCopied: $isCopied)'; } @override @@ -249,14 +241,13 @@ class _$GeneratedImpl implements _Generated { return identical(this, other) || (other.runtimeType == runtimeType && other is _$GeneratedImpl && - const DeepCollectionEquality().equals(other._words, _words) && + (identical(other.seed, seed) || other.seed == seed) && (identical(other.isCopied, isCopied) || other.isCopied == isCopied)); } @override - int get hashCode => Object.hash( - runtimeType, const DeepCollectionEquality().hash(_words), isCopied); + int get hashCode => Object.hash(runtimeType, seed, isCopied); /// Create a copy of CreateSeedCubitState /// with the given fields replaced by the non-null parameter values. @@ -270,29 +261,29 @@ class _$GeneratedImpl implements _Generated { @optionalTypeArgs TResult when({ required TResult Function() initial, - required TResult Function(List words, bool isCopied) generated, + required TResult Function(SeedPhraseModel seed, bool isCopied) generated, }) { - return generated(words, isCopied); + return generated(seed, isCopied); } @override @optionalTypeArgs TResult? whenOrNull({ TResult? Function()? initial, - TResult? Function(List words, bool isCopied)? generated, + TResult? Function(SeedPhraseModel seed, bool isCopied)? generated, }) { - return generated?.call(words, isCopied); + return generated?.call(seed, isCopied); } @override @optionalTypeArgs TResult maybeWhen({ TResult Function()? initial, - TResult Function(List words, bool isCopied)? generated, + TResult Function(SeedPhraseModel seed, bool isCopied)? generated, required TResult orElse(), }) { if (generated != null) { - return generated(words, isCopied); + return generated(seed, isCopied); } return orElse(); } @@ -331,10 +322,10 @@ class _$GeneratedImpl implements _Generated { abstract class _Generated implements CreateSeedCubitState { const factory _Generated( - {required final List words, + {required final SeedPhraseModel seed, required final bool isCopied}) = _$GeneratedImpl; - List get words; + SeedPhraseModel get seed; bool get isCopied; /// Create a copy of CreateSeedCubitState diff --git a/lib/v1/feature/add_seed/create_seed/cubit/create_seed_state.dart b/lib/v1/feature/add_seed/create_seed/cubit/create_seed_state.dart index 1b1394129..661df00d8 100644 --- a/lib/v1/feature/add_seed/create_seed/cubit/create_seed_state.dart +++ b/lib/v1/feature/add_seed/create_seed/cubit/create_seed_state.dart @@ -5,7 +5,7 @@ class CreateSeedCubitState with _$CreateSeedCubitState { const factory CreateSeedCubitState.initial() = _Initial; const factory CreateSeedCubitState.generated({ - required List words, + required SeedPhraseModel seed, required bool isCopied, }) = _Generated; } diff --git a/lib/v1/feature/add_seed/create_seed/view/create_seed_page.dart b/lib/v1/feature/add_seed/create_seed/view/create_seed_page.dart index 6f1e6ecff..3ca269a93 100644 --- a/lib/v1/feature/add_seed/create_seed/view/create_seed_page.dart +++ b/lib/v1/feature/add_seed/create_seed/view/create_seed_page.dart @@ -1,4 +1,5 @@ import 'package:app/app/router/router.dart'; +import 'package:app/data/models/seed/seed_phrase_model.dart'; import 'package:app/v1/feature/add_seed/create_seed/create_seed.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; @@ -20,19 +21,19 @@ class CreateSeedPage extends StatelessWidget { appBar: const DefaultAppBar(), body: CreateSeedView( // ignore: prefer-extracting-callbacks - checkCallback: (String phrase) { + checkCallback: (SeedPhraseModel seed) { context.goFurther( AppRoute.checkSeed.pathWithData( - queryParameters: {addSeedPhraseQueryParam: phrase}, + queryParameters: {addSeedPhraseQueryParam: seed.phrase}, ), preserveQueryParams: true, ); }, // ignore: prefer-extracting-callbacks - skipCallback: (String phrase) { + skipCallback: (SeedPhraseModel seed) { context.goFurther( AppRoute.createSeedPassword.pathWithData( - queryParameters: {addSeedPhraseQueryParam: phrase}, + queryParameters: {addSeedPhraseQueryParam: seed.phrase}, ), preserveQueryParams: true, ); diff --git a/lib/v1/feature/add_seed/create_seed/view/create_seed_view.dart b/lib/v1/feature/add_seed/create_seed/view/create_seed_view.dart index 1b79f2c6a..03e7dfdfd 100644 --- a/lib/v1/feature/add_seed/create_seed/view/create_seed_view.dart +++ b/lib/v1/feature/add_seed/create_seed/view/create_seed_view.dart @@ -1,3 +1,4 @@ +import 'package:app/data/models/seed/seed_phrase_model.dart'; import 'package:app/generated/generated.dart'; import 'package:app/v1/feature/add_seed/create_seed/create_seed.dart'; import 'package:collection/collection.dart'; @@ -8,7 +9,7 @@ import 'package:ui_components_lib/ui_components_lib.dart'; import 'package:ui_components_lib/v2/ui_components_lib_v2.dart'; /// Callback that calls if user taps skip checking or check phrase. -typedef CreateSeedCompleteCallback = void Function(String phrase); +typedef CreateSeedCompleteCallback = ValueChanged; /// {@template create_seed_view} /// Widget that allows user to create random seed phrase, copy it and check @@ -53,11 +54,11 @@ class CreateSeedView extends StatelessWidget { builder: (context, state) { return state.when( initial: Container.new, - generated: (words, isCopied) { + generated: (seed, isCopied) { return Column( mainAxisSize: MainAxisSize.min, children: [ - _wordsField(words), + _wordsField(seed), const SizedBox(height: DimensSizeV2.d4), _copyButton(isCopied), ], @@ -73,9 +74,9 @@ class CreateSeedView extends StatelessWidget { ), BlocBuilder( builder: (context, state) { - final words = state.maybeWhen( - generated: (words, _) => words, - orElse: () => const [], + final seed = state.maybeWhen( + generated: (seed, _) => seed, + orElse: SeedPhraseModel.empty, ); return Column( @@ -83,13 +84,13 @@ class CreateSeedView extends StatelessWidget { AccentButton( buttonShape: ButtonShape.pill, title: LocaleKeys.checkSeedPhrase.tr(), - onPressed: () => checkCallback(words.join(' ')), + onPressed: () => checkCallback(seed), ), const SizedBox(height: DimensSizeV2.d8), PrimaryButton( buttonShape: ButtonShape.pill, title: LocaleKeys.skipTakeRisk.tr(), - onPressed: () => skipCallback(words.join(' ')), + onPressed: () => skipCallback(seed), ), const SizedBox(height: DimensSizeV2.d12), ], @@ -140,14 +141,14 @@ class CreateSeedView extends StatelessWidget { ); } - Widget _wordsField(List words) { - final lengthHalf = words.length ~/ 2; + Widget _wordsField(SeedPhraseModel seed) { + final lengthHalf = seed.wordsCount ~/ 2; return SeparatedRow( children: [ Expanded( child: SeparatedColumn( - children: words + children: seed.words .getRange(0, lengthHalf) .mapIndexed((i, word) => _textPair(word, i + 1)) .toList(), @@ -155,8 +156,8 @@ class CreateSeedView extends StatelessWidget { ), Expanded( child: SeparatedColumn( - children: words - .getRange(lengthHalf, words.length) + children: seed.words + .getRange(lengthHalf, seed.wordsCount) .mapIndexed( (i, word) => _textPair(word, i + lengthHalf + 1), )