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
This commit is contained in:
Omar Hatem 2023-05-10 16:58:31 +03:00 committed by GitHub
parent e28e2fbdde
commit 1a3d47748d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 113 additions and 157 deletions

View file

@ -88,7 +88,7 @@ class ElectrumClient {
unterminatedString = '';
}
} on TypeError catch (e) {
if (!e.toString().contains('Map<String, Object>') || !e.toString().contains('Map<String, dynamic>')) {
if (!e.toString().contains('Map<String, Object>') && !e.toString().contains('Map<String, dynamic>')) {
return;
}

View file

@ -1,6 +1,7 @@
import 'package:cake_wallet/.secrets.g.dart' as secrets;
import 'package:cake_wallet/store/settings_store.dart';
import 'package:cake_wallet/themes/theme_base.dart';
import 'package:cw_core/crypto_currency.dart';
import 'package:cw_core/wallet_base.dart';
class OnRamperBuyProvider {
@ -13,7 +14,16 @@ class OnRamperBuyProvider {
static const _baseUrl = 'buy.onramper.com';
static String get _apiKey => secrets.onramperApiKey;
String get _apiKey => secrets.onramperApiKey;
String get _normalizeCryptoCurrency {
switch (_wallet.currency) {
case CryptoCurrency.ltc:
return "LTC_LITECOIN";
default:
return _wallet.currency.title;
}
}
Uri requestUrl() {
String primaryColor,
@ -53,7 +63,7 @@ class OnRamperBuyProvider {
return Uri.https(_baseUrl, '', <String, dynamic>{
'apiKey': _apiKey,
'defaultCrypto': _wallet.currency.title,
'defaultCrypto': _normalizeCryptoCurrency,
'defaultFiat': _settingsStore.fiatCurrency.title,
'wallets': '${_wallet.currency.title}:${_wallet.walletAddresses.address}',
'supportSell': "false",

View file

@ -169,6 +169,7 @@ Route<dynamic> createRoute(RouteSettings settings) {
fullscreenDialog: true);
} else if (isSingleCoin) {
return MaterialPageRoute<void>(
fullscreenDialog: true,
builder: (_) => getIt.get<WalletRestorePage>(
param1: availableWalletTypes.first
));
@ -188,6 +189,7 @@ Route<dynamic> createRoute(RouteSettings settings) {
case Routes.restoreWallet:
return MaterialPageRoute<void>(
fullscreenDialog: true,
builder: (_) => getIt.get<WalletRestorePage>(
param1: settings.arguments as WalletType));
@ -509,7 +511,9 @@ Route<dynamic> createRoute(RouteSettings settings) {
case Routes.anonPayInvoicePage:
final args = settings.arguments as List;
return CupertinoPageRoute<void>(builder: (_) => getIt.get<AnonPayInvoicePage>(param1: args));
return CupertinoPageRoute<void>(
fullscreenDialog: true,
builder: (_) => getIt.get<AnonPayInvoicePage>(param1: args));
case Routes.anonPayReceivePage:
final anonInvoiceViewData = settings.arguments as AnonpayInfoBase;

View file

@ -96,7 +96,10 @@ class AddressPage extends BasePage {
@override
Widget middle(BuildContext context) =>
PresentReceiveOptionPicker(receiveOptionViewModel: receiveOptionViewModel);
PresentReceiveOptionPicker(
receiveOptionViewModel: receiveOptionViewModel,
hasWhiteBackground: currentTheme.type == ThemeType.light,
);
@override
Widget Function(BuildContext, Widget) get rootWrapper =>

View file

@ -9,14 +9,22 @@ import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:cake_wallet/generated/i18n.dart';
class PresentReceiveOptionPicker extends StatelessWidget {
PresentReceiveOptionPicker({required this.receiveOptionViewModel});
PresentReceiveOptionPicker(
{required this.receiveOptionViewModel, this.hasWhiteBackground = false});
final ReceiveOptionViewModel receiveOptionViewModel;
final bool hasWhiteBackground;
@override
Widget build(BuildContext context) {
final arrowBottom =
Image.asset('assets/images/arrow_bottom_purple_icon.png', color: Colors.white, height: 6);
final textIconTheme = hasWhiteBackground
? Theme.of(context).accentTextTheme.headline2!.backgroundColor!
: Colors.white;
final arrowBottom = Image.asset(
'assets/images/arrow_bottom_purple_icon.png',
color: textIconTheme,
height: 6,
);
return TextButton(
onPressed: () => _showPicker(context),
@ -40,14 +48,14 @@ class PresentReceiveOptionPicker extends StatelessWidget {
fontSize: 18.0,
fontWeight: FontWeight.bold,
fontFamily: 'Lato',
color: Theme.of(context).accentTextTheme.headline2!.backgroundColor!),
color: textIconTheme),
),
Observer(
builder: (_) => Text(receiveOptionViewModel.selectedReceiveOption.toString(),
style: TextStyle(
fontSize: 10.0,
fontWeight: FontWeight.w500,
color: Theme.of(context).textTheme.headline5!.color!)))
color: textIconTheme)))
],
),
SizedBox(width: 5),

View file

@ -32,7 +32,7 @@ class AnonpayCurrencyInputField extends StatelessWidget {
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(
color: Theme.of(context).accentTextTheme.headline6!.backgroundColor!,
color: Theme.of(context).primaryTextTheme.bodyText1!.color!,
width: 1)),
),
child: Padding(

View file

@ -69,7 +69,7 @@ class AnonInvoiceForm extends StatelessWidget {
BaseTextFormField(
controller: nameController,
focusNode: _nameFocusNode,
borderColor: Theme.of(context).accentTextTheme.headline6!.backgroundColor,
borderColor: Theme.of(context).primaryTextTheme.bodyText1!.color!,
suffixIcon: SizedBox(width: 36),
hintText: S.of(context).optional_name,
textInputAction: TextInputAction.next,
@ -88,7 +88,7 @@ class AnonInvoiceForm extends StatelessWidget {
controller: descriptionController,
focusNode: _descriptionFocusNode,
textInputAction: TextInputAction.next,
borderColor: Theme.of(context).accentTextTheme.headline6!.backgroundColor,
borderColor: Theme.of(context).primaryTextTheme.bodyText1!.color!,
suffixIcon: SizedBox(width: 36),
hintText: S.of(context).optional_description,
placeholderTextStyle: TextStyle(
@ -104,7 +104,7 @@ class AnonInvoiceForm extends StatelessWidget {
controller: emailController,
textInputAction: TextInputAction.next,
focusNode: _emailFocusNode,
borderColor: Theme.of(context).accentTextTheme.headline6!.backgroundColor,
borderColor: Theme.of(context).primaryTextTheme.bodyText1!.color!,
suffixIcon: SizedBox(width: 36),
keyboardType: TextInputType.emailAddress,
hintText: S.of(context).optional_email_hint,

View file

@ -1,4 +1,3 @@
import 'package:cake_wallet/core/amount_validator.dart';
import 'package:cake_wallet/src/widgets/base_text_form_field.dart';
import 'package:cw_core/currency.dart';
import 'package:flutter/material.dart';
@ -10,18 +9,20 @@ class CurrencyInputField extends StatelessWidget {
required this.onTapPicker,
required this.selectedCurrency,
this.focusNode,
required this.controller,
required this.controller, required this.isLight,
});
final Function() onTapPicker;
final Currency selectedCurrency;
final FocusNode? focusNode;
final TextEditingController controller;
final bool isLight;
@override
Widget build(BuildContext context) {
final arrowBottomPurple = Image.asset(
'assets/images/arrow_bottom_purple_icon.png',
color: Colors.white,
color: Theme.of(context).accentTextTheme.headline2!.backgroundColor!,
height: 8,
);
final _width = MediaQuery.of(context).size.width;
@ -38,14 +39,14 @@ class CurrencyInputField extends StatelessWidget {
keyboardType: TextInputType.numberWithOptions(signed: false, decimal: true),
inputFormatters: [FilteringTextInputFormatter.allow(RegExp(r'^\d+(\.|\,)?\d{0,8}'))],
hintText: '0.000',
placeholderTextStyle: TextStyle(
placeholderTextStyle: isLight ? null : TextStyle(
color: Theme.of(context).primaryTextTheme.headline5!.color!,
fontWeight: FontWeight.w600,
),
borderColor: Theme.of(context).accentTextTheme.headline6!.backgroundColor!,
textColor: Colors.white,
textColor: Theme.of(context).accentTextTheme.headline2!.backgroundColor!,
textStyle: TextStyle(
color: Colors.white,
color: Theme.of(context).accentTextTheme.headline2!.backgroundColor!,
),
prefixIcon: Padding(
padding: EdgeInsets.only(
@ -68,7 +69,7 @@ class CurrencyInputField extends StatelessWidget {
style: TextStyle(
fontWeight: FontWeight.w600,
fontSize: 16,
color: Colors.white,
color: Theme.of(context).accentTextTheme.headline2!.backgroundColor!,
),
),
if (selectedCurrency.tag != null)
@ -103,7 +104,8 @@ class CurrencyInputField extends StatelessWidget {
style: TextStyle(
fontWeight: FontWeight.w600,
fontSize: 20,
color: Colors.white,
color:
Theme.of(context).accentTextTheme.headline2!.backgroundColor!,
),
),
),

View file

@ -23,7 +23,7 @@ class QrImage extends StatelessWidget {
size: size,
foregroundColor: Colors.black,
backgroundColor: Colors.white,
padding: EdgeInsets.zero,
padding: const EdgeInsets.all(8.0),
);
}
}

View file

@ -119,6 +119,7 @@ class QRWidget extends StatelessWidget {
controller: amountController,
onTapPicker: () => _presentPicker(context),
selectedCurrency: addressListViewModel.selectedCurrency,
isLight: isLight,
),
),
),

View file

@ -1,83 +0,0 @@
import 'package:flutter/services.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/src/widgets/blockchain_height_widget.dart';
import 'package:cake_wallet/src/widgets/base_text_form_field.dart';
class RestoreFromKeysFrom extends StatefulWidget {
@override
_RestoreFromKeysFromState createState() => _RestoreFromKeysFromState();
}
class _RestoreFromKeysFromState extends State<RestoreFromKeysFrom> {
final _formKey = GlobalKey<FormState>();
final _blockchainHeightKey = GlobalKey<BlockchainHeightState>();
final _nameController = TextEditingController();
final _addressController = TextEditingController();
final _viewKeyController = TextEditingController();
final _spendKeyController = TextEditingController();
final _wifController = TextEditingController();
@override
void initState() {
// _nameController.addListener(() =>
// widget.walletRestorationFromKeysVM.name = _nameController.text);
// _addressController.addListener(() =>
// widget.walletRestorationFromKeysVM.address = _addressController.text);
// _viewKeyController.addListener(() =>
// widget.walletRestorationFromKeysVM.viewKey = _viewKeyController.text);
// _spendKeyController.addListener(() =>
// widget.walletRestorationFromKeysVM.spendKey = _spendKeyController.text);
// _wifController.addListener(() =>
// widget.walletRestorationFromKeysVM.wif = _wifController.text);
super.initState();
}
@override
void dispose() {
_nameController.dispose();
_addressController.dispose();
_viewKeyController.dispose();
_spendKeyController.dispose();
_wifController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.only(left: 24, right: 24),
child: Form(
key: _formKey,
child: Column(children: <Widget>[
BaseTextFormField(
controller: _addressController,
keyboardType: TextInputType.multiline,
maxLines: null,
hintText: S.of(context).restore_address,
),
Container(
padding: EdgeInsets.only(top: 20.0),
child: BaseTextFormField(
controller: _viewKeyController,
hintText: S.of(context).restore_view_key_private,
)),
Container(
padding: EdgeInsets.only(top: 20.0),
child: BaseTextFormField(
controller: _spendKeyController,
hintText: S.of(context).restore_spend_key_private,
)),
BlockchainHeightWidget(
key: _blockchainHeightKey,
onHeightChange: (height) {
// widget.walletRestorationFromKeysVM.height = height;
print(height);
}),
]),
),
);
}
}

View file

@ -8,6 +8,7 @@ import 'package:cake_wallet/src/screens/settings/widgets/settings_cell_with_arro
import 'package:cake_wallet/src/screens/settings/widgets/settings_picker_cell.dart';
import 'package:cake_wallet/src/screens/settings/widgets/settings_switcher_cell.dart';
import 'package:cake_wallet/src/widgets/standard_list.dart';
import 'package:cake_wallet/utils/device_info.dart';
import 'package:cake_wallet/view_model/settings/security_settings_view_model.dart';
import 'package:flutter/material.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
@ -48,29 +49,30 @@ class SecurityBackupPage extends BasePage {
),
),
StandardListSeparator(padding: EdgeInsets.symmetric(horizontal: 24)),
Observer(builder: (_) {
return SettingsSwitcherCell(
title: S.current.settings_allow_biometrical_authentication,
value: _securitySettingsViewModel.allowBiometricalAuthentication,
onValueChange: (BuildContext context, bool value) {
if (value) {
_authService.authenticateAction(context,
onAuthSuccess: (isAuthenticatedSuccessfully) async {
if (isAuthenticatedSuccessfully) {
if (await _securitySettingsViewModel.biometricAuthenticated()) {
if (DeviceInfo.instance.isMobile)
Observer(builder: (_) {
return SettingsSwitcherCell(
title: S.current.settings_allow_biometrical_authentication,
value: _securitySettingsViewModel.allowBiometricalAuthentication,
onValueChange: (BuildContext context, bool value) {
if (value) {
_authService.authenticateAction(context,
onAuthSuccess: (isAuthenticatedSuccessfully) async {
if (isAuthenticatedSuccessfully) {
if (await _securitySettingsViewModel.biometricAuthenticated()) {
_securitySettingsViewModel
.setAllowBiometricalAuthentication(isAuthenticatedSuccessfully);
}
} else {
_securitySettingsViewModel
.setAllowBiometricalAuthentication(isAuthenticatedSuccessfully);
}
} else {
_securitySettingsViewModel
.setAllowBiometricalAuthentication(isAuthenticatedSuccessfully);
}
});
} else {
_securitySettingsViewModel.setAllowBiometricalAuthentication(value);
}
});
}),
});
} else {
_securitySettingsViewModel.setAllowBiometricalAuthentication(value);
}
});
}),
Observer(builder: (_) {
return SettingsPickerCell<PinCodeRequiredDuration>(
title: S.current.require_pin_after,

View file

@ -141,9 +141,9 @@ class ExceptionHandler {
"errno = 103", // SocketException: Software caused connection abort
"errno = 104", // SocketException: Connection reset by peer
"errno = 110", // SocketException: Connection timed out
"HttpException: Connection reset by peer",
"HttpException: Connection closed before full header was received",
"HandshakeException: Connection terminated during handshake",
"Connection reset by peer",
"Connection closed before full header was received",
"Connection terminated during handshake",
"PERMISSION_NOT_GRANTED",
];
@ -172,7 +172,7 @@ class ExceptionHandler {
}
await file.writeAsString(
"App Version: $currentVersion\n\nDevice Info $deviceInfo",
"App Version: $currentVersion\n\nDevice Info $deviceInfo\n\n",
mode: FileMode.append,
);
}
@ -193,6 +193,7 @@ class ExceptionHandler {
'systemVersion': data.systemVersion,
'model': data.model,
'localizedModel': data.localizedModel,
'isPhysicalDevice': data.isPhysicalDevice,
};
}

View file

@ -123,8 +123,8 @@ abstract class ExchangeTradeViewModelBase with Store {
}
void _updateItems() {
final tagFrom = trade.from.tag != null ? '${trade.from.tag}' + ' ' : '';
final tagTo = trade.to.tag != null ? '${trade.to.tag}' + ' ' : '';
final tagFrom = tradesStore.trade!.from.tag != null ? '${tradesStore.trade!.from.tag}' + ' ' : '';
final tagTo = tradesStore.trade!.to.tag != null ? '${tradesStore.trade!.to.tag}' + ' ' : '';
items.clear();
items.add(ExchangeTradeItem(
title: "${trade.provider.title} ${S.current.id}", data: '${trade.id}', isCopied: true));
@ -142,11 +142,11 @@ abstract class ExchangeTradeViewModelBase with Store {
items.addAll([
ExchangeTradeItem(title: S.current.amount, data: '${trade.amount}', isCopied: true),
ExchangeTradeItem(
title: S.current.send_to_this_address('${trade.from}', tagFrom) + ':',
title: S.current.send_to_this_address('${tradesStore.trade!.from}', tagFrom) + ':',
data: trade.inputAddress ?? '',
isCopied: true),
ExchangeTradeItem(
title: S.current.arrive_in_this_address('${trade.to}', tagTo) + ':',
title: S.current.arrive_in_this_address('${tradesStore.trade!.to}', tagTo) + ':',
data: trade.payoutAddress ?? '',
isCopied: true),
]);

View file

@ -3,7 +3,6 @@ import 'dart:collection';
import 'dart:convert';
import 'package:cake_wallet/entities/exchange_api_mode.dart';
import 'package:cake_wallet/entities/fiat_api_mode.dart';
import 'package:cake_wallet/entities/preferences_key.dart';
import 'package:cake_wallet/exchange/sideshift/sideshift_exchange_provider.dart';
import 'package:cake_wallet/exchange/sideshift/sideshift_request.dart';
@ -244,7 +243,7 @@ abstract class ExchangeViewModelBase with Store {
List<CryptoCurrency> depositCurrencies;
NumberFormat _cryptoNumberFormat;
final NumberFormat _cryptoNumberFormat;
final SettingsStore _settingsStore;
@ -388,27 +387,36 @@ abstract class ExchangeViewModelBase with Store {
double? lowestMin = double.maxFinite;
double? highestMax = 0.0;
for (var provider in selectedProviders) {
/// if this provider is not valid for the current pair, skip it
if (!providersForCurrentPair().contains(provider)) {
continue;
}
try {
final tempLimits = await provider.fetchLimits(
from: from,
to: to,
isFixedRateMode: isFixedRateMode);
if (lowestMin != null && (tempLimits.min ?? -1) < lowestMin) {
lowestMin = tempLimits.min;
try {
for (var provider in selectedProviders) {
/// if this provider is not valid for the current pair, skip it
if (!providersForCurrentPair().contains(provider)) {
continue;
}
if (highestMax != null && (tempLimits.max ?? double.maxFinite) > highestMax) {
highestMax = tempLimits.max;
try {
final tempLimits = await provider.fetchLimits(
from: from,
to: to,
isFixedRateMode: isFixedRateMode);
if (lowestMin != null && (tempLimits.min ?? -1) < lowestMin) {
lowestMin = tempLimits.min;
}
if (highestMax != null && (tempLimits.max ?? double.maxFinite) > highestMax) {
highestMax = tempLimits.max;
}
} catch (e) {
continue;
}
} catch (e) {
continue;
}
} on ConcurrentModificationError {
/// if user changed the selected providers while fetching limits
/// then delay the fetching limits a bit and try again
///
/// this is because the limitation of collections that
/// you can't modify it while iterating through it
Future.delayed(Duration(milliseconds: 200), loadLimits);
}
if (lowestMin != double.maxFinite) {
@ -534,7 +542,7 @@ abstract class ExchangeViewModelBase with Store {
///
/// this is because the limitation of the SplayTreeMap that
/// you can't modify it while iterating through it
Future.delayed(Duration(milliseconds: 500), createTrade);
Future.delayed(Duration(milliseconds: 200), createTrade);
}
}

View file

@ -17,8 +17,8 @@ dependencies:
git:
url: https://github.com/cake-tech/flutter_secure_storage.git
path: flutter_secure_storage
ref: cake-6.0.0
version: 6.0.0
ref: cake-8.0.0
version: 8.0.0
# provider: ^6.0.3
rxdart: ^0.27.4
yaml: ^3.1.1