V4.6.4 bug fixes (#922)
* Fix Concurrent modification exception * Fix minor UI issues * Change onramper crypto asset name for Litcoin * Fix secure storage issue, fetching password/PIN with null * - Fix Navigation issue while keyboard is displaying - Remove deprecated screen * Take currency From/To info from our trade not the returned one * Fix anon pay fields UI * Fix Anonpay border/icons UI * Add extra padding in QR image as a safe layer * Generalize ignored connection error * Remove Bio Auth option from desktop * Fix some Transaction info not parsed correctly
Omar Hatem committed
May 10, 2023 at 16:58 UTC
1a3d47748dd89fbb323d00a36b04198bc8a6b566
16 files changed
+112
-156
cw_bitcoin/lib/electrum.dart
+1
-1
@@ -88,7 +88,7 @@ class ElectrumClient {
88
unterminatedString = '';
89
}
90
} on TypeError catch (e) {
91
- if (!e.toString().contains('Map<String, Object>') || !e.toString().contains('Map<String, dynamic>')) {
91
+ if (!e.toString().contains('Map<String, Object>') && !e.toString().contains('Map<String, dynamic>')) {
92
return;
93
}
94
lib/buy/onramper/onramper_buy_provider.dart
+12
-2
@@ -1,6 +1,7 @@
1
import 'package:cake_wallet/.secrets.g.dart' as secrets;
2
import 'package:cake_wallet/store/settings_store.dart';
3
import 'package:cake_wallet/themes/theme_base.dart';
4
+import 'package:cw_core/crypto_currency.dart';
5
import 'package:cw_core/wallet_base.dart';
6
7
class OnRamperBuyProvider {
@@ -13,7 +14,16 @@ class OnRamperBuyProvider {
14
15
static const _baseUrl = 'buy.onramper.com';
16
16
- static String get _apiKey => secrets.onramperApiKey;
17
+ String get _apiKey => secrets.onramperApiKey;
18
+
19
+ String get _normalizeCryptoCurrency {
20
+ switch (_wallet.currency) {
21
+ case CryptoCurrency.ltc:
22
+ return "LTC_LITECOIN";
23
+ default:
24
+ return _wallet.currency.title;
25
+ }
26
+ }
27
28
Uri requestUrl() {
29
String primaryColor,
@@ -53,7 +63,7 @@ class OnRamperBuyProvider {
63
64
return Uri.https(_baseUrl, '', <String, dynamic>{
65
'apiKey': _apiKey,
56
- 'defaultCrypto': _wallet.currency.title,
66
+ 'defaultCrypto': _normalizeCryptoCurrency,
67
'defaultFiat': _settingsStore.fiatCurrency.title,
68
'wallets': '${_wallet.currency.title}:${_wallet.walletAddresses.address}',
69
'supportSell': "false",
lib/router.dart
+5
-1
@@ -169,6 +169,7 @@ Route<dynamic> createRoute(RouteSettings settings) {
169
fullscreenDialog: true);
170
} else if (isSingleCoin) {
171
return MaterialPageRoute<void>(
172
+ fullscreenDialog: true,
173
builder: (_) => getIt.get<WalletRestorePage>(
174
param1: availableWalletTypes.first
175
));
@@ -188,6 +189,7 @@ Route<dynamic> createRoute(RouteSettings settings) {
189
190
case Routes.restoreWallet:
191
return MaterialPageRoute<void>(
192
+ fullscreenDialog: true,
193
builder: (_) => getIt.get<WalletRestorePage>(
194
param1: settings.arguments as WalletType));
195
@@ -509,7 +511,9 @@ Route<dynamic> createRoute(RouteSettings settings) {
511
512
case Routes.anonPayInvoicePage:
513
final args = settings.arguments as List;
512
- return CupertinoPageRoute<void>(builder: (_) => getIt.get<AnonPayInvoicePage>(param1: args));
514
+ return CupertinoPageRoute<void>(
515
+ fullscreenDialog: true,
516
+ builder: (_) => getIt.get<AnonPayInvoicePage>(param1: args));
517
518
case Routes.anonPayReceivePage:
519
final anonInvoiceViewData = settings.arguments as AnonpayInfoBase;
lib/src/screens/dashboard/widgets/address_page.dart
+4
-1
@@ -96,7 +96,10 @@ class AddressPage extends BasePage {
96
97
@override
98
Widget middle(BuildContext context) =>
99
- PresentReceiveOptionPicker(receiveOptionViewModel: receiveOptionViewModel);
99
+ PresentReceiveOptionPicker(
100
+ receiveOptionViewModel: receiveOptionViewModel,
101
+ hasWhiteBackground: currentTheme.type == ThemeType.light,
102
+ );
103
104
@override
105
Widget Function(BuildContext, Widget) get rootWrapper =>
lib/src/screens/dashboard/widgets/present_receive_option_picker.dart
+13
-5
@@ -9,14 +9,22 @@ import 'package:flutter_mobx/flutter_mobx.dart';
9
import 'package:cake_wallet/generated/i18n.dart';
10
11
class PresentReceiveOptionPicker extends StatelessWidget {
12
- PresentReceiveOptionPicker({required this.receiveOptionViewModel});
12
+ PresentReceiveOptionPicker(
13
+ {required this.receiveOptionViewModel, this.hasWhiteBackground = false});
14
15
final ReceiveOptionViewModel receiveOptionViewModel;
16
+ final bool hasWhiteBackground;
17
18
@override
19
Widget build(BuildContext context) {
18
- final arrowBottom =
19
- Image.asset('assets/images/arrow_bottom_purple_icon.png', color: Colors.white, height: 6);
20
+ final textIconTheme = hasWhiteBackground
21
+ ? Theme.of(context).accentTextTheme.headline2!.backgroundColor!
22
+ : Colors.white;
23
+ final arrowBottom = Image.asset(
24
+ 'assets/images/arrow_bottom_purple_icon.png',
25
+ color: textIconTheme,
26
+ height: 6,
27
+ );
28
29
return TextButton(
30
onPressed: () => _showPicker(context),
@@ -40,14 +48,14 @@ class PresentReceiveOptionPicker extends StatelessWidget {
48
fontSize: 18.0,
49
fontWeight: FontWeight.bold,
50
fontFamily: 'Lato',
43
- color: Theme.of(context).accentTextTheme.headline2!.backgroundColor!),
51
+ color: textIconTheme),
52
),
53
Observer(
54
builder: (_) => Text(receiveOptionViewModel.selectedReceiveOption.toString(),
55
style: TextStyle(
56
fontSize: 10.0,
57
fontWeight: FontWeight.w500,
50
- color: Theme.of(context).textTheme.headline5!.color!)))
58
+ color: textIconTheme)))
59
],
60
),
61
SizedBox(width: 5),
lib/src/screens/receive/widgets/anonpay_currency_input_field.dart
+1
-1
@@ -32,7 +32,7 @@ class AnonpayCurrencyInputField extends StatelessWidget {
32
decoration: BoxDecoration(
33
border: Border(
34
bottom: BorderSide(
35
- color: Theme.of(context).accentTextTheme.headline6!.backgroundColor!,
35
+ color: Theme.of(context).primaryTextTheme.bodyText1!.color!,
36
width: 1)),
37
),
38
child: Padding(
lib/src/screens/receive/widgets/anonpay_input_form.dart
+3
-3
@@ -69,7 +69,7 @@ class AnonInvoiceForm extends StatelessWidget {
69
BaseTextFormField(
70
controller: nameController,
71
focusNode: _nameFocusNode,
72
- borderColor: Theme.of(context).accentTextTheme.headline6!.backgroundColor,
72
+ borderColor: Theme.of(context).primaryTextTheme.bodyText1!.color!,
73
suffixIcon: SizedBox(width: 36),
74
hintText: S.of(context).optional_name,
75
textInputAction: TextInputAction.next,
@@ -88,7 +88,7 @@ class AnonInvoiceForm extends StatelessWidget {
88
controller: descriptionController,
89
focusNode: _descriptionFocusNode,
90
textInputAction: TextInputAction.next,
91
- borderColor: Theme.of(context).accentTextTheme.headline6!.backgroundColor,
91
+ borderColor: Theme.of(context).primaryTextTheme.bodyText1!.color!,
92
suffixIcon: SizedBox(width: 36),
93
hintText: S.of(context).optional_description,
94
placeholderTextStyle: TextStyle(
@@ -104,7 +104,7 @@ class AnonInvoiceForm extends StatelessWidget {
104
controller: emailController,
105
textInputAction: TextInputAction.next,
106
focusNode: _emailFocusNode,
107
- borderColor: Theme.of(context).accentTextTheme.headline6!.backgroundColor,
107
+ borderColor: Theme.of(context).primaryTextTheme.bodyText1!.color!,
108
suffixIcon: SizedBox(width: 36),
109
keyboardType: TextInputType.emailAddress,
110
hintText: S.of(context).optional_email_hint,
lib/src/screens/receive/widgets/currency_input_field.dart
+10
-8
@@ -1,4 +1,3 @@
1
-import 'package:cake_wallet/core/amount_validator.dart';
1
import 'package:cake_wallet/src/widgets/base_text_form_field.dart';
2
import 'package:cw_core/currency.dart';
3
import 'package:flutter/material.dart';
@@ -10,18 +9,20 @@ class CurrencyInputField extends StatelessWidget {
9
required this.onTapPicker,
10
required this.selectedCurrency,
11
this.focusNode,
13
- required this.controller,
12
+ required this.controller, required this.isLight,
13
});
14
+
15
final Function() onTapPicker;
16
final Currency selectedCurrency;
17
final FocusNode? focusNode;
18
final TextEditingController controller;
19
+ final bool isLight;
20
21
@override
22
Widget build(BuildContext context) {
23
final arrowBottomPurple = Image.asset(
24
'assets/images/arrow_bottom_purple_icon.png',
24
- color: Colors.white,
25
+ color: Theme.of(context).accentTextTheme.headline2!.backgroundColor!,
26
height: 8,
27
);
28
final _width = MediaQuery.of(context).size.width;
@@ -38,14 +39,14 @@ class CurrencyInputField extends StatelessWidget {
39
keyboardType: TextInputType.numberWithOptions(signed: false, decimal: true),
40
inputFormatters: [FilteringTextInputFormatter.allow(RegExp(r'^\d+(\.|\,)?\d{0,8}'))],
41
hintText: '0.000',
41
- placeholderTextStyle: TextStyle(
42
+ placeholderTextStyle: isLight ? null : TextStyle(
43
color: Theme.of(context).primaryTextTheme.headline5!.color!,
44
fontWeight: FontWeight.w600,
45
),
46
borderColor: Theme.of(context).accentTextTheme.headline6!.backgroundColor!,
46
- textColor: Colors.white,
47
+ textColor: Theme.of(context).accentTextTheme.headline2!.backgroundColor!,
48
textStyle: TextStyle(
48
- color: Colors.white,
49
+ color: Theme.of(context).accentTextTheme.headline2!.backgroundColor!,
50
),
51
prefixIcon: Padding(
52
padding: EdgeInsets.only(
@@ -68,7 +69,7 @@ class CurrencyInputField extends StatelessWidget {
69
style: TextStyle(
70
fontWeight: FontWeight.w600,
71
fontSize: 16,
71
- color: Colors.white,
72
+ color: Theme.of(context).accentTextTheme.headline2!.backgroundColor!,
73
),
74
),
75
if (selectedCurrency.tag != null)
@@ -103,7 +104,8 @@ class CurrencyInputField extends StatelessWidget {
104
style: TextStyle(
105
fontWeight: FontWeight.w600,
106
fontSize: 20,
106
- color: Colors.white,
107
+ color:
108
+ Theme.of(context).accentTextTheme.headline2!.backgroundColor!,
109
),
110
),
111
),
lib/src/screens/receive/widgets/qr_image.dart
+1
-1
@@ -23,7 +23,7 @@ class QrImage extends StatelessWidget {
23
size: size,
24
foregroundColor: Colors.black,
25
backgroundColor: Colors.white,
26
- padding: EdgeInsets.zero,
26
+ padding: const EdgeInsets.all(8.0),
27
);
28
}
29
}
lib/src/screens/receive/widgets/qr_widget.dart
+1
@@ -119,6 +119,7 @@ class QRWidget extends StatelessWidget {
119
controller: amountController,
120
onTapPicker: () => _presentPicker(context),
121
selectedCurrency: addressListViewModel.selectedCurrency,
122
+ isLight: isLight,
123
),
124
),
125
),
lib/src/screens/restore/restore_from_keys.dart
deleted
-83
@@ -1,83 +0,0 @@
1
-import 'package:flutter/services.dart';
2
-import 'package:flutter/cupertino.dart';
3
-import 'package:flutter/material.dart';
4
-import 'package:cake_wallet/generated/i18n.dart';
5
-import 'package:cake_wallet/src/widgets/blockchain_height_widget.dart';
6
-import 'package:cake_wallet/src/widgets/base_text_form_field.dart';
7
-
8
-class RestoreFromKeysFrom extends StatefulWidget {
9
- @override
10
- _RestoreFromKeysFromState createState() => _RestoreFromKeysFromState();
11
-}
12
-
13
-class _RestoreFromKeysFromState extends State<RestoreFromKeysFrom> {
14
- final _formKey = GlobalKey<FormState>();
15
- final _blockchainHeightKey = GlobalKey<BlockchainHeightState>();
16
- final _nameController = TextEditingController();
17
- final _addressController = TextEditingController();
18
- final _viewKeyController = TextEditingController();
19
- final _spendKeyController = TextEditingController();
20
- final _wifController = TextEditingController();
21
-
22
- @override
23
- void initState() {
24
- // _nameController.addListener(() =>
25
- // widget.walletRestorationFromKeysVM.name = _nameController.text);
26
- // _addressController.addListener(() =>
27
- // widget.walletRestorationFromKeysVM.address = _addressController.text);
28
- // _viewKeyController.addListener(() =>
29
- // widget.walletRestorationFromKeysVM.viewKey = _viewKeyController.text);
30
- // _spendKeyController.addListener(() =>
31
- // widget.walletRestorationFromKeysVM.spendKey = _spendKeyController.text);
32
- // _wifController.addListener(() =>
33
- // widget.walletRestorationFromKeysVM.wif = _wifController.text);
34
-
35
- super.initState();
36
- }
37
-
38
- @override
39
- void dispose() {
40
- _nameController.dispose();
41
- _addressController.dispose();
42
- _viewKeyController.dispose();
43
- _spendKeyController.dispose();
44
- _wifController.dispose();
45
- super.dispose();
46
- }
47
-
48
- @override
49
- Widget build(BuildContext context) {
50
- return Container(
51
- padding: EdgeInsets.only(left: 24, right: 24),
52
- child: Form(
53
- key: _formKey,
54
- child: Column(children: <Widget>[
55
- BaseTextFormField(
56
- controller: _addressController,
57
- keyboardType: TextInputType.multiline,
58
- maxLines: null,
59
- hintText: S.of(context).restore_address,
60
- ),
61
- Container(
62
- padding: EdgeInsets.only(top: 20.0),
63
- child: BaseTextFormField(
64
- controller: _viewKeyController,
65
- hintText: S.of(context).restore_view_key_private,
66
- )),
67
- Container(
68
- padding: EdgeInsets.only(top: 20.0),
69
- child: BaseTextFormField(
70
- controller: _spendKeyController,
71
- hintText: S.of(context).restore_spend_key_private,
72
- )),
73
- BlockchainHeightWidget(
74
- key: _blockchainHeightKey,
75
- onHeightChange: (height) {
76
- // widget.walletRestorationFromKeysVM.height = height;
77
- print(height);
78
- }),
79
- ]),
80
- ),
81
- );
82
- }
83
-}
lib/src/screens/settings/security_backup_page.dart
+22
-20
@@ -8,6 +8,7 @@ import 'package:cake_wallet/src/screens/settings/widgets/settings_cell_with_arro
8
import 'package:cake_wallet/src/screens/settings/widgets/settings_picker_cell.dart';
9
import 'package:cake_wallet/src/screens/settings/widgets/settings_switcher_cell.dart';
10
import 'package:cake_wallet/src/widgets/standard_list.dart';
11
+import 'package:cake_wallet/utils/device_info.dart';
12
import 'package:cake_wallet/view_model/settings/security_settings_view_model.dart';
13
import 'package:flutter/material.dart';
14
import 'package:flutter_mobx/flutter_mobx.dart';
@@ -48,29 +49,30 @@ class SecurityBackupPage extends BasePage {
49
),
50
),
51
StandardListSeparator(padding: EdgeInsets.symmetric(horizontal: 24)),
51
- Observer(builder: (_) {
52
- return SettingsSwitcherCell(
53
- title: S.current.settings_allow_biometrical_authentication,
54
- value: _securitySettingsViewModel.allowBiometricalAuthentication,
55
- onValueChange: (BuildContext context, bool value) {
56
- if (value) {
57
- _authService.authenticateAction(context,
58
- onAuthSuccess: (isAuthenticatedSuccessfully) async {
59
- if (isAuthenticatedSuccessfully) {
60
- if (await _securitySettingsViewModel.biometricAuthenticated()) {
52
+ if (DeviceInfo.instance.isMobile)
53
+ Observer(builder: (_) {
54
+ return SettingsSwitcherCell(
55
+ title: S.current.settings_allow_biometrical_authentication,
56
+ value: _securitySettingsViewModel.allowBiometricalAuthentication,
57
+ onValueChange: (BuildContext context, bool value) {
58
+ if (value) {
59
+ _authService.authenticateAction(context,
60
+ onAuthSuccess: (isAuthenticatedSuccessfully) async {
61
+ if (isAuthenticatedSuccessfully) {
62
+ if (await _securitySettingsViewModel.biometricAuthenticated()) {
63
+ _securitySettingsViewModel
64
+ .setAllowBiometricalAuthentication(isAuthenticatedSuccessfully);
65
+ }
66
+ } else {
67
_securitySettingsViewModel
68
.setAllowBiometricalAuthentication(isAuthenticatedSuccessfully);
69
}
64
- } else {
65
- _securitySettingsViewModel
66
- .setAllowBiometricalAuthentication(isAuthenticatedSuccessfully);
67
- }
68
- });
69
- } else {
70
- _securitySettingsViewModel.setAllowBiometricalAuthentication(value);
71
- }
72
- });
73
- }),
70
+ });
71
+ } else {
72
+ _securitySettingsViewModel.setAllowBiometricalAuthentication(value);
73
+ }
74
+ });
75
+ }),
76
Observer(builder: (_) {
77
return SettingsPickerCell<PinCodeRequiredDuration>(
78
title: S.current.require_pin_after,
lib/utils/exception_handler.dart
+5
-4
@@ -141,9 +141,9 @@ class ExceptionHandler {
141
"errno = 103", // SocketException: Software caused connection abort
142
"errno = 104", // SocketException: Connection reset by peer
143
"errno = 110", // SocketException: Connection timed out
144
- "HttpException: Connection reset by peer",
145
- "HttpException: Connection closed before full header was received",
146
- "HandshakeException: Connection terminated during handshake",
144
+ "Connection reset by peer",
145
+ "Connection closed before full header was received",
146
+ "Connection terminated during handshake",
147
"PERMISSION_NOT_GRANTED",
148
];
149
@@ -172,7 +172,7 @@ class ExceptionHandler {
172
}
173
174
await file.writeAsString(
175
- "App Version: $currentVersion\n\nDevice Info $deviceInfo",
175
+ "App Version: $currentVersion\n\nDevice Info $deviceInfo\n\n",
176
mode: FileMode.append,
177
);
178
}
@@ -193,6 +193,7 @@ class ExceptionHandler {
193
'systemVersion': data.systemVersion,
194
'model': data.model,
195
'localizedModel': data.localizedModel,
196
+ 'isPhysicalDevice': data.isPhysicalDevice,
197
};
198
}
199
lib/view_model/exchange/exchange_trade_view_model.dart
+4
-4
@@ -123,8 +123,8 @@ abstract class ExchangeTradeViewModelBase with Store {
123
}
124
125
void _updateItems() {
126
- final tagFrom = trade.from.tag != null ? '${trade.from.tag}' + ' ' : '';
127
- final tagTo = trade.to.tag != null ? '${trade.to.tag}' + ' ' : '';
126
+ final tagFrom = tradesStore.trade!.from.tag != null ? '${tradesStore.trade!.from.tag}' + ' ' : '';
127
+ final tagTo = tradesStore.trade!.to.tag != null ? '${tradesStore.trade!.to.tag}' + ' ' : '';
128
items.clear();
129
items.add(ExchangeTradeItem(
130
title: "${trade.provider.title} ${S.current.id}", data: '${trade.id}', isCopied: true));
@@ -142,11 +142,11 @@ abstract class ExchangeTradeViewModelBase with Store {
142
items.addAll([
143
ExchangeTradeItem(title: S.current.amount, data: '${trade.amount}', isCopied: true),
144
ExchangeTradeItem(
145
- title: S.current.send_to_this_address('${trade.from}', tagFrom) + ':',
145
+ title: S.current.send_to_this_address('${tradesStore.trade!.from}', tagFrom) + ':',
146
data: trade.inputAddress ?? '',
147
isCopied: true),
148
ExchangeTradeItem(
149
- title: S.current.arrive_in_this_address('${trade.to}', tagTo) + ':',
149
+ title: S.current.arrive_in_this_address('${tradesStore.trade!.to}', tagTo) + ':',
150
data: trade.payoutAddress ?? '',
151
isCopied: true),
152
]);
lib/view_model/exchange/exchange_view_model.dart
+28
-20
@@ -3,7 +3,6 @@ import 'dart:collection';
3
import 'dart:convert';
4
5
import 'package:cake_wallet/entities/exchange_api_mode.dart';
6
-import 'package:cake_wallet/entities/fiat_api_mode.dart';
6
import 'package:cake_wallet/entities/preferences_key.dart';
7
import 'package:cake_wallet/exchange/sideshift/sideshift_exchange_provider.dart';
8
import 'package:cake_wallet/exchange/sideshift/sideshift_request.dart';
@@ -244,7 +243,7 @@ abstract class ExchangeViewModelBase with Store {
243
244
List<CryptoCurrency> depositCurrencies;
245
247
- NumberFormat _cryptoNumberFormat;
246
+ final NumberFormat _cryptoNumberFormat;
247
248
final SettingsStore _settingsStore;
249
@@ -388,27 +387,36 @@ abstract class ExchangeViewModelBase with Store {
387
double? lowestMin = double.maxFinite;
388
double? highestMax = 0.0;
389
391
- for (var provider in selectedProviders) {
392
- /// if this provider is not valid for the current pair, skip it
393
- if (!providersForCurrentPair().contains(provider)) {
394
- continue;
395
- }
390
+ try {
391
+ for (var provider in selectedProviders) {
392
+ /// if this provider is not valid for the current pair, skip it
393
+ if (!providersForCurrentPair().contains(provider)) {
394
+ continue;
395
+ }
396
397
- try {
398
- final tempLimits = await provider.fetchLimits(
399
- from: from,
400
- to: to,
401
- isFixedRateMode: isFixedRateMode);
397
+ try {
398
+ final tempLimits = await provider.fetchLimits(
399
+ from: from,
400
+ to: to,
401
+ isFixedRateMode: isFixedRateMode);
402
403
- if (lowestMin != null && (tempLimits.min ?? -1) < lowestMin) {
404
- lowestMin = tempLimits.min;
405
- }
406
- if (highestMax != null && (tempLimits.max ?? double.maxFinite) > highestMax) {
407
- highestMax = tempLimits.max;
403
+ if (lowestMin != null && (tempLimits.min ?? -1) < lowestMin) {
404
+ lowestMin = tempLimits.min;
405
+ }
406
+ if (highestMax != null && (tempLimits.max ?? double.maxFinite) > highestMax) {
407
+ highestMax = tempLimits.max;
408
+ }
409
+ } catch (e) {
410
+ continue;
411
}
409
- } catch (e) {
410
- continue;
412
}
413
+ } on ConcurrentModificationError {
414
+ /// if user changed the selected providers while fetching limits
415
+ /// then delay the fetching limits a bit and try again
416
+ ///
417
+ /// this is because the limitation of collections that
418
+ /// you can't modify it while iterating through it
419
+ Future.delayed(Duration(milliseconds: 200), loadLimits);
420
}
421
422
if (lowestMin != double.maxFinite) {
@@ -534,7 +542,7 @@ abstract class ExchangeViewModelBase with Store {
542
///
543
/// this is because the limitation of the SplayTreeMap that
544
/// you can't modify it while iterating through it
537
- Future.delayed(Duration(milliseconds: 500), createTrade);
545
+ Future.delayed(Duration(milliseconds: 200), createTrade);
546
}
547
}
548
pubspec_base.yaml
+2
-2
@@ -17,8 +17,8 @@ dependencies:
17
git:
18
url: https://github.com/cake-tech/flutter_secure_storage.git
19
path: flutter_secure_storage
20
- ref: cake-6.0.0
21
- version: 6.0.0
20
+ ref: cake-8.0.0
21
+ version: 8.0.0
22
# provider: ^6.0.3
23
rxdart: ^0.27.4
24
yaml: ^3.1.1