Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

feat(cat-voices): Upload seedphrase #1019

Merged
merged 11 commits into from
Oct 21, 2024
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import 'package:catalyst_voices/pages/registration/create_keychain/bloc_seed_phrase_builder.dart';
import 'package:catalyst_voices/pages/registration/incorrect_seedphrase_dialog.dart';
import 'package:catalyst_voices/pages/registration/upload_seedphrase_confirmation_dialog.dart';
import 'package:catalyst_voices/pages/registration/upload_seedphrase_dialog.dart';
import 'package:catalyst_voices/pages/registration/widgets/registration_stage_navigation.dart';
import 'package:catalyst_voices/pages/registration/widgets/seed_phrase_actions.dart';
import 'package:catalyst_voices/widgets/widgets.dart';
Expand Down Expand Up @@ -38,7 +41,33 @@ class _SeedPhraseCheckPanelState extends State<SeedPhraseCheckPanel> {
}

Future<void> _uploadSeedPhrase() async {
// TODO(damian-molinski): open upload dialog
final showUpload = await UploadSeedphraseConfirmationDialog.show(context);
if (showUpload) {
await _showUploadDialog();
}
}

Future<void> _showUploadDialog() async {
final words = await UploadSeedphraseDialog.show(context);

if (!mounted) return;

final areWordsMatching =
RegistrationCubit.of(context).keychainCreation.areWordsMatching(words);

final isValid = areWordsMatching &&
SeedPhrase.isValid(
words: words,
);

if (isValid) {
_onWordsSequenceChanged(words);
} else {
final showUpload = await IncorrectSeedphraseDialog.show(context);
if (showUpload) {
await _showUploadDialog();
}
}
}

void _clearUserWords() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import 'package:catalyst_voices/widgets/buttons/voices_filled_button.dart';
import 'package:catalyst_voices/widgets/buttons/voices_text_button.dart';
import 'package:catalyst_voices/widgets/modals/voices_alert_dialog.dart';
import 'package:catalyst_voices/widgets/modals/voices_dialog.dart';
import 'package:catalyst_voices_assets/catalyst_voices_assets.dart';
import 'package:catalyst_voices_localization/catalyst_voices_localization.dart';
import 'package:flutter/material.dart';

