CW-782: Show error report popup without cooldown (#1739)
Some checks are pending
Cache Dependencies / test (push) Waiting to run

* improve exception throwing on broken wallets
- put _lastOpenedWallet to avoid issues on windows (file is currently open by)
- don't throw corruptedWalletsSeed - instead store it inside of secureStorage
- await ExceptionHandler.onError calls where possible to makse sure that popup won't be canceled by some UI element
- adjust BaseAlertDialog to be scrollable if the text is too long
- add ExceptionHandler.resetLastPopupDate - that can be called when we want to show error report screen (bypassing cooldown)

* fix: HiveError: Box has already been closed.

* await the alerts to be sure that each one of them is being shown
fix typo in secure storage

* Update lib/core/backup_service.dart

Co-authored-by: Omar Hatem <omarh.ismail1@gmail.com>

* address comments on github

* don't store seeds in secure storage

* fix wallet password

* update monero_c
update corrupted seeds UI
prevent app from crashing when wallet is corrupted

* show alert with seeds

* Update corrupted wallet UI
Fix wallet opening cache

* remove unused code

---------

Co-authored-by: Omar Hatem <omarh.ismail1@gmail.com>
This commit is contained in:
cyan 2024-11-28 20:28:31 +01:00 committed by GitHub
parent d8d4190608
commit 17d34beae9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
51 changed files with 205 additions and 87 deletions

View file

@ -81,6 +81,7 @@ void createWalletSync(
wptr = newWptr; wptr = newWptr;
monero.Wallet_store(wptr!, path: path); monero.Wallet_store(wptr!, path: path);
openedWalletsByPath[path] = wptr!; openedWalletsByPath[path] = wptr!;
_lastOpenedWallet = path;
// is the line below needed? // is the line below needed?
// setupNodeSync(address: "node.moneroworld.com:18089"); // setupNodeSync(address: "node.moneroworld.com:18089");
@ -116,6 +117,7 @@ void restoreWalletFromSeedSync(
wptr = newWptr; wptr = newWptr;
openedWalletsByPath[path] = wptr!; openedWalletsByPath[path] = wptr!;
_lastOpenedWallet = path;
} }
void restoreWalletFromKeysSync( void restoreWalletFromKeysSync(
@ -183,6 +185,7 @@ void restoreWalletFromKeysSync(
wptr = newWptr; wptr = newWptr;
openedWalletsByPath[path] = wptr!; openedWalletsByPath[path] = wptr!;
_lastOpenedWallet = path;
} }
void restoreWalletFromSpendKeySync( void restoreWalletFromSpendKeySync(
@ -231,6 +234,7 @@ void restoreWalletFromSpendKeySync(
storeSync(); storeSync();
openedWalletsByPath[path] = wptr!; openedWalletsByPath[path] = wptr!;
_lastOpenedWallet = path;
} }
String _lastOpenedWallet = ""; String _lastOpenedWallet = "";
@ -260,7 +264,7 @@ Future<void> restoreWalletFromHardwareWallet(
throw WalletRestoreFromSeedException(message: error); throw WalletRestoreFromSeedException(message: error);
} }
wptr = newWptr; wptr = newWptr;
_lastOpenedWallet = path;
openedWalletsByPath[path] = wptr!; openedWalletsByPath[path] = wptr!;
} }
@ -295,6 +299,11 @@ Future<void> loadWallet(
password: password, password: password,
kdfRounds: 1, kdfRounds: 1,
); );
final status = monero.WalletManager_errorString(wmPtr);
if (status != "") {
print("loadWallet:"+status);
throw WalletOpeningException(message: status);
}
} else { } else {
deviceType = 0; deviceType = 0;
} }
@ -314,15 +323,15 @@ Future<void> loadWallet(
final newWptr = Pointer<Void>.fromAddress(newWptrAddr); final newWptr = Pointer<Void>.fromAddress(newWptrAddr);
_lastOpenedWallet = path;
final status = monero.Wallet_status(newWptr); final status = monero.Wallet_status(newWptr);
if (status != 0) { if (status != 0) {
final err = monero.Wallet_errorString(newWptr); final err = monero.Wallet_errorString(newWptr);
print(err); print("loadWallet:"+err);
throw WalletOpeningException(message: err); throw WalletOpeningException(message: err);
} }
wptr = newWptr; wptr = newWptr;
_lastOpenedWallet = path;
openedWalletsByPath[path] = wptr!; openedWalletsByPath[path] = wptr!;
} }
} }

View file

@ -168,7 +168,7 @@ class MoneroWalletService extends WalletService<
} }
await restoreOrResetWalletFiles(name); await restoreOrResetWalletFiles(name);
return openWallet(name, password, retryOnFailure: false); return await openWallet(name, password, retryOnFailure: false);
} }
} }

View file

@ -503,8 +503,8 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
path: "impls/monero.dart" path: "impls/monero.dart"
ref: d72c15f4339791a7bbdf17e9d827b7b56ca144e4 ref: c41c4dad9aa5003a914cfb2c528c76386f952665
resolved-ref: d72c15f4339791a7bbdf17e9d827b7b56ca144e4 resolved-ref: c41c4dad9aa5003a914cfb2c528c76386f952665
url: "https://github.com/mrcyjanek/monero_c" url: "https://github.com/mrcyjanek/monero_c"
source: git source: git
version: "0.0.0" version: "0.0.0"

View file

@ -25,7 +25,7 @@ dependencies:
monero: monero:
git: git:
url: https://github.com/mrcyjanek/monero_c url: https://github.com/mrcyjanek/monero_c
ref: d72c15f4339791a7bbdf17e9d827b7b56ca144e4 ref: c41c4dad9aa5003a914cfb2c528c76386f952665
# ref: 6eb571ea498ed7b854934785f00fabfd0dadf75b # monero_c hash # ref: 6eb571ea498ed7b854934785f00fabfd0dadf75b # monero_c hash
path: impls/monero.dart path: impls/monero.dart
mutex: ^3.1.0 mutex: ^3.1.0

View file

@ -463,8 +463,8 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
path: "impls/monero.dart" path: "impls/monero.dart"
ref: d72c15f4339791a7bbdf17e9d827b7b56ca144e4 ref: c41c4dad9aa5003a914cfb2c528c76386f952665
resolved-ref: d72c15f4339791a7bbdf17e9d827b7b56ca144e4 resolved-ref: c41c4dad9aa5003a914cfb2c528c76386f952665
url: "https://github.com/mrcyjanek/monero_c" url: "https://github.com/mrcyjanek/monero_c"
source: git source: git
version: "0.0.0" version: "0.0.0"

View file

@ -25,7 +25,7 @@ dependencies:
monero: monero:
git: git:
url: https://github.com/mrcyjanek/monero_c url: https://github.com/mrcyjanek/monero_c
ref: d72c15f4339791a7bbdf17e9d827b7b56ca144e4 ref: c41c4dad9aa5003a914cfb2c528c76386f952665
# ref: 6eb571ea498ed7b854934785f00fabfd0dadf75b # monero_c hash # ref: 6eb571ea498ed7b854934785f00fabfd0dadf75b # monero_c hash
path: impls/monero.dart path: impls/monero.dart
mutex: ^3.1.0 mutex: ^3.1.0

View file

@ -56,7 +56,7 @@ class AnyPayApi {
final response = await post(url, headers: headers, body: utf8.encode(json.encode(body))); final response = await post(url, headers: headers, body: utf8.encode(json.encode(body)));
if (response.statusCode != 200) { if (response.statusCode != 200) {
ExceptionHandler.onError(FlutterErrorDetails(exception: response)); await ExceptionHandler.onError(FlutterErrorDetails(exception: response));
throw Exception('Unexpected response http code: ${response.statusCode}'); throw Exception('Unexpected response http code: ${response.statusCode}');
} }

View file

@ -230,17 +230,15 @@ class BackupService {
json.decode(transactionDescriptionFile.readAsStringSync()) as Map<String, dynamic>; json.decode(transactionDescriptionFile.readAsStringSync()) as Map<String, dynamic>;
final descriptionsMap = jsonData.map((key, value) => final descriptionsMap = jsonData.map((key, value) =>
MapEntry(key, TransactionDescription.fromJson(value as Map<String, dynamic>))); MapEntry(key, TransactionDescription.fromJson(value as Map<String, dynamic>)));
var box = _transactionDescriptionBox;
if (!_transactionDescriptionBox.isOpen) { if (!box.isOpen) {
final transactionDescriptionsBoxKey = await getEncryptionKey(secureStorage: secureStorageShared, forKey: TransactionDescription.boxKey); final transactionDescriptionsBoxKey =
final transactionDescriptionBox = await CakeHive.openBox<TransactionDescription>( await getEncryptionKey(secureStorage: _secureStorage, forKey: TransactionDescription.boxKey);
box = await CakeHive.openBox<TransactionDescription>(
TransactionDescription.boxName, TransactionDescription.boxName,
encryptionKey: transactionDescriptionsBoxKey, encryptionKey: transactionDescriptionsBoxKey);
);
await transactionDescriptionBox.putAll(descriptionsMap);
return;
} }
await _transactionDescriptionBox.putAll(descriptionsMap); await box.putAll(descriptionsMap);
} }
Future<void> _importPreferencesDump() async { Future<void> _importPreferencesDump() async {

View file

@ -2,15 +2,22 @@ import 'dart:async';
import 'package:cake_wallet/core/generate_wallet_password.dart'; import 'package:cake_wallet/core/generate_wallet_password.dart';
import 'package:cake_wallet/core/key_service.dart'; import 'package:cake_wallet/core/key_service.dart';
import 'package:cake_wallet/core/secure_storage.dart';
import 'package:cake_wallet/entities/preferences_key.dart'; import 'package:cake_wallet/entities/preferences_key.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/main.dart';
import 'package:cake_wallet/reactions/on_authentication_state_change.dart'; import 'package:cake_wallet/reactions/on_authentication_state_change.dart';
import 'package:cake_wallet/src/screens/auth/auth_page.dart';
import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
import 'package:cake_wallet/utils/exception_handler.dart'; import 'package:cake_wallet/utils/exception_handler.dart';
import 'package:cake_wallet/utils/show_pop_up.dart';
import 'package:cw_core/cake_hive.dart'; import 'package:cw_core/cake_hive.dart';
import 'package:cw_core/wallet_base.dart'; import 'package:cw_core/wallet_base.dart';
import 'package:cw_core/wallet_info.dart'; import 'package:cw_core/wallet_info.dart';
import 'package:cw_core/wallet_service.dart'; import 'package:cw_core/wallet_service.dart';
import 'package:cw_core/wallet_type.dart'; import 'package:cw_core/wallet_type.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:shared_preferences/shared_preferences.dart'; import 'package:shared_preferences/shared_preferences.dart';
class WalletLoadingService { class WalletLoadingService {
@ -58,7 +65,8 @@ class WalletLoadingService {
return wallet; return wallet;
} catch (error, stack) { } catch (error, stack) {
ExceptionHandler.onError(FlutterErrorDetails(exception: error, stack: stack)); await ExceptionHandler.resetLastPopupDate();
await ExceptionHandler.onError(FlutterErrorDetails(exception: error, stack: stack));
// try fetching the seeds of the corrupted wallet to show it to the user // try fetching the seeds of the corrupted wallet to show it to the user
String corruptedWalletsSeeds = "Corrupted wallets seeds (if retrievable, empty otherwise):"; String corruptedWalletsSeeds = "Corrupted wallets seeds (if retrievable, empty otherwise):";
@ -70,12 +78,12 @@ class WalletLoadingService {
// try opening another wallet that is not corrupted to give user access to the app // try opening another wallet that is not corrupted to give user access to the app
final walletInfoSource = await CakeHive.openBox<WalletInfo>(WalletInfo.boxName); final walletInfoSource = await CakeHive.openBox<WalletInfo>(WalletInfo.boxName);
WalletBase? wallet;
for (var walletInfo in walletInfoSource.values) { for (var walletInfo in walletInfoSource.values) {
try { try {
final walletService = walletServiceFactory.call(walletInfo.type); final walletService = walletServiceFactory.call(walletInfo.type);
final walletPassword = password ?? (await keyService.getWalletPassword(walletName: name)); final walletPassword = await keyService.getWalletPassword(walletName: walletInfo.name);
final wallet = await walletService.openWallet(walletInfo.name, walletPassword); wallet = await walletService.openWallet(walletInfo.name, walletPassword);
if (walletInfo.type == WalletType.monero) { if (walletInfo.type == WalletType.monero) {
await updateMoneroWalletPassword(wallet); await updateMoneroWalletPassword(wallet);
@ -88,8 +96,6 @@ class WalletLoadingService {
// if found a wallet that is not corrupted, then still display the seeds of the corrupted ones // if found a wallet that is not corrupted, then still display the seeds of the corrupted ones
authenticatedErrorStreamController.add(corruptedWalletsSeeds); authenticatedErrorStreamController.add(corruptedWalletsSeeds);
return wallet;
} catch (e) { } catch (e) {
print(e); print(e);
// save seeds and show corrupted wallets' seeds to the user // save seeds and show corrupted wallets' seeds to the user
@ -105,8 +111,48 @@ class WalletLoadingService {
} }
// if all user's wallets are corrupted throw exception // if all user's wallets are corrupted throw exception
throw error.toString() + "\n\n" + corruptedWalletsSeeds; final msg = error.toString() + "\n" + corruptedWalletsSeeds;
if (navigatorKey.currentContext != null) {
await showPopUp<void>(
context: navigatorKey.currentContext!,
builder: (BuildContext context) {
return AlertWithTwoActions(
alertTitle: "Corrupted seeds",
alertContent: S.of(context).corrupted_seed_notice,
leftButtonText: S.of(context).cancel,
rightButtonText: S.of(context).show_seed,
actionLeftButton: () => Navigator.of(context).pop(),
actionRightButton: () => showSeedsPopup(context, msg),
);
});
} else {
throw msg;
} }
if (wallet == null) {
throw Exception("Wallet is null");
}
return wallet;
}
}
Future<void> showSeedsPopup(BuildContext context, String message) async {
Navigator.of(context).pop();
await showPopUp<void>(
context: context,
builder: (BuildContext context) {
return AlertWithTwoActions(
alertTitle: "Corrupted seeds",
alertContent: message,
leftButtonText: S.of(context).copy,
rightButtonText: S.of(context).ok,
actionLeftButton: () async {
await Clipboard.setData(ClipboardData(text: message));
},
actionRightButton: () async {
Navigator.of(context).pop();
},
);
});
} }
Future<void> updateMoneroWalletPassword(WalletBase wallet) async { Future<void> updateMoneroWalletPassword(WalletBase wallet) async {

View file

@ -575,7 +575,7 @@ Future<void> setup({
totpAuthPageState.changeProcessText('Loading the wallet'); totpAuthPageState.changeProcessText('Loading the wallet');
if (loginError != null) { if (loginError != null) {
totpAuthPageState.changeProcessText('ERROR: ${loginError.toString()}'); totpAuthPageState.changeProcessText('ERROR: ${loginError.toString()}'.trim());
} }
ReactionDisposer? _reaction; ReactionDisposer? _reaction;
@ -604,7 +604,7 @@ Future<void> setup({
authPageState.changeProcessText('Loading the wallet'); authPageState.changeProcessText('Loading the wallet');
if (loginError != null) { if (loginError != null) {
authPageState.changeProcessText('ERROR: ${loginError.toString()}'); authPageState.changeProcessText('ERROR: ${loginError.toString()}'.trim());
loginError = null; loginError = null;
} }
@ -624,7 +624,7 @@ Future<void> setup({
} }
if (loginError != null) { if (loginError != null) {
authPageState.changeProcessText('ERROR: ${loginError.toString()}'); authPageState.changeProcessText('ERROR: ${loginError.toString()}'.trim());
timer.cancel(); timer.cancel();
} }
}); });

View file

@ -89,7 +89,7 @@ Future<void> runAppWithZone({Key? topLevelKey}) async {
); );
} }
ExceptionHandler.onError(FlutterErrorDetails(exception: error, stack: stackTrace)); await ExceptionHandler.onError(FlutterErrorDetails(exception: error, stack: stackTrace));
}); });
} }

View file

@ -43,8 +43,8 @@ void startAuthenticationStateChange(
if (!requireHardwareWalletConnection()) await loadCurrentWallet(); if (!requireHardwareWalletConnection()) await loadCurrentWallet();
} catch (error, stack) { } catch (error, stack) {
loginError = error; loginError = error;
ExceptionHandler.onError( await ExceptionHandler.resetLastPopupDate();
FlutterErrorDetails(exception: error, stack: stack)); await ExceptionHandler.onError(FlutterErrorDetails(exception: error, stack: stack));
} }
return; return;
} }
@ -81,7 +81,7 @@ void startAuthenticationStateChange(
.pushNamedAndRemoveUntil(Routes.dashboard, (route) => false); .pushNamedAndRemoveUntil(Routes.dashboard, (route) => false);
} }
if (!(await authenticatedErrorStreamController.stream.isEmpty)) { if (!(await authenticatedErrorStreamController.stream.isEmpty)) {
ExceptionHandler.showError( await ExceptionHandler.showError(
(await authenticatedErrorStreamController.stream.first).toString()); (await authenticatedErrorStreamController.stream.first).toString());
authenticatedErrorStreamController.stream.drain(); authenticatedErrorStreamController.stream.drain();
} }

