mirror of
https://github.com/Such-Software/hash-wallet.git
synced 2026-10-17 05:41:29 +02:00
Merge remote-tracking branch 'origin/main'
This commit is contained in:
@@ -32,23 +32,28 @@ class WalletLoadingService {
|
||||
|
||||
Future<void> renameWallet(WalletType type, String name, String newName,
|
||||
{String? password}) async {
|
||||
final walletService = walletServiceFactory.call(type);
|
||||
final walletPassword = password ?? (await keyService.getWalletPassword(walletName: name));
|
||||
try {
|
||||
final walletService = walletServiceFactory.call(type);
|
||||
final walletPassword = password ?? (await keyService.getWalletPassword(walletName: name));
|
||||
|
||||
// Save the current wallet's password to the new wallet name's key
|
||||
await keyService.saveWalletPassword(walletName: newName, password: walletPassword);
|
||||
// Delete previous wallet name from keyService to keep only new wallet's name
|
||||
// otherwise keeps duplicate (old and new names)
|
||||
await keyService.deleteWalletPassword(walletName: name);
|
||||
// Save the current wallet's password to the new wallet name's key
|
||||
await keyService.saveWalletPassword(walletName: newName, password: walletPassword);
|
||||
|
||||
await walletService.rename(name, walletPassword, newName);
|
||||
await walletService.rename(name, walletPassword, newName);
|
||||
// Delete previous wallet name from keyService to keep only new wallet's name
|
||||
// otherwise keeps duplicate (old and new names)
|
||||
await keyService.deleteWalletPassword(walletName: name);
|
||||
|
||||
// set shared preferences flag based on previous wallet name
|
||||
if (type == WalletType.monero) {
|
||||
final oldNameKey = PreferencesKey.moneroWalletUpdateV1Key(name);
|
||||
final isPasswordUpdated = sharedPreferences.getBool(oldNameKey) ?? false;
|
||||
final newNameKey = PreferencesKey.moneroWalletUpdateV1Key(newName);
|
||||
await sharedPreferences.setBool(newNameKey, isPasswordUpdated);
|
||||
// set shared preferences flag based on previous wallet name
|
||||
if (type == WalletType.monero) {
|
||||
final oldNameKey = PreferencesKey.moneroWalletUpdateV1Key(name);
|
||||
final isPasswordUpdated = sharedPreferences.getBool(oldNameKey) ?? false;
|
||||
final newNameKey = PreferencesKey.moneroWalletUpdateV1Key(newName);
|
||||
await sharedPreferences.setBool(newNameKey, isPasswordUpdated);
|
||||
}
|
||||
} catch (error, stack) {
|
||||
await ExceptionHandler.resetLastPopupDate();
|
||||
await ExceptionHandler.onError(FlutterErrorDetails(exception: error, stack: stack));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -39,14 +39,14 @@ class CWMoneroAccountList extends MoneroAccountList {
|
||||
@override
|
||||
Future<void> addAccount(Object wallet, {required String label}) async {
|
||||
final moneroWallet = wallet as MoneroWallet;
|
||||
await moneroWallet.walletAddresses.accountList.addAccount(label: label);
|
||||
moneroWallet.walletAddresses.accountList.addAccount(label: label);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> setLabelAccount(Object wallet,
|
||||
{required int accountIndex, required String label}) async {
|
||||
final moneroWallet = wallet as MoneroWallet;
|
||||
await moneroWallet.walletAddresses.accountList
|
||||
moneroWallet.walletAddresses.accountList
|
||||
.setLabelAccount(accountIndex: accountIndex, label: label);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -204,7 +204,7 @@ class _AdvancedPrivacySettingsBodyState extends State<_AdvancedPrivacySettingsBo
|
||||
);
|
||||
return Container();
|
||||
}),
|
||||
if (widget.privacySettingsViewModel.hasPassphraseOption)
|
||||
if (widget.privacySettingsViewModel.hasPassphraseOption && !widget.isFromRestore)
|
||||
Padding(
|
||||
padding: EdgeInsets.all(24),
|
||||
child: Form(
|
||||
|
||||
@@ -5,10 +5,14 @@ import 'package:cake_wallet/src/screens/base_page.dart';
|
||||
import 'package:cake_wallet/src/screens/restore/wallet_restore_from_keys_form.dart';
|
||||
import 'package:cake_wallet/src/screens/restore/wallet_restore_from_seed_form.dart';
|
||||
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
|
||||
import 'package:cake_wallet/src/widgets/bottom_sheet/add_passphrase_bottom_sheet_widget.dart';
|
||||
import 'package:cake_wallet/src/widgets/keyboard_done_button.dart';
|
||||
import 'package:cake_wallet/src/widgets/primary_button.dart';
|
||||
import 'package:cake_wallet/src/widgets/standard_checkbox.dart';
|
||||
import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
|
||||
import 'package:cake_wallet/themes/extensions/dashboard_page_theme.dart';
|
||||
import 'package:cake_wallet/themes/extensions/keyboard_theme.dart';
|
||||
import 'package:cake_wallet/themes/extensions/wallet_list_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/restore/restore_mode.dart';
|
||||
@@ -52,7 +56,6 @@ class WalletRestorePage extends BasePage {
|
||||
// String? derivationPath = null;
|
||||
DerivationInfo? derivationInfo;
|
||||
|
||||
|
||||
@override
|
||||
Function(BuildContext)? get popWidget => (context) => seedSettingsViewModel.setPassphrase(null);
|
||||
|
||||
@@ -102,37 +105,81 @@ class WalletRestorePage extends BasePage {
|
||||
padding: EdgeInsets.only(top: 20, bottom: 24, left: 24, right: 24),
|
||||
child: Column(
|
||||
children: [
|
||||
Observer(
|
||||
builder: (context) {
|
||||
return walletRestoreViewModel.mode == WalletRestoreMode.seed
|
||||
? StandardCheckbox(
|
||||
value: walletRestoreViewModel.hasPassphrase,
|
||||
caption: S.of(context).wallet_has_passphrase,
|
||||
onChanged: (value) {
|
||||
walletRestoreViewModel.hasPassphrase = value;
|
||||
},
|
||||
)
|
||||
: SizedBox.shrink();
|
||||
},
|
||||
),
|
||||
SizedBox(height: 16),
|
||||
PrimaryButton(
|
||||
key: ValueKey('wallet_restore_advanced_settings_button_key'),
|
||||
onPressed: () {
|
||||
Navigator.of(context).pushNamed(
|
||||
Routes.advancedPrivacySettings,
|
||||
arguments: {
|
||||
'isFromRestore': true,
|
||||
'type': walletRestoreViewModel.type,
|
||||
'useTestnet': walletRestoreViewModel.useTestnet,
|
||||
'toggleTestnet': walletRestoreViewModel.toggleUseTestnet
|
||||
},
|
||||
);
|
||||
},
|
||||
text: S.of(context).advanced_settings,
|
||||
color: Theme.of(context).cardColor,
|
||||
textColor: Theme.of(context).extension<CakeTextTheme>()!.buttonTextColor,
|
||||
),
|
||||
SizedBox(height: 8),
|
||||
Observer(
|
||||
builder: (context) {
|
||||
return LoadingPrimaryButton(
|
||||
key: ValueKey('wallet_restore_seed_or_key_restore_button_key'),
|
||||
onPressed: () async => await _confirmForm(context),
|
||||
text: S.of(context).restore_recover,
|
||||
color: Theme.of(context)
|
||||
.extension<WalletListTheme>()!
|
||||
.createNewWalletButtonBackgroundColor,
|
||||
textColor: Theme.of(context)
|
||||
.extension<WalletListTheme>()!
|
||||
.restoreWalletButtonTextColor,
|
||||
onPressed: () async {
|
||||
if (walletRestoreViewModel.hasPassphrase) {
|
||||
await showModalBottomSheet<void>(
|
||||
context: context,
|
||||
isDismissible: false,
|
||||
isScrollControlled: true,
|
||||
builder: (BuildContext bottomSheetContext) {
|
||||
return Padding(
|
||||
padding: EdgeInsets.only(
|
||||
bottom: MediaQuery.of(bottomSheetContext).viewInsets.bottom,
|
||||
),
|
||||
child: AddPassphraseBottomSheet(
|
||||
currentTheme: currentTheme,
|
||||
titleText: S.of(context).add_passphrase,
|
||||
onRestoreButtonPressed: (passphrase) async {
|
||||
await _onPassphraseBottomSheetRestoreButtonPressed(
|
||||
passphrase,
|
||||
context,
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
} else {
|
||||
await _confirmForm(context);
|
||||
}
|
||||
},
|
||||
text: walletRestoreViewModel.hasPassphrase
|
||||
? S.of(context).add_passphrase
|
||||
: S.of(context).restore_recover,
|
||||
color: Theme.of(context).primaryColor,
|
||||
textColor: Colors.white,
|
||||
isLoading: walletRestoreViewModel.state is IsExecutingState,
|
||||
isDisabled: !walletRestoreViewModel.isButtonEnabled,
|
||||
);
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 25),
|
||||
GestureDetector(
|
||||
key: ValueKey('wallet_restore_advanced_settings_button_key'),
|
||||
onTap: () {
|
||||
Navigator.of(context)
|
||||
.pushNamed(Routes.advancedPrivacySettings, arguments: {
|
||||
'isFromRestore': true,
|
||||
'type': walletRestoreViewModel.type,
|
||||
'useTestnet': walletRestoreViewModel.useTestnet,
|
||||
'toggleTestnet': walletRestoreViewModel.toggleUseTestnet
|
||||
});
|
||||
},
|
||||
child: Text(S.of(context).advanced_settings),
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
],
|
||||
),
|
||||
)
|
||||
@@ -144,6 +191,14 @@ class WalletRestorePage extends BasePage {
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _onPassphraseBottomSheetRestoreButtonPressed(
|
||||
String passphrase,
|
||||
BuildContext context,
|
||||
) async {
|
||||
walletRestoreViewModel.seedSettingsViewModel.setPassphrase(passphrase);
|
||||
await _confirmForm(context);
|
||||
}
|
||||
|
||||
Map<String, dynamic> _credentials() {
|
||||
final credentials = <String, dynamic>{};
|
||||
|
||||
@@ -172,9 +227,10 @@ class WalletRestorePage extends BasePage {
|
||||
walletRestoreFromKeysFormKey.currentState!.nameTextEditingController.text;
|
||||
credentials['viewKey'] = walletRestoreFromKeysFormKey.currentState!.viewKeyController.text;
|
||||
if (walletRestoreViewModel.type != WalletType.decred) {
|
||||
credentials['address'] = walletRestoreFromKeysFormKey.currentState!.addressController.text;
|
||||
credentials['address'] =
|
||||
walletRestoreFromKeysFormKey.currentState!.addressController.text;
|
||||
credentials['spendKey'] =
|
||||
walletRestoreFromKeysFormKey.currentState!.spendKeyController.text;
|
||||
walletRestoreFromKeysFormKey.currentState!.spendKeyController.text;
|
||||
credentials['height'] =
|
||||
walletRestoreFromKeysFormKey.currentState!.blockchainHeightKey.currentState!.height;
|
||||
}
|
||||
@@ -335,8 +391,8 @@ class _WalletRestorePageBodyState extends State<_WalletRestorePageBody>
|
||||
final initialIndex = walletRestoreViewModel.mode == WalletRestoreMode.seed
|
||||
? 0
|
||||
: _hasKeysTab
|
||||
? 1
|
||||
: 0;
|
||||
? 1
|
||||
: 0;
|
||||
|
||||
_tabController = TabController(length: tabCount, vsync: this, initialIndex: initialIndex);
|
||||
|
||||
@@ -429,7 +485,7 @@ class _WalletRestorePageBodyState extends State<_WalletRestorePageBody>
|
||||
padding: EdgeInsets.zero,
|
||||
tabs: [
|
||||
Tab(text: S.of(context).widgets_seed),
|
||||
if (_hasKeysTab) Tab(text: S.of(context).keys),
|
||||
if (_hasKeysTab) Tab(text: S.of(context).keys),
|
||||
],
|
||||
),
|
||||
),
|
||||
@@ -527,42 +583,30 @@ class _WalletRestorePageBodyState extends State<_WalletRestorePageBody>
|
||||
}
|
||||
|
||||
bool _isValidSeed() {
|
||||
final seedPhrase = walletRestoreFromSeedFormKey
|
||||
.currentState!.seedWidgetStateKey.currentState!.text;
|
||||
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 (seedWords.length == 14 && walletRestoreViewModel.type == WalletType.wownero) return true;
|
||||
if (seedWords.length == 26 && walletRestoreViewModel.type == WalletType.zano) return true;
|
||||
|
||||
if (seedWords.length == 12 &&
|
||||
walletRestoreViewModel.type == WalletType.monero) {
|
||||
return walletRestoreFromSeedFormKey
|
||||
.currentState
|
||||
?.blockchainHeightKey
|
||||
.currentState
|
||||
?.restoreHeightController
|
||||
.text
|
||||
.isNotEmpty == true;
|
||||
if (seedWords.length == 12 && walletRestoreViewModel.type == WalletType.monero) {
|
||||
return walletRestoreFromSeedFormKey.currentState?.blockchainHeightKey.currentState
|
||||
?.restoreHeightController.text.isNotEmpty ==
|
||||
true;
|
||||
}
|
||||
|
||||
if ([WalletType.monero, WalletType.wownero, WalletType.haven]
|
||||
.contains(walletRestoreViewModel.type) &&
|
||||
seedWords.length ==
|
||||
WalletRestoreViewModelBase.moneroSeedMnemonicLength) {
|
||||
seedWords.length == WalletRestoreViewModelBase.moneroSeedMnemonicLength) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// bip39:
|
||||
final validBip39SeedLengths = [12, 18, 24];
|
||||
final nonBip39WalletTypes = [
|
||||
WalletType.wownero,
|
||||
WalletType.haven,
|
||||
WalletType.decred
|
||||
];
|
||||
final nonBip39WalletTypes = [WalletType.wownero, WalletType.haven, WalletType.decred];
|
||||
// if it's a bip39 wallet and the length is not valid return false
|
||||
if (!nonBip39WalletTypes.contains(walletRestoreViewModel.type) &&
|
||||
!(validBip39SeedLengths.contains(seedWords.length))) {
|
||||
@@ -570,14 +614,12 @@ class _WalletRestorePageBodyState extends State<_WalletRestorePageBody>
|
||||
}
|
||||
|
||||
if ((walletRestoreViewModel.type == WalletType.decred) &&
|
||||
seedWords.length !=
|
||||
WalletRestoreViewModelBase.decredSeedMnemonicLength) {
|
||||
seedWords.length != WalletRestoreViewModelBase.decredSeedMnemonicLength) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final words = walletRestoreFromSeedFormKey
|
||||
.currentState!.seedWidgetStateKey.currentState!.words
|
||||
.toSet();
|
||||
final words =
|
||||
walletRestoreFromSeedFormKey.currentState!.seedWidgetStateKey.currentState!.words.toSet();
|
||||
return seedWords.toSet().difference(words).toSet().isEmpty;
|
||||
}
|
||||
|
||||
|
||||
@@ -15,6 +15,8 @@ class BaseTextFormField extends StatelessWidget {
|
||||
this.textColor,
|
||||
this.hintColor,
|
||||
this.borderColor,
|
||||
this.fillColor,
|
||||
this.filled,
|
||||
this.prefix,
|
||||
this.prefixIcon,
|
||||
this.suffix,
|
||||
@@ -44,6 +46,8 @@ class BaseTextFormField extends StatelessWidget {
|
||||
final Color? textColor;
|
||||
final Color? hintColor;
|
||||
final Color? borderColor;
|
||||
final Color? fillColor;
|
||||
bool? filled;
|
||||
final Widget? prefix;
|
||||
final Widget? prefixIcon;
|
||||
final Widget? suffix;
|
||||
@@ -89,6 +93,8 @@ class BaseTextFormField extends StatelessWidget {
|
||||
prefixIcon: prefixIcon,
|
||||
suffix: suffix,
|
||||
suffixIcon: suffixIcon,
|
||||
fillColor: fillColor,
|
||||
filled: filled,
|
||||
hintStyle: placeholderTextStyle ??
|
||||
TextStyle(
|
||||
color: hintColor ?? Theme.of(context).hintColor,
|
||||
|
||||
@@ -0,0 +1,220 @@
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/palette.dart';
|
||||
import 'package:cake_wallet/src/widgets/primary_button.dart';
|
||||
import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
|
||||
import 'package:cake_wallet/themes/theme_base.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
|
||||
class AddPassphraseBottomSheet extends StatefulWidget {
|
||||
AddPassphraseBottomSheet({
|
||||
required String titleText,
|
||||
required this.currentTheme,
|
||||
required this.onRestoreButtonPressed,
|
||||
});
|
||||
|
||||
final void Function(String) onRestoreButtonPressed;
|
||||
final ThemeBase currentTheme;
|
||||
|
||||
@override
|
||||
State<AddPassphraseBottomSheet> createState() => _AddPassphraseBottomSheetState();
|
||||
}
|
||||
|
||||
class _AddPassphraseBottomSheetState extends State<AddPassphraseBottomSheet> {
|
||||
late final TextEditingController passphraseController;
|
||||
late final TextEditingController confirmPassphraseController;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
passphraseController = TextEditingController();
|
||||
confirmPassphraseController = TextEditingController();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
passphraseController.dispose();
|
||||
confirmPassphraseController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
bool obscurePassphrase = true;
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: const BorderRadius.vertical(top: Radius.circular(30.0)),
|
||||
color: Theme.of(context).dialogBackgroundColor,
|
||||
),
|
||||
child: SingleChildScrollView(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 16),
|
||||
child: Column(
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
const Spacer(flex: 4),
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Container(
|
||||
height: 6,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(4),
|
||||
color:
|
||||
Theme.of(context).extension<CakeTextTheme>()!.titleColor.withOpacity(0.6),
|
||||
),
|
||||
),
|
||||
),
|
||||
const Spacer(flex: 4),
|
||||
],
|
||||
),
|
||||
SizedBox(height: 16),
|
||||
Text(
|
||||
S.of(context).add_passphrase,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
fontFamily: 'Lato',
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Theme.of(context).extension<CakeTextTheme>()!.titleColor,
|
||||
decoration: TextDecoration.none,
|
||||
),
|
||||
),
|
||||
SvgPicture.asset('assets/images/passphrase_key.svg'),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
child: Text.rich(
|
||||
TextSpan(
|
||||
children: [
|
||||
TextSpan(
|
||||
text: '${S.of(context).warning.toUpperCase()}: ',
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontFamily: 'Lato',
|
||||
fontWeight: FontWeight.w700,
|
||||
color: Palette.red,
|
||||
decoration: TextDecoration.none,
|
||||
),
|
||||
),
|
||||
TextSpan(
|
||||
text: S.of(context).add_passphrase_warning_text,
|
||||
),
|
||||
],
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontFamily: 'Lato',
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Theme.of(context).extension<CakeTextTheme>()!.titleColor.withOpacity(0.7),
|
||||
decoration: TextDecoration.none,
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(height: 24),
|
||||
TextFormField(
|
||||
key: ValueKey('add_passphrase_bottom_sheet_widget_passphrase_textfield_key'),
|
||||
controller: passphraseController,
|
||||
obscureText: obscurePassphrase,
|
||||
decoration: InputDecoration(
|
||||
contentPadding: EdgeInsets.symmetric(horizontal: 12),
|
||||
filled: true,
|
||||
fillColor: Theme.of(context).cardColor,
|
||||
hintText: S.of(context).required_passphrase,
|
||||
suffixIcon: GestureDetector(
|
||||
onTap: () {
|
||||
setState(() {
|
||||
obscurePassphrase = !obscurePassphrase;
|
||||
});
|
||||
},
|
||||
child: Icon(
|
||||
obscurePassphrase ? Icons.visibility_off : Icons.visibility,
|
||||
size: 24,
|
||||
color: Theme.of(context).textTheme.bodyLarge?.color?.withOpacity(0.6),
|
||||
),
|
||||
),
|
||||
border: OutlineInputBorder(
|
||||
borderSide: BorderSide.none,
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(height: 8),
|
||||
TextFormField(
|
||||
key: ValueKey('add_passphrase_bottom_sheet_widget_confirm_passphrase_textfield_key'),
|
||||
controller: confirmPassphraseController,
|
||||
obscureText: obscurePassphrase,
|
||||
decoration: InputDecoration(
|
||||
contentPadding: EdgeInsets.symmetric(horizontal: 12),
|
||||
filled: true,
|
||||
fillColor: Theme.of(context).cardColor,
|
||||
hintText: S.of(context).confirm_passphrase,
|
||||
suffixIcon: GestureDetector(
|
||||
onTap: () {
|
||||
setState(() {
|
||||
obscurePassphrase = !obscurePassphrase;
|
||||
});
|
||||
},
|
||||
child: Icon(
|
||||
obscurePassphrase ? Icons.visibility_off : Icons.visibility,
|
||||
size: 24,
|
||||
color: Theme.of(context).textTheme.bodyLarge?.color?.withOpacity(0.6),
|
||||
),
|
||||
),
|
||||
border: OutlineInputBorder(
|
||||
borderSide: BorderSide.none,
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
),
|
||||
),
|
||||
validator: (text) {
|
||||
if (text == passphraseController.text) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return S.of(context).passphrases_doesnt_match;
|
||||
},
|
||||
),
|
||||
SizedBox(height: 16),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
children: [
|
||||
Flexible(
|
||||
child: Container(
|
||||
padding: const EdgeInsets.only(right: 8.0, top: 8.0),
|
||||
child: PrimaryButton(
|
||||
key: ValueKey('add_passphrase_bottom_sheet_widget_cancel_button_key'),
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
text: S.of(context).cancel,
|
||||
color: Theme.of(context).cardColor,
|
||||
textColor: Theme.of(context).extension<CakeTextTheme>()!.buttonTextColor,
|
||||
),
|
||||
),
|
||||
),
|
||||
Flexible(
|
||||
child: Container(
|
||||
padding: const EdgeInsets.only(left: 8.0, top: 8.0),
|
||||
child: PrimaryButton(
|
||||
key: ValueKey('add_passphrase_bottom_sheet_widget_restore_button_key'),
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
widget.onRestoreButtonPressed(passphraseController.text);
|
||||
},
|
||||
text: S.of(context).restore,
|
||||
color: Theme.of(context).primaryColor,
|
||||
textColor: Colors.white,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
SizedBox(height: 24),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -57,7 +57,11 @@ abstract class ContactViewModelBase with Store {
|
||||
state = IsExecutingState();
|
||||
final now = DateTime.now();
|
||||
|
||||
if (doesContactNameExist(name)) {
|
||||
final nameExists = _contact == null
|
||||
? doesContactNameExist(name)
|
||||
: doesContactNameExist(name) && _contact.original.name != name;
|
||||
|
||||
if (nameExists) {
|
||||
state = FailureState(S.current.contact_name_exists);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -271,10 +271,19 @@ abstract class DashboardViewModelBase with Store {
|
||||
});
|
||||
|
||||
_transactionDisposer?.reaction.dispose();
|
||||
_transactionDisposer = reaction(
|
||||
(_) => appStore.wallet!.transactionHistory.transactions.length,
|
||||
_transactionDisposerCallback,
|
||||
);
|
||||
_transactionDisposer = reaction((_) {
|
||||
final length = appStore.wallet!.transactionHistory.transactions.length;
|
||||
if (length == 0) {
|
||||
return 0;
|
||||
}
|
||||
int confirmations = 1;
|
||||
if (![WalletType.solana, WalletType.tron].contains(wallet.type)) {
|
||||
try {
|
||||
confirmations = appStore.wallet!.transactionHistory.transactions.values.first.confirmations + 1;
|
||||
} catch (_) {}
|
||||
}
|
||||
return length * confirmations;
|
||||
}, _transactionDisposerCallback);
|
||||
|
||||
if (hasSilentPayments) {
|
||||
silentPaymentsScanningActive = bitcoin!.getScanningActive(wallet);
|
||||
@@ -891,8 +900,19 @@ abstract class DashboardViewModelBase with Store {
|
||||
|
||||
_transactionDisposer?.reaction.dispose();
|
||||
|
||||
_transactionDisposer = reaction((_) => appStore.wallet!.transactionHistory.transactions.length,
|
||||
_transactionDisposerCallback);
|
||||
_transactionDisposer = reaction((_) {
|
||||
final length = appStore.wallet!.transactionHistory.transactions.length;
|
||||
if (length == 0) {
|
||||
return 0;
|
||||
}
|
||||
int confirmations = 1;
|
||||
if (![WalletType.solana, WalletType.tron].contains(wallet.type)) {
|
||||
try {
|
||||
confirmations = appStore.wallet!.transactionHistory.transactions.values.first.confirmations + 1;
|
||||
} catch (_) {}
|
||||
}
|
||||
return length * confirmations;
|
||||
}, _transactionDisposerCallback);
|
||||
}
|
||||
|
||||
@action
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:cake_wallet/bitcoin/bitcoin.dart';
|
||||
import 'package:cake_wallet/core/address_validator.dart';
|
||||
import 'package:cake_wallet/core/amount_validator.dart';
|
||||
@@ -591,7 +593,7 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor
|
||||
}
|
||||
final sharedPreferences = await SharedPreferences.getInstance();
|
||||
await sharedPreferences.setString(PreferencesKey.backgroundSyncLastTrigger(wallet.name), DateTime.now().add(Duration(minutes: 1)).toIso8601String());
|
||||
|
||||
unawaited(wallet.fetchTransactions());
|
||||
state = TransactionCommitted();
|
||||
} catch (e) {
|
||||
state = FailureState(translateErrorMessage(e, wallet.type, wallet.currency));
|
||||
|
||||
@@ -43,6 +43,7 @@ abstract class WalletRestoreViewModelBase extends WalletCreationVM with Store {
|
||||
type == WalletType.solana ||
|
||||
type == WalletType.tron,
|
||||
isButtonEnabled = false,
|
||||
hasPassphrase = false,
|
||||
mode = restoredWallet?.restoreMode ?? WalletRestoreMode.seed,
|
||||
super(appStore, walletInfoSource, walletCreationService, seedSettingsViewModel,
|
||||
type: type, isRecovery: true) {
|
||||
@@ -89,6 +90,9 @@ abstract class WalletRestoreViewModelBase extends WalletCreationVM with Store {
|
||||
@observable
|
||||
WalletRestoreMode mode;
|
||||
|
||||
@observable
|
||||
bool hasPassphrase;
|
||||
|
||||
@observable
|
||||
bool isButtonEnabled;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user