fetch fiat rate from dashboard page

This commit is contained in:
Serhii 2023-05-19 09:30:47 +03:00
parent 3eb297f953
commit 2d4a6824bb
5 changed files with 147 additions and 113 deletions

View file

@ -50,7 +50,7 @@ Future<double> _fetchPrice(Map<String, dynamic> args) async {
}
}
Future<double> _fetchHistoricalPrice(Map<String, dynamic> args) async {
Future<double?> _fetchHistoricalPrice(Map<String, dynamic> args) async {
final crypto = args['crypto'] as CryptoCurrency;
final fiat = args['fiat'] as FiatCurrency;
final torOnly = args['torOnly'] as bool;
@ -77,35 +77,28 @@ Future<double> _fetchHistoricalPrice(Map<String, dynamic> args) async {
final response = await get(uri);
if (response.statusCode != 200) {
return 0.0;
}
if (response.statusCode != 200) return null;
final data = json.decode(response.body) as Map<String, dynamic>;
final errors = data['errors'] as Map<String, dynamic>;
if (errors.isNotEmpty) {
return 0.0;
}
if (errors.isNotEmpty) return 0.0;
final results = data['results'] as Map<String, dynamic>;
if (results.isNotEmpty) {
price = results.values.first as double;
}
print('results.key: ${results.keys.first} results.value: ${results.values.first}');
if (results.isNotEmpty) price = results.values.first as double;
return price;
} catch (e) {
print(e.toString());
return 0.0;
return null;
}
}
Future<double> _fetchPriceAsync(CryptoCurrency crypto, FiatCurrency fiat, bool torOnly) async =>
compute(_fetchPrice, {'fiat': fiat, 'crypto': crypto, 'torOnly': torOnly});
Future<double> _fetchHistoricalAsync(
Future<double?> _fetchHistoricalAsync(
CryptoCurrency crypto, FiatCurrency fiat, bool torOnly, DateTime date) async =>
compute(
_fetchHistoricalPrice, {'fiat': fiat, 'crypto': crypto, 'torOnly': torOnly, 'date': date});
@ -118,7 +111,7 @@ class FiatConversionService {
}) async =>
await _fetchPriceAsync(crypto, fiat, torOnly);
static Future<double> fetchHistoricalPrice({
static Future<double?> fetchHistoricalPrice({
required CryptoCurrency crypto,
required FiatCurrency fiat,
required bool torOnly,

View file

@ -349,7 +349,9 @@ Future setup(
settingsStore: settingsStore,
yatStore: getIt.get<YatStore>(),
ordersStore: getIt.get<OrdersStore>(),
anonpayTransactionsStore: getIt.get<AnonpayTransactionsStore>())
anonpayTransactionsStore: getIt.get<AnonpayTransactionsStore>(),
transactionDescriptionBox: _transactionDescriptionBox,
)
);
getIt.registerFactory<AuthService>(() => AuthService(

View file

@ -4,7 +4,12 @@ part 'transaction_description.g.dart';
@HiveType(typeId: TransactionDescription.typeId)
class TransactionDescription extends HiveObject {
TransactionDescription({required this.id, this.recipientAddress, this.transactionNote});
TransactionDescription(
{required this.id,
this.recipientAddress,
this.transactionNote,
this.historicalFiatRaw,
this.historicalFiatRate});
static const typeId = 2;
static const boxName = 'TransactionDescriptions';
@ -19,5 +24,13 @@ class TransactionDescription extends HiveObject {
@HiveField(2)
String? transactionNote;
@HiveField(3)
String? historicalFiatRaw;
@HiveField(4)
double? historicalFiatRate;
String get note => transactionNote ?? '';
String get historicalFiat => historicalFiatRaw ?? '';
}

View file

@ -1,7 +1,13 @@
import 'package:cake_wallet/core/fiat_conversion_service.dart';
import 'package:cake_wallet/entities/exchange_api_mode.dart';
import 'package:cake_wallet/entities/fiat_api_mode.dart';
import 'package:cake_wallet/entities/fiat_currency.dart';
import 'package:cake_wallet/entities/transaction_description.dart';
import 'package:cake_wallet/store/anonpay/anonpay_transactions_store.dart';
import 'package:cake_wallet/view_model/dashboard/anonpay_transaction_list_item.dart';
import 'package:cake_wallet/wallet_type_utils.dart';
import 'package:cw_bitcoin/bitcoin_amount_format.dart';
import 'package:cw_core/monero_amount_format.dart';
import 'package:cw_core/transaction_history.dart';
import 'package:cw_core/balance.dart';
import 'package:cake_wallet/entities/balance_display_mode.dart';
@ -17,6 +23,7 @@ import 'package:cake_wallet/view_model/dashboard/order_list_item.dart';
import 'package:cake_wallet/view_model/dashboard/trade_list_item.dart';
import 'package:cake_wallet/view_model/dashboard/transaction_list_item.dart';
import 'package:cake_wallet/view_model/dashboard/action_list_item.dart';
import 'package:hive/hive.dart';
import 'package:mobx/mobx.dart';
import 'package:cw_core/wallet_base.dart';
import 'package:cw_core/sync_status.dart';
@ -43,6 +50,7 @@ abstract class DashboardViewModelBase with Store {
required this.settingsStore,
required this.yatStore,
required this.ordersStore,
required this.transactionDescriptionBox,
required this.anonpayTransactionsStore})
: isOutdatedElectrumWallet = false,
hasSellAction = false,
@ -116,6 +124,15 @@ abstract class DashboardViewModelBase with Store {
final _wallet = wallet;
reaction((_) => settingsStore.fiatCurrency,
(FiatCurrency fiatCurrency) {
_wallet.transactionHistory.transactions.values.forEach((tx) {
_getHistoricalFiatRate(tx);
});
});
if (_wallet.type == WalletType.monero) {
subname = monero!.getCurrentAccount(_wallet).label;
@ -130,11 +147,16 @@ abstract class DashboardViewModelBase with Store {
.where((tx) => monero!.getTransactionInfoAccountId(tx) == monero!.getCurrentAccount(wallet).id)
.toList();
transactions = ObservableList.of(_accountTransactions.map((transaction) =>
TransactionListItem(
transaction: transaction,
balanceViewModel: balanceViewModel,
settingsStore: appStore.settingsStore)));
transactions = ObservableList.of(_accountTransactions.map((transaction) {
_getHistoricalFiatRate(transaction);
return TransactionListItem(
transaction: transaction,
balanceViewModel: balanceViewModel,
settingsStore: appStore.settingsStore);
}));
} else {
transactions = ObservableList.of(wallet
.transactionHistory.transactions.values
@ -154,6 +176,11 @@ abstract class DashboardViewModelBase with Store {
balanceViewModel: balanceViewModel,
settingsStore: appStore.settingsStore),
filter: (TransactionInfo? transaction) {
_wallet.transactionHistory.transactions.values.forEach((tx) {
_getHistoricalFiatRate(tx);
});
if (transaction == null) {
return false;
}
@ -273,6 +300,8 @@ abstract class DashboardViewModelBase with Store {
Map<String, List<FilterItem>> filterItems;
final Box<TransactionDescription> transactionDescriptionBox;
bool get isBuyEnabled => settingsStore.isBitcoinBuyEnabled;
bool get shouldShowYatPopup => settingsStore.shouldShowYatPopup;
@ -327,6 +356,11 @@ abstract class DashboardViewModelBase with Store {
wallet.type == WalletType.bitcoin && wallet.seed.split(' ').length < 24;
updateActions();
wallet.transactionHistory.transactions.values.forEach((tx) {
_getHistoricalFiatRate(tx);
});
if (wallet.type == WalletType.monero) {
subname = monero!.getCurrentAccount(wallet).label;
@ -383,6 +417,7 @@ abstract class DashboardViewModelBase with Store {
@action
void _onMoneroTransactionsUpdate(WalletBase wallet) {
transactions.clear();
final _accountTransactions = monero!.getTransactionHistory(wallet).transactions.values
@ -405,4 +440,49 @@ abstract class DashboardViewModelBase with Store {
&& wallet.type != WalletType.litecoin;
hasSellAction = !isHaven;
}
Future<void> _getHistoricalFiatRate(TransactionInfo transactionInfo) async {
final description = transactionDescriptionBox.values.firstWhere(
(val) => val.id == transactionInfo.id,
orElse: () => TransactionDescription(id: transactionInfo.id));
if (description.historicalFiat != settingsStore.fiatCurrency.toString()
|| description.historicalFiatRate == null) {
if (description.key == 0) description.delete();
description.historicalFiatRate = null;
transactionDescriptionBox.put(description.id, description);
final fiat = settingsStore.fiatCurrency;
final historicalFiatRate = await FiatConversionService.fetchHistoricalPrice(
crypto: wallet.currency,
fiat: fiat,
torOnly: settingsStore.fiatApiMode == FiatApiMode.torOnly,
date: transactionInfo.date);
var formattedFiatAmount = 0.0;
switch (wallet.type) {
case WalletType.bitcoin:
case WalletType.litecoin:
formattedFiatAmount = bitcoinAmountToDouble(amount: transactionInfo.amount);
break;
case WalletType.monero:
case WalletType.haven:
formattedFiatAmount = moneroAmountToDouble(amount: transactionInfo.amount);
break;
default:
formattedFiatAmount;
}
description.historicalFiatRaw = settingsStore.fiatCurrency.toString();
if (historicalFiatRate != null) {
final historicalFiatAmountFormatted = formattedFiatAmount * historicalFiatRate;
if (description.key == 0) description.delete();
description.historicalFiatRate = historicalFiatAmountFormatted;
transactionDescriptionBox.put(description.id, description);
} else {
if (description.key == 0) description.delete();
description.historicalFiatRate = null;
transactionDescriptionBox.put(description.id, description);
}
}
}
}

View file

@ -31,8 +31,8 @@ abstract class TransactionDetailsViewModelBase with Store {
required this.wallet,
required this.settingsStore})
: items = ObservableList<TransactionDetailsListItem>(),
isRecipientAddressShown = false,
showRecipientAddress = settingsStore.shouldSaveRecipientAddress {
isRecipientAddressShown = false,
showRecipientAddress = settingsStore.shouldSaveRecipientAddress {
final dateFormat = DateFormatter.withCurrentLocal();
final tx = transactionInfo;
@ -42,19 +42,13 @@ abstract class TransactionDetailsViewModelBase with Store {
final addressIndex = tx.additionalInfo['addressIndex'] as int;
final feeFormatted = tx.feeFormatted();
final _items = [
StandartListItem(title: S.current.transaction_details_transaction_id, value: tx.id),
StandartListItem(
title: S.current.transaction_details_transaction_id, value: tx.id),
StandartListItem(
title: S.current.transaction_details_date,
value: dateFormat.format(tx.date)),
StandartListItem(
title: S.current.transaction_details_height, value: '${tx.height}'),
StandartListItem(
title: S.current.transaction_details_amount,
value: tx.amountFormatted()),
title: S.current.transaction_details_date, value: dateFormat.format(tx.date)),
StandartListItem(title: S.current.transaction_details_height, value: '${tx.height}'),
StandartListItem(title: S.current.transaction_details_amount, value: tx.amountFormatted()),
if (feeFormatted != null)
StandartListItem(
title: S.current.transaction_details_fee, value: feeFormatted),
StandartListItem(title: S.current.transaction_details_fee, value: feeFormatted),
if (key?.isNotEmpty ?? false)
StandartListItem(title: S.current.transaction_key, value: key!)
];
@ -68,18 +62,12 @@ abstract class TransactionDetailsViewModelBase with Store {
if (address?.isNotEmpty ?? false) {
isRecipientAddressShown = true;
_items.add(
StandartListItem(
title: S.current.transaction_details_recipient_address,
value: address));
_items.add(StandartListItem(
title: S.current.transaction_details_recipient_address, value: address));
}
if (label?.isNotEmpty ?? false) {
_items.add(
StandartListItem(
title: S.current.address_label,
value: label)
);
_items.add(StandartListItem(title: S.current.address_label, value: label));
}
} catch (e) {
print(e.toString());
@ -89,26 +77,16 @@ abstract class TransactionDetailsViewModelBase with Store {
items.addAll(_items);
}
if (wallet.type == WalletType.bitcoin
|| wallet.type == WalletType.litecoin) {
if (wallet.type == WalletType.bitcoin || wallet.type == WalletType.litecoin) {
final _items = [
StandartListItem(title: S.current.transaction_details_transaction_id, value: tx.id),
StandartListItem(
title: S.current.transaction_details_transaction_id, value: tx.id),
StandartListItem(
title: S.current.transaction_details_date,
value: dateFormat.format(tx.date)),
StandartListItem(
title: S.current.confirmations,
value: tx.confirmations.toString()),
StandartListItem(
title: S.current.transaction_details_height, value: '${tx.height}'),
StandartListItem(
title: S.current.transaction_details_amount,
value: tx.amountFormatted()),
title: S.current.transaction_details_date, value: dateFormat.format(tx.date)),
StandartListItem(title: S.current.confirmations, value: tx.confirmations.toString()),
StandartListItem(title: S.current.transaction_details_height, value: '${tx.height}'),
StandartListItem(title: S.current.transaction_details_amount, value: tx.amountFormatted()),
if (tx.feeFormatted()?.isNotEmpty ?? false)
StandartListItem(
title: S.current.transaction_details_fee,
value: tx.feeFormatted()!)
StandartListItem(title: S.current.transaction_details_fee, value: tx.feeFormatted()!)
];
items.addAll(_items);
@ -116,19 +94,13 @@ abstract class TransactionDetailsViewModelBase with Store {
if (wallet.type == WalletType.haven) {
items.addAll([
StandartListItem(title: S.current.transaction_details_transaction_id, value: tx.id),
StandartListItem(
title: S.current.transaction_details_transaction_id, value: tx.id),
StandartListItem(
title: S.current.transaction_details_date,
value: dateFormat.format(tx.date)),
StandartListItem(
title: S.current.transaction_details_height, value: '${tx.height}'),
StandartListItem(
title: S.current.transaction_details_amount,
value: tx.amountFormatted()),
title: S.current.transaction_details_date, value: dateFormat.format(tx.date)),
StandartListItem(title: S.current.transaction_details_height, value: '${tx.height}'),
StandartListItem(title: S.current.transaction_details_amount, value: tx.amountFormatted()),
if (tx.feeFormatted()?.isNotEmpty ?? false)
StandartListItem(
title: S.current.transaction_details_fee, value: tx.feeFormatted()!)
StandartListItem(title: S.current.transaction_details_fee, value: tx.feeFormatted()!)
]);
}
@ -140,10 +112,9 @@ abstract class TransactionDetailsViewModelBase with Store {
if (recipientAddress?.isNotEmpty ?? false) {
items.add(StandartListItem(
title: S.current.transaction_details_recipient_address,
value: recipientAddress!));
title: S.current.transaction_details_recipient_address, value: recipientAddress!));
}
} catch(_) {
} catch (_) {
// FIX-ME: Unhandled exception
}
}
@ -175,8 +146,20 @@ abstract class TransactionDetailsViewModelBase with Store {
transactionDescriptionBox.add(description);
}
}));
if (settingsStore.showHistoricalFiatRate) {
getHistoricalFiatRate();
if (settingsStore.showHistoricalFiatRate &&
description.historicalFiatRate != null &&
description.historicalFiatRate! > 0) {
final index =
items.indexWhere((element) => element.title == S.current.transaction_details_fee);
items.insert(
index + 1,
StandartListItem(
title: S.current.historical_fiat_rate,
value: description.historicalFiatRate!.toStringAsFixed(2) +
' ' +
settingsStore.fiatCurrency.toString()));
}
}
@ -189,43 +172,6 @@ abstract class TransactionDetailsViewModelBase with Store {
bool showRecipientAddress;
bool isRecipientAddressShown;
@action
Future<void> getHistoricalFiatRate() async {
if (settingsStore.fiatApiMode != FiatApiMode.disabled && settingsStore.showHistoricalFiatRate) {
var fiatRateItemIndex =
items.indexWhere((element) => element.title == S.current.transaction_details_fee);
fiatRateItemIndex = fiatRateItemIndex == -1 ? items.length - 3 : fiatRateItemIndex;
final fiat = settingsStore.fiatCurrency;
final historicalFiatRate = await FiatConversionService.fetchHistoricalPrice(
crypto: wallet.currency,
fiat: fiat,
torOnly: settingsStore.fiatApiMode == FiatApiMode.torOnly,
date: transactionInfo.date);
var formattedFiatAmount = 0.0;
switch (wallet.type) {
case WalletType.bitcoin:
case WalletType.litecoin:
formattedFiatAmount = bitcoinAmountToDouble(amount: transactionInfo.amount);
break;
case WalletType.monero:
case WalletType.haven:
formattedFiatAmount = moneroAmountToDouble(amount: transactionInfo.amount);
break;
default:
formattedFiatAmount;
}
final historicalFiatAmountFormatted = formattedFiatAmount * historicalFiatRate;
if (historicalFiatAmountFormatted > 0.0)
items.insert(
fiatRateItemIndex + 1,
StandartListItem(
title: S.current.historical_fiat_rate,
value: historicalFiatAmountFormatted.toStringAsFixed(2) + ' ${fiat}'));
}
}
String _explorerUrl(WalletType type, String txId) {
switch (type) {
case WalletType.monero: