CW-782: Show error report popup without cooldown (#1739)

* 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>

cyan committed Nov 28, 2024 at 20:28 UTC 17d34beae95e5caf4942a5a177331b604a96a1e4
51 files changed +206 -88
cw_monero/lib/api/wallet_manager.dart
+12 -3
@@ -81,6 +81,7 @@ void createWalletSync(
81 wptr = newWptr;
82 monero.Wallet_store(wptr!, path: path);
83 openedWalletsByPath[path] = wptr!;
84 + _lastOpenedWallet = path;
85
86 // is the line below needed?
87 // setupNodeSync(address: "node.moneroworld.com:18089");
@@ -116,6 +117,7 @@ void restoreWalletFromSeedSync(
117 wptr = newWptr;
118
119 openedWalletsByPath[path] = wptr!;
120 + _lastOpenedWallet = path;
121 }
122
123 void restoreWalletFromKeysSync(
@@ -183,6 +185,7 @@ void restoreWalletFromKeysSync(
185 wptr = newWptr;
186
187 openedWalletsByPath[path] = wptr!;
188 + _lastOpenedWallet = path;
189 }
190
191 void restoreWalletFromSpendKeySync(
@@ -231,6 +234,7 @@ void restoreWalletFromSpendKeySync(
234 storeSync();
235
236 openedWalletsByPath[path] = wptr!;
237 + _lastOpenedWallet = path;
238 }
239
240 String _lastOpenedWallet = "";
@@ -260,7 +264,7 @@ Future<void> restoreWalletFromHardwareWallet(
264 throw WalletRestoreFromSeedException(message: error);
265 }
266 wptr = newWptr;
263 -
267 + _lastOpenedWallet = path;
268 openedWalletsByPath[path] = wptr!;
269 }
270
@@ -295,6 +299,11 @@ Future<void> loadWallet(
299 password: password,
300 kdfRounds: 1,
301 );
302 + final status = monero.WalletManager_errorString(wmPtr);
303 + if (status != "") {
304 + print("loadWallet:"+status);
305 + throw WalletOpeningException(message: status);
306 + }
307 } else {
308 deviceType = 0;
309 }
@@ -314,15 +323,15 @@ Future<void> loadWallet(
323
324 final newWptr = Pointer<Void>.fromAddress(newWptrAddr);
325
317 - _lastOpenedWallet = path;
326 final status = monero.Wallet_status(newWptr);
327 if (status != 0) {
328 final err = monero.Wallet_errorString(newWptr);
321 - print(err);
329 + print("loadWallet:"+err);
330 throw WalletOpeningException(message: err);
331 }
332
333 wptr = newWptr;
334 + _lastOpenedWallet = path;
335 openedWalletsByPath[path] = wptr!;
336 }
337 }
cw_monero/lib/monero_wallet_service.dart
+1 -1
@@ -168,7 +168,7 @@ class MoneroWalletService extends WalletService<
168 }
169
170 await restoreOrResetWalletFiles(name);
171 - return openWallet(name, password, retryOnFailure: false);
171 + return await openWallet(name, password, retryOnFailure: false);
172 }
173 }
174
cw_monero/pubspec.lock
+2 -2
@@ -503,8 +503,8 @@ packages:
503 dependency: "direct main"
504 description:
505 path: "impls/monero.dart"
506 - ref: d72c15f4339791a7bbdf17e9d827b7b56ca144e4
507 - resolved-ref: d72c15f4339791a7bbdf17e9d827b7b56ca144e4
506 + ref: c41c4dad9aa5003a914cfb2c528c76386f952665
507 + resolved-ref: c41c4dad9aa5003a914cfb2c528c76386f952665
508 url: "https://github.com/mrcyjanek/monero_c"
509 source: git
510 version: "0.0.0"
cw_monero/pubspec.yaml
+1 -1
@@ -25,7 +25,7 @@ dependencies:
25 monero:
26 git:
27 url: https://github.com/mrcyjanek/monero_c
28 - ref: d72c15f4339791a7bbdf17e9d827b7b56ca144e4
28 + ref: c41c4dad9aa5003a914cfb2c528c76386f952665
29 # ref: 6eb571ea498ed7b854934785f00fabfd0dadf75b # monero_c hash
30 path: impls/monero.dart
31 mutex: ^3.1.0
cw_wownero/pubspec.lock
+2 -2
@@ -463,8 +463,8 @@ packages:
463 dependency: "direct main"
464 description:
465 path: "impls/monero.dart"
466 - ref: d72c15f4339791a7bbdf17e9d827b7b56ca144e4
467 - resolved-ref: d72c15f4339791a7bbdf17e9d827b7b56ca144e4
466 + ref: c41c4dad9aa5003a914cfb2c528c76386f952665
467 + resolved-ref: c41c4dad9aa5003a914cfb2c528c76386f952665
468 url: "https://github.com/mrcyjanek/monero_c"
469 source: git
470 version: "0.0.0"
cw_wownero/pubspec.yaml
+1 -1
@@ -25,7 +25,7 @@ dependencies:
25 monero:
26 git:
27 url: https://github.com/mrcyjanek/monero_c
28 - ref: d72c15f4339791a7bbdf17e9d827b7b56ca144e4
28 + ref: c41c4dad9aa5003a914cfb2c528c76386f952665
29 # ref: 6eb571ea498ed7b854934785f00fabfd0dadf75b # monero_c hash
30 path: impls/monero.dart
31 mutex: ^3.1.0
lib/anypay/anypay_api.dart
+1 -1
@@ -56,7 +56,7 @@ class AnyPayApi {
56 final response = await post(url, headers: headers, body: utf8.encode(json.encode(body)));
57
58 if (response.statusCode != 200) {
59 - ExceptionHandler.onError(FlutterErrorDetails(exception: response));
59 + await ExceptionHandler.onError(FlutterErrorDetails(exception: response));
60 throw Exception('Unexpected response http code: ${response.statusCode}');
61 }
62
lib/core/backup_service.dart
+8 -10
@@ -230,17 +230,15 @@ class BackupService {
230 json.decode(transactionDescriptionFile.readAsStringSync()) as Map<String, dynamic>;
231 final descriptionsMap = jsonData.map((key, value) =>
232 MapEntry(key, TransactionDescription.fromJson(value as Map<String, dynamic>)));
233 -
234 - if (!_transactionDescriptionBox.isOpen) {
235 - final transactionDescriptionsBoxKey = await getEncryptionKey(secureStorage: secureStorageShared, forKey: TransactionDescription.boxKey);
236 - final transactionDescriptionBox = await CakeHive.openBox<TransactionDescription>(
233 + var box = _transactionDescriptionBox;
234 + if (!box.isOpen) {
235 + final transactionDescriptionsBoxKey =
236 + await getEncryptionKey(secureStorage: _secureStorage, forKey: TransactionDescription.boxKey);
237 + box = await CakeHive.openBox<TransactionDescription>(
238 TransactionDescription.boxName,
238 - encryptionKey: transactionDescriptionsBoxKey,
239 - );
240 - await transactionDescriptionBox.putAll(descriptionsMap);
241 - return;
242 - }
243 - await _transactionDescriptionBox.putAll(descriptionsMap);
239 + encryptionKey: transactionDescriptionsBoxKey);
240 + }
241 + await box.putAll(descriptionsMap);
242 }
243
244 Future<void> _importPreferencesDump() async {
lib/core/wallet_loading_service.dart
+55 -9
@@ -2,15 +2,22 @@ import 'dart:async';
2
3 import 'package:cake_wallet/core/generate_wallet_password.dart';
4 import 'package:cake_wallet/core/key_service.dart';
5 +import 'package:cake_wallet/core/secure_storage.dart';
6 import 'package:cake_wallet/entities/preferences_key.dart';
7 +import 'package:cake_wallet/generated/i18n.dart';
8 +import 'package:cake_wallet/main.dart';
9 import 'package:cake_wallet/reactions/on_authentication_state_change.dart';
10 +import 'package:cake_wallet/src/screens/auth/auth_page.dart';
11 +import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
12 import 'package:cake_wallet/utils/exception_handler.dart';
13 +import 'package:cake_wallet/utils/show_pop_up.dart';
14 import 'package:cw_core/cake_hive.dart';
15 import 'package:cw_core/wallet_base.dart';
16 import 'package:cw_core/wallet_info.dart';
17 import 'package:cw_core/wallet_service.dart';
18 import 'package:cw_core/wallet_type.dart';
19 import 'package:flutter/material.dart';
20 +import 'package:flutter/services.dart';
21 import 'package:shared_preferences/shared_preferences.dart';
22
23 class WalletLoadingService {
@@ -58,24 +65,25 @@ class WalletLoadingService {
65
66 return wallet;
67 } catch (error, stack) {
61 - ExceptionHandler.onError(FlutterErrorDetails(exception: error, stack: stack));
68 + await ExceptionHandler.resetLastPopupDate();
69 + await ExceptionHandler.onError(FlutterErrorDetails(exception: error, stack: stack));
70
71 // try fetching the seeds of the corrupted wallet to show it to the user
72 String corruptedWalletsSeeds = "Corrupted wallets seeds (if retrievable, empty otherwise):";
73 try {
74 corruptedWalletsSeeds += await _getCorruptedWalletSeeds(name, type);
75 } catch (e) {
68 - corruptedWalletsSeeds += "\nFailed to fetch $name seeds: $e";
76 + corruptedWalletsSeeds += "\nFailed to fetch $name seeds: $e";
77 }
78
79 // try opening another wallet that is not corrupted to give user access to the app
80 final walletInfoSource = await CakeHive.openBox<WalletInfo>(WalletInfo.boxName);
73 -
81 + WalletBase? wallet;
82 for (var walletInfo in walletInfoSource.values) {
83 try {
84 final walletService = walletServiceFactory.call(walletInfo.type);
77 - final walletPassword = password ?? (await keyService.getWalletPassword(walletName: name));
78 - final wallet = await walletService.openWallet(walletInfo.name, walletPassword);
85 + final walletPassword = await keyService.getWalletPassword(walletName: walletInfo.name);
86 + wallet = await walletService.openWallet(walletInfo.name, walletPassword);
87
88 if (walletInfo.type == WalletType.monero) {
89 await updateMoneroWalletPassword(wallet);
@@ -88,8 +96,6 @@ class WalletLoadingService {
96
97 // if found a wallet that is not corrupted, then still display the seeds of the corrupted ones
98 authenticatedErrorStreamController.add(corruptedWalletsSeeds);
91 -
92 - return wallet;
99 } catch (e) {
100 print(e);
101 // save seeds and show corrupted wallets' seeds to the user
@@ -99,16 +105,56 @@ class WalletLoadingService {
105 corruptedWalletsSeeds += seeds;
106 }
107 } catch (e) {
102 - corruptedWalletsSeeds += "\nFailed to fetch $name seeds: $e";
108 + corruptedWalletsSeeds += "\nFailed to fetch $name seeds: $e";
109 }
110 }
111 }
112
113 // if all user's wallets are corrupted throw exception
108 - throw error.toString() + "\n\n" + corruptedWalletsSeeds;
114 + final msg = error.toString() + "\n" + corruptedWalletsSeeds;
115 + if (navigatorKey.currentContext != null) {
116 + await showPopUp<void>(
117 + context: navigatorKey.currentContext!,
118 + builder: (BuildContext context) {
119 + return AlertWithTwoActions(
120 + alertTitle: "Corrupted seeds",
121 + alertContent: S.of(context).corrupted_seed_notice,
122 + leftButtonText: S.of(context).cancel,
123 + rightButtonText: S.of(context).show_seed,
124 + actionLeftButton: () => Navigator.of(context).pop(),
125 + actionRightButton: () => showSeedsPopup(context, msg),
126 + );
127 + });
128 + } else {
129 + throw msg;
130 + }
131 + if (wallet == null) {
132 + throw Exception("Wallet is null");
133 + }
134 + return wallet;
135 }
136 }
137
138 + Future<void> showSeedsPopup(BuildContext context, String message) async {
139 + Navigator.of(context).pop();
140 + await showPopUp<void>(
141 + context: context,
142 + builder: (BuildContext context) {
143 + return AlertWithTwoActions(
144 + alertTitle: "Corrupted seeds",
145 + alertContent: message,
146 + leftButtonText: S.of(context).copy,
147 + rightButtonText: S.of(context).ok,
148 + actionLeftButton: () async {
149 + await Clipboard.setData(ClipboardData(text: message));
150 + },
151 + actionRightButton: () async {
152 + Navigator.of(context).pop();
153 + },
154 + );
155 + });
156 + }
157 +
158 Future<void> updateMoneroWalletPassword(WalletBase wallet) async {
159 final key = PreferencesKey.moneroWalletUpdateV1Key(wallet.name);
160 var isPasswordUpdated = sharedPreferences.getBool(key) ?? false;
lib/di.dart
+3 -3
@@ -575,7 +575,7 @@ Future<void> setup({
575 totpAuthPageState.changeProcessText('Loading the wallet');
576
577 if (loginError != null) {
578 - totpAuthPageState.changeProcessText('ERROR: ${loginError.toString()}');
578 + totpAuthPageState.changeProcessText('ERROR: ${loginError.toString()}'.trim());
579 }
580
581 ReactionDisposer? _reaction;
@@ -604,7 +604,7 @@ Future<void> setup({
604 authPageState.changeProcessText('Loading the wallet');
605
606 if (loginError != null) {
607 - authPageState.changeProcessText('ERROR: ${loginError.toString()}');
607 + authPageState.changeProcessText('ERROR: ${loginError.toString()}'.trim());
608 loginError = null;
609 }
610
@@ -624,7 +624,7 @@ Future<void> setup({
624 }
625
626 if (loginError != null) {
627 - authPageState.changeProcessText('ERROR: ${loginError.toString()}');
627 + authPageState.changeProcessText('ERROR: ${loginError.toString()}'.trim());
628 timer.cancel();
629 }
630 });
lib/main.dart
+1 -1
@@ -89,7 +89,7 @@ Future<void> runAppWithZone({Key? topLevelKey}) async {
89 );
90 }
91
92 - ExceptionHandler.onError(FlutterErrorDetails(exception: error, stack: stackTrace));
92 + await ExceptionHandler.onError(FlutterErrorDetails(exception: error, stack: stackTrace));
93 });
94 }
95
lib/reactions/on_authentication_state_change.dart
+3 -3
@@ -43,8 +43,8 @@ void startAuthenticationStateChange(
43 if (!requireHardwareWalletConnection()) await loadCurrentWallet();
44 } catch (error, stack) {
45 loginError = error;
46 - ExceptionHandler.onError(
47 - FlutterErrorDetails(exception: error, stack: stack));
46 + await ExceptionHandler.resetLastPopupDate();
47 + await ExceptionHandler.onError(FlutterErrorDetails(exception: error, stack: stack));
48 }
49 return;
50 }
@@ -81,7 +81,7 @@ void startAuthenticationStateChange(
81 .pushNamedAndRemoveUntil(Routes.dashboard, (route) => false);
82 }
83 if (!(await authenticatedErrorStreamController.stream.isEmpty)) {
84 - ExceptionHandler.showError(
84 + await ExceptionHandler.showError(
85 (await authenticatedErrorStreamController.stream.first).toString());
86 authenticatedErrorStreamController.stream.drain();
87 }
lib/src/screens/auth/auth_page.dart
+21 -2
@@ -1,5 +1,6 @@
1 import 'package:another_flushbar/flushbar.dart';
2 import 'package:cake_wallet/utils/show_bar.dart';
3 +import 'package:cake_wallet/utils/show_pop_up.dart';
4 import 'package:mobx/mobx.dart';
5 import 'package:flutter/material.dart';
6 import 'package:flutter/cupertino.dart';
@@ -9,6 +10,8 @@ import 'package:cake_wallet/view_model/auth_view_model.dart';
10 import 'package:cake_wallet/src/screens/pin_code/pin_code.dart';
11 import 'package:cake_wallet/src/screens/pin_code/pin_code_widget.dart';
12 import 'package:cake_wallet/core/execution_state.dart';
13 +import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
14 +import 'package:flutter/services.dart';
15
16 typedef OnAuthenticationFinished = void Function(bool, AuthPageState);
17
@@ -66,7 +69,6 @@ class AuthPagePinCodeStateImpl extends AuthPageState<AuthPage> {
69 dismissFlushBar(_authBar);
70 showBar<void>(
71 context, S.of(context).failed_authentication(state.error));
69 -
72 widget.onAuthenticationFinished(false, this);
73 });
74 }
@@ -77,12 +79,12 @@ class AuthPagePinCodeStateImpl extends AuthPageState<AuthPage> {
79 dismissFlushBar(_authBar);
80 showBar<void>(
81 context, S.of(context).failed_authentication(state.error));
80 -
82 widget.onAuthenticationFinished(false, this);
83 });
84 }
85 });
86
87 +
88 if (widget.authViewModel.isBiometricalAuthenticationAllowed) {
89 WidgetsBinding.instance.addPostFrameCallback((_) async {
90 await Future<void>.delayed(Duration(milliseconds: 100));
@@ -93,6 +95,23 @@ class AuthPagePinCodeStateImpl extends AuthPageState<AuthPage> {
95 super.initState();
96 }
97
98 + Future<void> _showSeedsPopup(BuildContext context, String message) async {
99 + await showPopUp<void>(
100 + context: context,
101 + builder: (BuildContext context) {
102 + return AlertWithTwoActions(
103 + alertTitle: "Corrupted seeds",
104 + alertContent: message,
105 + leftButtonText: S.of(context).copy,
106 + rightButtonText: S.of(context).ok,
107 + actionLeftButton: () async {
108 + await Clipboard.setData(ClipboardData(text: message));
109 + },
110 + actionRightButton: () => Navigator.of(context).pop(),
111 + );
112 + });
113 + }
114 +
115 @override
116 void dispose() {
117 _reaction?.reaction.dispose();
lib/src/screens/backup/backup_page.dart
+1 -1
@@ -154,7 +154,7 @@ class BackupPage extends BasePage {
154 File returnedFile = File(outputFile!);
155 await returnedFile.writeAsBytes(backup.content);
156 } catch (exception, stackTrace) {
157 - ExceptionHandler.onError(FlutterErrorDetails(
157 + await ExceptionHandler.onError(FlutterErrorDetails(
158 exception: exception,
159 stack: stackTrace,
160 library: "Export Backup",
lib/src/screens/dashboard/desktop_widgets/desktop_wallet_selection_dropdown.dart
+1
@@ -11,6 +11,7 @@ import 'package:cake_wallet/src/screens/wallet_unlock/wallet_unlock_arguments.da
11 import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
12 import 'package:cake_wallet/store/settings_store.dart';
13 import 'package:cake_wallet/themes/extensions/menu_theme.dart';
14 +import 'package:cake_wallet/utils/exception_handler.dart';
15 import 'package:cake_wallet/utils/show_bar.dart';
16 import 'package:cake_wallet/utils/show_pop_up.dart';
17 import 'package:cake_wallet/view_model/wallet_list/wallet_list_item.dart';
lib/src/screens/wallet_list/wallet_list_page.dart
+5
@@ -1,6 +1,7 @@
1 import 'package:another_flushbar/flushbar.dart';
2 import 'package:cake_wallet/core/auth_service.dart';
3 import 'package:cake_wallet/core/new_wallet_arguments.dart';
4 +import 'package:cake_wallet/core/secure_storage.dart';
5 import 'package:cake_wallet/entities/wallet_edit_page_arguments.dart';
6 import 'package:cake_wallet/entities/wallet_list_order_types.dart';
7 import 'package:cake_wallet/generated/i18n.dart';
@@ -20,6 +21,7 @@ import 'package:cake_wallet/store/settings_store.dart';
21 import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
22 import 'package:cake_wallet/themes/extensions/filter_theme.dart';
23 import 'package:cake_wallet/themes/extensions/wallet_list_theme.dart';
24 +import 'package:cake_wallet/utils/exception_handler.dart';
25 import 'package:cake_wallet/utils/responsive_layout_util.dart';
26 import 'package:cake_wallet/utils/show_bar.dart';
27 import 'package:cake_wallet/utils/show_pop_up.dart';
@@ -459,6 +461,9 @@ class WalletListBodyState extends State<WalletListBody> {
461 });
462 }
463 } catch (e) {
464 + await ExceptionHandler.resetLastPopupDate();
465 + final err = e.toString();
466 + await ExceptionHandler.onError(FlutterErrorDetails(exception: err));
467 if (this.mounted) {
468 changeProcessText(S
469 .of(context)
lib/src/widgets/base_alert_dialog.dart
+16 -9
@@ -73,15 +73,22 @@ class BaseAlertDialog extends StatelessWidget {
73 }
74
75 Widget content(BuildContext context) {
76 - return Text(
77 - contentText,
78 - textAlign: TextAlign.center,
79 - style: TextStyle(
80 - fontSize: 16,
81 - fontWeight: FontWeight.normal,
82 - fontFamily: 'Lato',
83 - color: Theme.of(context).extension<CakeTextTheme>()!.titleColor,
84 - decoration: TextDecoration.none,
76 + return SingleChildScrollView(
77 + child: Column(
78 + mainAxisSize: MainAxisSize.min,
79 + children: [
80 + Text(
81 + contentText,
82 + textAlign: TextAlign.center,
83 + style: TextStyle(
84 + fontSize: 16,
85 + fontWeight: FontWeight.normal,
86 + fontFamily: 'Lato',
87 + color: Theme.of(context).extension<CakeTextTheme>()!.titleColor,
88 + decoration: TextDecoration.none,
89 + ),
90 + ),
91 + ],
92 ),
93 );
94 }
lib/utils/exception_handler.dart
+42 -33
@@ -1,5 +1,6 @@
1 import 'dart:io';
2
3 +import 'package:cake_wallet/core/secure_storage.dart';
4 import 'package:cake_wallet/entities/preferences_key.dart';
5 import 'package:cake_wallet/generated/i18n.dart';
6 import 'package:cake_wallet/main.dart';
@@ -20,7 +21,7 @@ class ExceptionHandler {
21 static const _coolDownDurationInDays = 7;
22 static File? _file;
23
23 - static void _saveException(String? error, StackTrace? stackTrace, {String? library}) async {
24 + static Future<void> _saveException(String? error, StackTrace? stackTrace, {String? library}) async {
25 final appDocDir = await getAppDir();
26
27 if (_file == null) {
@@ -90,7 +91,12 @@ class ExceptionHandler {
91 }
92 }
93
93 - static void onError(FlutterErrorDetails errorDetails) async {
94 + static Future<void> resetLastPopupDate() async {
95 + final sharedPrefs = await SharedPreferences.getInstance();
96 + await sharedPrefs.setString(PreferencesKey.lastPopupDate, DateTime(1971).toString());
97 + }
98 +
99 + static Future<void> onError(FlutterErrorDetails errorDetails) async {
100 if (kDebugMode || kProfileMode) {
101 FlutterError.presentError(errorDetails);
102 debugPrint(errorDetails.toString());
@@ -124,35 +130,40 @@ class ExceptionHandler {
130 }
131 _hasError = true;
132
127 - sharedPrefs.setString(PreferencesKey.lastPopupDate, DateTime.now().toString());
128 -
129 - WidgetsBinding.instance.addPostFrameCallback(
130 - (timeStamp) async {
131 - if (navigatorKey.currentContext != null) {
132 - await showPopUp<void>(
133 - context: navigatorKey.currentContext!,
134 - builder: (context) {
135 - return AlertWithTwoActions(
136 - isDividerExist: true,
137 - alertTitle: S.of(context).error,
138 - alertContent: S.of(context).error_dialog_content,
139 - rightButtonText: S.of(context).send,
140 - leftButtonText: S.of(context).do_not_send,
141 - actionRightButton: () {
142 - Navigator.of(context).pop();
143 - _sendExceptionFile();
144 - },
145 - actionLeftButton: () {
146 - Navigator.of(context).pop();
147 - },
148 - );
133 + await sharedPrefs.setString(PreferencesKey.lastPopupDate, DateTime.now().toString());
134 +
135 + // Instead of using WidgetsBinding.instance.addPostFrameCallback we
136 + // await Future.delayed(Duration.zero), which does essentially the same (
137 + // but doesn't wait for actual frame to be rendered), but it allows us to
138 + // properly await the execution - which is what we want, without awaiting
139 + // other code may call functions like Navigator.pop(), and close the alert
140 + // instead of the intended UI.
141 + // WidgetsBinding.instance.addPostFrameCallback(
142 + // (timeStamp) async {
143 + await Future.delayed(Duration.zero);
144 + if (navigatorKey.currentContext != null) {
145 + await showPopUp<void>(
146 + context: navigatorKey.currentContext!,
147 + builder: (context) {
148 + return AlertWithTwoActions(
149 + isDividerExist: true,
150 + alertTitle: S.of(context).error,
151 + alertContent: S.of(context).error_dialog_content,
152 + rightButtonText: S.of(context).send,
153 + leftButtonText: S.of(context).do_not_send,
154 + actionRightButton: () {
155 + Navigator.of(context).pop();
156 + _sendExceptionFile();
157 + },
158 + actionLeftButton: () {
159 + Navigator.of(context).pop();
160 },
161 );
151 - }
162 + },
163 + );
164 + }
165
153 - _hasError = false;
154 - },
155 - );
166 + _hasError = false;
167 }
168
169 /// Ignore User related errors or system errors
@@ -272,20 +283,18 @@ class ExceptionHandler {
283 };
284 }
285
275 - static void showError(String error, {int? delayInSeconds}) async {
286 + static Future<void> showError(String error, {int? delayInSeconds}) async {
287 if (_hasError) {
288 return;
289 }
290 _hasError = true;
280 -
291 if (delayInSeconds != null) {
292 Future.delayed(Duration(seconds: delayInSeconds), () => _showCopyPopup(error));
293 return;
294 }
295
286 - WidgetsBinding.instance.addPostFrameCallback(
287 - (_) async => _showCopyPopup(error),
288 - );
296 + await Future.delayed(Duration.zero);
297 + await _showCopyPopup(error);
298 }
299
300 static Future<void> _showCopyPopup(String content) async {
lib/view_model/restore_from_backup_view_model.dart
+1 -1
@@ -68,7 +68,7 @@ abstract class RestoreFromBackupViewModelBase with Store {
68 if (msg.toLowerCase().contains("message authentication code (mac)")) {
69 msg = 'Incorrect backup password';
70 } else {
71 - ExceptionHandler.onError(FlutterErrorDetails(
71 + await ExceptionHandler.onError(FlutterErrorDetails(
72 exception: e,
73 stack: s,
74 library: this.toString(),
linux/flutter/generated_plugins.cmake
-1
@@ -10,7 +10,6 @@ list(APPEND FLUTTER_PLUGIN_LIST
10 )
11
12 list(APPEND FLUTTER_FFI_PLUGIN_LIST
13 - sp_scanner
13 )
14
15 set(PLUGIN_BUNDLED_LIBRARIES)
macos/Flutter/GeneratedPluginRegistrant.swift
-2
@@ -6,7 +6,6 @@ import FlutterMacOS
6 import Foundation
7
8 import connectivity_plus
9 -import cw_mweb
9 import device_info_plus
10 import devicelocale
11 import fast_scanner
@@ -24,7 +23,6 @@ import wakelock_plus
23
24 func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
25 ConnectivityPlugin.register(with: registry.registrar(forPlugin: "ConnectivityPlugin"))
27 - CwMwebPlugin.register(with: registry.registrar(forPlugin: "CwMwebPlugin"))
26 DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin"))
27 DevicelocalePlugin.register(with: registry.registrar(forPlugin: "DevicelocalePlugin"))
28 MobileScannerPlugin.register(with: registry.registrar(forPlugin: "MobileScannerPlugin"))
res/values/strings_ar.arb
+1
@@ -177,6 +177,7 @@
177 "copy_address": "نسخ العنوان",
178 "copy_id": "نسخ معرف العملية",
179 "copyWalletConnectLink": "ﺎﻨﻫ ﻪﻘﺼﻟﺍﻭ dApp ﻦﻣ WalletConnect ﻂﺑﺍﺭ ﺦﺴﻧﺍ",
180 + "corrupted_seed_notice": "تالف ملفات هذه المحفظة ولا يمكن فتحها. يرجى الاطلاع على عبارة البذور وحفظها واستعادة المحفظة.\n\nإذا كانت القيمة فارغة ، لم تتمكن البذور من استردادها بشكل صحيح.",
181 "countries": "بلدان",
182 "create_account": "إنشاء حساب",
183 "create_backup": "انشئ نسخة احتياطية",
res/values/strings_bg.arb
+1
@@ -177,6 +177,7 @@
177 "copy_address": "Copy Address",
178 "copy_id": "Копиране на ID",
179 "copyWalletConnectLink": "Копирайте връзката WalletConnect от dApp и я поставете тук",
180 + "corrupted_seed_notice": "Файловете за този портфейл са повредени и не могат да бъдат отворени. Моля, прегледайте фразата за семена, запазете я и възстановете портфейла.\n\nАко стойността е празна, тогава семето не успя да бъде правилно възстановено.",
181 "countries": "Държави",
182 "create_account": "Създаване на профил",
183 "create_backup": "Създаване на резервно копие",
res/values/strings_cs.arb
+1
@@ -177,6 +177,7 @@
177 "copy_address": "Zkopírovat adresu",
178 "copy_id": "Kopírovat ID",
179 "copyWalletConnectLink": "Zkopírujte odkaz WalletConnect z dApp a vložte jej sem",
180 + "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.",
181 "countries": "Země",
182 "create_account": "Vytvořit účet",
183 "create_backup": "Vytvořit zálohu",
res/values/strings_de.arb
+1
@@ -177,6 +177,7 @@
177 "copy_address": "Adresse kopieren",
178 "copy_id": "ID kopieren",
179 "copyWalletConnectLink": "Kopieren Sie den WalletConnect-Link von dApp und fügen Sie ihn hier ein",
180 + "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.",
181 "countries": "Länder",
182 "create_account": "Konto erstellen",
183 "create_backup": "Backup erstellen",
res/values/strings_en.arb
+1
@@ -177,6 +177,7 @@
177 "copy_address": "Copy Address",
178 "copy_id": "Copy ID",
179 "copyWalletConnectLink": "Copy the WalletConnect link from dApp and paste here",
180 + "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.",
181 "countries": "Countries",
182 "create_account": "Create Account",
183 "create_backup": "Create backup",
res/values/strings_es.arb
+1
@@ -177,6 +177,7 @@
177 "copy_address": "Copiar dirección ",
178 "copy_id": "Copiar ID",
179 "copyWalletConnectLink": "Copie el enlace de WalletConnect de dApp y péguelo aquí",
180 + "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.",
181 "countries": "Países",
182 "create_account": "Crear Cuenta",
183 "create_backup": "Crear copia de seguridad",
res/values/strings_fr.arb
+1
@@ -177,6 +177,7 @@
177 "copy_address": "Copier l'Adresse",
178 "copy_id": "Copier l'ID",
179 "copyWalletConnectLink": "Copiez le lien WalletConnect depuis l'application décentralisée (dApp) et collez-le ici",
180 + "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.",
181 "countries": "Des pays",
182 "create_account": "Créer un compte",
183 "create_backup": "Créer une sauvegarde",
res/values/strings_ha.arb
+1
@@ -177,6 +177,7 @@
177 "copy_address": "Kwafi Adireshin",
178 "copy_id": "Kwafi ID",
179 "copyWalletConnectLink": "Kwafi hanyar haɗin WalletConnect daga dApp kuma liƙa a nan",
180 + "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.",
181 "countries": "Kasashe",
182 "create_account": "Kirkira ajiya",
183 "create_backup": "Ƙirƙiri madadin",
res/values/strings_hi.arb
+1
@@ -177,6 +177,7 @@
177 "copy_address": "पता कॉपी करें",
178 "copy_id": "प्रतिलिपि ID",
179 "copyWalletConnectLink": "dApp से वॉलेटकनेक्ट लिंक को कॉपी करें और यहां पेस्ट करें",
180 + "corrupted_seed_notice": "इस वॉलेट की फाइलें दूषित हैं और उन्हें खोलने में असमर्थ हैं। कृपया बीज वाक्यांश देखें, इसे बचाएं, और बटुए को पुनर्स्थापित करें।\n\nयदि मूल्य खाली है, तो बीज सही ढंग से पुनर्प्राप्त करने में असमर्थ था।",
181 "countries": "देशों",
182 "create_account": "खाता बनाएं",
183 "create_backup": "बैकअप बनाएँ",
res/values/strings_hr.arb
+1
@@ -177,6 +177,7 @@
177 "copy_address": "Kopiraj adresu",
178 "copy_id": "Kopirati ID",
179 "copyWalletConnectLink": "Kopirajte vezu WalletConnect iz dApp-a i zalijepite je ovdje",
180 + "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.",
181 "countries": "Zemalja",
182 "create_account": "Stvori račun",
183 "create_backup": "Stvori sigurnosnu kopiju",
res/values/strings_hy.arb
+1
@@ -177,6 +177,7 @@
177 "copy_address": "Պատճենել հասցեն",
178 "copy_id": "Պատճենել ID",
179 "copyWalletConnectLink": "Պատճենել WalletConnect հղումը dApp-ից և տեղադրել այստեղ",
180 + "corrupted_seed_notice": "Այս դրամապանակի համար ֆայլերը կոռումպացված են եւ չեն կարողանում բացվել: Խնդրում ենք դիտել սերմերի արտահայտությունը, պահպանել այն եւ վերականգնել դրամապանակը:\n\nԵթե ​​արժեքը դատարկ է, ապա սերմը չկարողացավ ճիշտ վերականգնվել:",
181 "countries": "Երկրներ",
182 "create_account": "Ստեղծել հաշիվ",
183 "create_backup": "Ստեղծել կրկնօրինակ",
res/values/strings_id.arb
+1
@@ -177,6 +177,7 @@
177 "copy_address": "Salin Alamat",
178 "copy_id": "Salin ID",
179 "copyWalletConnectLink": "Salin tautan WalletConnect dari dApp dan tempel di sini",
180 + "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.",
181 "countries": "Negara",
182 "create_account": "Buat Akun",
183 "create_backup": "Buat cadangan",
res/values/strings_it.arb
+1
@@ -178,6 +178,7 @@
178 "copy_address": "Copia Indirizzo",
179 "copy_id": "Copia ID",
180 "copyWalletConnectLink": "Copia il collegamento WalletConnect dalla dApp e incollalo qui",
181 + "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.",
182 "countries": "Paesi",
183 "create_account": "Crea account",
184 "create_backup": "Crea backup",
res/values/strings_ja.arb
+1
@@ -177,6 +177,7 @@
177 "copy_address": "住所をコピー",
178 "copy_id": "IDをコピー",
179 "copyWalletConnectLink": "dApp から WalletConnect リンクをコピーし、ここに貼り付けます",
180 + "corrupted_seed_notice": "このウォレットのファイルは破損しており、開くことができません。シードフレーズを表示し、保存し、財布を復元してください。\n\n値が空の場合、種子を正しく回復することができませんでした。",
181 "countries": "国",
182 "create_account": "アカウントの作成",
183 "create_backup": "バックアップを作成",
res/values/strings_ko.arb
+1
@@ -177,6 +177,7 @@
177 "copy_address": "주소 복사",
178 "copy_id": "부 ID",
179 "copyWalletConnectLink": "dApp에서 WalletConnect 링크를 복사하여 여기에 붙여넣으세요.",
180 + "corrupted_seed_notice": "이 지갑의 파일은 손상되어 열 수 없습니다. 씨앗 문구를보고 저장하고 지갑을 복원하십시오.\n\n값이 비어 있으면 씨앗을 올바르게 회수 할 수 없었습니다.",
181 "countries": "국가",
182 "create_account": "계정 만들기",
183 "create_backup": "백업 생성",
res/values/strings_my.arb
+1
@@ -177,6 +177,7 @@
177 "copy_address": "လိပ်စာကို ကူးယူပါ။",
178 "copy_id": "ID ကူးယူပါ။",
179 "copyWalletConnectLink": "dApp မှ WalletConnect လင့်ခ်ကို ကူးယူပြီး ဤနေရာတွင် ကူးထည့်ပါ။",
180 + "corrupted_seed_notice": "ဤပိုက်ဆံအိတ်အတွက်ဖိုင်များသည်အကျင့်ပျက်ခြစားမှုများနှင့်မဖွင့်နိုင်ပါ။ ကျေးဇူးပြု. မျိုးစေ့များကိုကြည့်ပါ, ၎င်းကိုသိမ်းဆည်းပါ, ပိုက်ဆံအိတ်ကိုပြန်ယူပါ။\n\nအကယ်. တန်ဖိုးသည်အချည်းနှီးဖြစ်ပါကမျိုးစေ့ကိုမှန်ကန်စွာပြန်လည်ကောင်းမွန်မရရှိနိုင်ပါ။",
181 "countries": "နိုင်ငံများ",
182 "create_account": "အကောင့်ပြုလုပ်ပါ",
183 "create_backup": "အရန်သိမ်းခြင်းကို ဖန်တီးပါ။",
res/values/strings_nl.arb
+1
@@ -177,6 +177,7 @@
177 "copy_address": "Adres kopiëren",
178 "copy_id": "ID kopiëren",
179 "copyWalletConnectLink": "Kopieer de WalletConnect-link van dApp en plak deze hier",
180 + "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.",
181 "countries": "Landen",
182 "create_account": "Account aanmaken",
183 "create_backup": "Maak een back-up",
res/values/strings_pl.arb
+1
@@ -177,6 +177,7 @@
177 "copy_address": "Skopiuj adress",
178 "copy_id": "skopiuj ID",
179 "copyWalletConnectLink": "Skopiuj link do WalletConnect z dApp i wklej tutaj",
180 + "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ć.",
181 "countries": "Kraje",
182 "create_account": "Utwórz konto",
183 "create_backup": "Utwórz kopię zapasową",
res/values/strings_pt.arb
+1
@@ -177,6 +177,7 @@
177 "copy_address": "Copiar endereço",
178 "copy_id": "Copiar ID",
179 "copyWalletConnectLink": "Copie o link WalletConnect do dApp e cole aqui",
180 + "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.",
181 "countries": "Países",
182 "create_account": "Criar conta",
183 "create_backup": "Criar backup",
res/values/strings_ru.arb
+1
@@ -177,6 +177,7 @@
177 "copy_address": "Cкопировать адрес",
178 "copy_id": "Скопировать ID",
179 "copyWalletConnectLink": "Скопируйте ссылку WalletConnect из dApp и вставьте сюда.",
180 + "corrupted_seed_notice": "Файлы для этого кошелька повреждены и не могут быть открыты. Пожалуйста, просмотрите семенную фразу, сохраните ее и восстановите кошелек.\n\nЕсли значение пустое, то семя не смог правильно восстановить.",
181 "countries": "Страны",
182 "create_account": "Создать аккаунт",
183 "create_backup": "Создать резервную копию",
res/values/strings_th.arb
+1
@@ -177,6 +177,7 @@
177 "copy_address": "คัดลอกที่อยู่",
178 "copy_id": "คัดลอก ID",
179 "copyWalletConnectLink": "คัดลอกลิงก์ WalletConnect จาก dApp แล้ววางที่นี่",
180 + "corrupted_seed_notice": "ไฟล์สำหรับกระเป๋าเงินนี้เสียหายและไม่สามารถเปิดได้ โปรดดูวลีเมล็ดบันทึกและกู้คืนกระเป๋าเงิน\n\nหากค่าว่างเปล่าเมล็ดก็ไม่สามารถกู้คืนได้อย่างถูกต้อง",
181 "countries": "ประเทศ",
182 "create_account": "สร้างบัญชี",
183 "create_backup": "สร้างการสำรองข้อมูล",
res/values/strings_tl.arb
+1
@@ -177,6 +177,7 @@
177 "copy_address": "Kopyahin ang Address",
178 "copy_id": "Kopyahin ang ID",
179 "copyWalletConnectLink": "Kopyahin ang link ng WalletConnect mula sa dApp at i-paste dito",
180 + "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.",
181 "countries": "Mga bansa",
182 "create_account": "Lumikha ng Account",
183 "create_backup": "Lumikha ng backup",
res/values/strings_tr.arb
+1
@@ -177,6 +177,7 @@
177 "copy_address": "Adresi kopyala",
178 "copy_id": "ID'yi kopyala",
179 "copyWalletConnectLink": "WalletConnect bağlantısını dApp'ten kopyalayıp buraya yapıştırın",
180 + "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ı.",
181 "countries": "Ülkeler",
182 "create_account": "Hesap oluştur",
183 "create_backup": "Yedek oluştur",
res/values/strings_uk.arb
+1
@@ -177,6 +177,7 @@
177 "copy_address": "Cкопіювати адресу",
178 "copy_id": "Скопіювати ID",
179 "copyWalletConnectLink": "Скопіюйте посилання WalletConnect із dApp і вставте сюди",
180 + "corrupted_seed_notice": "Файли для цього гаманця пошкоджені і не можуть бути відкриті. Перегляньте насіннєву фразу, збережіть її та відновіть гаманець.\n\nЯкщо значення порожнє, то насіння не могло бути правильно відновленим.",
181 "countries": "Країни",
182 "create_account": "Створити обліковий запис",
183 "create_backup": "Створити резервну копію",
res/values/strings_ur.arb
+1
@@ -177,6 +177,7 @@
177 "copy_address": "ایڈریس کاپی کریں۔",
178 "copy_id": "کاپی ID",
179 "copyWalletConnectLink": "dApp ﮯﺳ WalletConnect ۔ﮟﯾﺮﮐ ﭧﺴﯿﭘ ﮞﺎﮩﯾ ﺭﻭﺍ ﮟﯾﺮﮐ ﯽﭘﺎﮐ ﻮﮐ ﮏﻨﻟ",
180 + "corrupted_seed_notice": "اس پرس کے لئے فائلیں خراب ہیں اور کھولنے سے قاصر ہیں۔ براہ کرم بیج کے فقرے کو دیکھیں ، اسے بچائیں ، اور بٹوے کو بحال کریں۔\n\nاگر قیمت خالی ہے ، تو بیج صحیح طور پر بازیافت کرنے سے قاصر تھا۔",
181 "countries": "ممالک",
182 "create_account": "اکاؤنٹ بنائیں",
183 "create_backup": "بیک اپ بنائیں",
res/values/strings_vi.arb
+1
@@ -176,6 +176,7 @@
176 "copy_address": "Sao chép Địa chỉ",
177 "copy_id": "Sao chép ID",
178 "copyWalletConnectLink": "Sao chép liên kết WalletConnect từ dApp và dán vào đây",
179 + "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.",
180 "countries": "Quốc gia",
181 "create_account": "Tạo tài khoản",
182 "create_backup": "Tạo sao lưu",
res/values/strings_yo.arb
+1
@@ -177,6 +177,7 @@
177 "copy_address": "Ṣẹ̀dà àdírẹ́sì",
178 "copy_id": "Ṣẹ̀dà àmì ìdánimọ̀",
179 "copyWalletConnectLink": "Daakọ ọna asopọ WalletConnect lati dApp ki o si lẹẹmọ nibi",
180 + "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.",
181 "countries": "Awọn orilẹ-ede",
182 "create_account": "Dá àkáǹtì",
183 "create_backup": "Ṣẹ̀dà nípamọ́",
res/values/strings_zh.arb
+1
@@ -177,6 +177,7 @@
177 "copy_address": "复制地址",
178 "copy_id": "复制ID",
179 "copyWalletConnectLink": "从 dApp 复制 WalletConnect 链接并粘贴到此处",
180 + "corrupted_seed_notice": "该钱包的文件被损坏,无法打开。请查看种子短语,保存并恢复钱包。\n\n如果该值为空,则种子无法正确恢复。",
181 "countries": "国家",
182 "create_account": "创建账户",
183 "create_backup": "创建备份",
scripts/prepare_moneroc.sh
+1 -1
@@ -8,7 +8,7 @@ if [[ ! -d "monero_c" ]];
8 then
9 git clone https://github.com/mrcyjanek/monero_c --branch master
10 cd monero_c
11 - git checkout d72c15f4339791a7bbdf17e9d827b7b56ca144e4
11 + git checkout c41c4dad9aa5003a914cfb2c528c76386f952665
12 git reset --hard
13 git submodule update --init --force --recursive
14 ./apply_patches.sh monero
windows/flutter/generated_plugins.cmake
-1
@@ -14,7 +14,6 @@ list(APPEND FLUTTER_PLUGIN_LIST
14 )
15
16 list(APPEND FLUTTER_FFI_PLUGIN_LIST
17 - sp_scanner
17 )
18
19 set(PLUGIN_BUNDLED_LIBRARIES)