class IncorrectSeedphraseDialog extends StatelessWidget {
const IncorrectSeedphraseDialog({
super.key,
});

static Future<bool> show(BuildContext context) async {
final result = await VoicesDialog.show<bool>(
context: context,
builder: (context) => const IncorrectSeedphraseDialog(),
);

return result ?? false;
}

@override
Widget build(BuildContext context) {
return VoicesAlertDialog(
title: Text(context.l10n.warning.toUpperCase()),
icon: CatalystImage.asset(
VoicesAssets.images.keyIncorrect.path,
width: 80,
height: 80,
),
subtitle: Text(context.l10n.incorrectUploadDialogSubtitle),
content: Text(
context.l10n.incorrectUploadDialogContent,
),
buttons: [
VoicesFilledButton(
child: Text(context.l10n.incorrectUploadDialogTryAgainButton),
onTap: () => Navigator.of(context).pop(true),
),
VoicesTextButton(
child: Text(context.l10n.cancelButtonText),
onTap: () => Navigator.of(context).pop(false),
),
],
);
}
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
import 'dart:async';

import 'package:catalyst_voices/pages/registration/incorrect_seedphrase_dialog.dart';
import 'package:catalyst_voices/pages/registration/recover/bloc_recover_builder.dart';
import 'package:catalyst_voices/pages/registration/upload_seedphrase_confirmation_dialog.dart';
import 'package:catalyst_voices/pages/registration/upload_seedphrase_dialog.dart';
import 'package:catalyst_voices/pages/registration/widgets/registration_stage_message.dart';
import 'package:catalyst_voices/pages/registration/widgets/registration_stage_navigation.dart';
import 'package:catalyst_voices/pages/registration/widgets/seed_phrase_actions.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/material.dart';

class SeedPhraseInputPanel extends StatefulWidget {
Expand Down Expand Up @@ -78,7 +82,29 @@ class _SeedPhraseInputPanelState extends State<SeedPhraseInputPanel> {
}

Future<void> _uploadSeedPhrase() async {
// TODO(damian-molinski): Import implementation for KeychainCreation
final showUpload = await UploadSeedphraseConfirmationDialog.show(context);
if (showUpload) {
await _showUploadDialog();
}
}

Future<void> _showUploadDialog() async {
final words = await UploadSeedphraseDialog.show(context);

final isValid = SeedPhrase.isValid(
words: words,
);

if (isValid) {
_controller.words = words;
} else {
if (!mounted) return;
digitalheartxs marked this conversation as resolved.
Show resolved Hide resolved

final showUpload = await IncorrectSeedphraseDialog.show(context);
if (showUpload) {
await _showUploadDialog();
}
}
}

void _resetControllerWords() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import 'package:catalyst_voices/widgets/avatars/voices_avatar.dart';
import 'package:catalyst_voices/widgets/buttons/voices_filled_button.dart';
import 'package:catalyst_voices/widgets/buttons/voices_text_button.dart';
import 'package:catalyst_voices/widgets/modals/voices_alert_dialog.dart';
import 'package:catalyst_voices/widgets/modals/voices_dialog.dart';
import 'package:catalyst_voices_assets/catalyst_voices_assets.dart';
import 'package:catalyst_voices_brands/catalyst_voices_brands.dart';
import 'package:catalyst_voices_localization/catalyst_voices_localization.dart';
import 'package:flutter/material.dart';

class UploadSeedphraseConfirmationDialog extends StatelessWidget {
digitalheartxs marked this conversation as resolved.
Show resolved Hide resolved
const UploadSeedphraseConfirmationDialog({
super.key,
});

static Future<bool> show(BuildContext context) async {
final result = await VoicesDialog.show<bool>(
context: context,
builder: (context) => const UploadSeedphraseConfirmationDialog(),
);

return result ?? false;
}

@override
Widget build(BuildContext context) {
return VoicesAlertDialog(
title: Text(context.l10n.alert.toUpperCase()),
icon: VoicesAvatar(
radius: 40,
backgroundColor: Colors.transparent,
icon: VoicesAssets.icons.exclamation.buildIcon(
size: 36,
color: Theme.of(context).colors.iconsError,
),
border: Border.all(
color: Theme.of(context).colors.iconsError!,
width: 3,
),
),
subtitle: Text(context.l10n.uploadConfirmDialogSubtitle),
content: Text(context.l10n.uploadConfirmDialogContent),
buttons: [
VoicesFilledButton(
child: Text(context.l10n.uploadConfirmDialogYesButton),
onTap: () => Navigator.of(context).pop(true),
),
VoicesTextButton(
child: Text(context.l10n.uploadConfirmDialogResumeButton),
onTap: () => Navigator.of(context).pop(false),
),
],
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import 'dart:convert';

import 'package:catalyst_voices/widgets/modals/voices_upload_file_dialog.dart';
import 'package:catalyst_voices_localization/catalyst_voices_localization.dart';
import 'package:catalyst_voices_models/catalyst_voices_models.dart';
import 'package:collection/collection.dart';
import 'package:flutter/material.dart';

class UploadSeedphraseDialog {
static Future<List<SeedPhraseWord>> show(BuildContext rootContext) async {
final file = await VoicesUploadFileDialog.show(
rootContext,
digitalheartxs marked this conversation as resolved.
Show resolved Hide resolved
title: rootContext.l10n.uploadKeychainTitle,
itemNameToUpload: rootContext.l10n.key,
info: rootContext.l10n.uploadKeychainInfo,
allowedExtensions: ['txt'],
);

final bytes = file?.bytes;
if (bytes != null) {
final decodedText = utf8.decode(bytes);
final words = decodedText
.split(' ')
.mapIndexed((i, e) => SeedPhraseWord(e, nr: i + 1))
.toList();

return words;
} else {
return [];
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,14 @@ final class SeedPhraseFieldController
extends ValueNotifier<List<SeedPhraseWord>> {
SeedPhraseFieldController([super._value = const <SeedPhraseWord>[]]);

set words(List<SeedPhraseWord> words) {
value = words;
}

List<SeedPhraseWord> get words {
return value;
}

void clear() {
value = const [];
}
Expand Down
Binary file not shown.
Binary file not shown.
Binary file not shown.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ abstract interface class KeychainCreationManager

Future<void> downloadSeedPhrase();

bool areWordsMatching(List<SeedPhraseWord> words);

Future<bool> createKeychain();
}

Expand Down Expand Up @@ -169,4 +171,13 @@ final class KeychainCreationCubit extends Cubit<KeychainStateData>
_buildSeedPhrase();
}
}

@override
bool areWordsMatching(List<SeedPhraseWord> words) {
final mappedWords = words.map((e) => e.data).toList()..sort();
final mappedShuffledWords =
_seedPhraseStateData.shuffledWords.map((e) => e.data).toList()..sort();
digitalheartxs marked this conversation as resolved.
Show resolved Hide resolved

return listEquals(mappedWords, mappedShuffledWords);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1606,6 +1606,12 @@ abstract class VoicesLocalizations {
/// **'Warning'**
String get warning;

/// No description provided for @alert.
///
/// In en, this message translates to:
/// **'Alert'**
String get alert;

/// No description provided for @registrationExitConfirmDialogSubtitle.
///
/// In en, this message translates to:
Expand Down Expand Up @@ -1773,6 +1779,48 @@ abstract class VoicesLocalizations {
/// In en, this message translates to:
/// **'Continue recovery process'**
String get recoveryExitConfirmDialogContinue;

/// No description provided for @uploadConfirmDialogSubtitle.
///
/// In en, this message translates to:
/// **'SWITCH TO FILE UPLOAD'**
String get uploadConfirmDialogSubtitle;

/// No description provided for @uploadConfirmDialogContent.
///
/// In en, this message translates to:
/// **'Do you want to cancel manual input, and switch to Catalyst key upload?'**
String get uploadConfirmDialogContent;

/// No description provided for @uploadConfirmDialogYesButton.
///
/// In en, this message translates to:
/// **'Yes, switch to Catalyst key upload'**
String get uploadConfirmDialogYesButton;

/// No description provided for @uploadConfirmDialogResumeButton.
///
/// In en, this message translates to:
/// **'Resume manual inputs'**
String get uploadConfirmDialogResumeButton;

/// No description provided for @incorrectUploadDialogSubtitle.
///
/// In en, this message translates to:
/// **'CATALYST KEY INCORRECT'**
String get incorrectUploadDialogSubtitle;

/// No description provided for @incorrectUploadDialogContent.
///
/// In en, this message translates to:
/// **'The Catalyst keychain that you entered or uploaded is incorrect, please try again.'**
String get incorrectUploadDialogContent;

/// No description provided for @incorrectUploadDialogTryAgainButton.
///
/// In en, this message translates to:
/// **'Try again'**
String get incorrectUploadDialogTryAgainButton;
}

class _VoicesLocalizationsDelegate extends LocalizationsDelegate<VoicesLocalizations> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -848,6 +848,9 @@ class VoicesLocalizationsEn extends VoicesLocalizations {
@override
String get warning => 'Warning';

@override
String get alert => 'Alert';

@override
String get registrationExitConfirmDialogSubtitle => 'Account creation incomplete!';

Expand Down Expand Up @@ -931,4 +934,25 @@ class VoicesLocalizationsEn extends VoicesLocalizations {

@override
String get recoveryExitConfirmDialogContinue => 'Continue recovery process';

@override
String get uploadConfirmDialogSubtitle => 'SWITCH TO FILE UPLOAD';

@override
String get uploadConfirmDialogContent => 'Do you want to cancel manual input, and switch to Catalyst key upload?';

@override
String get uploadConfirmDialogYesButton => 'Yes, switch to Catalyst key upload';

@override
String get uploadConfirmDialogResumeButton => 'Resume manual inputs';

@override
String get incorrectUploadDialogSubtitle => 'CATALYST KEY INCORRECT';

@override
String get incorrectUploadDialogContent => 'The Catalyst keychain that you entered or uploaded is incorrect, please try again.';

@override
String get incorrectUploadDialogTryAgainButton => 'Try again';
}
Loading
Loading