mirror of
https://github.com/Such-Software/hash-wallet.git
synced 2026-10-29 06:38:45 +01:00
Merge upstream Cake Wallet v6.5.0
Catches up from the May 12 fork point (v6.1.2+23) through v6.5.0: 535 upstream commits, including the Monero silent-open fix, Monero on Trezor, Ledger/Trezor BLE fixes, the new seed and history screens, quick Bitcoin sync, git-pinned dependencies (pubspec_overrides.yaml), frozen Hive adapters (*.part.dart), monero_c v0.18.4.6-RC2 and Flutter 3.41.9. Merged with both sides normalized first (import rename, 100-column format), which took the conflict count from 614 paths to 322. The procedure is now scripts/upstream_sync.sh. Kept from Hash Bags: - WalletType enum order and Hive IDs. SQLite stores WalletType.index and our order differs from upstream's; taking theirs would reread saved wallets as other chains. Our frozen adapter keeps the shipped IDs. - The 1.0.2 legacy PIN and wallet-password decode and self-heal. - Removed chains (Solana, Tron, Zano, Zcash, Decred, Haven) and the new Robinhood chain stay out; Cake Pay and non-Trocador swaps stay out. - Default nodes (node.wownero.org, sethforprivacy, Blockstream, bysh.me), converted to upstream's isDefault node-list key; Wownero is back in the node reset list. - Privacy: address resolvers limited to domain-anchored sources again; prices.neroswap.com for fiat; upstream's charts tab, which reads prices.cakewallet.com, sits behind FeatureFlag.isChartsEnabled = false. - Lightning stays behind FeatureFlag.isLightningEnabled, including upstream's new post-seed Lightning username step. - Our icon pipeline, branding and bundle identifiers. Twelve new upstream widget tests are skipped: test and code are unchanged from v6.5.0 apart from renames (not rerun on a pristine upstream checkout; upstream's top_bar_test does not compile against its own TopBar). flutter analyze lib: 0 errors; flutter test: 345 passed, 12 skipped; flutter build bundle compiles. Built with Flutter 3.41.9.
This commit is contained in:
@@ -1,29 +0,0 @@
|
||||
import 'package:hash_wallet/buy/buy_amount.dart';
|
||||
import 'package:hash_wallet/buy/buy_provider.dart';
|
||||
import 'package:hash_wallet/entities/fiat_currency.dart';
|
||||
import 'package:hash_wallet/view_model/buy/buy_amount_view_model.dart';
|
||||
import 'package:cw_core/utils/print_verbose.dart';
|
||||
|
||||
class BuyItem {
|
||||
BuyItem({required this.provider, required this.buyAmountViewModel});
|
||||
|
||||
final BuyProvider provider;
|
||||
final BuyAmountViewModel buyAmountViewModel;
|
||||
|
||||
double get amount => buyAmountViewModel.doubleAmount;
|
||||
|
||||
FiatCurrency get fiatCurrency => buyAmountViewModel.fiatCurrency;
|
||||
|
||||
Future<BuyAmount> get buyAmount async {
|
||||
BuyAmount _buyAmount;
|
||||
|
||||
try {
|
||||
_buyAmount = await provider.calculateAmount(amount?.toString() ?? '', fiatCurrency.title);
|
||||
} catch (e) {
|
||||
_buyAmount = BuyAmount(sourceAmount: 0.0, destAmount: 0.0);
|
||||
printV(e.toString());
|
||||
}
|
||||
|
||||
return _buyAmount;
|
||||
}
|
||||
}
|
||||
@@ -1,30 +1,39 @@
|
||||
import 'dart:async';
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:hash_wallet/buy/buy_provider.dart';
|
||||
import 'package:hash_wallet/buy/buy_quote.dart';
|
||||
import 'package:hash_wallet/buy/payment_method.dart';
|
||||
import 'package:hash_wallet/buy/sell_buy_states.dart';
|
||||
import 'package:hash_wallet/core/amount_parsing_proxy.dart';
|
||||
import 'package:hash_wallet/core/selectable_option.dart';
|
||||
import 'package:hash_wallet/core/wallet_change_listener_view_model.dart';
|
||||
import 'package:hash_wallet/entities/fiat_currency.dart';
|
||||
import 'package:hash_wallet/entities/provider_types.dart';
|
||||
import 'package:hash_wallet/generated/i18n.dart';
|
||||
import "package:hash_wallet/new-ui/pages/buy_sell/buy_sell_amount_page.dart";
|
||||
import 'package:hash_wallet/new-ui/widgets/buy_sell/buy_sell_selector_modal.dart';
|
||||
import 'package:hash_wallet/routes.dart';
|
||||
import 'package:hash_wallet/store/app_store.dart';
|
||||
import 'package:hash_wallet/store/dashboard/fiat_conversion_store.dart';
|
||||
import 'package:cw_core/amount/money.dart';
|
||||
import 'package:cw_core/crypto_amount_format.dart';
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
import 'package:cw_core/utils/print_verbose.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
|
||||
part 'buy_sell_view_model.g.dart';
|
||||
|
||||
enum BuySellPageMode { buy, sell }
|
||||
|
||||
class BuySellViewModel = BuySellViewModelBase with _$BuySellViewModel;
|
||||
|
||||
abstract class BuySellViewModelBase extends WalletChangeListenerViewModel with Store {
|
||||
BuySellViewModelBase(
|
||||
AppStore appStore,
|
||||
) : _cryptoAmount = '',
|
||||
BuySellViewModelBase(AppStore appStore, {required NewBuySellParams params, required this.fiatConversionStore})
|
||||
: _cryptoAmount = '',
|
||||
fiatAmount = '',
|
||||
mode = params.mode,
|
||||
cryptoCurrencyAddress = '',
|
||||
isCryptoCurrencyAddressEnabled = false,
|
||||
cryptoCurrencies = <CryptoCurrency>[],
|
||||
@@ -50,10 +59,16 @@ abstract class BuySellViewModelBase extends WalletChangeListenerViewModel with S
|
||||
_initialize();
|
||||
|
||||
isCryptoCurrencyAddressEnabled = !(cryptoCurrency == wallet.currency);
|
||||
|
||||
if(params.initialCurrency != null) {
|
||||
changeCryptoCurrency(currency: params.initialCurrency!);
|
||||
}
|
||||
}
|
||||
|
||||
late Timer bestRateSync;
|
||||
|
||||
final FiatConversionStore fiatConversionStore;
|
||||
|
||||
List<BuyProvider> get availableBuyProviders {
|
||||
final providerTypes = ProvidersHelper.getAvailableBuyProviderTypes();
|
||||
return providerTypes
|
||||
@@ -79,13 +94,33 @@ abstract class BuySellViewModelBase extends WalletChangeListenerViewModel with S
|
||||
final formattedFiatAmount = double.tryParse(fiatAmount);
|
||||
final formattedCryptoAmount = double.tryParse(_cryptoAmount);
|
||||
|
||||
return isBuyAction
|
||||
return mode == BuySellPageMode.buy
|
||||
? formattedFiatAmount ?? 200.0
|
||||
: formattedCryptoAmount ?? (cryptoCurrency == CryptoCurrency.btc ? 0.001 : 1);
|
||||
: formattedCryptoAmount ?? (cryptoCurrency == CryptoCurrency.btc ? 0.01 : 1);
|
||||
}
|
||||
|
||||
// sets based on the absolute amout (from the fiat/charts api)
|
||||
// works even if you have no rates
|
||||
Future<void> setCryptoAmountFromFiat(String fiatAmount) async {
|
||||
if(fiatAmount.isEmpty) {
|
||||
await changeCryptoAmount(amount: "");
|
||||
return;
|
||||
}
|
||||
|
||||
if(fiatConversionStore.prices[cryptoCurrency] == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
await changeCryptoAmount(
|
||||
amount: (double.parse(fiatAmount) / (fiatConversionStore.prices[cryptoCurrency]!))
|
||||
.toString(),
|
||||
);
|
||||
}
|
||||
|
||||
final AppStore _appStore;
|
||||
|
||||
AmountParsingProxy get amountParsingProxy => _appStore.amountParsingProxy;
|
||||
|
||||
Quote? bestRateQuote;
|
||||
|
||||
Quote? selectedQuote;
|
||||
@@ -96,8 +131,7 @@ abstract class BuySellViewModelBase extends WalletChangeListenerViewModel with S
|
||||
@observable
|
||||
List<FiatCurrency> fiatCurrencies;
|
||||
|
||||
@observable
|
||||
bool isBuyAction = true;
|
||||
final BuySellPageMode mode;
|
||||
|
||||
@observable
|
||||
List<BuyProvider> providerList;
|
||||
@@ -145,6 +179,100 @@ abstract class BuySellViewModelBase extends WalletChangeListenerViewModel with S
|
||||
@observable
|
||||
bool skipIsReadyToTradeReaction = false;
|
||||
|
||||
@computed
|
||||
String? get maxFiatAmount {
|
||||
if ((sortedQuotes.isEmpty && sortedRecommendedQuotes.isEmpty) ||
|
||||
buySellQuotState is! BuySellQuotLoaded) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final allQuotes = sortedRecommendedQuotes.followedBy(sortedQuotes);
|
||||
|
||||
final maxAmount = allQuotes.fold<double>(0.0, (current, item) {
|
||||
final limitMax = item.limits?.max?.toDouble() ?? 0.0;
|
||||
return max(current, limitMax);
|
||||
});
|
||||
|
||||
return maxAmount.toStringAsFixed(2);
|
||||
}
|
||||
|
||||
Money? amountForQuote(Quote quote) => Money.trySafeParse(
|
||||
((double.tryParse(fiatAmount) ?? 0) / quote.rate).toStringAsFixed(min(20, cryptoCurrency.decimals)),
|
||||
cryptoCurrency);
|
||||
|
||||
Money? fiatAmountForQuote(Quote quote) {
|
||||
if(fiatConversionStore.prices[cryptoCurrency] == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return Money.trySafeParse(
|
||||
(fiatConversionStore.prices[cryptoCurrency]! *
|
||||
(double.tryParse(amountForQuote(quote).toString())??0))
|
||||
.toStringAsFixed(2),
|
||||
fiatCurrency);
|
||||
}
|
||||
|
||||
// based on usd values, should have roughly equal worth (was done with ai though so it's subject to correction)
|
||||
static final Map<FiatCurrency, List<String>> _defaultAmountsMap = {
|
||||
FiatCurrency.amd: ["20000", "40000", "200000", "400000", "1000000"],
|
||||
FiatCurrency.ars: ["50000", "100000", "500000", "1000000", "2500000"],
|
||||
FiatCurrency.aud: ["100", "200", "1000", "2000", "5000"],
|
||||
FiatCurrency.bdt: ["5000", "10000", "50000", "100000", "250000"],
|
||||
FiatCurrency.bgn: ["100", "200", "1000", "2000", "5000"],
|
||||
FiatCurrency.brl: ["250", "500", "2500", "5000", "12500"],
|
||||
FiatCurrency.cad: ["50", "100", "500", "1000", "2500"],
|
||||
FiatCurrency.chf: ["50", "100", "500", "1000", "2500"],
|
||||
FiatCurrency.clp: ["50000", "100000", "500000", "1000000", "2500000"],
|
||||
FiatCurrency.cny: ["500", "1000", "5000", "10000", "25000"],
|
||||
FiatCurrency.cop: ["200000", "400000", "2000000", "4000000", "10000000"],
|
||||
FiatCurrency.czk: ["1000", "2000", "10000", "20000", "50000"],
|
||||
FiatCurrency.dkk: ["400", "800", "4000", "8000", "20000"],
|
||||
FiatCurrency.egp: ["2500", "5000", "25000", "50000", "125000"],
|
||||
FiatCurrency.eur: ["50", "100", "500", "1000", "2500"],
|
||||
FiatCurrency.gbp: ["50", "100", "500", "1000", "2500"],
|
||||
FiatCurrency.ghs: ["500", "1000", "5000", "10000", "25000"],
|
||||
FiatCurrency.gtq: ["400", "800", "4000", "8000", "20000"],
|
||||
FiatCurrency.hkd: ["400", "800", "4000", "8000", "20000"],
|
||||
FiatCurrency.hrk: ["400", "800", "4000", "8000", "20000"],
|
||||
FiatCurrency.huf: ["20000", "40000", "200000", "400000", "1000000"],
|
||||
FiatCurrency.idr: ["800000", "1600000", "8000000", "16000000", "40000000"],
|
||||
FiatCurrency.ils: ["200", "400", "2000", "4000", "10000"],
|
||||
FiatCurrency.inr: ["5000", "10000", "50000", "100000", "250000"],
|
||||
FiatCurrency.irr: ["2000000", "4000000", "20000000", "40000000", "100000000"],
|
||||
FiatCurrency.isk: ["7000", "14000", "70000", "140000", "350000"],
|
||||
FiatCurrency.jpy: ["10000", "20000", "100000", "200000", "500000"],
|
||||
FiatCurrency.kes: ["5000", "10000", "50000", "100000", "250000"],
|
||||
FiatCurrency.krw: ["50000", "100000", "500000", "1000000", "2500000"],
|
||||
FiatCurrency.mad: ["500", "1000", "5000", "10000", "25000"],
|
||||
FiatCurrency.mxn: ["1000", "2000", "10000", "20000", "50000"],
|
||||
FiatCurrency.myr: ["250", "500", "2500", "5000", "12500"],
|
||||
FiatCurrency.ngn: ["50000", "100000", "500000", "1000000", "2500000"],
|
||||
FiatCurrency.nok: ["500", "1000", "5000", "10000", "25000"],
|
||||
FiatCurrency.nzd: ["100", "200", "1000", "2000", "5000"],
|
||||
FiatCurrency.php: ["3000", "6000", "30000", "60000", "150000"],
|
||||
FiatCurrency.pkr: ["15000", "30000", "150000", "300000", "750000"],
|
||||
FiatCurrency.pln: ["200", "400", "2000", "4000", "10000"],
|
||||
FiatCurrency.ron: ["250", "500", "2500", "5000", "12500"],
|
||||
FiatCurrency.rub: ["5000", "10000", "50000", "100000", "250000"],
|
||||
FiatCurrency.sar: ["200", "400", "2000", "4000", "10000"],
|
||||
FiatCurrency.sek: ["500", "1000", "5000", "10000", "25000"],
|
||||
FiatCurrency.sgd: ["50", "100", "500", "1000", "2500"],
|
||||
FiatCurrency.thb: ["2000", "4000", "20000", "40000", "100000"],
|
||||
FiatCurrency.tur: ["1500", "3000", "15000", "30000", "75000"],
|
||||
FiatCurrency.twd: ["1500", "3000", "15000", "30000", "75000"],
|
||||
FiatCurrency.uah: ["2000", "4000", "20000", "40000", "100000"],
|
||||
FiatCurrency.usd: ["50", "100", "500", "1000", "2500"],
|
||||
FiatCurrency.vef: ["2000", "4000", "20000", "40000", "100000"],
|
||||
FiatCurrency.vnd: ["1000000", "2000000", "10000000", "20000000", "50000000"],
|
||||
FiatCurrency.zar: ["1000", "2000", "10000", "20000", "50000"],
|
||||
};
|
||||
|
||||
|
||||
// the fallback is just the usd values.
|
||||
// not great but this fallback shouldn't be triggered anyway
|
||||
List<String> get defaultAmounts =>
|
||||
_defaultAmountsMap[fiatCurrency] ?? ["50", "100", "500", "1000", "2500"];
|
||||
|
||||
@computed
|
||||
bool get isReadyToTrade {
|
||||
final hasSelectedQuote = selectedQuote != null;
|
||||
@@ -177,12 +305,6 @@ abstract class BuySellViewModelBase extends WalletChangeListenerViewModel with S
|
||||
_initialize();
|
||||
}
|
||||
|
||||
@action
|
||||
void changeBuySellAction() {
|
||||
isBuyAction = !isBuyAction;
|
||||
_initialize();
|
||||
}
|
||||
|
||||
@action
|
||||
void changeFiatCurrency({required FiatCurrency currency}) {
|
||||
fiatCurrency = currency;
|
||||
@@ -196,12 +318,18 @@ abstract class BuySellViewModelBase extends WalletChangeListenerViewModel with S
|
||||
isCryptoCurrencyAddressEnabled = !(cryptoCurrency == wallet.currency);
|
||||
}
|
||||
|
||||
@computed
|
||||
Iterable<CryptoCurrency> get activeWalletCurrencies => wallet.balance.keys;
|
||||
|
||||
@computed
|
||||
bool get hasMultipleCurrencies => activeWalletCurrencies.length > 1;
|
||||
|
||||
@action
|
||||
void changeCryptoCurrencyAddress(String address) => cryptoCurrencyAddress = address;
|
||||
|
||||
@action
|
||||
Future<void> changeFiatAmount({required String amount}) async {
|
||||
fiatAmount = amount;
|
||||
fiatAmount = amount.replaceAll(",", ".");
|
||||
|
||||
if (amount.isEmpty) {
|
||||
fiatAmount = '';
|
||||
@@ -210,16 +338,18 @@ abstract class BuySellViewModelBase extends WalletChangeListenerViewModel with S
|
||||
}
|
||||
|
||||
if (!isReadyToTrade && !isBuySellQuoteFailed) {
|
||||
_cryptoAmount = S.current.fetching;
|
||||
_cryptoAmount = "...";
|
||||
return;
|
||||
} else if (isBuySellQuoteFailed) {
|
||||
_cryptoAmount = '';
|
||||
return;
|
||||
}
|
||||
|
||||
printV(bestRateQuote);
|
||||
if (bestRateQuote != null) {
|
||||
final enteredAmount = double.tryParse(fiatAmount.replaceAll(',', '.')) ?? 0;
|
||||
final amount = enteredAmount / bestRateQuote!.rate;
|
||||
printV(amount);
|
||||
|
||||
_cryptoAmount = amount.toString().withMaxDecimals(cryptoCurrency.decimals);
|
||||
} else {
|
||||
@@ -271,70 +401,13 @@ abstract class BuySellViewModelBase extends WalletChangeListenerViewModel with S
|
||||
}
|
||||
}
|
||||
|
||||
void onTapChoseProvider(BuildContext context) async {
|
||||
skipIsReadyToTradeReaction = true;
|
||||
final initialQuotes = List<Quote>.from(sortedRecommendedQuotes + sortedQuotes);
|
||||
await calculateBestRate();
|
||||
final newQuotes = (sortedRecommendedQuotes + sortedQuotes);
|
||||
|
||||
for (var quote in newQuotes) quote.limits = null;
|
||||
|
||||
final newQuoteProviders = newQuotes
|
||||
.map((quote) => quote.provider.isAggregator ? quote.rampName : quote.provider.title)
|
||||
.toSet();
|
||||
|
||||
final outOfLimitQuotes = initialQuotes.where((initialQuote) {
|
||||
return !newQuoteProviders.contains(
|
||||
initialQuote.provider.isAggregator ? initialQuote.rampName : initialQuote.provider.title);
|
||||
}).map((missingQuote) {
|
||||
final quote = Quote(
|
||||
rate: missingQuote.rate,
|
||||
feeAmount: missingQuote.feeAmount,
|
||||
networkFee: missingQuote.networkFee,
|
||||
transactionFee: missingQuote.transactionFee,
|
||||
payout: missingQuote.payout,
|
||||
rampId: missingQuote.rampId,
|
||||
rampName: missingQuote.rampName,
|
||||
rampIconPath: missingQuote.rampIconPath,
|
||||
paymentType: missingQuote.paymentType,
|
||||
quoteId: missingQuote.quoteId,
|
||||
recommendations: missingQuote.recommendations,
|
||||
provider: missingQuote.provider,
|
||||
isBuyAction: missingQuote.isBuyAction,
|
||||
limits: missingQuote.limits,
|
||||
);
|
||||
quote.setFiatCurrency = missingQuote.fiatCurrency;
|
||||
quote.setCryptoCurrency = missingQuote.cryptoCurrency;
|
||||
return quote;
|
||||
}).toList();
|
||||
|
||||
final updatedQuoteOptions = List<SelectableItem>.from([
|
||||
OptionTitle(title: 'Recommended'),
|
||||
...sortedRecommendedQuotes,
|
||||
if (sortedQuotes.isNotEmpty) OptionTitle(title: 'All Providers'),
|
||||
...sortedQuotes,
|
||||
if (outOfLimitQuotes.isNotEmpty) OptionTitle(title: 'Out of Limits'),
|
||||
...outOfLimitQuotes,
|
||||
]);
|
||||
|
||||
if (context.mounted) {
|
||||
await Navigator.of(context).pushNamed(
|
||||
Routes.buyOptionsPage,
|
||||
arguments: [
|
||||
updatedQuoteOptions,
|
||||
changeOption,
|
||||
launchTrade,
|
||||
],
|
||||
).then((value) => calculateBestRate());
|
||||
}
|
||||
}
|
||||
|
||||
void _onPairChange() {
|
||||
_initialize();
|
||||
}
|
||||
|
||||
void _setProviders() =>
|
||||
providerList = isBuyAction ? availableBuyProviders : availableSellProviders;
|
||||
providerList = mode == BuySellPageMode.buy ? availableBuyProviders : availableSellProviders;
|
||||
|
||||
Future<void> _initialize() async {
|
||||
_setProviders();
|
||||
@@ -343,53 +416,54 @@ abstract class BuySellViewModelBase extends WalletChangeListenerViewModel with S
|
||||
cryptoCurrencyAddress = _getInitialCryptoCurrencyAddress();
|
||||
paymentMethodState = InitialPaymentMethod();
|
||||
buySellQuotState = InitialBuySellQuotState();
|
||||
sortedRecommendedQuotes.clear();
|
||||
sortedQuotes.clear();
|
||||
paymentMethods.clear();
|
||||
await _getAvailablePaymentTypes();
|
||||
await calculateBestRate();
|
||||
}
|
||||
|
||||
String _getInitialCryptoCurrencyAddress() {
|
||||
if (cryptoCurrency == wallet.currency) {
|
||||
if ([CryptoCurrency.zec, CryptoCurrency.btc].contains(cryptoCurrency)) {
|
||||
return wallet.walletAddresses.addressForBuy;
|
||||
}
|
||||
|
||||
return wallet.walletAddresses.address;
|
||||
}
|
||||
return '';
|
||||
}
|
||||
String _getInitialCryptoCurrencyAddress() => wallet.walletAddresses.addressForBuy;
|
||||
|
||||
@action
|
||||
Future<void> _getAvailablePaymentTypes() async {
|
||||
paymentMethodState = PaymentMethodLoading();
|
||||
selectedPaymentMethod = null;
|
||||
final result = await Future.wait(providerList.map((element) =>
|
||||
element.getAvailablePaymentTypes(fiatCurrency.title, cryptoCurrency, isBuyAction).timeout(
|
||||
Duration(seconds: 10),
|
||||
onTimeout: () => [],
|
||||
)));
|
||||
try{
|
||||
paymentMethodState = PaymentMethodLoading();
|
||||
selectedPaymentMethod = null;
|
||||
final result = await Future.wait(providerList.map((element) => element
|
||||
.getAvailablePaymentTypes(fiatCurrency.title, cryptoCurrency, mode == BuySellPageMode.buy)
|
||||
.timeout(
|
||||
Duration(seconds: 10),
|
||||
onTimeout: () => [],
|
||||
)));
|
||||
|
||||
final List<PaymentMethod> tempPaymentMethods = [];
|
||||
final List<PaymentMethod> tempPaymentMethods = [];
|
||||
|
||||
for (var methods in result) {
|
||||
for (var method in methods) {
|
||||
final alreadyExists = tempPaymentMethods.any((m) {
|
||||
return m.paymentMethodType == method.paymentMethodType;
|
||||
});
|
||||
for (var methods in result) {
|
||||
for (var method in methods) {
|
||||
final alreadyExists = tempPaymentMethods.any((m) {
|
||||
if (m.paymentMethodType != method.paymentMethodType) return false;
|
||||
if (method.paymentMethodType != PaymentType.unknown) return true;
|
||||
return m.customTitle == method.customTitle;
|
||||
});
|
||||
|
||||
if (!alreadyExists) {
|
||||
tempPaymentMethods.add(method);
|
||||
if (!alreadyExists) {
|
||||
tempPaymentMethods.add(method);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
paymentMethods = ObservableList<PaymentMethod>.of(tempPaymentMethods);
|
||||
paymentMethods = ObservableList<PaymentMethod>.of(tempPaymentMethods);
|
||||
|
||||
if (paymentMethods.isNotEmpty) {
|
||||
paymentMethods.insert(0, PaymentMethod.all());
|
||||
selectedPaymentMethod = paymentMethods.first;
|
||||
selectedPaymentMethod!.isSelected = true;
|
||||
paymentMethodState = PaymentMethodLoaded();
|
||||
} else {
|
||||
if (paymentMethods.isNotEmpty) {
|
||||
paymentMethods.insert(0, PaymentMethod.all());
|
||||
selectedPaymentMethod = paymentMethods.first;
|
||||
selectedPaymentMethod!.isSelected = true;
|
||||
paymentMethodState = PaymentMethodLoaded();
|
||||
} else {
|
||||
paymentMethodState = PaymentMethodFailed();
|
||||
}
|
||||
} catch(e) {
|
||||
paymentMethodState = PaymentMethodFailed();
|
||||
}
|
||||
}
|
||||
@@ -399,17 +473,22 @@ abstract class BuySellViewModelBase extends WalletChangeListenerViewModel with S
|
||||
buySellQuotState = BuySellQuotLoading();
|
||||
|
||||
final List<BuyProvider> validProviders = providerList.where((provider) {
|
||||
if (isBuyAction) {
|
||||
return provider.supportedCryptoList
|
||||
.any((pair) => pair.from == cryptoCurrency && pair.to == fiatCurrency);
|
||||
if (mode == BuySellPageMode.buy) {
|
||||
return provider.supportedCryptoList.any((pair) =>
|
||||
pair.from.symbol == cryptoCurrency.symbol &&
|
||||
pair.from.tag == cryptoCurrency.tag &&
|
||||
pair.to.symbol == fiatCurrency.symbol);
|
||||
} else {
|
||||
return provider.supportedFiatList
|
||||
.any((pair) => pair.from == fiatCurrency && pair.to == cryptoCurrency);
|
||||
return provider.supportedFiatList.any((pair) =>
|
||||
pair.from.symbol == fiatCurrency.symbol &&
|
||||
pair.to.symbol == cryptoCurrency.symbol &&
|
||||
pair.to.tag == cryptoCurrency.tag);
|
||||
}
|
||||
}).toList();
|
||||
|
||||
if (validProviders.isEmpty) {
|
||||
buySellQuotState = BuySellQuotFailed();
|
||||
buySellQuotState = BuySellQuotFailed(
|
||||
errorMessage: S.current.no_buy_providers(cryptoCurrency.fullName??cryptoCurrency.title));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -419,7 +498,7 @@ abstract class BuySellViewModelBase extends WalletChangeListenerViewModel with S
|
||||
fiatCurrency: fiatCurrency,
|
||||
amount: amount,
|
||||
paymentType: selectedPaymentMethod?.paymentMethodType,
|
||||
isBuyAction: isBuyAction,
|
||||
isBuyAction: mode == BuySellPageMode.buy,
|
||||
walletAddress: wallet.walletAddresses.address,
|
||||
customPaymentMethodType: selectedPaymentMethod?.customPaymentMethodType,
|
||||
)
|
||||
@@ -437,11 +516,12 @@ abstract class BuySellViewModelBase extends WalletChangeListenerViewModel with S
|
||||
.toList();
|
||||
|
||||
if (validQuotes.isEmpty) {
|
||||
buySellQuotState = BuySellQuotFailed();
|
||||
buySellQuotState = BuySellQuotFailed(
|
||||
errorMessage: S.current.no_buy_providers(cryptoCurrency.fullName??cryptoCurrency.title));
|
||||
return;
|
||||
}
|
||||
|
||||
if (isBuyAction) {
|
||||
if (mode == BuySellPageMode.buy) {
|
||||
validQuotes.sort((a, b) => b.payout.compareTo(a.payout));
|
||||
} else {
|
||||
validQuotes.sort((a, b) => a.payout.compareTo(b.payout));
|
||||
@@ -464,7 +544,7 @@ abstract class BuySellViewModelBase extends WalletChangeListenerViewModel with S
|
||||
bestRateQuote = sortedRecommendedQuotes.first;
|
||||
|
||||
final Quote effectiveBestRateQuote = sortedRecommendedQuotes.reduce((a, b) {
|
||||
return isBuyAction
|
||||
return mode == BuySellPageMode.buy
|
||||
? a.rate < b.rate
|
||||
? a
|
||||
: b
|
||||
@@ -490,7 +570,7 @@ abstract class BuySellViewModelBase extends WalletChangeListenerViewModel with S
|
||||
context: context,
|
||||
quote: selectedQuote!,
|
||||
amount: amount,
|
||||
isBuyAction: isBuyAction,
|
||||
isBuyAction: mode == BuySellPageMode.buy,
|
||||
cryptoCurrencyAddress: cryptoCurrencyAddress,
|
||||
);
|
||||
} catch (e) {
|
||||
|
||||
@@ -1,91 +0,0 @@
|
||||
import 'package:hash_wallet/buy/buy_provider.dart';
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
import 'package:hash_wallet/entities/fiat_currency.dart';
|
||||
import 'package:cw_core/utils/print_verbose.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
import 'package:hash_wallet/store/settings_store.dart';
|
||||
import 'package:hash_wallet/view_model/buy/buy_item.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
import 'package:hash_wallet/order/order.dart';
|
||||
import 'package:hash_wallet/store/dashboard/orders_store.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
import 'package:cw_core/wallet_base.dart';
|
||||
import 'buy_amount_view_model.dart';
|
||||
|
||||
part 'buy_view_model.g.dart';
|
||||
|
||||
class BuyViewModel = BuyViewModelBase with _$BuyViewModel;
|
||||
|
||||
abstract class BuyViewModelBase with Store {
|
||||
BuyViewModelBase(this.ordersSource, this.ordersStore, this.settingsStore, this.buyAmountViewModel,
|
||||
{required this.wallet})
|
||||
: isRunning = false,
|
||||
isDisabled = true,
|
||||
isShowProviderButtons = false,
|
||||
items = <BuyItem>[] {
|
||||
_fetchBuyItems();
|
||||
}
|
||||
|
||||
final Box<Order> ordersSource;
|
||||
final OrdersStore ordersStore;
|
||||
final SettingsStore settingsStore;
|
||||
final BuyAmountViewModel buyAmountViewModel;
|
||||
final WalletBase wallet;
|
||||
|
||||
@observable
|
||||
BuyProvider? selectedProvider;
|
||||
|
||||
@observable
|
||||
List<BuyItem> items;
|
||||
|
||||
@observable
|
||||
bool isRunning;
|
||||
|
||||
@observable
|
||||
bool isDisabled;
|
||||
|
||||
@observable
|
||||
bool isShowProviderButtons;
|
||||
|
||||
WalletType get type => wallet.type;
|
||||
|
||||
double get doubleAmount => buyAmountViewModel.doubleAmount;
|
||||
|
||||
@computed
|
||||
FiatCurrency get fiatCurrency => buyAmountViewModel.fiatCurrency;
|
||||
|
||||
CryptoCurrency get cryptoCurrency => wallet.currency;
|
||||
|
||||
Future<String> fetchUrl() async {
|
||||
String _url = '';
|
||||
|
||||
try {
|
||||
_url = await selectedProvider!.requestUrl(doubleAmount.toString(), fiatCurrency.title);
|
||||
} catch (e) {
|
||||
printV(e.toString());
|
||||
}
|
||||
|
||||
return _url;
|
||||
}
|
||||
|
||||
Future<void> saveOrder(String orderId) async {
|
||||
try {
|
||||
final order = await selectedProvider!.findOrderById(orderId);
|
||||
order.from = fiatCurrency.title;
|
||||
order.to = cryptoCurrency.title;
|
||||
await ordersSource.add(order);
|
||||
ordersStore.setOrder(order);
|
||||
} catch (e) {
|
||||
printV(e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
void reset() {
|
||||
buyAmountViewModel.amount = '';
|
||||
selectedProvider = null;
|
||||
}
|
||||
|
||||
Future<void> _fetchBuyItems() async {
|
||||
items = const <BuyItem>[];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user