only show exchanges supported by selected aggregate currency pair based on exchange flow type

This commit is contained in:
julian 2023-02-08 14:06:58 -06:00
parent b1c8a56ba6
commit 4630d616cd
5 changed files with 543 additions and 432 deletions

View file

@ -19,8 +19,22 @@ class AggregateCurrency {
} }
String get ticker => _map.values.first!.ticker; String get ticker => _map.values.first!.ticker;
String get name => _map.values.first!.name; String get name => _map.values.first!.name;
String get image => _map.values.first!.image; String get image => _map.values.first!.image;
SupportedRateType get rateType => _map.values.first!.rateType; SupportedRateType get rateType => _map.values.first!.rateType;
bool get isStackCoin => _map.values.first!.isStackCoin; bool get isStackCoin => _map.values.first!.isStackCoin;
@override
String toString() {
String str = "AggregateCurrency: {";
for (final key in _map.keys) {
str += " $key: ${_map[key]},";
}
str += " }";
return str;
}
} }

View file

@ -3,7 +3,9 @@ import 'package:flutter/foundation.dart';
import 'package:stackwallet/models/exchange/aggregate_currency.dart'; import 'package:stackwallet/models/exchange/aggregate_currency.dart';
import 'package:stackwallet/models/exchange/response_objects/estimate.dart'; import 'package:stackwallet/models/exchange/response_objects/estimate.dart';
import 'package:stackwallet/pages/exchange_view/sub_widgets/exchange_rate_sheet.dart'; import 'package:stackwallet/pages/exchange_view/sub_widgets/exchange_rate_sheet.dart';
import 'package:stackwallet/services/exchange/change_now/change_now_exchange.dart';
import 'package:stackwallet/services/exchange/exchange.dart'; import 'package:stackwallet/services/exchange/exchange.dart';
import 'package:stackwallet/services/exchange/majestic_bank/majestic_bank_exchange.dart';
import 'package:stackwallet/utilities/logger.dart'; import 'package:stackwallet/utilities/logger.dart';
class ExchangeFormState extends ChangeNotifier { class ExchangeFormState extends ChangeNotifier {
@ -323,6 +325,29 @@ class ExchangeFormState extends ChangeNotifier {
required bool shouldNotifyListeners, required bool shouldNotifyListeners,
}) async { }) async {
try { try {
switch (exchange.name) {
case ChangeNowExchange.exchangeName:
if (!_exchangeSupported(
exchangeName: exchange.name,
sendCurrency: sendCurrency,
receiveCurrency: receiveCurrency,
exchangeRateType: exchangeRateType,
)) {
_exchange = MajesticBankExchange.instance;
}
break;
case MajesticBankExchange.exchangeName:
if (!_exchangeSupported(
exchangeName: exchange.name,
sendCurrency: sendCurrency,
receiveCurrency: receiveCurrency,
exchangeRateType: exchangeRateType,
)) {
_exchange = ChangeNowExchange.instance;
}
break;
}
await _updateRanges(shouldNotifyListeners: false); await _updateRanges(shouldNotifyListeners: false);
await _updateEstimate(shouldNotifyListeners: false); await _updateEstimate(shouldNotifyListeners: false);
if (shouldNotifyListeners) { if (shouldNotifyListeners) {
@ -452,6 +477,25 @@ class ExchangeFormState extends ChangeNotifier {
notifyListeners(); notifyListeners();
} }
bool _exchangeSupported({
required String exchangeName,
required AggregateCurrency? sendCurrency,
required AggregateCurrency? receiveCurrency,
required ExchangeRateType exchangeRateType,
}) {
final send = sendCurrency?.forExchange(exchangeName);
if (send == null) return false;
final rcv = receiveCurrency?.forExchange(exchangeName);
if (rcv == null) return false;
if (exchangeRateType == ExchangeRateType.fixed) {
return send.supportsFixedRate && rcv.supportsFixedRate;
} else {
return send.supportsEstimatedRate && rcv.supportsEstimatedRate;
}
}
@override @override
String toString() { String toString() {
return "{" return "{"

View file

@ -44,6 +44,12 @@ class Currency {
@Index() @Index()
final bool isStackCoin; final bool isStackCoin;
@ignore
bool get supportsFixedRate => rateType == SupportedRateType.fixed || rateType == SupportedRateType.both;
@ignore
bool get supportsEstimatedRate => rateType == SupportedRateType.estimated || rateType == SupportedRateType.both;
Currency({ Currency({
required this.exchangeName, required this.exchangeName,
required this.ticker, required this.ticker,

View file

@ -862,10 +862,6 @@ class _ExchangeFormState extends ConsumerState<ExchangeForm> {
if (ref.watch(exchangeFormStateProvider).sendAmount != null && if (ref.watch(exchangeFormStateProvider).sendAmount != null &&
ref.watch(exchangeFormStateProvider).sendAmount != Decimal.zero) ref.watch(exchangeFormStateProvider).sendAmount != Decimal.zero)
ExchangeProviderOptions( ExchangeProviderOptions(
from: ref.watch(exchangeFormStateProvider).fromTicker,
to: ref.watch(exchangeFormStateProvider).toTicker,
fromAmount: ref.watch(exchangeFormStateProvider).sendAmount,
toAmount: ref.watch(exchangeFormStateProvider).receiveAmount,
fixedRate: rateType == ExchangeRateType.fixed, fixedRate: rateType == ExchangeRateType.fixed,
reversed: ref.watch( reversed: ref.watch(
exchangeFormStateProvider.select((value) => value.reversed)), exchangeFormStateProvider.select((value) => value.reversed)),

View file

@ -3,6 +3,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_svg/svg.dart'; import 'package:flutter_svg/svg.dart';
import 'package:stackwallet/exceptions/exchange/pair_unavailable_exception.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/models/exchange/response_objects/estimate.dart';
import 'package:stackwallet/providers/providers.dart'; import 'package:stackwallet/providers/providers.dart';
import 'package:stackwallet/services/exchange/change_now/change_now_exchange.dart'; import 'package:stackwallet/services/exchange/change_now/change_now_exchange.dart';
@ -20,27 +21,62 @@ import 'package:stackwallet/widgets/animated_text.dart';
import 'package:stackwallet/widgets/conditional_parent.dart'; import 'package:stackwallet/widgets/conditional_parent.dart';
import 'package:stackwallet/widgets/rounded_white_container.dart'; import 'package:stackwallet/widgets/rounded_white_container.dart';
class ExchangeProviderOptions extends ConsumerWidget { class ExchangeProviderOptions extends ConsumerStatefulWidget {
const ExchangeProviderOptions({ const ExchangeProviderOptions({
Key? key, Key? key,
required this.from,
required this.to,
required this.fromAmount,
required this.toAmount,
required this.fixedRate, required this.fixedRate,
required this.reversed, required this.reversed,
}) : super(key: key); }) : super(key: key);
final String? from;
final String? to;
final Decimal? fromAmount;
final Decimal? toAmount;
final bool fixedRate; final bool fixedRate;
final bool reversed; final bool reversed;
@override @override
Widget build(BuildContext context, WidgetRef ref) { ConsumerState<ExchangeProviderOptions> createState() =>
final isDesktop = Util.isDesktop; _ExchangeProviderOptionsState();
}
class _ExchangeProviderOptionsState
extends ConsumerState<ExchangeProviderOptions> {
final isDesktop = Util.isDesktop;
bool exchangeSupported({
required String exchangeName,
required AggregateCurrency? sendCurrency,
required AggregateCurrency? receiveCurrency,
}) {
final send = sendCurrency?.forExchange(exchangeName);
if (send == null) return false;
final rcv = receiveCurrency?.forExchange(exchangeName);
if (rcv == null) return false;
if (widget.fixedRate) {
return send.supportsFixedRate && rcv.supportsFixedRate;
} else {
return send.supportsEstimatedRate && rcv.supportsEstimatedRate;
}
}
@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 showChangeNow = exchangeSupported(
exchangeName: ChangeNowExchange.exchangeName,
sendCurrency: sendCurrency,
receiveCurrency: receivingCurrency,
);
final showMajesticBank = exchangeSupported(
exchangeName: MajesticBankExchange.exchangeName,
sendCurrency: sendCurrency,
receiveCurrency: receivingCurrency,
);
return RoundedWhiteContainer( return RoundedWhiteContainer(
padding: isDesktop ? const EdgeInsets.all(0) : const EdgeInsets.all(12), padding: isDesktop ? const EdgeInsets.all(0) : const EdgeInsets.all(12),
borderColor: isDesktop borderColor: isDesktop
@ -48,181 +84,203 @@ class ExchangeProviderOptions extends ConsumerWidget {
: null, : null,
child: Column( child: Column(
children: [ children: [
ConditionalParent( if (showChangeNow)
condition: isDesktop, ConditionalParent(
builder: (child) => MouseRegion( condition: isDesktop,
cursor: SystemMouseCursors.click, builder: (child) => MouseRegion(
child: child, cursor: SystemMouseCursors.click,
), child: child,
child: GestureDetector( ),
onTap: () { child: GestureDetector(
if (ref.read(currentExchangeNameStateProvider.state).state != onTap: () {
ChangeNowExchange.exchangeName) { if (ref.read(currentExchangeNameStateProvider.state).state !=
ref.read(currentExchangeNameStateProvider.state).state = ChangeNowExchange.exchangeName) {
ChangeNowExchange.exchangeName; ref.read(currentExchangeNameStateProvider.state).state =
ref.read(exchangeFormStateProvider).updateExchange( ChangeNowExchange.exchangeName;
exchange: ref.read(exchangeProvider), ref.read(exchangeFormStateProvider).updateExchange(
shouldUpdateData: true, exchange: ref.read(exchangeProvider),
shouldNotifyListeners: true, shouldUpdateData: true,
); shouldNotifyListeners: true,
} );
}, }
child: Container( },
color: Colors.transparent, child: Container(
child: Padding( color: Colors.transparent,
padding: isDesktop child: Padding(
? const EdgeInsets.all(16) padding: isDesktop
: const EdgeInsets.all(0), ? const EdgeInsets.all(16)
child: Row( : const EdgeInsets.all(0),
crossAxisAlignment: CrossAxisAlignment.start, child: Row(
children: [ crossAxisAlignment: CrossAxisAlignment.start,
SizedBox( children: [
width: 20, SizedBox(
height: 20, width: 20,
child: Padding( height: 20,
padding: child: Padding(
EdgeInsets.only(top: isDesktop ? 20.0 : 15.0), padding:
child: Radio( EdgeInsets.only(top: isDesktop ? 20.0 : 15.0),
activeColor: Theme.of(context) child: Radio(
.extension<StackColors>()! activeColor: Theme.of(context)
.radioButtonIconEnabled, .extension<StackColors>()!
value: ChangeNowExchange.exchangeName, .radioButtonIconEnabled,
groupValue: ref value: ChangeNowExchange.exchangeName,
.watch(currentExchangeNameStateProvider.state) groupValue: ref
.state, .watch(currentExchangeNameStateProvider.state)
onChanged: (_) { .state,
// if (value is String) { onChanged: (_) {
// ref if (ref
// .read( .read(currentExchangeNameStateProvider
// currentExchangeNameStateProvider.state) .state)
// .state = value; .state !=
// ref ChangeNowExchange.exchangeName) {
// .read(exchangeFormStateProvider(ref ref
// .read(prefsChangeNotifierProvider) .read(currentExchangeNameStateProvider
// .exchangeRateType)) .state)
// .exchange = .state = ChangeNowExchange.exchangeName;
// Exchange.fromName(ref ref
// .read(currentExchangeNameStateProvider .read(exchangeFormStateProvider)
// .state) .updateExchange(
// .state); exchange: ref.read(exchangeProvider),
// } shouldUpdateData: true,
}, shouldNotifyListeners: true,
);
}
},
),
), ),
), ),
), const SizedBox(
const SizedBox( width: 14,
width: 14, ),
), Padding(
Padding( padding: const EdgeInsets.only(top: 5.0),
padding: const EdgeInsets.only(top: 5.0), child: SizedBox(
child: SizedBox(
width: isDesktop ? 32 : 24,
height: isDesktop ? 32 : 24,
child: SvgPicture.asset(
Assets.exchange.changeNow,
width: isDesktop ? 32 : 24, width: isDesktop ? 32 : 24,
height: isDesktop ? 32 : 24, height: isDesktop ? 32 : 24,
child: SvgPicture.asset(
Assets.exchange.changeNow,
width: isDesktop ? 32 : 24,
height: isDesktop ? 32 : 24,
),
), ),
), ),
), const SizedBox(
const SizedBox( width: 10,
width: 10, ),
), Expanded(
Expanded( child: Column(
child: Column( mainAxisAlignment: MainAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start, mainAxisSize: MainAxisSize.min,
mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start, children: [
children: [ Text(
Text( ChangeNowExchange.exchangeName,
ChangeNowExchange.exchangeName, style:
style: STextStyles.titleBold12(context).copyWith( STextStyles.titleBold12(context).copyWith(
color: Theme.of(context) color: Theme.of(context)
.extension<StackColors>()! .extension<StackColors>()!
.textDark2, .textDark2,
),
),
if (from != null &&
to != null &&
toAmount != null &&
toAmount! > Decimal.zero &&
fromAmount != null &&
fromAmount! > Decimal.zero)
FutureBuilder(
future: ChangeNowExchange.instance.getEstimate(
from!,
to!,
reversed ? toAmount! : fromAmount!,
fixedRate,
reversed,
), ),
builder: (context, ),
AsyncSnapshot<ExchangeResponse<Estimate>> if (sendCurrency != null &&
snapshot) { receivingCurrency != null &&
if (snapshot.connectionState == toAmount != null &&
ConnectionState.done && toAmount > Decimal.zero &&
snapshot.hasData) { fromAmount != null &&
final estimate = snapshot.data?.value; fromAmount > Decimal.zero)
if (estimate != null) { FutureBuilder(
Decimal rate; future:
if (estimate.reversed) { ChangeNowExchange.instance.getEstimate(
rate = (toAmount! / sendCurrency.ticker,
estimate.estimatedAmount) receivingCurrency.ticker,
.toDecimal( widget.reversed ? toAmount : fromAmount,
scaleOnInfinitePrecision: 12); widget.fixedRate,
} else { widget.reversed,
rate = (estimate.estimatedAmount / ),
fromAmount!) builder: (context,
.toDecimal( AsyncSnapshot<ExchangeResponse<Estimate>>
scaleOnInfinitePrecision: 12); snapshot) {
} if (snapshot.connectionState ==
Coin coin; ConnectionState.done &&
try { snapshot.hasData) {
coin = final estimate = snapshot.data?.value;
coinFromTickerCaseInsensitive(to!); if (estimate != null) {
} catch (_) { Decimal rate;
coin = Coin.bitcoin; if (estimate.reversed) {
} rate = (toAmount /
estimate.estimatedAmount)
.toDecimal(
scaleOnInfinitePrecision: 12);
} else {
rate = (estimate.estimatedAmount /
fromAmount)
.toDecimal(
scaleOnInfinitePrecision: 12);
}
Coin coin;
try {
coin = coinFromTickerCaseInsensitive(
receivingCurrency.ticker);
} catch (_) {
coin = Coin.bitcoin;
}
return Text( return Text(
"1 ${from!.toUpperCase()} ~ ${Format.localizedStringAsFixed( "1 ${sendCurrency.ticker.toUpperCase()} ~ ${Format.localizedStringAsFixed(
value: rate, value: rate,
locale: ref.watch( locale: ref.watch(
localeServiceChangeNotifierProvider localeServiceChangeNotifierProvider
.select( .select(
(value) => value.locale), (value) => value.locale),
),
decimalPlaces:
Constants.decimalPlacesForCoin(
coin),
)} ${receivingCurrency.ticker.toUpperCase()}",
style: STextStyles.itemSubtitle12(
context)
.copyWith(
color: Theme.of(context)
.extension<StackColors>()!
.textSubtitle1,
), ),
decimalPlaces: );
Constants.decimalPlacesForCoin( } else if (snapshot.data?.exception
coin), is PairUnavailableException) {
)} ${to!.toUpperCase()}", return Text(
style: "Unsupported pair",
STextStyles.itemSubtitle12(context) style: STextStyles.itemSubtitle12(
.copyWith( context)
color: Theme.of(context) .copyWith(
.extension<StackColors>()! color: Theme.of(context)
.textSubtitle1, .extension<StackColors>()!
), .textSubtitle1,
); ),
} else if (snapshot.data?.exception );
is PairUnavailableException) { } else {
return Text( Logging.instance.log(
"Unsupported pair", "$runtimeType failed to fetch rate for ChangeNOW: ${snapshot.data}",
style: level: LogLevel.Warning,
STextStyles.itemSubtitle12(context) );
.copyWith( return Text(
color: Theme.of(context) "Failed to fetch rate",
.extension<StackColors>()! style: STextStyles.itemSubtitle12(
.textSubtitle1, context)
), .copyWith(
); color: Theme.of(context)
.extension<StackColors>()!
.textSubtitle1,
),
);
}
} else { } else {
Logging.instance.log( return AnimatedText(
"$runtimeType failed to fetch rate for ChangeNOW: ${snapshot.data}", stringsToLoopThrough: const [
level: LogLevel.Warning, "Loading",
); "Loading.",
return Text( "Loading..",
"Failed to fetch rate", "Loading...",
],
style: style:
STextStyles.itemSubtitle12(context) STextStyles.itemSubtitle12(context)
.copyWith( .copyWith(
@ -232,233 +290,242 @@ class ExchangeProviderOptions extends ConsumerWidget {
), ),
); );
} }
} 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 &&
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,
), ),
), 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,
),
),
],
),
), ),
), ],
], ),
), ),
), ),
), ),
), ),
),
if (isDesktop) if (showChangeNow && showMajesticBank)
Container( isDesktop
height: 1, ? Container(
color: Theme.of(context).extension<StackColors>()!.background, height: 1,
), color:
if (!isDesktop) Theme.of(context).extension<StackColors>()!.background,
const SizedBox( )
height: 16, : const SizedBox(
), height: 16,
ConditionalParent( ),
condition: isDesktop,
builder: (child) => MouseRegion( if (showMajesticBank)
cursor: SystemMouseCursors.click, ConditionalParent(
child: child, condition: isDesktop,
), builder: (child) => MouseRegion(
child: GestureDetector( cursor: SystemMouseCursors.click,
onTap: () { child: child,
if (ref.read(currentExchangeNameStateProvider.state).state != ),
MajesticBankExchange.exchangeName) { child: GestureDetector(
ref.read(currentExchangeNameStateProvider.state).state = onTap: () {
MajesticBankExchange.exchangeName; if (ref.read(currentExchangeNameStateProvider.state).state !=
ref.read(exchangeFormStateProvider).updateExchange( MajesticBankExchange.exchangeName) {
exchange: ref.read(exchangeProvider), ref.read(currentExchangeNameStateProvider.state).state =
shouldUpdateData: true, MajesticBankExchange.exchangeName;
shouldNotifyListeners: true, ref.read(exchangeFormStateProvider).updateExchange(
); exchange: ref.read(exchangeProvider),
} shouldUpdateData: true,
}, shouldNotifyListeners: true,
child: Container( );
color: Colors.transparent, }
child: Padding( },
padding: isDesktop child: Container(
? const EdgeInsets.all(16) color: Colors.transparent,
: const EdgeInsets.all(0), child: Padding(
child: Row( padding: isDesktop
crossAxisAlignment: CrossAxisAlignment.start, ? const EdgeInsets.all(16)
children: [ : const EdgeInsets.all(0),
SizedBox( child: Row(
width: 20, crossAxisAlignment: CrossAxisAlignment.start,
height: 20, children: [
child: Padding( SizedBox(
padding: width: 20,
EdgeInsets.only(top: isDesktop ? 20.0 : 15.0), height: 20,
child: Radio( child: Padding(
activeColor: Theme.of(context) padding:
.extension<StackColors>()! EdgeInsets.only(top: isDesktop ? 20.0 : 15.0),
.radioButtonIconEnabled, child: Radio(
value: MajesticBankExchange.exchangeName, activeColor: Theme.of(context)
groupValue: ref .extension<StackColors>()!
.watch(currentExchangeNameStateProvider.state) .radioButtonIconEnabled,
.state, value: MajesticBankExchange.exchangeName,
onChanged: (_) { groupValue: ref
// if (value is String) { .watch(currentExchangeNameStateProvider.state)
// ref .state,
// .read( onChanged: (_) {
// currentExchangeNameStateProvider.state) if (ref
// .state = value; .read(currentExchangeNameStateProvider
// ref .state)
// .read(exchangeFormStateProvider(ref .state !=
// .read(prefsChangeNotifierProvider) MajesticBankExchange.exchangeName) {
// .exchangeRateType)) ref
// .exchange = .read(currentExchangeNameStateProvider
// Exchange.fromName(ref .state)
// .read(currentExchangeNameStateProvider .state =
// .state) MajesticBankExchange.exchangeName;
// .state); ref
// } .read(exchangeFormStateProvider)
}, .updateExchange(
exchange: ref.read(exchangeProvider),
shouldUpdateData: true,
shouldNotifyListeners: true,
);
}
},
),
), ),
), ),
), const SizedBox(
const SizedBox( width: 14,
width: 14, ),
), Padding(
Padding( padding: const EdgeInsets.only(top: 5.0),
padding: const EdgeInsets.only(top: 5.0), child: SizedBox(
child: SizedBox(
width: isDesktop ? 32 : 24,
height: isDesktop ? 32 : 24,
child: SvgPicture.asset(
Assets.exchange.majesticBankBlue,
width: isDesktop ? 32 : 24, width: isDesktop ? 32 : 24,
height: isDesktop ? 32 : 24, height: isDesktop ? 32 : 24,
child: SvgPicture.asset(
Assets.exchange.majesticBankBlue,
width: isDesktop ? 32 : 24,
height: isDesktop ? 32 : 24,
),
), ),
), ),
), const SizedBox(
const SizedBox( width: 10,
width: 10, ),
), Expanded(
Expanded( child: Column(
child: Column( mainAxisAlignment: MainAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start, mainAxisSize: MainAxisSize.min,
mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start, children: [
children: [ Text(
Text( MajesticBankExchange.exchangeName,
MajesticBankExchange.exchangeName, style:
style: STextStyles.titleBold12(context).copyWith( STextStyles.titleBold12(context).copyWith(
color: Theme.of(context) color: Theme.of(context)
.extension<StackColors>()! .extension<StackColors>()!
.textDark2, .textDark2,
),
),
if (from != null &&
to != null &&
toAmount != null &&
toAmount! > Decimal.zero &&
fromAmount != null &&
fromAmount! > Decimal.zero)
FutureBuilder(
future:
MajesticBankExchange.instance.getEstimate(
from!,
to!,
reversed ? toAmount! : fromAmount!,
fixedRate,
reversed,
), ),
builder: (context, ),
AsyncSnapshot<ExchangeResponse<Estimate>> if (sendCurrency != null &&
snapshot) { receivingCurrency != null &&
if (snapshot.connectionState == toAmount != null &&
ConnectionState.done && toAmount > Decimal.zero &&
snapshot.hasData) { fromAmount != null &&
final estimate = snapshot.data?.value; fromAmount > Decimal.zero)
if (estimate != null) { FutureBuilder(
Decimal rate; future:
if (estimate.reversed) { MajesticBankExchange.instance.getEstimate(
rate = (toAmount! / sendCurrency.ticker,
estimate.estimatedAmount) receivingCurrency.ticker,
.toDecimal( widget.reversed ? toAmount : fromAmount,
scaleOnInfinitePrecision: 12); widget.fixedRate,
} else { widget.reversed,
rate = (estimate.estimatedAmount / ),
fromAmount!) builder: (context,
.toDecimal( AsyncSnapshot<ExchangeResponse<Estimate>>
scaleOnInfinitePrecision: 12); snapshot) {
} if (snapshot.connectionState ==
Coin coin; ConnectionState.done &&
try { snapshot.hasData) {
coin = final estimate = snapshot.data?.value;
coinFromTickerCaseInsensitive(to!); if (estimate != null) {
} catch (_) { Decimal rate;
coin = Coin.bitcoin; if (estimate.reversed) {
} rate = (toAmount /
estimate.estimatedAmount)
.toDecimal(
scaleOnInfinitePrecision: 12);
} else {
rate = (estimate.estimatedAmount /
fromAmount)
.toDecimal(
scaleOnInfinitePrecision: 12);
}
Coin coin;
try {
coin = coinFromTickerCaseInsensitive(
receivingCurrency.ticker);
} catch (_) {
coin = Coin.bitcoin;
}
return Text( return Text(
"1 ${from!.toUpperCase()} ~ ${Format.localizedStringAsFixed( "1 ${sendCurrency.ticker.toUpperCase()} ~ ${Format.localizedStringAsFixed(
value: rate, value: rate,
locale: ref.watch( locale: ref.watch(
localeServiceChangeNotifierProvider localeServiceChangeNotifierProvider
.select( .select(
(value) => value.locale), (value) => value.locale),
),
decimalPlaces:
Constants.decimalPlacesForCoin(
coin),
)} ${receivingCurrency.ticker.toUpperCase()}",
style: STextStyles.itemSubtitle12(
context)
.copyWith(
color: Theme.of(context)
.extension<StackColors>()!
.textSubtitle1,
), ),
decimalPlaces: );
Constants.decimalPlacesForCoin( } else if (snapshot.data?.exception
coin), is PairUnavailableException) {
)} ${to!.toUpperCase()}", return Text(
style: "Unsupported pair",
STextStyles.itemSubtitle12(context) style: STextStyles.itemSubtitle12(
.copyWith( context)
color: Theme.of(context) .copyWith(
.extension<StackColors>()! color: Theme.of(context)
.textSubtitle1, .extension<StackColors>()!
), .textSubtitle1,
); ),
} else if (snapshot.data?.exception );
is PairUnavailableException) { } else {
return Text( Logging.instance.log(
"Unsupported pair", "$runtimeType failed to fetch rate for ChangeNOW: ${snapshot.data}",
style: level: LogLevel.Warning,
STextStyles.itemSubtitle12(context) );
.copyWith( return Text(
color: Theme.of(context) "Failed to fetch rate",
.extension<StackColors>()! style: STextStyles.itemSubtitle12(
.textSubtitle1, context)
), .copyWith(
); color: Theme.of(context)
.extension<StackColors>()!
.textSubtitle1,
),
);
}
} else { } else {
Logging.instance.log( return AnimatedText(
"$runtimeType failed to fetch rate for ChangeNOW: ${snapshot.data}", stringsToLoopThrough: const [
level: LogLevel.Warning, "Loading",
); "Loading.",
return Text( "Loading..",
"Failed to fetch rate", "Loading...",
],
style: style:
STextStyles.itemSubtitle12(context) STextStyles.itemSubtitle12(context)
.copyWith( .copyWith(
@ -468,53 +535,37 @@ class ExchangeProviderOptions extends ConsumerWidget {
), ),
); );
} }
} 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 &&
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,
), ),
), 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,
),
),
],
),
), ),
), ],
], ),
), ),
), ),
), ),
), ),
), // if (isDesktop)
if (isDesktop) // Container(
Container( // height: 1,
height: 1, // color: Theme.of(context).extension<StackColors>()!.background,
color: Theme.of(context).extension<StackColors>()!.background, // ),
),
// if (!isDesktop) // if (!isDesktop)
// const SizedBox( // const SizedBox(
// height: 16, // height: 16,