mirror of
https://github.com/cake-tech/cake_wallet.git
synced 2025-03-29 18:49:01 +00:00
Cw 773 restoring from qr gives no visual feedback of progress (#1944)
* init commit * fix for passphrase * update restore from keys flow * remove WalletRestorationFromQRVM * update creation vm * fix for blockchainHeightKey * fix merge conflicts * Update wallet_restore_page.dart --------- Co-authored-by: Omar Hatem <omarh.ismail1@gmail.com>
This commit is contained in:
parent
9f3078740e
commit
6abefc25a7
11 changed files with 129 additions and 321 deletions
lib
di.dartrouter.dart
src
screens/restore
restore_options_page.dartwallet_restore_from_keys_form.dartwallet_restore_from_seed_form.dartwallet_restore_page.dart
widgets
view_model
23
lib/di.dart
23
lib/di.dart
|
@ -54,6 +54,7 @@ import 'package:cake_wallet/view_model/link_view_model.dart';
|
|||
import 'package:cake_wallet/tron/tron.dart';
|
||||
import 'package:cake_wallet/src/screens/transaction_details/rbf_details_page.dart';
|
||||
import 'package:cake_wallet/view_model/dashboard/sign_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/restore/restore_wallet.dart';
|
||||
import 'package:cake_wallet/view_model/send/fees_view_model.dart';
|
||||
import 'package:cw_core/receive_page_option.dart';
|
||||
import 'package:cake_wallet/entities/preferences_key.dart';
|
||||
|
@ -173,7 +174,6 @@ import 'package:cake_wallet/view_model/node_list/pow_node_list_view_model.dart';
|
|||
import 'package:cake_wallet/view_model/wallet_groups_display_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/seed_settings_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/set_up_2fa_viewmodel.dart';
|
||||
import 'package:cake_wallet/view_model/restore/restore_from_qr_vm.dart';
|
||||
import 'package:cake_wallet/view_model/settings/display_settings_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/settings/mweb_settings_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/settings/other_settings_view_model.dart';
|
||||
|
@ -475,14 +475,6 @@ Future<void> setup({
|
|||
walletType: args.walletType ?? currentWalletType);
|
||||
});
|
||||
|
||||
getIt.registerFactoryParam<WalletRestorationFromQRVM, WalletType, void>((WalletType type, _) =>
|
||||
WalletRestorationFromQRVM(
|
||||
getIt.get<AppStore>(),
|
||||
getIt.get<WalletCreationService>(param1: type),
|
||||
_walletInfoSource,
|
||||
type,
|
||||
getIt.get<SeedSettingsViewModel>()));
|
||||
|
||||
getIt.registerFactoryParam<WalletHardwareRestoreViewModel, WalletType, void>((type, _) =>
|
||||
WalletHardwareRestoreViewModel(
|
||||
getIt.get<LedgerViewModel>(),
|
||||
|
@ -1144,13 +1136,18 @@ Future<void> setup({
|
|||
|
||||
getIt.registerFactory(() => FaqPage(getIt.get<SettingsStore>()));
|
||||
|
||||
getIt.registerFactoryParam<WalletRestoreViewModel, WalletType, void>((type, _) =>
|
||||
getIt.registerFactoryParam<WalletRestoreViewModel, WalletType, RestoredWallet?>((WalletType type,
|
||||
restoredWallet) =>
|
||||
WalletRestoreViewModel(getIt.get<AppStore>(), getIt.get<WalletCreationService>(param1: type),
|
||||
_walletInfoSource, getIt.get<SeedSettingsViewModel>(),
|
||||
type: type));
|
||||
type: type, restoredWallet: restoredWallet));
|
||||
|
||||
getIt.registerFactoryParam<WalletRestorePage, WalletType, void>((type, _) => WalletRestorePage(
|
||||
getIt.get<WalletRestoreViewModel>(param1: type), getIt.get<SeedSettingsViewModel>()));
|
||||
getIt.registerFactoryParam<WalletRestorePage, WalletType, RestoredWallet?>((WalletType type,
|
||||
restoredWallet) {
|
||||
return WalletRestorePage(
|
||||
getIt.get<WalletRestoreViewModel>(param1: type, param2: restoredWallet),
|
||||
getIt.get<SeedSettingsViewModel>());
|
||||
});
|
||||
|
||||
getIt.registerFactoryParam<WalletRestoreChooseDerivationViewModel, List<DerivationInfo>, void>(
|
||||
(derivations, _) => WalletRestoreChooseDerivationViewModel(derivationInfos: derivations));
|
||||
|
|
|
@ -120,6 +120,7 @@ import 'package:cake_wallet/view_model/dashboard/sign_view_model.dart';
|
|||
import 'package:cake_wallet/view_model/hardware_wallet/ledger_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/monero_account_list/account_list_item.dart';
|
||||
import 'package:cake_wallet/view_model/node_list/node_create_or_edit_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/restore/restore_wallet.dart';
|
||||
import 'package:cake_wallet/view_model/wallet_groups_display_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/seed_settings_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/wallet_hardware_restore_view_model.dart';
|
||||
|
@ -235,8 +236,9 @@ Route<dynamic> createRoute(RouteSettings settings) {
|
|||
return CupertinoPageRoute<void>(
|
||||
builder: (_) => getIt.get<NewWalletTypePage>(
|
||||
param1: NewWalletTypeArguments(
|
||||
onTypeSelected: (BuildContext context, WalletType type) =>
|
||||
Navigator.of(context).pushNamed(Routes.restoreWallet, arguments: type),
|
||||
onTypeSelected: (BuildContext context, WalletType type) {
|
||||
final arg = {'walletType': type};
|
||||
Navigator.of(context).pushNamed(Routes.restoreWallet, arguments: arg);},
|
||||
isCreate: false,
|
||||
isHardwareWallet: false,
|
||||
),
|
||||
|
@ -261,8 +263,9 @@ Route<dynamic> createRoute(RouteSettings settings) {
|
|||
return CupertinoPageRoute<void>(
|
||||
builder: (_) => getIt.get<NewWalletTypePage>(
|
||||
param1: NewWalletTypeArguments(
|
||||
onTypeSelected: (BuildContext context, WalletType type) =>
|
||||
Navigator.of(context).pushNamed(Routes.restoreWallet, arguments: type),
|
||||
onTypeSelected: (BuildContext context, WalletType type) {
|
||||
final arg = {'walletType': type};
|
||||
Navigator.of(context).pushNamed(Routes.restoreWallet, arguments: arg);},
|
||||
isCreate: false,
|
||||
isHardwareWallet: false,
|
||||
),
|
||||
|
@ -318,8 +321,11 @@ Route<dynamic> createRoute(RouteSettings settings) {
|
|||
builder: (_) => getIt.get<WalletSeedPage>(param1: settings.arguments as bool));
|
||||
|
||||
case Routes.restoreWallet:
|
||||
final args = settings.arguments as Map<String, dynamic>?;
|
||||
final walletType = args?['walletType'] as WalletType;
|
||||
final restoredWallet = args?['restoredWallet'] as RestoredWallet?;
|
||||
return MaterialPageRoute<void>(
|
||||
builder: (_) => getIt.get<WalletRestorePage>(param1: settings.arguments as WalletType));
|
||||
builder: (_) => getIt.get<WalletRestorePage>(param1: walletType, param2: restoredWallet));
|
||||
|
||||
case Routes.restoreWalletChooseDerivation:
|
||||
return MaterialPageRoute<void>(
|
||||
|
@ -677,6 +683,7 @@ Route<dynamic> createRoute(RouteSettings settings) {
|
|||
final isChildWallet = args['isChildWallet'] as bool? ?? false;
|
||||
final useTestnet = args['useTestnet'] as bool;
|
||||
final toggleTestnet = args['toggleTestnet'] as Function(bool? val);
|
||||
final restoredWallet = args['restoredWallet'] as RestoredWallet?;
|
||||
|
||||
return CupertinoPageRoute<void>(
|
||||
builder: (_) => AdvancedPrivacySettingsPage(
|
||||
|
|
|
@ -1,18 +1,14 @@
|
|||
import 'dart:io';
|
||||
|
||||
import 'package:cake_wallet/core/execution_state.dart';
|
||||
import 'package:cake_wallet/di.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/routes.dart';
|
||||
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||
import 'package:cake_wallet/src/screens/pin_code/pin_code_widget.dart';
|
||||
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
|
||||
import 'package:cake_wallet/src/widgets/option_tile.dart';
|
||||
import 'package:cake_wallet/utils/device_info.dart';
|
||||
import 'package:cake_wallet/utils/permission_handler.dart';
|
||||
import 'package:cake_wallet/utils/responsive_layout_util.dart';
|
||||
import 'package:cake_wallet/utils/show_pop_up.dart';
|
||||
import 'package:cake_wallet/view_model/restore/restore_from_qr_vm.dart';
|
||||
import 'package:cake_wallet/view_model/restore/wallet_restore_from_qr_code.dart';
|
||||
import 'package:cake_wallet/wallet_type_utils.dart';
|
||||
import 'package:cw_core/hardware/device_connection_type.dart';
|
||||
|
@ -131,10 +127,8 @@ class _RestoreOptionsBodyState extends State<_RestoreOptionsBody> {
|
|||
);
|
||||
}
|
||||
|
||||
void _onWalletCreateFailure(BuildContext context, String error) {
|
||||
setState(() {
|
||||
isRestoring = false;
|
||||
});
|
||||
void _showQRScanError(BuildContext context, String error) {
|
||||
setState(() => isRestoring = false);
|
||||
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
showPopUp<void>(
|
||||
|
@ -151,28 +145,23 @@ class _RestoreOptionsBodyState extends State<_RestoreOptionsBody> {
|
|||
|
||||
Future<void> _onScanQRCode(BuildContext context) async {
|
||||
final isCameraPermissionGranted =
|
||||
await PermissionHandler.checkPermission(Permission.camera, context);
|
||||
await PermissionHandler.checkPermission(Permission.camera, context);
|
||||
|
||||
if (!isCameraPermissionGranted) return;
|
||||
try {
|
||||
if (isRestoring) {
|
||||
return;
|
||||
}
|
||||
setState(() {
|
||||
isRestoring = true;
|
||||
});
|
||||
final restoreWallet = await WalletRestoreFromQRCode.scanQRCodeForRestoring(context);
|
||||
try {
|
||||
if (isRestoring) return;
|
||||
|
||||
final restoreFromQRViewModel =
|
||||
getIt.get<WalletRestorationFromQRVM>(param1: restoreWallet.type);
|
||||
setState(() => isRestoring = true);
|
||||
|
||||
await restoreFromQRViewModel.create(restoreWallet: restoreWallet);
|
||||
if (restoreFromQRViewModel.state is FailureState) {
|
||||
_onWalletCreateFailure(context,
|
||||
'Create wallet state: ${(restoreFromQRViewModel.state as FailureState).error}');
|
||||
}
|
||||
} catch (e) {
|
||||
_onWalletCreateFailure(context, e.toString());
|
||||
}
|
||||
final restoredWallet = await WalletRestoreFromQRCode.scanQRCodeForRestoring(context);
|
||||
|
||||
final params = {'walletType': restoredWallet.type, 'restoredWallet': restoredWallet};
|
||||
|
||||
Navigator.pushNamed(context, Routes.restoreWallet, arguments: params).then((_) {
|
||||
if (mounted) setState(() => isRestoring = false);
|
||||
});
|
||||
} catch (e) {
|
||||
_showQRScanError(context, e.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import 'package:cake_wallet/src/widgets/address_text_field.dart';
|
||||
import 'package:cake_wallet/view_model/restore/restore_wallet.dart';
|
||||
import 'package:cake_wallet/view_model/wallet_restore_view_model.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
@ -10,14 +11,15 @@ import 'package:cake_wallet/entities/generate_name.dart';
|
|||
import 'package:cake_wallet/themes/extensions/send_page_theme.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
class WalletRestoreFromKeysFrom extends StatefulWidget {
|
||||
WalletRestoreFromKeysFrom({
|
||||
class WalletRestoreFromKeysForm extends StatefulWidget {
|
||||
WalletRestoreFromKeysForm({
|
||||
required this.walletRestoreViewModel,
|
||||
required this.onPrivateKeyChange,
|
||||
required this.displayPrivateKeyField,
|
||||
required this.onHeightOrDateEntered,
|
||||
required this.displayWalletPassword,
|
||||
required this.onRepeatedPasswordChange,
|
||||
this.restoredWallet,
|
||||
this.onPasswordChange,
|
||||
Key? key,
|
||||
}) : super(key: key);
|
||||
|
@ -27,23 +29,32 @@ class WalletRestoreFromKeysFrom extends StatefulWidget {
|
|||
final void Function(String)? onPrivateKeyChange;
|
||||
final bool displayPrivateKeyField;
|
||||
final bool displayWalletPassword;
|
||||
final RestoredWallet? restoredWallet;
|
||||
final void Function(String)? onPasswordChange;
|
||||
final void Function(String)? onRepeatedPasswordChange;
|
||||
|
||||
@override
|
||||
WalletRestoreFromKeysFromState createState() =>
|
||||
WalletRestoreFromKeysFromState(displayWalletPassword: displayWalletPassword);
|
||||
WalletRestoreFromKeysFormState createState() =>
|
||||
WalletRestoreFromKeysFormState(displayWalletPassword: displayWalletPassword, restoredWallet: restoredWallet);
|
||||
}
|
||||
|
||||
class WalletRestoreFromKeysFromState extends State<WalletRestoreFromKeysFrom> {
|
||||
WalletRestoreFromKeysFromState({required bool displayWalletPassword})
|
||||
class WalletRestoreFromKeysFormState extends State<WalletRestoreFromKeysForm> {
|
||||
WalletRestoreFromKeysFormState({required bool displayWalletPassword, RestoredWallet? restoredWallet})
|
||||
: formKey = GlobalKey<FormState>(),
|
||||
blockchainHeightKey = GlobalKey<BlockchainHeightState>(),
|
||||
nameController = TextEditingController(),
|
||||
addressController = TextEditingController(),
|
||||
viewKeyController = TextEditingController(),
|
||||
spendKeyController = TextEditingController(),
|
||||
privateKeyController = TextEditingController(),
|
||||
addressController = restoredWallet != null
|
||||
? TextEditingController(text: restoredWallet.address)
|
||||
: TextEditingController(),
|
||||
viewKeyController = restoredWallet != null
|
||||
? TextEditingController(text: restoredWallet.viewKey)
|
||||
: TextEditingController(),
|
||||
spendKeyController = restoredWallet != null
|
||||
? TextEditingController(text: restoredWallet.spendKey)
|
||||
: TextEditingController(),
|
||||
privateKeyController = restoredWallet != null
|
||||
? TextEditingController(text: restoredWallet.privateKey)
|
||||
: TextEditingController(),
|
||||
nameTextEditingController = TextEditingController(),
|
||||
passwordTextEditingController = displayWalletPassword ? TextEditingController() : null,
|
||||
repeatedPasswordTextEditingController = displayWalletPassword ? TextEditingController() : null;
|
||||
|
@ -80,6 +91,12 @@ class WalletRestoreFromKeysFromState extends State<WalletRestoreFromKeysFrom> {
|
|||
}
|
||||
widget.onPrivateKeyChange?.call(privateKeyController.text);
|
||||
});
|
||||
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
if (widget.restoredWallet?.height != null) {
|
||||
blockchainHeightKey.currentState?.restoreHeightController.text = widget.restoredWallet!.height.toString();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
|
|
|
@ -9,6 +9,7 @@ import 'package:cake_wallet/src/widgets/seed_language_picker.dart';
|
|||
import 'package:cake_wallet/src/widgets/seed_widget.dart';
|
||||
import 'package:cake_wallet/themes/extensions/send_page_theme.dart';
|
||||
import 'package:cake_wallet/utils/show_pop_up.dart';
|
||||
import 'package:cake_wallet/view_model/restore/restore_wallet.dart';
|
||||
import 'package:cake_wallet/view_model/seed_settings_view_model.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
@ -23,6 +24,7 @@ class WalletRestoreFromSeedForm extends StatefulWidget {
|
|||
required this.displayWalletPassword,
|
||||
required this.seedSettingsViewModel,
|
||||
this.blockHeightFocusNode,
|
||||
this.restoredWallet,
|
||||
this.onHeightOrDateEntered,
|
||||
this.onSeedChange,
|
||||
this.onLanguageChange,
|
||||
|
@ -36,6 +38,7 @@ class WalletRestoreFromSeedForm extends StatefulWidget {
|
|||
final bool displayWalletPassword;
|
||||
final SeedSettingsViewModel seedSettingsViewModel;
|
||||
final FocusNode? blockHeightFocusNode;
|
||||
final RestoredWallet? restoredWallet;
|
||||
final Function(bool)? onHeightOrDateEntered;
|
||||
final void Function(String)? onSeedChange;
|
||||
final void Function(String)? onLanguageChange;
|
||||
|
@ -184,6 +187,7 @@ class WalletRestoreFromSeedFormState extends State<WalletRestoreFromSeedForm> {
|
|||
Container(height: 20),
|
||||
SeedWidget(
|
||||
key: seedWidgetStateKey,
|
||||
initialSeed: widget.restoredWallet?.mnemonicSeed,
|
||||
language: language,
|
||||
type: widget.type,
|
||||
onSeedChange: onSeedChange,
|
||||
|
|
|
@ -24,13 +24,13 @@ import 'package:mobx/mobx.dart';
|
|||
class WalletRestorePage extends BasePage {
|
||||
WalletRestorePage(this.walletRestoreViewModel, this.seedSettingsViewModel)
|
||||
: walletRestoreFromSeedFormKey = GlobalKey<WalletRestoreFromSeedFormState>(),
|
||||
walletRestoreFromKeysFormKey = GlobalKey<WalletRestoreFromKeysFromState>(),
|
||||
walletRestoreFromKeysFormKey = GlobalKey<WalletRestoreFromKeysFormState>(),
|
||||
_blockHeightFocusNode = FocusNode();
|
||||
|
||||
final WalletRestoreViewModel walletRestoreViewModel;
|
||||
final SeedSettingsViewModel seedSettingsViewModel;
|
||||
final GlobalKey<WalletRestoreFromSeedFormState> walletRestoreFromSeedFormKey;
|
||||
final GlobalKey<WalletRestoreFromKeysFromState> walletRestoreFromKeysFormKey;
|
||||
final GlobalKey<WalletRestoreFromKeysFormState> walletRestoreFromKeysFormKey;
|
||||
final FocusNode _blockHeightFocusNode;
|
||||
|
||||
bool _formProcessing = false;
|
||||
|
@ -52,6 +52,10 @@ class WalletRestorePage extends BasePage {
|
|||
// String? derivationPath = null;
|
||||
DerivationInfo? derivationInfo;
|
||||
|
||||
|
||||
@override
|
||||
Function(BuildContext)? get popWidget => (context) => seedSettingsViewModel.setPassphrase(null);
|
||||
|
||||
@override
|
||||
Function(BuildContext)? get pushToNextWidget => (context) {
|
||||
FocusScopeNode currentFocus = FocusScope.of(context);
|
||||
|
@ -283,7 +287,7 @@ class _WalletRestorePageBody extends StatefulWidget {
|
|||
final WalletRestoreViewModel walletRestoreViewModel;
|
||||
final SeedSettingsViewModel seedSettingsViewModel;
|
||||
final GlobalKey<WalletRestoreFromSeedFormState> walletRestoreFromSeedFormKey;
|
||||
final GlobalKey<WalletRestoreFromKeysFromState> walletRestoreFromKeysFormKey;
|
||||
final GlobalKey<WalletRestoreFromKeysFormState> walletRestoreFromKeysFormKey;
|
||||
final FocusNode blockHeightFocusNode;
|
||||
final DerivationInfo? derivationInfo;
|
||||
final void Function(DerivationInfo?) onDerivationInfoChanged;
|
||||
|
@ -311,7 +315,7 @@ class _WalletRestorePageBodyState extends State<_WalletRestorePageBody>
|
|||
final WalletRestoreViewModel walletRestoreViewModel;
|
||||
final SeedSettingsViewModel seedSettingsViewModel;
|
||||
final GlobalKey<WalletRestoreFromSeedFormState> walletRestoreFromSeedFormKey;
|
||||
final GlobalKey<WalletRestoreFromKeysFromState> walletRestoreFromKeysFormKey;
|
||||
final GlobalKey<WalletRestoreFromKeysFormState> walletRestoreFromKeysFormKey;
|
||||
final FocusNode blockHeightFocusNode;
|
||||
DerivationInfo? derivationInfo;
|
||||
|
||||
|
@ -325,7 +329,14 @@ class _WalletRestorePageBodyState extends State<_WalletRestorePageBody>
|
|||
|
||||
_hasKeysTab = widget.walletRestoreViewModel.availableModes.contains(WalletRestoreMode.keys);
|
||||
final tabCount = _hasKeysTab ? 2 : 1;
|
||||
_tabController = TabController(length: tabCount, vsync: this);
|
||||
|
||||
final initialIndex = walletRestoreViewModel.mode == WalletRestoreMode.seed
|
||||
? 0
|
||||
: _hasKeysTab
|
||||
? 1
|
||||
: 0;
|
||||
|
||||
_tabController = TabController(length: tabCount, vsync: this, initialIndex: initialIndex);
|
||||
|
||||
_tabController.addListener(() {
|
||||
if (!_tabController.indexIsChanging) {
|
||||
|
@ -442,9 +453,10 @@ class _WalletRestorePageBodyState extends State<_WalletRestorePageBody>
|
|||
);
|
||||
}
|
||||
|
||||
WalletRestoreFromKeysFrom _buildWalletRestoreFromKeysTab() {
|
||||
return WalletRestoreFromKeysFrom(
|
||||
WalletRestoreFromKeysForm _buildWalletRestoreFromKeysTab() {
|
||||
return WalletRestoreFromKeysForm(
|
||||
key: widget.walletRestoreFromKeysFormKey,
|
||||
restoredWallet: walletRestoreViewModel.restoredWallet,
|
||||
walletRestoreViewModel: widget.walletRestoreViewModel,
|
||||
displayPrivateKeyField: widget.walletRestoreViewModel.hasRestoreFromPrivateKey,
|
||||
displayWalletPassword: widget.walletRestoreViewModel.hasWalletPassword,
|
||||
|
@ -466,6 +478,7 @@ class _WalletRestorePageBodyState extends State<_WalletRestorePageBody>
|
|||
WalletRestoreFromSeedForm _buildWalletRestoreFromSeedTab() {
|
||||
return WalletRestoreFromSeedForm(
|
||||
key: widget.walletRestoreFromSeedFormKey,
|
||||
restoredWallet: walletRestoreViewModel.restoredWallet,
|
||||
seedSettingsViewModel: widget.seedSettingsViewModel,
|
||||
displayBlockHeightSelector: widget.walletRestoreViewModel.hasBlockchainHeightLanguageSelector,
|
||||
displayLanguageSelector: widget.walletRestoreViewModel.hasSeedLanguageSelector,
|
||||
|
|
|
@ -14,6 +14,7 @@ class SeedWidget extends StatefulWidget {
|
|||
this.onSeedChange,
|
||||
this.pasteButtonKey,
|
||||
this.seedTextFieldKey,
|
||||
this.initialSeed,
|
||||
super.key,
|
||||
});
|
||||
final Key? seedTextFieldKey;
|
||||
|
@ -21,17 +22,18 @@ class SeedWidget extends StatefulWidget {
|
|||
final String language;
|
||||
final WalletType type;
|
||||
final void Function(String)? onSeedChange;
|
||||
final String? initialSeed;
|
||||
|
||||
@override
|
||||
SeedWidgetState createState() => SeedWidgetState(language, type);
|
||||
SeedWidgetState createState() => SeedWidgetState(language, type, initialSeed);
|
||||
}
|
||||
|
||||
class SeedWidgetState extends State<SeedWidget> {
|
||||
SeedWidgetState(String language, this.type)
|
||||
: controller = TextEditingController(),
|
||||
SeedWidgetState(String language, this.type, String? initialSeed)
|
||||
: controller = TextEditingController(text: initialSeed ?? ''),
|
||||
focusNode = FocusNode(),
|
||||
words = SeedValidator.getWordList(type: type, language: language),
|
||||
_showPlaceholder = false {
|
||||
_showPlaceholder = initialSeed == null || initialSeed.isEmpty {
|
||||
focusNode.addListener(() {
|
||||
setState(() {
|
||||
if (!focusNode.hasFocus && controller.text.isEmpty) {
|
||||
|
@ -57,8 +59,12 @@ class SeedWidgetState extends State<SeedWidget> {
|
|||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_showPlaceholder = true;
|
||||
controller.addListener(() => widget.onSeedChange?.call(text));
|
||||
controller.addListener(() {
|
||||
setState(() {
|
||||
_showPlaceholder = controller.text.isEmpty;
|
||||
});
|
||||
widget.onSeedChange?.call(text);
|
||||
});
|
||||
}
|
||||
|
||||
void changeSeedLanguage(String language) {
|
||||
|
|
|
@ -1,219 +0,0 @@
|
|||
import 'package:cake_wallet/bitcoin/bitcoin.dart';
|
||||
import 'package:cake_wallet/bitcoin_cash/bitcoin_cash.dart';
|
||||
import 'package:cake_wallet/ethereum/ethereum.dart';
|
||||
import 'package:cake_wallet/nano/nano.dart';
|
||||
import 'package:cake_wallet/polygon/polygon.dart';
|
||||
import 'package:cake_wallet/solana/solana.dart';
|
||||
import 'package:cake_wallet/tron/tron.dart';
|
||||
import 'package:cake_wallet/view_model/restore/restore_mode.dart';
|
||||
import 'package:cake_wallet/view_model/restore/restore_wallet.dart';
|
||||
import 'package:cake_wallet/view_model/seed_settings_view_model.dart';
|
||||
import 'package:cake_wallet/wownero/wownero.dart';
|
||||
import 'package:cake_wallet/zano/zano.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
import 'package:cake_wallet/monero/monero.dart';
|
||||
import 'package:cake_wallet/store/app_store.dart';
|
||||
import 'package:cw_core/wallet_base.dart';
|
||||
import 'package:cake_wallet/core/generate_wallet_password.dart';
|
||||
import 'package:cake_wallet/core/wallet_creation_service.dart';
|
||||
import 'package:cw_core/wallet_credentials.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
import 'package:cake_wallet/view_model/wallet_creation_vm.dart';
|
||||
import 'package:cw_core/wallet_info.dart';
|
||||
|
||||
part 'restore_from_qr_vm.g.dart';
|
||||
|
||||
class WalletRestorationFromQRVM = WalletRestorationFromQRVMBase with _$WalletRestorationFromQRVM;
|
||||
|
||||
abstract class WalletRestorationFromQRVMBase extends WalletCreationVM with Store {
|
||||
WalletRestorationFromQRVMBase(
|
||||
AppStore appStore,
|
||||
WalletCreationService walletCreationService,
|
||||
Box<WalletInfo> walletInfoSource,
|
||||
WalletType type,
|
||||
SeedSettingsViewModel seedSettingsViewModel)
|
||||
: height = 0,
|
||||
viewKey = '',
|
||||
spendKey = '',
|
||||
wif = '',
|
||||
address = '',
|
||||
super(appStore, walletInfoSource, walletCreationService, seedSettingsViewModel,
|
||||
type: type, isRecovery: true);
|
||||
|
||||
@observable
|
||||
int height;
|
||||
|
||||
@observable
|
||||
String viewKey;
|
||||
|
||||
@observable
|
||||
String spendKey;
|
||||
|
||||
@observable
|
||||
String wif;
|
||||
|
||||
@observable
|
||||
String address;
|
||||
|
||||
bool get hasRestorationHeight => type == WalletType.monero || type == WalletType.wownero;
|
||||
|
||||
@override
|
||||
Future<WalletCredentials> getWalletCredentialsFromQRCredentials(
|
||||
RestoredWallet restoreWallet) async {
|
||||
final password = generateWalletPassword();
|
||||
|
||||
switch (restoreWallet.restoreMode) {
|
||||
case WalletRestoreMode.keys:
|
||||
switch (restoreWallet.type) {
|
||||
case WalletType.monero:
|
||||
return monero!.createMoneroRestoreWalletFromKeysCredentials(
|
||||
name: name,
|
||||
password: password,
|
||||
language: 'English',
|
||||
address: restoreWallet.address ?? '',
|
||||
viewKey: restoreWallet.viewKey ?? '',
|
||||
spendKey: restoreWallet.spendKey ?? '',
|
||||
height: restoreWallet.height ?? 0);
|
||||
case WalletType.wownero:
|
||||
return wownero!.createWowneroRestoreWalletFromKeysCredentials(
|
||||
name: name,
|
||||
password: password,
|
||||
language: 'English',
|
||||
address: restoreWallet.address ?? '',
|
||||
viewKey: restoreWallet.viewKey ?? '',
|
||||
spendKey: restoreWallet.spendKey ?? '',
|
||||
height: restoreWallet.height ?? 0);
|
||||
case WalletType.bitcoin:
|
||||
case WalletType.litecoin:
|
||||
return bitcoin!.createBitcoinRestoreWalletFromWIFCredentials(
|
||||
name: name, password: password, wif: wif);
|
||||
case WalletType.ethereum:
|
||||
return ethereum!.createEthereumRestoreWalletFromPrivateKey(
|
||||
name: name, password: password, privateKey: restoreWallet.privateKey!);
|
||||
case WalletType.polygon:
|
||||
return polygon!.createPolygonRestoreWalletFromPrivateKey(
|
||||
name: name, password: password, privateKey: restoreWallet.privateKey!);
|
||||
case WalletType.solana:
|
||||
return solana!.createSolanaRestoreWalletFromPrivateKey(
|
||||
name: name, password: password, privateKey: restoreWallet.privateKey!);
|
||||
case WalletType.tron:
|
||||
return tron!.createTronRestoreWalletFromPrivateKey(
|
||||
name: name, password: password, privateKey: restoreWallet.privateKey!);
|
||||
default:
|
||||
throw Exception('Unexpected type: ${restoreWallet.type.toString()}');
|
||||
}
|
||||
case WalletRestoreMode.seed:
|
||||
switch (restoreWallet.type) {
|
||||
case WalletType.monero:
|
||||
return monero!.createMoneroRestoreWalletFromSeedCredentials(
|
||||
name: name,
|
||||
height: restoreWallet.height ?? 0,
|
||||
mnemonic: restoreWallet.mnemonicSeed ?? '',
|
||||
password: password,
|
||||
passphrase: restoreWallet.passphrase ?? '',
|
||||
);
|
||||
case WalletType.bitcoin:
|
||||
case WalletType.litecoin:
|
||||
|
||||
final derivationInfoList = await getDerivationInfoFromQRCredentials(restoreWallet);
|
||||
DerivationInfo derivationInfo;
|
||||
if (derivationInfoList.isEmpty) {
|
||||
derivationInfo = getDefaultCreateDerivation()!;
|
||||
} else {
|
||||
derivationInfo = derivationInfoList.first;
|
||||
}
|
||||
return bitcoin!.createBitcoinRestoreWalletFromSeedCredentials(
|
||||
name: name,
|
||||
mnemonic: restoreWallet.mnemonicSeed ?? '',
|
||||
password: password,
|
||||
passphrase: restoreWallet.passphrase,
|
||||
derivationType: derivationInfo.derivationType!,
|
||||
derivationPath: derivationInfo.derivationPath!,
|
||||
);
|
||||
case WalletType.bitcoinCash:
|
||||
return bitcoinCash!.createBitcoinCashRestoreWalletFromSeedCredentials(
|
||||
name: name,
|
||||
mnemonic: restoreWallet.mnemonicSeed ?? '',
|
||||
password: password,
|
||||
passphrase: restoreWallet.passphrase,
|
||||
);
|
||||
case WalletType.ethereum:
|
||||
return ethereum!.createEthereumRestoreWalletFromSeedCredentials(
|
||||
name: name,
|
||||
mnemonic: restoreWallet.mnemonicSeed ?? '',
|
||||
password: password,
|
||||
passphrase: restoreWallet.passphrase,
|
||||
);
|
||||
case WalletType.nano:
|
||||
final derivationInfo =
|
||||
(await getDerivationInfoFromQRCredentials(restoreWallet)).first;
|
||||
return nano!.createNanoRestoreWalletFromSeedCredentials(
|
||||
name: name,
|
||||
mnemonic: restoreWallet.mnemonicSeed ?? '',
|
||||
password: password,
|
||||
derivationType: derivationInfo.derivationType!,
|
||||
passphrase: restoreWallet.passphrase,
|
||||
);
|
||||
case WalletType.polygon:
|
||||
return polygon!.createPolygonRestoreWalletFromSeedCredentials(
|
||||
name: name,
|
||||
mnemonic: restoreWallet.mnemonicSeed ?? '',
|
||||
password: password,
|
||||
passphrase: restoreWallet.passphrase,
|
||||
);
|
||||
case WalletType.solana:
|
||||
return solana!.createSolanaRestoreWalletFromSeedCredentials(
|
||||
name: name,
|
||||
mnemonic: restoreWallet.mnemonicSeed ?? '',
|
||||
password: password,
|
||||
passphrase: restoreWallet.passphrase,
|
||||
);
|
||||
case WalletType.tron:
|
||||
return tron!.createTronRestoreWalletFromSeedCredentials(
|
||||
name: name,
|
||||
mnemonic: restoreWallet.mnemonicSeed ?? '',
|
||||
password: password,
|
||||
passphrase: restoreWallet.passphrase,
|
||||
);
|
||||
case WalletType.wownero:
|
||||
return wownero!.createWowneroRestoreWalletFromSeedCredentials(
|
||||
name: name,
|
||||
height: restoreWallet.height ?? 0,
|
||||
mnemonic: restoreWallet.mnemonicSeed ?? '',
|
||||
password: password,
|
||||
passphrase: restoreWallet.passphrase ?? '',
|
||||
);
|
||||
case WalletType.zano:
|
||||
return zano!.createZanoRestoreWalletFromSeedCredentials(
|
||||
name: name,
|
||||
password: password,
|
||||
height: height,
|
||||
mnemonic: restoreWallet.mnemonicSeed ?? '',
|
||||
passphrase: restoreWallet.passphrase ?? '',
|
||||
);
|
||||
default:
|
||||
throw Exception('Unexpected type: ${type.toString()}');
|
||||
}
|
||||
default:
|
||||
throw Exception('Unexpected type: ${type.toString()}');
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<WalletBase> processFromRestoredWallet(WalletCredentials credentials,
|
||||
RestoredWallet restoreWallet) async {
|
||||
try {
|
||||
switch (restoreWallet.restoreMode) {
|
||||
case WalletRestoreMode.keys:
|
||||
return walletCreationService.restoreFromKeys(credentials);
|
||||
case WalletRestoreMode.seed:
|
||||
return walletCreationService.restoreFromSeed(credentials);
|
||||
default:
|
||||
throw Exception('Unexpected restore mode: ${restoreWallet.restoreMode.toString()}');
|
||||
}
|
||||
} catch (e) {
|
||||
throw Exception('Unexpected restore mode: ${e.toString()}');
|
||||
}
|
||||
}
|
||||
}
|
|
@ -46,8 +46,6 @@ class WalletRestoreFromQRCode {
|
|||
'zano_wallet': WalletType.zano,
|
||||
};
|
||||
|
||||
static bool _containsAssetSpecifier(String code) => _extractWalletType(code) != null;
|
||||
|
||||
static WalletType? _extractWalletType(String code) {
|
||||
final sortedKeys = _walletTypeMap.keys.toList()..sort((a, b) => b.length.compareTo(a.length));
|
||||
|
||||
|
@ -55,15 +53,18 @@ class WalletRestoreFromQRCode {
|
|||
|
||||
if (extracted == null) {
|
||||
// Special case for view-only monero wallet
|
||||
final codeParsed = json.decode(code);
|
||||
if (codeParsed["version"] == 0 &&
|
||||
codeParsed["primaryAddress"] != null &&
|
||||
codeParsed["privateViewKey"] != null &&
|
||||
codeParsed["restoreHeight"] != null) {
|
||||
return WalletType.monero;
|
||||
try {
|
||||
final codeParsed = json.decode(code);
|
||||
if (codeParsed["version"] == 0 &&
|
||||
codeParsed["primaryAddress"] != null &&
|
||||
codeParsed["privateViewKey"] != null &&
|
||||
codeParsed["restoreHeight"] != null) {
|
||||
return WalletType.monero;
|
||||
}
|
||||
} catch (e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return _walletTypeMap[extracted];
|
||||
}
|
||||
|
||||
|
@ -93,10 +94,10 @@ class WalletRestoreFromQRCode {
|
|||
if (code == null) throw Exception("Unexpected scan QR code value: aborted");
|
||||
if (code.isEmpty) throw Exception('Unexpected scan QR code value: value is empty');
|
||||
|
||||
WalletType? walletType;
|
||||
String formattedUri = '';
|
||||
WalletType? walletType = _extractWalletType(code);
|
||||
|
||||
if (!_containsAssetSpecifier(code)) {
|
||||
if (walletType == null) {
|
||||
await _specifyWalletAssets(context, "Can't determine wallet type, please pick it manually");
|
||||
walletType =
|
||||
await Navigator.pushNamed(context, Routes.restoreWalletTypeFromQR) as WalletType?;
|
||||
|
@ -108,7 +109,6 @@ class WalletRestoreFromQRCode {
|
|||
? '$walletType:?seed=$seedPhrase'
|
||||
: throw Exception('Failed to determine valid seed phrase');
|
||||
} else {
|
||||
walletType = _extractWalletType(code);
|
||||
final index = code.indexOf(':');
|
||||
final query = code.substring(index + 1).replaceAll('?', '&');
|
||||
formattedUri = '$walletType:?$query';
|
||||
|
@ -118,12 +118,11 @@ class WalletRestoreFromQRCode {
|
|||
Map<String, dynamic> queryParameters = {...uri.queryParameters};
|
||||
|
||||
if (queryParameters['seed'] == null) {
|
||||
queryParameters['seed'] = _extractSeedPhraseFromUrl(code, walletType!);
|
||||
queryParameters['seed'] = _extractSeedPhraseFromUrl(code, walletType);
|
||||
}
|
||||
if (queryParameters['address'] == null) {
|
||||
try {
|
||||
queryParameters['address'] = _extractAddressFromUrl(code, walletType!);
|
||||
} catch (_) {}
|
||||
queryParameters['address'] = _extractAddressFromUrl(code, walletType);
|
||||
|
||||
}
|
||||
|
||||
Map<String, dynamic> credentials = {'type': walletType, ...queryParameters, 'raw_qr': code};
|
||||
|
|
|
@ -67,8 +67,8 @@ abstract class WalletCreationVMBase with Store {
|
|||
|
||||
bool typeExists(WalletType type) => walletCreationService.typeExists(type);
|
||||
|
||||
Future<void> create({dynamic options, RestoredWallet? restoreWallet}) async {
|
||||
final type = restoreWallet?.type ?? this.type;
|
||||
Future<void> create({dynamic options}) async {
|
||||
final type = this.type;
|
||||
try {
|
||||
state = IsExecutingState();
|
||||
if (name.isEmpty) {
|
||||
|
@ -87,9 +87,7 @@ abstract class WalletCreationVMBase with Store {
|
|||
final dirPath = await pathForWalletDir(name: name, type: type);
|
||||
final path = await pathForWallet(name: name, type: type);
|
||||
|
||||
final credentials = restoreWallet != null
|
||||
? await getWalletCredentialsFromQRCredentials(restoreWallet)
|
||||
: getCredentials(options);
|
||||
final credentials = getCredentials(options);
|
||||
|
||||
final walletInfo = WalletInfo.external(
|
||||
id: WalletBase.idFor(name, type),
|
||||
|
@ -107,9 +105,7 @@ abstract class WalletCreationVMBase with Store {
|
|||
);
|
||||
|
||||
credentials.walletInfo = walletInfo;
|
||||
final wallet = restoreWallet != null
|
||||
? await processFromRestoredWallet(credentials, restoreWallet)
|
||||
: await process(credentials);
|
||||
final wallet = await process(credentials);
|
||||
|
||||
final isNonSeedWallet = isRecovery ? wallet.seed == null : false;
|
||||
walletInfo.isNonSeedWallet = isNonSeedWallet;
|
||||
|
@ -234,14 +230,6 @@ abstract class WalletCreationVMBase with Store {
|
|||
|
||||
Future<WalletBase> process(WalletCredentials credentials) => throw UnimplementedError();
|
||||
|
||||
Future<WalletCredentials> getWalletCredentialsFromQRCredentials(
|
||||
RestoredWallet restoreWallet) async =>
|
||||
throw UnimplementedError();
|
||||
|
||||
Future<WalletBase> processFromRestoredWallet(
|
||||
WalletCredentials credentials, RestoredWallet restoreWallet) =>
|
||||
throw UnimplementedError();
|
||||
|
||||
@action
|
||||
void toggleUseTestnet(bool? value) {
|
||||
_useTestnet = value ?? !_useTestnet;
|
||||
|
|
|
@ -12,6 +12,7 @@ import 'package:cake_wallet/solana/solana.dart';
|
|||
import 'package:cake_wallet/store/app_store.dart';
|
||||
import 'package:cake_wallet/tron/tron.dart';
|
||||
import 'package:cake_wallet/view_model/restore/restore_mode.dart';
|
||||
import 'package:cake_wallet/view_model/restore/restore_wallet.dart';
|
||||
import 'package:cake_wallet/view_model/seed_settings_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/wallet_creation_vm.dart';
|
||||
import 'package:cake_wallet/wownero/wownero.dart';
|
||||
|
@ -30,7 +31,7 @@ class WalletRestoreViewModel = WalletRestoreViewModelBase with _$WalletRestoreVi
|
|||
abstract class WalletRestoreViewModelBase extends WalletCreationVM with Store {
|
||||
WalletRestoreViewModelBase(AppStore appStore, WalletCreationService walletCreationService,
|
||||
Box<WalletInfo> walletInfoSource, SeedSettingsViewModel seedSettingsViewModel,
|
||||
{required WalletType type})
|
||||
{required WalletType type, this.restoredWallet})
|
||||
: hasSeedLanguageSelector =
|
||||
type == WalletType.monero || type == WalletType.haven || type == WalletType.wownero,
|
||||
hasBlockchainHeightLanguageSelector =
|
||||
|
@ -42,7 +43,7 @@ abstract class WalletRestoreViewModelBase extends WalletCreationVM with Store {
|
|||
type == WalletType.solana ||
|
||||
type == WalletType.tron,
|
||||
isButtonEnabled = false,
|
||||
mode = WalletRestoreMode.seed,
|
||||
mode = restoredWallet?.restoreMode ?? WalletRestoreMode.seed,
|
||||
super(appStore, walletInfoSource, walletCreationService, seedSettingsViewModel,
|
||||
type: type, isRecovery: true) {
|
||||
switch (type) {
|
||||
|
@ -68,6 +69,11 @@ abstract class WalletRestoreViewModelBase extends WalletCreationVM with Store {
|
|||
break;
|
||||
}
|
||||
walletCreationService.changeWalletType(type: type);
|
||||
if (restoredWallet != null) {
|
||||
if(restoredWallet!.restoreMode == WalletRestoreMode.seed) {
|
||||
seedSettingsViewModel.setPassphrase(restoredWallet!.passphrase);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static const moneroSeedMnemonicLength = 25;
|
||||
|
@ -76,6 +82,7 @@ abstract class WalletRestoreViewModelBase extends WalletCreationVM with Store {
|
|||
final bool hasSeedLanguageSelector;
|
||||
final bool hasBlockchainHeightLanguageSelector;
|
||||
final bool hasRestoreFromPrivateKey;
|
||||
final RestoredWallet? restoredWallet;
|
||||
|
||||
@observable
|
||||
WalletRestoreMode mode;
|
||||
|
|
Loading…
Reference in a new issue