show token row in receive infobox (#3211)

* show token row in receive infobox * fix showing currencies w/o image

malik1004x committed May 6, 2026 at 21:48 UTC cfb5da012eedbaaa4aa11a9f96b4be7fd4407498
2 files changed +114 -16
lib/new-ui/pages/receive_page.dart
+4 -2
@@ -165,8 +165,10 @@ class _NewReceivePageState extends State<NewReceivePage> {
165 final hasLabel = _addressItemWithLabel?.name != null && _addressItemWithLabel!.name!.isNotEmpty;
166 final infoboxDismissed = widget.addressListViewModel.wallet.walletInfo.receiveInfoboxDismissed;
167 final infobox = ReceiveInfoBox.forWalletType(widget.addressListViewModel.type,
168 - onDismissed: () {
169 - widget.addressListViewModel.dismissInfobox();
168 + supportedCurrencies: widget.addressListViewModel.tokenCurrencies
169 + .whereType<CryptoCurrency>()
170 + .toList(), onDismissed: () {
171 + widget.addressListViewModel.dismissInfobox();
172 setState(() {});
173 }, autoGenerateSubaddressStatus: widget.lightningMode ? AutoGenerateSubaddressStatus.disabled : widget.dashboardViewModel.settingsStore.autoGenerateSubaddressStatus);
174
lib/new-ui/widgets/receive_page/receive_info_box.dart
+110 -14
@@ -1,15 +1,17 @@
1 +import 'dart:math';
2 +
3 import 'package:cake_wallet/entities/auto_generate_subaddress_status.dart';
4 import 'package:cake_wallet/generated/i18n.dart';
5 import 'package:cake_wallet/src/widgets/cake_image_widget.dart';
6 +import 'package:cw_core/crypto_currency.dart';
7 import 'package:cw_core/wallet_type.dart';
8 import 'package:flutter/material.dart';
6 -import 'package:flutter_svg/svg.dart';
9
10 class ReceiveInfoBox extends StatelessWidget {
11 ReceiveInfoBox(
10 - {super.key, required this.iconPath, required this.message, required this.onDismissed});
12 + {super.key, required this.iconPath, required this.message, required this.onDismissed, this.bottomWidget});
13
12 - static ReceiveInfoBox? forWalletType(WalletType type, {required VoidCallback onDismissed, required AutoGenerateSubaddressStatus autoGenerateSubaddressStatus}) {
14 + static ReceiveInfoBox? forWalletType(WalletType type, {required VoidCallback onDismissed, required AutoGenerateSubaddressStatus autoGenerateSubaddressStatus, List<CryptoCurrency>? supportedCurrencies}) {
15 switch (type) {
16 case WalletType.nano:
17 return null;
@@ -24,11 +26,15 @@ class ReceiveInfoBox extends StatelessWidget {
26 if(autoGenerateSubaddressStatus == AutoGenerateSubaddressStatus.disabled)
27 return null;
28 return ReceiveInfoBox(
27 - iconPath: "assets/new-ui/chain_badges/${walletTypeToString(type).toLowerCase()}.svg",
29 + iconPath: "",
30 message:
31 "${S.current.infobox_multichain} ${walletTypeToString(type)}",
32 onDismissed: onDismissed,
31 - );
33 + bottomWidget: InfoboxCurrencyRow(
34 + currencies: supportedCurrencies ?? [],
35 + chainIconPath:
36 + "assets/new-ui/chain_badges/${walletTypeToString(type).toLowerCase()}.svg",
37 + ));
38 default:
39 if(autoGenerateSubaddressStatus == AutoGenerateSubaddressStatus.disabled)
40 return null;
@@ -42,6 +48,7 @@ class ReceiveInfoBox extends StatelessWidget {
48
49 late final String iconPath;
50 late final String message;
51 + final Widget? bottomWidget;
52 final VoidCallback onDismissed;
53
54 @override
@@ -58,6 +65,7 @@ class ReceiveInfoBox extends StatelessWidget {
65 crossAxisAlignment: CrossAxisAlignment.start,
66 spacing: 10,
67 children: [
68 + if(iconPath.isNotEmpty)
69 CakeImageWidget(imageUrl:
70 iconPath,
71 width: 16,
@@ -79,15 +87,21 @@ class ReceiveInfoBox extends StatelessWidget {
87 fontSize: 12,
88 fontWeight: FontWeight.w300),
89 ),
82 - GestureDetector(
83 - onTap: onDismissed,
84 - child: Text(
85 - S.of(context).dismiss,
86 - style: TextStyle(
87 - color: Theme.of(context).colorScheme.primary,
88 - fontSize: 12,
89 - fontWeight: FontWeight.w300),
90 - ))
90 + Row(
91 + mainAxisAlignment: MainAxisAlignment.spaceBetween,
92 + children: [
93 + if (bottomWidget != null) bottomWidget!,
94 + GestureDetector(
95 + onTap: onDismissed,
96 + child: Text(
97 + S.of(context).dismiss,
98 + style: TextStyle(
99 + color: Theme.of(context).colorScheme.primary,
100 + fontSize: 12,
101 + fontWeight: FontWeight.w300),
102 + )),
103 + ],
104 + )
105 ]),
106 )
107 ],
@@ -97,3 +111,85 @@ class ReceiveInfoBox extends StatelessWidget {
111 );
112 }
113 }
114 +
115 +class InfoboxCurrencyRow extends StatelessWidget {
116 + const InfoboxCurrencyRow({super.key, required this.currencies, required this.chainIconPath});
117 +
118 + final String chainIconPath;
119 + final List<CryptoCurrency> currencies;
120 +
121 + static const overlap = 16.0;
122 + static const iconSize = 24.0;
123 + static const maxCurrencies = 4;
124 + static const iconBorder = 1.5;
125 +
126 + @override
127 + Widget build(BuildContext context) {
128 + final currenciesWithImage = currencies.where((item)=>item.iconPath != null).toList();
129 + final currenciesLimited = currenciesWithImage.sublist(0, min(currenciesWithImage.length, maxCurrencies));
130 +
131 + final double stackWidth = iconSize + (overlap * (currenciesLimited.length));
132 +
133 + return Row(
134 + spacing: 8,
135 + children: [
136 + CakeImageWidget(
137 + imageUrl: chainIconPath,
138 + width: 20,
139 + height: 20,
140 + colorFilter:
141 + ColorFilter.mode(Theme.of(context).colorScheme.onSurfaceVariant, BlendMode.srcIn),
142 + ),
143 + Container(
144 + height: 28,
145 + width: 1,
146 + color: Theme.of(context).colorScheme.surfaceContainerHigh,
147 + ),
148 + SizedBox(
149 + height: iconSize + iconBorder * 2,
150 + width: stackWidth,
151 + child: Stack(
152 + children: [
153 + Positioned(
154 + top: iconBorder,
155 + left: overlap * currenciesLimited.length,
156 + child: Container(
157 + width: 24,
158 + height: 24,
159 + decoration: BoxDecoration(
160 + color: Colors.white.withAlpha(25),
161 + borderRadius: BorderRadius.circular(9999999)),
162 + child: Icon(
163 + Icons.add,
164 + size: 16,
165 + color: Colors.white.withAlpha(128),
166 + ),
167 + ),
168 + ),
169 + ...currenciesLimited
170 + .asMap()
171 + .entries
172 + .map((entry) => Positioned(
173 + left: 16.0 * entry.key,
174 + child: Container(
175 + decoration: BoxDecoration(
176 + border: Border.all(
177 + color: Theme.of(context).colorScheme.surfaceContainer,
178 + width: iconBorder),
179 + borderRadius: BorderRadius.circular(9999999)),
180 + child: CakeImageWidget(
181 + imageUrl: entry.value.iconPath,
182 + width: 24,
183 + height: 24,
184 + ),
185 + ),
186 + ))
187 + .toList()
188 + .reversed,
189 + ],
190 + ),
191 + )
192 + ],
193 + );
194 + }
195 +}