View file

@ -1,5 +1,6 @@
import 'package:another_flushbar/flushbar.dart'; import 'package:another_flushbar/flushbar.dart';
import 'package:cake_wallet/utils/show_bar.dart'; import 'package:cake_wallet/utils/show_bar.dart';
import 'package:cake_wallet/utils/show_pop_up.dart';
import 'package:mobx/mobx.dart'; import 'package:mobx/mobx.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
@ -9,6 +10,8 @@ import 'package:cake_wallet/view_model/auth_view_model.dart';
import 'package:cake_wallet/src/screens/pin_code/pin_code.dart'; import 'package:cake_wallet/src/screens/pin_code/pin_code.dart';
import 'package:cake_wallet/src/screens/pin_code/pin_code_widget.dart'; import 'package:cake_wallet/src/screens/pin_code/pin_code_widget.dart';
import 'package:cake_wallet/core/execution_state.dart'; import 'package:cake_wallet/core/execution_state.dart';
import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
import 'package:flutter/services.dart';
typedef OnAuthenticationFinished = void Function(bool, AuthPageState); typedef OnAuthenticationFinished = void Function(bool, AuthPageState);
@ -66,7 +69,6 @@ class AuthPagePinCodeStateImpl extends AuthPageState<AuthPage> {
dismissFlushBar(_authBar); dismissFlushBar(_authBar);
showBar<void>( showBar<void>(
context, S.of(context).failed_authentication(state.error)); context, S.of(context).failed_authentication(state.error));
widget.onAuthenticationFinished(false, this); widget.onAuthenticationFinished(false, this);
}); });
} }
@ -77,12 +79,12 @@ class AuthPagePinCodeStateImpl extends AuthPageState<AuthPage> {
dismissFlushBar(_authBar); dismissFlushBar(_authBar);
showBar<void>( showBar<void>(
context, S.of(context).failed_authentication(state.error)); context, S.of(context).failed_authentication(state.error));
widget.onAuthenticationFinished(false, this); widget.onAuthenticationFinished(false, this);
}); });
} }
}); });
if (widget.authViewModel.isBiometricalAuthenticationAllowed) { if (widget.authViewModel.isBiometricalAuthenticationAllowed) {
WidgetsBinding.instance.addPostFrameCallback((_) async { WidgetsBinding.instance.addPostFrameCallback((_) async {
await Future<void>.delayed(Duration(milliseconds: 100)); await Future<void>.delayed(Duration(milliseconds: 100));
@ -93,6 +95,23 @@ class AuthPagePinCodeStateImpl extends AuthPageState<AuthPage> {
super.initState(); super.initState();
} }
Future<void> _showSeedsPopup(BuildContext context, String message) async {
await showPopUp<void>(
context: context,
builder: (BuildContext context) {
return AlertWithTwoActions(
alertTitle: "Corrupted seeds",
alertContent: message,
leftButtonText: S.of(context).copy,
rightButtonText: S.of(context).ok,
actionLeftButton: () async {
await Clipboard.setData(ClipboardData(text: message));
},
actionRightButton: () => Navigator.of(context).pop(),
);
});
}
@override @override
void dispose() { void dispose() {
_reaction?.reaction.dispose(); _reaction?.reaction.dispose();

View file

@ -154,7 +154,7 @@ class BackupPage extends BasePage {
File returnedFile = File(outputFile!); File returnedFile = File(outputFile!);
await returnedFile.writeAsBytes(backup.content); await returnedFile.writeAsBytes(backup.content);
} catch (exception, stackTrace) { } catch (exception, stackTrace) {
ExceptionHandler.onError(FlutterErrorDetails( await ExceptionHandler.onError(FlutterErrorDetails(
exception: exception, exception: exception,
stack: stackTrace, stack: stackTrace,
library: "Export Backup", library: "Export Backup",

View file

@ -11,6 +11,7 @@ import 'package:cake_wallet/src/screens/wallet_unlock/wallet_unlock_arguments.da
import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart'; import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
import 'package:cake_wallet/store/settings_store.dart'; import 'package:cake_wallet/store/settings_store.dart';
import 'package:cake_wallet/themes/extensions/menu_theme.dart'; import 'package:cake_wallet/themes/extensions/menu_theme.dart';
import 'package:cake_wallet/utils/exception_handler.dart';
import 'package:cake_wallet/utils/show_bar.dart'; import 'package:cake_wallet/utils/show_bar.dart';
import 'package:cake_wallet/utils/show_pop_up.dart'; import 'package:cake_wallet/utils/show_pop_up.dart';
import 'package:cake_wallet/view_model/wallet_list/wallet_list_item.dart'; import 'package:cake_wallet/view_model/wallet_list/wallet_list_item.dart';

View file

@ -1,6 +1,7 @@
import 'package:another_flushbar/flushbar.dart'; import 'package:another_flushbar/flushbar.dart';
import 'package:cake_wallet/core/auth_service.dart'; import 'package:cake_wallet/core/auth_service.dart';
import 'package:cake_wallet/core/new_wallet_arguments.dart'; import 'package:cake_wallet/core/new_wallet_arguments.dart';
import 'package:cake_wallet/core/secure_storage.dart';
import 'package:cake_wallet/entities/wallet_edit_page_arguments.dart'; import 'package:cake_wallet/entities/wallet_edit_page_arguments.dart';
import 'package:cake_wallet/entities/wallet_list_order_types.dart'; import 'package:cake_wallet/entities/wallet_list_order_types.dart';
import 'package:cake_wallet/generated/i18n.dart'; import 'package:cake_wallet/generated/i18n.dart';
@ -20,6 +21,7 @@ import 'package:cake_wallet/store/settings_store.dart';
import 'package:cake_wallet/themes/extensions/cake_text_theme.dart'; import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
import 'package:cake_wallet/themes/extensions/filter_theme.dart'; import 'package:cake_wallet/themes/extensions/filter_theme.dart';
import 'package:cake_wallet/themes/extensions/wallet_list_theme.dart'; import 'package:cake_wallet/themes/extensions/wallet_list_theme.dart';
import 'package:cake_wallet/utils/exception_handler.dart';
import 'package:cake_wallet/utils/responsive_layout_util.dart'; import 'package:cake_wallet/utils/responsive_layout_util.dart';
import 'package:cake_wallet/utils/show_bar.dart'; import 'package:cake_wallet/utils/show_bar.dart';
import 'package:cake_wallet/utils/show_pop_up.dart'; import 'package:cake_wallet/utils/show_pop_up.dart';
@ -459,6 +461,9 @@ class WalletListBodyState extends State<WalletListBody> {
}); });
} }
} catch (e) { } catch (e) {
await ExceptionHandler.resetLastPopupDate();
final err = e.toString();
await ExceptionHandler.onError(FlutterErrorDetails(exception: err));
if (this.mounted) { if (this.mounted) {
changeProcessText(S changeProcessText(S
.of(context) .of(context)

View file

@ -73,7 +73,11 @@ class BaseAlertDialog extends StatelessWidget {
} }
Widget content(BuildContext context) { Widget content(BuildContext context) {
return Text( return SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text(
contentText, contentText,
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: TextStyle( style: TextStyle(
@ -83,6 +87,9 @@ class BaseAlertDialog extends StatelessWidget {
color: Theme.of(context).extension<CakeTextTheme>()!.titleColor, color: Theme.of(context).extension<CakeTextTheme>()!.titleColor,
decoration: TextDecoration.none, decoration: TextDecoration.none,
), ),
),
],
),
); );
} }

View file

@ -1,5 +1,6 @@
import 'dart:io'; import 'dart:io';
import 'package:cake_wallet/core/secure_storage.dart';
import 'package:cake_wallet/entities/preferences_key.dart'; import 'package:cake_wallet/entities/preferences_key.dart';
import 'package:cake_wallet/generated/i18n.dart'; import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/main.dart'; import 'package:cake_wallet/main.dart';
@ -20,7 +21,7 @@ class ExceptionHandler {
static const _coolDownDurationInDays = 7; static const _coolDownDurationInDays = 7;
static File? _file; static File? _file;
static void _saveException(String? error, StackTrace? stackTrace, {String? library}) async { static Future<void> _saveException(String? error, StackTrace? stackTrace, {String? library}) async {
final appDocDir = await getAppDir(); final appDocDir = await getAppDir();
if (_file == null) { if (_file == null) {
@ -90,7 +91,12 @@ class ExceptionHandler {
} }
} }
static void onError(FlutterErrorDetails errorDetails) async { static Future<void> resetLastPopupDate() async {
final sharedPrefs = await SharedPreferences.getInstance();
await sharedPrefs.setString(PreferencesKey.lastPopupDate, DateTime(1971).toString());
}
static Future<void> onError(FlutterErrorDetails errorDetails) async {
if (kDebugMode || kProfileMode) { if (kDebugMode || kProfileMode) {
FlutterError.presentError(errorDetails); FlutterError.presentError(errorDetails);
debugPrint(errorDetails.toString()); debugPrint(errorDetails.toString());
@ -124,10 +130,17 @@ class ExceptionHandler {
} }
_hasError = true; _hasError = true;
sharedPrefs.setString(PreferencesKey.lastPopupDate, DateTime.now().toString()); await sharedPrefs.setString(PreferencesKey.lastPopupDate, DateTime.now().toString());
WidgetsBinding.instance.addPostFrameCallback( // Instead of using WidgetsBinding.instance.addPostFrameCallback we
(timeStamp) async { // await Future.delayed(Duration.zero), which does essentially the same (
// but doesn't wait for actual frame to be rendered), but it allows us to
// properly await the execution - which is what we want, without awaiting
// other code may call functions like Navigator.pop(), and close the alert
// instead of the intended UI.
// WidgetsBinding.instance.addPostFrameCallback(
// (timeStamp) async {
await Future.delayed(Duration.zero);
if (navigatorKey.currentContext != null) { if (navigatorKey.currentContext != null) {
await showPopUp<void>( await showPopUp<void>(
context: navigatorKey.currentContext!, context: navigatorKey.currentContext!,
@ -151,8 +164,6 @@ class ExceptionHandler {
} }
_hasError = false; _hasError = false;
},
);
} }
/// Ignore User related errors or system errors /// Ignore User related errors or system errors
@ -272,20 +283,18 @@ class ExceptionHandler {
}; };
} }
static void showError(String error, {int? delayInSeconds}) async { static Future<void> showError(String error, {int? delayInSeconds}) async {
if (_hasError) { if (_hasError) {
return; return;
} }
_hasError = true; _hasError = true;
if (delayInSeconds != null) { if (delayInSeconds != null) {
Future.delayed(Duration(seconds: delayInSeconds), () => _showCopyPopup(error)); Future.delayed(Duration(seconds: delayInSeconds), () => _showCopyPopup(error));
return; return;
} }
WidgetsBinding.instance.addPostFrameCallback( await Future.delayed(Duration.zero);
(_) async => _showCopyPopup(error), await _showCopyPopup(error);
);
} }
static Future<void> _showCopyPopup(String content) async { static Future<void> _showCopyPopup(String content) async {

View file

@ -68,7 +68,7 @@ abstract class RestoreFromBackupViewModelBase with Store {
if (msg.toLowerCase().contains("message authentication code (mac)")) { if (msg.toLowerCase().contains("message authentication code (mac)")) {
msg = 'Incorrect backup password'; msg = 'Incorrect backup password';
} else { } else {
ExceptionHandler.onError(FlutterErrorDetails( await ExceptionHandler.onError(FlutterErrorDetails(
exception: e, exception: e,
stack: s, stack: s,
library: this.toString(), library: this.toString(),

View file

@ -10,7 +10,6 @@ list(APPEND FLUTTER_PLUGIN_LIST
) )
list(APPEND FLUTTER_FFI_PLUGIN_LIST list(APPEND FLUTTER_FFI_PLUGIN_LIST
sp_scanner
) )
set(PLUGIN_BUNDLED_LIBRARIES) set(PLUGIN_BUNDLED_LIBRARIES)

View file

@ -6,7 +6,6 @@ import FlutterMacOS
import Foundation import Foundation
import connectivity_plus import connectivity_plus
import cw_mweb
import device_info_plus import device_info_plus
import devicelocale import devicelocale
import fast_scanner import fast_scanner
@ -24,7 +23,6 @@ import wakelock_plus
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
ConnectivityPlugin.register(with: registry.registrar(forPlugin: "ConnectivityPlugin")) ConnectivityPlugin.register(with: registry.registrar(forPlugin: "ConnectivityPlugin"))
CwMwebPlugin.register(with: registry.registrar(forPlugin: "CwMwebPlugin"))
DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin")) DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin"))
DevicelocalePlugin.register(with: registry.registrar(forPlugin: "DevicelocalePlugin")) DevicelocalePlugin.register(with: registry.registrar(forPlugin: "DevicelocalePlugin"))
MobileScannerPlugin.register(with: registry.registrar(forPlugin: "MobileScannerPlugin")) MobileScannerPlugin.register(with: registry.registrar(forPlugin: "MobileScannerPlugin"))

View file

@ -177,6 +177,7 @@
"copy_address": "نسخ العنوان", "copy_address": "نسخ العنوان",
"copy_id": "نسخ معرف العملية", "copy_id": "نسخ معرف العملية",
"copyWalletConnectLink": "ﺎﻨﻫ ﻪﻘﺼﻟﺍﻭ dApp ﻦﻣ WalletConnect ﻂﺑﺍﺭ ﺦﺴﻧﺍ", "copyWalletConnectLink": "ﺎﻨﻫ ﻪﻘﺼﻟﺍﻭ dApp ﻦﻣ WalletConnect ﻂﺑﺍﺭ ﺦﺴﻧﺍ",
"corrupted_seed_notice": "تالف ملفات هذه المحفظة ولا يمكن فتحها. يرجى الاطلاع على عبارة البذور وحفظها واستعادة المحفظة.\n\nإذا كانت القيمة فارغة ، لم تتمكن البذور من استردادها بشكل صحيح.",
"countries": "بلدان", "countries": "بلدان",
"create_account": "إنشاء حساب", "create_account": "إنشاء حساب",
"create_backup": "انشئ نسخة احتياطية", "create_backup": "انشئ نسخة احتياطية",

View file

@ -177,6 +177,7 @@
"copy_address": "Copy Address", "copy_address": "Copy Address",
"copy_id": "Копиране на ID", "copy_id": "Копиране на ID",
"copyWalletConnectLink": "Копирайте връзката WalletConnect от dApp и я поставете тук", "copyWalletConnectLink": "Копирайте връзката WalletConnect от dApp и я поставете тук",
"corrupted_seed_notice": "Файловете за този портфейл са повредени и не могат да бъдат отворени. Моля, прегледайте фразата за семена, запазете я и възстановете портфейла.\n\nАко стойността е празна, тогава семето не успя да бъде правилно възстановено.",
"countries": "Държави", "countries": "Държави",
"create_account": "Създаване на профил", "create_account": "Създаване на профил",
"create_backup": "Създаване на резервно копие", "create_backup": "Създаване на резервно копие",

View file

@ -177,6 +177,7 @@
"copy_address": "Zkopírovat adresu", "copy_address": "Zkopírovat adresu",
"copy_id": "Kopírovat ID", "copy_id": "Kopírovat ID",
"copyWalletConnectLink": "Zkopírujte odkaz WalletConnect z dApp a vložte jej sem", "copyWalletConnectLink": "Zkopírujte odkaz WalletConnect z dApp a vložte jej sem",
"corrupted_seed_notice": "Soubory pro tuto peněženku jsou poškozeny a nemohou být otevřeny. Podívejte se prosím na osivo, uložte ji a obnovte peněženku.\n\nPokud je hodnota prázdná, pak semeno nebylo možné správně obnovit.",
"countries": "Země", "countries": "Země",
"create_account": "Vytvořit účet", "create_account": "Vytvořit účet",
"create_backup": "Vytvořit zálohu", "create_backup": "Vytvořit zálohu",

View file

@ -177,6 +177,7 @@
"copy_address": "Adresse kopieren", "copy_address": "Adresse kopieren",
"copy_id": "ID kopieren", "copy_id": "ID kopieren",
"copyWalletConnectLink": "Kopieren Sie den WalletConnect-Link von dApp und fügen Sie ihn hier ein", "copyWalletConnectLink": "Kopieren Sie den WalletConnect-Link von dApp und fügen Sie ihn hier ein",
"corrupted_seed_notice": "Die Dateien für diese Brieftasche sind beschädigt und können nicht geöffnet werden. Bitte sehen Sie sich die Saatgutphrase an, speichern Sie sie und stellen Sie die Brieftasche wieder her.\n\nWenn der Wert leer ist, konnte der Samen nicht korrekt wiederhergestellt werden.",
"countries": "Länder", "countries": "Länder",
"create_account": "Konto erstellen", "create_account": "Konto erstellen",
"create_backup": "Backup erstellen", "create_backup": "Backup erstellen",

View file

@ -177,6 +177,7 @@
"copy_address": "Copy Address", "copy_address": "Copy Address",
"copy_id": "Copy ID", "copy_id": "Copy ID",
"copyWalletConnectLink": "Copy the WalletConnect link from dApp and paste here", "copyWalletConnectLink": "Copy the WalletConnect link from dApp and paste here",
"corrupted_seed_notice": "The files for this wallet are corrupted and are unable to be opened. Please view the seed phrase, save it, and restore the wallet.\n\nIf the value is empty, then the seed was unable to be correctly recovered.",
"countries": "Countries", "countries": "Countries",
"create_account": "Create Account", "create_account": "Create Account",
"create_backup": "Create backup", "create_backup": "Create backup",

View file

@ -177,6 +177,7 @@
"copy_address": "Copiar dirección ", "copy_address": "Copiar dirección ",
"copy_id": "Copiar ID", "copy_id": "Copiar ID",
"copyWalletConnectLink": "Copie el enlace de WalletConnect de dApp y péguelo aquí", "copyWalletConnectLink": "Copie el enlace de WalletConnect de dApp y péguelo aquí",
"corrupted_seed_notice": "Los archivos para esta billetera están dañados y no pueden abrirse. Vea la frase de semillas, guárdela y restaura la billetera.\n\nSi el valor está vacío, entonces la semilla no pudo recuperarse correctamente.",
"countries": "Países", "countries": "Países",
"create_account": "Crear Cuenta", "create_account": "Crear Cuenta",
"create_backup": "Crear copia de seguridad", "create_backup": "Crear copia de seguridad",

View file

@ -177,6 +177,7 @@
"copy_address": "Copier l'Adresse", "copy_address": "Copier l'Adresse",
"copy_id": "Copier l'ID", "copy_id": "Copier l'ID",
"copyWalletConnectLink": "Copiez le lien WalletConnect depuis l'application décentralisée (dApp) et collez-le ici", "copyWalletConnectLink": "Copiez le lien WalletConnect depuis l'application décentralisée (dApp) et collez-le ici",
"corrupted_seed_notice": "Les fichiers de ce portefeuille sont corrompus et ne peuvent pas être ouverts. Veuillez consulter la phrase de graines, sauver et restaurer le portefeuille.\n\nSi la valeur est vide, la graine n'a pas pu être correctement récupérée.",
"countries": "Des pays", "countries": "Des pays",
"create_account": "Créer un compte", "create_account": "Créer un compte",
"create_backup": "Créer une sauvegarde", "create_backup": "Créer une sauvegarde",

View file

@ -177,6 +177,7 @@
"copy_address": "Kwafi Adireshin", "copy_address": "Kwafi Adireshin",
"copy_id": "Kwafi ID", "copy_id": "Kwafi ID",
"copyWalletConnectLink": "Kwafi hanyar haɗin WalletConnect daga dApp kuma liƙa a nan", "copyWalletConnectLink": "Kwafi hanyar haɗin WalletConnect daga dApp kuma liƙa a nan",
"corrupted_seed_notice": "Fayilolin don wannan walat ɗin sun lalata kuma ba za a iya buɗe su ba. Da fatan za a duba kalmar iri, adana shi, da dawo da walat.\n\nIdan darajar ta kasance fanko, to sai zuriyar da ba ta iya murmurewa daidai ba.",
"countries": "Kasashe", "countries": "Kasashe",
"create_account": "Kirkira ajiya", "create_account": "Kirkira ajiya",
"create_backup": "Ƙirƙiri madadin", "create_backup": "Ƙirƙiri madadin",

View file

@ -177,6 +177,7 @@
"copy_address": "पता कॉपी करें", "copy_address": "पता कॉपी करें",
"copy_id": "प्रतिलिपि ID", "copy_id": "प्रतिलिपि ID",
"copyWalletConnectLink": "dApp से वॉलेटकनेक्ट लिंक को कॉपी करें और यहां पेस्ट करें", "copyWalletConnectLink": "dApp से वॉलेटकनेक्ट लिंक को कॉपी करें और यहां पेस्ट करें",
"corrupted_seed_notice": "इस वॉलेट की फाइलें दूषित हैं और उन्हें खोलने में असमर्थ हैं। कृपया बीज वाक्यांश देखें, इसे बचाएं, और बटुए को पुनर्स्थापित करें।\n\nयदि मूल्य खाली है, तो बीज सही ढंग से पुनर्प्राप्त करने में असमर्थ था।",
"countries": "देशों", "countries": "देशों",
"create_account": "खाता बनाएं", "create_account": "खाता बनाएं",
"create_backup": "बैकअप बनाएँ", "create_backup": "बैकअप बनाएँ",

View file

@ -177,6 +177,7 @@
"copy_address": "Kopiraj adresu", "copy_address": "Kopiraj adresu",
"copy_id": "Kopirati ID", "copy_id": "Kopirati ID",
"copyWalletConnectLink": "Kopirajte vezu WalletConnect iz dApp-a i zalijepite je ovdje", "copyWalletConnectLink": "Kopirajte vezu WalletConnect iz dApp-a i zalijepite je ovdje",
"corrupted_seed_notice": "Datoteke za ovaj novčanik su oštećene i nisu u mogućnosti otvoriti. Molimo pogledajte sjemensku frazu, spremite je i vratite novčanik.\n\nAko je vrijednost prazna, tada sjeme nije bilo u stanju ispravno oporaviti.",
"countries": "Zemalja", "countries": "Zemalja",
"create_account": "Stvori račun", "create_account": "Stvori račun",
"create_backup": "Stvori sigurnosnu kopiju", "create_backup": "Stvori sigurnosnu kopiju",

View file

@ -177,6 +177,7 @@
"copy_address": "Պատճենել հասցեն", "copy_address": "Պատճենել հասցեն",
"copy_id": "Պատճենել ID", "copy_id": "Պատճենել ID",
"copyWalletConnectLink": "Պատճենել WalletConnect հղումը dApp-ից և տեղադրել այստեղ", "copyWalletConnectLink": "Պատճենել WalletConnect հղումը dApp-ից և տեղադրել այստեղ",
"corrupted_seed_notice": "Այս դրամապանակի համար ֆայլերը կոռումպացված են եւ չեն կարողանում բացվել: Խնդրում ենք դիտել սերմերի արտահայտությունը, պահպանել այն եւ վերականգնել դրամապանակը:\n\nԵթե ​​արժեքը դատարկ է, ապա սերմը չկարողացավ ճիշտ վերականգնվել:",
"countries": "Երկրներ", "countries": "Երկրներ",
"create_account": "Ստեղծել հաշիվ", "create_account": "Ստեղծել հաշիվ",
"create_backup": "Ստեղծել կրկնօրինակ", "create_backup": "Ստեղծել կրկնօրինակ",

View file

@ -177,6 +177,7 @@
"copy_address": "Salin Alamat", "copy_address": "Salin Alamat",
"copy_id": "Salin ID", "copy_id": "Salin ID",
"copyWalletConnectLink": "Salin tautan WalletConnect dari dApp dan tempel di sini", "copyWalletConnectLink": "Salin tautan WalletConnect dari dApp dan tempel di sini",
"corrupted_seed_notice": "File untuk dompet ini rusak dan tidak dapat dibuka. Silakan lihat frasa benih, simpan, dan kembalikan dompet.\n\nJika nilainya kosong, maka benih tidak dapat dipulihkan dengan benar.",
"countries": "Negara", "countries": "Negara",
"create_account": "Buat Akun", "create_account": "Buat Akun",
"create_backup": "Buat cadangan", "create_backup": "Buat cadangan",

View file

@ -178,6 +178,7 @@
"copy_address": "Copia Indirizzo", "copy_address": "Copia Indirizzo",
"copy_id": "Copia ID", "copy_id": "Copia ID",
"copyWalletConnectLink": "Copia il collegamento WalletConnect dalla dApp e incollalo qui", "copyWalletConnectLink": "Copia il collegamento WalletConnect dalla dApp e incollalo qui",
"corrupted_seed_notice": "I file per questo portafoglio sono corrotti e non sono in grado di essere aperti. Visualizza la frase del seme, salvala e ripristina il portafoglio.\n\nSe il valore è vuoto, il seme non è stato in grado di essere recuperato correttamente.",
"countries": "Paesi", "countries": "Paesi",
"create_account": "Crea account", "create_account": "Crea account",
"create_backup": "Crea backup", "create_backup": "Crea backup",

View file

@ -177,6 +177,7 @@
"copy_address": "住所をコピー", "copy_address": "住所をコピー",
"copy_id": "IDをコピー", "copy_id": "IDをコピー",
"copyWalletConnectLink": "dApp から WalletConnect リンクをコピーし、ここに貼り付けます", "copyWalletConnectLink": "dApp から WalletConnect リンクをコピーし、ここに貼り付けます",
"corrupted_seed_notice": "このウォレットのファイルは破損しており、開くことができません。シードフレーズを表示し、保存し、財布を復元してください。\n\n値が空の場合、種子を正しく回復することができませんでした。",
"countries": "国", "countries": "国",
"create_account": "アカウントの作成", "create_account": "アカウントの作成",
"create_backup": "バックアップを作成", "create_backup": "バックアップを作成",

View file

@ -177,6 +177,7 @@
"copy_address": "주소 복사", "copy_address": "주소 복사",
"copy_id": "부 ID", "copy_id": "부 ID",
"copyWalletConnectLink": "dApp에서 WalletConnect 링크를 복사하여 여기에 붙여넣으세요.", "copyWalletConnectLink": "dApp에서 WalletConnect 링크를 복사하여 여기에 붙여넣으세요.",
"corrupted_seed_notice": "이 지갑의 파일은 손상되어 열 수 없습니다. 씨앗 문구를보고 저장하고 지갑을 복원하십시오.\n\n값이 비어 있으면 씨앗을 올바르게 회수 할 수 없었습니다.",
"countries": "국가", "countries": "국가",
"create_account": "계정 만들기", "create_account": "계정 만들기",
"create_backup": "백업 생성", "create_backup": "백업 생성",

View file

@ -177,6 +177,7 @@
"copy_address": "လိပ်စာကို ကူးယူပါ။", "copy_address": "လိပ်စာကို ကူးယူပါ။",
"copy_id": "ID ကူးယူပါ။", "copy_id": "ID ကူးယူပါ။",
"copyWalletConnectLink": "dApp မှ WalletConnect လင့်ခ်ကို ကူးယူပြီး ဤနေရာတွင် ကူးထည့်ပါ။", "copyWalletConnectLink": "dApp မှ WalletConnect လင့်ခ်ကို ကူးယူပြီး ဤနေရာတွင် ကူးထည့်ပါ။",
"corrupted_seed_notice": "ဤပိုက်ဆံအိတ်အတွက်ဖိုင်များသည်အကျင့်ပျက်ခြစားမှုများနှင့်မဖွင့်နိုင်ပါ။ ကျေးဇူးပြု. မျိုးစေ့များကိုကြည့်ပါ, ၎င်းကိုသိမ်းဆည်းပါ, ပိုက်ဆံအိတ်ကိုပြန်ယူပါ။\n\nအကယ်. တန်ဖိုးသည်အချည်းနှီးဖြစ်ပါကမျိုးစေ့ကိုမှန်ကန်စွာပြန်လည်ကောင်းမွန်မရရှိနိုင်ပါ။",
"countries": "နိုင်ငံများ", "countries": "နိုင်ငံများ",
"create_account": "အကောင့်ပြုလုပ်ပါ", "create_account": "အကောင့်ပြုလုပ်ပါ",
"create_backup": "အရန်သိမ်းခြင်းကို ဖန်တီးပါ။", "create_backup": "အရန်သိမ်းခြင်းကို ဖန်တီးပါ။",

View file

@ -177,6 +177,7 @@
"copy_address": "Adres kopiëren", "copy_address": "Adres kopiëren",
"copy_id": "ID kopiëren", "copy_id": "ID kopiëren",
"copyWalletConnectLink": "Kopieer de WalletConnect-link van dApp en plak deze hier", "copyWalletConnectLink": "Kopieer de WalletConnect-link van dApp en plak deze hier",
"corrupted_seed_notice": "De bestanden voor deze portemonnee zijn beschadigd en kunnen niet worden geopend. Bekijk de zaadzin, bewaar deze en herstel de portemonnee.\n\nAls de waarde leeg is, kon het zaad niet correct worden hersteld.",
"countries": "Landen", "countries": "Landen",
"create_account": "Account aanmaken", "create_account": "Account aanmaken",
"create_backup": "Maak een back-up", "create_backup": "Maak een back-up",

View file

@ -177,6 +177,7 @@
"copy_address": "Skopiuj adress", "copy_address": "Skopiuj adress",
"copy_id": "skopiuj ID", "copy_id": "skopiuj ID",
"copyWalletConnectLink": "Skopiuj link do WalletConnect z dApp i wklej tutaj", "copyWalletConnectLink": "Skopiuj link do WalletConnect z dApp i wklej tutaj",
"corrupted_seed_notice": "Pliki dla tego portfela są uszkodzone i nie można ich otworzyć. Zobacz wyrażenie nasion, zapisz je i przywróć portfel.\n\nJeśli wartość jest pusta, ziarno nie można było poprawnie odzyskać.",
"countries": "Kraje", "countries": "Kraje",
"create_account": "Utwórz konto", "create_account": "Utwórz konto",
"create_backup": "Utwórz kopię zapasową", "create_backup": "Utwórz kopię zapasową",

View file

@ -177,6 +177,7 @@
"copy_address": "Copiar endereço", "copy_address": "Copiar endereço",
"copy_id": "Copiar ID", "copy_id": "Copiar ID",
"copyWalletConnectLink": "Copie o link WalletConnect do dApp e cole aqui", "copyWalletConnectLink": "Copie o link WalletConnect do dApp e cole aqui",
"corrupted_seed_notice": "Os arquivos para esta carteira estão corrompidos e não podem ser abertos. Veja a frase das sementes, salve -a e restaure a carteira.\n\nSe o valor estiver vazio, a semente não pôde ser recuperada corretamente.",
"countries": "Países", "countries": "Países",
"create_account": "Criar conta", "create_account": "Criar conta",
"create_backup": "Criar backup", "create_backup": "Criar backup",

View file

@ -177,6 +177,7 @@
"copy_address": "Cкопировать адрес", "copy_address": "Cкопировать адрес",
"copy_id": "Скопировать ID", "copy_id": "Скопировать ID",
"copyWalletConnectLink": "Скопируйте ссылку WalletConnect из dApp и вставьте сюда.", "copyWalletConnectLink": "Скопируйте ссылку WalletConnect из dApp и вставьте сюда.",
"corrupted_seed_notice": "Файлы для этого кошелька повреждены и не могут быть открыты. Пожалуйста, просмотрите семенную фразу, сохраните ее и восстановите кошелек.\n\nЕсли значение пустое, то семя не смог правильно восстановить.",
"countries": "Страны", "countries": "Страны",
"create_account": "Создать аккаунт", "create_account": "Создать аккаунт",
"create_backup": "Создать резервную копию", "create_backup": "Создать резервную копию",

View file

@ -177,6 +177,7 @@
"copy_address": "คัดลอกที่อยู่", "copy_address": "คัดลอกที่อยู่",
"copy_id": "คัดลอก ID", "copy_id": "คัดลอก ID",
"copyWalletConnectLink": "คัดลอกลิงก์ WalletConnect จาก dApp แล้ววางที่นี่", "copyWalletConnectLink": "คัดลอกลิงก์ WalletConnect จาก dApp แล้ววางที่นี่",
"corrupted_seed_notice": "ไฟล์สำหรับกระเป๋าเงินนี้เสียหายและไม่สามารถเปิดได้ โปรดดูวลีเมล็ดบันทึกและกู้คืนกระเป๋าเงิน\n\nหากค่าว่างเปล่าเมล็ดก็ไม่สามารถกู้คืนได้อย่างถูกต้อง",
"countries": "ประเทศ", "countries": "ประเทศ",
"create_account": "สร้างบัญชี", "create_account": "สร้างบัญชี",
"create_backup": "สร้างการสำรองข้อมูล", "create_backup": "สร้างการสำรองข้อมูล",

View file

@ -177,6 +177,7 @@
"copy_address": "Kopyahin ang Address", "copy_address": "Kopyahin ang Address",
"copy_id": "Kopyahin ang ID", "copy_id": "Kopyahin ang ID",
"copyWalletConnectLink": "Kopyahin ang link ng WalletConnect mula sa dApp at i-paste dito", "copyWalletConnectLink": "Kopyahin ang link ng WalletConnect mula sa dApp at i-paste dito",
"corrupted_seed_notice": "Ang mga file para sa pitaka na ito ay nasira at hindi mabubuksan. Mangyaring tingnan ang parirala ng binhi, i -save ito, at ibalik ang pitaka.\n\nKung ang halaga ay walang laman, kung gayon ang binhi ay hindi ma -recover nang tama.",
"countries": "Mga bansa", "countries": "Mga bansa",
"create_account": "Lumikha ng Account", "create_account": "Lumikha ng Account",
"create_backup": "Lumikha ng backup", "create_backup": "Lumikha ng backup",

View file

@ -177,6 +177,7 @@
"copy_address": "Adresi kopyala", "copy_address": "Adresi kopyala",
"copy_id": "ID'yi kopyala", "copy_id": "ID'yi kopyala",
"copyWalletConnectLink": "WalletConnect bağlantısını dApp'ten kopyalayıp buraya yapıştırın", "copyWalletConnectLink": "WalletConnect bağlantısını dApp'ten kopyalayıp buraya yapıştırın",
"corrupted_seed_notice": "Bu cüzdanın dosyaları bozuk ve açılamıyor. Lütfen tohum ifadesini görüntüleyin, kaydedin ve cüzdanı geri yükleyin.\n\nDeğer boşsa, tohum doğru bir şekilde geri kazanılamadı.",
"countries": "Ülkeler", "countries": "Ülkeler",
"create_account": "Hesap oluştur", "create_account": "Hesap oluştur",
"create_backup": "Yedek oluştur", "create_backup": "Yedek oluştur",

View file

@ -177,6 +177,7 @@
"copy_address": "Cкопіювати адресу", "copy_address": "Cкопіювати адресу",
"copy_id": "Скопіювати ID", "copy_id": "Скопіювати ID",
"copyWalletConnectLink": "Скопіюйте посилання WalletConnect із dApp і вставте сюди", "copyWalletConnectLink": "Скопіюйте посилання WalletConnect із dApp і вставте сюди",
"corrupted_seed_notice": "Файли для цього гаманця пошкоджені і не можуть бути відкриті. Перегляньте насіннєву фразу, збережіть її та відновіть гаманець.\n\nЯкщо значення порожнє, то насіння не могло бути правильно відновленим.",
"countries": "Країни", "countries": "Країни",
"create_account": "Створити обліковий запис", "create_account": "Створити обліковий запис",
"create_backup": "Створити резервну копію", "create_backup": "Створити резервну копію",

View file

@ -177,6 +177,7 @@
"copy_address": "ایڈریس کاپی کریں۔", "copy_address": "ایڈریس کاپی کریں۔",
"copy_id": "کاپی ID", "copy_id": "کاپی ID",
"copyWalletConnectLink": "dApp ﮯﺳ WalletConnect ۔ﮟﯾﺮﮐ ﭧﺴﯿﭘ ﮞﺎﮩﯾ ﺭﻭﺍ ﮟﯾﺮﮐ ﯽﭘﺎﮐ ﻮﮐ ﮏﻨﻟ", "copyWalletConnectLink": "dApp ﮯﺳ WalletConnect ۔ﮟﯾﺮﮐ ﭧﺴﯿﭘ ﮞﺎﮩﯾ ﺭﻭﺍ ﮟﯾﺮﮐ ﯽﭘﺎﮐ ﻮﮐ ﮏﻨﻟ",
"corrupted_seed_notice": "اس پرس کے لئے فائلیں خراب ہیں اور کھولنے سے قاصر ہیں۔ براہ کرم بیج کے فقرے کو دیکھیں ، اسے بچائیں ، اور بٹوے کو بحال کریں۔\n\nاگر قیمت خالی ہے ، تو بیج صحیح طور پر بازیافت کرنے سے قاصر تھا۔",
"countries": "ممالک", "countries": "ممالک",
"create_account": "اکاؤنٹ بنائیں", "create_account": "اکاؤنٹ بنائیں",
"create_backup": "بیک اپ بنائیں", "create_backup": "بیک اپ بنائیں",

View file

@ -176,6 +176,7 @@
"copy_address": "Sao chép Địa chỉ", "copy_address": "Sao chép Địa chỉ",
"copy_id": "Sao chép ID", "copy_id": "Sao chép ID",
"copyWalletConnectLink": "Sao chép liên kết WalletConnect từ dApp và dán vào đây", "copyWalletConnectLink": "Sao chép liên kết WalletConnect từ dApp và dán vào đây",
"corrupted_seed_notice": "Các tệp cho ví này bị hỏng và không thể mở. Vui lòng xem cụm từ hạt giống, lưu nó và khôi phục ví.\n\nNếu giá trị trống, thì hạt giống không thể được phục hồi chính xác.",
"countries": "Quốc gia", "countries": "Quốc gia",
"create_account": "Tạo tài khoản", "create_account": "Tạo tài khoản",
"create_backup": "Tạo sao lưu", "create_backup": "Tạo sao lưu",

View file

@ -177,6 +177,7 @@
"copy_address": "Ṣẹ̀dà àdírẹ́sì", "copy_address": "Ṣẹ̀dà àdírẹ́sì",
"copy_id": "Ṣẹ̀dà àmì ìdánimọ̀", "copy_id": "Ṣẹ̀dà àmì ìdánimọ̀",
"copyWalletConnectLink": "Daakọ ọna asopọ WalletConnect lati dApp ki o si lẹẹmọ nibi", "copyWalletConnectLink": "Daakọ ọna asopọ WalletConnect lati dApp ki o si lẹẹmọ nibi",
"corrupted_seed_notice": "Awọn faili fun apamọwọ yii jẹ ibajẹ ati pe ko lagbara lati ṣii. Jọwọ wo ọrọ iseda, fipamọ rẹ, ki o mu apamọwọ naa pada.\n\nTi iye ba ṣofo, lẹhinna irugbin naa ko lagbara lati gba pada ni deede.",
"countries": "Awọn orilẹ-ede", "countries": "Awọn orilẹ-ede",
"create_account": "Dá àkáǹtì", "create_account": "Dá àkáǹtì",
"create_backup": "Ṣẹ̀dà nípamọ́", "create_backup": "Ṣẹ̀dà nípamọ́",

View file

@ -177,6 +177,7 @@
"copy_address": "复制地址", "copy_address": "复制地址",
"copy_id": "复制ID", "copy_id": "复制ID",
"copyWalletConnectLink": "从 dApp 复制 WalletConnect 链接并粘贴到此处", "copyWalletConnectLink": "从 dApp 复制 WalletConnect 链接并粘贴到此处",
"corrupted_seed_notice": "该钱包的文件被损坏,无法打开。请查看种子短语,保存并恢复钱包。\n\n如果该值为空则种子无法正确恢复。",
"countries": "国家", "countries": "国家",
"create_account": "创建账户", "create_account": "创建账户",
"create_backup": "创建备份", "create_backup": "创建备份",

View file

@ -8,7 +8,7 @@ if [[ ! -d "monero_c" ]];
then then
git clone https://github.com/mrcyjanek/monero_c --branch master git clone https://github.com/mrcyjanek/monero_c --branch master
cd monero_c cd monero_c
git checkout d72c15f4339791a7bbdf17e9d827b7b56ca144e4 git checkout c41c4dad9aa5003a914cfb2c528c76386f952665
git reset --hard git reset --hard
git submodule update --init --force --recursive git submodule update --init --force --recursive
./apply_patches.sh monero ./apply_patches.sh monero

View file

@ -14,7 +14,6 @@ list(APPEND FLUTTER_PLUGIN_LIST
) )
list(APPEND FLUTTER_FFI_PLUGIN_LIST list(APPEND FLUTTER_FFI_PLUGIN_LIST
sp_scanner
) )
set(PLUGIN_BUNDLED_LIBRARIES) set(PLUGIN_BUNDLED_LIBRARIES)