mirror of
https://github.com/cake-tech/cake_wallet.git
synced 2025-01-13 14:25:03 +00:00
Merge branch 'main' into CW-292-Save-historical-fiat-API-rate
This commit is contained in:
commit
5d6d9b9589
9 changed files with 516 additions and 436 deletions
1
.github/workflows/pr_test_build.yml
vendored
1
.github/workflows/pr_test_build.yml
vendored
|
@ -106,7 +106,6 @@ jobs:
|
|||
echo "const moonPayApiKey = '${{ secrets.MOON_PAY_API_KEY }}';" >> lib/.secrets.g.dart
|
||||
echo "const moonPaySecretKey = '${{ secrets.MOON_PAY_SECRET_KEY }}';" >> lib/.secrets.g.dart
|
||||
echo "const sideShiftAffiliateId = '${{ secrets.SIDE_SHIFT_AFFILIATE_ID }}';" >> lib/.secrets.g.dart
|
||||
echo "const sideShiftApiKey = '${{ secrets.SIDE_SHIFT_API_KEY }}';" >> lib/.secrets.g.dart
|
||||
echo "const simpleSwapApiKey = '${{ secrets.SIMPLE_SWAP_API_KEY }}';" >> lib/.secrets.g.dart
|
||||
echo "const simpleSwapApiKeyDesktop = '${{ secrets.SIMPLE_SWAP_API_KEY_DESKTOP }}';" >> lib/.secrets.g.dart
|
||||
echo "const onramperApiKey = '${{ secrets.ONRAMPER_API_KEY }}';" >> lib/.secrets.g.dart
|
||||
|
|
|
@ -19,10 +19,10 @@ class SideShiftExchangeProvider extends ExchangeProvider {
|
|||
|
||||
static const affiliateId = secrets.sideShiftAffiliateId;
|
||||
static const apiBaseUrl = 'https://sideshift.ai/api';
|
||||
static const rangePath = '/v1/pairs';
|
||||
static const orderPath = '/v1/orders';
|
||||
static const quotePath = '/v1/quotes';
|
||||
static const permissionPath = '/v1/permissions';
|
||||
static const rangePath = '/v2/pair';
|
||||
static const orderPath = '/v2/shifts';
|
||||
static const quotePath = '/v2/quotes';
|
||||
static const permissionPath = '/v2/permissions';
|
||||
|
||||
static const List<CryptoCurrency> _notSupported = [
|
||||
CryptoCurrency.xhv,
|
||||
|
@ -36,23 +36,22 @@ class SideShiftExchangeProvider extends ExchangeProvider {
|
|||
CryptoCurrency.scrt,
|
||||
CryptoCurrency.stx,
|
||||
CryptoCurrency.bttc,
|
||||
CryptoCurrency.usdt,
|
||||
CryptoCurrency.eos,
|
||||
];
|
||||
|
||||
static List<ExchangePair> _supportedPairs() {
|
||||
final supportedCurrencies = CryptoCurrency.all
|
||||
.where((element) => !_notSupported.contains(element))
|
||||
.toList();
|
||||
final supportedCurrencies =
|
||||
CryptoCurrency.all.where((element) => !_notSupported.contains(element)).toList();
|
||||
|
||||
return supportedCurrencies
|
||||
.map((i) => supportedCurrencies
|
||||
.map((k) => ExchangePair(from: i, to: k, reverse: true)))
|
||||
.map((i) => supportedCurrencies.map((k) => ExchangePair(from: i, to: k, reverse: true)))
|
||||
.expand((i) => i)
|
||||
.toList();
|
||||
}
|
||||
|
||||
@override
|
||||
ExchangeProviderDescription get description =>
|
||||
ExchangeProviderDescription.sideShift;
|
||||
ExchangeProviderDescription get description => ExchangeProviderDescription.sideShift;
|
||||
|
||||
@override
|
||||
Future<double> fetchRate(
|
||||
|
@ -65,17 +64,18 @@ class SideShiftExchangeProvider extends ExchangeProvider {
|
|||
if (amount == 0) {
|
||||
return 0.0;
|
||||
}
|
||||
final fromCurrency = _normalizeCryptoCurrency(from);
|
||||
final toCurrency = _normalizeCryptoCurrency(to);
|
||||
final url =
|
||||
apiBaseUrl + rangePath + '/' + fromCurrency + '/' + toCurrency;
|
||||
|
||||
final fromCurrency = from.title.toLowerCase();
|
||||
final toCurrency = to.title.toLowerCase();
|
||||
final depositNetwork = _networkFor(from);
|
||||
final settleNetwork = _networkFor(to);
|
||||
|
||||
final url = "$apiBaseUrl$rangePath/$fromCurrency-$depositNetwork/$toCurrency-$settleNetwork";
|
||||
|
||||
final uri = Uri.parse(url);
|
||||
final response = await get(uri);
|
||||
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
||||
final rate = double.parse(responseJSON['rate'] as String);
|
||||
final max = double.parse(responseJSON['max'] as String);
|
||||
|
||||
if (amount > max) return 0.00;
|
||||
|
||||
return rate;
|
||||
} catch (_) {
|
||||
|
@ -101,25 +101,38 @@ class SideShiftExchangeProvider extends ExchangeProvider {
|
|||
}
|
||||
|
||||
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
||||
final canCreateOrder = responseJSON['createOrder'] as bool;
|
||||
final canCreateQuote = responseJSON['createQuote'] as bool;
|
||||
return canCreateOrder && canCreateQuote;
|
||||
final cancreateShift = responseJSON['createShift'] as bool;
|
||||
return cancreateShift;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Trade> createTrade(
|
||||
{required TradeRequest request, required bool isFixedRateMode}) async {
|
||||
Future<Trade> createTrade({required TradeRequest request, required bool isFixedRateMode}) async {
|
||||
final _request = request as SideShiftRequest;
|
||||
final quoteId = await _createQuote(_request);
|
||||
final url = apiBaseUrl + orderPath;
|
||||
final headers = {'Content-Type': 'application/json'};
|
||||
String url = '';
|
||||
final depositCoin = request.depositMethod.title.toLowerCase();
|
||||
final settleCoin = request.settleMethod.title.toLowerCase();
|
||||
final body = {
|
||||
'type': 'fixed',
|
||||
'quoteId': quoteId,
|
||||
'affiliateId': affiliateId,
|
||||
'settleAddress': _request.settleAddress,
|
||||
'refundAddress': _request.refundAddress
|
||||
'refundAddress': _request.refundAddress,
|
||||
};
|
||||
|
||||
if (isFixedRateMode) {
|
||||
final quoteId = await _createQuote(_request);
|
||||
body['quoteId'] = quoteId;
|
||||
|
||||
url = apiBaseUrl + orderPath + '/fixed';
|
||||
} else {
|
||||
url = apiBaseUrl + orderPath + '/variable';
|
||||
final depositNetwork = _networkFor(request.depositMethod);
|
||||
final settleNetwork = _networkFor(request.settleMethod);
|
||||
body["depositCoin"] = depositCoin;
|
||||
body["settleCoin"] = settleCoin;
|
||||
body["settleNetwork"] = settleNetwork;
|
||||
body["depositNetwork"] = depositNetwork;
|
||||
}
|
||||
final headers = {'Content-Type': 'application/json'};
|
||||
|
||||
final uri = Uri.parse(url);
|
||||
final response = await post(uri, headers: headers, body: json.encode(body));
|
||||
|
||||
|
@ -136,8 +149,9 @@ class SideShiftExchangeProvider extends ExchangeProvider {
|
|||
|
||||
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
||||
final id = responseJSON['id'] as String;
|
||||
final inputAddress = responseJSON['depositAddress']['address'] as String;
|
||||
final settleAddress = responseJSON['settleAddress']['address'] as String;
|
||||
final inputAddress = responseJSON['depositAddress'] as String;
|
||||
final settleAddress = responseJSON['settleAddress'] as String;
|
||||
final depositAmount = responseJSON['depositAmount'] as String?;
|
||||
|
||||
return Trade(
|
||||
id: id,
|
||||
|
@ -147,7 +161,7 @@ class SideShiftExchangeProvider extends ExchangeProvider {
|
|||
inputAddress: inputAddress,
|
||||
refundAddress: settleAddress,
|
||||
state: TradeState.created,
|
||||
amount: _request.depositAmount,
|
||||
amount: depositAmount ?? _request.depositAmount,
|
||||
payoutAddress: settleAddress,
|
||||
createdAt: DateTime.now(),
|
||||
);
|
||||
|
@ -156,13 +170,17 @@ class SideShiftExchangeProvider extends ExchangeProvider {
|
|||
Future<String> _createQuote(SideShiftRequest request) async {
|
||||
final url = apiBaseUrl + quotePath;
|
||||
final headers = {'Content-Type': 'application/json'};
|
||||
final depositMethod = _normalizeCryptoCurrency(request.depositMethod);
|
||||
final settleMethod = _normalizeCryptoCurrency(request.settleMethod);
|
||||
final depositMethod = request.depositMethod.title.toLowerCase();
|
||||
final settleMethod = request.settleMethod.title.toLowerCase();
|
||||
final depositNetwork = _networkFor(request.depositMethod);
|
||||
final settleNetwork = _networkFor(request.settleMethod);
|
||||
final body = {
|
||||
'depositMethod': depositMethod,
|
||||
'settleMethod': settleMethod,
|
||||
'depositCoin': depositMethod,
|
||||
'settleCoin': settleMethod,
|
||||
'affiliateId': affiliateId,
|
||||
'depositAmount': request.depositAmount,
|
||||
'settleAmount': request.depositAmount,
|
||||
'settleNetwork': settleNetwork,
|
||||
'depositNetwork': depositNetwork,
|
||||
};
|
||||
final uri = Uri.parse(url);
|
||||
final response = await post(uri, headers: headers, body: json.encode(body));
|
||||
|
@ -189,9 +207,15 @@ class SideShiftExchangeProvider extends ExchangeProvider {
|
|||
{required CryptoCurrency from,
|
||||
required CryptoCurrency to,
|
||||
required bool isFixedRateMode}) async {
|
||||
final fromCurrency = _normalizeCryptoCurrency(from);
|
||||
final toCurrency = _normalizeCryptoCurrency(to);
|
||||
final url = apiBaseUrl + rangePath + '/' + fromCurrency + '/' + toCurrency;
|
||||
final fromCurrency = isFixedRateMode ? to : from;
|
||||
final toCurrency = isFixedRateMode ? from : to;
|
||||
|
||||
final fromNetwork = _networkFor(fromCurrency);
|
||||
final toNetwork = _networkFor(toCurrency);
|
||||
|
||||
final url =
|
||||
"$apiBaseUrl$rangePath/${fromCurrency.title.toLowerCase()}-$fromNetwork/${toCurrency.title.toLowerCase()}-$toNetwork";
|
||||
|
||||
final uri = Uri.parse(url);
|
||||
final response = await get(uri);
|
||||
|
||||
|
@ -210,6 +234,14 @@ class SideShiftExchangeProvider extends ExchangeProvider {
|
|||
final min = double.tryParse(responseJSON['min'] as String? ?? '');
|
||||
final max = double.tryParse(responseJSON['max'] as String? ?? '');
|
||||
|
||||
if (isFixedRateMode) {
|
||||
final currentRate = double.parse(responseJSON['rate'] as String);
|
||||
return Limits(
|
||||
min: min != null ? (min * currentRate) : null,
|
||||
max: max != null ? (max * currentRate) : null,
|
||||
);
|
||||
}
|
||||
|
||||
return Limits(min: min, max: max);
|
||||
}
|
||||
|
||||
|
@ -227,8 +259,7 @@ class SideShiftExchangeProvider extends ExchangeProvider {
|
|||
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
||||
final error = responseJSON['error']['message'] as String;
|
||||
|
||||
throw TradeNotFoundException(id,
|
||||
provider: description, description: error);
|
||||
throw TradeNotFoundException(id, provider: description, description: error);
|
||||
}
|
||||
|
||||
if (response.statusCode != 200) {
|
||||
|
@ -236,24 +267,21 @@ class SideShiftExchangeProvider extends ExchangeProvider {
|
|||
}
|
||||
|
||||
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
||||
final fromCurrency = responseJSON['depositMethodId'] as String;
|
||||
final fromCurrency = responseJSON['depositCoin'] as String;
|
||||
final from = CryptoCurrency.fromString(fromCurrency);
|
||||
final toCurrency = responseJSON['settleMethodId'] as String;
|
||||
final toCurrency = responseJSON['settleCoin'] as String;
|
||||
final to = CryptoCurrency.fromString(toCurrency);
|
||||
final inputAddress = responseJSON['depositAddress']['address'] as String;
|
||||
final expectedSendAmount = responseJSON['depositAmount'].toString();
|
||||
final deposits = responseJSON['deposits'] as List?;
|
||||
final settleAddress = responseJSON['settleAddress']['address'] as String;
|
||||
final inputAddress = responseJSON['depositAddress'] as String;
|
||||
final expectedSendAmount = responseJSON['depositAmount'] as String?;
|
||||
final status = responseJSON['status'] as String?;
|
||||
final settleAddress = responseJSON['settleAddress'] as String;
|
||||
TradeState? state;
|
||||
String? status;
|
||||
|
||||
if (deposits?.isNotEmpty ?? false) {
|
||||
status = deposits![0]['status'] as String?;
|
||||
}
|
||||
state = TradeState.deserialize(raw: status ?? 'created');
|
||||
final isVariable = (responseJSON['type'] as String) == 'variable';
|
||||
|
||||
final expiredAtRaw = responseJSON['expiresAtISO'] as String;
|
||||
final expiredAt = DateTime.tryParse(expiredAtRaw)?.toLocal();
|
||||
final expiredAtRaw = responseJSON['expiresAt'] as String;
|
||||
final expiredAt = isVariable ? null : DateTime.tryParse(expiredAtRaw)?.toLocal();
|
||||
|
||||
return Trade(
|
||||
id: id,
|
||||
|
@ -261,11 +289,10 @@ class SideShiftExchangeProvider extends ExchangeProvider {
|
|||
to: to,
|
||||
provider: description,
|
||||
inputAddress: inputAddress,
|
||||
amount: expectedSendAmount,
|
||||
amount: expectedSendAmount ?? '',
|
||||
state: state,
|
||||
expiredAt: expiredAt,
|
||||
payoutAddress: settleAddress
|
||||
);
|
||||
payoutAddress: settleAddress);
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -280,28 +307,25 @@ class SideShiftExchangeProvider extends ExchangeProvider {
|
|||
@override
|
||||
String get title => 'SideShift';
|
||||
|
||||
static String _normalizeCryptoCurrency(CryptoCurrency currency) {
|
||||
switch (currency) {
|
||||
case CryptoCurrency.zaddr:
|
||||
return 'zaddr';
|
||||
case CryptoCurrency.zec:
|
||||
return 'zec';
|
||||
case CryptoCurrency.bnb:
|
||||
return currency.tag!.toLowerCase();
|
||||
case CryptoCurrency.usdterc20:
|
||||
return 'usdtErc20';
|
||||
case CryptoCurrency.usdttrc20:
|
||||
return 'usdtTrc20';
|
||||
case CryptoCurrency.usdcpoly:
|
||||
return 'usdcpolygon';
|
||||
case CryptoCurrency.usdcsol:
|
||||
return 'usdcsol';
|
||||
case CryptoCurrency.maticpoly:
|
||||
String _networkFor(CryptoCurrency currency) =>
|
||||
currency.tag != null ? _normalizeTag(currency.tag!) : 'mainnet';
|
||||
|
||||
String _normalizeTag(String tag) {
|
||||
switch (tag) {
|
||||
case 'ETH':
|
||||
return 'ethereum';
|
||||
case 'TRX':
|
||||
return 'tron';
|
||||
case 'LN':
|
||||
return 'lightning';
|
||||
case 'POLY':
|
||||
return 'polygon';
|
||||
case CryptoCurrency.btcln:
|
||||
return 'ln';
|
||||
case 'ZEC':
|
||||
return 'zcash';
|
||||
case 'AVAXC':
|
||||
return 'avax';
|
||||
default:
|
||||
return currency.title.toLowerCase();
|
||||
return tag.toLowerCase();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,7 +26,12 @@ class TransactionsPage extends StatelessWidget {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
return GestureDetector(
|
||||
onLongPress: () => dashboardViewModel.balanceViewModel.isReversing =
|
||||
!dashboardViewModel.balanceViewModel.isReversing,
|
||||
onLongPressUp: () => dashboardViewModel.balanceViewModel.isReversing =
|
||||
!dashboardViewModel.balanceViewModel.isReversing,
|
||||
child: Container(
|
||||
color: ResponsiveLayoutUtil.instance.isMobile(context)
|
||||
? null
|
||||
: Theme.of(context).colorScheme.background,
|
||||
|
@ -79,17 +84,20 @@ class TransactionsPage extends StatelessWidget {
|
|||
final transactionInfo = item.transaction;
|
||||
|
||||
return AnonpayTransactionRow(
|
||||
onTap: () => Navigator.of(context)
|
||||
.pushNamed(Routes.anonPayDetailsPage, arguments: transactionInfo),
|
||||
onTap: () => Navigator.of(context).pushNamed(
|
||||
Routes.anonPayDetailsPage,
|
||||
arguments: transactionInfo),
|
||||
currency: transactionInfo.fiatAmount != null
|
||||
? transactionInfo.fiatEquiv ?? ''
|
||||
: CryptoCurrency.fromFullName(transactionInfo.coinTo)
|
||||
: CryptoCurrency.fromFullName(
|
||||
transactionInfo.coinTo)
|
||||
.name
|
||||
.toUpperCase(),
|
||||
provider: transactionInfo.provider,
|
||||
amount: transactionInfo.fiatAmount?.toString() ??
|
||||
(transactionInfo.amountTo?.toString() ?? ''),
|
||||
createdAt: DateFormat('HH:mm').format(transactionInfo.createdAt),
|
||||
createdAt: DateFormat('HH:mm')
|
||||
.format(transactionInfo.createdAt),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -98,13 +106,16 @@ class TransactionsPage extends StatelessWidget {
|
|||
|
||||
return Observer(
|
||||
builder: (_) => TradeRow(
|
||||
onTap: () => Navigator.of(context)
|
||||
.pushNamed(Routes.tradeDetails, arguments: trade),
|
||||
onTap: () => Navigator.of(context).pushNamed(
|
||||
Routes.tradeDetails,
|
||||
arguments: trade),
|
||||
provider: trade.provider,
|
||||
from: trade.from,
|
||||
to: trade.to,
|
||||
createdAtFormattedDate: trade.createdAt != null
|
||||
? DateFormat('HH:mm').format(trade.createdAt!)
|
||||
createdAtFormattedDate:
|
||||
trade.createdAt != null
|
||||
? DateFormat('HH:mm')
|
||||
.format(trade.createdAt!)
|
||||
: null,
|
||||
formattedAmount: item.tradeFormattedAmount));
|
||||
}
|
||||
|
@ -115,12 +126,13 @@ class TransactionsPage extends StatelessWidget {
|
|||
return Observer(
|
||||
builder: (_) => OrderRow(
|
||||
onTap: () => Navigator.of(context)
|
||||
.pushNamed(Routes.orderDetails, arguments: order),
|
||||
.pushNamed(Routes.orderDetails,
|
||||
arguments: order),
|
||||
provider: order.provider,
|
||||
from: order.from!,
|
||||
to: order.to!,
|
||||
createdAtFormattedDate:
|
||||
DateFormat('HH:mm').format(order.createdAt),
|
||||
createdAtFormattedDate: DateFormat('HH:mm')
|
||||
.format(order.createdAt),
|
||||
formattedAmount: item.orderFormattedAmount,
|
||||
));
|
||||
}
|
||||
|
@ -132,12 +144,16 @@ class TransactionsPage extends StatelessWidget {
|
|||
S.of(context).placeholder_transactions,
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: Theme.of(context).primaryTextTheme!.labelSmall!.decorationColor!),
|
||||
color: Theme.of(context)
|
||||
.primaryTextTheme
|
||||
.labelSmall!
|
||||
.decorationColor!),
|
||||
),
|
||||
);
|
||||
}))
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -145,7 +145,12 @@ class SendPage extends BasePage {
|
|||
Widget body(BuildContext context) {
|
||||
_setEffects(context);
|
||||
|
||||
return Form(
|
||||
return GestureDetector(
|
||||
onLongPress: () => sendViewModel.balanceViewModel.isReversing =
|
||||
!sendViewModel.balanceViewModel.isReversing,
|
||||
onLongPressUp: () => sendViewModel.balanceViewModel.isReversing =
|
||||
!sendViewModel.balanceViewModel.isReversing,
|
||||
child: Form(
|
||||
key: _formKey,
|
||||
child: ScrollableWithBottomSection(
|
||||
contentPadding: EdgeInsets.only(bottom: 24),
|
||||
|
@ -174,8 +179,8 @@ class SendPage extends BasePage {
|
|||
},
|
||||
)),
|
||||
Padding(
|
||||
padding:
|
||||
EdgeInsets.only(top: 10, left: 24, right: 24, bottom: 10),
|
||||
padding: EdgeInsets.only(
|
||||
top: 10, left: 24, right: 24, bottom: 10),
|
||||
child: Container(
|
||||
height: 10,
|
||||
child: Observer(
|
||||
|
@ -192,10 +197,12 @@ class SendPage extends BasePage {
|
|||
dotWidth: 6.0,
|
||||
dotHeight: 6.0,
|
||||
dotColor: Theme.of(context)
|
||||
.primaryTextTheme!.displaySmall!
|
||||
.primaryTextTheme
|
||||
!.displaySmall!
|
||||
.backgroundColor!,
|
||||
activeDotColor: Theme.of(context)
|
||||
.primaryTextTheme!.displayMedium!
|
||||
.primaryTextTheme
|
||||
!.displayMedium!
|
||||
.backgroundColor!),
|
||||
)
|
||||
: Offstage();
|
||||
|
@ -218,7 +225,8 @@ class SendPage extends BasePage {
|
|||
return Row(
|
||||
children: <Widget>[
|
||||
AddTemplateButton(
|
||||
onTap: () => Navigator.of(context).pushNamed(Routes.sendTemplate),
|
||||
onTap: () => Navigator.of(context)
|
||||
.pushNamed(Routes.sendTemplate),
|
||||
currentTemplatesLength: templates.length,
|
||||
),
|
||||
ListView.builder(
|
||||
|
@ -231,35 +239,52 @@ class SendPage extends BasePage {
|
|||
return TemplateTile(
|
||||
key: UniqueKey(),
|
||||
to: template.name,
|
||||
amount: template.isCurrencySelected ? template.amount : template.amountFiat,
|
||||
from: template.isCurrencySelected ? template.cryptoCurrency : template.fiatCurrency,
|
||||
amount: template.isCurrencySelected
|
||||
? template.amount
|
||||
: template.amountFiat,
|
||||
from: template.isCurrencySelected
|
||||
? template.cryptoCurrency
|
||||
: template.fiatCurrency,
|
||||
onTap: () async {
|
||||
final fiatFromTemplate = FiatCurrency.all.singleWhere((element) => element.title == template.fiatCurrency);
|
||||
final fiatFromTemplate = FiatCurrency
|
||||
.all
|
||||
.singleWhere((element) =>
|
||||
element.title ==
|
||||
template.fiatCurrency);
|
||||
final output = _defineCurrentOutput();
|
||||
output.address = template.address;
|
||||
if(template.isCurrencySelected){
|
||||
output.setCryptoAmount(template.amount);
|
||||
}else{
|
||||
sendViewModel.setFiatCurrency(fiatFromTemplate);
|
||||
output.setFiatAmount(template.amountFiat);
|
||||
if (template.isCurrencySelected) {
|
||||
output
|
||||
.setCryptoAmount(template.amount);
|
||||
} else {
|
||||
sendViewModel.setFiatCurrency(
|
||||
fiatFromTemplate);
|
||||
output.setFiatAmount(
|
||||
template.amountFiat);
|
||||
}
|
||||
output.resetParsedAddress();
|
||||
await output.fetchParsedAddress(context);
|
||||
await output
|
||||
.fetchParsedAddress(context);
|
||||
},
|
||||
onRemove: () {
|
||||
showPopUp<void>(
|
||||
context: context,
|
||||
builder: (dialogContext) {
|
||||
return AlertWithTwoActions(
|
||||
alertTitle: S.of(context).template,
|
||||
alertTitle:
|
||||
S.of(context).template,
|
||||
alertContent: S
|
||||
.of(context)
|
||||
.confirm_delete_template,
|
||||
rightButtonText: S.of(context).delete,
|
||||
leftButtonText: S.of(context).cancel,
|
||||
rightButtonText:
|
||||
S.of(context).delete,
|
||||
leftButtonText:
|
||||
S.of(context).cancel,
|
||||
actionRightButton: () {
|
||||
Navigator.of(dialogContext).pop();
|
||||
sendViewModel.sendTemplateViewModel
|
||||
Navigator.of(dialogContext)
|
||||
.pop();
|
||||
sendViewModel
|
||||
.sendTemplateViewModel
|
||||
.removeTemplate(
|
||||
template: template);
|
||||
},
|
||||
|
@ -286,19 +311,19 @@ class SendPage extends BasePage {
|
|||
bottomSection: Column(
|
||||
children: [
|
||||
if (sendViewModel.hasCurrecyChanger)
|
||||
Observer(builder: (_) =>
|
||||
Padding(
|
||||
Observer(
|
||||
builder: (_) => Padding(
|
||||
padding: EdgeInsets.only(bottom: 12),
|
||||
child: PrimaryButton(
|
||||
onPressed: () => presentCurrencyPicker(context),
|
||||
text: 'Change your asset (${sendViewModel.selectedCryptoCurrency})',
|
||||
text:
|
||||
'Change your asset (${sendViewModel.selectedCryptoCurrency})',
|
||||
color: Colors.transparent,
|
||||
textColor: Theme.of(context)
|
||||
.accentTextTheme!.displaySmall!
|
||||
.accentTextTheme
|
||||
!.displaySmall!
|
||||
.decorationColor!,
|
||||
)
|
||||
)
|
||||
),
|
||||
))),
|
||||
if (sendViewModel.hasMultiRecipient)
|
||||
Padding(
|
||||
padding: EdgeInsets.only(bottom: 12),
|
||||
|
@ -306,24 +331,28 @@ class SendPage extends BasePage {
|
|||
onPressed: () {
|
||||
sendViewModel.addOutput();
|
||||
Future.delayed(const Duration(milliseconds: 250), () {
|
||||
controller.jumpToPage(sendViewModel.outputs.length - 1);
|
||||
controller
|
||||
.jumpToPage(sendViewModel.outputs.length - 1);
|
||||
});
|
||||
},
|
||||
text: S.of(context).add_receiver,
|
||||
color: Colors.transparent,
|
||||
textColor: Theme.of(context)
|
||||
.accentTextTheme!.displaySmall!
|
||||
.accentTextTheme
|
||||
!.displaySmall!
|
||||
.decorationColor!,
|
||||
isDottedBorder: true,
|
||||
borderColor: Theme.of(context)
|
||||
.primaryTextTheme!.displaySmall!
|
||||
.primaryTextTheme
|
||||
!.displaySmall!
|
||||
.decorationColor!,
|
||||
)),
|
||||
Observer(
|
||||
builder: (_) {
|
||||
return LoadingPrimaryButton(
|
||||
onPressed: () async {
|
||||
if (_formKey.currentState != null && !_formKey.currentState!.validate()) {
|
||||
if (_formKey.currentState != null &&
|
||||
!_formKey.currentState!.validate()) {
|
||||
if (sendViewModel.outputs.length > 1) {
|
||||
showErrorValidationAlert(context);
|
||||
}
|
||||
|
@ -333,7 +362,8 @@ class SendPage extends BasePage {
|
|||
|
||||
final notValidItems = sendViewModel.outputs
|
||||
.where((item) =>
|
||||
item.address.isEmpty || item.cryptoAmount.isEmpty)
|
||||
item.address.isEmpty ||
|
||||
item.cryptoAmount.isEmpty)
|
||||
.toList();
|
||||
|
||||
if (notValidItems.isNotEmpty ?? false) {
|
||||
|
@ -342,10 +372,10 @@ class SendPage extends BasePage {
|
|||
}
|
||||
|
||||
await sendViewModel.createTransaction();
|
||||
|
||||
},
|
||||
text: S.of(context).send,
|
||||
color: Theme.of(context).accentTextTheme!.bodyLarge!.color!,
|
||||
color:
|
||||
Theme.of(context).accentTextTheme!.bodyLarge!.color!,
|
||||
textColor: Colors.white,
|
||||
isLoading: sendViewModel.state is IsExecutingState ||
|
||||
sendViewModel.state is TransactionCommitting,
|
||||
|
@ -355,6 +385,7 @@ class SendPage extends BasePage {
|
|||
)
|
||||
],
|
||||
)),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -389,10 +420,12 @@ class SendPage extends BasePage {
|
|||
amount: S.of(context).send_amount,
|
||||
amountValue:
|
||||
sendViewModel.pendingTransaction!.amountFormatted,
|
||||
fiatAmountValue: sendViewModel.pendingTransactionFiatAmountFormatted,
|
||||
fiatAmountValue:
|
||||
sendViewModel.pendingTransactionFiatAmountFormatted,
|
||||
fee: S.of(context).send_fee,
|
||||
feeValue: sendViewModel.pendingTransaction!.feeFormatted,
|
||||
feeFiatAmount: sendViewModel.pendingTransactionFeeFiatAmountFormatted,
|
||||
feeFiatAmount: sendViewModel
|
||||
.pendingTransactionFeeFiatAmountFormatted,
|
||||
outputs: sendViewModel.outputs,
|
||||
rightButtonText: S.of(context).ok,
|
||||
leftButtonText: S.of(context).cancel,
|
||||
|
@ -413,7 +446,8 @@ class SendPage extends BasePage {
|
|||
return AlertWithOneAction(
|
||||
alertTitle: '',
|
||||
alertContent: S.of(context).send_success(
|
||||
sendViewModel.selectedCryptoCurrency.toString()),
|
||||
sendViewModel.selectedCryptoCurrency
|
||||
.toString()),
|
||||
buttonText: S.of(context).ok,
|
||||
buttonAction: () {
|
||||
Navigator.of(context).pop();
|
||||
|
@ -466,10 +500,12 @@ class SendPage extends BasePage {
|
|||
builder: (_) => Picker(
|
||||
items: sendViewModel.currencies,
|
||||
displayItem: (Object item) => item.toString(),
|
||||
selectedAtIndex: sendViewModel.currencies.indexOf(sendViewModel.selectedCryptoCurrency),
|
||||
selectedAtIndex: sendViewModel.currencies
|
||||
.indexOf(sendViewModel.selectedCryptoCurrency),
|
||||
title: S.of(context).please_select,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
onItemSelected: (CryptoCurrency cur) => sendViewModel.selectedCryptoCurrency = cur,
|
||||
onItemSelected: (CryptoCurrency cur) =>
|
||||
sendViewModel.selectedCryptoCurrency = cur,
|
||||
),
|
||||
context: context);
|
||||
}
|
||||
|
|
|
@ -149,12 +149,26 @@ class WalletListBodyState extends State<WalletListBody> {
|
|||
|
||||
return wallet.isCurrent
|
||||
? row
|
||||
: Slidable(
|
||||
key: Key('${wallet.key}'),
|
||||
startActionPane: _actionPane(wallet),
|
||||
endActionPane: _actionPane(wallet),
|
||||
child: row,
|
||||
);
|
||||
: Row(children: [
|
||||
Expanded(child: row),
|
||||
GestureDetector(
|
||||
onTap: () => _removeWallet(wallet),
|
||||
child: Container(
|
||||
height: 40,
|
||||
width: 44,
|
||||
padding: EdgeInsets.only(right: 20),
|
||||
child: Center(
|
||||
child: Image.asset('assets/images/trash.png',
|
||||
height: 16,
|
||||
width: 16,
|
||||
color: Theme.of(context)
|
||||
.primaryTextTheme
|
||||
.titleLarge!
|
||||
.color),
|
||||
),
|
||||
),
|
||||
)
|
||||
]);
|
||||
}),
|
||||
),
|
||||
),
|
||||
|
@ -277,18 +291,4 @@ class WalletListBodyState extends State<WalletListBody> {
|
|||
_progressBar = null;
|
||||
});
|
||||
}
|
||||
|
||||
ActionPane _actionPane(WalletListItem wallet) => ActionPane(
|
||||
motion: const ScrollMotion(),
|
||||
extentRatio: 0.3,
|
||||
children: [
|
||||
SlidableAction(
|
||||
onPressed: (_) => _removeWallet(wallet),
|
||||
backgroundColor: Colors.red,
|
||||
foregroundColor: Colors.white,
|
||||
icon: CupertinoIcons.delete,
|
||||
label: S.of(context).delete,
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
|
|
@ -13,7 +13,6 @@ import 'package:cake_wallet/view_model/dashboard/balance_view_model.dart';
|
|||
import 'package:cw_core/keyable.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
|
||||
|
||||
class TransactionListItem extends ActionListItem with Keyable {
|
||||
TransactionListItem(
|
||||
{required this.transaction,
|
||||
|
@ -28,7 +27,7 @@ class TransactionListItem extends ActionListItem with Keyable {
|
|||
|
||||
FiatCurrency get fiatCurrency => settingsStore.fiatCurrency;
|
||||
|
||||
BalanceDisplayMode get displayMode => settingsStore.balanceDisplayMode;
|
||||
BalanceDisplayMode get displayMode => balanceViewModel.displayMode;
|
||||
|
||||
@override
|
||||
dynamic get keyIndex => transaction.id;
|
||||
|
|
|
@ -114,6 +114,10 @@ abstract class ExchangeTradeViewModelBase with Store {
|
|||
updatedTrade.createdAt = trade.createdAt;
|
||||
}
|
||||
|
||||
if (updatedTrade.amount.isEmpty) {
|
||||
updatedTrade.amount = trade.amount;
|
||||
}
|
||||
|
||||
trade = updatedTrade;
|
||||
|
||||
_updateItems();
|
||||
|
@ -123,7 +127,8 @@ abstract class ExchangeTradeViewModelBase with Store {
|
|||
}
|
||||
|
||||
void _updateItems() {
|
||||
final tagFrom = tradesStore.trade!.from.tag != null ? '${tradesStore.trade!.from.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(
|
||||
|
|
|
@ -443,7 +443,9 @@ abstract class ExchangeViewModelBase with Store {
|
|||
request = SideShiftRequest(
|
||||
depositMethod: depositCurrency,
|
||||
settleMethod: receiveCurrency,
|
||||
depositAmount: depositAmount.replaceAll(',', '.'),
|
||||
depositAmount: isFixedRateMode
|
||||
? receiveAmount.replaceAll(',', '.')
|
||||
: depositAmount.replaceAll(',', '.'),
|
||||
settleAddress: receiveAddress,
|
||||
refundAddress: depositAddress,
|
||||
);
|
||||
|
|
|
@ -20,7 +20,6 @@ class SecretKey {
|
|||
SecretKey('moonPayApiKey', () => ''),
|
||||
SecretKey('moonPaySecretKey', () => ''),
|
||||
SecretKey('sideShiftAffiliateId', () => ''),
|
||||
SecretKey('sideShiftApiKey', () => ''),
|
||||
SecretKey('simpleSwapApiKey', () => ''),
|
||||
SecretKey('simpleSwapApiKeyDesktop', () => ''),
|
||||
SecretKey('anypayToken', () => ''),
|
||||
|
|
Loading…
Reference in a new issue