CW-427-Refactor-wallet-type-selection-UI (#968)

* refactor the asset selection screen * formatting * ui fixes * remove Ethereum related

Serhii committed Jul 10, 2023 at 18:12 UTC c01321008b33431b5e88ce0d0c75ad73e4fdc0a8
5 files changed +122 -116
cw_core/lib/wallet_type.dart
+5 -5
@@ -26,7 +26,7 @@ enum WalletType {
26 litecoin,
27
28 @HiveField(4)
29 - haven
29 + haven,
30 }
31
32 int serializeToInt(WalletType type) {
@@ -77,13 +77,13 @@ String walletTypeToString(WalletType type) {
77 String walletTypeToDisplayName(WalletType type) {
78 switch (type) {
79 case WalletType.monero:
80 - return 'Monero';
80 + return 'Monero (XMR)';
81 case WalletType.bitcoin:
82 - return 'Bitcoin (Electrum)';
82 + return 'Bitcoin (BTC)';
83 case WalletType.litecoin:
84 - return 'Litecoin (Electrum)';
84 + return 'Litecoin (LTC)';
85 case WalletType.haven:
86 - return 'Haven';
86 + return 'Haven (XHV)';
87 default:
88 return '';
89 }
lib/src/screens/new_wallet/new_wallet_type_page.dart
+69 -78
@@ -1,13 +1,14 @@
1 -import 'package:cake_wallet/utils/responsive_layout_util.dart';
2 -import 'package:cw_core/wallet_type.dart';
3 -import 'package:cake_wallet/themes/theme_base.dart';
4 -import 'package:flutter/material.dart';
1 import 'package:cake_wallet/generated/i18n.dart';
2 import 'package:cake_wallet/src/screens/base_page.dart';
3 +import 'package:cake_wallet/src/screens/new_wallet/widgets/select_button.dart';
4 import 'package:cake_wallet/src/widgets/primary_button.dart';
5 import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
9 -import 'package:cake_wallet/src/screens/new_wallet/widgets/select_button.dart';
6 +import 'package:cake_wallet/src/widgets/search_bar_widget.dart';
7 +import 'package:cake_wallet/themes/theme_base.dart';
8 +import 'package:cake_wallet/utils/responsive_layout_util.dart';
9 import 'package:cake_wallet/wallet_types.g.dart';
10 +import 'package:cw_core/wallet_type.dart';
11 +import 'package:flutter/material.dart';
12
13 class NewWalletTypePage extends BasePage {
14 NewWalletTypePage({required this.onTypeSelected});
@@ -40,92 +41,82 @@ class WalletTypeFormState extends State<WalletTypeForm> {
41
42 static const aspectRatioImage = 1.22;
43
43 - final moneroIcon = Image.asset('assets/images/monero_logo.png', height: 24, width: 24);
44 - final bitcoinIcon = Image.asset('assets/images/bitcoin.png', height: 24, width: 24);
45 - final litecoinIcon = Image.asset('assets/images/litecoin_icon.png', height: 24, width: 24);
46 - final walletTypeImage = Image.asset('assets/images/wallet_type.png');
47 - final walletTypeLightImage = Image.asset('assets/images/wallet_type_light.png');
48 - final havenIcon = Image.asset('assets/images/haven_logo.png', height: 24, width: 24);
44 + final TextEditingController searchController = TextEditingController();
45
46 WalletType? selected;
47 List<WalletType> types;
48 + List<WalletType> filteredTypes = [];
49
50 @override
51 void initState() {
55 - types = availableWalletTypes;
52 + types = filteredTypes = availableWalletTypes;
53 super.initState();
54 +
55 + searchController.addListener(() {
56 + setState(() {
57 + filteredTypes = List.from(types.where((type) => walletTypeToDisplayName(type)
58 + .toLowerCase()
59 + .contains(searchController.text.toLowerCase())));
60 + return;
61 + });
62 + });
63 }
64
65 @override
66 Widget build(BuildContext context) {
61 - return ScrollableWithBottomSection(
62 - contentPadding: EdgeInsets.only(left: 24, right: 24, bottom: 24),
63 - content: Center(
67 + return Center(
68 child: ConstrainedBox(
65 - constraints: BoxConstraints(maxWidth: ResponsiveLayoutUtil.kDesktopMaxWidthConstraint),
66 - child: Column(
67 - crossAxisAlignment: CrossAxisAlignment.center,
68 - children: <Widget>[
69 - Padding(
70 - padding: EdgeInsets.only(left: 12, right: 12),
71 - child: AspectRatio(
72 - aspectRatio: aspectRatioImage,
73 - child: FittedBox(child: widget.walletImage, fit: BoxFit.fill)),
74 - ),
75 - Padding(
76 - padding: EdgeInsets.only(top: 48),
77 - child: Text(
78 - S.of(context).choose_wallet_currency,
79 - textAlign: TextAlign.center,
80 - style: TextStyle(
81 - fontSize: 16,
82 - fontWeight: FontWeight.w500,
83 - color: Theme.of(context)
84 - .primaryTextTheme!
85 - .titleLarge!
86 - .color!),
69 + constraints: BoxConstraints(maxWidth: ResponsiveLayoutUtil.kDesktopMaxWidthConstraint),
70 + child: Column(
71 + children: [
72 + Padding(
73 + padding: EdgeInsets.only(top: 48),
74 + child: Text(
75 + S.of(context).choose_wallet_currency,
76 + textAlign: TextAlign.center,
77 + style: TextStyle(
78 + fontSize: 16,
79 + fontWeight: FontWeight.w500,
80 + color: Theme.of(context).primaryTextTheme!.titleLarge!.color!),
81 + ),
82 ),
88 - ),
89 - ...types.map((type) => Padding(
90 - padding: EdgeInsets.only(top: 24),
91 - child: SelectButton(
92 - image: _iconFor(type),
93 - text: walletTypeToDisplayName(type),
94 - isSelected: selected == type,
95 - onTap: () => setState(() => selected = type)),
96 - ))
97 - ],
98 - ),
99 - ),
100 - ),
101 - bottomSectionPadding: EdgeInsets.only(left: 24, right: 24, bottom: 24),
102 - bottomSection: PrimaryButton(
103 - onPressed: () => onTypeSelected(),
104 - text: S.of(context).seed_language_next,
105 - color: Theme.of(context)
106 - .accentTextTheme!
107 - .bodyLarge!
108 - .color!,
109 - textColor: Colors.white,
110 - isDisabled: selected == null,
111 - ),
112 - );
113 - }
114 -
115 - Image _iconFor(WalletType type) {
116 - switch (type) {
117 - case WalletType.monero:
118 - return moneroIcon;
119 - case WalletType.bitcoin:
120 - return bitcoinIcon;
121 - case WalletType.litecoin:
122 - return litecoinIcon;
123 - case WalletType.haven:
124 - return havenIcon;
125 - default:
126 - throw Exception(
127 - '_iconFor: Incorrect Wallet Type. Cannot find icon for Wallet Type: ${type.toString()}');
128 - }
83 + Padding(
84 + padding: const EdgeInsets.fromLTRB(24, 24, 24, 12),
85 + child: SearchBarWidget(searchController: searchController, borderRadius: 24),
86 + ),
87 + Expanded(
88 + child: ScrollableWithBottomSection(
89 + contentPadding: EdgeInsets.only(left: 24, right: 24, bottom: 24),
90 + content: Column(
91 + crossAxisAlignment: CrossAxisAlignment.center,
92 + children: <Widget>[
93 + ...filteredTypes.map((type) => Padding(
94 + padding: EdgeInsets.only(top: 12),
95 + child: SelectButton(
96 + image: Image.asset(
97 + walletTypeToCryptoCurrency(type).iconPath ?? '',
98 + height: 24,
99 + width: 24),
100 + text: walletTypeToDisplayName(type),
101 + showTrailingIcon: false,
102 + height: 54,
103 + isSelected: selected == type,
104 + onTap: () => setState(() => selected = type)),
105 + ))
106 + ],
107 + ),
108 + bottomSectionPadding: EdgeInsets.only(left: 24, right: 24, bottom: 24),
109 + bottomSection: PrimaryButton(
110 + onPressed: () => onTypeSelected(),
111 + text: S.of(context).seed_language_next,
112 + color: Theme.of(context).accentTextTheme!.bodyLarge!.color!,
113 + textColor: Colors.white,
114 + isDisabled: selected == null,
115 + ),
116 + ),
117 + ),
118 + ],
119 + )));
120 }
121
122 Future<void> onTypeSelected() async {
lib/src/screens/new_wallet/widgets/select_button.dart
+6 -2
@@ -6,12 +6,16 @@ class SelectButton extends StatelessWidget {
6 required this.onTap,
7 this.image,
8 this.isSelected = false,
9 + this.showTrailingIcon = true,
10 + this.height = 60,
11 });
12
13 final Image? image;
14 final String text;
15 final bool isSelected;
16 final VoidCallback onTap;
17 + final bool showTrailingIcon;
18 + final double height;
19
20 @override
21 Widget build(BuildContext context) {
@@ -44,7 +48,7 @@ class SelectButton extends StatelessWidget {
48 onTap: onTap,
49 child: Container(
50 width: double.infinity,
47 - height: 60,
51 + height: height,
52 padding: EdgeInsets.only(left: 30, right: 30),
53 alignment: Alignment.center,
54 decoration: BoxDecoration(
@@ -76,7 +80,7 @@ class SelectButton extends StatelessWidget {
80 )
81 ],
82 ),
79 - selectArrowImage
83 + if (showTrailingIcon) selectArrowImage
84 ],
85 ),
86 ),
lib/src/widgets/picker.dart
+2 -31
@@ -1,5 +1,6 @@
1 // ignore_for_file: deprecated_member_use
2
3 +import 'package:cake_wallet/src/widgets/search_bar_widget.dart';
4 import 'package:cake_wallet/utils/responsive_layout_util.dart';
5 import 'package:flutter/material.dart';
6 import 'package:cw_core/currency.dart';
@@ -158,37 +159,7 @@ class _PickerState<Item> extends State<Picker<Item>> {
159 if (widget.hintText != null)
160 Padding(
161 padding: const EdgeInsets.all(16),
161 - child: TextFormField(
162 - controller: searchController,
163 - style: TextStyle(
164 - color: Theme.of(context)
165 - .primaryTextTheme!
166 - .titleLarge!
167 - .color!),
168 - decoration: InputDecoration(
169 - hintText: widget.hintText,
170 - prefixIcon:
171 - Image.asset("assets/images/search_icon.png"),
172 - filled: true,
173 - fillColor: Theme.of(context)
174 - .accentTextTheme!
175 - .displaySmall!
176 - .color!,
177 - alignLabelWithHint: false,
178 - contentPadding: const EdgeInsets.symmetric(
179 - vertical: 4, horizontal: 16),
180 - enabledBorder: OutlineInputBorder(
181 - borderRadius: BorderRadius.circular(14),
182 - borderSide: const BorderSide(
183 - color: Colors.transparent,
184 - )),
185 - focusedBorder: OutlineInputBorder(
186 - borderRadius: BorderRadius.circular(14),
187 - borderSide: const BorderSide(
188 - color: Colors.transparent,
189 - )),
190 - ),
191 - ),
162 + child: SearchBarWidget(searchController: searchController),
163 ),
164 Divider(
165 color: Theme.of(context)
lib/src/widgets/search_bar_widget.dart new
+40
@@ -0,0 +1,40 @@
1 +import 'package:flutter/material.dart';
2 +import 'package:cake_wallet/generated/i18n.dart';
3 +
4 +class SearchBarWidget extends StatelessWidget {
5 + const SearchBarWidget({
6 + required this.searchController,
7 + this.hintText,
8 + this.borderRadius = 14,
9 + });
10 +
11 + final TextEditingController searchController;
12 + final String? hintText;
13 + final double borderRadius;
14 +
15 + @override
16 + Widget build(BuildContext context) {
17 + return TextFormField(
18 + controller: searchController,
19 + style: TextStyle(color: Theme.of(context).primaryTextTheme!.titleLarge!.color!),
20 + decoration: InputDecoration(
21 + hintText: hintText ?? S.of(context).search_currency,
22 + prefixIcon: Image.asset("assets/images/search_icon.png"),
23 + filled: true,
24 + fillColor: Theme.of(context).accentTextTheme!.displaySmall!.color!,
25 + alignLabelWithHint: false,
26 + contentPadding: const EdgeInsets.symmetric(vertical: 4, horizontal: 16),
27 + enabledBorder: OutlineInputBorder(
28 + borderRadius: BorderRadius.circular(borderRadius),
29 + borderSide: const BorderSide(
30 + color: Colors.transparent,
31 + )),
32 + focusedBorder: OutlineInputBorder(
33 + borderRadius: BorderRadius.circular(borderRadius),
34 + borderSide: const BorderSide(
35 + color: Colors.transparent,
36 + )),
37 + ),
38 + );
39 + }
40 +}