mirror of
https://github.com/cypherstack/stack_wallet.git
synced 2024-11-17 09:47:37 +00:00
swap rate refresh fixes and error propagation
This commit is contained in:
parent
a1b7c9248b
commit
1c33dd5062
3 changed files with 105 additions and 118 deletions
|
@ -10,6 +10,7 @@ import 'package:isar/isar.dart';
|
|||
import 'package:stackwallet/models/exchange/aggregate_currency.dart';
|
||||
import 'package:stackwallet/models/exchange/incomplete_exchange.dart';
|
||||
import 'package:stackwallet/models/exchange/response_objects/estimate.dart';
|
||||
import 'package:stackwallet/models/exchange/response_objects/range.dart';
|
||||
import 'package:stackwallet/models/isar/exchange_cache/currency.dart';
|
||||
import 'package:stackwallet/models/isar/exchange_cache/pair.dart';
|
||||
import 'package:stackwallet/models/isar/models/ethereum/eth_contract.dart';
|
||||
|
@ -28,7 +29,6 @@ import 'package:stackwallet/utilities/assets.dart';
|
|||
import 'package:stackwallet/utilities/constants.dart';
|
||||
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||
import 'package:stackwallet/utilities/enums/exchange_rate_type_enum.dart';
|
||||
import 'package:stackwallet/utilities/logger.dart';
|
||||
import 'package:stackwallet/utilities/text_styles.dart';
|
||||
import 'package:stackwallet/utilities/theme/stack_colors.dart';
|
||||
import 'package:stackwallet/utilities/util.dart';
|
||||
|
@ -43,6 +43,9 @@ import 'package:stackwallet/widgets/rounded_white_container.dart';
|
|||
import 'package:stackwallet/widgets/stack_dialog.dart';
|
||||
import 'package:stackwallet/widgets/textfields/exchange_textfield.dart';
|
||||
import 'package:tuple/tuple.dart';
|
||||
import 'package:uuid/uuid.dart';
|
||||
|
||||
import '../../services/exchange/exchange_response.dart';
|
||||
|
||||
class ExchangeForm extends ConsumerStatefulWidget {
|
||||
const ExchangeForm({
|
||||
|
@ -604,7 +607,9 @@ class _ExchangeFormState extends ConsumerState<ExchangeForm> {
|
|||
}
|
||||
|
||||
Future<void> update() async {
|
||||
_addUpdate();
|
||||
final uuid = const Uuid().v1();
|
||||
_latestUuid = uuid;
|
||||
_addUpdate(uuid);
|
||||
for (final exchange in exchanges) {
|
||||
ref.read(efEstimatesListProvider(exchange.name).notifier).state = null;
|
||||
}
|
||||
|
@ -619,10 +624,12 @@ class _ExchangeFormState extends ConsumerState<ExchangeForm> {
|
|||
amount <= Decimal.zero ||
|
||||
pair.send == null ||
|
||||
pair.receive == null) {
|
||||
_removeUpdate();
|
||||
_removeUpdate(uuid);
|
||||
return;
|
||||
}
|
||||
final rateType = ref.read(efRateTypeProvider);
|
||||
final Map<String, Tuple2<ExchangeResponse<List<Estimate>>, Range?>>
|
||||
results = {};
|
||||
|
||||
for (final exchange in exchanges) {
|
||||
final sendCurrency = pair.send?.forExchange(exchange.name);
|
||||
|
@ -635,14 +642,6 @@ class _ExchangeFormState extends ConsumerState<ExchangeForm> {
|
|||
rateType == ExchangeRateType.fixed,
|
||||
);
|
||||
|
||||
if (rangeResponse.value == null) {
|
||||
Logging.instance.log(
|
||||
"Tried to $runtimeType.update Range for:"
|
||||
" $exchange where response: $rangeResponse",
|
||||
level: LogLevel.Info,
|
||||
);
|
||||
}
|
||||
|
||||
final estimateResponse = await exchange.getEstimates(
|
||||
sendCurrency.ticker,
|
||||
receiveCurrency.ticker,
|
||||
|
@ -651,43 +650,41 @@ class _ExchangeFormState extends ConsumerState<ExchangeForm> {
|
|||
reversed,
|
||||
);
|
||||
|
||||
if (estimateResponse.value == null) {
|
||||
Logging.instance.log(
|
||||
"Tried to $runtimeType._fetchEstimateAndRange Estimate for:"
|
||||
" $exchange where response: $estimateResponse",
|
||||
level: LogLevel.Info,
|
||||
);
|
||||
}
|
||||
|
||||
if (mounted) {
|
||||
if (estimateResponse.value != null && rangeResponse.value != null) {
|
||||
ref.read(efEstimatesListProvider(exchange.name).notifier).state =
|
||||
Tuple2(estimateResponse.value!, rangeResponse.value!);
|
||||
} else {
|
||||
ref.read(efEstimatesListProvider(exchange.name).notifier).state =
|
||||
null;
|
||||
}
|
||||
}
|
||||
results.addAll(
|
||||
{
|
||||
exchange.name: Tuple2(
|
||||
estimateResponse,
|
||||
rangeResponse.value,
|
||||
),
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
_removeUpdate();
|
||||
// });
|
||||
for (final exchange in exchanges) {
|
||||
if (uuid == _latestUuid) {
|
||||
ref.read(efEstimatesListProvider(exchange.name).notifier).state =
|
||||
results[exchange.name];
|
||||
}
|
||||
}
|
||||
|
||||
_removeUpdate(uuid);
|
||||
}
|
||||
|
||||
int _updateCount = 0;
|
||||
String? _latestUuid;
|
||||
final Set<String> _uuids = {};
|
||||
|
||||
void _addUpdate() {
|
||||
_updateCount++;
|
||||
void _addUpdate(String uuid) {
|
||||
_uuids.add(uuid);
|
||||
ref.read(efRefreshingProvider.notifier).state = true;
|
||||
}
|
||||
|
||||
void _removeUpdate() {
|
||||
_updateCount--;
|
||||
if (_updateCount <= 0) {
|
||||
_updateCount = 0;
|
||||
ref.read(efRefreshingProvider.notifier).state = false;
|
||||
void _removeUpdate(String uuid) {
|
||||
_uuids.remove(uuid);
|
||||
if (_uuids.isEmpty) {
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
ref.read(efRefreshingProvider.notifier).state = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -711,16 +708,24 @@ class _ExchangeFormState extends ConsumerState<ExchangeForm> {
|
|||
|
||||
_sendFocusNode.addListener(() {
|
||||
if (_sendFocusNode.hasFocus) {
|
||||
final reversed = ref.read(efReversedProvider);
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
ref.read(efReversedProvider.notifier).state = false;
|
||||
if (reversed == true) {
|
||||
update();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
_receiveFocusNode.addListener(() {
|
||||
if (_receiveFocusNode.hasFocus &&
|
||||
ref.read(efExchangeProvider).name != ChangeNowExchange.exchangeName) {
|
||||
final reversed = ref.read(efReversedProvider);
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
ref.read(efReversedProvider.notifier).state = true;
|
||||
if (reversed != true) {
|
||||
update();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
@ -856,12 +861,6 @@ class _ExchangeFormState extends ConsumerState<ExchangeForm> {
|
|||
SizedBox(
|
||||
height: isDesktop ? 10 : 4,
|
||||
),
|
||||
// if (ref.watch(efWarningProvider).isNotEmpty &&
|
||||
// !ref.watch(efReversedProvider))
|
||||
// Text(
|
||||
// ref.watch(efWarningProvider),
|
||||
// style: STextStyles.errorSmall(context),
|
||||
// ),
|
||||
Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.end,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
|
@ -926,27 +925,24 @@ class _ExchangeFormState extends ConsumerState<ExchangeForm> {
|
|||
borderRadius: Constants.size.circularBorderRadius,
|
||||
background:
|
||||
Theme.of(context).extension<StackColors>()!.textFieldDefaultBG,
|
||||
onTap: () {
|
||||
if (!(ref.read(efRateTypeProvider) == ExchangeRateType.estimated) &&
|
||||
_receiveController.text == "-") {
|
||||
_receiveController.text = "";
|
||||
}
|
||||
},
|
||||
onTap: rateType == ExchangeRateType.estimated &&
|
||||
ref.watch(efExchangeProvider).name ==
|
||||
ChangeNowExchange.exchangeName
|
||||
? null
|
||||
: () {
|
||||
if (_sendController.text == "-") {
|
||||
_sendController.text = "";
|
||||
}
|
||||
},
|
||||
onChanged: receiveFieldOnChanged,
|
||||
onButtonTap: selectReceiveCurrency,
|
||||
isWalletCoin: isWalletCoin(coin, true),
|
||||
currency: ref
|
||||
.watch(efCurrencyPairProvider.select((value) => value.receive)),
|
||||
readOnly: (rateType) == ExchangeRateType.estimated &&
|
||||
readOnly: rateType == ExchangeRateType.estimated &&
|
||||
ref.watch(efExchangeProvider).name ==
|
||||
ChangeNowExchange.exchangeName,
|
||||
),
|
||||
// if (ref.watch(efWarningProvider).isNotEmpty &&
|
||||
// ref.watch(efReversedProvider))
|
||||
// Text(
|
||||
// ref.watch(efWarningProvider),
|
||||
// style: STextStyles.errorSmall(context),
|
||||
// ),
|
||||
SizedBox(
|
||||
height: isDesktop ? 20 : 12,
|
||||
),
|
||||
|
@ -957,21 +953,12 @@ class _ExchangeFormState extends ConsumerState<ExchangeForm> {
|
|||
onChanged: onRateTypeChanged,
|
||||
),
|
||||
),
|
||||
// AnimatedSize(
|
||||
// duration: const Duration(milliseconds: 250),
|
||||
// curve: Curves.easeInOutCirc,
|
||||
// child: ref.watch(efSendAmountProvider).sendAmount != null &&
|
||||
// ref.watch(exchangeFormStateProvider).sendAmount != Decimal.zero
|
||||
// ?
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: isDesktop ? 20 : 12),
|
||||
child: ExchangeProviderOptions(
|
||||
fixedRate: rateType == ExchangeRateType.fixed,
|
||||
reversed: ref.watch(efReversedProvider),
|
||||
),
|
||||
// : const SizedBox(
|
||||
// height: 0,
|
||||
// ),
|
||||
),
|
||||
SizedBox(
|
||||
height: isDesktop ? 20 : 12,
|
||||
|
|
|
@ -9,6 +9,7 @@ import 'package:stackwallet/services/exchange/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/enums/exchange_rate_type_enum.dart';
|
||||
import 'package:stackwallet/utilities/logger.dart';
|
||||
import 'package:stackwallet/utilities/text_styles.dart';
|
||||
import 'package:stackwallet/utilities/theme/stack_colors.dart';
|
||||
|
@ -31,11 +32,10 @@ class ExchangeOption extends ConsumerStatefulWidget {
|
|||
final bool reversed;
|
||||
|
||||
@override
|
||||
ConsumerState<ExchangeOption> createState() =>
|
||||
_ExchangeMultiProviderOptionState();
|
||||
ConsumerState<ExchangeOption> createState() => _ExchangeOptionState();
|
||||
}
|
||||
|
||||
class _ExchangeMultiProviderOptionState extends ConsumerState<ExchangeOption> {
|
||||
class _ExchangeOptionState extends ConsumerState<ExchangeOption> {
|
||||
final isDesktop = Util.isDesktop;
|
||||
|
||||
@override
|
||||
|
@ -49,7 +49,8 @@ class _ExchangeMultiProviderOptionState extends ConsumerState<ExchangeOption> {
|
|||
? ref.watch(efReceiveAmountProvider)
|
||||
: ref.watch(efSendAmountProvider);
|
||||
|
||||
final estimates = ref.watch(efEstimatesListProvider(widget.exchange.name));
|
||||
final data = ref.watch(efEstimatesListProvider(widget.exchange.name));
|
||||
final estimates = data?.item1.value;
|
||||
|
||||
return AnimatedSize(
|
||||
duration: const Duration(milliseconds: 500),
|
||||
|
@ -68,14 +69,14 @@ class _ExchangeMultiProviderOptionState extends ConsumerState<ExchangeOption> {
|
|||
receivingCurrency != null &&
|
||||
amount != null &&
|
||||
amount > Decimal.zero) {
|
||||
if (estimates != null && estimates.item1.isNotEmpty) {
|
||||
if (estimates != null && estimates.isNotEmpty) {
|
||||
return Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
for (int i = 0; i < estimates.item1.length; i++)
|
||||
for (int i = 0; i < estimates.length; i++)
|
||||
Builder(
|
||||
builder: (context) {
|
||||
final e = estimates.item1[i];
|
||||
final e = estimates[i];
|
||||
|
||||
int decimals;
|
||||
try {
|
||||
|
@ -136,14 +137,37 @@ class _ExchangeMultiProviderOptionState extends ConsumerState<ExchangeOption> {
|
|||
);
|
||||
} else {
|
||||
Logging.instance.log(
|
||||
"$runtimeType failed to fetch rate for ${widget.exchange.name}: $estimates",
|
||||
"$runtimeType rate unavailable for ${widget.exchange.name}: $data",
|
||||
level: LogLevel.Warning,
|
||||
);
|
||||
|
||||
return _ProviderOption(
|
||||
exchange: widget.exchange,
|
||||
estimate: null,
|
||||
rateString: "Failed to fetch rate",
|
||||
return Consumer(
|
||||
builder: (_, ref, __) {
|
||||
String? message;
|
||||
|
||||
final range = data?.item2;
|
||||
if (range != null) {
|
||||
if (range.min != null && amount < range.min!) {
|
||||
message ??= "Amount too small";
|
||||
} else if (range.max != null && amount > range.max!) {
|
||||
message ??= "Amount too large";
|
||||
}
|
||||
} else if (data?.item1.value == null) {
|
||||
final rateType = ref.watch(efRateTypeProvider) ==
|
||||
ExchangeRateType.estimated
|
||||
? "estimated"
|
||||
: "fixed";
|
||||
message ??= "Pair unavailable on $rateType rate flow";
|
||||
}
|
||||
|
||||
return _ProviderOption(
|
||||
exchange: widget.exchange,
|
||||
estimate: null,
|
||||
rateString: message ?? "Failed to fetch rate",
|
||||
rateColor:
|
||||
Theme.of(context).extension<StackColors>()!.textError,
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
} else {
|
||||
|
@ -168,6 +192,7 @@ class _ProviderOption extends ConsumerStatefulWidget {
|
|||
required this.rateString,
|
||||
this.kycRating,
|
||||
this.loadingString = false,
|
||||
this.rateColor,
|
||||
}) : super(key: key);
|
||||
|
||||
final Exchange exchange;
|
||||
|
@ -175,6 +200,7 @@ class _ProviderOption extends ConsumerStatefulWidget {
|
|||
final String rateString;
|
||||
final String? kycRating;
|
||||
final bool loadingString;
|
||||
final Color? rateColor;
|
||||
|
||||
@override
|
||||
ConsumerState<_ProviderOption> createState() => _ProviderOptionState();
|
||||
|
@ -201,8 +227,6 @@ class _ProviderOptionState extends ConsumerState<_ProviderOption> {
|
|||
groupValue = _id;
|
||||
}
|
||||
|
||||
// bool selected = groupValue == _id;
|
||||
|
||||
return ConditionalParent(
|
||||
condition: isDesktop,
|
||||
builder: (child) => MouseRegion(
|
||||
|
@ -214,17 +238,6 @@ class _ProviderOptionState extends ConsumerState<_ProviderOption> {
|
|||
ref.read(efExchangeProvider.notifier).state = widget.exchange;
|
||||
ref.read(efExchangeProviderNameProvider.notifier).state =
|
||||
widget.estimate?.exchangeProvider ?? widget.exchange.name;
|
||||
|
||||
// if (!selected) {
|
||||
// ref.read(exchangeFormStateProvider).updateExchange(
|
||||
// exchange: widget.exchange,
|
||||
// shouldUpdateData: false,
|
||||
// shouldNotifyListeners: false,
|
||||
// providerName:
|
||||
// widget.estimate?.exchangeProvider ?? widget.exchange.name,
|
||||
// shouldAwait: false,
|
||||
// );
|
||||
// }
|
||||
},
|
||||
child: Container(
|
||||
color: Colors.transparent,
|
||||
|
@ -253,19 +266,6 @@ class _ProviderOptionState extends ConsumerState<_ProviderOption> {
|
|||
.state =
|
||||
widget.estimate?.exchangeProvider ??
|
||||
widget.exchange.name;
|
||||
// if (!selected) {
|
||||
//
|
||||
//
|
||||
// ref.read(exchangeFormStateProvider).updateExchange(
|
||||
// exchange: widget.exchange,
|
||||
// shouldUpdateData: false,
|
||||
// shouldNotifyListeners: false,
|
||||
// providerName:
|
||||
// widget.estimate?.exchangeProvider ??
|
||||
// widget.exchange.name,
|
||||
// shouldAwait: false,
|
||||
// );
|
||||
// }
|
||||
},
|
||||
),
|
||||
),
|
||||
|
@ -324,9 +324,10 @@ class _ProviderOptionState extends ConsumerState<_ProviderOption> {
|
|||
widget.rateString,
|
||||
style:
|
||||
STextStyles.itemSubtitle12(context).copyWith(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textSubtitle1,
|
||||
color: widget.rateColor ??
|
||||
Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textSubtitle1,
|
||||
),
|
||||
),
|
||||
],
|
||||
|
|
|
@ -4,12 +4,13 @@ import 'package:stackwallet/models/exchange/active_pair.dart';
|
|||
import 'package:stackwallet/models/exchange/response_objects/estimate.dart';
|
||||
import 'package:stackwallet/models/exchange/response_objects/range.dart';
|
||||
import 'package:stackwallet/services/exchange/exchange.dart';
|
||||
import 'package:stackwallet/services/exchange/exchange_response.dart';
|
||||
import 'package:stackwallet/utilities/enums/exchange_rate_type_enum.dart';
|
||||
import 'package:tuple/tuple.dart';
|
||||
|
||||
final efEstimatesListProvider =
|
||||
StateProvider.family<Tuple2<List<Estimate>, Range>?, String>(
|
||||
(ref, exchangeName) => null);
|
||||
final efEstimatesListProvider = StateProvider.family<
|
||||
Tuple2<ExchangeResponse<List<Estimate>>, Range?>?,
|
||||
String>((ref, exchangeName) => null);
|
||||
|
||||
final efRateTypeProvider =
|
||||
StateProvider<ExchangeRateType>((ref) => ExchangeRateType.estimated);
|
||||
|
@ -53,19 +54,17 @@ final efCurrencyPairProvider = ChangeNotifierProvider<ActivePair>(
|
|||
(ref) => ActivePair(),
|
||||
);
|
||||
|
||||
final efRangeProvider = StateProvider<Range?>((ref) {
|
||||
final exchange = ref.watch(efExchangeProvider);
|
||||
return ref.watch(efEstimatesListProvider(exchange.name))?.item2;
|
||||
});
|
||||
|
||||
final efEstimateProvider = StateProvider<Estimate?>((ref) {
|
||||
final exchange = ref.watch(efExchangeProvider);
|
||||
final provider = ref.watch(efExchangeProviderNameProvider);
|
||||
final reversed = ref.watch(efReversedProvider);
|
||||
final fixedRate = ref.watch(efRateTypeProvider) == ExchangeRateType.fixed;
|
||||
|
||||
final matches =
|
||||
ref.watch(efEstimatesListProvider(exchange.name))?.item1.where((e) {
|
||||
final matches = ref
|
||||
.watch(efEstimatesListProvider(exchange.name))
|
||||
?.item1
|
||||
.value
|
||||
?.where((e) {
|
||||
return e.exchangeProvider == provider &&
|
||||
e.fixedRate == fixedRate &&
|
||||
e.reversed == reversed;
|
||||
|
|
Loading…
Reference in a new issue