feat: Add UI signifying the currently selected wallet indicator (#1704)
* feat: Add UI signifying the currently selected wallet indicator * fix: Product Fix - Add more padding to child wallets list item tile in grouped wallets, fix sort by dragging for general single wallets, and also groups, add animation to trailing arrow icon when tile is expanded or not * Update wallet group image and change maxLines --------- Co-authored-by: tuxpizza <tuxsudo@tux.pizza>
David Adegoke committed
Sep 27, 2024 at 23:36 UTC
b2850c203f319a37d7888465a46b83d951383156
10 files changed
+144
-26
assets/images/wallet_group.png
Binary files a/assets/images/wallet_group.png and /dev/null differ
assets/images/wallet_group_bright.png
Binary files /dev/null and b/assets/images/wallet_group_bright.png differ
assets/images/wallet_group_dark.png
Binary files /dev/null and b/assets/images/wallet_group_dark.png differ
assets/images/wallet_group_light.png
Binary files /dev/null and b/assets/images/wallet_group_light.png differ
lib/src/screens/new_wallet/wallet_group_description_page.dart
+14
-5
@@ -3,10 +3,11 @@ import 'package:cake_wallet/src/widgets/primary_button.dart';
3
import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
4
import 'package:cw_core/wallet_type.dart';
5
import 'package:flutter/material.dart';
6
-
6
+import 'package:cake_wallet/themes/theme_base.dart';
7
import 'package:cake_wallet/generated/i18n.dart';
8
import 'package:cake_wallet/routes.dart';
9
import 'package:cake_wallet/src/screens/base_page.dart';
10
+import 'package:flutter_svg/svg.dart';
11
12
class WalletGroupDescriptionPage extends BasePage {
13
WalletGroupDescriptionPage({required this.selectedWalletType});
@@ -16,17 +17,25 @@ class WalletGroupDescriptionPage extends BasePage {
17
@override
18
String get title => S.current.wallet_group;
19
20
+
21
@override
22
Widget body(BuildContext context) {
23
+
24
+ final lightImage = 'assets/images/wallet_group_light.png';
25
+ final darkImage = 'assets/images/wallet_group_dark.png';
26
+ final brightImage = 'assets/images/wallet_group_bright.png';
27
+
28
+ final image = currentTheme.type == ThemeType.light ? lightImage : darkImage;
29
+
30
return Container(
31
alignment: Alignment.center,
32
padding: EdgeInsets.all(24),
33
child: Column(
34
children: [
26
- Image.asset(
27
- 'assets/images/wallet_group.png',
28
- scale: 0.8,
29
- ),
35
+ Image.asset(
36
+ image,
37
+ height: 200
38
+ ),
39
SizedBox(height: 32),
40
Expanded(
41
child: Text.rich(
lib/src/screens/new_wallet/wallet_group_display_page.dart
+1
@@ -58,6 +58,7 @@ class WalletGroupsDisplayBody extends StatelessWidget {
58
final groupName =
59
group.groupName ?? '${S.of(context).wallet_group} ${index + 1}';
60
return GroupedWalletExpansionTile(
61
+ shouldShowCurrentWalletPointer: false,
62
leadingWidget:
63
Icon(Icons.account_balance_wallet_outlined, size: 28),
64
borderRadius: BorderRadius.all(Radius.circular(16)),
lib/src/screens/new_wallet/widgets/grouped_wallet_expansion_tile.dart
+41
-6
@@ -12,6 +12,7 @@ class GroupedWalletExpansionTile extends StatelessWidget {
12
this.childWallets = const [],
13
this.onTitleTapped,
14
this.onChildItemTapped = _defaultVoidCallback,
15
+ this.onExpansionChanged,
16
this.leadingWidget,
17
this.trailingWidget,
18
this.childTrailingWidget,
@@ -22,13 +23,18 @@ class GroupedWalletExpansionTile extends StatelessWidget {
23
this.borderRadius,
24
this.margin,
25
this.tileKey,
26
+ this.isCurrentlySelectedWallet = false,
27
+ this.shouldShowCurrentWalletPointer = false,
28
}) : super(key: tileKey);
29
30
final Key? tileKey;
31
final bool isSelected;
32
+ final bool isCurrentlySelectedWallet;
33
+ final bool shouldShowCurrentWalletPointer;
34
35
final VoidCallback? onTitleTapped;
36
final void Function(WalletListItem item) onChildItemTapped;
37
+ final void Function(bool)? onExpansionChanged;
38
39
final String title;
40
final Widget? leadingWidget;
@@ -70,8 +76,10 @@ class GroupedWalletExpansionTile extends StatelessWidget {
76
splashFactory: NoSplash.splashFactory,
77
),
78
child: ExpansionTile(
79
+ onExpansionChanged: onExpansionChanged,
80
key: tileKey,
74
- tilePadding: EdgeInsets.symmetric(vertical: 1, horizontal: 16),
81
+ tilePadding:
82
+ EdgeInsets.symmetric(vertical: 1, horizontal: !isCurrentlySelectedWallet ? 16 : 0),
83
iconColor: effectiveArrowColor,
84
collapsedIconColor: effectiveArrowColor,
85
leading: leadingWidget,
@@ -90,19 +98,46 @@ class GroupedWalletExpansionTile extends StatelessWidget {
98
),
99
children: childWallets.map(
100
(item) {
101
+ final currentColor = item.isCurrent
102
+ ? Theme.of(context)
103
+ .extension<WalletListTheme>()!
104
+ .createNewWalletButtonBackgroundColor
105
+ : Theme.of(context).colorScheme.background;
106
final walletTypeToCrypto = walletTypeToCryptoCurrency(item.type);
107
return ListTile(
108
+ contentPadding: EdgeInsets.zero,
109
key: ValueKey(item.name),
110
trailing: childTrailingWidget?.call(item),
111
onTap: () => onChildItemTapped(item),
98
- leading: Image.asset(
99
- walletTypeToCrypto.iconPath!,
100
- width: 32,
101
- height: 32,
112
+ leading: SizedBox(
113
+ width: 60,
114
+ child: Row(
115
+ children: [
116
+ item.isCurrent && shouldShowCurrentWalletPointer
117
+ ? Container(
118
+ height: 35,
119
+ width: 6,
120
+ decoration: BoxDecoration(
121
+ borderRadius: BorderRadius.only(
122
+ topRight: Radius.circular(16),
123
+ bottomRight: Radius.circular(16),
124
+ ),
125
+ color: currentColor,
126
+ ),
127
+ )
128
+ : SizedBox(width: 6),
129
+ SizedBox(width: 16),
130
+ Image.asset(
131
+ walletTypeToCrypto.iconPath!,
132
+ width: 32,
133
+ height: 32,
134
+ ),
135
+ ],
136
+ ),
137
),
138
title: Text(
139
item.name,
105
- maxLines: 1,
140
+ maxLines: 2,
141
style: TextStyle(
142
fontSize: 18,
143
fontWeight: FontWeight.w500,
lib/src/screens/wallet_list/edit_wallet_button_widget.dart
+3
-1
@@ -7,11 +7,13 @@ class EditWalletButtonWidget extends StatelessWidget {
7
required this.width,
8
required this.onTap,
9
this.isGroup = false,
10
+ this.isExpanded = false,
11
super.key,
12
});
13
14
final bool isGroup;
15
final double width;
16
+ final bool isExpanded;
17
final VoidCallback onTap;
18
19
@override
@@ -42,7 +44,7 @@ class EditWalletButtonWidget extends StatelessWidget {
44
if (isGroup) ...{
45
SizedBox(width: 6),
46
Icon(
45
- Icons.keyboard_arrow_down,
47
+ isExpanded ? Icons.keyboard_arrow_up : Icons.keyboard_arrow_down,
48
size: 24,
49
color: Theme.of(context).extension<FilterTheme>()!.titlesColor,
50
),
lib/src/screens/wallet_list/wallet_list_page.dart
+55
-11
@@ -11,6 +11,7 @@ import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
11
import 'package:cake_wallet/src/screens/auth/auth_page.dart';
12
import 'package:cake_wallet/core/auth_service.dart';
13
import 'package:cake_wallet/themes/extensions/filter_theme.dart';
14
+import 'package:cake_wallet/themes/extensions/wallet_list_theme.dart';
15
import 'package:cake_wallet/utils/responsive_layout_util.dart';
16
import 'package:cake_wallet/utils/show_bar.dart';
17
import 'package:cake_wallet/utils/show_pop_up.dart';
@@ -156,7 +157,18 @@ class WalletListBodyState extends State<WalletListBody> {
157
final group = widget.walletListViewModel.multiWalletGroups[index];
158
final groupName = group.groupName ??
159
'${S.current.wallet_group} ${index + 1}';
160
+
161
+ widget.walletListViewModel.updateTileState(
162
+ index,
163
+ widget.walletListViewModel.expansionTileStateTrack[index] ?? false,
164
+ );
165
+
166
return GroupedWalletExpansionTile(
167
+ onExpansionChanged: (value) {
168
+ widget.walletListViewModel.updateTileState(index, value);
169
+ setState(() {});
170
+ },
171
+ shouldShowCurrentWalletPointer: true,
172
borderRadius: BorderRadius.all(Radius.circular(16)),
173
margin: EdgeInsets.only(left: 20, right: 20, bottom: 12),
174
title: groupName,
@@ -168,6 +180,8 @@ class WalletListBodyState extends State<WalletListBody> {
180
trailingWidget: EditWalletButtonWidget(
181
width: 74,
182
isGroup: true,
183
+ isExpanded:
184
+ widget.walletListViewModel.expansionTileStateTrack[index]!,
185
onTap: () {
186
final wallet = widget.walletListViewModel
187
.convertWalletInfoToWalletListItem(group.wallets.first);
@@ -193,13 +207,16 @@ class WalletListBodyState extends State<WalletListBody> {
207
childTrailingWidget: (item) {
208
return item.isCurrent
209
? SizedBox.shrink()
196
- : EditWalletButtonWidget(
197
- width: 44,
198
- onTap: () => Navigator.of(context).pushNamed(
199
- Routes.walletEdit,
200
- arguments: WalletEditPageArguments(
201
- walletListViewModel: widget.walletListViewModel,
202
- editingWallet: item,
210
+ : Padding(
211
+ padding: const EdgeInsets.only(right: 16),
212
+ child: EditWalletButtonWidget(
213
+ width: 44,
214
+ onTap: () => Navigator.of(context).pushNamed(
215
+ Routes.walletEdit,
216
+ arguments: WalletEditPageArguments(
217
+ walletListViewModel: widget.walletListViewModel,
218
+ editingWallet: item,
219
+ ),
220
),
221
),
222
);
@@ -232,13 +249,40 @@ class WalletListBodyState extends State<WalletListBody> {
249
updateFunction: widget.walletListViewModel.reorderAccordingToWalletList,
250
itemBuilder: (context, index) {
251
final wallet = widget.walletListViewModel.singleWalletsList[index];
252
+ final currentColor = wallet.isCurrent
253
+ ? Theme.of(context)
254
+ .extension<WalletListTheme>()!
255
+ .createNewWalletButtonBackgroundColor
256
+ : Theme.of(context).colorScheme.background;
257
258
return GroupedWalletExpansionTile(
259
tileKey: ValueKey('single_wallets_expansion_tile_widget_$index'),
238
- leadingWidget: Image.asset(
239
- walletTypeToCryptoCurrency(wallet.type).iconPath!,
240
- width: 32,
241
- height: 32,
260
+ isCurrentlySelectedWallet: wallet.isCurrent,
261
+ leadingWidget: SizedBox(
262
+ width: 60,
263
+ child: Row(
264
+ children: [
265
+ wallet.isCurrent
266
+ ? Container(
267
+ height: 35,
268
+ width: 6,
269
+ margin: EdgeInsets.only(right: 16),
270
+ decoration: BoxDecoration(
271
+ borderRadius: BorderRadius.only(
272
+ topRight: Radius.circular(16),
273
+ bottomRight: Radius.circular(16),
274
+ ),
275
+ color: currentColor,
276
+ ),
277
+ )
278
+ : SizedBox(width: 6),
279
+ Image.asset(
280
+ walletTypeToCryptoCurrency(wallet.type).iconPath!,
281
+ width: 32,
282
+ height: 32,
283
+ ),
284
+ ],
285
+ ),
286
),
287
title: wallet.name,
288
isSelected: false,
lib/view_model/wallet_list/wallet_list_view_model.dart
+30
-3
@@ -22,7 +22,8 @@ abstract class WalletListViewModelBase with Store {
22
this._walletManager,
23
) : wallets = ObservableList<WalletListItem>(),
24
multiWalletGroups = ObservableList<WalletGroup>(),
25
- singleWalletsList = ObservableList<WalletListItem>() {
25
+ singleWalletsList = ObservableList<WalletListItem>(),
26
+ expansionTileStateTrack = ObservableMap<int, bool>() {
27
setOrderType(_appStore.settingsStore.walletListOrder);
28
reaction((_) => _appStore.wallet, (_) => updateList());
29
updateList();
@@ -40,6 +41,18 @@ abstract class WalletListViewModelBase with Store {
41
@observable
42
ObservableList<WalletListItem> singleWalletsList;
43
44
+ @observable
45
+ ObservableMap<int, bool> expansionTileStateTrack;
46
+
47
+ @action
48
+ void updateTileState(int index, bool isExpanded) {
49
+ if (expansionTileStateTrack.containsKey(index)) {
50
+ expansionTileStateTrack.update(index, (value) => isExpanded);
51
+ } else {
52
+ expansionTileStateTrack.addEntries({index: isExpanded}.entries);
53
+ }
54
+ }
55
+
56
@computed
57
bool get shouldRequireTOTP2FAForAccessingWallet =>
58
_appStore.settingsStore.shouldRequireTOTP2FAForAccessingWallet;
@@ -100,8 +113,8 @@ abstract class WalletListViewModelBase with Store {
113
// delete all wallets from walletInfoSource:
114
await _walletInfoSource.clear();
115
103
- // add wallets from wallets list in order of wallets list, by name:
104
- for (WalletListItem wallet in wallets) {
116
+ // Reorder single wallets using the singleWalletsList
117
+ for (WalletListItem wallet in singleWalletsList) {
118
for (int i = 0; i < walletInfoSourceCopy.length; i++) {
119
if (walletInfoSourceCopy[i].name == wallet.name) {
120
await _walletInfoSource.add(walletInfoSourceCopy[i]);
@@ -111,6 +124,20 @@ abstract class WalletListViewModelBase with Store {
124
}
125
}
126
127
+ // Reorder wallets within multi-wallet groups
128
+ for (WalletGroup group in multiWalletGroups) {
129
+ for (WalletInfo walletInfo in group.wallets) {
130
+ for (int i = 0; i < walletInfoSourceCopy.length; i++) {
131
+ if (walletInfoSourceCopy[i].name == walletInfo.name) {
132
+ await _walletInfoSource.add(walletInfoSourceCopy[i]);
133
+ walletInfoSourceCopy.removeAt(i);
134
+ break;
135
+ }
136
+ }
137
+ }
138
+ }
139
+
140
+ // Rebuild the list of wallets and groups
141
updateList();
142
}
143