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:
Serhii
2025-03-15 01:45:46 +02:00
committed by GitHub
co-authored by Omar Hatem
parent 9f3078740e
commit 6abefc25a7
11 changed files with 129 additions and 321 deletions
@@ -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,
+12 -6
View File
@@ -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) {