address review comments

This commit is contained in:
Robert Malikowski
2026-08-27 12:27:49 +02:00
parent c2441b16d5
commit 09a3428245
12 changed files with 979 additions and 863 deletions
+1 -1
View File
@@ -16,7 +16,7 @@ extension RecommendationTitle on ProviderRecommendation {
case ProviderRecommendation.bestRate:
return S.current.best_rate;
case ProviderRecommendation.lowKyc:
return 'LOW KYC';
return S.current.low_kyc;
case ProviderRecommendation.successRate:
return S.current.highest_success_rate;
}
@@ -5,7 +5,6 @@ import "package:cake_wallet/buy/sell_buy_states.dart";
import "package:cake_wallet/entities/fiat_currency.dart";
import "package:cake_wallet/generated/i18n.dart";
import "package:cake_wallet/new-ui/pages/buy_sell/buy_sell_provider_page.dart";
import "package:cake_wallet/new-ui/widgets/buy_sell/buy_sell_selector_modal.dart";
import "package:cake_wallet/new-ui/widgets/currency_picker/currency_picker_args.dart";
import "package:cake_wallet/new-ui/widgets/currency_picker/currency_picker_sheet.dart";
import "package:cake_wallet/new-ui/widgets/currency_picker/fiat_currency_picker_sheet.dart";
@@ -43,6 +42,13 @@ class _NewBuySellAmountPageState extends State<NewBuySellAmountPage> {
final customInputController = TextEditingController();
final customInputFocusNode = FocusNode();
@override
void dispose() {
customInputController.dispose();
customInputFocusNode.dispose();
super.dispose();
}
@override
void initState() {
super.initState();
@@ -50,107 +56,120 @@ class _NewBuySellAmountPageState extends State<NewBuySellAmountPage> {
// this is a hack for the "up to" display to show the actual upper limit.
// limits are loaded alongside quotes, and quotes for some providers only load properly with an amount and payment method selected.
// it'll be refactored soon anyway, i guess.
widget.buySellViewModel.changeFiatAmount(amount: "1000");
widget.buySellViewModel.changeFiatAmount(amount: widget.buySellViewModel.defaultAmounts[3]);
widget.buySellViewModel.calculateBestRate();
when(
(_) => widget.buySellViewModel.paymentMethodState is PaymentMethodLoaded,
() => widget.buySellViewModel.selectedPaymentMethod = widget.buySellViewModel.paymentMethods
.firstWhere((item) => item.paymentMethodType == PaymentType.all),);
(_) => widget.buySellViewModel.paymentMethodState is PaymentMethodLoaded,
() => widget.buySellViewModel.selectedPaymentMethod = widget.buySellViewModel.paymentMethods
.firstWhere((item) => item.paymentMethodType == PaymentType.all),
);
}
@override
Widget build(BuildContext context) => Container(
decoration: BoxDecoration(
borderRadius: const BorderRadius.vertical(top: Radius.circular(18)),
gradient: LinearGradient(
colors: [
Theme.of(context).colorScheme.surface,
Theme.of(context).colorScheme.surfaceDim,
],
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
),
),
child: SafeArea(
child: Column(
children: [
Observer(
builder: (_) => ModalTopBar(
title: _pageTitle,
bottomText: !_customAmountMode || widget.buySellViewModel.maxFiatAmount == null
? null
: "${S.of(context).up_to} ~${widget.buySellViewModel.maxFiatAmount} ${widget.buySellViewModel.fiatCurrency.title}",
leadingIcon: const Icon(Icons.close),
leadingSemanticLabel: S.of(context).close,
onLeadingPressed: Navigator.of(context, rootNavigator: true).pop,
),
decoration: BoxDecoration(
borderRadius: const BorderRadius.vertical(top: Radius.circular(18)),
gradient: LinearGradient(
colors: [
Theme.of(context).colorScheme.surface,
Theme.of(context).colorScheme.surfaceDim,
],
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
),
Expanded(
child: Observer(
builder: (_) => AnimatedSwitcher(
duration: const Duration(milliseconds: 300),
child: _customAmountMode
? BuySellCustomAmountInput(
fiatCurrency: widget.buySellViewModel.fiatCurrency,
cryptoCurrency: widget.buySellViewModel.cryptoCurrency,
cryptoAmount: widget.buySellViewModel.cryptoAmount,
isLoading: _isLoadingPaymentMethods,
hasCurrencySelector: widget.buySellViewModel.hasMultipleCurrencies,
onCurrencySelectorPressed: () => selectCryptoCurrency(context),
controller: customInputController,
focusNode: customInputFocusNode,
onContinuePressed: () {
navigateToProviders(context);
},
onChanged: (amount) =>
widget.buySellViewModel.changeFiatAmount(amount: amount),
)
: BuySellDefaultAmountSelector(
key: const ValueKey(0),
defaultAmounts: widget.buySellViewModel.defaultAmounts,
fiatCurrency: widget.buySellViewModel.fiatCurrency,
currentAmount: widget.buySellViewModel.fiatAmount,
hasCurrencySelector: widget.buySellViewModel.hasMultipleCurrencies,
onCurrencySelectorPressed: () => selectCryptoCurrency(context),
onFiatSelectorPressed: () => selectFiatCurrency(context),
),
child: SafeArea(
child: Column(
children: [
Observer(
builder: (_) => ModalTopBar(
title: _pageTitle,
bottomText: !_customAmountMode || widget.buySellViewModel.maxFiatAmount == null
? null
: "${S.of(context).up_to} ~${widget.buySellViewModel.maxFiatAmount} ${widget.buySellViewModel.fiatCurrency.title}",
leadingIcon: const Icon(Icons.close),
leadingSemanticLabel: S.of(context).close,
onLeadingPressed: Navigator.of(context, rootNavigator: true).pop,
),
),
Expanded(
child: Observer(
builder: (_) => AnimatedSwitcher(
duration: const Duration(milliseconds: 300),
child: _customAmountMode
? BuySellCustomAmountInput(
fiatCurrency: widget.buySellViewModel.fiatCurrency,
cryptoCurrency: widget.buySellViewModel.cryptoCurrency,
isLoading: _isLoadingPaymentMethods,
mode: widget.buySellViewModel.mode,
onSelected: (amount) async {
if (amount == null) {
// this resets the rate and prevents showing 0 usd = 0.something btc
await widget.buySellViewModel.changeFiatAmount(amount: "");
setState(() {
_customAmountMode = true;
});
customInputFocusNode.requestFocus();
} else {
await widget.buySellViewModel.changeFiatAmount(amount: amount);
if(context.mounted) {
await navigateToProviders(context);
}
}
},
),
),
),),
],
),
),
);
cryptoAmount: widget.buySellViewModel.cryptoAmount,
isLoading: _isLoadingPaymentMethods,
hasCurrencySelector: widget.buySellViewModel.hasMultipleCurrencies,
onCurrencySelectorPressed: () => selectCryptoCurrency(context),
controller: customInputController,
focusNode: customInputFocusNode,
onContinuePressed: () {
navigateToProviders(context);
},
onChanged: (amount) {
if (widget.buySellViewModel.mode == BuySellPageMode.sell) {
widget.buySellViewModel.setCryptoAmountFromFiat(amount);
} else {
widget.buySellViewModel.changeFiatAmount(amount: amount);
}
},
)
: BuySellDefaultAmountSelector(
key: const ValueKey(0),
defaultAmounts: widget.buySellViewModel.defaultAmounts,
fiatCurrency: widget.buySellViewModel.fiatCurrency,
currentAmount: widget.buySellViewModel.fiatAmount,
hasCurrencySelector: widget.buySellViewModel.hasMultipleCurrencies,
onCurrencySelectorPressed: () => selectCryptoCurrency(context),
onFiatSelectorPressed: () => selectFiatCurrency(context),
cryptoCurrency: widget.buySellViewModel.cryptoCurrency,
isLoading: _isLoadingPaymentMethods,
mode: widget.buySellViewModel.mode,
onSelected: (amount) async {
if (amount == null) {
// this resets the rate and prevents showing 0 usd = 0.something btc
await widget.buySellViewModel.changeFiatAmount(amount: "");
setState(() {
_customAmountMode = true;
});
customInputFocusNode.requestFocus();
} else {
if (widget.buySellViewModel.mode == BuySellPageMode.sell) {
await widget.buySellViewModel.setCryptoAmountFromFiat(amount);
} else {
await widget.buySellViewModel.changeFiatAmount(amount: amount);
}
if (context.mounted) {
await navigateToProviders(context);
}
}
},
),
),
),
),
],
),
),
);
void selectCryptoCurrency(BuildContext context) => CurrencyPickerSheet.show(
context: context,
args: CurrencyPickerArgs(
items: widget.buySellViewModel.activeWalletCurrencies.toList(),
onSelected: (item) => widget.buySellViewModel.changeCryptoCurrency(currency: item),
symbolResolver: widget.buySellViewModel.amountParsingProxy.getCryptoSymbol,
),);
context: context,
args: CurrencyPickerArgs(
items: widget.buySellViewModel.activeWalletCurrencies.toList(),
onSelected: (item) => widget.buySellViewModel.changeCryptoCurrency(currency: item),
symbolResolver: widget.buySellViewModel.amountParsingProxy.getCryptoSymbol,
),
);
void selectFiatCurrency(BuildContext context) => FiatCurrencyPickerSheet.show(
context: context,
selected: widget.buySellViewModel.fiatCurrency,
onSelected: (item) => widget.buySellViewModel.changeFiatCurrency(currency: item));
context: context,
selected: widget.buySellViewModel.fiatCurrency,
onSelected: (item) => widget.buySellViewModel.changeFiatCurrency(currency: item),
);
String get _pageTitle => widget.buySellViewModel.mode == BuySellPageMode.buy
? S.current.buy
@@ -169,18 +188,22 @@ class _NewBuySellAmountPageState extends State<NewBuySellAmountPage> {
_isLoadingPaymentMethods = true;
});
await asyncWhen((_) => [PaymentMethodLoaded, PaymentMethodFailed]
.contains(widget.buySellViewModel.paymentMethodState.runtimeType),);
await asyncWhen(
(_) => [PaymentMethodLoaded, PaymentMethodFailed]
.contains(widget.buySellViewModel.paymentMethodState.runtimeType),
);
if (widget.buySellViewModel.paymentMethodState is PaymentMethodFailed) {
if(context.mounted) {
if (context.mounted) {
await showPopUp(
context: context,
builder: (context) => AlertWithOneAction(
alertTitle: S.of(context).failed_to_load_payment_methods,
alertContent: S.of(context).please_try_again_later,
buttonText: "OK",
buttonAction: Navigator.of(context).pop,),);
buttonAction: Navigator.of(context).pop,
),
);
}
return;
}
@@ -192,11 +215,15 @@ class _NewBuySellAmountPageState extends State<NewBuySellAmountPage> {
unawaited(widget.buySellViewModel.calculateBestRate());
final page = BuySellProviderPage(buySellViewModel: widget.buySellViewModel);
if(context.mounted) {
unawaited(Navigator.of(context).push(CupertinoPageRoute(
builder: (context) => Material(color: Colors.transparent, child: page),),));
if (context.mounted) {
unawaited(
Navigator.of(context).push(
CupertinoPageRoute(
builder: (context) => Material(color: Colors.transparent, child: page),
),
),
);
}
} finally {
setState(() {
_isLoadingPaymentMethods = false;
@@ -233,50 +260,62 @@ class BuySellCustomAmountInput extends StatelessWidget {
@override
Widget build(BuildContext context) => Padding(
padding: EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const SizedBox.shrink(),
Column(
spacing: 8,
children: [
FloatingAmountInput(
currency: fiatCurrency,
focusNode: focusNode,
controller: controller,
onChanged: onChanged,
),
Opacity(
opacity: cryptoAmount.isEmpty ? 0 : 1,
child: Text(
"≈ ${cryptoAmount} ${cryptoCurrency.symbol}",
style: TextStyle(
padding: EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const SizedBox.shrink(),
Column(
spacing: 8,
children: [
FloatingAmountInput(
currency: fiatCurrency,
focusNode: focusNode,
controller: controller,
onChanged: onChanged,
),
Opacity(
opacity: cryptoAmount.isEmpty ? 0 : 1,
child: Text(
"≈ ${cryptoAmount} ${cryptoCurrency.symbol}",
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.w600,
color: Theme.of(context).colorScheme.onSurfaceVariant,),
color: Theme.of(context).colorScheme.onSurfaceVariant,
),
),
),
),
],
),
Padding(
padding: const EdgeInsets.all(18),
child: NewPrimaryButton(
],
),
Padding(
padding: const EdgeInsets.all(18),
child: NewPrimaryButton(
onPressed: onContinuePressed,
isLoading: isLoading,
text: S.of(context).continue_text,
color: Theme.of(context).colorScheme.primary,
textColor: Theme.of(context).colorScheme.onPrimary,),
),
],
),
);
textColor: Theme.of(context).colorScheme.onPrimary,
),
),
],
),
);
}
class BuySellDefaultAmountSelector extends StatelessWidget {
const BuySellDefaultAmountSelector(
{required this.onFiatSelectorPressed, required this.defaultAmounts, required this.fiatCurrency, required this.mode, required this.onSelected, required this.isLoading, required this.hasCurrencySelector, required this.onCurrencySelectorPressed, required this.cryptoCurrency, super.key,
this.currentAmount,});
const BuySellDefaultAmountSelector({
required this.onFiatSelectorPressed,
required this.defaultAmounts,
required this.fiatCurrency,
required this.mode,
required this.onSelected,
required this.isLoading,
required this.hasCurrencySelector,
required this.onCurrencySelectorPressed,
required this.cryptoCurrency,
super.key,
this.currentAmount,
});
final List<String> defaultAmounts;
final String? currentAmount;
@@ -291,37 +330,42 @@ class BuySellDefaultAmountSelector extends StatelessWidget {
@override
Widget build(BuildContext context) => Padding(
padding: const EdgeInsets.symmetric(horizontal: 18),
child: Column(
spacing: 24,
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (hasCurrencySelector)
BuySellCurrencyPickerPill(title: mode == BuySellPageMode.sell ? S
.of(context)
.sell : S
.of(context)
.buy, curr: cryptoCurrency, onTap: onCurrencySelectorPressed),
BuySellCurrencyPickerPill(title: mode == BuySellPageMode.sell ? S
.of(context)
.receive : S
.of(context)
.purchase_with, curr: fiatCurrency, onTap: onFiatSelectorPressed),
Text(
mode == BuySellPageMode.sell
? S.of(context).choose_amount_to_sell
: S.of(context).choose_amount_to_buy,
style: TextStyle(color: Theme.of(context).colorScheme.onSurfaceVariant),
),
GridView.builder(
padding: const EdgeInsets.symmetric(horizontal: 18),
child: Column(
spacing: 24,
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (hasCurrencySelector)
BuySellCurrencyPickerPill(
title: mode == BuySellPageMode.sell ? S.of(context).sell : S.of(context).buy,
curr: cryptoCurrency,
onTap: onCurrencySelectorPressed,
),
BuySellCurrencyPickerPill(
title: mode == BuySellPageMode.sell
? S.of(context).receive
: S.of(context).purchase_with,
curr: fiatCurrency,
onTap: onFiatSelectorPressed,
),
Text(
mode == BuySellPageMode.sell
? S.of(context).choose_amount_to_sell
: S.of(context).choose_amount_to_buy,
style: TextStyle(color: Theme.of(context).colorScheme.onSurfaceVariant),
),
GridView.builder(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
// +1 for "custom" option
itemCount: defaultAmounts.length + 1,
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2, crossAxisSpacing: 8, mainAxisSpacing: 16, mainAxisExtent: 105,),
crossAxisCount: 2,
crossAxisSpacing: 8,
mainAxisSpacing: 16,
mainAxisExtent: 105,
),
itemBuilder: (context, index) {
final String? item = index == defaultAmounts.length ? null : defaultAmounts[index];
@@ -330,10 +374,11 @@ class BuySellDefaultAmountSelector extends StatelessWidget {
amount: item == null ? null : Money.parse(item, fiatCurrency),
onTap: () => onSelected(item),
);
},),
],
),
);
},
),
],
),
);
}
class BuySellAmountPill extends StatelessWidget {
@@ -345,68 +390,72 @@ class BuySellAmountPill extends StatelessWidget {
@override
Widget build(BuildContext context) => Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(9999999999),
border: Border.all(
width: 1,
color: Theme.of(context).colorScheme.surfaceContainerHigh,
),
gradient: LinearGradient(
colors: [
context.customColors.cardGradientColorPrimary,
context.customColors.cardGradientColorSecondary,
],
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
),
),
child: Material(
color: Colors.transparent,
borderRadius: BorderRadius.circular(9999999999),
child: InkWell(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(9999999999),
onTap: onTap,
child: isLoading
? const CupertinoActivityIndicator()
: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Row(
spacing: 4,
mainAxisAlignment: MainAxisAlignment.center,
children: [
if (amount != null)
MoneyText(
amount!,
style: const TextStyle(fontSize: 18, fontWeight: FontWeight.w600),
showSymbol: false,
),
Text(
amount?.currency.symbol ?? S.of(context).custom,
style: TextStyle(
border: Border.all(
width: 1,
color: Theme.of(context).colorScheme.surfaceContainerHigh,
),
gradient: LinearGradient(
colors: [
context.customColors.cardGradientColorPrimary,
context.customColors.cardGradientColorSecondary,
],
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
),
),
child: Material(
color: Colors.transparent,
borderRadius: BorderRadius.circular(9999999999),
child: InkWell(
borderRadius: BorderRadius.circular(9999999999),
onTap: onTap,
child: isLoading
? const CupertinoActivityIndicator()
: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Row(
spacing: 4,
mainAxisAlignment: MainAxisAlignment.center,
children: [
if (amount != null)
MoneyText(
amount!,
style: const TextStyle(fontSize: 18, fontWeight: FontWeight.w600),
showSymbol: false,
),
Text(
amount?.currency.symbol ?? S.of(context).custom,
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.w600,
color: amount == null
? Theme.of(context).colorScheme.primary
: Theme.of(context).colorScheme.onSurfaceVariant,),
),
],
),
if (amount == null)
Text(
S.of(context).enter_amount,
style: TextStyle(
fontSize: 12, color: Theme.of(context).colorScheme.onSurfaceVariant,),
: Theme.of(context).colorScheme.onSurfaceVariant,
),
),
],
),
],
),
if (amount == null)
Text(
S.of(context).enter_amount,
style: TextStyle(
fontSize: 12,
color: Theme.of(context).colorScheme.onSurfaceVariant,
),
),
],
),
),
),
),
);
);
}
class BuySellCurrencyPickerPill extends StatelessWidget {
const BuySellCurrencyPickerPill({required this.title, required this.curr, required this.onTap, super.key});
const BuySellCurrencyPickerPill(
{required this.title, required this.curr, required this.onTap, super.key});
final String title;
final Currency curr;
@@ -414,65 +463,74 @@ class BuySellCurrencyPickerPill extends StatelessWidget {
@override
Widget build(BuildContext context) => Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
spacing: 12,
children: [
Text(title, style: TextStyle(color: Theme.of(context).colorScheme.onSurfaceVariant),),
GestureDetector(
onTap: onTap,
child: Container(
width: MediaQuery.sizeOf(context).width,
height: 62,
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.surfaceContainer,
borderRadius: BorderRadius.circular(18),
),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 12),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(spacing:12, children: [
if(curr is CryptoCurrency)
TokenChainDisplay(size: 30, asset: curr as CryptoCurrency)
else if(curr is FiatCurrency)
SizedBox(width: 30, child: Text((curr as FiatCurrency).emoji, style: const TextStyle(fontSize: 24),)),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
spacing: 2,
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
spacing: 12,
children: [
Text(
title,
style: TextStyle(color: Theme.of(context).colorScheme.onSurfaceVariant),
),
GestureDetector(
onTap: onTap,
child: Container(
width: MediaQuery.sizeOf(context).width,
height: 62,
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.surfaceContainer,
borderRadius: BorderRadius.circular(18),
),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 12),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
spacing: 12,
children: [
Text(
curr.fullName ?? curr.symbol,
if (curr is CryptoCurrency)
TokenChainDisplay(size: 30, asset: curr as CryptoCurrency)
else if (curr is FiatCurrency)
SizedBox(
width: 30,
child: Text(
(curr as FiatCurrency).emoji,
style: const TextStyle(fontSize: 24),
)),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
spacing: 2,
children: [
Text(
curr.fullName ?? curr.symbol,
),
CurrencySymbolText(
curr,
style: TextStyle(
fontSize: 12,
color: Theme.of(context).colorScheme.onSurfaceVariant,
),
),
],
),
CurrencySymbolText(
curr,
style: TextStyle(
fontSize: 12,
color: Theme.of(context).colorScheme.onSurfaceVariant,
),
)
],
),
],),
RotatedBox(
quarterTurns: 2,
child: CakeImageWidget(
imageUrl: "assets/new-ui/dropdown_arrow.svg",
width: 8,
height: 8,
colorFilter:
ColorFilter.mode(Theme.of(context).colorScheme.primary, BlendMode.srcIn),
RotatedBox(
quarterTurns: 2,
child: CakeImageWidget(
imageUrl: "assets/new-ui/dropdown_arrow.svg",
width: 8,
height: 8,
colorFilter: ColorFilter.mode(
Theme.of(context).colorScheme.primary, BlendMode.srcIn),
),
),
),
],
],
),
),
),
),
),
],
);
],
);
}
@@ -1,134 +1,144 @@
import 'package:cake_wallet/buy/payment_method.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_redirecting_page.dart';
import 'package:cake_wallet/new-ui/widgets/buy_sell/buy_sell_selector_modal.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/cake_image_widget.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';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
import "package:cake_wallet/buy/payment_method.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_redirecting_page.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/cake_image_widget.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";
import "package:flutter/cupertino.dart";
import "package:flutter/material.dart";
import "package:flutter_mobx/flutter_mobx.dart";
class BuySellConfirmationPage extends StatelessWidget {
const BuySellConfirmationPage({super.key, required this.buySellViewModel});
const BuySellConfirmationPage({required this.buySellViewModel, super.key});
final BuySellViewModel buySellViewModel;
@override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.vertical(top: Radius.circular(18)),
gradient: LinearGradient(
colors: [
Theme.of(context).colorScheme.surface,
Theme.of(context).colorScheme.surfaceDim,
],
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
Widget build(BuildContext context) => Container(
decoration: BoxDecoration(
borderRadius: const BorderRadius.vertical(top: Radius.circular(18)),
gradient: LinearGradient(
colors: [
Theme.of(context).colorScheme.surface,
Theme.of(context).colorScheme.surfaceDim,
],
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
),
),
),
child: SafeArea(
child: Column(
children: [
ModalTopBar(
title: _pageTitle,
leadingIcon: Icon(Icons.arrow_back_ios_new),
onLeadingPressed: Navigator.of(context).pop,
),
Expanded(child: Observer(
builder: (_) {
return Column(
spacing: 24,
children: [
Column(
spacing: 4,
children: [
Text(
"${buySellViewModel.fiatAmount} ${buySellViewModel.fiatCurrency}",
style: TextStyle(fontSize: 32),
),
Text(
"≈ ${buySellViewModel.amountForQuote(buySellViewModel.selectedQuote!)?.toStringWithSymbol(fractionalDigits: 8)}",
style: TextStyle(
color: Theme.of(context).colorScheme.onSurfaceVariant,
fontWeight: FontWeight.w500),
)
],
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 18.0),
child: NewListSections(sections: {
"": [
ListItemRegularRow(
keyValue: "provider",
label: S.of(context).provider,
trailingWidget: Row(
spacing: 8,
children: [
CakeImageWidget(
imageUrl: Theme.of(context).brightness == Brightness.light
? buySellViewModel.selectedQuote!.lightIconPath
: buySellViewModel.selectedQuote!.darkIconPath,
width: 24,
height: 24,
),
Text(
buySellViewModel.selectedQuote!.rampName ??
buySellViewModel.selectedQuote!.provider.title,
style: TextStyle(
child: SafeArea(
child: Column(
children: [
ModalTopBar(
title: _pageTitle,
leadingIcon: const Icon(Icons.arrow_back_ios_new),
onLeadingPressed: Navigator.of(context).pop,
leadingSemanticLabel: S.of(context).seed_alert_back,
),
Expanded(
child: Observer(
builder: (_) => Column(
spacing: 24,
children: [
Column(
spacing: 4,
children: [
Text(
"${buySellViewModel.fiatAmount} ${buySellViewModel.fiatCurrency}",
style: const TextStyle(fontSize: 32),
),
if (buySellViewModel.amountForQuote(buySellViewModel.selectedQuote!) !=
null)
Text(
"≈ ${buySellViewModel.amountForQuote(buySellViewModel.selectedQuote!)?.toStringWithSymbol(fractionalDigits: 8)}",
style: TextStyle(
color: Theme.of(context).colorScheme.onSurfaceVariant,
fontWeight: FontWeight.w500,
),
),
],
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 18),
child: NewListSections(
sections: {
"": [
ListItemRegularRow(
keyValue: "provider",
label: S.of(context).provider,
trailingWidget: Row(
spacing: 8,
children: [
CakeImageWidget(
imageUrl: Theme.of(context).brightness == Brightness.light
? buySellViewModel.selectedQuote!.lightIconPath
: buySellViewModel.selectedQuote!.darkIconPath,
width: 24,
height: 24,
),
Text(
buySellViewModel.selectedQuote!.rampName ??
buySellViewModel.selectedQuote!.provider.title,
style: TextStyle(
color: Theme.of(context).colorScheme.onSurfaceVariant,
fontWeight: FontWeight.w500),
),
SizedBox.shrink()
],
)),
if(buySellViewModel.selectedQuote!.paymentType.title?.isNotEmpty ?? false)
ListItemRegularRow(
showArrow: false,
keyValue: "payment method",
label: S.of(context).payment_method,
trailingText: buySellViewModel.selectedQuote!.paymentType.title),
ListItemRegularRow(
showArrow: false,
keyValue: "rate",
label: S.of(context).rate,
trailingText: buySellViewModel.selectedQuote!.topLeftSubTitle)
]
}),
)
],
);
},
)),
Padding(
padding: EdgeInsets.all(18),
child: NewPrimaryButton(
fontWeight: FontWeight.w500,
),
),
const SizedBox.shrink(),
],
),
),
if (buySellViewModel.selectedQuote!.paymentType.title?.isNotEmpty ??
false)
ListItemRegularRow(
showArrow: false,
keyValue: "payment method",
label: S.of(context).payment_method,
trailingText: buySellViewModel.selectedQuote!.paymentType.title,
),
ListItemRegularRow(
showArrow: false,
keyValue: "rate",
label: S.of(context).rate,
trailingText: buySellViewModel.selectedQuote!.topLeftSubTitle,
),
],
},
),
),
],
),
),
),
Padding(
padding: const EdgeInsets.all(18),
child: NewPrimaryButton(
onPressed: () => confirm(context),
text: S.of(context).proceed,
color: Theme.of(context).colorScheme.primary,
textColor: Theme.of(context).colorScheme.onPrimary),
)
],
textColor: Theme.of(context).colorScheme.onPrimary,
),
),
],
),
),
),
);
}
);
String get _pageTitle =>
(buySellViewModel.mode == BuySellPageMode.buy ? S.current.buy : S.current.sell) +
" " +
(buySellViewModel.cryptoCurrency.fullName ?? "");
"${buySellViewModel.mode == BuySellPageMode.buy ? S.current.buy : S.current.sell} ${buySellViewModel.cryptoCurrency.fullName ?? ""}";
void confirm(BuildContext context) {
final page = BuySellRedirectingPage(buySellViewModel: buySellViewModel);
Navigator.of(context, rootNavigator: true).pop();
Navigator.of(context, rootNavigator: true).push(CupertinoPageRoute(
Navigator.of(context, rootNavigator: true).push(
CupertinoPageRoute(
builder: (context) => Material(
child: page,
)));
child: page,
),
),
);
}
}
@@ -1,73 +1,81 @@
import 'package:cake_wallet/buy/payment_method.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/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';
import 'package:flutter/material.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
import "dart:async";
import "package:cake_wallet/buy/payment_method.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/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";
import "package:flutter/material.dart";
import "package:flutter_mobx/flutter_mobx.dart";
class BuySellPaymentMethodPage extends StatelessWidget {
const BuySellPaymentMethodPage({super.key, required this.buySellViewModel});
const BuySellPaymentMethodPage({required this.buySellViewModel, super.key});
final BuySellViewModel buySellViewModel;
@override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.vertical(top: Radius.circular(18)),
gradient: LinearGradient(
colors: [
Theme.of(context).colorScheme.surface,
Theme.of(context).colorScheme.surfaceDim,
],
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
),
),
child: SafeArea(
child: Column(
children: [
ModalTopBar(
title: S.of(context).payment_method,
leadingIcon: Icon(Icons.arrow_back_ios_new),
onLeadingPressed: Navigator.of(context).pop,
Widget build(BuildContext context) => Container(
decoration: BoxDecoration(
borderRadius: const BorderRadius.vertical(top: Radius.circular(18)),
gradient: LinearGradient(
colors: [
Theme.of(context).colorScheme.surface,
Theme.of(context).colorScheme.surfaceDim,
],
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
),
Expanded(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 18.0),
child: Observer(
builder: (_) => NewListSections(sections: {
"": buySellViewModel.paymentMethods
.map((item) => ListItemRegularRow(
keyValue: item.title,
label: item.title,
showArrow: false,
iconPath: Theme.of(context).brightness == Brightness.light
? item.lightIconPath
: item.darkIconPath,
iconColor: item.paymentMethodType.isMonochromeIcon
? Theme.of(context).colorScheme.onSurfaceVariant
: null,
trailingWidget: buySellViewModel.selectedPaymentMethod == item
? Icon(
Icons.check,
color: Theme.of(context).colorScheme.primary,
size: 16,
)
: null,
onTap: () async {
buySellViewModel.changeOption(item);
buySellViewModel.calculateBestRate();
Navigator.of(context).pop();
}))
.toList()
}),
),
))
],
)),
);
}
),
child: SafeArea(
child: Column(
children: [
ModalTopBar(
title: S.of(context).payment_method,
leadingIcon: const Icon(Icons.arrow_back_ios_new),
onLeadingPressed: Navigator.of(context).pop,
leadingSemanticLabel: S.of(context).seed_alert_back,
),
Expanded(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 18),
child: Observer(
builder: (_) => NewListSections(
sections: {
"": buySellViewModel.paymentMethods
.map(
(item) => ListItemRegularRow(
keyValue: item.title,
label: item.title,
showArrow: false,
iconPath: Theme.of(context).brightness == Brightness.light
? item.lightIconPath
: item.darkIconPath,
iconColor: item.paymentMethodType.isMonochromeIcon
? Theme.of(context).colorScheme.onSurfaceVariant
: null,
trailingWidget: buySellViewModel.selectedPaymentMethod == item
? Icon(
Icons.check,
color: Theme.of(context).colorScheme.primary,
size: 16,
)
: null,
onTap: () {
buySellViewModel.changeOption(item);
unawaited(buySellViewModel.calculateBestRate());
Navigator.of(context).pop();
},
),
)
.toList(),
},
),
),
),
),
],
),
),
);
}
@@ -1,23 +1,22 @@
import 'package:cake_wallet/buy/buy_quote.dart';
import 'package:cake_wallet/buy/sell_buy_states.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/buy_sell/buy_sell_selector_modal.dart';
import "package:cake_wallet/buy/buy_quote.dart";
import "package:cake_wallet/buy/sell_buy_states.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/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';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_mobx/flutter_mobx.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";
import "package:flutter/cupertino.dart";
import "package:flutter/material.dart";
import "package:flutter_mobx/flutter_mobx.dart";
import "package:modal_bottom_sheet/modal_bottom_sheet.dart";
class BuySellProviderPage extends StatefulWidget {
const BuySellProviderPage({super.key, required this.buySellViewModel});
const BuySellProviderPage({required this.buySellViewModel, super.key});
final BuySellViewModel buySellViewModel;
@@ -29,116 +28,128 @@ class _BuySellProviderPageState extends State<BuySellProviderPage> {
bool _allProvidersExpanded = false;
@override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.vertical(top: Radius.circular(18)),
gradient: LinearGradient(
colors: [
Theme.of(context).colorScheme.surface,
Theme.of(context).colorScheme.surfaceDim,
],
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
),
),
child: SafeArea(
child: Column(
children: [
ModalTopBar(
title: _pageTitle,
leadingIcon: Icon(Icons.arrow_back_ios_new),
onLeadingPressed: Navigator.of(context).pop,
Widget build(BuildContext context) => Container(
decoration: BoxDecoration(
borderRadius: const BorderRadius.vertical(top: Radius.circular(18)),
gradient: LinearGradient(
colors: [
Theme.of(context).colorScheme.surface,
Theme.of(context).colorScheme.surfaceDim,
],
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
),
Expanded(child: Observer(
builder: (_) {
if (widget.buySellViewModel.buySellQuotState is BuySellQuotFailed) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
spacing: 24,
children: [
Icon(Icons.warning_amber_outlined, size: 48),
Column(
spacing: 10,
children: [
Text(
S.of(context).could_not_load_quotes,
style: TextStyle(fontSize: 20, fontWeight: FontWeight.w500),
),
child: SafeArea(
child: Column(
children: [
ModalTopBar(
title: _pageTitle,
leadingIcon: const Icon(Icons.arrow_back_ios_new),
onLeadingPressed: Navigator.of(context).pop,
leadingSemanticLabel: S.of(context).seed_alert_back,
),
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) {
return Center(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
spacing: 8,
children: [
const CupertinoActivityIndicator(),
Text(
S.of(context).loading_rates,
style:
TextStyle(color: Theme.of(context).colorScheme.onSurfaceVariant),
),
],
),
Text((widget.buySellViewModel.buySellQuotState as BuySellQuotFailed)
.errorMessage ??
S.of(context).please_try_again_later)
],
)
],
);
}
);
}
if (widget.buySellViewModel.buySellQuotState is BuySellQuotLoading) {
return Center(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
spacing: 8,
children: [
CupertinoActivityIndicator(),
Text(
S.of(context).loading_rates,
style: TextStyle(color: Theme.of(context).colorScheme.onSurfaceVariant),
)
],
),
);
}
return SingleChildScrollView(
controller: ModalScrollController.of(context),
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 18),
child: NewListSections(showHeader: true, sections: {
"": [
ListItemRegularRow(
keyValue: "payment method",
label: S.of(context).payment_method,
showArrow: true,
onTap: () {
final page =
BuySellPaymentMethodPage(buySellViewModel: widget.buySellViewModel);
Navigator.of(context).push(CupertinoPageRoute(
builder: (context) => Material(
color: Colors.transparent,
child: page,
)));
return SingleChildScrollView(
controller: ModalScrollController.of(context),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 18),
child: NewListSections(
showHeader: true,
sections: {
"": [
ListItemRegularRow(
keyValue: "payment method",
label: S.of(context).payment_method,
showArrow: true,
onTap: () {
final page = BuySellPaymentMethodPage(
buySellViewModel: widget.buySellViewModel,
);
Navigator.of(context).push(
CupertinoPageRoute(
builder: (context) => Material(
color: Colors.transparent,
child: page,
),
),
);
},
trailingText: widget.buySellViewModel.selectedPaymentMethod?.title,
),
],
S.of(context).available_providers: [
...widget.buySellViewModel.sortedRecommendedQuotes.map(quoteListItem),
if (widget.buySellViewModel.sortedQuotes.isNotEmpty)
ListItemDropdown(
keyValue: "more options",
label: S.of(context).more_options,
onTap: () {
setState(() {
_allProvidersExpanded = !_allProvidersExpanded;
});
},
),
if (_allProvidersExpanded)
...widget.buySellViewModel.sortedQuotes.map(quoteListItem),
],
},
trailingText: widget.buySellViewModel.selectedPaymentMethod?.title)
],
S.of(context).available_providers: [
...widget.buySellViewModel.sortedRecommendedQuotes.map(quoteListItem),
if (widget.buySellViewModel.sortedQuotes.isNotEmpty)
ListItemDropdown(
keyValue: "more options",
label: S.of(context).more_options,
onTap: () {
setState(() {
_allProvidersExpanded = !_allProvidersExpanded;
});
}),
if (_allProvidersExpanded)
...widget.buySellViewModel.sortedQuotes.map(quoteListItem)
]
}),
),
),
);
},
),
);
},
))
],
)),
);
}
),
],
),
),
);
String get _pageTitle =>
(widget.buySellViewModel.mode == BuySellPageMode.buy ? S.current.buy : S.current.sell) +
" " +
(widget.buySellViewModel.cryptoCurrency.fullName ?? "");
"${widget.buySellViewModel.mode == BuySellPageMode.buy ? S.current.buy : S.current.sell} ${widget.buySellViewModel.cryptoCurrency.fullName ?? ""}";
ListItem quoteListItem(Quote quote) {
final fiatAmount = widget.buySellViewModel.fiatAmountForQuote(quote);
@@ -148,10 +159,10 @@ class _BuySellProviderPageState extends State<BuySellProviderPage> {
secondaryLabel: quote.rampName != null ? quote.provider.title : null,
subtitle: quote.badges.isEmpty ? null : quote.badges.join(" - "),
subtitleColor: Theme.of(context).colorScheme.primary,
iconPath: Theme.of(context).brightness == Brightness.light
? quote.lightIconPath
: quote.darkIconPath,
onTap: () {
iconPath: Theme.of(context).brightness == Brightness.light
? quote.lightIconPath
: quote.darkIconPath,
onTap: () {
widget.buySellViewModel.changeOption(quote);
navigateToConfirmation(context);
},
@@ -161,21 +172,26 @@ class _BuySellProviderPageState extends State<BuySellProviderPage> {
mainAxisAlignment: MainAxisAlignment.center,
spacing: 4,
children: [
MoneyText.optional(widget.buySellViewModel.amountForQuote(quote)),
if (fiatAmount != null)
Text(
MoneyText.optional(widget.buySellViewModel.amountForQuote(quote)),
if (fiatAmount != null)
Text(
"= ${fiatAmount.toStringWithSymbol(fractionalDigits: 2, trimZeros: false)}",
style: TextStyle(fontSize: 12, color: Theme.of(context).colorScheme.onSurfaceVariant))
style: TextStyle(fontSize: 12, color: Theme.of(context).colorScheme.onSurfaceVariant),
),
],
));
),
);
}
void navigateToConfirmation(BuildContext context) {
final page = BuySellConfirmationPage(buySellViewModel: widget.buySellViewModel);
Navigator.of(context).push(CupertinoPageRoute(
Navigator.of(context).push(
CupertinoPageRoute(
builder: (context) => Material(
color: Colors.transparent,
child: page,
)));
color: Colors.transparent,
child: page,
),
),
);
}
}
@@ -1,13 +1,13 @@
import 'package:cake_wallet/buy/sell_buy_states.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/new-ui/widgets/new_primary_button.dart';
import 'package:cake_wallet/src/widgets/cake_image_widget.dart';
import 'package:cake_wallet/view_model/buy/buy_sell_view_model.dart';
import 'package:flutter/material.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
import "package:cake_wallet/buy/sell_buy_states.dart";
import "package:cake_wallet/generated/i18n.dart";
import "package:cake_wallet/new-ui/widgets/new_primary_button.dart";
import "package:cake_wallet/src/widgets/cake_image_widget.dart";
import "package:cake_wallet/view_model/buy/buy_sell_view_model.dart";
import "package:flutter/material.dart";
import "package:flutter_mobx/flutter_mobx.dart";
class BuySellRedirectingPage extends StatefulWidget {
const BuySellRedirectingPage({super.key, required this.buySellViewModel});
const BuySellRedirectingPage({required this.buySellViewModel, super.key});
final BuySellViewModel buySellViewModel;
@@ -21,7 +21,7 @@ class _BuySellRedirectingPageState extends State<BuySellRedirectingPage> {
@override
void initState() {
super.initState();
Future.delayed(Duration(seconds: 2)).then((_) async {
Future.delayed(const Duration(seconds: 2)).then((_) {
WidgetsBinding.instance
.addPostFrameCallback((_) => widget.buySellViewModel.launchTrade(context));
setState(() {
@@ -31,97 +31,99 @@ class _BuySellRedirectingPageState extends State<BuySellRedirectingPage> {
}
@override
Widget build(BuildContext context) {
return PopScope(
canPop: false,
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.vertical(top: Radius.circular(18)),
gradient: LinearGradient(
colors: [
Theme.of(context).colorScheme.surface,
Theme.of(context).colorScheme.surfaceDim,
],
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
Widget build(BuildContext context) => PopScope(
canPop: false,
child: Container(
decoration: BoxDecoration(
borderRadius: const BorderRadius.vertical(top: Radius.circular(18)),
gradient: LinearGradient(
colors: [
Theme.of(context).colorScheme.surface,
Theme.of(context).colorScheme.surfaceDim,
],
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
),
),
),
child: Observer(
builder: (_) {
final showExitButton =
_hasRedirected || widget.buySellViewModel.buySellQuotState is BuySellQuotFailed;
child: Observer(
builder: (_) {
final showExitButton =
_hasRedirected || widget.buySellViewModel.buySellQuotState is BuySellQuotFailed;
return SafeArea(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
SizedBox.shrink(),
Observer(
builder: (_) {
if (widget.buySellViewModel.buySellQuotState is BuySellQuotFailed) {
return SafeArea(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const SizedBox.shrink(),
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_proceed_with_trade,
style:
const TextStyle(fontSize: 20, fontWeight: FontWeight.w500),
),
Text(
(widget.buySellViewModel.buySellQuotState as BuySellQuotFailed)
.errorMessage ??
S.of(context).please_try_again_later,
),
],
),
],
);
}
return Column(
mainAxisAlignment: MainAxisAlignment.center,
spacing: 24,
children: [
Icon(Icons.warning_amber_outlined, size: 48),
CakeImageWidget(
imageUrl: Theme.of(context).brightness == Brightness.light
? widget.buySellViewModel.selectedQuote!.lightIconPath
: widget.buySellViewModel.selectedQuote!.darkIconPath,
width: 64,
height: 64,
),
Column(
spacing: 10,
children: [
Text(
S.of(context).could_not_proceed_with_trade,
style: TextStyle(fontSize: 20, fontWeight: FontWeight.w500),
"${S.of(context).connecting_you_to} ${widget.buySellViewModel.selectedQuote!.provider.title}...",
style: const TextStyle(fontSize: 20, fontWeight: FontWeight.w500),
),
Text(
"${widget.buySellViewModel.fiatAmount} ${widget.buySellViewModel.fiatCurrency} → ${widget.buySellViewModel.amountForQuote(widget.buySellViewModel.selectedQuote!)?.toStringWithSymbol(fractionalDigits: 8)}",
),
Text((widget.buySellViewModel.buySellQuotState as BuySellQuotFailed)
.errorMessage ??
S.of(context).please_try_again_later)
],
)
),
],
);
}
return Column(
mainAxisAlignment: MainAxisAlignment.center,
spacing: 24,
children: [
CakeImageWidget(
imageUrl: Theme.of(context).brightness == Brightness.light
? widget.buySellViewModel.selectedQuote!.lightIconPath
: widget.buySellViewModel.selectedQuote!.darkIconPath,
width: 64,
height: 64,
),
Column(
spacing: 10,
children: [
Text(
"${S.of(context).connecting_you_to} ${widget.buySellViewModel.selectedQuote!.provider.title}...",
style: TextStyle(fontSize: 20, fontWeight: FontWeight.w500),
),
Text(
"${widget.buySellViewModel.fiatAmount} ${widget.buySellViewModel.fiatCurrency} → ${widget.buySellViewModel.amountForQuote(widget.buySellViewModel.selectedQuote!)?.toStringWithSymbol(fractionalDigits: 8)}")
],
},
),
showExitButton
? Padding(
padding: const EdgeInsets.all(18),
child: NewPrimaryButton(
onPressed: Navigator.of(context).pop,
text: S.of(context).close,
color: Theme.of(context).colorScheme.primary,
textColor: Theme.of(context).colorScheme.onPrimary,
),
)
],
);
},
),
showExitButton
? Padding(
padding: EdgeInsets.all(18),
child: NewPrimaryButton(
onPressed: Navigator.of(context).pop,
text: S.of(context).close,
color: Theme.of(context).colorScheme.primary,
textColor: Theme.of(context).colorScheme.onPrimary,
),
)
: SizedBox.shrink()
],
),
);
},
: const SizedBox.shrink(),
],
),
);
},
),
),
),
);
}
);
}
@@ -1,22 +1,20 @@
import 'package:cake_wallet/di.dart';
import 'package:cake_wallet/generated/i18n.dart';
import "package:cake_wallet/di.dart";
import "package:cake_wallet/generated/i18n.dart";
import "package:cake_wallet/main.dart";
import 'package:cake_wallet/new-ui/modal_navigator.dart';
import 'package:cake_wallet/new-ui/pages/buy_sell/buy_sell_amount_page.dart';
import 'package:cake_wallet/src/widgets/cake_image_widget.dart';
import 'package:cake_wallet/themes/core/theme_extension.dart';
import 'package:flutter/material.dart';
enum BuySellPageMode { buy, sell }
import "package:cake_wallet/new-ui/modal_navigator.dart";
import "package:cake_wallet/new-ui/pages/buy_sell/buy_sell_amount_page.dart";
import "package:cake_wallet/src/widgets/cake_image_widget.dart";
import "package:cake_wallet/themes/core/theme_extension.dart";
import "package:cake_wallet/view_model/buy/buy_sell_view_model.dart";
import "package:flutter/material.dart";
class BuySellSelectorModal extends StatelessWidget {
const BuySellSelectorModal({super.key});
@override
Widget build(BuildContext context) {
return Container(
Widget build(BuildContext context) => Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.vertical(top: Radius.circular(18)),
borderRadius: const BorderRadius.vertical(top: Radius.circular(18)),
gradient: LinearGradient(
colors: [
Theme.of(context).colorScheme.surface,
@@ -27,12 +25,15 @@ class BuySellSelectorModal extends StatelessWidget {
),
),
child: SafeArea(
top: false,
child: Column(spacing: 24, mainAxisSize: MainAxisSize.min, children: [
SizedBox.shrink(),
top: false,
child: Column(
spacing: 24,
mainAxisSize: MainAxisSize.min,
children: [
const SizedBox.shrink(),
Text(
S.of(context).buy_or_sell,
style: TextStyle(fontSize: 20, fontWeight: FontWeight.w500),
style: const TextStyle(fontSize: 20, fontWeight: FontWeight.w500),
),
Text(
S.of(context).buy_or_sell_desc,
@@ -40,7 +41,7 @@ class BuySellSelectorModal extends StatelessWidget {
TextStyle(fontSize: 12, color: Theme.of(context).colorScheme.onSurfaceVariant),
),
Padding(
padding: EdgeInsets.symmetric(horizontal: 18.0),
padding: const EdgeInsets.symmetric(horizontal: 18),
child: Column(
spacing: 12,
children: [
@@ -51,39 +52,43 @@ class BuySellSelectorModal extends StatelessWidget {
onTap: () => openBuySellPage(context, BuySellPageMode.buy),
),
BuySellSelectorModalButton(
title: S.of(context).sell_crypto,
description: S.of(context).sell_crypto_desc,
iconPath: "assets/new-ui/sell.svg",
onTap: () => openBuySellPage(context, BuySellPageMode.sell))
title: S.of(context).sell_crypto,
description: S.of(context).sell_crypto_desc,
iconPath: "assets/new-ui/sell.svg",
onTap: () => openBuySellPage(context, BuySellPageMode.sell),
),
],
),
),
SizedBox.shrink()
])));
}
const SizedBox.shrink(),
],
),
),
);
void openBuySellPage(BuildContext context, BuySellPageMode mode) {
Navigator.of(context).pop();
final page = getIt.get<NewBuySellAmountPage>(param1: mode);
showModalBottomSheet(
useSafeArea: true,
isScrollControlled: true,
context: navigatorKey.currentContext!,
builder: (modalContext) => ModalNavigator(
rootPage: page,
parentContext: modalContext,
));
useSafeArea: true,
isScrollControlled: true,
context: navigatorKey.currentContext!,
builder: (modalContext) => ModalNavigator(
rootPage: page,
parentContext: modalContext,
),
);
}
}
class BuySellSelectorModalButton extends StatelessWidget {
const BuySellSelectorModalButton(
{super.key,
required this.title,
required this.description,
required this.iconPath,
required this.onTap});
const BuySellSelectorModalButton({
required this.title,
required this.description,
required this.iconPath,
required this.onTap,
super.key,
});
final String title;
final String description;
@@ -91,56 +96,58 @@ class BuySellSelectorModalButton extends StatelessWidget {
final VoidCallback onTap;
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: onTap,
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(16),
border: Border.all(
width: 1,
color: Theme.of(context).colorScheme.surfaceContainerHigh,
Widget build(BuildContext context) => GestureDetector(
onTap: onTap,
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(16),
border: Border.all(
width: 1,
color: Theme.of(context).colorScheme.surfaceContainerHigh,
),
gradient: LinearGradient(
colors: [
context.customColors.cardGradientColorPrimary,
context.customColors.cardGradientColorSecondary,
],
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
),
),
gradient: LinearGradient(
colors: [
context.customColors.cardGradientColorPrimary,
context.customColors.cardGradientColorSecondary
],
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
),
),
child: Padding(
padding: EdgeInsets.all(24),
child: Row(
spacing: 20,
children: [
CakeImageWidget(
imageUrl: iconPath,
width: 55,
height: 55,
colorFilter: ColorFilter.mode(
Theme.of(context).colorScheme.onSurfaceVariant, BlendMode.srcIn),
),
Column(
spacing: 8,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
title,
style: TextStyle(fontWeight: FontWeight.w500, fontSize: 16),
child: Padding(
padding: const EdgeInsets.all(24),
child: Row(
spacing: 20,
children: [
CakeImageWidget(
imageUrl: iconPath,
width: 55,
height: 55,
colorFilter: ColorFilter.mode(
Theme.of(context).colorScheme.onSurfaceVariant,
BlendMode.srcIn,
),
Text(
description,
style: TextStyle(
fontSize: 12, color: Theme.of(context).colorScheme.onSurfaceVariant),
)
],
)
],
),
Column(
spacing: 8,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
title,
style: const TextStyle(fontWeight: FontWeight.w500, fontSize: 16),
),
Text(
description,
style: TextStyle(
fontSize: 12,
color: Theme.of(context).colorScheme.onSurfaceVariant,
),
),
],
),
],
),
),
),
),
);
}
);
}
+69 -62
View File
@@ -1,17 +1,18 @@
import "package:cake_wallet/new-ui/widgets/money/currency_symbol_text.dart";
import 'package:cw_core/currency.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import "package:cw_core/currency.dart";
import "package:flutter/material.dart";
import "package:flutter/services.dart";
class FloatingAmountInput extends StatefulWidget {
const FloatingAmountInput(
{super.key,
required this.currency,
required this.controller,
this.focusNode,
this.inputFormatters,
this.onChanged,
this.validator});
const FloatingAmountInput({
required this.currency,
required this.controller,
super.key,
this.focusNode,
this.inputFormatters,
this.onChanged,
this.validator,
});
final Currency currency;
final TextEditingController controller;
@@ -35,64 +36,70 @@ class _FloatingAmountInputState extends State<FloatingAmountInput> {
}
@override
Widget build(BuildContext context) {
return Center(
child: Row(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.baseline,
textBaseline: TextBaseline.alphabetic,
children: [
IntrinsicWidth(
child: TextFormField(
controller: widget.controller,
focusNode: focusNode,
maxLines: 1,
onChanged: widget.onChanged,
autovalidateMode: AutovalidateMode.always,
validator: widget.validator,
keyboardType: TextInputType.numberWithOptions(
signed: false,
decimal: true,
),
inputFormatters: <TextInputFormatter>[
FilteringTextInputFormatter.allow(
RegExp(r'^\d*[.,]?\d*$'),
void dispose() {
if (focusNode != widget.focusNode) {
focusNode.dispose();
}
super.dispose();
}
@override
Widget build(BuildContext context) => Center(
child: Row(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.baseline,
textBaseline: TextBaseline.alphabetic,
children: [
IntrinsicWidth(
child: TextFormField(
controller: widget.controller,
focusNode: focusNode,
maxLines: 1,
onChanged: widget.onChanged,
autovalidateMode: AutovalidateMode.always,
validator: widget.validator,
keyboardType: const TextInputType.numberWithOptions(
signed: false,
decimal: true,
),
],
decoration: InputDecoration(
isDense: true,
isCollapsed: true,
contentPadding: EdgeInsets.zero,
fillColor: Colors.transparent,
hoverColor: Colors.transparent,
focusedBorder: InputBorder.none,
enabledBorder: InputBorder.none,
hintText: _amountFocused || widget.controller.text.isNotEmpty ? null : "0.00",
hintStyle: Theme.of(context).textTheme.displayMedium?.copyWith(
inputFormatters: <TextInputFormatter>[
FilteringTextInputFormatter.allow(
RegExp(r"^\d*[.,]?\d*$"),
),
],
decoration: InputDecoration(
isDense: true,
isCollapsed: true,
contentPadding: EdgeInsets.zero,
fillColor: Colors.transparent,
hoverColor: Colors.transparent,
focusedBorder: InputBorder.none,
enabledBorder: InputBorder.none,
hintText: _amountFocused || widget.controller.text.isNotEmpty ? null : "0.00",
hintStyle: Theme.of(context).textTheme.displayMedium?.copyWith(
fontWeight: FontWeight.w400,
color: Theme.of(context).colorScheme.onSurfaceVariant,
),
),
style: Theme.of(context).textTheme.displayMedium?.copyWith(
fontWeight: FontWeight.w400,
color: Theme.of(context).colorScheme.onSurfaceVariant,
fontSize: 45,
color: Theme.of(context).colorScheme.onSurface,
),
),
),
const SizedBox(width: 8),
CurrencySymbolText(
widget.currency,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: Theme.of(context).textTheme.displayMedium?.copyWith(
fontWeight: FontWeight.w400,
fontSize: 45,
color: Theme.of(context).colorScheme.onSurface,
color: Theme.of(context).colorScheme.onSurfaceVariant,
),
),
),
const SizedBox(width: 8),
CurrencySymbolText(
widget.currency,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: Theme.of(context).textTheme.displayMedium?.copyWith(
fontWeight: FontWeight.w400,
fontSize: 45,
color: Theme.of(context).colorScheme.onSurfaceVariant,
),
),
],
),
);
}
],
),
);
}
+4 -2
View File
@@ -7,11 +7,13 @@ import 'package:cake_wallet/new-ui/pages/about_page.dart';
import 'package:cake_wallet/new-ui/pages/bridge/bridge_history_page.dart';
import 'package:cake_wallet/new-ui/pages/bridge/bridge_network_page.dart';
import 'package:cake_wallet/new-ui/pages/bridge/bridge_receiving_wallet_page.dart';
import "package:cake_wallet/new-ui/pages/buy_sell/buy_sell_amount_page.dart";
import 'package:cake_wallet/new-ui/pages/coin_control_page.dart';
import 'package:cake_wallet/new-ui/pages/addresses_page.dart';
import 'package:cake_wallet/new-ui/pages/lightning_username_page.dart';
import "package:cake_wallet/new-ui/pages/receive_page.dart";
import 'package:cake_wallet/new-ui/pages/send_page.dart';
import "package:cake_wallet/new-ui/widgets/buy_sell/buy_sell_selector_modal.dart";
import 'package:cake_wallet/new-ui/widgets/hardware_wallet/sync_key_images_sheet.dart';
import 'package:cake_wallet/order/order.dart';
import 'package:cake_wallet/core/new_wallet_type_arguments.dart';
@@ -142,6 +144,7 @@ import 'package:cake_wallet/utils/payment_request.dart';
import 'package:cake_wallet/view_model/advanced_privacy_settings_view_model.dart';
import 'package:cake_wallet/view_model/bridge/bridge_view_model.dart';
import 'package:cake_wallet/view_model/bridge/bridge_history_view_model.dart';
import "package:cake_wallet/view_model/buy/buy_sell_view_model.dart";
import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
import 'package:cake_wallet/view_model/dashboard/nft_view_model.dart';
import 'package:cake_wallet/view_model/dashboard/sign_view_model.dart';
@@ -703,9 +706,8 @@ Route<dynamic> createRoute(RouteSettings settings) {
builder: (_) => getIt.get<OrderDetailsPage>(param1: settings.arguments as Order));
case Routes.buySellPage:
final args = settings.arguments as bool?;
return handleRouteWithPlatformAwareness(
(context) => getIt.get<BuySellPage>(param1: args),
(context) => Material(child: getIt.get<NewBuySellAmountPage>(param1: BuySellPageMode.buy)),
);
case Routes.buyOptionsPage:
+53 -41
View File
@@ -25,6 +25,8 @@ import 'package:mobx/mobx.dart';
part 'buy_sell_view_model.g.dart';
enum BuySellPageMode { buy, sell }
class BuySellViewModel = BuySellViewModelBase with _$BuySellViewModel;
abstract class BuySellViewModelBase extends WalletChangeListenerViewModel with Store {
@@ -89,9 +91,16 @@ abstract class BuySellViewModelBase extends WalletChangeListenerViewModel with S
return mode == BuySellPageMode.buy
? formattedFiatAmount ?? 200.0
: formattedCryptoAmount ?? (cryptoCurrency == CryptoCurrency.btc ? 0.001 : 1);
: formattedCryptoAmount ?? (cryptoCurrency == CryptoCurrency.btc ? 0.01 : 1);
}
// sets based on the absolute amout (from the fiat/charts api)
// works even if you have no rates
Future<void> setCryptoAmountFromFiat(String fiatAmount) async => changeCryptoAmount(
amount: (double.parse(fiatAmount) / (fiatConversionStore.prices[cryptoCurrency] ?? 0))
.toString(),
);
final AppStore _appStore;
AmountParsingProxy get amountParsingProxy => _appStore.amountParsingProxy;
@@ -190,18 +199,22 @@ abstract class BuySellViewModelBase extends WalletChangeListenerViewModel with S
// based on usd values, should have roughly equal worth (was done with ai though so it's subject to correction)
static final Map<FiatCurrency, List<String>> _defaultAmountsMap = {
FiatCurrency.amd: ["20000", "40000", "200000", "400000", "1000000"],
FiatCurrency.ars: ["50000", "100000", "500000", "1000000", "2500000"],
FiatCurrency.aud: ["100", "200", "1000", "2000", "5000"],
FiatCurrency.bdt: ["5000", "10000", "50000", "100000", "250000"],
FiatCurrency.bgn: ["100", "200", "1000", "2000", "5000"],
FiatCurrency.brl: ["250", "500", "2500", "5000", "12500"],
FiatCurrency.cad: ["50", "100", "500", "1000", "2500"],
FiatCurrency.chf: ["50", "100", "500", "1000", "2500"],
FiatCurrency.clp: ["50000", "100000", "500000", "1000000", "2500000"],
FiatCurrency.cny: ["500", "1000", "5000", "10000", "25000"],
FiatCurrency.cop: ["200000", "400000", "2000000", "4000000", "10000000"],
FiatCurrency.czk: ["1000", "2000", "10000", "20000", "50000"],
FiatCurrency.dkk: ["400", "800", "4000", "8000", "20000"],
FiatCurrency.egp: ["2500", "5000", "25000", "50000", "125000"],
FiatCurrency.eur: ["50", "100", "500", "1000", "2500"],
FiatCurrency.gbp: ["50", "100", "500", "1000", "2500"],
FiatCurrency.ghs: ["500", "1000", "5000", "10000", "25000"],
FiatCurrency.gtq: ["400", "800", "4000", "8000", "20000"],
FiatCurrency.hkd: ["400", "800", "4000", "8000", "20000"],
FiatCurrency.hrk: ["400", "800", "4000", "8000", "20000"],
@@ -209,8 +222,10 @@ abstract class BuySellViewModelBase extends WalletChangeListenerViewModel with S
FiatCurrency.idr: ["800000", "1600000", "8000000", "16000000", "40000000"],
FiatCurrency.ils: ["200", "400", "2000", "4000", "10000"],
FiatCurrency.inr: ["5000", "10000", "50000", "100000", "250000"],
FiatCurrency.irr: ["2000000", "4000000", "20000000", "40000000", "100000000"],
FiatCurrency.isk: ["7000", "14000", "70000", "140000", "350000"],
FiatCurrency.jpy: ["10000", "20000", "100000", "200000", "500000"],
FiatCurrency.kes: ["5000", "10000", "50000", "100000", "250000"],
FiatCurrency.krw: ["50000", "100000", "500000", "1000000", "2500000"],
FiatCurrency.mad: ["500", "1000", "5000", "10000", "25000"],
FiatCurrency.mxn: ["1000", "2000", "10000", "20000", "50000"],
@@ -222,17 +237,21 @@ abstract class BuySellViewModelBase extends WalletChangeListenerViewModel with S
FiatCurrency.pkr: ["15000", "30000", "150000", "300000", "750000"],
FiatCurrency.pln: ["200", "400", "2000", "4000", "10000"],
FiatCurrency.ron: ["250", "500", "2500", "5000", "12500"],
FiatCurrency.rub: ["5000", "10000", "50000", "100000", "250000"],
FiatCurrency.sar: ["200", "400", "2000", "4000", "10000"],
FiatCurrency.sek: ["500", "1000", "5000", "10000", "25000"],
FiatCurrency.sgd: ["50", "100", "500", "1000", "2500"],
FiatCurrency.thb: ["2000", "4000", "20000", "40000", "100000"],
FiatCurrency.tur: ["1500", "3000", "15000", "30000", "75000"],
FiatCurrency.twd: ["1500", "3000", "15000", "30000", "75000"],
FiatCurrency.uah: ["2000", "4000", "20000", "40000", "100000"],
FiatCurrency.usd: ["50", "100", "500", "1000", "2500"],
FiatCurrency.vef: ["2000", "4000", "20000", "40000", "100000"],
FiatCurrency.vnd: ["1000000", "2000000", "10000000", "20000000", "50000000"],
FiatCurrency.zar: ["1000", "2000", "10000", "20000", "50000"],
FiatCurrency.kes: ["5000", "10000", "50000", "100000", "250000"],
};
// the fallback is just the usd values.
// not great but this fallback shouldn't be triggered anyway
List<String> get defaultAmounts =>
@@ -445,50 +464,45 @@ abstract class BuySellViewModelBase extends WalletChangeListenerViewModel with S
await calculateBestRate();
}
String _getInitialCryptoCurrencyAddress() {
if (cryptoCurrency == wallet.currency) {
if ([CryptoCurrency.zec, CryptoCurrency.btc].contains(cryptoCurrency)) {
return wallet.walletAddresses.addressForBuy;
}
return wallet.walletAddresses.address;
}
return '';
}
String _getInitialCryptoCurrencyAddress() => wallet.walletAddresses.addressForBuy;
@action
Future<void> _getAvailablePaymentTypes() async {
paymentMethodState = PaymentMethodLoading();
selectedPaymentMethod = null;
final result = await Future.wait(providerList.map((element) => element
.getAvailablePaymentTypes(fiatCurrency.title, cryptoCurrency, mode == BuySellPageMode.buy)
.timeout(
Duration(seconds: 10),
onTimeout: () => [],
)));
try{
paymentMethodState = PaymentMethodLoading();
selectedPaymentMethod = null;
final result = await Future.wait(providerList.map((element) => element
.getAvailablePaymentTypes(fiatCurrency.title, cryptoCurrency, mode == BuySellPageMode.buy)
.timeout(
Duration(seconds: 10),
onTimeout: () => [],
)));
final List<PaymentMethod> tempPaymentMethods = [];
final List<PaymentMethod> tempPaymentMethods = [];
for (var methods in result) {
for (var method in methods) {
final alreadyExists = tempPaymentMethods.any((m) {
return m.paymentMethodType == method.paymentMethodType;
});
for (var methods in result) {
for (var method in methods) {
final alreadyExists = tempPaymentMethods.any((m) {
return m.paymentMethodType == method.paymentMethodType;
});
if (!alreadyExists) {
tempPaymentMethods.add(method);
if (!alreadyExists) {
tempPaymentMethods.add(method);
}
}
}
}
paymentMethods = ObservableList<PaymentMethod>.of(tempPaymentMethods);
paymentMethods = ObservableList<PaymentMethod>.of(tempPaymentMethods);
if (paymentMethods.isNotEmpty) {
paymentMethods.insert(0, PaymentMethod.all());
selectedPaymentMethod = paymentMethods.first;
selectedPaymentMethod!.isSelected = true;
paymentMethodState = PaymentMethodLoaded();
} else {
if (paymentMethods.isNotEmpty) {
paymentMethods.insert(0, PaymentMethod.all());
selectedPaymentMethod = paymentMethods.first;
selectedPaymentMethod!.isSelected = true;
paymentMethodState = PaymentMethodLoaded();
} else {
paymentMethodState = PaymentMethodFailed();
}
} catch(e) {
paymentMethodState = PaymentMethodFailed();
}
}
@@ -502,12 +516,10 @@ abstract class BuySellViewModelBase extends WalletChangeListenerViewModel with S
return provider.supportedCryptoList.any((pair) =>
pair.from.symbol == cryptoCurrency.symbol &&
pair.from.tag == cryptoCurrency.tag &&
pair.to.symbol == fiatCurrency.symbol &&
pair.to.tag == fiatCurrency.tag);
pair.to.symbol == fiatCurrency.symbol);
} else {
return provider.supportedFiatList.any((pair) =>
pair.from.symbol == fiatCurrency.symbol &&
pair.from.tag == fiatCurrency.tag &&
pair.to.symbol == cryptoCurrency.symbol &&
pair.to.tag == cryptoCurrency.tag);
}
@@ -515,7 +527,7 @@ abstract class BuySellViewModelBase extends WalletChangeListenerViewModel with S
if (validProviders.isEmpty) {
buySellQuotState = BuySellQuotFailed(
errorMessage: "Couldn't find a provider that supports ${cryptoCurrency.fullName}.");
errorMessage: S.current.no_buy_providers(cryptoCurrency.fullName??cryptoCurrency.title));
return;
}
@@ -544,7 +556,7 @@ abstract class BuySellViewModelBase extends WalletChangeListenerViewModel with S
if (validQuotes.isEmpty) {
buySellQuotState = BuySellQuotFailed(
errorMessage: "No provider could create a quote for ${cryptoCurrency.fullName}");
errorMessage: S.current.no_buy_providers(cryptoCurrency.fullName??cryptoCurrency.title));
return;
}