mirror of
https://github.com/cake-tech/cake_wallet.git
synced 2024-12-22 19:49:22 +00:00
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:
parent
e28e2fbdde
commit
1a3d47748d
16 changed files with 113 additions and 157 deletions
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 =>
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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!,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
|
|
@ -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),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -119,6 +119,7 @@ class QRWidget extends StatelessWidget {
|
|||
controller: amountController,
|
||||
onTapPicker: () => _presentPicker(context),
|
||||
selectedCurrency: addressListViewModel.selectedCurrency,
|
||||
isLight: isLight,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
|
|
@ -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);
|
||||
}),
|
||||
]),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -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,6 +49,7 @@ class SecurityBackupPage extends BasePage {
|
|||
),
|
||||
),
|
||||
StandardListSeparator(padding: EdgeInsets.symmetric(horizontal: 24)),
|
||||
if (DeviceInfo.instance.isMobile)
|
||||
Observer(builder: (_) {
|
||||
return SettingsSwitcherCell(
|
||||
title: S.current.settings_allow_biometrical_authentication,
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -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),
|
||||
]);
|
||||
|
|
|
@ -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,6 +387,7 @@ abstract class ExchangeViewModelBase with Store {
|
|||
double? lowestMin = double.maxFinite;
|
||||
double? highestMax = 0.0;
|
||||
|
||||
try {
|
||||
for (var provider in selectedProviders) {
|
||||
/// if this provider is not valid for the current pair, skip it
|
||||
if (!providersForCurrentPair().contains(provider)) {
|
||||
|
@ -410,6 +410,14 @@ abstract class ExchangeViewModelBase with Store {
|
|||
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) {
|
||||
limits = Limits(min: lowestMin, max: highestMax);
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue