Merge branch 'main' into CAKE-284-add-support-to-the-main-menu

# Conflicts:
#	lib/view_model/settings/settings_view_model.dart
This commit is contained in:
OleksandrSobol
2021-03-01 19:51:08 +02:00
25 changed files with 594 additions and 221 deletions
+3 -2
View File
@@ -15,7 +15,8 @@ class AddressValidator extends TextValidator {
case CryptoCurrency.xmr:
return '[0-9a-zA-Z]';
case CryptoCurrency.ada:
return '[0-9a-zA-Z]';
return '^[0-9a-zA-Z]{59}\$|^[0-9a-zA-Z]{92}\$|^[0-9a-zA-Z]{104}\$'
'|^[0-9a-zA-Z]{105}\$|^addr1[0-9a-zA-Z]{98}\$';
case CryptoCurrency.bch:
return '[0-9a-zA-Z]';
case CryptoCurrency.bnb:
@@ -54,7 +55,7 @@ class AddressValidator extends TextValidator {
case CryptoCurrency.xmr:
return [95, 106];
case CryptoCurrency.ada:
return [59, 92, 104, 105];
return null;
case CryptoCurrency.bch:
return [42];
case CryptoCurrency.bnb:
@@ -29,6 +29,8 @@ class ChangeNowExchangeProvider extends ExchangeProvider {
static const _exchangeAmountUriSufix = '/exchange-amount/';
static const _transactionsUriSufix = '/transactions/';
static const _minAmountUriSufix = '/min-amount/';
static const _marketInfoUriSufix = '/market-info/';
static const _fixedRateUriSufix = 'fixed-rate/';
@override
String get title => 'ChangeNOW';
@@ -44,19 +46,43 @@ class ChangeNowExchangeProvider extends ExchangeProvider {
Future<bool> checkIsAvailable() async => true;
@override
Future<Limits> fetchLimits({CryptoCurrency from, CryptoCurrency to}) async {
Future<Limits> fetchLimits({CryptoCurrency from, CryptoCurrency to,
bool isFixedRateMode}) async {
final symbol = from.toString() + '_' + to.toString();
final url = apiUri + _minAmountUriSufix + symbol;
final url = isFixedRateMode
? apiUri + _marketInfoUriSufix + _fixedRateUriSufix + apiKey
: apiUri + _minAmountUriSufix + symbol;
final response = await get(url);
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
final min = responseJSON['minAmount'] as double;
return Limits(min: min, max: null);
if (isFixedRateMode) {
final responseJSON = json.decode(response.body) as List<dynamic>;
for (var elem in responseJSON) {
final elemFrom = elem["from"] as String;
final elemTo = elem["to"] as String;
if ((elemFrom == from.toString().toLowerCase()) &&
(elemTo == to.toString().toLowerCase())) {
final min = elem["min"] as double;
final max = elem["max"] as double;
return Limits(min: min, max: max);
}
}
return Limits(min: 0, max: 0);
} else {
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
final min = responseJSON['minAmount'] as double;
return Limits(min: min, max: null);
}
}
@override
Future<Trade> createTrade({TradeRequest request}) async {
const url = apiUri + _transactionsUriSufix + apiKey;
Future<Trade> createTrade({TradeRequest request, bool isFixedRateMode}) async {
final url = isFixedRateMode
? apiUri + _transactionsUriSufix + _fixedRateUriSufix + apiKey
: apiUri + _transactionsUriSufix + apiKey;
final _request = request as ChangeNowRequest;
final body = {
'from': _request.from.toString(),
@@ -127,17 +153,35 @@ class ChangeNowExchangeProvider extends ExchangeProvider {
final state = TradeState.deserialize(raw: status);
final extraId = responseJSON['payinExtraId'] as String;
final outputTransaction = responseJSON['payoutHash'] as String;
final expiredAtRaw = responseJSON['validUntil'] as String;
final expiredAt = expiredAtRaw != null
? DateTime.parse(expiredAtRaw).toLocal()
: null;
return Trade(
id: id,
from: from,
to: to,
provider: description,
inputAddress: inputAddress,
amount: expectedSendAmount,
state: state,
extraId: extraId,
outputTransaction: outputTransaction);
if (expiredAt != null) {
return Trade(
id: id,
from: from,
to: to,
provider: description,
inputAddress: inputAddress,
amount: expectedSendAmount,
state: state,
extraId: extraId,
expiredAt: expiredAt,
outputTransaction: outputTransaction);
} else {
return Trade(
id: id,
from: from,
to: to,
provider: description,
inputAddress: inputAddress,
amount: expectedSendAmount,
state: state,
extraId: extraId,
outputTransaction: outputTransaction);
}
}
@override
@@ -145,18 +189,54 @@ class ChangeNowExchangeProvider extends ExchangeProvider {
{CryptoCurrency from,
CryptoCurrency to,
double amount,
bool isFixedRateMode,
bool isReceiveAmount}) async {
final url = apiUri +
_exchangeAmountUriSufix +
amount.toString() +
'/' +
from.toString() +
'_' +
to.toString();
final response = await get(url);
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
final estimatedAmount = responseJSON['estimatedAmount'] as double;
if (isReceiveAmount && isFixedRateMode) {
final url = apiUri + _marketInfoUriSufix + _fixedRateUriSufix + apiKey;
final response = await get(url);
final responseJSON = json.decode(response.body) as List<dynamic>;
var rate = 0.0;
var fee = 0.0;
return estimatedAmount;
for (var elem in responseJSON) {
final elemFrom = elem["from"] as String;
final elemTo = elem["to"] as String;
if ((elemFrom == to.toString().toLowerCase()) &&
(elemTo == from.toString().toLowerCase())) {
rate = elem["rate"] as double;
fee = elem["minerFee"] as double;
break;
}
}
final estimatedAmount = (amount == 0.0)||(rate == 0.0) ? 0.0
: (amount + fee)/rate;
return estimatedAmount;
} else {
final url = isFixedRateMode
? apiUri +
_exchangeAmountUriSufix +
_fixedRateUriSufix +
amount.toString() +
'/' +
from.toString() +
'_' +
to.toString() +
'?api_key=' + apiKey
: apiUri +
_exchangeAmountUriSufix +
amount.toString() +
'/' +
from.toString() +
'_' +
to.toString();
final response = await get(url);
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
final estimatedAmount = responseJSON['estimatedAmount'] as double;
return estimatedAmount;
}
}
}
+5 -4
View File
@@ -17,10 +17,11 @@ abstract class ExchangeProvider {
@override
String toString() => title;
Future<Limits> fetchLimits({CryptoCurrency from, CryptoCurrency to});
Future<Trade> createTrade({TradeRequest request});
Future<Limits> fetchLimits(
{CryptoCurrency from, CryptoCurrency to, bool isFixedRateMode});
Future<Trade> createTrade({TradeRequest request, bool isFixedRateMode});
Future<Trade> findTradeById({@required String id});
Future<double> calculateAmount(
{CryptoCurrency from, CryptoCurrency to, double amount, bool isReceiveAmount});
Future<double> calculateAmount({CryptoCurrency from, CryptoCurrency to,
double amount, bool isFixedRateMode, bool isReceiveAmount});
Future<bool> checkIsAvailable();
}
@@ -71,7 +71,7 @@ class MorphTokenExchangeProvider extends ExchangeProvider {
Future<bool> checkIsAvailable() async => true;
@override
Future<Limits> fetchLimits({CryptoCurrency from, CryptoCurrency to}) async {
Future<Limits> fetchLimits({CryptoCurrency from, CryptoCurrency to, bool isFixedRateMode}) async {
final url = apiUri + _limitsURISuffix;
final headers = {'Content-type': 'application/json'};
final body = json.encode({
@@ -100,7 +100,7 @@ class MorphTokenExchangeProvider extends ExchangeProvider {
}
@override
Future<Trade> createTrade({TradeRequest request}) async {
Future<Trade> createTrade({TradeRequest request, bool isFixedRateMode}) async {
const url = apiUri + _morphURISuffix;
final _request = request as MorphTokenRequest;
final body = {
@@ -191,7 +191,7 @@ class MorphTokenExchangeProvider extends ExchangeProvider {
@override
Future<double> calculateAmount(
{CryptoCurrency from, CryptoCurrency to, double amount,
{CryptoCurrency from, CryptoCurrency to, double amount, bool isFixedRateMode,
bool isReceiveAmount}) async {
final url = apiUri + _ratesURISuffix;
final response = await get(url);
@@ -58,7 +58,7 @@ class XMRTOExchangeProvider extends ExchangeProvider {
}
@override
Future<Limits> fetchLimits({CryptoCurrency from, CryptoCurrency to}) async {
Future<Limits> fetchLimits({CryptoCurrency from, CryptoCurrency to, bool isFixedRateMode}) async {
final url = originalApiUri + _orderParameterUriSuffix;
final response = await get(url);
final correction = 0.001;
@@ -91,7 +91,7 @@ class XMRTOExchangeProvider extends ExchangeProvider {
}
@override
Future<Trade> createTrade({TradeRequest request}) async {
Future<Trade> createTrade({TradeRequest request, bool isFixedRateMode}) async {
final _request = request as XMRTOTradeRequest;
final url = originalApiUri + _orderCreateUriSuffix;
final _amount =
@@ -188,6 +188,7 @@ class XMRTOExchangeProvider extends ExchangeProvider {
{CryptoCurrency from,
CryptoCurrency to,
double amount,
bool isFixedRateMode,
bool isReceiveAmount}) async {
if (from != CryptoCurrency.xmr && to != CryptoCurrency.btc) {
return 0;
+104 -12
View File
@@ -35,7 +35,7 @@ class S implements WidgetsLocalizations {
String get all => "ALL";
String get amount => "Amount: ";
String get amount_is_estimate => "The receive amount is an estimate";
String get amount_is_guaranteed => "In xmr.to, to receive a guaranteed BTC amount, enter the BTC amount and not the XMR amount above";
String get amount_is_guaranteed => "The receive amount is guaranteed";
String get auth_store_ban_timeout => "ban_timeout";
String get auth_store_banned_for => "Banned for ";
String get auth_store_banned_minutes => " minutes";
@@ -395,6 +395,10 @@ class S implements WidgetsLocalizations {
String get confirmed => 'Confirmed';
String get unconfirmed => 'Unconfirmed';
String get displayable => 'Displayable';
String get fixed_rate => 'Fixed rate';
String get fixed_rate_alert => 'You will be able to enter receive amount when fixed rate mode is checked. Do you want to switch to fixed rate mode?';
String get xlm_extra_info => 'Please don’t forget to specify the Memo ID while sending the XLM transaction for the exchange';
String get xrp_extra_info => 'Please don’t forget to specify the Destination Tag while sending the XRP transaction for the exchange';
}
class $de extends S {
@@ -536,7 +540,7 @@ class $de extends S {
@override
String get receive => "Erhalten";
@override
String get amount_is_guaranteed => "Geben Sie in xmr.to den BTC-Betrag und nicht den oben genannten XMR-Betrag ein, um einen garantierten BTC-Betrag zu erhalten";
String get amount_is_guaranteed => "Der Empfangsbetrag ist garantiert";
@override
String get auth_store_banned_for => "Gebannt für ";
@override
@@ -1151,6 +1155,14 @@ class $de extends S {
String get unconfirmed => 'Unbestätigt';
@override
String get displayable => 'Anzeigebar';
@override
String get fixed_rate => 'Fester Zinssatz';
@override
String get fixed_rate_alert => 'Sie können den Empfangsbetrag eingeben, wenn der Festpreismodus aktiviert ist. Möchten Sie in den Festpreismodus wechseln?';
@override
String get xlm_extra_info => 'Bitte vergessen Sie nicht, die Memo-ID anzugeben, während Sie die XLM-Transaktion für den Austausch senden';
@override
String get xrp_extra_info => 'Bitte vergessen Sie nicht, das Ziel-Tag anzugeben, während Sie die XRP-Transaktion für den Austausch senden';
}
class $hi extends S {
@@ -1292,7 +1304,7 @@ class $hi extends S {
@override
String get receive => "प्राप्त करना";
@override
String get amount_is_guaranteed => "Xmr.to में, गारंटीशुदा BTC राशि प्राप्त करने के लिए, BTC राशि दर्ज करें और ऊपर XMR राशि नहीं";
String get amount_is_guaranteed => "प्राप्त राशि की गारंटी हैं";
@override
String get auth_store_banned_for => "के लिए प्रतिबंधित है ";
@override
@@ -1907,6 +1919,14 @@ class $hi extends S {
String get unconfirmed => 'अपुष्ट';
@override
String get displayable => 'प्रदर्शन योग्य';
@override
String get fixed_rate => 'निर्धारित दर';
@override
String get fixed_rate_alert => 'फिक्स्ड रेट मोड की जांच करने पर आप प्राप्त राशि दर्ज कर पाएंगे। क्या आप निश्चित दर मोड पर स्विच करना चाहते हैं?';
@override
String get xlm_extra_info => 'एक्सचेंज के लिए XLM ट्रांजेक्शन भेजते समय मेमो आईडी निर्दिष्ट करना न भूलें';
@override
String get xrp_extra_info => 'एक्सचेंज के लिए एक्सआरपी लेनदेन भेजते समय कृपया गंतव्य टैग निर्दिष्ट करना न भूलें';
}
class $ru extends S {
@@ -2048,7 +2068,7 @@ class $ru extends S {
@override
String get receive => "Получить";
@override
String get amount_is_guaranteed => "В xmr.to, чтобы получить гарантированную сумму BTC, введите сумму BTC, а не сумму XMR выше";
String get amount_is_guaranteed => "Полученная сумма гарантирована";
@override
String get auth_store_banned_for => "Заблокировано на ";
@override
@@ -2663,6 +2683,14 @@ class $ru extends S {
String get unconfirmed => 'Неподтвержденный';
@override
String get displayable => 'Отображаемый';
@override
String get fixed_rate => 'Фиксированная ставка';
@override
String get fixed_rate_alert => 'Вы сможете ввести сумму получения тогда, когда будет установлен режим фиксированной ставки. Вы хотите перейти в режим фиксированной ставки?';
@override
String get xlm_extra_info => 'Не забудьте указать Memo ID (памятка) при отправке транзакции XLM для обмена';
@override
String get xrp_extra_info => 'Не забудьте указать целевой тег при отправке транзакции XRP для обмена';
}
class $ko extends S {
@@ -2804,7 +2832,7 @@ class $ko extends S {
@override
String get receive => "받다";
@override
String get amount_is_guaranteed => "xmr.to에서 보장 된 BTC 금액을 받으려면 위의 XMR 금액이 아닌 BTC 금액을 입력하십시오.";
String get amount_is_guaranteed => "수령 금액이 보장됩니다.";
@override
String get auth_store_banned_for => "금지";
@override
@@ -3419,6 +3447,14 @@ class $ko extends S {
String get unconfirmed => '미확인';
@override
String get displayable => '표시 가능';
@override
String get fixed_rate => '고정 비율';
@override
String get fixed_rate_alert => '고정 금리 모드 체크시 수취 금액 입력이 가능합니다. 고정 속도 모드로 전환 하시겠습니까?';
@override
String get xlm_extra_info => '교환을 위해 XLM 거래를 보낼 때 메모 ID를 지정하는 것을 잊지 마십시오';
@override
String get xrp_extra_info => '교환을 위해 XRP 트랜잭션을 보내는 동안 대상 태그를 지정하는 것을 잊지 마십시오';
}
class $pt extends S {
@@ -3560,7 +3596,7 @@ class $pt extends S {
@override
String get receive => "Receber";
@override
String get amount_is_guaranteed => "Em xmr.to, para receber um valor BTC garantido, insira o valor BTC e não o valor XMR acima";
String get amount_is_guaranteed => "O valor recebido é garantido";
@override
String get auth_store_banned_for => "Banido por";
@override
@@ -4175,6 +4211,14 @@ class $pt extends S {
String get unconfirmed => 'Não confirmado';
@override
String get displayable => 'Exibível';
@override
String get fixed_rate => 'Taxa fixa';
@override
String get fixed_rate_alert => 'Você poderá inserir a quantia recebida quando o modo de taxa fixa estiver marcado. Quer mudar para o modo de taxa fixa?';
@override
String get xlm_extra_info => 'Não se esqueça de especificar o Memo ID ao enviar a transação XLM para a troca';
@override
String get xrp_extra_info => 'Não se esqueça de especificar a etiqueta de destino ao enviar a transação XRP para a troca';
}
class $uk extends S {
@@ -4316,7 +4360,7 @@ class $uk extends S {
@override
String get receive => "Отримати";
@override
String get amount_is_guaranteed => "У xmr.to, щоб отримати гарантовану суму BTC, введіть суму BTC, а не XMR вище";
String get amount_is_guaranteed => "Отримана сума є гарантованою";
@override
String get auth_store_banned_for => "Заблоковано на ";
@override
@@ -4931,6 +4975,14 @@ class $uk extends S {
String get unconfirmed => 'Непідтверджений';
@override
String get displayable => 'Відображуваний';
@override
String get fixed_rate => 'Фіксована ставка';
@override
String get fixed_rate_alert => 'Ви зможете ввести суму отримання тоді, коли буде встановлений режим фіксованої ставки. Ви хочете перейти в режим фіксованої ставки?';
@override
String get xlm_extra_info => "Будь ласка, не забудьте вказати ідентифікатор пам'ятки під час надсилання транзакції XLM для обміну";
@override
String get xrp_extra_info => 'Будь ласка, не забудьте вказати тег призначення під час надсилання XRP-транзакції для обміну';
}
class $ja extends S {
@@ -5072,7 +5124,7 @@ class $ja extends S {
@override
String get receive => "受け取る";
@override
String get amount_is_guaranteed => "xmr.toで、保証されたBTC金額を受け取るには、上記のXMR金額ではなく、BTC金額を入力します";
String get amount_is_guaranteed => "受け取り金額は保証されています";
@override
String get auth_store_banned_for => "禁止されています ";
@override
@@ -5687,6 +5739,14 @@ class $ja extends S {
String get unconfirmed => '未確認';
@override
String get displayable => '表示可能';
@override
String get fixed_rate => '固定金利';
@override
String get fixed_rate_alert => '固定金利モードにチェックを入れると、受取額を入力できるようになります。 固定金利モードに切り替えますか?';
@override
String get xlm_extra_info => '交換用のXLMトランザクションを送信するときに、メモIDを指定することを忘れないでください';
@override
String get xrp_extra_info => '取引所のXRPトランザクションを送信するときに、宛先タグを指定することを忘れないでください';
}
class $en extends S {
@@ -5832,7 +5892,7 @@ class $pl extends S {
@override
String get receive => "Otrzymać";
@override
String get amount_is_guaranteed => "W xmr.to, aby otrzymać gwarantowaną kwotę BTC, wprowadź kwotę BTC, a nie kwotę XMR powyżej";
String get amount_is_guaranteed => "Otrzymana kwota jest gwarantowana";
@override
String get auth_store_banned_for => "Bzbanowany za ";
@override
@@ -6447,6 +6507,14 @@ class $pl extends S {
String get unconfirmed => 'niepotwierdzony';
@override
String get displayable => 'Wyświetlane';
@override
String get fixed_rate => 'Stała stawka';
@override
String get fixed_rate_alert => 'Będziesz mógł wprowadzić kwotę otrzymaną, gdy zaznaczony jest tryb stałej stawki. Czy chcesz przejść do trybu stałej stawki?';
@override
String get xlm_extra_info => 'Nie zapomnij podać identyfikatora notatki podczas wysyłania transakcji XLM do wymiany';
@override
String get xrp_extra_info => 'Nie zapomnij podać tagu docelowego podczas wysyłania transakcji XRP do wymiany';
}
class $es extends S {
@@ -6588,7 +6656,7 @@ class $es extends S {
@override
String get receive => "Recibir";
@override
String get amount_is_guaranteed => "En xmr.to, para recibir una cantidad BTC garantizada, ingrese la cantidad BTC y no la cantidad XMR arriba";
String get amount_is_guaranteed => "La cantidad recibida está garantizada";
@override
String get auth_store_banned_for => "Prohibido para ";
@override
@@ -7203,6 +7271,14 @@ class $es extends S {
String get unconfirmed => 'inconfirmado';
@override
String get displayable => 'Visualizable';
@override
String get fixed_rate => 'Tipo de interés fijo';
@override
String get fixed_rate_alert => 'Podrá ingresar la cantidad recibida cuando el modo de tarifa fija esté marcado. ¿Quieres cambiar al modo de tarifa fija?';
@override
String get xlm_extra_info => 'No olvide especificar el ID de nota al enviar la transacción XLM para el intercambio';
@override
String get xrp_extra_info => 'No olvide especificar la etiqueta de destino al enviar la transacción XRP para el intercambio';
}
class $nl extends S {
@@ -7344,7 +7420,7 @@ class $nl extends S {
@override
String get receive => "Krijgen";
@override
String get amount_is_guaranteed => "Om een gegarandeerd BTC-bedrag te ontvangen, voert u in xmr.to het BTC-bedrag in en niet het bovenstaande XMR-bedrag";
String get amount_is_guaranteed => "Het ontvangen bedrag is gegarandeerd";
@override
String get auth_store_banned_for => "Verboden voor ";
@override
@@ -7959,6 +8035,14 @@ class $nl extends S {
String get unconfirmed => 'niet bevestigd';
@override
String get displayable => 'Weer te geven';
@override
String get fixed_rate => 'Vast tarief';
@override
String get fixed_rate_alert => 'U kunt het ontvangen bedrag invoeren wanneer de modus voor vaste tarieven is aangevinkt. Wilt u overschakelen naar de vaste-tariefmodus?';
@override
String get xlm_extra_info => 'Vergeet niet om de Memo-ID op te geven tijdens het verzenden van de XLM-transactie voor de uitwisseling';
@override
String get xrp_extra_info => 'Vergeet niet om de Destination Tag op te geven tijdens het verzenden van de XRP-transactie voor de uitwisseling';
}
class $zh extends S {
@@ -8100,7 +8184,7 @@ class $zh extends S {
@override
String get receive => "接收";
@override
String get amount_is_guaranteed => "在xmr.to中,要接收保证的BTC数量,请输入BTC数量,而不要输入上方的XMR数量";
String get amount_is_guaranteed => "接收金額有保證";
@override
String get auth_store_banned_for => "禁止 ";
@override
@@ -8715,6 +8799,14 @@ class $zh extends S {
String get unconfirmed => '未经证实';
@override
String get displayable => '可显示';
@override
String get fixed_rate => '固定利率';
@override
String get fixed_rate_alert => '選中固定費率模式後,您將可以輸入接收金額。 您要切換到固定速率模式嗎?';
@override
String get xlm_extra_info => '發送用於交換的XLM交易時,請不要忘記指定備忘錄ID';
@override
String get xrp_extra_info => '發送用於交換的XRP交易時,請不要忘記指定目標標記';
}
class GeneratedLocalizationsDelegate extends LocalizationsDelegate<S> {
+119 -72
View File
@@ -1,6 +1,8 @@
import 'dart:ui';
import 'package:cake_wallet/entities/sync_status.dart';
import 'package:cake_wallet/entities/wallet_type.dart';
import 'package:cake_wallet/exchange/changenow/changenow_exchange_provider.dart';
import 'package:cake_wallet/src/widgets/standard_checkbox.dart';
import 'package:dotted_border/dotted_border.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
@@ -37,6 +39,7 @@ class ExchangePage extends BasePage {
final ExchangeViewModel exchangeViewModel;
final depositKey = GlobalKey<ExchangeCardState>();
final receiveKey = GlobalKey<ExchangeCardState>();
final checkBoxKey = GlobalKey<StandardCheckboxState>();
final _formKey = GlobalKey<FormState>();
final _depositAmountFocus = FocusNode();
final _receiveAmountFocus = FocusNode();
@@ -115,7 +118,7 @@ class ExchangePage extends BasePage {
key: _formKey,
child: ScrollableWithBottomSection(
contentPadding: EdgeInsets.only(bottom: 24),
content: Column(
content: Observer(builder: (_) => Column(
children: <Widget>[
Container(
padding: EdgeInsets.only(bottom: 32),
@@ -165,22 +168,22 @@ class ExchangePage extends BasePage {
hasAllAmount: exchangeViewModel.hasAllAmount,
allAmount: exchangeViewModel.hasAllAmount
? () => exchangeViewModel
.calculateDepositAllAmount()
.calculateDepositAllAmount()
: null,
amountFocusNode: _depositAmountFocus,
key: depositKey,
title: S.of(context).you_will_send,
initialCurrency:
exchangeViewModel.depositCurrency,
exchangeViewModel.depositCurrency,
initialWalletName: depositWalletName,
initialAddress:
exchangeViewModel.depositCurrency ==
exchangeViewModel.wallet.currency
? exchangeViewModel.wallet.address
: exchangeViewModel.depositAddress,
exchangeViewModel.depositCurrency ==
exchangeViewModel.wallet.currency
? exchangeViewModel.wallet.address
: exchangeViewModel.depositAddress,
initialIsAmountEditable: true,
initialIsAddressEditable:
exchangeViewModel.isDepositAddressEnabled,
exchangeViewModel.isDepositAddressEnabled,
isAmountEstimated: false,
hasRefundAddress: true,
currencies: CryptoCurrency.all,
@@ -211,7 +214,7 @@ class ExchangePage extends BasePage {
imageArrow: arrowBottomPurple,
currencyButtonColor: Colors.transparent,
addressButtonsColor:
Theme.of(context).focusColor,
Theme.of(context).focusColor,
borderColor: Theme.of(context)
.primaryTextTheme
.body2
@@ -225,52 +228,65 @@ class ExchangePage extends BasePage {
),
Padding(
padding:
EdgeInsets.only(top: 29, left: 24, right: 24),
EdgeInsets.only(top: 29, left: 24, right: 24),
child: Observer(
builder: (_) => ExchangeCard(
amountFocusNode: _receiveAmountFocus,
key: receiveKey,
title: S.of(context).you_will_get,
initialCurrency:
exchangeViewModel.receiveCurrency,
initialWalletName: receiveWalletName,
initialAddress: exchangeViewModel
.receiveCurrency ==
exchangeViewModel.wallet.currency
? exchangeViewModel.wallet.address
: exchangeViewModel.receiveAddress,
initialIsAmountEditable: exchangeViewModel
.provider is XMRTOExchangeProvider
? true
: false,
initialIsAddressEditable:
exchangeViewModel
.isReceiveAddressEnabled,
isAmountEstimated: true,
currencies: CryptoCurrency.all,
onCurrencySelected: (currency) =>
exchangeViewModel
.changeReceiveCurrency(
currency: currency),
imageArrow: arrowBottomCakeGreen,
currencyButtonColor: Colors.transparent,
addressButtonsColor:
Theme.of(context).focusColor,
borderColor: Theme.of(context)
.primaryTextTheme
.body2
.decorationColor,
currencyValueValidator: AmountValidator(
type: exchangeViewModel.wallet.type),
addressTextFieldValidator:
AddressValidator(
type: exchangeViewModel
.receiveCurrency),
)),
amountFocusNode: _receiveAmountFocus,
key: receiveKey,
title: S.of(context).you_will_get,
initialCurrency:
exchangeViewModel.receiveCurrency,
initialWalletName: receiveWalletName,
initialAddress: exchangeViewModel
.receiveCurrency ==
exchangeViewModel.wallet.currency
? exchangeViewModel.wallet.address
: exchangeViewModel.receiveAddress,
initialIsAmountEditable: exchangeViewModel
.isReceiveAmountEditable,
initialIsAddressEditable:
exchangeViewModel
.isReceiveAddressEnabled,
isAmountEstimated: true,
currencies: CryptoCurrency.all,
onCurrencySelected: (currency) =>
exchangeViewModel
.changeReceiveCurrency(
currency: currency),
imageArrow: arrowBottomCakeGreen,
currencyButtonColor: Colors.transparent,
addressButtonsColor:
Theme.of(context).focusColor,
borderColor: Theme.of(context)
.primaryTextTheme
.body2
.decorationColor,
currencyValueValidator: AmountValidator(
type: exchangeViewModel.wallet.type),
addressTextFieldValidator:
AddressValidator(
type: exchangeViewModel
.receiveCurrency),
)),
)
],
),
),
if (exchangeViewModel.isReceiveAmountEditable) Padding(
padding: EdgeInsets.only(top: 12, left: 24),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
StandardCheckbox(
key: checkBoxKey,
value: exchangeViewModel.isFixedRateMode,
caption: S.of(context).fixed_rate,
onChanged: (value) =>
exchangeViewModel.isFixedRateMode = value,
),
],
)
),
Padding(
padding: EdgeInsets.only(top: 30, left: 24, bottom: 24),
child: Row(
@@ -302,7 +318,7 @@ class ExchangePage extends BasePage {
.pushNamed(Routes.exchangeTemplate),
child: Container(
padding:
EdgeInsets.only(left: 1, right: 10),
EdgeInsets.only(left: 1, right: 10),
child: DottedBorder(
borderType: BorderType.RRect,
dashPattern: [6, 4],
@@ -369,23 +385,23 @@ class ExchangePage extends BasePage {
.of(context)
.confirm_delete_template,
rightButtonText:
S.of(context).delete,
S.of(context).delete,
leftButtonText:
S.of(context).cancel,
S.of(context).cancel,
actionRightButton: () {
Navigator.of(
dialogContext)
dialogContext)
.pop();
exchangeViewModel
.removeTemplate(
template:
template);
template:
template);
exchangeViewModel
.updateTemplate();
},
actionLeftButton: () =>
Navigator.of(
dialogContext)
dialogContext)
.pop());
});
},
@@ -395,15 +411,14 @@ class ExchangePage extends BasePage {
],
)))
],
),
)),
bottomSectionPadding:
EdgeInsets.only(left: 24, right: 24, bottom: 24),
bottomSection: Column(children: <Widget>[
Padding(
padding: EdgeInsets.only(bottom: 15),
child: Observer(builder: (_) {
final description =
exchangeViewModel.provider is XMRTOExchangeProvider
final description = exchangeViewModel.isFixedRateMode
? S.of(context).amount_is_guaranteed
: S.of(context).amount_is_estimate;
return Center(
@@ -464,17 +479,9 @@ class ExchangePage extends BasePage {
currency: CryptoCurrency.fromString(template.receiveCurrency));
switch (template.provider) {
case 'XMR.TO':
exchangeViewModel.changeProvider(
provider: exchangeViewModel.providerList[0]);
break;
case 'ChangeNOW':
exchangeViewModel.changeProvider(
provider: exchangeViewModel.providerList[1]);
break;
case 'MorphToken':
exchangeViewModel.changeProvider(
provider: exchangeViewModel.providerList[2]);
provider: exchangeViewModel.providerList[0]);
break;
}
@@ -482,6 +489,7 @@ class ExchangePage extends BasePage {
exchangeViewModel.depositAddress = template.depositAddress;
exchangeViewModel.receiveAddress = template.receiveAddress;
exchangeViewModel.isReceiveAmountEntered = false;
exchangeViewModel.isFixedRateMode = false;
}
void _setReactions(
@@ -566,10 +574,10 @@ class ExchangePage extends BasePage {
receiveKey.currentState.isAddressEditable(isEditable: isEnabled);
});
reaction((_) => exchangeViewModel.provider, (ExchangeProvider provider) {
provider is XMRTOExchangeProvider
? receiveKey.currentState.isAmountEditable(isEditable: true)
: receiveKey.currentState.isAmountEditable(isEditable: false);
reaction((_) => exchangeViewModel.isReceiveAmountEditable,
(bool isReceiveAmountEditable) {
receiveKey.currentState
.isAmountEditable(isEditable: isReceiveAmountEditable);
});
reaction((_) => exchangeViewModel.tradeState, (ExchangeTradeState state) {
@@ -647,6 +655,45 @@ class ExchangePage extends BasePage {
}
});
_receiveAmountFocus.addListener(() {
if (_receiveAmountFocus.hasFocus && !exchangeViewModel.isFixedRateMode) {
showPopUp<void>(
context: context,
builder: (BuildContext context) {
return AlertWithTwoActions(
alertTitle: S.of(context).exchange,
alertContent: S.of(context).fixed_rate_alert,
leftButtonText: S.of(context).cancel,
rightButtonText: S.of(context).ok,
actionLeftButton: () {
FocusScope.of(context).unfocus();
Navigator.of(context).pop();
},
actionRightButton: () {
exchangeViewModel.isFixedRateMode = true;
checkBoxKey.currentState
.changeValue(exchangeViewModel.isFixedRateMode);
Navigator.of(context).pop();
});
});
}
});
reaction((_) => exchangeViewModel.isFixedRateMode, (bool isFixedRateMode) {
if ((_receiveAmountFocus.hasFocus ||
exchangeViewModel.isReceiveAmountEntered) && !isFixedRateMode) {
FocusScope.of(context).unfocus();
receiveAmountController.text = '';
} else {
exchangeViewModel.changeDepositAmount(
amount: depositAmountController.text);
}
checkBoxKey.currentState
.changeValue(exchangeViewModel.isFixedRateMode);
exchangeViewModel.loadLimits();
});
_isReactionsSet = true;
}
@@ -28,9 +28,11 @@ void showInformation(
final information = exchangeTradeViewModel.isSendable
? S.current.exchange_result_confirm(
trade.amount ?? fetchingLabel, trade.from.toString(), walletName)
trade.amount ?? fetchingLabel, trade.from.toString(), walletName) +
exchangeTradeViewModel.extraInfo
: S.current.exchange_result_description(
trade.amount ?? fetchingLabel, trade.from.toString());
trade.amount ?? fetchingLabel, trade.from.toString()) +
exchangeTradeViewModel.extraInfo;
showPopUp<void>(
context: context,
@@ -148,6 +150,7 @@ class ExchangeTradeState extends State<ExchangeTradeForm> {
padding: EdgeInsets.all(5),
decoration: BoxDecoration(
border: Border.all(
width: 3,
color: Theme.of(context)
.accentTextTheme
.subtitle
@@ -48,6 +48,7 @@ class QRWidget extends StatelessWidget {
padding: EdgeInsets.all(5),
decoration: BoxDecoration(
border: Border.all(
width: 3,
color: Theme.of(context).accentTextTheme.
display3.backgroundColor
)
+6 -1
View File
@@ -4,9 +4,10 @@ import 'package:flutter/material.dart';
class StandardCheckbox extends StatefulWidget {
StandardCheckbox({
Key key,
@required this.value,
this.caption = '',
@required this.onChanged});
@required this.onChanged}) : super(key: key);
final bool value;
final String caption;
@@ -24,6 +25,10 @@ class StandardCheckboxState extends State<StandardCheckbox> {
String caption;
Function(bool) onChanged;
void changeValue(bool newValue) {
setState(() => value = newValue);
}
@override
Widget build(BuildContext context) {
return GestureDetector(
@@ -59,6 +59,13 @@ abstract class ExchangeTradeViewModelBase with Store {
@observable
bool isSendable;
@computed
String get extraInfo => trade.from == CryptoCurrency.xlm
? '\n\n' + S.current.xlm_extra_info
: trade.from == CryptoCurrency.xrp
? '\n\n' + S.current.xrp_extra_info
: '';
@observable
ObservableList<ExchangeTradeItem> items;
@@ -57,7 +57,8 @@ abstract class ExchangeViewModelBase with Store {
_onPairChange();
}
});
_defineIsReceiveAmountEditable();
isFixedRateMode = false;
isReceiveAmountEntered = false;
loadLimits();
}
@@ -106,6 +107,12 @@ abstract class ExchangeViewModelBase with Store {
@observable
bool isReceiveAmountEntered;
@observable
bool isReceiveAmountEditable;
@observable
bool isFixedRateMode;
@computed
SyncStatus get status => wallet.syncStatus;
@@ -127,12 +134,15 @@ abstract class ExchangeViewModelBase with Store {
this.provider = provider;
depositAmount = '';
receiveAmount = '';
isFixedRateMode = false;
_defineIsReceiveAmountEditable();
loadLimits();
}
@action
void changeDepositCurrency({CryptoCurrency currency}) {
depositCurrency = currency;
isFixedRateMode = false;
_onPairChange();
isDepositAddressEnabled = !(depositCurrency == wallet.currency);
isReceiveAddressEnabled = !(receiveCurrency == wallet.currency);
@@ -141,6 +151,7 @@ abstract class ExchangeViewModelBase with Store {
@action
void changeReceiveCurrency({CryptoCurrency currency}) {
receiveCurrency = currency;
isFixedRateMode = false;
_onPairChange();
isDepositAddressEnabled = !(depositCurrency == wallet.currency);
isReceiveAddressEnabled = !(receiveCurrency == wallet.currency);
@@ -160,9 +171,10 @@ abstract class ExchangeViewModelBase with Store {
provider
.calculateAmount(
from: depositCurrency,
to: receiveCurrency,
from: receiveCurrency,
to: depositCurrency,
amount: _amount,
isFixedRateMode: isFixedRateMode,
isReceiveAmount: true)
.then((amount) => _cryptoNumberFormat
.format(amount)
@@ -187,6 +199,7 @@ abstract class ExchangeViewModelBase with Store {
from: depositCurrency,
to: receiveCurrency,
amount: _amount,
isFixedRateMode: isFixedRateMode,
isReceiveAmount: false)
.then((amount) => _cryptoNumberFormat
.format(amount)
@@ -200,8 +213,8 @@ abstract class ExchangeViewModelBase with Store {
limitsState = LimitsIsLoading();
try {
limits = await provider.fetchLimits(
from: depositCurrency, to: receiveCurrency);
limits = await provider.fetchLimits(from: depositCurrency,
to: receiveCurrency, isFixedRateMode: isFixedRateMode);
limitsState = LimitsLoadedSuccessfully(limits: limits);
} catch (e) {
limitsState = LimitsLoadedFailure(error: e.toString());
@@ -265,7 +278,8 @@ abstract class ExchangeViewModelBase with Store {
} else {
try {
tradeState = TradeIsCreating();
final trade = await provider.createTrade(request: request);
final trade = await provider.createTrade(request: request,
isFixedRateMode: isFixedRateMode);
trade.walletId = wallet.id;
tradesStore.setTrade(trade);
await trades.add(trade);
@@ -285,15 +299,15 @@ abstract class ExchangeViewModelBase with Store {
@action
void reset() {
_initialPairBasedOnWallet();
isReceiveAmountEntered = false;
depositAmount = '';
receiveAmount = '';
depositCurrency = CryptoCurrency.xmr;
receiveCurrency = CryptoCurrency.btc;
depositAddress = depositCurrency == wallet.currency ? wallet.address : '';
receiveAddress = receiveCurrency == wallet.currency ? wallet.address : '';
isDepositAddressEnabled = !(depositCurrency == wallet.currency);
isReceiveAddressEnabled = !(receiveCurrency == wallet.currency);
isFixedRateMode = false;
_onPairChange();
}
@@ -364,7 +378,7 @@ abstract class ExchangeViewModelBase with Store {
}
}
depositAddress = depositCurrency == wallet.currency ? wallet.address : '';
_defineIsReceiveAmountEditable();
depositAmount = '';
receiveAmount = '';
loadLimits();
@@ -389,4 +403,14 @@ abstract class ExchangeViewModelBase with Store {
break;
}
}
void _defineIsReceiveAmountEditable() {
if ((provider is ChangeNowExchangeProvider)
&&(depositCurrency == CryptoCurrency.xmr)
&&(receiveCurrency == CryptoCurrency.btc)) {
isReceiveAmountEditable = true;
} else {
isReceiveAmountEditable = false;
}
}
}