Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 13 additions & 8 deletions lib/buy/onramper/onramper_buy_provider.dart
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ class OnRamperBuyProvider extends BuyProvider {

String? recommendedPaymentType;

FiatCurrency? recommendedFiat;

String get _apiKey => secrets.onramperApiKey;

String get _exchangeHelperApiKey => secrets.exchangeHelperApiKey;
Expand Down Expand Up @@ -76,7 +78,7 @@ class OnRamperBuyProvider extends BuyProvider {
}
}

Future<String?> getRecommendedPaymentType(bool isBuyAction) async {
Future<void> fetchRecommendedDefaults(bool isBuyAction) async {
final params = {'type': isBuyAction ? 'buy' : 'sell'};

final url = Uri.https(_baseApiUrl, '$supported$defaultsAll', params);
Expand All @@ -91,21 +93,26 @@ class OnRamperBuyProvider extends BuyProvider {
final Map<String, dynamic> data = jsonDecode(response.body) as Map<String, dynamic>;
final recommended = data['message']['recommended'] as Map<String, dynamic>;

final recommendedPaymentType = recommended['paymentMethod'] as String?;
recommendedPaymentType = recommended['paymentMethod'] as String?;

return recommendedPaymentType;
// the recommendation is a source -> target pair, so which side is the
// fiat one flips with the action
final fiat = recommended[isBuyAction ? 'source' : 'target'] as String?;
recommendedFiat =
fiat == null ? null : FiatCurrency.tryDeserialize(raw: fiat.toUpperCase());
} else {
final responseBody = jsonDecode(response.body) as Map<String, dynamic>;
printV('Failed to fetch available payment types: ${responseBody['message']}');
printV('Failed to fetch recommended defaults: ${responseBody['message']}');
}
} catch (e) {
printV('Failed to fetch available payment types: $e');
printV('Failed to fetch recommended defaults: $e');
}
return null;
}

