mirror of
https://github.com/cake-tech/cake_wallet.git
synced 2024-11-16 17:27:37 +00:00
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>
This commit is contained in:
parent
791b410277
commit
b2850c203f
10 changed files with 144 additions and 26 deletions
Binary file not shown.
Before Width: | Height: | Size: 4.9 KiB |
BIN
assets/images/wallet_group_bright.png
Normal file
BIN
assets/images/wallet_group_bright.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 10 KiB |
BIN
assets/images/wallet_group_dark.png
Normal file
BIN
assets/images/wallet_group_dark.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.9 KiB |
BIN
assets/images/wallet_group_light.png
Normal file
BIN
assets/images/wallet_group_light.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 7 KiB |
|
@ -3,10 +3,11 @@ import 'package:cake_wallet/src/widgets/primary_button.dart';
|
||||||
import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
|
import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
|
||||||
import 'package:cw_core/wallet_type.dart';
|
import 'package:cw_core/wallet_type.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:cake_wallet/themes/theme_base.dart';
|
||||||
import 'package:cake_wallet/generated/i18n.dart';
|
import 'package:cake_wallet/generated/i18n.dart';
|
||||||
import 'package:cake_wallet/routes.dart';
|
import 'package:cake_wallet/routes.dart';
|
||||||
import 'package:cake_wallet/src/screens/base_page.dart';
|
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||||
|
import 'package:flutter_svg/svg.dart';
|
||||||
|
|
||||||
class WalletGroupDescriptionPage extends BasePage {
|
class WalletGroupDescriptionPage extends BasePage {
|
||||||
WalletGroupDescriptionPage({required this.selectedWalletType});
|
WalletGroupDescriptionPage({required this.selectedWalletType});
|
||||||
|
@ -16,16 +17,24 @@ class WalletGroupDescriptionPage extends BasePage {
|
||||||
@override
|
@override
|
||||||
String get title => S.current.wallet_group;
|
String get title => S.current.wallet_group;
|
||||||
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget body(BuildContext context) {
|
Widget body(BuildContext context) {
|
||||||
|
|
||||||
|
final lightImage = 'assets/images/wallet_group_light.png';
|
||||||
|
final darkImage = 'assets/images/wallet_group_dark.png';
|
||||||
|
final brightImage = 'assets/images/wallet_group_bright.png';
|
||||||
|
|
||||||
|
final image = currentTheme.type == ThemeType.light ? lightImage : darkImage;
|
||||||
|
|
||||||
return Container(
|
return Container(
|
||||||
alignment: Alignment.center,
|
alignment: Alignment.center,
|
||||||
padding: EdgeInsets.all(24),
|
padding: EdgeInsets.all(24),
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
Image.asset(
|
Image.asset(
|
||||||
'assets/images/wallet_group.png',
|
image,
|
||||||
scale: 0.8,
|
height: 200
|
||||||
),
|
),
|
||||||
SizedBox(height: 32),
|
SizedBox(height: 32),
|
||||||
Expanded(
|
Expanded(
|
||||||
|
|
|
@ -58,6 +58,7 @@ class WalletGroupsDisplayBody extends StatelessWidget {
|
||||||
final groupName =
|
final groupName =
|
||||||
group.groupName ?? '${S.of(context).wallet_group} ${index + 1}';
|
group.groupName ?? '${S.of(context).wallet_group} ${index + 1}';
|
||||||
return GroupedWalletExpansionTile(
|
return GroupedWalletExpansionTile(
|
||||||
|
shouldShowCurrentWalletPointer: false,
|
||||||
leadingWidget:
|
leadingWidget:
|
||||||
Icon(Icons.account_balance_wallet_outlined, size: 28),
|
Icon(Icons.account_balance_wallet_outlined, size: 28),
|
||||||
borderRadius: BorderRadius.all(Radius.circular(16)),
|
borderRadius: BorderRadius.all(Radius.circular(16)),
|
||||||
|
|
|
@ -12,6 +12,7 @@ class GroupedWalletExpansionTile extends StatelessWidget {
|
||||||
this.childWallets = const [],
|
this.childWallets = const [],
|
||||||
this.onTitleTapped,
|
this.onTitleTapped,
|
||||||
this.onChildItemTapped = _defaultVoidCallback,
|
this.onChildItemTapped = _defaultVoidCallback,
|
||||||
|
this.onExpansionChanged,
|
||||||
this.leadingWidget,
|
this.leadingWidget,
|
||||||
this.trailingWidget,
|
this.trailingWidget,
|
||||||
this.childTrailingWidget,
|
this.childTrailingWidget,
|
||||||
|
@ -22,13 +23,18 @@ class GroupedWalletExpansionTile extends StatelessWidget {
|
||||||
this.borderRadius,
|
this.borderRadius,
|
||||||
this.margin,
|
this.margin,
|
||||||
this.tileKey,
|
this.tileKey,
|
||||||
|
this.isCurrentlySelectedWallet = false,
|
||||||
|
this.shouldShowCurrentWalletPointer = false,
|
||||||
}) : super(key: tileKey);
|
}) : super(key: tileKey);
|
||||||
|
|
||||||
final Key? tileKey;
|
final Key? tileKey;
|
||||||
final bool isSelected;
|
final bool isSelected;
|
||||||
|
final bool isCurrentlySelectedWallet;
|
||||||
|
final bool shouldShowCurrentWalletPointer;
|
||||||
|
|
||||||
final VoidCallback? onTitleTapped;
|
final VoidCallback? onTitleTapped;
|
||||||
final void Function(WalletListItem item) onChildItemTapped;
|
final void Function(WalletListItem item) onChildItemTapped;
|
||||||
|
final void Function(bool)? onExpansionChanged;
|
||||||
|
|
||||||
final String title;
|
final String title;
|
||||||
final Widget? leadingWidget;
|
final Widget? leadingWidget;
|
||||||
|
@ -70,8 +76,10 @@ class GroupedWalletExpansionTile extends StatelessWidget {
|
||||||
splashFactory: NoSplash.splashFactory,
|
splashFactory: NoSplash.splashFactory,
|
||||||
),
|
),
|
||||||
child: ExpansionTile(
|
child: ExpansionTile(
|
||||||
|
onExpansionChanged: onExpansionChanged,
|
||||||
key: tileKey,
|
key: tileKey,
|
||||||
tilePadding: EdgeInsets.symmetric(vertical: 1, horizontal: 16),
|
tilePadding:
|
||||||
|
EdgeInsets.symmetric(vertical: 1, horizontal: !isCurrentlySelectedWallet ? 16 : 0),
|
||||||
iconColor: effectiveArrowColor,
|
iconColor: effectiveArrowColor,
|
||||||
collapsedIconColor: effectiveArrowColor,
|
collapsedIconColor: effectiveArrowColor,
|
||||||
leading: leadingWidget,
|
leading: leadingWidget,
|
||||||
|
@ -90,19 +98,46 @@ class GroupedWalletExpansionTile extends StatelessWidget {
|
||||||
),
|
),
|
||||||
children: childWallets.map(
|
children: childWallets.map(
|
||||||
(item) {
|
(item) {
|
||||||
|
final currentColor = item.isCurrent
|
||||||
|
? Theme.of(context)
|
||||||
|
.extension<WalletListTheme>()!
|
||||||
|
.createNewWalletButtonBackgroundColor
|
||||||
|
: Theme.of(context).colorScheme.background;
|
||||||
final walletTypeToCrypto = walletTypeToCryptoCurrency(item.type);
|
final walletTypeToCrypto = walletTypeToCryptoCurrency(item.type);
|
||||||
return ListTile(
|
return ListTile(
|
||||||
|
contentPadding: EdgeInsets.zero,
|
||||||
key: ValueKey(item.name),
|
key: ValueKey(item.name),
|
||||||
trailing: childTrailingWidget?.call(item),
|
trailing: childTrailingWidget?.call(item),
|
||||||
onTap: () => onChildItemTapped(item),
|
onTap: () => onChildItemTapped(item),
|
||||||
leading: Image.asset(
|
leading: SizedBox(
|
||||||
|
width: 60,
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
item.isCurrent && shouldShowCurrentWalletPointer
|
||||||
|
? Container(
|
||||||
|
height: 35,
|
||||||
|
width: 6,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
borderRadius: BorderRadius.only(
|
||||||
|
topRight: Radius.circular(16),
|
||||||
|
bottomRight: Radius.circular(16),
|
||||||
|
),
|
||||||
|
color: currentColor,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
: SizedBox(width: 6),
|
||||||
|
SizedBox(width: 16),
|
||||||
|
Image.asset(
|
||||||
walletTypeToCrypto.iconPath!,
|
walletTypeToCrypto.iconPath!,
|
||||||
width: 32,
|
width: 32,
|
||||||
height: 32,
|
height: 32,
|
||||||
),
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
title: Text(
|
title: Text(
|
||||||
item.name,
|
item.name,
|
||||||
maxLines: 1,
|
maxLines: 2,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 18,
|
fontSize: 18,
|
||||||
fontWeight: FontWeight.w500,
|
fontWeight: FontWeight.w500,
|
||||||
|
|
|
@ -7,11 +7,13 @@ class EditWalletButtonWidget extends StatelessWidget {
|
||||||
required this.width,
|
required this.width,
|
||||||
required this.onTap,
|
required this.onTap,
|
||||||
this.isGroup = false,
|
this.isGroup = false,
|
||||||
|
this.isExpanded = false,
|
||||||
super.key,
|
super.key,
|
||||||
});
|
});
|
||||||
|
|
||||||
final bool isGroup;
|
final bool isGroup;
|
||||||
final double width;
|
final double width;
|
||||||
|
final bool isExpanded;
|
||||||
final VoidCallback onTap;
|
final VoidCallback onTap;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -42,7 +44,7 @@ class EditWalletButtonWidget extends StatelessWidget {
|
||||||
if (isGroup) ...{
|
if (isGroup) ...{
|
||||||
SizedBox(width: 6),
|
SizedBox(width: 6),
|
||||||
Icon(
|
Icon(
|
||||||
Icons.keyboard_arrow_down,
|
isExpanded ? Icons.keyboard_arrow_up : Icons.keyboard_arrow_down,
|
||||||
size: 24,
|
size: 24,
|
||||||
color: Theme.of(context).extension<FilterTheme>()!.titlesColor,
|
color: Theme.of(context).extension<FilterTheme>()!.titlesColor,
|
||||||
),
|
),
|
||||||
|
|
|
@ -11,6 +11,7 @@ import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
|
||||||
import 'package:cake_wallet/src/screens/auth/auth_page.dart';
|
import 'package:cake_wallet/src/screens/auth/auth_page.dart';
|
||||||
import 'package:cake_wallet/core/auth_service.dart';
|
import 'package:cake_wallet/core/auth_service.dart';
|
||||||
import 'package:cake_wallet/themes/extensions/filter_theme.dart';
|
import 'package:cake_wallet/themes/extensions/filter_theme.dart';
|
||||||
|
import 'package:cake_wallet/themes/extensions/wallet_list_theme.dart';
|
||||||
import 'package:cake_wallet/utils/responsive_layout_util.dart';
|
import 'package:cake_wallet/utils/responsive_layout_util.dart';
|
||||||
import 'package:cake_wallet/utils/show_bar.dart';
|
import 'package:cake_wallet/utils/show_bar.dart';
|
||||||
import 'package:cake_wallet/utils/show_pop_up.dart';
|
import 'package:cake_wallet/utils/show_pop_up.dart';
|
||||||
|
@ -156,7 +157,18 @@ class WalletListBodyState extends State<WalletListBody> {
|
||||||
final group = widget.walletListViewModel.multiWalletGroups[index];
|
final group = widget.walletListViewModel.multiWalletGroups[index];
|
||||||
final groupName = group.groupName ??
|
final groupName = group.groupName ??
|
||||||
'${S.current.wallet_group} ${index + 1}';
|
'${S.current.wallet_group} ${index + 1}';
|
||||||
|
|
||||||
|
widget.walletListViewModel.updateTileState(
|
||||||
|
index,
|
||||||
|
widget.walletListViewModel.expansionTileStateTrack[index] ?? false,
|
||||||
|
);
|
||||||
|
|
||||||
return GroupedWalletExpansionTile(
|
return GroupedWalletExpansionTile(
|
||||||
|
onExpansionChanged: (value) {
|
||||||
|
widget.walletListViewModel.updateTileState(index, value);
|
||||||
|
setState(() {});
|
||||||
|
},
|
||||||
|
shouldShowCurrentWalletPointer: true,
|
||||||
borderRadius: BorderRadius.all(Radius.circular(16)),
|
borderRadius: BorderRadius.all(Radius.circular(16)),
|
||||||
margin: EdgeInsets.only(left: 20, right: 20, bottom: 12),
|
margin: EdgeInsets.only(left: 20, right: 20, bottom: 12),
|
||||||
title: groupName,
|
title: groupName,
|
||||||
|
@ -168,6 +180,8 @@ class WalletListBodyState extends State<WalletListBody> {
|
||||||
trailingWidget: EditWalletButtonWidget(
|
trailingWidget: EditWalletButtonWidget(
|
||||||
width: 74,
|
width: 74,
|
||||||
isGroup: true,
|
isGroup: true,
|
||||||
|
isExpanded:
|
||||||
|
widget.walletListViewModel.expansionTileStateTrack[index]!,
|
||||||
onTap: () {
|
onTap: () {
|
||||||
final wallet = widget.walletListViewModel
|
final wallet = widget.walletListViewModel
|
||||||
.convertWalletInfoToWalletListItem(group.wallets.first);
|
.convertWalletInfoToWalletListItem(group.wallets.first);
|
||||||
|
@ -193,7 +207,9 @@ class WalletListBodyState extends State<WalletListBody> {
|
||||||
childTrailingWidget: (item) {
|
childTrailingWidget: (item) {
|
||||||
return item.isCurrent
|
return item.isCurrent
|
||||||
? SizedBox.shrink()
|
? SizedBox.shrink()
|
||||||
: EditWalletButtonWidget(
|
: Padding(
|
||||||
|
padding: const EdgeInsets.only(right: 16),
|
||||||
|
child: EditWalletButtonWidget(
|
||||||
width: 44,
|
width: 44,
|
||||||
onTap: () => Navigator.of(context).pushNamed(
|
onTap: () => Navigator.of(context).pushNamed(
|
||||||
Routes.walletEdit,
|
Routes.walletEdit,
|
||||||
|
@ -202,6 +218,7 @@ class WalletListBodyState extends State<WalletListBody> {
|
||||||
editingWallet: item,
|
editingWallet: item,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
@ -232,14 +249,41 @@ class WalletListBodyState extends State<WalletListBody> {
|
||||||
updateFunction: widget.walletListViewModel.reorderAccordingToWalletList,
|
updateFunction: widget.walletListViewModel.reorderAccordingToWalletList,
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
final wallet = widget.walletListViewModel.singleWalletsList[index];
|
final wallet = widget.walletListViewModel.singleWalletsList[index];
|
||||||
|
final currentColor = wallet.isCurrent
|
||||||
|
? Theme.of(context)
|
||||||
|
.extension<WalletListTheme>()!
|
||||||
|
.createNewWalletButtonBackgroundColor
|
||||||
|
: Theme.of(context).colorScheme.background;
|
||||||
|
|
||||||
return GroupedWalletExpansionTile(
|
return GroupedWalletExpansionTile(
|
||||||
tileKey: ValueKey('single_wallets_expansion_tile_widget_$index'),
|
tileKey: ValueKey('single_wallets_expansion_tile_widget_$index'),
|
||||||
leadingWidget: Image.asset(
|
isCurrentlySelectedWallet: wallet.isCurrent,
|
||||||
|
leadingWidget: SizedBox(
|
||||||
|
width: 60,
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
wallet.isCurrent
|
||||||
|
? Container(
|
||||||
|
height: 35,
|
||||||
|
width: 6,
|
||||||
|
margin: EdgeInsets.only(right: 16),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
borderRadius: BorderRadius.only(
|
||||||
|
topRight: Radius.circular(16),
|
||||||
|
bottomRight: Radius.circular(16),
|
||||||
|
),
|
||||||
|
color: currentColor,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
: SizedBox(width: 6),
|
||||||
|
Image.asset(
|
||||||
walletTypeToCryptoCurrency(wallet.type).iconPath!,
|
walletTypeToCryptoCurrency(wallet.type).iconPath!,
|
||||||
width: 32,
|
width: 32,
|
||||||
height: 32,
|
height: 32,
|
||||||
),
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
title: wallet.name,
|
title: wallet.name,
|
||||||
isSelected: false,
|
isSelected: false,
|
||||||
borderRadius: BorderRadius.all(Radius.circular(16)),
|
borderRadius: BorderRadius.all(Radius.circular(16)),
|
||||||
|
|
|
@ -22,7 +22,8 @@ abstract class WalletListViewModelBase with Store {
|
||||||
this._walletManager,
|
this._walletManager,
|
||||||
) : wallets = ObservableList<WalletListItem>(),
|
) : wallets = ObservableList<WalletListItem>(),
|
||||||
multiWalletGroups = ObservableList<WalletGroup>(),
|
multiWalletGroups = ObservableList<WalletGroup>(),
|
||||||
singleWalletsList = ObservableList<WalletListItem>() {
|
singleWalletsList = ObservableList<WalletListItem>(),
|
||||||
|
expansionTileStateTrack = ObservableMap<int, bool>() {
|
||||||
setOrderType(_appStore.settingsStore.walletListOrder);
|
setOrderType(_appStore.settingsStore.walletListOrder);
|
||||||
reaction((_) => _appStore.wallet, (_) => updateList());
|
reaction((_) => _appStore.wallet, (_) => updateList());
|
||||||
updateList();
|
updateList();
|
||||||
|
@ -40,6 +41,18 @@ abstract class WalletListViewModelBase with Store {
|
||||||
@observable
|
@observable
|
||||||
ObservableList<WalletListItem> singleWalletsList;
|
ObservableList<WalletListItem> singleWalletsList;
|
||||||
|
|
||||||
|
@observable
|
||||||
|
ObservableMap<int, bool> expansionTileStateTrack;
|
||||||
|
|
||||||
|
@action
|
||||||
|
void updateTileState(int index, bool isExpanded) {
|
||||||
|
if (expansionTileStateTrack.containsKey(index)) {
|
||||||
|
expansionTileStateTrack.update(index, (value) => isExpanded);
|
||||||
|
} else {
|
||||||
|
expansionTileStateTrack.addEntries({index: isExpanded}.entries);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@computed
|
@computed
|
||||||
bool get shouldRequireTOTP2FAForAccessingWallet =>
|
bool get shouldRequireTOTP2FAForAccessingWallet =>
|
||||||
_appStore.settingsStore.shouldRequireTOTP2FAForAccessingWallet;
|
_appStore.settingsStore.shouldRequireTOTP2FAForAccessingWallet;
|
||||||
|
@ -100,8 +113,8 @@ abstract class WalletListViewModelBase with Store {
|
||||||
// delete all wallets from walletInfoSource:
|
// delete all wallets from walletInfoSource:
|
||||||
await _walletInfoSource.clear();
|
await _walletInfoSource.clear();
|
||||||
|
|
||||||
// add wallets from wallets list in order of wallets list, by name:
|
// Reorder single wallets using the singleWalletsList
|
||||||
for (WalletListItem wallet in wallets) {
|
for (WalletListItem wallet in singleWalletsList) {
|
||||||
for (int i = 0; i < walletInfoSourceCopy.length; i++) {
|
for (int i = 0; i < walletInfoSourceCopy.length; i++) {
|
||||||
if (walletInfoSourceCopy[i].name == wallet.name) {
|
if (walletInfoSourceCopy[i].name == wallet.name) {
|
||||||
await _walletInfoSource.add(walletInfoSourceCopy[i]);
|
await _walletInfoSource.add(walletInfoSourceCopy[i]);
|
||||||
|
@ -111,6 +124,20 @@ abstract class WalletListViewModelBase with Store {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Reorder wallets within multi-wallet groups
|
||||||
|
for (WalletGroup group in multiWalletGroups) {
|
||||||
|
for (WalletInfo walletInfo in group.wallets) {
|
||||||
|
for (int i = 0; i < walletInfoSourceCopy.length; i++) {
|
||||||
|
if (walletInfoSourceCopy[i].name == walletInfo.name) {
|
||||||
|
await _walletInfoSource.add(walletInfoSourceCopy[i]);
|
||||||
|
walletInfoSourceCopy.removeAt(i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rebuild the list of wallets and groups
|
||||||
updateList();
|
updateList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue