add new currency selection
What changed, and why it matters
This commit is a routine user-interface update for Cake Wallet's buy/sell flow. It adds a new fiat-currency picker and a small widget that shows a token icon with its chain/network badge. There is nothing in the changes that suggests a security vulnerability or fix.
No security action required; treat as normal feature/UI code review.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The diff modifies two Dart files. buy_sell_amount_page.dart imports a new FiatCurrencyPickerSheet and TokenChainDisplay, wires a selectFiatCurrency callback, and restyles the currency picker pills to show both crypto and fiat selections. token_chain_display.dart is a new StatelessWidget that renders a CryptoCurrency icon with an optional chain icon overlay. No security-sensitive logic (key handling, network calls, validation, permissions) is changed.
Changed components
lib/new-ui/pages/buy_sell/buy_sell_amount_page.dartlib/new-ui/widgets/token_chain_display.dartInspect captured patch +145 / −60
diff --git a/lib/new-ui/pages/buy_sell/buy_sell_amount_page.dart b/lib/new-ui/pages/buy_sell/buy_sell_amount_page.dart
index bf04c5ab..dea7ce63 100644
--- a/lib/new-ui/pages/buy_sell/buy_sell_amount_page.dart
+++ b/lib/new-ui/pages/buy_sell/buy_sell_amount_page.dart
@@ -8,9 +8,11 @@ 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";
import "package:cake_wallet/new-ui/widgets/floating_amount_input.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/new-ui/widgets/token_chain_display.dart";
import "package:cake_wallet/src/widgets/alert_with_one_action.dart";
import "package:cake_wallet/src/widgets/cake_image_widget.dart";
import "package:cake_wallet/themes/core/theme_extension.dart";
@@ -18,6 +20,7 @@ import "package:cake_wallet/utils/show_pop_up.dart";
import "package:cake_wallet/view_model/buy/buy_sell_view_model.dart";
import "package:cw_core/amount/money.dart";
import "package:cw_core/crypto_currency.dart";
+import "package:cw_core/currency.dart";
import "package:flutter/cupertino.dart";
import "package:flutter/material.dart";
import "package:flutter_mobx/flutter_mobx.dart";
@@ -107,7 +110,8 @@ class _NewBuySellAmountPageState extends State<NewBuySellAmountPage> {
currentAmount: widget.buySellViewModel.fiatAmount,
hasCurrencySelector: widget.buySellViewModel.hasMultipleCurrencies,
onCurrencySelectorPressed: () => selectCryptoCurrency(context),
- cryptoCurrency: widget.buySellViewModel.cryptoCurrency,
+ onFiatSelectorPressed: () => selectFiatCurrency(context),
+ cryptoCurrency: widget.buySellViewModel.cryptoCurrency,
isLoading: _isLoadingPaymentMethods,
mode: widget.buySellViewModel.mode,
onSelected: (amount) async {
@@ -141,6 +145,11 @@ class _NewBuySellAmountPageState extends State<NewBuySellAmountPage> {
symbolResolver: widget.buySellViewModel.amountParsingProxy.getCryptoSymbol,
),);
+ void selectFiatCurrency(BuildContext context) => FiatCurrencyPickerSheet.show(
+ context: context,
+ selected: widget.buySellViewModel.fiatCurrency,
+ onSelected: (item) => widget.buySellViewModel.changeFiatCurrency(currency: item));
+
String get _pageTitle => widget.buySellViewModel.mode == BuySellPageMode.buy
? S.current.buy
: S.current.sell +
@@ -230,10 +239,6 @@ class BuySellCustomAmountInput extends StatelessWidget {
Column(
spacing: 8,
children: [
- if (hasCurrencySelector) ...[
- BuySellCurrencyPickerPill(curr: cryptoCurrency, onTap: onCurrencySelectorPressed),
- const SizedBox.shrink(),
- ],
FloatingAmountInput(
currency: fiatCurrency,
focusNode: focusNode,
@@ -268,7 +273,7 @@ class BuySellCustomAmountInput extends StatelessWidget {
class BuySellDefaultAmountSelector extends StatelessWidget {
const BuySellDefaultAmountSelector(
- {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,
+ {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;
@@ -276,27 +281,31 @@ class BuySellDefaultAmountSelector extends StatelessWidget {
final bool isLoading;
final bool hasCurrencySelector;
final VoidCallback onCurrencySelectorPressed;
+ final VoidCallback onFiatSelectorPressed;
final CryptoCurrency cryptoCurrency;
final FiatCurrency fiatCurrency;
final BuySellPageMode mode;
final Function(String?) onSelected;
@override
- Widget build(BuildContext context) => Column(
- spacing: 24,
- mainAxisAlignment: MainAxisAlignment.center,
- children: [
- if (hasCurrencySelector)
- BuySellCurrencyPickerPill(curr: cryptoCurrency, onTap: onCurrencySelectorPressed),
- 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),
- ),
- Padding(
- padding: const EdgeInsets.symmetric(horizontal: 18),
- child: GridView.builder(
+ 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).sell : S.of(context).buy,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
@@ -312,9 +321,9 @@ class BuySellDefaultAmountSelector extends StatelessWidget {
onTap: () => onSelected(item),
);
},),
- ),
- ],
- );
+ ],
+ ),
+ );
}
class BuySellAmountPill extends StatelessWidget {
@@ -386,47 +395,73 @@ class BuySellAmountPill extends StatelessWidget {
}
class BuySellCurrencyPickerPill extends StatelessWidget {
- const BuySellCurrencyPickerPill({required this.curr, required this.onTap, super.key});
+ const BuySellCurrencyPickerPill({required this.title, required this.curr, required this.onTap, super.key});
- final CryptoCurrency curr;
+ final String title;
+ final Currency curr;
final VoidCallback onTap;
@override
- Widget build(BuildContext context) => GestureDetector(
- onTap: onTap,
- child: Container(
- decoration: BoxDecoration(
- color: Theme.of(context).colorScheme.surfaceContainerHigh,
- borderRadius: BorderRadius.circular(999999999),
- ),
- child: Padding(
- padding: const EdgeInsets.only(top: 5, bottom: 5, left: 5, right: 10),
- child: Row(
- mainAxisSize: MainAxisSize.min,
- spacing: 10,
- children: [
- CakeImageWidget(
- imageUrl: curr.iconPath,
- width: 30,
- height: 30,
- ),
- Text(
- curr.fullName ?? curr.title,
- style: const TextStyle(fontSize: 16),
- ),
- 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),
- ),
+ 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,
+ children: [
+ Text(
+ curr.fullName ?? curr.symbol,
+ ),
+ Text(
+ curr.symbol,
+ 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),
+ ),
+ ),
+ ],
),
- ],
+ ),
),
),
- ),
- );
+ ],
+ );
}
diff --git a/lib/new-ui/widgets/token_chain_display.dart b/lib/new-ui/widgets/token_chain_display.dart
new file mode 100644
index 00000000..5755e018
--- /dev/null
+++ b/lib/new-ui/widgets/token_chain_display.dart
@@ -0,0 +1,50 @@
+import "package:cake_wallet/src/widgets/cake_image_widget.dart";
+import "package:cw_core/crypto_currency.dart";
+import "package:flutter/material.dart";
+
+class TokenChainDisplay extends StatelessWidget {
+ const TokenChainDisplay({required this.size, required this.asset, super.key});
+
+ final CryptoCurrency asset;
+ final double size;
+
+ static const double _chainIconSizeFactor = 0.35;
+
+ double get _chainIconSize => size * _chainIconSizeFactor;
+
+ @override
+ Widget build(BuildContext context) => SizedBox(
+ width: size,
+ height: size,
+ child: Stack(
+ children: [
+ CakeImageWidget(
+ imageUrl: asset.iconPath ?? "",
+ width: size,
+ ),
+ if ((asset.chainIconPath ?? "").isNotEmpty)
+ Align(
+ alignment: Alignment.bottomRight,
+ child: Container(
+ decoration: ShapeDecoration(
+ shape: RoundedSuperellipseBorder(
+ borderRadius: BorderRadius.circular(5),
+ side: const BorderSide(color: Colors.black),
+ ),
+ color: Colors.white,
+ ),
+ child: Padding(
+ padding: const EdgeInsets.all(2),
+ child: CakeImageWidget(
+ imageUrl: asset.chainIconPath,
+ width: _chainIconSize,
+ height: _chainIconSize,
+ colorFilter: const ColorFilter.mode(Colors.black, BlendMode.srcIn),
+ ),
+ ),
+ ),
+ ),
+ ],
+ ),
+ );
+}
Why this scored 15/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.