Future<List<PaymentMethod>> getAvailablePaymentTypes(
String fiatCurrency, CryptoCurrency cryptoCurrency, bool isBuyAction) async {
await fetchRecommendedDefaults(isBuyAction);

final normalizedCryptoCurrency = cryptoCurrency.title + _getNormalizeNetwork(cryptoCurrency);

final sourceCurrency = (isBuyAction ? fiatCurrency : normalizedCryptoCurrency).toLowerCase();
Expand All @@ -128,8 +135,6 @@ class OnRamperBuyProvider extends BuyProvider {
.map((item) => PaymentMethod.fromOnramperJson(item as Map<String, dynamic>))
.toList();

recommendedPaymentType = await getRecommendedPaymentType(isBuyAction);

return allAvailablePaymentMethods;
} else {
final responseBody = jsonDecode(response.body) as Map<String, dynamic>;
Expand Down
4 changes: 2 additions & 2 deletions lib/buy/sell_buy_states.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ class BuySellQuotLoading extends BuySellQuotLoadingState {}
class BuySellQuotLoaded extends BuySellQuotLoadingState {}

class BuySellQuotFailed extends BuySellQuotLoadingState {
final String? errorMessage;
final String errorMessage;

BuySellQuotFailed({this.errorMessage});
BuySellQuotFailed({required this.errorMessage});
}
2 changes: 2 additions & 0 deletions lib/entities/fiat_currency.dart
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,8 @@ class FiatCurrency extends EnumerableItem<String> with Serializable<String> impl

static FiatCurrency deserialize({required String raw}) => _all[raw] ?? FiatCurrency.usd;

static FiatCurrency? tryDeserialize({required String raw}) => _all[raw];

@override
bool operator ==(Object other) => other is FiatCurrency && other.raw == raw;

Expand Down
92 changes: 67 additions & 25 deletions lib/new-ui/pages/buy_sell/buy_sell_provider_page.dart
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import "package:cake_wallet/buy/buy_quote.dart";
import "package:cake_wallet/buy/sell_buy_states.dart";
import "package:cake_wallet/entities/fiat_currency.dart";
import "package:cake_wallet/entities/new_ui_entities/list_item/list_item.dart";
import "package:cake_wallet/entities/new_ui_entities/list_item/list_item_dropdown.dart";
import "package:cake_wallet/entities/new_ui_entities/list_item/list_item_regular_row.dart";
import "package:cake_wallet/generated/i18n.dart";
import "package:cake_wallet/new-ui/pages/buy_sell/buy_sell_confirmation_page.dart";
import "package:cake_wallet/new-ui/pages/buy_sell/buy_sell_payment_method_page.dart";
import "package:cake_wallet/new-ui/widgets/money/money_text.dart";
import "package:cake_wallet/new-ui/widgets/new_primary_button.dart";
import "package:cake_wallet/new-ui/widgets/receive_page/receive_top_bar.dart";
import "package:cake_wallet/src/widgets/new_list_row/new_list_section.dart";
import "package:cake_wallet/view_model/buy/buy_sell_view_model.dart";
Expand Down Expand Up @@ -52,31 +54,8 @@ class _BuySellProviderPageState extends State<BuySellProviderPage> {
Expanded(
child: Observer(
builder: (_) {
if (widget.buySellViewModel.buySellQuotState is BuySellQuotFailed) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
spacing: 24,
children: [
const Icon(Icons.warning_amber_outlined, size: 48),
Column(
spacing: 10,
children: [
Text(
S.of(context).could_not_load_quotes,
style: const TextStyle(fontSize: 20, fontWeight: FontWeight.w500),
),
Text(
(widget.buySellViewModel.buySellQuotState as BuySellQuotFailed)
.errorMessage ??
S.of(context).please_try_again_later,
),
],
),
],
);
}

if (widget.buySellViewModel.buySellQuotState is BuySellQuotLoading) {
if (widget.buySellViewModel.buySellQuotState is BuySellQuotLoading ||
widget.buySellViewModel.buySellQuotState is InitialBuySellQuotState) {
return Center(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
Expand All @@ -93,6 +72,18 @@ class _BuySellProviderPageState extends State<BuySellProviderPage> {
);
}

if (widget.buySellViewModel.buySellQuotState is BuySellQuotFailed) {
final recommendedFiat = widget.buySellViewModel.recommendedFiat;

return BuySellQuoteFailure(
state: widget.buySellViewModel.buySellQuotState as BuySellQuotFailed,
recommendedFiat: recommendedFiat == widget.buySellViewModel.fiatCurrency
? null
: recommendedFiat,
onRetryPressed: widget.buySellViewModel.retryWithRecommendedFiat,
);
}

return SingleChildScrollView(
controller: ModalScrollController.of(context),
child: Padding(
Expand Down Expand Up @@ -195,3 +186,54 @@ class _BuySellProviderPageState extends State<BuySellProviderPage> {
);
}
}

class BuySellQuoteFailure extends StatelessWidget {
const BuySellQuoteFailure({
required this.state,
required this.onRetryPressed,
super.key,
this.recommendedFiat,
});

final BuySellQuotFailed state;
final FiatCurrency? recommendedFiat;
final VoidCallback onRetryPressed;

@override
Widget build(BuildContext context) {
final recommendedFiat = this.recommendedFiat;

return Padding(
padding: const EdgeInsets.symmetric(horizontal: 18),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
spacing: 24,
children: [
const Icon(Icons.warning_amber_outlined, size: 48),
Column(
spacing: 10,
children: [
Text(
S.of(context).could_not_load_quotes,
style: const TextStyle(fontSize: 20, fontWeight: FontWeight.w500),
),
Text(
recommendedFiat == null
? state.errorMessage
: S.of(context).providers_in_region_use_fiat(recommendedFiat.title),
textAlign: TextAlign.center,
),
],
),
if (recommendedFiat != null)
NewPrimaryButton(
onPressed: onRetryPressed,
text: S.of(context).switch_to_fiat(recommendedFiat.title),
color: Theme.of(context).colorScheme.primary,
textColor: Theme.of(context).colorScheme.onPrimary,
),
],
),
);
}
}
Loading
Loading