mirror of
https://github.com/Such-Software/hash-wallet.git
synced 2026-10-17 05:41:29 +02:00
CW-894-Improve-UX-for-restore-from-seeds-keys-page (#1986)
* Update wallet_restore_page.dart * Fix conflicts with main [skip ci] --------- Co-authored-by: OmarHatem <omarh.ismail1@gmail.com>
This commit is contained in:
@@ -20,10 +20,20 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
import 'package:keyboard_actions/keyboard_actions.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
import 'package:smooth_page_indicator/smooth_page_indicator.dart';
|
||||
|
||||
class WalletRestorePage extends BasePage {
|
||||
WalletRestorePage(this.walletRestoreViewModel, this.seedSettingsViewModel);
|
||||
WalletRestorePage(this.walletRestoreViewModel, this.seedSettingsViewModel)
|
||||
: walletRestoreFromSeedFormKey = GlobalKey<WalletRestoreFromSeedFormState>(),
|
||||
walletRestoreFromKeysFormKey = GlobalKey<WalletRestoreFromKeysFromState>(),
|
||||
_blockHeightFocusNode = FocusNode();
|
||||
|
||||
final WalletRestoreViewModel walletRestoreViewModel;
|
||||
final SeedSettingsViewModel seedSettingsViewModel;
|
||||
final GlobalKey<WalletRestoreFromSeedFormState> walletRestoreFromSeedFormKey;
|
||||
final GlobalKey<WalletRestoreFromKeysFromState> walletRestoreFromKeysFormKey;
|
||||
final FocusNode _blockHeightFocusNode;
|
||||
|
||||
bool _formProcessing = false;
|
||||
|
||||
@override
|
||||
Widget middle(BuildContext context) => Observer(
|
||||
@@ -38,8 +48,9 @@ class WalletRestorePage extends BasePage {
|
||||
color: titleColor(context)),
|
||||
));
|
||||
|
||||
final WalletRestoreViewModel walletRestoreViewModel;
|
||||
final SeedSettingsViewModel seedSettingsViewModel;
|
||||
// DerivationType derivationType = DerivationType.unknown;
|
||||
// String? derivationPath = null;
|
||||
DerivationInfo? derivationInfo;
|
||||
|
||||
@override
|
||||
Function(BuildContext)? get pushToNextWidget => (context) {
|
||||
@@ -51,137 +62,6 @@ class WalletRestorePage extends BasePage {
|
||||
|
||||
@override
|
||||
Widget body(BuildContext context) {
|
||||
return WalletRestorePageBody(walletRestoreViewModel, seedSettingsViewModel);
|
||||
}
|
||||
}
|
||||
|
||||
class WalletRestorePageBody extends StatefulWidget {
|
||||
WalletRestorePageBody(this.walletRestoreViewModel, this.seedSettingsViewModel);
|
||||
|
||||
final WalletRestoreViewModel walletRestoreViewModel;
|
||||
final SeedSettingsViewModel seedSettingsViewModel;
|
||||
|
||||
@override
|
||||
State<WalletRestorePageBody> createState() =>
|
||||
_WalletRestorePageBodyState(walletRestoreViewModel, seedSettingsViewModel);
|
||||
}
|
||||
|
||||
class _WalletRestorePageBodyState extends State<WalletRestorePageBody> {
|
||||
_WalletRestorePageBodyState(this.walletRestoreViewModel, this.seedSettingsViewModel)
|
||||
: walletRestoreFromSeedFormKey = GlobalKey<WalletRestoreFromSeedFormState>(),
|
||||
walletRestoreFromKeysFormKey = GlobalKey<WalletRestoreFromKeysFromState>(),
|
||||
_pages = [],
|
||||
_blockHeightFocusNode = FocusNode(),
|
||||
_controller = PageController(initialPage: 0) {
|
||||
walletRestoreViewModel.availableModes.forEach((mode) {
|
||||
switch (mode) {
|
||||
case WalletRestoreMode.seed:
|
||||
_pages.add(WalletRestoreFromSeedForm(
|
||||
seedSettingsViewModel: seedSettingsViewModel,
|
||||
displayBlockHeightSelector:
|
||||
walletRestoreViewModel.hasBlockchainHeightLanguageSelector,
|
||||
displayLanguageSelector: walletRestoreViewModel.hasSeedLanguageSelector,
|
||||
type: walletRestoreViewModel.type,
|
||||
key: walletRestoreFromSeedFormKey,
|
||||
blockHeightFocusNode: _blockHeightFocusNode,
|
||||
onHeightOrDateEntered: (value) {
|
||||
if (_isValidSeed()) {
|
||||
walletRestoreViewModel.isButtonEnabled = value;
|
||||
}
|
||||
},
|
||||
onSeedChange: (String seed) {
|
||||
final isPolyseed = walletRestoreViewModel.isPolyseed(seed);
|
||||
_validateOnChange(isPolyseed: isPolyseed);
|
||||
},
|
||||
onLanguageChange: (String language) {
|
||||
final isPolyseed = language.startsWith("POLYSEED_");
|
||||
_validateOnChange(isPolyseed: isPolyseed);
|
||||
},
|
||||
displayWalletPassword: walletRestoreViewModel.hasWalletPassword,
|
||||
onPasswordChange: (String password) =>
|
||||
walletRestoreViewModel.walletPassword = password,
|
||||
onRepeatedPasswordChange: (String repeatedPassword) =>
|
||||
walletRestoreViewModel.repeatedWalletPassword = repeatedPassword));
|
||||
break;
|
||||
case WalletRestoreMode.keys:
|
||||
_pages.add(WalletRestoreFromKeysFrom(
|
||||
key: walletRestoreFromKeysFormKey,
|
||||
walletRestoreViewModel: walletRestoreViewModel,
|
||||
onPrivateKeyChange: (String seed) {
|
||||
if (walletRestoreViewModel.type == WalletType.nano ||
|
||||
walletRestoreViewModel.type == WalletType.banano) {
|
||||
walletRestoreViewModel.isButtonEnabled = _isValidSeedKey();
|
||||
}
|
||||
},
|
||||
displayPrivateKeyField: walletRestoreViewModel.hasRestoreFromPrivateKey,
|
||||
displayWalletPassword: walletRestoreViewModel.hasWalletPassword,
|
||||
onPasswordChange: (String password) =>
|
||||
walletRestoreViewModel.walletPassword = password,
|
||||
onRepeatedPasswordChange: (String repeatedPassword) =>
|
||||
walletRestoreViewModel.repeatedWalletPassword = repeatedPassword,
|
||||
onHeightOrDateEntered: (value) => walletRestoreViewModel.isButtonEnabled = value));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
final WalletRestoreViewModel walletRestoreViewModel;
|
||||
final SeedSettingsViewModel seedSettingsViewModel;
|
||||
final PageController _controller;
|
||||
final List<Widget> _pages;
|
||||
final GlobalKey<WalletRestoreFromSeedFormState> walletRestoreFromSeedFormKey;
|
||||
final GlobalKey<WalletRestoreFromKeysFromState> walletRestoreFromKeysFormKey;
|
||||
final FocusNode _blockHeightFocusNode;
|
||||
|
||||
bool _formProcessing = false;
|
||||
|
||||
// DerivationType derivationType = DerivationType.unknown;
|
||||
// String? derivationPath = null;
|
||||
DerivationInfo? derivationInfo;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
|
||||
reaction((_) => walletRestoreViewModel.state, (ExecutionState state) {
|
||||
if (state is FailureState) {
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
showPopUp<void>(
|
||||
context: context,
|
||||
builder: (_) {
|
||||
return AlertWithOneAction(
|
||||
alertTitle: S.current.new_wallet,
|
||||
alertContent: state.error,
|
||||
buttonText: S.of(context).ok,
|
||||
buttonAction: () => Navigator.of(context).pop());
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
reaction((_) => walletRestoreViewModel.mode, (WalletRestoreMode mode) {
|
||||
walletRestoreViewModel.isButtonEnabled = false;
|
||||
walletRestoreViewModel.walletPassword = null;
|
||||
walletRestoreViewModel.repeatedWalletPassword = null;
|
||||
|
||||
walletRestoreFromSeedFormKey
|
||||
.currentState!.blockchainHeightKey.currentState!.restoreHeightController.text = '';
|
||||
walletRestoreFromSeedFormKey
|
||||
.currentState!.blockchainHeightKey.currentState!.dateController.text = '';
|
||||
walletRestoreFromSeedFormKey.currentState!.nameTextEditingController.text = '';
|
||||
|
||||
walletRestoreFromKeysFormKey
|
||||
.currentState!.blockchainHeightKey.currentState!.restoreHeightController.text = '';
|
||||
walletRestoreFromKeysFormKey
|
||||
.currentState!.blockchainHeightKey.currentState!.dateController.text = '';
|
||||
walletRestoreFromKeysFormKey.currentState!.nameTextEditingController.text = '';
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return KeyboardActions(
|
||||
config: KeyboardActionsConfig(
|
||||
keyboardActionsPlatform: KeyboardActionsPlatform.IOS,
|
||||
@@ -202,41 +82,18 @@ class _WalletRestorePageBodyState extends State<WalletRestorePageBody> {
|
||||
constraints:
|
||||
BoxConstraints(maxWidth: ResponsiveLayoutUtilBase.kDesktopMaxWidthConstraint),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Expanded(
|
||||
child: PageView.builder(
|
||||
onPageChanged: (page) {
|
||||
walletRestoreViewModel.mode =
|
||||
page == 0 ? WalletRestoreMode.seed : WalletRestoreMode.keys;
|
||||
},
|
||||
controller: _controller,
|
||||
itemCount: _pages.length,
|
||||
itemBuilder: (_, index) => SingleChildScrollView(child: _pages[index]),
|
||||
child: _WalletRestorePageBody(
|
||||
walletRestoreViewModel: walletRestoreViewModel,
|
||||
seedSettingsViewModel: seedSettingsViewModel,
|
||||
walletRestoreFromSeedFormKey: walletRestoreFromSeedFormKey,
|
||||
walletRestoreFromKeysFormKey: walletRestoreFromKeysFormKey,
|
||||
blockHeightFocusNode: _blockHeightFocusNode,
|
||||
derivationInfo: derivationInfo,
|
||||
onDerivationInfoChanged: (info) => derivationInfo = info,
|
||||
),
|
||||
),
|
||||
if (_pages.length > 1)
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 10),
|
||||
child: Semantics(
|
||||
button: false,
|
||||
label: 'Page Indicator',
|
||||
hint: 'Swipe to change restore mode',
|
||||
excludeSemantics: true,
|
||||
child: SmoothPageIndicator(
|
||||
controller: _controller,
|
||||
count: _pages.length,
|
||||
effect: ColorTransitionEffect(
|
||||
spacing: 6.0,
|
||||
radius: 6.0,
|
||||
dotWidth: 6.0,
|
||||
dotHeight: 6.0,
|
||||
dotColor: Theme.of(context).hintColor.withOpacity(0.5),
|
||||
activeDotColor: Theme.of(context).hintColor,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 20, bottom: 24, left: 24, right: 24),
|
||||
child: Column(
|
||||
@@ -245,9 +102,7 @@ class _WalletRestorePageBodyState extends State<WalletRestorePageBody> {
|
||||
builder: (context) {
|
||||
return LoadingPrimaryButton(
|
||||
key: ValueKey('wallet_restore_seed_or_key_restore_button_key'),
|
||||
onPressed: () async {
|
||||
await _confirmForm(context);
|
||||
},
|
||||
onPressed: () async => await _confirmForm(context),
|
||||
text: S.of(context).restore_recover,
|
||||
color: Theme.of(context)
|
||||
.extension<WalletListTheme>()!
|
||||
@@ -285,60 +140,6 @@ class _WalletRestorePageBodyState extends State<WalletRestorePageBody> {
|
||||
);
|
||||
}
|
||||
|
||||
void _validateOnChange({bool isPolyseed = false}) {
|
||||
if (!isPolyseed && walletRestoreViewModel.hasBlockchainHeightLanguageSelector) {
|
||||
final hasHeight = walletRestoreFromSeedFormKey
|
||||
.currentState?.blockchainHeightKey.currentState?.restoreHeightController.text.isNotEmpty;
|
||||
|
||||
if (hasHeight == true) {
|
||||
walletRestoreViewModel.isButtonEnabled = _isValidSeed();
|
||||
}
|
||||
} else {
|
||||
walletRestoreViewModel.isButtonEnabled = _isValidSeed();
|
||||
}
|
||||
}
|
||||
|
||||
bool _isValidSeed() {
|
||||
final seedPhrase =
|
||||
walletRestoreFromSeedFormKey.currentState!.seedWidgetStateKey.currentState!.text;
|
||||
if (walletRestoreViewModel.isPolyseed(seedPhrase)) return true;
|
||||
|
||||
final seedWords = seedPhrase.split(' ');
|
||||
|
||||
if (seedWords.length == 14 && walletRestoreViewModel.type == WalletType.wownero) return true;
|
||||
if (seedWords.length == 26 && walletRestoreViewModel.type == WalletType.zano) return true;
|
||||
|
||||
if ((walletRestoreViewModel.type == WalletType.monero ||
|
||||
walletRestoreViewModel.type == WalletType.wownero ||
|
||||
walletRestoreViewModel.type == WalletType.haven) &&
|
||||
seedWords.length != WalletRestoreViewModelBase.moneroSeedMnemonicLength) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// bip39:
|
||||
final validBip39SeedLengths = [12, 18, 24];
|
||||
final nonBip39WalletTypes = [WalletType.monero, WalletType.wownero, WalletType.haven];
|
||||
// if it's a bip39 wallet and the length is not valid return false
|
||||
if (!nonBip39WalletTypes.contains(walletRestoreViewModel.type) &&
|
||||
!(validBip39SeedLengths.contains(seedWords.length))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final words =
|
||||
walletRestoreFromSeedFormKey.currentState!.seedWidgetStateKey.currentState!.words.toSet();
|
||||
return seedWords.toSet().difference(words).toSet().isEmpty;
|
||||
}
|
||||
|
||||
bool _isValidSeedKey() {
|
||||
final seedKey = walletRestoreFromKeysFormKey.currentState!.privateKeyController.text;
|
||||
|
||||
if (seedKey.length != 64 && seedKey.length != 128) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Map<String, dynamic> _credentials() {
|
||||
final credentials = <String, dynamic>{};
|
||||
|
||||
@@ -466,3 +267,283 @@ class _WalletRestorePageBodyState extends State<WalletRestorePageBody> {
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
class _WalletRestorePageBody extends StatefulWidget {
|
||||
const _WalletRestorePageBody({
|
||||
Key? key,
|
||||
required this.walletRestoreViewModel,
|
||||
required this.seedSettingsViewModel,
|
||||
required this.walletRestoreFromSeedFormKey,
|
||||
required this.walletRestoreFromKeysFormKey,
|
||||
required this.blockHeightFocusNode,
|
||||
required this.derivationInfo,
|
||||
required this.onDerivationInfoChanged,
|
||||
}) : super(key: key);
|
||||
|
||||
final WalletRestoreViewModel walletRestoreViewModel;
|
||||
final SeedSettingsViewModel seedSettingsViewModel;
|
||||
final GlobalKey<WalletRestoreFromSeedFormState> walletRestoreFromSeedFormKey;
|
||||
final GlobalKey<WalletRestoreFromKeysFromState> walletRestoreFromKeysFormKey;
|
||||
final FocusNode blockHeightFocusNode;
|
||||
final DerivationInfo? derivationInfo;
|
||||
final void Function(DerivationInfo?) onDerivationInfoChanged;
|
||||
|
||||
@override
|
||||
State<_WalletRestorePageBody> createState() => _WalletRestorePageBodyState(
|
||||
walletRestoreViewModel: walletRestoreViewModel,
|
||||
seedSettingsViewModel: seedSettingsViewModel,
|
||||
walletRestoreFromSeedFormKey: walletRestoreFromSeedFormKey,
|
||||
walletRestoreFromKeysFormKey: walletRestoreFromKeysFormKey,
|
||||
blockHeightFocusNode: blockHeightFocusNode,
|
||||
derivationInfo: derivationInfo);
|
||||
}
|
||||
|
||||
class _WalletRestorePageBodyState extends State<_WalletRestorePageBody>
|
||||
with SingleTickerProviderStateMixin {
|
||||
_WalletRestorePageBodyState(
|
||||
{required this.walletRestoreViewModel,
|
||||
required this.seedSettingsViewModel,
|
||||
required this.walletRestoreFromSeedFormKey,
|
||||
required this.walletRestoreFromKeysFormKey,
|
||||
required this.blockHeightFocusNode,
|
||||
required this.derivationInfo});
|
||||
|
||||
final WalletRestoreViewModel walletRestoreViewModel;
|
||||
final SeedSettingsViewModel seedSettingsViewModel;
|
||||
final GlobalKey<WalletRestoreFromSeedFormState> walletRestoreFromSeedFormKey;
|
||||
final GlobalKey<WalletRestoreFromKeysFromState> walletRestoreFromKeysFormKey;
|
||||
final FocusNode blockHeightFocusNode;
|
||||
DerivationInfo? derivationInfo;
|
||||
|
||||
late TabController _tabController;
|
||||
|
||||
late bool _hasKeysTab;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
|
||||
_hasKeysTab = widget.walletRestoreViewModel.availableModes.contains(WalletRestoreMode.keys);
|
||||
final tabCount = _hasKeysTab ? 2 : 1;
|
||||
_tabController = TabController(length: tabCount, vsync: this);
|
||||
|
||||
_tabController.addListener(() {
|
||||
if (!_tabController.indexIsChanging) {
|
||||
widget.walletRestoreViewModel.mode =
|
||||
_tabController.index == 0 ? WalletRestoreMode.seed : WalletRestoreMode.keys;
|
||||
}
|
||||
});
|
||||
|
||||
reaction<WalletRestoreMode>(
|
||||
(_) => widget.walletRestoreViewModel.mode,
|
||||
(mode) {
|
||||
final index = mode == WalletRestoreMode.seed ? 0 : 1;
|
||||
if (_tabController.index != index) {
|
||||
_tabController.animateTo(index);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
reaction((_) => walletRestoreViewModel.state, (ExecutionState state) {
|
||||
if (state is FailureState) {
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
showPopUp<void>(
|
||||
context: context,
|
||||
builder: (_) {
|
||||
return AlertWithOneAction(
|
||||
alertTitle: S.current.new_wallet,
|
||||
alertContent: state.error,
|
||||
buttonText: S.of(context).ok,
|
||||
buttonAction: () => Navigator.of(context).pop());
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
reaction((_) => walletRestoreViewModel.mode, (WalletRestoreMode mode) {
|
||||
walletRestoreViewModel.isButtonEnabled = false;
|
||||
walletRestoreViewModel.walletPassword = null;
|
||||
walletRestoreViewModel.repeatedWalletPassword = null;
|
||||
|
||||
walletRestoreFromSeedFormKey
|
||||
.currentState!.blockchainHeightKey.currentState!.restoreHeightController.text = '';
|
||||
walletRestoreFromSeedFormKey
|
||||
.currentState!.blockchainHeightKey.currentState!.dateController.text = '';
|
||||
walletRestoreFromSeedFormKey.currentState!.nameTextEditingController.text = '';
|
||||
|
||||
walletRestoreFromKeysFormKey
|
||||
.currentState!.blockchainHeightKey.currentState!.restoreHeightController.text = '';
|
||||
walletRestoreFromKeysFormKey
|
||||
.currentState!.blockchainHeightKey.currentState!.dateController.text = '';
|
||||
walletRestoreFromKeysFormKey.currentState!.nameTextEditingController.text = '';
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_tabController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
child: Column(
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 22),
|
||||
child: TabBar(
|
||||
controller: _tabController,
|
||||
splashFactory: NoSplash.splashFactory,
|
||||
indicatorSize: TabBarIndicatorSize.label,
|
||||
isScrollable: true,
|
||||
labelStyle: TextStyle(
|
||||
fontSize: 18,
|
||||
fontFamily: 'Lato',
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Theme.of(context).appBarTheme.titleTextStyle!.color),
|
||||
unselectedLabelStyle: TextStyle(
|
||||
fontSize: 18,
|
||||
fontFamily: 'Lato',
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Theme.of(context).appBarTheme.titleTextStyle!.color?.withOpacity(0.5)),
|
||||
labelColor: Theme.of(context).appBarTheme.titleTextStyle!.color,
|
||||
indicatorColor: Theme.of(context).appBarTheme.titleTextStyle!.color,
|
||||
indicatorPadding: EdgeInsets.zero,
|
||||
labelPadding: const EdgeInsets.only(right: 24),
|
||||
tabAlignment: TabAlignment.start,
|
||||
dividerColor: Colors.transparent,
|
||||
padding: EdgeInsets.zero,
|
||||
tabs: [
|
||||
Tab(text: S.of(context).widgets_seed),
|
||||
if (_hasKeysTab) Tab(text: S.of(context).keys),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
Expanded(
|
||||
child: TabBarView(
|
||||
controller: _tabController,
|
||||
children: [
|
||||
SingleChildScrollView(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8),
|
||||
child: _buildWalletRestoreFromSeedTab(),
|
||||
),
|
||||
if (_hasKeysTab)
|
||||
SingleChildScrollView(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8),
|
||||
child: _buildWalletRestoreFromKeysTab(),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
WalletRestoreFromKeysFrom _buildWalletRestoreFromKeysTab() {
|
||||
return WalletRestoreFromKeysFrom(
|
||||
key: widget.walletRestoreFromKeysFormKey,
|
||||
walletRestoreViewModel: widget.walletRestoreViewModel,
|
||||
displayPrivateKeyField: widget.walletRestoreViewModel.hasRestoreFromPrivateKey,
|
||||
displayWalletPassword: widget.walletRestoreViewModel.hasWalletPassword,
|
||||
onPrivateKeyChange: (String seed) {
|
||||
// For nano/banano, set button state if valid seed key
|
||||
if (widget.walletRestoreViewModel.type == WalletType.nano ||
|
||||
widget.walletRestoreViewModel.type == WalletType.banano) {
|
||||
widget.walletRestoreViewModel.isButtonEnabled = _isValidSeedKey();
|
||||
}
|
||||
},
|
||||
onPasswordChange: (String password) =>
|
||||
widget.walletRestoreViewModel.walletPassword = password,
|
||||
onRepeatedPasswordChange: (String repeatedPassword) =>
|
||||
widget.walletRestoreViewModel.repeatedWalletPassword = repeatedPassword,
|
||||
onHeightOrDateEntered: (value) => widget.walletRestoreViewModel.isButtonEnabled = value,
|
||||
);
|
||||
}
|
||||
|
||||
WalletRestoreFromSeedForm _buildWalletRestoreFromSeedTab() {
|
||||
return WalletRestoreFromSeedForm(
|
||||
key: widget.walletRestoreFromSeedFormKey,
|
||||
seedSettingsViewModel: widget.seedSettingsViewModel,
|
||||
displayBlockHeightSelector: widget.walletRestoreViewModel.hasBlockchainHeightLanguageSelector,
|
||||
displayLanguageSelector: widget.walletRestoreViewModel.hasSeedLanguageSelector,
|
||||
type: widget.walletRestoreViewModel.type,
|
||||
blockHeightFocusNode: widget.blockHeightFocusNode,
|
||||
onHeightOrDateEntered: (value) {
|
||||
// set button state
|
||||
if (_isValidSeed()) {
|
||||
widget.walletRestoreViewModel.isButtonEnabled = value;
|
||||
}
|
||||
},
|
||||
onSeedChange: (String seed) {
|
||||
final isPolyseed = widget.walletRestoreViewModel.isPolyseed(seed);
|
||||
_validateOnChange(isPolyseed: isPolyseed);
|
||||
},
|
||||
onLanguageChange: (String language) {
|
||||
final isPolyseed = language.startsWith("POLYSEED_");
|
||||
_validateOnChange(isPolyseed: isPolyseed);
|
||||
},
|
||||
displayWalletPassword: widget.walletRestoreViewModel.hasWalletPassword,
|
||||
onPasswordChange: (String password) =>
|
||||
widget.walletRestoreViewModel.walletPassword = password,
|
||||
onRepeatedPasswordChange: (String repeatedPassword) =>
|
||||
widget.walletRestoreViewModel.repeatedWalletPassword = repeatedPassword,
|
||||
);
|
||||
}
|
||||
|
||||
void _validateOnChange({bool isPolyseed = false}) {
|
||||
if (!isPolyseed && walletRestoreViewModel.hasBlockchainHeightLanguageSelector) {
|
||||
final hasHeight = walletRestoreFromSeedFormKey
|
||||
.currentState?.blockchainHeightKey.currentState?.restoreHeightController.text.isNotEmpty;
|
||||
|
||||
if (hasHeight == true) {
|
||||
walletRestoreViewModel.isButtonEnabled = _isValidSeed();
|
||||
}
|
||||
} else {
|
||||
walletRestoreViewModel.isButtonEnabled = _isValidSeed();
|
||||
}
|
||||
}
|
||||
|
||||
bool _isValidSeed() {
|
||||
final seedPhrase =
|
||||
walletRestoreFromSeedFormKey.currentState!.seedWidgetStateKey.currentState!.text;
|
||||
if (walletRestoreViewModel.isPolyseed(seedPhrase)) return true;
|
||||
|
||||
final seedWords = seedPhrase.split(' ');
|
||||
|
||||
if (seedWords.length == 14 && walletRestoreViewModel.type == WalletType.wownero) return true;
|
||||
if (seedWords.length == 26 && walletRestoreViewModel.type == WalletType.zano) return true;
|
||||
|
||||
if ((walletRestoreViewModel.type == WalletType.monero ||
|
||||
walletRestoreViewModel.type == WalletType.wownero ||
|
||||
walletRestoreViewModel.type == WalletType.haven) &&
|
||||
seedWords.length != WalletRestoreViewModelBase.moneroSeedMnemonicLength) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// bip39:
|
||||
final validBip39SeedLengths = [12, 18, 24];
|
||||
final nonBip39WalletTypes = [WalletType.monero, WalletType.wownero, WalletType.haven];
|
||||
// if it's a bip39 wallet and the length is not valid return false
|
||||
if (!nonBip39WalletTypes.contains(walletRestoreViewModel.type) &&
|
||||
!(validBip39SeedLengths.contains(seedWords.length))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final words =
|
||||
walletRestoreFromSeedFormKey.currentState!.seedWidgetStateKey.currentState!.words.toSet();
|
||||
return seedWords.toSet().difference(words).toSet().isEmpty;
|
||||
}
|
||||
|
||||
bool _isValidSeedKey() {
|
||||
final seedKey = walletRestoreFromKeysFormKey.currentState!.privateKeyController.text;
|
||||
|
||||
if (seedKey.length != 64 && seedKey.length != 128) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user