mirror of
https://github.com/cypherstack/stack_wallet.git
synced 2024-12-22 19:39:22 +00:00
WIP exchange process refactor to handle multiple sub providers per exchange provider
This commit is contained in:
parent
34f7d80051
commit
e81521e374
14 changed files with 468 additions and 957 deletions
|
@ -13,6 +13,12 @@ class ExchangeFormState extends ChangeNotifier {
|
|||
Exchange? _exchange;
|
||||
Exchange get exchange => _exchange ??= Exchange.defaultExchange;
|
||||
|
||||
String? _providerName;
|
||||
// default to exchange name that isn't trocador
|
||||
String get providerName => _providerName ??= Exchange.defaultExchange.name;
|
||||
|
||||
String get combinedExchangeId => "${exchange.name} ($providerName)";
|
||||
|
||||
ExchangeRateType _exchangeRateType = ExchangeRateType.estimated;
|
||||
ExchangeRateType get exchangeRateType => _exchangeRateType;
|
||||
set exchangeRateType(ExchangeRateType exchangeRateType) {
|
||||
|
@ -20,8 +26,8 @@ class ExchangeFormState extends ChangeNotifier {
|
|||
//
|
||||
}
|
||||
|
||||
Estimate? _estimate;
|
||||
Estimate? get estimate => _estimate;
|
||||
List<Estimate> _estimates = [];
|
||||
List<Estimate> get estimates => _estimates;
|
||||
|
||||
bool _reversed = false;
|
||||
bool get reversed => _reversed;
|
||||
|
@ -149,10 +155,12 @@ class ExchangeFormState extends ChangeNotifier {
|
|||
|
||||
Future<void> updateExchange({
|
||||
required Exchange exchange,
|
||||
required String providerName,
|
||||
required bool shouldUpdateData,
|
||||
required bool shouldNotifyListeners,
|
||||
}) async {
|
||||
_exchange = exchange;
|
||||
_providerName = providerName;
|
||||
if (shouldUpdateData) {
|
||||
await _updateRangesAndEstimate(
|
||||
shouldNotifyListeners: false,
|
||||
|
@ -173,6 +181,7 @@ class ExchangeFormState extends ChangeNotifier {
|
|||
required bool shouldNotifyListeners,
|
||||
}) {
|
||||
_exchange = null;
|
||||
_providerName = null;
|
||||
_reversed = false;
|
||||
_rate = null;
|
||||
_sendAmount = null;
|
||||
|
@ -445,7 +454,7 @@ class ExchangeFormState extends ChangeNotifier {
|
|||
);
|
||||
return;
|
||||
}
|
||||
final response = await exchange.getEstimate(
|
||||
final response = await exchange.getEstimates(
|
||||
sendCurrency!.ticker,
|
||||
receiveCurrency!.ticker,
|
||||
amount,
|
||||
|
@ -461,12 +470,16 @@ class ExchangeFormState extends ChangeNotifier {
|
|||
return;
|
||||
}
|
||||
|
||||
_estimate = response.value!;
|
||||
_estimates = response.value!;
|
||||
|
||||
if (reversed) {
|
||||
_sendAmount = _estimate!.estimatedAmount;
|
||||
_sendAmount = _estimates
|
||||
.firstWhere((e) => e.exchangeProvider == providerName)
|
||||
.estimatedAmount;
|
||||
} else {
|
||||
_receiveAmount = _estimate!.estimatedAmount;
|
||||
_receiveAmount = _estimates
|
||||
.firstWhere((e) => e.exchangeProvider == providerName)
|
||||
.estimatedAmount;
|
||||
}
|
||||
|
||||
_rate =
|
||||
|
@ -518,7 +531,7 @@ class ExchangeFormState extends ChangeNotifier {
|
|||
"\n\t reversed: $reversed,"
|
||||
"\n\t sendAmount: $sendAmount,"
|
||||
"\n\t receiveAmount: $receiveAmount,"
|
||||
"\n\t estimate: $estimate,"
|
||||
"\n\t estimates: $estimates,"
|
||||
"\n\t minSendAmount: $minSendAmount,"
|
||||
"\n\t maxSendAmount: $maxSendAmount,"
|
||||
"\n\t minReceiveAmount: $minReceiveAmount,"
|
||||
|
|
|
@ -7,7 +7,8 @@ class Estimate {
|
|||
final bool reversed;
|
||||
final String? warningMessage;
|
||||
final String? rateId;
|
||||
final String? exchangeProvider;
|
||||
final String exchangeProvider;
|
||||
final String? kycRating;
|
||||
|
||||
Estimate({
|
||||
required this.estimatedAmount,
|
||||
|
@ -15,10 +16,15 @@ class Estimate {
|
|||
required this.reversed,
|
||||
this.warningMessage,
|
||||
this.rateId,
|
||||
this.exchangeProvider,
|
||||
required this.exchangeProvider,
|
||||
this.kycRating,
|
||||
});
|
||||
|
||||
factory Estimate.fromMap(Map<String, dynamic> map) {
|
||||
factory Estimate.fromMap(
|
||||
Map<String, dynamic> map, {
|
||||
required String exchangeProvider,
|
||||
String? kycRating,
|
||||
}) {
|
||||
try {
|
||||
return Estimate(
|
||||
estimatedAmount: Decimal.parse(map["estimatedAmount"] as String),
|
||||
|
@ -26,6 +32,8 @@ class Estimate {
|
|||
reversed: map["reversed"] as bool,
|
||||
warningMessage: map["warningMessage"] as String?,
|
||||
rateId: map["rateId"] as String?,
|
||||
exchangeProvider: exchangeProvider,
|
||||
kycRating: kycRating,
|
||||
);
|
||||
} catch (e, s) {
|
||||
Logging.instance.log("Estimate.fromMap(): $e\n$s", level: LogLevel.Error);
|
||||
|
@ -41,6 +49,7 @@ class Estimate {
|
|||
"warningMessage": warningMessage,
|
||||
"rateId": rateId,
|
||||
"exchangeProvider": exchangeProvider,
|
||||
"kycRating": kycRating,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -409,7 +409,11 @@ class _ExchangeFormState extends ConsumerState<ExchangeForm> {
|
|||
final fromTicker = ref.read(exchangeFormStateProvider).fromTicker ?? "";
|
||||
final toTicker = ref.read(exchangeFormStateProvider).toTicker ?? "";
|
||||
final sendAmount = ref.read(exchangeFormStateProvider).sendAmount!;
|
||||
final estimate = ref.read(exchangeFormStateProvider).estimate!;
|
||||
final estimate = ref.read(exchangeFormStateProvider).estimates.firstWhere(
|
||||
(e) =>
|
||||
e.exchangeProvider ==
|
||||
ref.read(exchangeFormStateProvider).providerName,
|
||||
);
|
||||
|
||||
if (rateType == ExchangeRateType.fixed && toTicker.toUpperCase() == "WOW") {
|
||||
await showDialog<void>(
|
||||
|
|
|
@ -0,0 +1,306 @@
|
|||
import 'package:decimal/decimal.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
import 'package:stackwallet/exceptions/exchange/pair_unavailable_exception.dart';
|
||||
import 'package:stackwallet/models/exchange/response_objects/estimate.dart';
|
||||
import 'package:stackwallet/providers/exchange/exchange_form_state_provider.dart';
|
||||
import 'package:stackwallet/providers/global/locale_provider.dart';
|
||||
import 'package:stackwallet/services/exchange/exchange.dart';
|
||||
import 'package:stackwallet/services/exchange/exchange_response.dart';
|
||||
import 'package:stackwallet/services/exchange/trocador/trocador_exchange.dart';
|
||||
import 'package:stackwallet/utilities/amount/amount.dart';
|
||||
import 'package:stackwallet/utilities/assets.dart';
|
||||
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||
import 'package:stackwallet/utilities/logger.dart';
|
||||
import 'package:stackwallet/utilities/show_loading.dart';
|
||||
import 'package:stackwallet/utilities/text_styles.dart';
|
||||
import 'package:stackwallet/utilities/theme/stack_colors.dart';
|
||||
import 'package:stackwallet/utilities/util.dart';
|
||||
import 'package:stackwallet/widgets/animated_text.dart';
|
||||
import 'package:stackwallet/widgets/conditional_parent.dart';
|
||||
import 'package:stackwallet/widgets/exchange/trocador/trocador_kyc_info_button.dart';
|
||||
import 'package:stackwallet/widgets/exchange/trocador/trocador_rating_type_enum.dart';
|
||||
|
||||
class ExchangeProviderOption extends ConsumerStatefulWidget {
|
||||
const ExchangeProviderOption({
|
||||
Key? key,
|
||||
required this.exchange,
|
||||
required this.exchangeProvider,
|
||||
required this.fixedRate,
|
||||
required this.reversed,
|
||||
}) : super(key: key);
|
||||
|
||||
final Exchange exchange;
|
||||
final String exchangeProvider;
|
||||
final bool fixedRate;
|
||||
final bool reversed;
|
||||
|
||||
@override
|
||||
ConsumerState<ExchangeProviderOption> createState() =>
|
||||
_ExchangeProviderOptionState();
|
||||
}
|
||||
|
||||
class _ExchangeProviderOptionState
|
||||
extends ConsumerState<ExchangeProviderOption> {
|
||||
final isDesktop = Util.isDesktop;
|
||||
late final String _id;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
_id = "${widget.exchange.name} (${widget.exchangeProvider})";
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final sendCurrency = ref
|
||||
.watch(exchangeFormStateProvider.select((value) => value.sendCurrency));
|
||||
final receivingCurrency = ref.watch(
|
||||
exchangeFormStateProvider.select((value) => value.receiveCurrency));
|
||||
final fromAmount = ref
|
||||
.watch(exchangeFormStateProvider.select((value) => value.sendAmount));
|
||||
final toAmount = ref.watch(
|
||||
exchangeFormStateProvider.select((value) => value.receiveAmount));
|
||||
|
||||
final selected = ref.watch(exchangeFormStateProvider
|
||||
.select((value) => value.combinedExchangeId)) ==
|
||||
_id;
|
||||
|
||||
return ConditionalParent(
|
||||
condition: isDesktop,
|
||||
builder: (child) => MouseRegion(
|
||||
cursor: SystemMouseCursors.click,
|
||||
child: child,
|
||||
),
|
||||
child: GestureDetector(
|
||||
onTap: () {
|
||||
if (!selected) {
|
||||
showLoading(
|
||||
whileFuture: ref.read(exchangeFormStateProvider).updateExchange(
|
||||
exchange: widget.exchange,
|
||||
shouldUpdateData: true,
|
||||
shouldNotifyListeners: true,
|
||||
providerName: widget.exchangeProvider,
|
||||
),
|
||||
context: context,
|
||||
message: "Updating rates",
|
||||
isDesktop: isDesktop,
|
||||
);
|
||||
}
|
||||
},
|
||||
child: Container(
|
||||
color: Colors.transparent,
|
||||
child: Padding(
|
||||
padding:
|
||||
isDesktop ? const EdgeInsets.all(16) : const EdgeInsets.all(0),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
SizedBox(
|
||||
width: 20,
|
||||
height: 20,
|
||||
child: Padding(
|
||||
padding: EdgeInsets.only(top: isDesktop ? 20.0 : 15.0),
|
||||
child: Radio(
|
||||
activeColor: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.radioButtonIconEnabled,
|
||||
value: _id,
|
||||
groupValue: ref.watch(exchangeFormStateProvider
|
||||
.select((value) => value.combinedExchangeId)),
|
||||
onChanged: (_) {
|
||||
if (!selected) {
|
||||
ref.read(exchangeFormStateProvider).updateExchange(
|
||||
exchange: widget.exchange,
|
||||
shouldUpdateData: true,
|
||||
shouldNotifyListeners: true,
|
||||
providerName: widget.exchangeProvider,
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
width: 14,
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 5.0),
|
||||
child: SizedBox(
|
||||
width: isDesktop ? 32 : 24,
|
||||
height: isDesktop ? 32 : 24,
|
||||
child: SvgPicture.asset(
|
||||
Assets.exchange.getIconFor(
|
||||
exchangeName: widget.exchange.name,
|
||||
),
|
||||
width: isDesktop ? 32 : 24,
|
||||
height: isDesktop ? 32 : 24,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
width: 10,
|
||||
),
|
||||
Expanded(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
widget.exchangeProvider,
|
||||
style: STextStyles.titleBold12(context).copyWith(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textDark2,
|
||||
),
|
||||
),
|
||||
if (sendCurrency != null &&
|
||||
receivingCurrency != null &&
|
||||
toAmount != null &&
|
||||
toAmount > Decimal.zero &&
|
||||
fromAmount != null &&
|
||||
fromAmount > Decimal.zero)
|
||||
FutureBuilder(
|
||||
future: widget.exchange.getEstimates(
|
||||
sendCurrency.ticker,
|
||||
receivingCurrency.ticker,
|
||||
widget.reversed ? toAmount : fromAmount,
|
||||
widget.fixedRate,
|
||||
widget.reversed,
|
||||
),
|
||||
builder: (context,
|
||||
AsyncSnapshot<ExchangeResponse<List<Estimate>>>
|
||||
snapshot) {
|
||||
if (snapshot.connectionState ==
|
||||
ConnectionState.done &&
|
||||
snapshot.hasData) {
|
||||
final estimates = snapshot.data?.value;
|
||||
if (estimates != null &&
|
||||
estimates
|
||||
.where((e) =>
|
||||
e.exchangeProvider ==
|
||||
widget.exchangeProvider)
|
||||
.isNotEmpty) {
|
||||
final estimate = estimates.firstWhere((e) =>
|
||||
e.exchangeProvider ==
|
||||
widget.exchangeProvider);
|
||||
int decimals;
|
||||
try {
|
||||
decimals = coinFromTickerCaseInsensitive(
|
||||
receivingCurrency.ticker)
|
||||
.decimals;
|
||||
} catch (_) {
|
||||
decimals = 8; // some reasonable alternative
|
||||
}
|
||||
Amount rate;
|
||||
if (estimate.reversed) {
|
||||
rate = (toAmount / estimate.estimatedAmount)
|
||||
.toDecimal(scaleOnInfinitePrecision: 18)
|
||||
.toAmount(fractionDigits: decimals);
|
||||
} else {
|
||||
rate = (estimate.estimatedAmount / fromAmount)
|
||||
.toDecimal(scaleOnInfinitePrecision: 18)
|
||||
.toAmount(fractionDigits: decimals);
|
||||
}
|
||||
|
||||
return ConditionalParent(
|
||||
condition: widget.exchange.name ==
|
||||
TrocadorExchange.exchangeName,
|
||||
builder: (child) {
|
||||
return Row(
|
||||
children: [
|
||||
child,
|
||||
TrocadorKYCInfoButton(
|
||||
kycType: TrocadorKYCType.fromString(
|
||||
estimate.kycRating!,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
child: Text(
|
||||
"1 ${sendCurrency.ticker.toUpperCase()} ~ ${rate.localizedStringAsFixed(
|
||||
locale: ref.watch(
|
||||
localeServiceChangeNotifierProvider
|
||||
.select((value) => value.locale),
|
||||
),
|
||||
)} ${receivingCurrency.ticker.toUpperCase()}",
|
||||
style: STextStyles.itemSubtitle12(context)
|
||||
.copyWith(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textSubtitle1,
|
||||
),
|
||||
),
|
||||
);
|
||||
} else if (snapshot.data?.exception
|
||||
is PairUnavailableException) {
|
||||
return Text(
|
||||
"Unsupported pair",
|
||||
style: STextStyles.itemSubtitle12(context)
|
||||
.copyWith(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textSubtitle1,
|
||||
),
|
||||
);
|
||||
} else {
|
||||
Logging.instance.log(
|
||||
"$runtimeType failed to fetch rate for $_id}: ${snapshot.data}",
|
||||
level: LogLevel.Warning,
|
||||
);
|
||||
return Text(
|
||||
"Failed to fetch rate",
|
||||
style: STextStyles.itemSubtitle12(context)
|
||||
.copyWith(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textSubtitle1,
|
||||
),
|
||||
);
|
||||
}
|
||||
} else {
|
||||
return AnimatedText(
|
||||
stringsToLoopThrough: const [
|
||||
"Loading",
|
||||
"Loading.",
|
||||
"Loading..",
|
||||
"Loading...",
|
||||
],
|
||||
style: STextStyles.itemSubtitle12(context)
|
||||
.copyWith(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textSubtitle1,
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
if (!(sendCurrency != null &&
|
||||
receivingCurrency != null &&
|
||||
toAmount != null &&
|
||||
toAmount > Decimal.zero &&
|
||||
fromAmount != null &&
|
||||
fromAmount > Decimal.zero))
|
||||
Text(
|
||||
"n/a",
|
||||
style: STextStyles.itemSubtitle12(context).copyWith(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textSubtitle1,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,27 +1,13 @@
|
|||
import 'package:decimal/decimal.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
import 'package:stackwallet/exceptions/exchange/pair_unavailable_exception.dart';
|
||||
import 'package:stackwallet/models/exchange/aggregate_currency.dart';
|
||||
import 'package:stackwallet/models/exchange/response_objects/estimate.dart';
|
||||
import 'package:stackwallet/pages/exchange_view/sub_widgets/exchange_provider_option.dart';
|
||||
import 'package:stackwallet/providers/providers.dart';
|
||||
import 'package:stackwallet/services/exchange/change_now/change_now_exchange.dart';
|
||||
import 'package:stackwallet/services/exchange/exchange_response.dart';
|
||||
import 'package:stackwallet/services/exchange/majestic_bank/majestic_bank_exchange.dart';
|
||||
import 'package:stackwallet/services/exchange/trocador/trocador_exchange.dart';
|
||||
import 'package:stackwallet/utilities/amount/amount.dart';
|
||||
import 'package:stackwallet/utilities/assets.dart';
|
||||
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||
import 'package:stackwallet/utilities/logger.dart';
|
||||
import 'package:stackwallet/utilities/show_loading.dart';
|
||||
import 'package:stackwallet/utilities/text_styles.dart';
|
||||
import 'package:stackwallet/utilities/theme/stack_colors.dart';
|
||||
import 'package:stackwallet/utilities/util.dart';
|
||||
import 'package:stackwallet/widgets/animated_text.dart';
|
||||
import 'package:stackwallet/widgets/conditional_parent.dart';
|
||||
import 'package:stackwallet/widgets/exchange/trocador/trocador_kyc_info_button.dart';
|
||||
import 'package:stackwallet/widgets/exchange/trocador/trocador_rating_type_enum.dart';
|
||||
import 'package:stackwallet/widgets/rounded_white_container.dart';
|
||||
|
||||
class ExchangeProviderOptions extends ConsumerStatefulWidget {
|
||||
|
@ -63,11 +49,16 @@ class _ExchangeProviderOptionsState
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final sendCurrency = ref.watch(exchangeFormStateProvider).sendCurrency;
|
||||
final receivingCurrency =
|
||||
ref.watch(exchangeFormStateProvider).receiveCurrency;
|
||||
final fromAmount = ref.watch(exchangeFormStateProvider).sendAmount;
|
||||
final toAmount = ref.watch(exchangeFormStateProvider).receiveAmount;
|
||||
final sendCurrency = ref.watch(
|
||||
exchangeFormStateProvider.select(
|
||||
(value) => value.sendCurrency,
|
||||
),
|
||||
);
|
||||
final receivingCurrency = ref.watch(
|
||||
exchangeFormStateProvider.select(
|
||||
(value) => value.receiveCurrency,
|
||||
),
|
||||
);
|
||||
|
||||
final showChangeNow = exchangeSupported(
|
||||
exchangeName: ChangeNowExchange.exchangeName,
|
||||
|
@ -93,239 +84,12 @@ class _ExchangeProviderOptionsState
|
|||
child: Column(
|
||||
children: [
|
||||
if (showChangeNow)
|
||||
ConditionalParent(
|
||||
condition: isDesktop,
|
||||
builder: (child) => MouseRegion(
|
||||
cursor: SystemMouseCursors.click,
|
||||
child: child,
|
||||
),
|
||||
child: GestureDetector(
|
||||
onTap: () {
|
||||
if (ref.read(exchangeFormStateProvider).exchange.name !=
|
||||
ChangeNowExchange.exchangeName) {
|
||||
showLoading(
|
||||
whileFuture:
|
||||
ref.read(exchangeFormStateProvider).updateExchange(
|
||||
exchange: ChangeNowExchange.instance,
|
||||
shouldUpdateData: true,
|
||||
shouldNotifyListeners: true,
|
||||
),
|
||||
context: context,
|
||||
message: "Updating rates",
|
||||
isDesktop: isDesktop,
|
||||
);
|
||||
}
|
||||
},
|
||||
child: Container(
|
||||
color: Colors.transparent,
|
||||
child: Padding(
|
||||
padding: isDesktop
|
||||
? const EdgeInsets.all(16)
|
||||
: const EdgeInsets.all(0),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
SizedBox(
|
||||
width: 20,
|
||||
height: 20,
|
||||
child: Padding(
|
||||
padding:
|
||||
EdgeInsets.only(top: isDesktop ? 20.0 : 15.0),
|
||||
child: Radio(
|
||||
activeColor: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.radioButtonIconEnabled,
|
||||
value: ChangeNowExchange.exchangeName,
|
||||
groupValue: ref.watch(exchangeFormStateProvider
|
||||
.select((value) => value.exchange.name)),
|
||||
onChanged: (_) {
|
||||
if (ref
|
||||
.read(exchangeFormStateProvider)
|
||||
.exchange
|
||||
.name !=
|
||||
ChangeNowExchange.exchangeName) {
|
||||
ref
|
||||
.read(exchangeFormStateProvider)
|
||||
.updateExchange(
|
||||
exchange: ChangeNowExchange.instance,
|
||||
shouldUpdateData: true,
|
||||
shouldNotifyListeners: true,
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
width: 14,
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 5.0),
|
||||
child: SizedBox(
|
||||
width: isDesktop ? 32 : 24,
|
||||
height: isDesktop ? 32 : 24,
|
||||
child: SvgPicture.asset(
|
||||
Assets.exchange.changeNow,
|
||||
width: isDesktop ? 32 : 24,
|
||||
height: isDesktop ? 32 : 24,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
width: 10,
|
||||
),
|
||||
Expanded(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
ChangeNowExchange.exchangeName,
|
||||
style:
|
||||
STextStyles.titleBold12(context).copyWith(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textDark2,
|
||||
),
|
||||
),
|
||||
if (sendCurrency != null &&
|
||||
receivingCurrency != null &&
|
||||
toAmount != null &&
|
||||
toAmount > Decimal.zero &&
|
||||
fromAmount != null &&
|
||||
fromAmount > Decimal.zero)
|
||||
FutureBuilder(
|
||||
future:
|
||||
ChangeNowExchange.instance.getEstimate(
|
||||
sendCurrency.ticker,
|
||||
receivingCurrency.ticker,
|
||||
widget.reversed ? toAmount : fromAmount,
|
||||
widget.fixedRate,
|
||||
widget.reversed,
|
||||
),
|
||||
builder: (context,
|
||||
AsyncSnapshot<ExchangeResponse<Estimate>>
|
||||
snapshot) {
|
||||
if (snapshot.connectionState ==
|
||||
ConnectionState.done &&
|
||||
snapshot.hasData) {
|
||||
final estimate = snapshot.data?.value;
|
||||
if (estimate != null) {
|
||||
Coin coin;
|
||||
try {
|
||||
coin = coinFromTickerCaseInsensitive(
|
||||
receivingCurrency.ticker);
|
||||
} catch (_) {
|
||||
coin = Coin.bitcoin;
|
||||
}
|
||||
Amount rate;
|
||||
if (estimate.reversed) {
|
||||
rate = (toAmount /
|
||||
estimate.estimatedAmount)
|
||||
.toDecimal(
|
||||
scaleOnInfinitePrecision: 18)
|
||||
.toAmount(
|
||||
fractionDigits:
|
||||
coin.decimals);
|
||||
} else {
|
||||
rate = (estimate.estimatedAmount /
|
||||
fromAmount)
|
||||
.toDecimal(
|
||||
scaleOnInfinitePrecision: 18)
|
||||
.toAmount(
|
||||
fractionDigits:
|
||||
coin.decimals);
|
||||
}
|
||||
|
||||
return Text(
|
||||
"1 ${sendCurrency.ticker.toUpperCase()} ~ ${rate.localizedStringAsFixed(
|
||||
locale: ref.watch(
|
||||
localeServiceChangeNotifierProvider
|
||||
.select(
|
||||
(value) => value.locale),
|
||||
),
|
||||
)} ${receivingCurrency.ticker.toUpperCase()}",
|
||||
style: STextStyles.itemSubtitle12(
|
||||
context)
|
||||
.copyWith(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textSubtitle1,
|
||||
),
|
||||
);
|
||||
} else if (snapshot.data?.exception
|
||||
is PairUnavailableException) {
|
||||
return Text(
|
||||
"Unsupported pair",
|
||||
style: STextStyles.itemSubtitle12(
|
||||
context)
|
||||
.copyWith(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textSubtitle1,
|
||||
),
|
||||
);
|
||||
} else {
|
||||
Logging.instance.log(
|
||||
"$runtimeType failed to fetch rate for ChangeNOW: ${snapshot.data}",
|
||||
level: LogLevel.Warning,
|
||||
);
|
||||
return Text(
|
||||
"Failed to fetch rate",
|
||||
style: STextStyles.itemSubtitle12(
|
||||
context)
|
||||
.copyWith(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textSubtitle1,
|
||||
),
|
||||
);
|
||||
}
|
||||
} else {
|
||||
return AnimatedText(
|
||||
stringsToLoopThrough: const [
|
||||
"Loading",
|
||||
"Loading.",
|
||||
"Loading..",
|
||||
"Loading...",
|
||||
],
|
||||
style:
|
||||
STextStyles.itemSubtitle12(context)
|
||||
.copyWith(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textSubtitle1,
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
if (!(sendCurrency != null &&
|
||||
receivingCurrency != null &&
|
||||
toAmount != null &&
|
||||
toAmount > Decimal.zero &&
|
||||
fromAmount != null &&
|
||||
fromAmount > Decimal.zero))
|
||||
Text(
|
||||
"n/a",
|
||||
style: STextStyles.itemSubtitle12(context)
|
||||
.copyWith(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textSubtitle1,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
ExchangeProviderOption(
|
||||
exchange: ChangeNowExchange.instance,
|
||||
exchangeProvider: ChangeNowExchange.exchangeName,
|
||||
fixedRate: widget.fixedRate,
|
||||
reversed: widget.reversed,
|
||||
),
|
||||
|
||||
if (showChangeNow && showMajesticBank)
|
||||
isDesktop
|
||||
? Container(
|
||||
|
@ -336,239 +100,12 @@ class _ExchangeProviderOptionsState
|
|||
: const SizedBox(
|
||||
height: 16,
|
||||
),
|
||||
|
||||
if (showMajesticBank)
|
||||
ConditionalParent(
|
||||
condition: isDesktop,
|
||||
builder: (child) => MouseRegion(
|
||||
cursor: SystemMouseCursors.click,
|
||||
child: child,
|
||||
),
|
||||
child: GestureDetector(
|
||||
onTap: () {
|
||||
if (ref.read(exchangeFormStateProvider).exchange.name !=
|
||||
MajesticBankExchange.exchangeName) {
|
||||
showLoading(
|
||||
whileFuture:
|
||||
ref.read(exchangeFormStateProvider).updateExchange(
|
||||
exchange: MajesticBankExchange.instance,
|
||||
shouldUpdateData: true,
|
||||
shouldNotifyListeners: true,
|
||||
),
|
||||
context: context,
|
||||
isDesktop: isDesktop,
|
||||
message: "Updating rates",
|
||||
);
|
||||
}
|
||||
},
|
||||
child: Container(
|
||||
color: Colors.transparent,
|
||||
child: Padding(
|
||||
padding: isDesktop
|
||||
? const EdgeInsets.all(16)
|
||||
: const EdgeInsets.all(0),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
SizedBox(
|
||||
width: 20,
|
||||
height: 20,
|
||||
child: Padding(
|
||||
padding:
|
||||
EdgeInsets.only(top: isDesktop ? 20.0 : 15.0),
|
||||
child: Radio(
|
||||
activeColor: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.radioButtonIconEnabled,
|
||||
value: MajesticBankExchange.exchangeName,
|
||||
groupValue: ref.watch(exchangeFormStateProvider
|
||||
.select((value) => value.exchange.name)),
|
||||
onChanged: (_) {
|
||||
if (ref
|
||||
.read(exchangeFormStateProvider)
|
||||
.exchange
|
||||
.name !=
|
||||
MajesticBankExchange.exchangeName) {
|
||||
ref
|
||||
.read(exchangeFormStateProvider)
|
||||
.updateExchange(
|
||||
exchange: MajesticBankExchange.instance,
|
||||
shouldUpdateData: true,
|
||||
shouldNotifyListeners: true,
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
width: 14,
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 5.0),
|
||||
child: SizedBox(
|
||||
width: isDesktop ? 32 : 24,
|
||||
height: isDesktop ? 32 : 24,
|
||||
child: SvgPicture.asset(
|
||||
Assets.exchange.majesticBankBlue,
|
||||
width: isDesktop ? 32 : 24,
|
||||
height: isDesktop ? 32 : 24,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
width: 10,
|
||||
),
|
||||
Expanded(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
MajesticBankExchange.exchangeName,
|
||||
style:
|
||||
STextStyles.titleBold12(context).copyWith(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textDark2,
|
||||
),
|
||||
),
|
||||
if (sendCurrency != null &&
|
||||
receivingCurrency != null &&
|
||||
toAmount != null &&
|
||||
toAmount > Decimal.zero &&
|
||||
fromAmount != null &&
|
||||
fromAmount > Decimal.zero)
|
||||
FutureBuilder(
|
||||
future:
|
||||
MajesticBankExchange.instance.getEstimate(
|
||||
sendCurrency.ticker,
|
||||
receivingCurrency.ticker,
|
||||
widget.reversed ? toAmount : fromAmount,
|
||||
widget.fixedRate,
|
||||
widget.reversed,
|
||||
),
|
||||
builder: (context,
|
||||
AsyncSnapshot<ExchangeResponse<Estimate>>
|
||||
snapshot) {
|
||||
if (snapshot.connectionState ==
|
||||
ConnectionState.done &&
|
||||
snapshot.hasData) {
|
||||
final estimate = snapshot.data?.value;
|
||||
if (estimate != null) {
|
||||
Coin coin;
|
||||
try {
|
||||
coin = coinFromTickerCaseInsensitive(
|
||||
receivingCurrency.ticker);
|
||||
} catch (_) {
|
||||
coin = Coin.bitcoin;
|
||||
}
|
||||
Amount rate;
|
||||
if (estimate.reversed) {
|
||||
rate = (toAmount /
|
||||
estimate.estimatedAmount)
|
||||
.toDecimal(
|
||||
scaleOnInfinitePrecision: 18)
|
||||
.toAmount(
|
||||
fractionDigits: coin.decimals,
|
||||
);
|
||||
} else {
|
||||
rate = (estimate.estimatedAmount /
|
||||
fromAmount)
|
||||
.toDecimal(
|
||||
scaleOnInfinitePrecision: 18)
|
||||
.toAmount(
|
||||
fractionDigits: coin.decimals,
|
||||
);
|
||||
}
|
||||
|
||||
return Text(
|
||||
"1 ${sendCurrency.ticker.toUpperCase()} ~ ${rate.localizedStringAsFixed(
|
||||
locale: ref.watch(
|
||||
localeServiceChangeNotifierProvider
|
||||
.select(
|
||||
(value) => value.locale),
|
||||
),
|
||||
)} ${receivingCurrency.ticker.toUpperCase()}",
|
||||
style: STextStyles.itemSubtitle12(
|
||||
context)
|
||||
.copyWith(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textSubtitle1,
|
||||
),
|
||||
);
|
||||
} else if (snapshot.data?.exception
|
||||
is PairUnavailableException) {
|
||||
return Text(
|
||||
"Unsupported pair",
|
||||
style: STextStyles.itemSubtitle12(
|
||||
context)
|
||||
.copyWith(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textSubtitle1,
|
||||
),
|
||||
);
|
||||
} else {
|
||||
Logging.instance.log(
|
||||
"$runtimeType failed to fetch rate for Majestic Bank: ${snapshot.data}",
|
||||
level: LogLevel.Warning,
|
||||
);
|
||||
return Text(
|
||||
"Failed to fetch rate",
|
||||
style: STextStyles.itemSubtitle12(
|
||||
context)
|
||||
.copyWith(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textSubtitle1,
|
||||
),
|
||||
);
|
||||
}
|
||||
} else {
|
||||
return AnimatedText(
|
||||
stringsToLoopThrough: const [
|
||||
"Loading",
|
||||
"Loading.",
|
||||
"Loading..",
|
||||
"Loading...",
|
||||
],
|
||||
style:
|
||||
STextStyles.itemSubtitle12(context)
|
||||
.copyWith(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textSubtitle1,
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
if (!(sendCurrency != null &&
|
||||
receivingCurrency != null &&
|
||||
toAmount != null &&
|
||||
toAmount > Decimal.zero &&
|
||||
fromAmount != null &&
|
||||
fromAmount > Decimal.zero))
|
||||
Text(
|
||||
"n/a",
|
||||
style: STextStyles.itemSubtitle12(context)
|
||||
.copyWith(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textSubtitle1,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
ExchangeProviderOption(
|
||||
exchange: MajesticBankExchange.instance,
|
||||
exchangeProvider: MajesticBankExchange.exchangeName,
|
||||
fixedRate: widget.fixedRate,
|
||||
reversed: widget.reversed,
|
||||
),
|
||||
if ((showChangeNow || showMajesticBank) && showTrocador)
|
||||
isDesktop
|
||||
|
@ -580,448 +117,13 @@ class _ExchangeProviderOptionsState
|
|||
: const SizedBox(
|
||||
height: 16,
|
||||
),
|
||||
|
||||
if (showTrocador)
|
||||
ConditionalParent(
|
||||
condition: isDesktop,
|
||||
builder: (child) => MouseRegion(
|
||||
cursor: SystemMouseCursors.click,
|
||||
child: child,
|
||||
),
|
||||
child: GestureDetector(
|
||||
onTap: () {
|
||||
if (ref.read(exchangeFormStateProvider).exchange.name !=
|
||||
TrocadorExchange.exchangeName) {
|
||||
showLoading(
|
||||
whileFuture:
|
||||
ref.read(exchangeFormStateProvider).updateExchange(
|
||||
exchange: TrocadorExchange.instance,
|
||||
shouldUpdateData: true,
|
||||
shouldNotifyListeners: true,
|
||||
),
|
||||
context: context,
|
||||
isDesktop: isDesktop,
|
||||
message: "Updating rates",
|
||||
);
|
||||
}
|
||||
},
|
||||
child: Container(
|
||||
color: Colors.transparent,
|
||||
child: Padding(
|
||||
padding: isDesktop
|
||||
? const EdgeInsets.all(16)
|
||||
: const EdgeInsets.all(0),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
SizedBox(
|
||||
width: 20,
|
||||
height: 20,
|
||||
child: Padding(
|
||||
padding:
|
||||
EdgeInsets.only(top: isDesktop ? 20.0 : 15.0),
|
||||
child: Radio(
|
||||
activeColor: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.radioButtonIconEnabled,
|
||||
value: TrocadorExchange.exchangeName,
|
||||
groupValue: ref.watch(exchangeFormStateProvider
|
||||
.select((value) => value.exchange.name)),
|
||||
onChanged: (_) {
|
||||
if (ref
|
||||
.read(exchangeFormStateProvider)
|
||||
.exchange
|
||||
.name !=
|
||||
TrocadorExchange.exchangeName) {
|
||||
ref
|
||||
.read(exchangeFormStateProvider)
|
||||
.updateExchange(
|
||||
exchange: TrocadorExchange.instance,
|
||||
shouldUpdateData: true,
|
||||
shouldNotifyListeners: true,
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
width: 14,
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 5.0),
|
||||
child: SizedBox(
|
||||
width: isDesktop ? 32 : 24,
|
||||
height: isDesktop ? 32 : 24,
|
||||
child: SvgPicture.asset(
|
||||
Assets.exchange.trocador,
|
||||
width: isDesktop ? 32 : 24,
|
||||
height: isDesktop ? 32 : 24,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
width: 10,
|
||||
),
|
||||
Expanded(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
TrocadorExchange.exchangeName,
|
||||
style:
|
||||
STextStyles.titleBold12(context).copyWith(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textDark2,
|
||||
),
|
||||
),
|
||||
if (sendCurrency != null &&
|
||||
receivingCurrency != null &&
|
||||
toAmount != null &&
|
||||
toAmount > Decimal.zero &&
|
||||
fromAmount != null &&
|
||||
fromAmount > Decimal.zero)
|
||||
FutureBuilder(
|
||||
future: TrocadorExchange.instance.getEstimate(
|
||||
sendCurrency.ticker,
|
||||
receivingCurrency.ticker,
|
||||
widget.reversed ? toAmount : fromAmount,
|
||||
widget.fixedRate,
|
||||
widget.reversed,
|
||||
),
|
||||
builder: (context,
|
||||
AsyncSnapshot<ExchangeResponse<Estimate>>
|
||||
snapshot) {
|
||||
if (snapshot.connectionState ==
|
||||
ConnectionState.done &&
|
||||
snapshot.hasData) {
|
||||
final estimate = snapshot.data?.value;
|
||||
if (estimate != null) {
|
||||
Coin coin;
|
||||
try {
|
||||
coin = coinFromTickerCaseInsensitive(
|
||||
receivingCurrency.ticker);
|
||||
} catch (_) {
|
||||
coin = Coin.bitcoin;
|
||||
}
|
||||
Amount rate;
|
||||
if (estimate.reversed) {
|
||||
rate = (toAmount /
|
||||
estimate.estimatedAmount)
|
||||
.toDecimal(
|
||||
scaleOnInfinitePrecision: 18)
|
||||
.toAmount(
|
||||
fractionDigits: coin.decimals,
|
||||
);
|
||||
} else {
|
||||
rate = (estimate.estimatedAmount /
|
||||
fromAmount)
|
||||
.toDecimal(
|
||||
scaleOnInfinitePrecision: 18)
|
||||
.toAmount(
|
||||
fractionDigits: coin.decimals,
|
||||
);
|
||||
}
|
||||
|
||||
return Text(
|
||||
"1 ${sendCurrency.ticker.toUpperCase()} ~ ${rate.localizedStringAsFixed(
|
||||
locale: ref.watch(
|
||||
localeServiceChangeNotifierProvider
|
||||
.select(
|
||||
(value) => value.locale),
|
||||
),
|
||||
)} ${receivingCurrency.ticker.toUpperCase()}",
|
||||
style: STextStyles.itemSubtitle12(
|
||||
context)
|
||||
.copyWith(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textSubtitle1,
|
||||
),
|
||||
);
|
||||
} else if (snapshot.data?.exception
|
||||
is PairUnavailableException) {
|
||||
return Text(
|
||||
"Unsupported pair",
|
||||
style: STextStyles.itemSubtitle12(
|
||||
context)
|
||||
.copyWith(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textSubtitle1,
|
||||
),
|
||||
);
|
||||
} else {
|
||||
Logging.instance.log(
|
||||
"$runtimeType failed to fetch rate for Trocador: ${snapshot.data}",
|
||||
level: LogLevel.Warning,
|
||||
);
|
||||
return Text(
|
||||
"Failed to fetch rate",
|
||||
style: STextStyles.itemSubtitle12(
|
||||
context)
|
||||
.copyWith(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textSubtitle1,
|
||||
),
|
||||
);
|
||||
}
|
||||
} else {
|
||||
return AnimatedText(
|
||||
stringsToLoopThrough: const [
|
||||
"Loading",
|
||||
"Loading.",
|
||||
"Loading..",
|
||||
"Loading...",
|
||||
],
|
||||
style:
|
||||
STextStyles.itemSubtitle12(context)
|
||||
.copyWith(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textSubtitle1,
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
if (!(sendCurrency != null &&
|
||||
receivingCurrency != null &&
|
||||
toAmount != null &&
|
||||
toAmount > Decimal.zero &&
|
||||
fromAmount != null &&
|
||||
fromAmount > Decimal.zero))
|
||||
Text(
|
||||
"n/a",
|
||||
style: STextStyles.itemSubtitle12(context)
|
||||
.copyWith(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textSubtitle1,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const TrocadorKYCInfoButton(
|
||||
kycType: TrocadorKYCType.a,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
ExchangeProviderOption(
|
||||
fixedRate: widget.fixedRate,
|
||||
reversed: widget.reversed,
|
||||
exchange: TrocadorExchange.instance,
|
||||
exchangeProvider: 'LetsExchange',
|
||||
),
|
||||
// if (isDesktop)
|
||||
// Container(
|
||||
// height: 1,
|
||||
// color: Theme.of(context).extension<StackColors>()!.background,
|
||||
// ),
|
||||
// if (!isDesktop)
|
||||
// const SizedBox(
|
||||
// height: 16,
|
||||
// ),
|
||||
// ConditionalParent(
|
||||
// condition: isDesktop,
|
||||
// builder: (child) => MouseRegion(
|
||||
// cursor: SystemMouseCursors.click,
|
||||
// child: child,
|
||||
// ),
|
||||
// child: GestureDetector(
|
||||
// onTap: () {
|
||||
// if (ref.read(currentExchangeNameStateProvider.state).state !=
|
||||
// SimpleSwapExchange.exchangeName) {
|
||||
// // ref.read(currentExchangeNameStateProvider.state).state =
|
||||
// // SimpleSwapExchange.exchangeName;
|
||||
// ref.read(exchangeFormStateProvider).exchange =
|
||||
// Exchange.fromName(ref
|
||||
// .read(currentExchangeNameStateProvider.state)
|
||||
// .state);
|
||||
// }
|
||||
// },
|
||||
// child: Container(
|
||||
// color: Colors.transparent,
|
||||
// child: Padding(
|
||||
// padding: isDesktop
|
||||
// ? const EdgeInsets.all(16)
|
||||
// : const EdgeInsets.all(0),
|
||||
// child: Row(
|
||||
// crossAxisAlignment: CrossAxisAlignment.start,
|
||||
// children: [
|
||||
// SizedBox(
|
||||
// width: 20,
|
||||
// height: 20,
|
||||
// child: Radio(
|
||||
// activeColor: Theme.of(context)
|
||||
// .extension<StackColors>()!
|
||||
// .radioButtonIconEnabled,
|
||||
// value: SimpleSwapExchange.exchangeName,
|
||||
// groupValue: ref
|
||||
// .watch(currentExchangeNameStateProvider.state)
|
||||
// .state,
|
||||
// onChanged: (value) {
|
||||
// if (value is String) {
|
||||
// ref
|
||||
// .read(currentExchangeNameStateProvider.state)
|
||||
// .state = value;
|
||||
// ref.read(exchangeFormStateProvider).exchange =
|
||||
// Exchange.fromName(ref
|
||||
// .read(currentExchangeNameStateProvider
|
||||
// .state)
|
||||
// .state);
|
||||
// }
|
||||
// },
|
||||
// ),
|
||||
// ),
|
||||
// const SizedBox(
|
||||
// width: 14,
|
||||
// ),
|
||||
// // SvgPicture.asset(
|
||||
// // Assets.exchange.simpleSwap,
|
||||
// // width: isDesktop ? 32 : 24,
|
||||
// // height: isDesktop ? 32 : 24,
|
||||
// // ),
|
||||
// // const SizedBox(
|
||||
// // width: 10,
|
||||
// // ),
|
||||
// // Expanded(
|
||||
// // child: Column(
|
||||
// // mainAxisAlignment: MainAxisAlignment.start,
|
||||
// // mainAxisSize: MainAxisSize.min,
|
||||
// // crossAxisAlignment: CrossAxisAlignment.start,
|
||||
// // children: [
|
||||
// // Text(
|
||||
// // SimpleSwapExchange.exchangeName,
|
||||
// // style: STextStyles.titleBold12(context).copyWith(
|
||||
// // color: Theme.of(context)
|
||||
// // .extension<StackColors>()!
|
||||
// // .textDark2,
|
||||
// // ),
|
||||
// // ),
|
||||
// // if (from != null &&
|
||||
// // to != null &&
|
||||
// // toAmount != null &&
|
||||
// // toAmount! > Decimal.zero &&
|
||||
// // fromAmount != null &&
|
||||
// // fromAmount! > Decimal.zero)
|
||||
// // FutureBuilder(
|
||||
// // future: SimpleSwapExchange().getEstimate(
|
||||
// // from!,
|
||||
// // to!,
|
||||
// // // reversed ? toAmount! : fromAmount!,
|
||||
// // fromAmount!,
|
||||
// // fixedRate,
|
||||
// // // reversed,
|
||||
// // false,
|
||||
// // ),
|
||||
// // builder: (context,
|
||||
// // AsyncSnapshot<ExchangeResponse<Estimate>>
|
||||
// // snapshot) {
|
||||
// // if (snapshot.connectionState ==
|
||||
// // ConnectionState.done &&
|
||||
// // snapshot.hasData) {
|
||||
// // final estimate = snapshot.data?.value;
|
||||
// // if (estimate != null) {
|
||||
// // Decimal rate = (estimate.estimatedAmount /
|
||||
// // fromAmount!)
|
||||
// // .toDecimal(
|
||||
// // scaleOnInfinitePrecision: 12);
|
||||
// //
|
||||
// // Coin coin;
|
||||
// // try {
|
||||
// // coin =
|
||||
// // coinFromTickerCaseInsensitive(to!);
|
||||
// // } catch (_) {
|
||||
// // coin = Coin.bitcoin;
|
||||
// // }
|
||||
// // return Text(
|
||||
// // "1 ${from!.toUpperCase()} ~ ${Format.localizedStringAsFixed(
|
||||
// // value: rate,
|
||||
// // locale: ref.watch(
|
||||
// // localeServiceChangeNotifierProvider
|
||||
// // .select(
|
||||
// // (value) => value.locale),
|
||||
// // ),
|
||||
// // decimalPlaces:
|
||||
// // Constants.decimalPlacesForCoin(
|
||||
// // coin),
|
||||
// // )} ${to!.toUpperCase()}",
|
||||
// // style:
|
||||
// // STextStyles.itemSubtitle12(context)
|
||||
// // .copyWith(
|
||||
// // color: Theme.of(context)
|
||||
// // .extension<StackColors>()!
|
||||
// // .textSubtitle1,
|
||||
// // ),
|
||||
// // );
|
||||
// // } else {
|
||||
// // Logging.instance.log(
|
||||
// // "$runtimeType failed to fetch rate for SimpleSwap: ${snapshot.data}",
|
||||
// // level: LogLevel.Warning,
|
||||
// // );
|
||||
// // return Text(
|
||||
// // "Failed to fetch rate",
|
||||
// // style:
|
||||
// // STextStyles.itemSubtitle12(context)
|
||||
// // .copyWith(
|
||||
// // color: Theme.of(context)
|
||||
// // .extension<StackColors>()!
|
||||
// // .textSubtitle1,
|
||||
// // ),
|
||||
// // );
|
||||
// // }
|
||||
// // } else {
|
||||
// // return AnimatedText(
|
||||
// // stringsToLoopThrough: const [
|
||||
// // "Loading",
|
||||
// // "Loading.",
|
||||
// // "Loading..",
|
||||
// // "Loading...",
|
||||
// // ],
|
||||
// // style: STextStyles.itemSubtitle12(context)
|
||||
// // .copyWith(
|
||||
// // color: Theme.of(context)
|
||||
// // .extension<StackColors>()!
|
||||
// // .textSubtitle1,
|
||||
// // ),
|
||||
// // );
|
||||
// // }
|
||||
// // },
|
||||
// // ),
|
||||
// // // if (!(from != null &&
|
||||
// // // to != null &&
|
||||
// // // (reversed
|
||||
// // // ? toAmount != null && toAmount! > Decimal.zero
|
||||
// // // : fromAmount != null &&
|
||||
// // // fromAmount! > Decimal.zero)))
|
||||
// // if (!(from != null &&
|
||||
// // to != null &&
|
||||
// // toAmount != null &&
|
||||
// // toAmount! > Decimal.zero &&
|
||||
// // fromAmount != null &&
|
||||
// // fromAmount! > Decimal.zero))
|
||||
// // Text(
|
||||
// // "n/a",
|
||||
// // style: STextStyles.itemSubtitle12(context)
|
||||
// // .copyWith(
|
||||
// // color: Theme.of(context)
|
||||
// // .extension<StackColors>()!
|
||||
// // .textSubtitle1,
|
||||
// // ),
|
||||
// // ),
|
||||
// // ],
|
||||
// // ),
|
||||
// // ),
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
|
|
@ -483,6 +483,7 @@ class ChangeNowAPI {
|
|||
reversed: false,
|
||||
rateId: value.rateId,
|
||||
warningMessage: value.warningMessage,
|
||||
exchangeProvider: ChangeNowExchange.exchangeName,
|
||||
),
|
||||
);
|
||||
} catch (_) {
|
||||
|
@ -566,6 +567,7 @@ class ChangeNowAPI {
|
|||
reversed: reversed,
|
||||
rateId: value.rateId,
|
||||
warningMessage: value.warningMessage,
|
||||
exchangeProvider: ChangeNowExchange.exchangeName,
|
||||
),
|
||||
);
|
||||
} catch (_) {
|
||||
|
|
|
@ -128,7 +128,7 @@ class ChangeNowExchange extends Exchange {
|
|||
}
|
||||
|
||||
@override
|
||||
Future<ExchangeResponse<Estimate>> getEstimate(
|
||||
Future<ExchangeResponse<List<Estimate>>> getEstimates(
|
||||
String from,
|
||||
String to,
|
||||
Decimal amount,
|
||||
|
@ -151,7 +151,10 @@ class ChangeNowExchange extends Exchange {
|
|||
fromAmount: amount,
|
||||
);
|
||||
}
|
||||
return response;
|
||||
return ExchangeResponse(
|
||||
value: response.value == null ? null : [response.value!],
|
||||
exception: response.exception,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
|
|
|
@ -60,7 +60,7 @@ abstract class Exchange {
|
|||
bool fixedRate,
|
||||
);
|
||||
|
||||
Future<ExchangeResponse<Estimate>> getEstimate(
|
||||
Future<ExchangeResponse<List<Estimate>>> getEstimates(
|
||||
String from,
|
||||
String to,
|
||||
Decimal amount,
|
||||
|
|
|
@ -170,7 +170,7 @@ class MajesticBankExchange extends Exchange {
|
|||
}
|
||||
|
||||
@override
|
||||
Future<ExchangeResponse<Estimate>> getEstimate(
|
||||
Future<ExchangeResponse<List<Estimate>>> getEstimates(
|
||||
String from,
|
||||
String to,
|
||||
Decimal amount,
|
||||
|
@ -192,8 +192,9 @@ class MajesticBankExchange extends Exchange {
|
|||
estimatedAmount: reversed ? calc.fromAmount : calc.receiveAmount,
|
||||
fixedRate: fixedRate,
|
||||
reversed: reversed,
|
||||
exchangeProvider: MajesticBankExchange.exchangeName,
|
||||
);
|
||||
return ExchangeResponse(value: estimate);
|
||||
return ExchangeResponse(value: [estimate]);
|
||||
}
|
||||
|
||||
@override
|
||||
|
|
|
@ -89,7 +89,7 @@ class SimpleSwapExchange extends Exchange {
|
|||
}
|
||||
|
||||
@override
|
||||
Future<ExchangeResponse<Estimate>> getEstimate(
|
||||
Future<ExchangeResponse<List<Estimate>>> getEstimates(
|
||||
String from,
|
||||
String to,
|
||||
Decimal amount,
|
||||
|
@ -109,11 +109,14 @@ class SimpleSwapExchange extends Exchange {
|
|||
}
|
||||
|
||||
return ExchangeResponse(
|
||||
value: Estimate(
|
||||
estimatedAmount: Decimal.parse(response.value!),
|
||||
fixedRate: fixedRate,
|
||||
reversed: reversed,
|
||||
),
|
||||
value: [
|
||||
Estimate(
|
||||
estimatedAmount: Decimal.parse(response.value!),
|
||||
fixedRate: fixedRate,
|
||||
reversed: reversed,
|
||||
exchangeProvider: SimpleSwapExchange.exchangeName,
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -5,7 +5,8 @@ class TrocadorQuote {
|
|||
final String kycRating;
|
||||
final int insurance;
|
||||
final bool fixed;
|
||||
final Decimal amountTo;
|
||||
final Decimal? amountTo;
|
||||
final Decimal? amountFrom;
|
||||
final Decimal waste;
|
||||
|
||||
TrocadorQuote({
|
||||
|
@ -14,6 +15,7 @@ class TrocadorQuote {
|
|||
required this.insurance,
|
||||
required this.fixed,
|
||||
required this.amountTo,
|
||||
required this.amountFrom,
|
||||
required this.waste,
|
||||
});
|
||||
|
||||
|
@ -24,7 +26,8 @@ class TrocadorQuote {
|
|||
insurance: map['insurance'] as int,
|
||||
// wtf trocador?
|
||||
fixed: map['fixed'] == "True",
|
||||
amountTo: Decimal.parse(map['amount_to'].toString()),
|
||||
amountTo: Decimal.tryParse(map['amount_to'].toString()),
|
||||
amountFrom: Decimal.tryParse(map['amount_from'].toString()),
|
||||
waste: Decimal.parse(map['waste'].toString()),
|
||||
);
|
||||
}
|
||||
|
@ -37,6 +40,7 @@ class TrocadorQuote {
|
|||
'insurance: $insurance, '
|
||||
'fixed: $fixed, '
|
||||
'amountTo: $amountTo, '
|
||||
'amountFrom: $amountFrom, '
|
||||
'waste: $waste '
|
||||
')';
|
||||
}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
import 'dart:math';
|
||||
|
||||
import 'package:decimal/decimal.dart';
|
||||
import 'package:stackwallet/exceptions/exchange/exchange_exception.dart';
|
||||
import 'package:stackwallet/models/exchange/response_objects/estimate.dart';
|
||||
|
@ -8,6 +10,7 @@ import 'package:stackwallet/models/isar/exchange_cache/pair.dart';
|
|||
import 'package:stackwallet/services/exchange/exchange.dart';
|
||||
import 'package:stackwallet/services/exchange/exchange_response.dart';
|
||||
import 'package:stackwallet/services/exchange/trocador/response_objects/trocador_coin.dart';
|
||||
import 'package:stackwallet/services/exchange/trocador/response_objects/trocador_quote.dart';
|
||||
import 'package:stackwallet/services/exchange/trocador/trocador_api.dart';
|
||||
import 'package:uuid/uuid.dart';
|
||||
|
||||
|
@ -177,7 +180,7 @@ class TrocadorExchange extends Exchange {
|
|||
}
|
||||
|
||||
@override
|
||||
Future<ExchangeResponse<Estimate>> getEstimate(
|
||||
Future<ExchangeResponse<List<Estimate>>> getEstimates(
|
||||
String from,
|
||||
String to,
|
||||
Decimal amount,
|
||||
|
@ -208,15 +211,47 @@ class TrocadorExchange extends Exchange {
|
|||
return ExchangeResponse(exception: response.exception);
|
||||
}
|
||||
|
||||
final List<Estimate> estimates = [];
|
||||
final List<TrocadorQuote> cOrLowerQuotes = [];
|
||||
|
||||
for (final quote in response.value!.quotes) {
|
||||
if (quote.fixed == isPayment) {
|
||||
final rating = quote.kycRating.toLowerCase();
|
||||
if (rating == "a" || rating == "b") {
|
||||
estimates.add(
|
||||
Estimate(
|
||||
estimatedAmount: isPayment ? quote.amountFrom! : quote.amountTo!,
|
||||
fixedRate: quote.fixed,
|
||||
reversed: isPayment,
|
||||
exchangeProvider: quote.provider,
|
||||
rateId: response.value!.tradeId,
|
||||
kycRating: quote.kycRating,
|
||||
),
|
||||
);
|
||||
} else {
|
||||
cOrLowerQuotes.add(quote);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cOrLowerQuotes.sort((a, b) => b.waste.compareTo(a.waste));
|
||||
|
||||
for (int i = 0; i < max(3, cOrLowerQuotes.length); i++) {
|
||||
final quote = cOrLowerQuotes[i];
|
||||
estimates.add(
|
||||
Estimate(
|
||||
estimatedAmount: isPayment ? quote.amountFrom! : quote.amountTo!,
|
||||
fixedRate: quote.fixed,
|
||||
reversed: isPayment,
|
||||
exchangeProvider: quote.provider,
|
||||
rateId: response.value!.tradeId,
|
||||
kycRating: quote.kycRating,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return ExchangeResponse(
|
||||
value: Estimate(
|
||||
estimatedAmount:
|
||||
isPayment ? response.value!.amountFrom : response.value!.amountTo,
|
||||
fixedRate: isPayment,
|
||||
reversed: isPayment,
|
||||
exchangeProvider: response.value!.provider,
|
||||
rateId: response.value!.tradeId,
|
||||
),
|
||||
value: estimates,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:stackwallet/services/exchange/change_now/change_now_exchange.dart';
|
||||
import 'package:stackwallet/services/exchange/majestic_bank/majestic_bank_exchange.dart';
|
||||
import 'package:stackwallet/services/exchange/simpleswap/simpleswap_exchange.dart';
|
||||
import 'package:stackwallet/services/exchange/trocador/trocador_exchange.dart';
|
||||
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||
import 'package:stackwallet/utilities/theme/color_theme.dart';
|
||||
import 'package:stackwallet/utilities/theme/stack_colors.dart';
|
||||
|
@ -64,6 +68,22 @@ class _EXCHANGE {
|
|||
String get majesticBankBlue => "${_path}mb_blue.svg";
|
||||
String get majesticBankGreen => "${_path}mb_green.svg";
|
||||
String get trocador => "${_path}trocador.svg";
|
||||
|
||||
String getIconFor({required String exchangeName}) {
|
||||
switch (exchangeName) {
|
||||
case SimpleSwapExchange.exchangeName:
|
||||
return simpleSwap;
|
||||
case ChangeNowExchange.exchangeName:
|
||||
return changeNow;
|
||||
case MajesticBankExchange.exchangeName:
|
||||
return majesticBankBlue;
|
||||
case TrocadorExchange.exchangeName:
|
||||
return trocador;
|
||||
default:
|
||||
throw ArgumentError("Invalid exchange name passed to "
|
||||
"Assets.exchange.getIconFor()");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class _BUY {
|
||||
|
|
|
@ -3,4 +3,13 @@ enum TrocadorKYCType {
|
|||
b,
|
||||
c,
|
||||
d;
|
||||
|
||||
static TrocadorKYCType fromString(String type) {
|
||||
for (final result in values) {
|
||||
if (result.name == type.toLowerCase()) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
throw ArgumentError("Invalid trocador kyc type: $type");
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue