mirror of
https://github.com/cake-tech/cake_wallet.git
synced 2024-12-22 19:49:22 +00:00
Cw 262 better handle user exchange amount below minimum or maximum trade size (#868)
* CW-262-Better-handle-user-exchange-amount-below-minimum-or-maximum-trade-size * fix: App should compute conversion even if it's not within the limits
This commit is contained in:
parent
efef30f8eb
commit
7b91b0e938
26 changed files with 185 additions and 12 deletions
|
@ -3,17 +3,45 @@ import 'package:cake_wallet/generated/i18n.dart';
|
|||
import 'package:cw_core/crypto_currency.dart';
|
||||
|
||||
class AmountValidator extends TextValidator {
|
||||
AmountValidator({required CryptoCurrency currency, bool isAutovalidate = false}) {
|
||||
AmountValidator({
|
||||
required CryptoCurrency currency,
|
||||
bool isAutovalidate = false,
|
||||
String? minValue,
|
||||
String? maxValue,
|
||||
}) {
|
||||
symbolsAmountValidator =
|
||||
SymbolsAmountValidator(isAutovalidate: isAutovalidate);
|
||||
decimalAmountValidator = DecimalAmountValidator(currency: currency,isAutovalidate: isAutovalidate);
|
||||
|
||||
amountMinValidator = AmountMinValidator(
|
||||
minValue: minValue,
|
||||
isAutovalidate: isAutovalidate,
|
||||
);
|
||||
|
||||
amountMaxValidator = AmountMaxValidator(
|
||||
maxValue: maxValue,
|
||||
isAutovalidate: isAutovalidate,
|
||||
);
|
||||
}
|
||||
|
||||
late final AmountMinValidator amountMinValidator;
|
||||
|
||||
late final AmountMaxValidator amountMaxValidator;
|
||||
|
||||
late final SymbolsAmountValidator symbolsAmountValidator;
|
||||
|
||||
late final DecimalAmountValidator decimalAmountValidator;
|
||||
|
||||
String? call(String? value) => symbolsAmountValidator(value) ?? decimalAmountValidator(value);
|
||||
String? call(String? value) {
|
||||
//* Validate for Text(length, symbols, decimals etc)
|
||||
|
||||
final textValidation = symbolsAmountValidator(value) ?? decimalAmountValidator(value);
|
||||
|
||||
//* Validate for Comparison(Value greater than min and less than )
|
||||
final comparisonValidation = amountMinValidator(value) ?? amountMaxValidator(value);
|
||||
|
||||
return textValidation ?? comparisonValidation;
|
||||
}
|
||||
}
|
||||
|
||||
class SymbolsAmountValidator extends TextValidator {
|
||||
|
@ -57,3 +85,71 @@ class AllAmountValidator extends TextValidator {
|
|||
minLength: 0,
|
||||
maxLength: 0);
|
||||
}
|
||||
|
||||
class AmountMinValidator extends Validator<String> {
|
||||
final String? minValue;
|
||||
final bool isAutovalidate;
|
||||
|
||||
AmountMinValidator({
|
||||
this.minValue,
|
||||
required this.isAutovalidate,
|
||||
}) : super(errorMessage: S.current.error_text_input_below_minimum_limit);
|
||||
|
||||
@override
|
||||
bool isValid(String? value) {
|
||||
if (value == null || value.isEmpty) {
|
||||
return isAutovalidate ? true : false;
|
||||
}
|
||||
|
||||
if (minValue == null || minValue == "null") {
|
||||
return true;
|
||||
}
|
||||
|
||||
final valueInDouble = parseToDouble(value);
|
||||
final minInDouble = parseToDouble(minValue ?? '');
|
||||
|
||||
if (valueInDouble == null || minInDouble == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return valueInDouble > minInDouble;
|
||||
}
|
||||
|
||||
double? parseToDouble(String value) {
|
||||
final data = double.tryParse(value.replaceAll(',', '.'));
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
class AmountMaxValidator extends Validator<String> {
|
||||
final String? maxValue;
|
||||
final bool isAutovalidate;
|
||||
|
||||
AmountMaxValidator({
|
||||
this.maxValue,
|
||||
required this.isAutovalidate,
|
||||
}) : super(errorMessage: S.current.error_text_input_above_maximum_limit);
|
||||
|
||||
@override
|
||||
bool isValid(String? value) {
|
||||
if (value == null || value.isEmpty) {
|
||||
return isAutovalidate ? true : false;
|
||||
}
|
||||
|
||||
if (maxValue == null || maxValue == "null") {
|
||||
return true;
|
||||
}
|
||||
|
||||
final valueInDouble = parseToDouble(value);
|
||||
final maxInDouble = parseToDouble(maxValue ?? '');
|
||||
|
||||
if (valueInDouble == null || maxInDouble == null) {
|
||||
return false;
|
||||
}
|
||||
return valueInDouble < maxInDouble;
|
||||
}
|
||||
|
||||
double? parseToDouble(String value) {
|
||||
return double.tryParse(value.replaceAll(',', '.'));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -456,8 +456,7 @@ class ExchangePage extends BasePage {
|
|||
depositAmountController.addListener(() {
|
||||
if (depositAmountController.text != exchangeViewModel.depositAmount) {
|
||||
_depositAmountDebounce.run(() {
|
||||
exchangeViewModel.changeDepositAmount(
|
||||
amount: depositAmountController.text);
|
||||
exchangeViewModel.changeDepositAmount(amount: depositAmountController.text);
|
||||
exchangeViewModel.isReceiveAmountEntered = false;
|
||||
});
|
||||
}
|
||||
|
@ -469,8 +468,7 @@ class ExchangePage extends BasePage {
|
|||
receiveAmountController.addListener(() {
|
||||
if (receiveAmountController.text != exchangeViewModel.receiveAmount) {
|
||||
_receiveAmountDebounce.run(() {
|
||||
exchangeViewModel.changeReceiveAmount(
|
||||
amount: receiveAmountController.text);
|
||||
exchangeViewModel.changeReceiveAmount(amount: receiveAmountController.text);
|
||||
exchangeViewModel.isReceiveAmountEntered = true;
|
||||
});
|
||||
}
|
||||
|
@ -626,8 +624,16 @@ class ExchangePage extends BasePage {
|
|||
currencyButtonColor: Colors.transparent,
|
||||
addressButtonsColor: Theme.of(context).focusColor!,
|
||||
borderColor: Theme.of(context).primaryTextTheme!.bodyText1!.color!,
|
||||
currencyValueValidator:
|
||||
AmountValidator(currency: exchangeViewModel.depositCurrency),
|
||||
currencyValueValidator: (value) {
|
||||
return !exchangeViewModel.isFixedRateMode
|
||||
? AmountValidator(
|
||||
isAutovalidate: true,
|
||||
currency: exchangeViewModel.depositCurrency,
|
||||
minValue: exchangeViewModel.limits.min.toString(),
|
||||
maxValue: exchangeViewModel.limits.max.toString(),
|
||||
).call(value)
|
||||
: null;
|
||||
},
|
||||
addressTextFieldValidator:
|
||||
AddressValidator(type: exchangeViewModel.depositCurrency),
|
||||
onPushPasteButton: (context) async {
|
||||
|
@ -668,8 +674,16 @@ class ExchangePage extends BasePage {
|
|||
addressButtonsColor: Theme.of(context).focusColor!,
|
||||
borderColor:
|
||||
Theme.of(context).primaryTextTheme!.bodyText1!.decorationColor!,
|
||||
currencyValueValidator:
|
||||
AmountValidator(currency: exchangeViewModel.receiveCurrency),
|
||||
currencyValueValidator: (value) {
|
||||
return exchangeViewModel.isFixedRateMode
|
||||
? AmountValidator(
|
||||
isAutovalidate: true,
|
||||
currency: exchangeViewModel.receiveCurrency,
|
||||
minValue: exchangeViewModel.limits.min.toString(),
|
||||
maxValue: exchangeViewModel.limits.max.toString(),
|
||||
).call(value)
|
||||
: null;
|
||||
},
|
||||
addressTextFieldValidator:
|
||||
AddressValidator(type: exchangeViewModel.receiveCurrency),
|
||||
onPushPasteButton: (context) async {
|
||||
|
|
|
@ -198,6 +198,9 @@ abstract class ExchangeViewModelBase with Store {
|
|||
@observable
|
||||
bool isFixedRateMode;
|
||||
|
||||
@observable
|
||||
Limits limits;
|
||||
|
||||
@computed
|
||||
SyncStatus get status => wallet.syncStatus;
|
||||
|
||||
|
@ -241,8 +244,6 @@ abstract class ExchangeViewModelBase with Store {
|
|||
|
||||
List<CryptoCurrency> depositCurrencies;
|
||||
|
||||
Limits limits;
|
||||
|
||||
NumberFormat _cryptoNumberFormat;
|
||||
|
||||
final SettingsStore _settingsStore;
|
||||
|
@ -320,6 +321,22 @@ abstract class ExchangeViewModelBase with Store {
|
|||
.replaceAll(RegExp('\\,'), '');
|
||||
}
|
||||
|
||||
bool checkIfInputMeetsMinOrMaxCondition(String input) {
|
||||
final _enteredAmount = double.tryParse(input.replaceAll(',', '.')) ?? 0;
|
||||
double minLimit = limits.min ?? 0;
|
||||
double? maxLimit = limits.max;
|
||||
|
||||
if (_enteredAmount < minLimit) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (maxLimit != null && _enteredAmount > maxLimit) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Future<void> _calculateBestRate() async {
|
||||
final amount = double.tryParse(isFixedRateMode ? receiveAmount : depositAmount) ?? 1;
|
||||
|
||||
|
|
|
@ -697,5 +697,7 @@
|
|||
"onion_link": "رابط البصل",
|
||||
"settings": "إعدادات",
|
||||
"sell_monero_com_alert_content": "بيع Monero غير مدعوم حتى الآن",
|
||||
"error_text_input_below_minimum_limit":" المبلغ أقل من الحد الأدنى",
|
||||
"error_text_input_above_maximum_limit":"المبلغ أكبر من الحد الأقصى",
|
||||
"show_market_place": "إظهار السوق"
|
||||
}
|
||||
|
|
|
@ -698,5 +698,7 @@
|
|||
"clearnet_link": "Clearnet връзка",
|
||||
"onion_link": "Лукова връзка",
|
||||
"sell_monero_com_alert_content": "Продажбата на Monero все още не се поддържа",
|
||||
"error_text_input_below_minimum_limit" : "Сумата е по-малко от минималната",
|
||||
"error_text_input_above_maximum_limit" : "Сумата надвишава максималната",
|
||||
"show_market_place":"Покажи пазар"
|
||||
}
|
||||
|
|
|
@ -698,5 +698,7 @@
|
|||
"clearnet_link": "Odkaz na Clearnet",
|
||||
"onion_link": "Cibulový odkaz",
|
||||
"sell_monero_com_alert_content": "Prodej Monero zatím není podporován",
|
||||
"error_text_input_below_minimum_limit" : "Částka je menší než minimální hodnota",
|
||||
"error_text_input_above_maximum_limit" : "Částka je větší než maximální hodnota",
|
||||
"show_market_place": "Zobrazit trh"
|
||||
}
|
||||
|
|
|
@ -699,5 +699,7 @@
|
|||
"onion_link": "Zwiebel-Link",
|
||||
"settings": "Einstellungen",
|
||||
"sell_monero_com_alert_content": "Der Verkauf von Monero wird noch nicht unterstützt",
|
||||
"error_text_input_below_minimum_limit" : "Menge ist unter dem Minimum",
|
||||
"error_text_input_above_maximum_limit" : "Menge ist über dem Maximum",
|
||||
"show_market_place": "Marktplatz anzeigen"
|
||||
}
|
||||
|
|
|
@ -699,5 +699,7 @@
|
|||
"edit_node": "Edit Node",
|
||||
"settings": "Settings",
|
||||
"sell_monero_com_alert_content": "Selling Monero is not supported yet",
|
||||
"error_text_input_below_minimum_limit" : "Amount is less than the minimum",
|
||||
"error_text_input_above_maximum_limit" : "Amount is more than the maximum",
|
||||
"show_market_place" :"Show Marketplace"
|
||||
}
|
||||
|
|
|
@ -699,5 +699,7 @@
|
|||
"onion_link": "Enlace de cebolla",
|
||||
"settings": "Configuraciones",
|
||||
"sell_monero_com_alert_content": "Aún no se admite la venta de Monero",
|
||||
"error_text_input_below_minimum_limit" : "La cantidad es menos que mínima",
|
||||
"error_text_input_above_maximum_limit" : "La cantidad es más que el máximo",
|
||||
"show_market_place": "Mostrar mercado"
|
||||
}
|
||||
|
|
|
@ -699,5 +699,7 @@
|
|||
"settings": "Paramètres",
|
||||
"onion_link": "Lien .onion",
|
||||
"sell_monero_com_alert_content": "La vente de Monero n'est pas encore prise en charge",
|
||||
"error_text_input_below_minimum_limit" : "Le montant est inférieur au minimum",
|
||||
"error_text_input_above_maximum_limit" : "Le montant est supérieur au maximum",
|
||||
"show_market_place" :"Afficher la place de marché"
|
||||
}
|
||||
|
|
|
@ -699,5 +699,7 @@
|
|||
"onion_link": "प्याज का लिंक",
|
||||
"settings": "समायोजन",
|
||||
"sell_monero_com_alert_content": "मोनेरो बेचना अभी तक समर्थित नहीं है",
|
||||
"error_text_input_below_minimum_limit" : "राशि न्यूनतम से कम है",
|
||||
"error_text_input_above_maximum_limit" : "राशि अधिकतम से अधिक है",
|
||||
"show_market_place":"बाज़ार दिखाएँ"
|
||||
}
|
||||
|
|
|
@ -699,5 +699,7 @@
|
|||
"onion_link": "Poveznica luka",
|
||||
"settings": "Postavke",
|
||||
"sell_monero_com_alert_content": "Prodaja Monera još nije podržana",
|
||||
"error_text_input_below_minimum_limit" : "Iznos je manji od minimalnog",
|
||||
"error_text_input_above_maximum_limit" : "Iznos je veći od maskimalnog",
|
||||
"show_market_place" : "Prikaži tržište"
|
||||
}
|
||||
|
|
|
@ -680,5 +680,7 @@
|
|||
"clearnet_link": "Tautan clearnet",
|
||||
"onion_link": "Tautan bawang",
|
||||
"sell_monero_com_alert_content": "Menjual Monero belum didukung",
|
||||
"error_text_input_below_minimum_limit" : "Jumlah kurang dari minimal",
|
||||
"error_text_input_above_maximum_limit" : "Jumlah lebih dari maksimal",
|
||||
"show_market_place": "Tampilkan Pasar"
|
||||
}
|
||||
|
|
|
@ -699,5 +699,7 @@
|
|||
"onion_link": "Collegamento a cipolla",
|
||||
"settings": "Impostazioni",
|
||||
"sell_monero_com_alert_content": "La vendita di Monero non è ancora supportata",
|
||||
"error_text_input_below_minimum_limit" : "L'ammontare è inferiore al minimo",
|
||||
"error_text_input_above_maximum_limit" : "L'ammontare è superiore al massimo",
|
||||
"show_market_place":"Mostra mercato"
|
||||
}
|
||||
|
|
|
@ -699,5 +699,7 @@
|
|||
"onion_link": "オニオンリンク",
|
||||
"settings": "設定",
|
||||
"sell_monero_com_alert_content": "モネロの販売はまだサポートされていません",
|
||||
"error_text_input_below_minimum_limit" : "金額は最小額より少ない",
|
||||
"error_text_input_above_maximum_limit" : "金額は最大値を超えています",
|
||||
"show_market_place":"マーケットプレイスを表示"
|
||||
}
|
||||
|
|
|
@ -699,5 +699,7 @@
|
|||
"onion_link": "양파 링크",
|
||||
"settings": "설정",
|
||||
"sell_monero_com_alert_content": "지원되지 않습니다.",
|
||||
"error_text_input_below_minimum_limit" : "금액이 최소보다 적습니다.",
|
||||
"error_text_input_above_maximum_limit" : "금액이 최대 값보다 많습니다.",
|
||||
"show_market_place":"마켓플레이스 표시"
|
||||
}
|
||||
|
|
|
@ -699,5 +699,7 @@
|
|||
"onion_link": "ကြက်သွန်လင့်",
|
||||
"settings": "ဆက်တင်များ",
|
||||
"sell_monero_com_alert_content": "Monero ရောင်းချခြင်းကို မပံ့ပိုးရသေးပါ။",
|
||||
"error_text_input_below_minimum_limit" : "ပမာဏသည် အနိမ့်ဆုံးထက်နည်းသည်။",
|
||||
"error_text_input_above_maximum_limit" : "ပမာဏသည် အများဆုံးထက် ပိုများသည်။",
|
||||
"show_market_place":"စျေးကွက်ကိုပြသပါ။"
|
||||
}
|
||||
|
|
|
@ -699,5 +699,7 @@
|
|||
"onion_link": "Ui koppeling",
|
||||
"settings": "Instellingen",
|
||||
"sell_monero_com_alert_content": "Het verkopen van Monero wordt nog niet ondersteund",
|
||||
"error_text_input_below_minimum_limit" : "Bedrag is minder dan minimaal",
|
||||
"error_text_input_above_maximum_limit" : "Bedrag is meer dan maximaal",
|
||||
"show_market_place":"Toon Marktplaats"
|
||||
}
|
||||
|
|
|
@ -699,5 +699,7 @@
|
|||
"onion_link": "Łącznik cebulowy",
|
||||
"settings": "Ustawienia",
|
||||
"sell_monero_com_alert_content": "Sprzedaż Monero nie jest jeszcze obsługiwana",
|
||||
"error_text_input_below_minimum_limit" : "Kwota jest mniejsza niż minimalna",
|
||||
"error_text_input_above_maximum_limit" : "Kwota jest większa niż maksymalna",
|
||||
"show_market_place" : "Pokaż rynek"
|
||||
}
|
||||
|
|
|
@ -698,5 +698,7 @@
|
|||
"onion_link": "ligação de cebola",
|
||||
"settings": "Configurações",
|
||||
"sell_monero_com_alert_content": "A venda de Monero ainda não é suportada",
|
||||
"error_text_input_below_minimum_limit" : "O valor é menor que o mínimo",
|
||||
"error_text_input_above_maximum_limit" : "O valor é superior ao máximo",
|
||||
"show_market_place":"Mostrar mercado"
|
||||
}
|
||||
|
|
|
@ -699,5 +699,7 @@
|
|||
"onion_link": "Луковая ссылка",
|
||||
"settings": "Настройки",
|
||||
"sell_monero_com_alert_content": "Продажа Monero пока не поддерживается",
|
||||
"error_text_input_below_minimum_limit" : "Сумма меньше минимальной",
|
||||
"error_text_input_above_maximum_limit" : "Сумма больше максимальной",
|
||||
"show_market_place":"Показать торговую площадку"
|
||||
}
|
||||
|
|
|
@ -697,5 +697,7 @@
|
|||
"onion_link": "ลิงค์หัวหอม",
|
||||
"settings": "การตั้งค่า",
|
||||
"sell_monero_com_alert_content": "ยังไม่รองรับการขาย Monero",
|
||||
"error_text_input_below_minimum_limit" : "จำนวนเงินน้อยกว่าขั้นต่ำ",
|
||||
"error_text_input_above_maximum_limit" : "จำนวนเงินสูงกว่าค่าสูงสุด",
|
||||
"show_market_place":"แสดงตลาดกลาง"
|
||||
}
|
||||
|
|
|
@ -699,5 +699,7 @@
|
|||
"onion_link": "soğan bağlantısı",
|
||||
"settings": "ayarlar",
|
||||
"sell_monero_com_alert_content": "Monero satışı henüz desteklenmiyor",
|
||||
"error_text_input_below_minimum_limit" : "Miktar minimumdan daha azdır",
|
||||
"error_text_input_above_maximum_limit" : "Miktar maksimumdan daha fazla",
|
||||
"show_market_place":"Pazar Yerini Göster"
|
||||
}
|
||||
|
|
|
@ -698,5 +698,7 @@
|
|||
"onion_link": "Посилання на цибулю",
|
||||
"settings": "Налаштування",
|
||||
"sell_monero_com_alert_content": "Продаж Monero ще не підтримується",
|
||||
"error_text_input_below_minimum_limit" : "Сума менша мінімальної",
|
||||
"error_text_input_above_maximum_limit" : "Сума більше максимальної",
|
||||
"show_market_place":"Шоу Ринок"
|
||||
}
|
||||
|
|
|
@ -699,5 +699,7 @@
|
|||
"clearnet_link": "کلیرنیٹ لنک",
|
||||
"onion_link": "پیاز کا لنک",
|
||||
"sell_monero_com_alert_content": "Monero فروخت کرنا ابھی تک تعاون یافتہ نہیں ہے۔",
|
||||
"error_text_input_below_minimum_limit" : "رقم کم از کم سے کم ہے۔",
|
||||
"error_text_input_above_maximum_limit" : "رقم زیادہ سے زیادہ سے زیادہ ہے۔",
|
||||
"show_market_place":"بازار دکھائیں۔"
|
||||
}
|
||||
|
|
|
@ -698,5 +698,7 @@
|
|||
"onion_link": "洋葱链接",
|
||||
"settings": "设置",
|
||||
"sell_monero_com_alert_content": "尚不支持出售门罗币",
|
||||
"error_text_input_below_minimum_limit" : "金额小于最小值",
|
||||
"error_text_input_above_maximum_limit" : "金额大于最大值",
|
||||
"show_market_place" :"显示市场"
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue