What changed, and why it matters
This commit is a routine UI polish update for an upcoming release. It adds small badge icons next to token logos in swap confirmation screens, fixes a missing icon for MWEB (Litecoin's privacy feature), corrects the decimal display for one Solana token, and swaps a plain image widget for a reusable token-image widget in a wallet selector. There is no change to security-sensitive code such as cryptography, key handling, transaction signing, network calls, or permissions.
No security action required; treat as normal release UI fix.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The diff is purely presentational Dart/Flutter code. It extends ListItemRegularRow and ListItemRegularRowWidget with optional badgeIconPath/badgeIconSize fields, renders a Stack-based badge overlay when provided, and wires a _resolveChainBadgePath helper into the swap confirm sheet. It also replaces Image.asset with TokenImageWidget in the L2 wallet selector and updates formatting. No logic affecting balances, addresses, signatures, secrets, or network trust is modified.
Changed components
lib/entities/new_ui_entities/list_item/list_item_regular_row.dartlib/new-ui/widgets/send_page/l2_action_wallet_selector.dartlib/new-ui/widgets/swap_page/swap_confirm_sheet.dartlib/src/widgets/new_list_row/list_item_regular_row_widget.dartlib/src/widgets/new_list_row/new_list_section.dartInspect captured patch +105 / −50
diff --git a/lib/entities/new_ui_entities/list_item/list_item_regular_row.dart b/lib/entities/new_ui_entities/list_item/list_item_regular_row.dart
index b8663212..4660199f 100644
--- a/lib/entities/new_ui_entities/list_item/list_item_regular_row.dart
+++ b/lib/entities/new_ui_entities/list_item/list_item_regular_row.dart
@@ -8,6 +8,7 @@ class ListItemRegularRow extends ListItem {
this.subtitle,
this.trailingText,
this.iconPath,
+ this.badgeIconPath,
this.onTap,
this.trailingIconPath,
this.showArrow = true,
@@ -19,6 +20,7 @@ class ListItemRegularRow extends ListItem {
this.copyableText,
this.leadingIconErrorWidget,
this.leadingIconSize,
+ this.badgeIconSize,
this.iconColor,
});
@@ -26,6 +28,7 @@ class ListItemRegularRow extends ListItem {
final String? trailingText;
final String? iconPath;
final String? trailingIconPath;
+ final String? badgeIconPath;
final String? copyableText;
final VoidCallback? onTap;
final bool showArrow;
@@ -36,5 +39,6 @@ class ListItemRegularRow extends ListItem {
final double? trailingIconSize;
final Widget? leadingIconErrorWidget;
final double? leadingIconSize;
+ final double? badgeIconSize;
final Color? iconColor;
}
diff --git a/lib/new-ui/widgets/send_page/l2_action_wallet_selector.dart b/lib/new-ui/widgets/send_page/l2_action_wallet_selector.dart
index 6a9aa35c..94e8c190 100644
--- a/lib/new-ui/widgets/send_page/l2_action_wallet_selector.dart
+++ b/lib/new-ui/widgets/send_page/l2_action_wallet_selector.dart
@@ -3,6 +3,7 @@ import 'dart:async';
import 'package:cake_wallet/bitcoin/bitcoin.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/main.dart';
+import 'package:cake_wallet/new-ui/widgets/coins_page/token_image_widget.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/send_page/l2_send_external_modal.dart';
@@ -56,8 +57,8 @@ class _L2ActionWalletSelectorState extends State<L2ActionWalletSelector> {
super.initState();
if (widget.showOtherWallets) {
() async {
- items.addAll((await WalletInfo.getAll())
- .where((item) => item.type == widget.sendViewModel.walletType && item.hardwareWalletType == null));
+ items.addAll((await WalletInfo.getAll()).where((item) =>
+ item.type == widget.sendViewModel.walletType && item.hardwareWalletType == null));
items.sort((a, b) {
if (a.name == widget.sendViewModel.wallet.name)
return -1;
@@ -125,8 +126,7 @@ class _L2ActionWalletSelectorState extends State<L2ActionWalletSelector> {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 4.0),
child: WalletRow(
- currencyIconPath:
- getCryptoCurrencyIconForWalletListItem(item.type),
+ currencyIconPath: getCryptoCurrencyIconForWalletListItem(item.type),
walletName: item.name,
isCurrent: item.name == widget.sendViewModel.wallet.name,
isSelected: _selectedWalletIndex == index && !textEntered,
@@ -252,8 +252,8 @@ class _L2ActionWalletSelectorState extends State<L2ActionWalletSelector> {
mainAxisAlignment: MainAxisAlignment.center,
spacing: 10,
children: [
- CakeImageWidget(imageUrl:
- "assets/new-ui/send_from_external.svg",
+ CakeImageWidget(
+ imageUrl: "assets/new-ui/send_from_external.svg",
colorFilter: ColorFilter.mode(
Theme.of(context).colorScheme.primary, BlendMode.srcIn),
),
@@ -378,10 +378,9 @@ class WalletRow extends StatelessWidget {
Row(
spacing: 12,
children: [
- Image.asset(
- currencyIconPath,
- height: 24,
- width: 24,
+ TokenImageWidget(
+ imageUrl: currencyIconPath,
+ size: 24,
),
Column(
mainAxisAlignment: MainAxisAlignment.center,
diff --git a/lib/new-ui/widgets/swap_page/swap_confirm_sheet.dart b/lib/new-ui/widgets/swap_page/swap_confirm_sheet.dart
index 3676cd6e..ede917ce 100644
--- a/lib/new-ui/widgets/swap_page/swap_confirm_sheet.dart
+++ b/lib/new-ui/widgets/swap_page/swap_confirm_sheet.dart
@@ -14,7 +14,10 @@ import 'package:cake_wallet/src/widgets/new_list_row/new_list_section.dart';
import 'package:cake_wallet/view_model/exchange/exchange_trade_view_model.dart';
import 'package:cake_wallet/view_model/exchange/exchange_view_model.dart';
import 'package:cake_wallet/view_model/send/send_view_model_state.dart';
+import 'package:cw_core/crypto_currency.dart';
import 'package:cw_core/currencies_with_memo.dart';
+import 'package:cw_core/currency_for_wallet_type.dart';
+import 'package:cw_core/wallet_type.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
@@ -160,6 +163,7 @@ class SwapTransactionDetails extends StatelessWidget {
keyValue: "send value",
label: exchangeViewModel.depositCurrency.fullName ?? "",
iconPath: exchangeViewModel.depositCurrency.iconPath ?? "",
+ badgeIconPath: _resolveChainBadgePath(exchangeViewModel.depositCurrency),
trailingText: exchangeTradeViewModel.trade.amountFormatted() +
" " +
(exchangeViewModel.depositCurrency.title)),
@@ -184,6 +188,7 @@ class SwapTransactionDetails extends StatelessWidget {
keyValue: "receive value",
label: exchangeViewModel.receiveCurrency.fullName ?? "",
iconPath: exchangeViewModel.receiveCurrency.iconPath ?? "",
+ badgeIconPath: _resolveChainBadgePath(exchangeViewModel.receiveCurrency),
trailingText:
(receiveAmount) + " " + (exchangeViewModel.receiveCurrency.title)),
ListItemRegularRow(
@@ -272,3 +277,21 @@ class SwapTransactionDetails extends StatelessWidget {
}
}
}
+
+String? _resolveChainBadgePath(CryptoCurrency currency) {
+ try {
+ if (currency.chainIconPath != null) return currency.chainIconPath;
+
+ final tag = currency.tag;
+ if (tag != null && tag.isNotEmpty) {
+ final byTag = CryptoCurrency.fromString(tag);
+ if (byTag.chainIconPath != null) return byTag.chainIconPath;
+ }
+
+ final walletType = cryptoCurrencyOrTokenToWalletType(currency);
+ if (walletType != null) {
+ return walletTypeToCryptoCurrency(walletType).chainIconPath;
+ }
+ } catch (_) {}
+ return null;
+}
diff --git a/lib/src/widgets/new_list_row/list_item_regular_row_widget.dart b/lib/src/widgets/new_list_row/list_item_regular_row_widget.dart
index 962cb87d..b2301b88 100644
--- a/lib/src/widgets/new_list_row/list_item_regular_row_widget.dart
+++ b/lib/src/widgets/new_list_row/list_item_regular_row_widget.dart
@@ -6,34 +6,36 @@ import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
class ListItemRegularRowWidget extends StatelessWidget {
- const ListItemRegularRowWidget({
- super.key,
- required this.keyValue,
- required this.label,
- this.subtitle,
- this.trailingText,
- this.iconPath,
- this.onTap,
- this.isFirstInSection = false,
- this.isLastInSection = false,
- this.showArrow = true,
- this.trailingIconPath,
- this.truncateTrailingText = false,
- this.foregroundColor,
- this.trailingIconSize,
- this.bottomWidget,
- this.trailingWidget,
- this.copyableText,
- this.leadingIconErrorWidget,
- this.leadingIconSize,
- this.iconColor
- });
+ const ListItemRegularRowWidget(
+ {super.key,
+ required this.keyValue,
+ required this.label,
+ this.subtitle,
+ this.trailingText,
+ this.iconPath,
+ this.badgeIconPath,
+ this.onTap,
+ this.isFirstInSection = false,
+ this.isLastInSection = false,
+ this.showArrow = true,
+ this.trailingIconPath,
+ this.truncateTrailingText = false,
+ this.foregroundColor,
+ this.trailingIconSize,
+ this.bottomWidget,
+ this.trailingWidget,
+ this.copyableText,
+ this.leadingIconErrorWidget,
+ this.leadingIconSize,
+ this.badgeIconSize,
+ this.iconColor});
final String keyValue;
final String label;
final String? subtitle;
final String? trailingText;
final String? iconPath;
+ final String? badgeIconPath;
final VoidCallback? onTap;
final bool isFirstInSection;
final bool isLastInSection;
@@ -47,6 +49,7 @@ class ListItemRegularRowWidget extends StatelessWidget {
final String? copyableText;
final Widget? leadingIconErrorWidget;
final double? leadingIconSize;
+ final double? badgeIconSize;
final Color? iconColor;
@override
@@ -69,6 +72,38 @@ class ListItemRegularRowWidget extends StatelessWidget {
isFirstInSection: isFirstInSection,
isLastInSection: isLastInSection,
builder: (context, textStyle, labelStyle) {
+ final leadingIcon = iconPath != null
+ ? CakeImageWidget(
+ imageUrl: iconPath!,
+ width: leadingIconSize ?? 24,
+ height: leadingIconSize ?? 24,
+ errorWidget: leadingIconErrorWidget,
+ colorFilter:
+ iconColor == null ? null : ColorFilter.mode(iconColor!, BlendMode.srcIn),
+ )
+ : null;
+
+ final imageWidget = badgeIconPath != null
+ ? Stack(
+ clipBehavior: Clip.none,
+ children: [
+ leadingIcon!,
+ Positioned(
+ right: -3,
+ bottom: -3,
+ child: CakeImageWidget(
+ imageUrl: badgeIconPath!,
+ width: badgeIconSize ?? 10,
+ height: badgeIconSize ?? 10,
+ errorWidget: leadingIconErrorWidget,
+ colorFilter: iconColor == null
+ ? null
+ : ColorFilter.mode(iconColor!, BlendMode.srcIn),
+ ),
+ ),
+ ],
+ )
+ : leadingIcon;
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
@@ -81,16 +116,9 @@ class ListItemRegularRowWidget extends StatelessWidget {
children: [
if (iconPath != null)
Padding(
- padding: const EdgeInsets.only(right: 12.0),
- child: CakeImageWidget(
- imageUrl: iconPath!,
- width: leadingIconSize ?? 24,
- height: leadingIconSize ?? 24,
- errorWidget: leadingIconErrorWidget,
- colorFilter: iconColor == null
- ? null
- : ColorFilter.mode(iconColor!, BlendMode.srcIn),
- )),
+ padding: const EdgeInsets.only(right: 12.0),
+ child: imageWidget ?? SizedBox(),
+ ),
Flexible(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
@@ -140,14 +168,13 @@ class ListItemRegularRowWidget extends StatelessWidget {
BlendMode.srcIn),
)
else if (showArrow)
- Padding(
- padding: const EdgeInsets.symmetric(vertical: 7.0),
- child: CakeImageWidget(imageUrl:
- "assets/new-ui/arrow_forward.svg",
- height: 14,
- color: theme.colorScheme.onSurfaceVariant
- ),
- )
+ Padding(
+ padding: const EdgeInsets.symmetric(vertical: 7.0),
+ child: CakeImageWidget(
+ imageUrl: "assets/new-ui/arrow_forward.svg",
+ height: 14,
+ color: theme.colorScheme.onSurfaceVariant),
+ )
],
),
],
diff --git a/lib/src/widgets/new_list_row/new_list_section.dart b/lib/src/widgets/new_list_row/new_list_section.dart
index edc0b4eb..8abef379 100644
--- a/lib/src/widgets/new_list_row/new_list_section.dart
+++ b/lib/src/widgets/new_list_row/new_list_section.dart
@@ -96,6 +96,7 @@ class NewListSections extends StatelessWidget {
subtitle: item.subtitle,
trailingText: item.trailingText,
iconPath: item.iconPath,
+ badgeIconPath: item.badgeIconPath,
trailingIconPath: item.trailingIconPath,
onTap: tapHandlers[item.keyValue] ?? item.onTap,
isFirstInSection: isFirst,
@@ -109,6 +110,7 @@ class NewListSections extends StatelessWidget {
bottomWidget: item.bottomWidget,
leadingIconErrorWidget: item.leadingIconErrorWidget,
leadingIconSize: item.leadingIconSize,
+ badgeIconSize: item.badgeIconSize,
iconColor: item.iconColor,
);
}
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.