Release fixes (#3301)

* fix: Solana GMT token showing the wrong decimal place * add badge icon to swap confirm sheet, also address book chain icons display correctly * missing mask icon for mweb

David Adegoke committed Jun 6, 2026 at 13:34 UTC 7c321faf2fd5b21c86b5813c0aee73e3a88093b8
5 files changed +105 -50
lib/entities/new_ui_entities/list_item/list_item_regular_row.dart
+4
@@ -8,6 +8,7 @@ class ListItemRegularRow extends ListItem {
8 this.subtitle,
9 this.trailingText,
10 this.iconPath,
11 + this.badgeIconPath,
12 this.onTap,
13 this.trailingIconPath,
14 this.showArrow = true,
@@ -19,6 +20,7 @@ class ListItemRegularRow extends ListItem {
20 this.copyableText,
21 this.leadingIconErrorWidget,
22 this.leadingIconSize,
23 + this.badgeIconSize,
24 this.iconColor,
25 });
26
@@ -26,6 +28,7 @@ class ListItemRegularRow extends ListItem {
28 final String? trailingText;
29 final String? iconPath;
30 final String? trailingIconPath;
31 + final String? badgeIconPath;
32 final String? copyableText;
33 final VoidCallback? onTap;
34 final bool showArrow;
@@ -36,5 +39,6 @@ class ListItemRegularRow extends ListItem {
39 final double? trailingIconSize;
40 final Widget? leadingIconErrorWidget;
41 final double? leadingIconSize;
42 + final double? badgeIconSize;
43 final Color? iconColor;
44 }
lib/new-ui/widgets/send_page/l2_action_wallet_selector.dart
+9 -10
@@ -3,6 +3,7 @@ import 'dart:async';
3 import 'package:cake_wallet/bitcoin/bitcoin.dart';
4 import 'package:cake_wallet/generated/i18n.dart';
5 import 'package:cake_wallet/main.dart';
6 +import 'package:cake_wallet/new-ui/widgets/coins_page/token_image_widget.dart';
7 import 'package:cake_wallet/new-ui/widgets/new_primary_button.dart';
8 import 'package:cake_wallet/new-ui/widgets/receive_page/receive_top_bar.dart';
9 import 'package:cake_wallet/new-ui/widgets/send_page/l2_send_external_modal.dart';
@@ -56,8 +57,8 @@ class _L2ActionWalletSelectorState extends State<L2ActionWalletSelector> {
57 super.initState();
58 if (widget.showOtherWallets) {
59 () async {
59 - items.addAll((await WalletInfo.getAll())
60 - .where((item) => item.type == widget.sendViewModel.walletType && item.hardwareWalletType == null));
60 + items.addAll((await WalletInfo.getAll()).where((item) =>
61 + item.type == widget.sendViewModel.walletType && item.hardwareWalletType == null));
62 items.sort((a, b) {
63 if (a.name == widget.sendViewModel.wallet.name)
64 return -1;
@@ -125,8 +126,7 @@ class _L2ActionWalletSelectorState extends State<L2ActionWalletSelector> {
126 return Padding(
127 padding: const EdgeInsets.symmetric(vertical: 4.0),
128 child: WalletRow(
128 - currencyIconPath:
129 - getCryptoCurrencyIconForWalletListItem(item.type),
129 + currencyIconPath: getCryptoCurrencyIconForWalletListItem(item.type),
130 walletName: item.name,
131 isCurrent: item.name == widget.sendViewModel.wallet.name,
132 isSelected: _selectedWalletIndex == index && !textEntered,
@@ -252,8 +252,8 @@ class _L2ActionWalletSelectorState extends State<L2ActionWalletSelector> {
252 mainAxisAlignment: MainAxisAlignment.center,
253 spacing: 10,
254 children: [
255 - CakeImageWidget(imageUrl:
256 - "assets/new-ui/send_from_external.svg",
255 + CakeImageWidget(
256 + imageUrl: "assets/new-ui/send_from_external.svg",
257 colorFilter: ColorFilter.mode(
258 Theme.of(context).colorScheme.primary, BlendMode.srcIn),
259 ),
@@ -378,10 +378,9 @@ class WalletRow extends StatelessWidget {
378 Row(
379 spacing: 12,
380 children: [
381 - Image.asset(
382 - currencyIconPath,
383 - height: 24,
384 - width: 24,
381 + TokenImageWidget(
382 + imageUrl: currencyIconPath,
383 + size: 24,
384 ),
385 Column(
386 mainAxisAlignment: MainAxisAlignment.center,
lib/new-ui/widgets/swap_page/swap_confirm_sheet.dart
+23
@@ -14,7 +14,10 @@ import 'package:cake_wallet/src/widgets/new_list_row/new_list_section.dart';
14 import 'package:cake_wallet/view_model/exchange/exchange_trade_view_model.dart';
15 import 'package:cake_wallet/view_model/exchange/exchange_view_model.dart';
16 import 'package:cake_wallet/view_model/send/send_view_model_state.dart';
17 +import 'package:cw_core/crypto_currency.dart';
18 import 'package:cw_core/currencies_with_memo.dart';
19 +import 'package:cw_core/currency_for_wallet_type.dart';
20 +import 'package:cw_core/wallet_type.dart';
21 import 'package:flutter/material.dart';
22 import 'package:flutter/services.dart';
23 import 'package:flutter_mobx/flutter_mobx.dart';
@@ -160,6 +163,7 @@ class SwapTransactionDetails extends StatelessWidget {
163 keyValue: "send value",
164 label: exchangeViewModel.depositCurrency.fullName ?? "",
165 iconPath: exchangeViewModel.depositCurrency.iconPath ?? "",
166 + badgeIconPath: _resolveChainBadgePath(exchangeViewModel.depositCurrency),
167 trailingText: exchangeTradeViewModel.trade.amountFormatted() +
168 " " +
169 (exchangeViewModel.depositCurrency.title)),
@@ -184,6 +188,7 @@ class SwapTransactionDetails extends StatelessWidget {
188 keyValue: "receive value",
189 label: exchangeViewModel.receiveCurrency.fullName ?? "",
190 iconPath: exchangeViewModel.receiveCurrency.iconPath ?? "",
191 + badgeIconPath: _resolveChainBadgePath(exchangeViewModel.receiveCurrency),
192 trailingText:
193 (receiveAmount) + " " + (exchangeViewModel.receiveCurrency.title)),
194 ListItemRegularRow(
@@ -272,3 +277,21 @@ class SwapTransactionDetails extends StatelessWidget {
277 }
278 }
279 }
280 +
281 +String? _resolveChainBadgePath(CryptoCurrency currency) {
282 + try {
283 + if (currency.chainIconPath != null) return currency.chainIconPath;
284 +
285 + final tag = currency.tag;
286 + if (tag != null && tag.isNotEmpty) {
287 + final byTag = CryptoCurrency.fromString(tag);
288 + if (byTag.chainIconPath != null) return byTag.chainIconPath;
289 + }
290 +
291 + final walletType = cryptoCurrencyOrTokenToWalletType(currency);
292 + if (walletType != null) {
293 + return walletTypeToCryptoCurrency(walletType).chainIconPath;
294 + }
295 + } catch (_) {}
296 + return null;
297 +}
lib/src/widgets/new_list_row/list_item_regular_row_widget.dart
+67 -40
@@ -6,34 +6,36 @@ import 'package:flutter/material.dart';
6 import 'package:flutter/services.dart';
7
8 class ListItemRegularRowWidget extends StatelessWidget {
9 - const ListItemRegularRowWidget({
10 - super.key,
11 - required this.keyValue,
12 - required this.label,
13 - this.subtitle,
14 - this.trailingText,
15 - this.iconPath,
16 - this.onTap,
17 - this.isFirstInSection = false,
18 - this.isLastInSection = false,
19 - this.showArrow = true,
20 - this.trailingIconPath,
21 - this.truncateTrailingText = false,
22 - this.foregroundColor,
23 - this.trailingIconSize,
24 - this.bottomWidget,
25 - this.trailingWidget,
26 - this.copyableText,
27 - this.leadingIconErrorWidget,
28 - this.leadingIconSize,
29 - this.iconColor
30 - });
9 + const ListItemRegularRowWidget(
10 + {super.key,
11 + required this.keyValue,
12 + required this.label,
13 + this.subtitle,
14 + this.trailingText,
15 + this.iconPath,
16 + this.badgeIconPath,
17 + this.onTap,
18 + this.isFirstInSection = false,
19 + this.isLastInSection = false,
20 + this.showArrow = true,
21 + this.trailingIconPath,
22 + this.truncateTrailingText = false,
23 + this.foregroundColor,
24 + this.trailingIconSize,
25 + this.bottomWidget,
26 + this.trailingWidget,
27 + this.copyableText,
28 + this.leadingIconErrorWidget,
29 + this.leadingIconSize,
30 + this.badgeIconSize,
31 + this.iconColor});
32
33 final String keyValue;
34 final String label;
35 final String? subtitle;
36 final String? trailingText;
37 final String? iconPath;
38 + final String? badgeIconPath;
39 final VoidCallback? onTap;
40 final bool isFirstInSection;
41 final bool isLastInSection;
@@ -47,6 +49,7 @@ class ListItemRegularRowWidget extends StatelessWidget {
49 final String? copyableText;
50 final Widget? leadingIconErrorWidget;
51 final double? leadingIconSize;
52 + final double? badgeIconSize;
53 final Color? iconColor;
54
55 @override
@@ -69,6 +72,38 @@ class ListItemRegularRowWidget extends StatelessWidget {
72 isFirstInSection: isFirstInSection,
73 isLastInSection: isLastInSection,
74 builder: (context, textStyle, labelStyle) {
75 + final leadingIcon = iconPath != null
76 + ? CakeImageWidget(
77 + imageUrl: iconPath!,
78 + width: leadingIconSize ?? 24,
79 + height: leadingIconSize ?? 24,
80 + errorWidget: leadingIconErrorWidget,
81 + colorFilter:
82 + iconColor == null ? null : ColorFilter.mode(iconColor!, BlendMode.srcIn),
83 + )
84 + : null;
85 +
86 + final imageWidget = badgeIconPath != null
87 + ? Stack(
88 + clipBehavior: Clip.none,
89 + children: [
90 + leadingIcon!,
91 + Positioned(
92 + right: -3,
93 + bottom: -3,
94 + child: CakeImageWidget(
95 + imageUrl: badgeIconPath!,
96 + width: badgeIconSize ?? 10,
97 + height: badgeIconSize ?? 10,
98 + errorWidget: leadingIconErrorWidget,
99 + colorFilter: iconColor == null
100 + ? null
101 + : ColorFilter.mode(iconColor!, BlendMode.srcIn),
102 + ),
103 + ),
104 + ],
105 + )
106 + : leadingIcon;
107 return Column(
108 crossAxisAlignment: CrossAxisAlignment.start,
109 mainAxisAlignment: MainAxisAlignment.center,
@@ -81,16 +116,9 @@ class ListItemRegularRowWidget extends StatelessWidget {
116 children: [
117 if (iconPath != null)
118 Padding(
84 - padding: const EdgeInsets.only(right: 12.0),
85 - child: CakeImageWidget(
86 - imageUrl: iconPath!,
87 - width: leadingIconSize ?? 24,
88 - height: leadingIconSize ?? 24,
89 - errorWidget: leadingIconErrorWidget,
90 - colorFilter: iconColor == null
91 - ? null
92 - : ColorFilter.mode(iconColor!, BlendMode.srcIn),
93 - )),
119 + padding: const EdgeInsets.only(right: 12.0),
120 + child: imageWidget ?? SizedBox(),
121 + ),
122 Flexible(
123 child: Column(
124 mainAxisAlignment: MainAxisAlignment.center,
@@ -140,14 +168,13 @@ class ListItemRegularRowWidget extends StatelessWidget {
168 BlendMode.srcIn),
169 )
170 else if (showArrow)
143 - Padding(
144 - padding: const EdgeInsets.symmetric(vertical: 7.0),
145 - child: CakeImageWidget(imageUrl:
146 - "assets/new-ui/arrow_forward.svg",
147 - height: 14,
148 - color: theme.colorScheme.onSurfaceVariant
149 - ),
150 - )
171 + Padding(
172 + padding: const EdgeInsets.symmetric(vertical: 7.0),
173 + child: CakeImageWidget(
174 + imageUrl: "assets/new-ui/arrow_forward.svg",
175 + height: 14,
176 + color: theme.colorScheme.onSurfaceVariant),
177 + )
178 ],
179 ),
180 ],
lib/src/widgets/new_list_row/new_list_section.dart
+2
@@ -96,6 +96,7 @@ class NewListSections extends StatelessWidget {
96 subtitle: item.subtitle,
97 trailingText: item.trailingText,
98 iconPath: item.iconPath,
99 + badgeIconPath: item.badgeIconPath,
100 trailingIconPath: item.trailingIconPath,
101 onTap: tapHandlers[item.keyValue] ?? item.onTap,
102 isFirstInSection: isFirst,
@@ -109,6 +110,7 @@ class NewListSections extends StatelessWidget {
110 bottomWidget: item.bottomWidget,
111 leadingIconErrorWidget: item.leadingIconErrorWidget,
112 leadingIconSize: item.leadingIconSize,
113 + badgeIconSize: item.badgeIconSize,
114 iconColor: item.iconColor,
115 );
116 }