CakeWallet/lib/src/screens/new_wallet/new_wallet_page.dart
Omar Hatem ce12f517f4
v4.26.0 Release Candidate (#2191)
* v4.26.0 Release Candidate

* Fix Wownero Creation issue

* Add KES fiat currency
2025-04-12 03:23:41 +02:00

428 lines
19 KiB
Dart

import 'package:cake_wallet/core/execution_state.dart';
import 'package:cake_wallet/core/wallet_name_validator.dart';
import 'package:cake_wallet/entities/generate_name.dart';
import 'package:cake_wallet/entities/seed_type.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/main.dart';
import 'package:cake_wallet/routes.dart';
import 'package:cake_wallet/src/screens/base_page.dart';
import 'package:cake_wallet/src/screens/new_wallet/widgets/select_button.dart';
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
import 'package:cake_wallet/src/widgets/picker.dart';
import 'package:cake_wallet/src/widgets/primary_button.dart';
import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
import 'package:cake_wallet/src/widgets/seed_language_picker.dart';
import 'package:cake_wallet/src/widgets/seed_language_selector.dart';
import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
import 'package:cake_wallet/themes/extensions/new_wallet_theme.dart';
import 'package:cake_wallet/themes/extensions/send_page_theme.dart';
import 'package:cake_wallet/themes/theme_base.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/seed_settings_view_model.dart';
import 'package:cake_wallet/view_model/wallet_new_vm.dart';
import 'package:cw_core/wallet_type.dart';
import 'package:flutter/material.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:mobx/mobx.dart';
class NewWalletPage extends BasePage {
NewWalletPage(
this._walletNewVM,
this._seedSettingsViewModel, {
this.isChildWallet = false,
});
final WalletNewVM _walletNewVM;
final SeedSettingsViewModel _seedSettingsViewModel;
final bool isChildWallet;
final walletNameImage = Image.asset('assets/images/wallet_name.png');
final walletNameLightImage = Image.asset('assets/images/wallet_name_light.png');
@override
String get title => S.current.new_wallet;
@override
Function(BuildContext)? get pushToNextWidget => (context) {
FocusScopeNode currentFocus = FocusScope.of(context);
if (!currentFocus.hasPrimaryFocus) {
currentFocus.focusedChild?.unfocus();
}
};
@override
Widget body(BuildContext context) => WalletNameForm(
_walletNewVM,
currentTheme.type == ThemeType.dark ? walletNameImage : walletNameLightImage,
_seedSettingsViewModel,
isChildWallet,
);
}
class WalletNameForm extends StatefulWidget {
WalletNameForm(
this._walletNewVM,
this.walletImage,
this._seedSettingsViewModel,
this.isChildWallet,
);
final WalletNewVM _walletNewVM;
final bool isChildWallet;
final Image walletImage;
final SeedSettingsViewModel _seedSettingsViewModel;
@override
_WalletNameFormState createState() => _WalletNameFormState(_walletNewVM);
}
class _WalletNameFormState extends State<WalletNameForm> {
_WalletNameFormState(this._walletNewVM)
: _formKey = GlobalKey<FormState>(),
_languageSelectorKey = GlobalKey<SeedLanguageSelectorState>(),
_nameController = TextEditingController(),
_passwordController = _walletNewVM.hasWalletPassword ? TextEditingController() : null,
_repeatedPasswordController =
_walletNewVM.hasWalletPassword ? TextEditingController() : null;
static const aspectRatioImage = 1.22;
bool _formProcessing = false;
final GlobalKey<FormState> _formKey;
final GlobalKey<SeedLanguageSelectorState> _languageSelectorKey;
final WalletNewVM _walletNewVM;
final TextEditingController _nameController;
final TextEditingController? _passwordController;
final TextEditingController? _repeatedPasswordController;
ReactionDisposer? _stateReaction;
@override
void initState() {
_stateReaction ??= reaction((_) => _walletNewVM.state, (ExecutionState state) async {
if (state is ExecutedSuccessfullyState) {
if (widget.isChildWallet) {
Navigator.of(navigatorKey.currentContext ?? context).pushNamed(
Routes.walletGroupExistingSeedDescriptionPage,
arguments: _walletNewVM.seedPhraseWordsLength);
} else {
Navigator.of(navigatorKey.currentContext ?? context)
.pushNamed(Routes.preSeedPage, arguments: _walletNewVM.seedPhraseWordsLength);
}
}
if (state is FailureState) {
WidgetsBinding.instance.addPostFrameCallback((_) {
if (mounted) {
showPopUp<void>(
context: context,
builder: (_) {
return AlertWithOneAction(
key: ValueKey('new_wallet_page_failure_dialog_key'),
buttonKey: ValueKey('new_wallet_page_failure_dialog_button_key'),
alertTitle: S.current.new_wallet,
alertContent: state.error,
buttonText: S.of(context).ok,
buttonAction: () => Navigator.of(context).pop(),
);
});
}
});
}
});
_setSeedType(MoneroSeedType.defaultSeedType);
super.initState();
}
@override
Widget build(BuildContext context) {
return Padding(
padding: EdgeInsets.only(top: 24),
child: ScrollableWithBottomSection(
contentPadding: EdgeInsets.only(left: 24, right: 24, bottom: 24),
content: Center(
child: ConstrainedBox(
constraints:
BoxConstraints(maxWidth: ResponsiveLayoutUtilBase.kDesktopMaxWidthConstraint),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Padding(
padding: EdgeInsets.only(left: 12, right: 12),
child: AspectRatio(
aspectRatio: aspectRatioImage,
child: FittedBox(child: widget.walletImage, fit: BoxFit.fill)),
),
Padding(
padding: EdgeInsets.only(top: 24),
child: Form(
key: _formKey,
child: Column(
children: [
TextFormField(
key: ValueKey('new_wallet_page_wallet_name_textformfield_key'),
onChanged: (value) => _walletNewVM.name = value,
controller: _nameController,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 20.0,
fontWeight: FontWeight.w600,
color: Theme.of(context).extension<CakeTextTheme>()!.titleColor),
decoration: InputDecoration(
hintStyle: TextStyle(
fontSize: 18.0,
fontWeight: FontWeight.w500,
color:
Theme.of(context).extension<NewWalletTheme>()!.hintTextColor),
hintText: S.of(context).wallet_name,
focusedBorder: UnderlineInputBorder(
borderSide: BorderSide(
color: Theme.of(context)
.extension<NewWalletTheme>()!
.underlineColor,
width: 1.0)),
enabledBorder: UnderlineInputBorder(
borderSide: BorderSide(
color: Theme.of(context)
.extension<NewWalletTheme>()!
.underlineColor,
width: 1.0),
),
suffixIcon: Semantics(
label: S.of(context).generate_name,
child: IconButton(
key: ValueKey(
'new_wallet_page_wallet_name_textformfield_generate_name_button_key'),
onPressed: () async {
final rName = await generateName();
FocusManager.instance.primaryFocus?.unfocus();
setState(() {
_nameController.text = rName;
_walletNewVM.name = rName;
_nameController.selection = TextSelection.fromPosition(
TextPosition(offset: _nameController.text.length));
});
},
icon: Container(
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(6.0),
color: Theme.of(context).hintColor,
),
width: 34,
height: 34,
child: Image.asset(
'assets/images/refresh_icon.png',
color: Theme.of(context)
.extension<SendPageTheme>()!
.textFieldButtonIconColor,
),
),
),
),
),
validator: WalletNameValidator(),
),
if (_walletNewVM.hasWalletPassword) ...[
TextFormField(
key: ValueKey('password'),
onChanged: (value) => _walletNewVM.walletPassword = value,
controller: _passwordController,
textAlign: TextAlign.center,
obscureText: true,
style: TextStyle(
fontSize: 20.0,
fontWeight: FontWeight.w600,
color: Theme.of(context).extension<CakeTextTheme>()!.titleColor,
),
decoration: InputDecoration(
hintStyle: TextStyle(
fontSize: 18.0,
fontWeight: FontWeight.w500,
color:
Theme.of(context).extension<NewWalletTheme>()!.hintTextColor,
),
hintText: S.of(context).password,
focusedBorder: UnderlineInputBorder(
borderSide: BorderSide(
color: Theme.of(context)
.extension<NewWalletTheme>()!
.underlineColor,
width: 1.0,
),
),
enabledBorder: UnderlineInputBorder(
borderSide: BorderSide(
color: Theme.of(context)
.extension<NewWalletTheme>()!
.underlineColor,
width: 1.0,
),
),
),
),
TextFormField(
key: ValueKey('repeat_wallet_password'),
onChanged: (value) => _walletNewVM.repeatedWalletPassword = value,
controller: _repeatedPasswordController,
textAlign: TextAlign.center,
obscureText: true,
style: TextStyle(
fontSize: 20.0,
fontWeight: FontWeight.w600,
color: Theme.of(context).extension<CakeTextTheme>()!.titleColor,
),
decoration: InputDecoration(
hintStyle: TextStyle(
fontSize: 18.0,
fontWeight: FontWeight.w500,
color:
Theme.of(context).extension<NewWalletTheme>()!.hintTextColor,
),
hintText: S.of(context).repeat_wallet_password,
focusedBorder: UnderlineInputBorder(
borderSide: BorderSide(
color: Theme.of(context)
.extension<NewWalletTheme>()!
.underlineColor,
width: 1.0,
),
),
enabledBorder: UnderlineInputBorder(
borderSide: BorderSide(
color: Theme.of(context)
.extension<NewWalletTheme>()!
.underlineColor,
width: 1.0,
),
),
),
),
],
],
),
),
),
if (_walletNewVM.showLanguageSelector) ...[
if (_walletNewVM.hasSeedType) ...[
Observer(
builder: (BuildContext build) => Padding(
padding: EdgeInsets.only(top: 24),
child: SelectButton(
key: ValueKey('new_wallet_page_monero_seed_type_button_key'),
text: widget._seedSettingsViewModel.moneroSeedType.title,
onTap: () async {
await showPopUp<void>(
context: context,
builder: (_) => Picker(
items: MoneroSeedType.all
.where((e) => // exclude bip39 in case of Wownero
widget._walletNewVM.type != WalletType.wownero ||
e.raw != MoneroSeedType.bip39.raw)
.toList(),
selectedAtIndex: isPolyseed ? 1 : 0,
onItemSelected: _setSeedType,
isSeparated: false,
),
);
},
),
),
),
],
Observer(
builder: (BuildContext build) => Padding(
padding: EdgeInsets.only(top: 10),
child: SeedLanguageSelector(
key: _languageSelectorKey,
buttonKey: ValueKey('new_wallet_page_seed_language_selector_button_key'),
initialSelected: defaultSeedLanguage,
seedType: _walletNewVM.hasSeedType
? widget._seedSettingsViewModel.moneroSeedType
: MoneroSeedType.legacy,
),
),
)
],
],
),
),
),
bottomSectionPadding: EdgeInsets.all(24),
bottomSection: Column(
children: [
Observer(
builder: (context) {
return LoadingPrimaryButton(
key: ValueKey('new_wallet_page_confirm_button_key'),
onPressed: _confirmForm,
text: S.of(context).seed_language_next,
color: Theme.of(context).primaryColor,
textColor: Colors.white,
isLoading: _walletNewVM.state is IsExecutingState,
isDisabled: _walletNewVM.name.isEmpty,
);
},
),
const SizedBox(height: 25),
GestureDetector(
key: ValueKey('new_wallet_page_advanced_settings_button_key'),
onTap: () {
Navigator.of(context).pushNamed(Routes.advancedPrivacySettings, arguments: {
"type": _walletNewVM.type,
"useTestnet": _walletNewVM.useTestnet,
"toggleTestnet": _walletNewVM.toggleUseTestnet,
"isChildWallet": widget.isChildWallet,
});
},
child: Text(S.of(context).advanced_settings),
),
],
)),
);
}
void _confirmForm() async {
if (_formProcessing) return;
_formProcessing = true;
try {
if (_formKey.currentState != null && !_formKey.currentState!.validate()) {
_formProcessing = false;
return;
}
if (_walletNewVM.nameExists(_walletNewVM.name)) {
await showPopUp<void>(
context: context,
builder: (_) {
return AlertWithOneAction(
alertTitle: '',
alertContent: S.of(context).wallet_name_exists,
buttonText: S.of(context).ok,
buttonAction: () => Navigator.of(context).pop());
});
} else {
await _walletNewVM.create(
options: _walletNewVM.hasLanguageSelector
? [
_languageSelectorKey.currentState?.selected ?? defaultSeedLanguage,
widget._seedSettingsViewModel.moneroSeedType
]
: null);
}
} catch (e) {
_formProcessing = false;
rethrow;
}
_formProcessing = false;
}
bool get isPolyseed => widget._seedSettingsViewModel.moneroSeedType == MoneroSeedType.polyseed;
void _setSeedType(MoneroSeedType item) {
widget._seedSettingsViewModel.setMoneroSeedType(item);
_languageSelectorKey.currentState?.selected = defaultSeedLanguage; // Reset Seed language
}
}