Cw 372 improve monero haven account selection picker (#939)
* refactor: Improve Monero/Haven account selection picker * feat: If the amount would be wrapped, instead display it under the account name * fix: balance str * refactor: add theme changes * refactor: remove duplicate observer
Rafael Saes committed
Jul 10, 2023 at 21:40 UTC
cb0ca169fbd0ba5397a2e6402e8558de6b6b2771
3 files changed
+182
-172
lib/src/screens/monero_accounts/monero_account_list_page.dart
+65
-147
@@ -1,176 +1,94 @@
1
+import 'package:cake_wallet/src/widgets/picker_inner_wrapper_widget.dart';
2
import 'package:cake_wallet/src/widgets/section_divider.dart';
2
-import 'package:cake_wallet/utils/responsive_layout_util.dart';
3
import 'package:flutter/material.dart';
4
import 'package:flutter_mobx/flutter_mobx.dart';
5
import 'package:cake_wallet/routes.dart';
6
import 'package:cake_wallet/generated/i18n.dart';
7
import 'package:cake_wallet/view_model/monero_account_list/monero_account_list_view_model.dart';
8
import 'package:cake_wallet/src/screens/monero_accounts/widgets/account_tile.dart';
9
-import 'package:cake_wallet/src/widgets/alert_background.dart';
10
-import 'package:cake_wallet/src/widgets/cake_scrollbar.dart';
11
-import 'package:cake_wallet/src/widgets/alert_close_button.dart';
9
10
class MoneroAccountListPage extends StatelessWidget {
14
- MoneroAccountListPage({required this.accountListViewModel})
15
- : backgroundHeight = 194,
16
- thumbHeight = 72,
17
- isAlwaysShowScrollThumb = false,
18
- controller = ScrollController() {
19
- controller.addListener(() {
20
- final scrollOffsetFromTop = controller.hasClients
21
- ? (controller.offset / controller.position.maxScrollExtent * (backgroundHeight - thumbHeight))
22
- : 0.0;
23
- accountListViewModel.setScrollOffsetFromTop(scrollOffsetFromTop);
24
- });
25
- }
11
+ MoneroAccountListPage({required this.accountListViewModel});
12
13
final MoneroAccountListViewModel accountListViewModel;
28
-
29
- ScrollController controller;
30
- double backgroundHeight;
31
- double thumbHeight;
32
- bool isAlwaysShowScrollThumb;
14
+ final ScrollController controller = ScrollController();
15
16
@override
17
Widget build(BuildContext context) {
36
- return AlertBackground(
37
- child: Column(
18
+ double itemHeight = 80;
19
+ double buttonHeight = 62;
20
+
21
+ return Observer(builder: (_) {
22
+ final accounts = accountListViewModel.accounts;
23
+
24
+ return PickerInnerWrapperWidget(
25
+ title: S.of(context).choose_account,
26
+ itemsHeight: (itemHeight * accounts.length) + buttonHeight,
27
children: [
28
Expanded(
40
- child: Stack(
41
- alignment: Alignment.center,
42
- children: <Widget>[
43
- Column(
29
+ child: Scrollbar(
30
+ controller: controller,
31
+ child: ListView.separated(
32
+ padding: EdgeInsets.zero,
33
+ controller: controller,
34
+ separatorBuilder: (context, index) => const SectionDivider(),
35
+ itemCount: accounts.length,
36
+ itemBuilder: (context, index) {
37
+ final account = accounts[index];
38
+
39
+ return AccountTile(
40
+ isCurrent: account.isSelected,
41
+ accountName: account.label,
42
+ accountBalance: account.balance ?? '0.00',
43
+ currency: accountListViewModel.currency.toString(),
44
+ onTap: () {
45
+ if (account.isSelected) {
46
+ return;
47
+ }
48
+
49
+ accountListViewModel.select(account);
50
+ Navigator.of(context).pop();
51
+ },
52
+ onEdit: () async => await Navigator.of(context)
53
+ .pushNamed(Routes.accountCreation, arguments: account));
54
+ },
55
+ ),
56
+ )),
57
+ GestureDetector(
58
+ onTap: () async =>
59
+ await Navigator.of(context).pushNamed(Routes.accountCreation),
60
+ child: Container(
61
+ height: buttonHeight,
62
+ color: Theme.of(context).cardColor,
63
+ padding: EdgeInsets.symmetric(horizontal: 24),
64
+ child: Center(
65
+ child: Row(
66
mainAxisSize: MainAxisSize.min,
67
children: <Widget>[
46
- Container(
47
- padding: EdgeInsets.only(left: 24, right: 24),
48
- child: Text(
49
- S.of(context).choose_account,
50
- textAlign: TextAlign.center,
51
- style: TextStyle(
52
- fontSize: 18,
53
- fontWeight: FontWeight.bold,
54
- fontFamily: 'Lato',
55
- decoration: TextDecoration.none,
56
- color: Colors.white
57
- ),
58
- ),
68
+ Icon(
69
+ Icons.add,
70
+ color: Colors.white,
71
),
72
Padding(
61
- padding: EdgeInsets.only(left: 24, right: 24, top: 24),
62
- child: GestureDetector(
63
- onTap: () => null,
64
- child: ClipRRect(
65
- borderRadius: BorderRadius.all(Radius.circular(14)),
66
- child: Container(
67
- height: 296,
68
- color: Theme.of(context).textTheme!.displayLarge!.decorationColor!,
69
- child: Column(
70
- children: <Widget>[
71
- Expanded(
72
- child: Observer(
73
- builder: (_) {
74
- final accounts = accountListViewModel.accounts;
75
- isAlwaysShowScrollThumb = accounts == null
76
- ? false
77
- : accounts.length > 3;
78
-
79
- return Stack(
80
- alignment: Alignment.center,
81
- children: <Widget>[
82
- ListView.separated(
83
- padding: EdgeInsets.zero,
84
- controller: controller,
85
- separatorBuilder: (context, index) =>
86
- const SectionDivider(),
87
- itemCount: accounts.length ?? 0,
88
- itemBuilder: (context, index) {
89
- final account = accounts[index];
90
-
91
- return AccountTile(
92
- isCurrent: account.isSelected,
93
- accountName: account.label,
94
- accountBalance: account.balance ?? '0.00',
95
- currency: accountListViewModel
96
- .currency.toString(),
97
- onTap: () {
98
- if (account.isSelected) {
99
- return;
100
- }
101
-
102
- accountListViewModel
103
- .select(account);
104
- Navigator.of(context).pop();
105
- },
106
- onEdit: () async =>
107
- await Navigator.of(context)
108
- .pushNamed(
109
- Routes.accountCreation,
110
- arguments: account));
111
- },
112
- ),
113
- isAlwaysShowScrollThumb
114
- ? CakeScrollbar(
115
- backgroundHeight: backgroundHeight,
116
- thumbHeight: thumbHeight,
117
- fromTop: accountListViewModel
118
- .scrollOffsetFromTop
119
- )
120
- : Offstage(),
121
- ],
122
- );
123
- }
124
- )
125
- ),
126
- GestureDetector(
127
- onTap: () async => await Navigator.of(context)
128
- .pushNamed(Routes.accountCreation),
129
- child: Container(
130
- height: 62,
131
- color: Theme.of(context).cardColor,
132
- padding: EdgeInsets.only(left: 24, right: 24),
133
- child: Center(
134
- child: Row(
135
- mainAxisSize: MainAxisSize.min,
136
- children: <Widget>[
137
- Icon(
138
- Icons.add,
139
- color: Colors.white,
140
- ),
141
- Padding(
142
- padding: EdgeInsets.only(left: 5),
143
- child: Text(
144
- S.of(context).create_new_account,
145
- style: TextStyle(
146
- fontSize: 15,
147
- fontWeight: FontWeight.w600,
148
- fontFamily: 'Lato',
149
- color: Colors.white,
150
- decoration: TextDecoration.none,
151
- ),
152
- ),
153
- )
154
- ],
155
- ),
156
- ),
157
- ),
158
- )
159
- ],
160
- ),
161
- ),
73
+ padding: EdgeInsets.only(left: 5),
74
+ child: Text(
75
+ S.of(context).create_new_account,
76
+ style: TextStyle(
77
+ fontSize: 15,
78
+ fontWeight: FontWeight.w600,
79
+ fontFamily: 'Lato',
80
+ color: Colors.white,
81
+ decoration: TextDecoration.none,
82
),
83
),
84
)
85
],
86
),
167
- SizedBox(height: ResponsiveLayoutUtil.kPopupSpaceHeight),
168
- AlertCloseButton()
169
- ],
87
+ ),
88
),
171
- ),
89
+ )
90
],
173
- ),
174
- );
91
+ );
92
+ });
93
}
94
}
lib/src/screens/monero_accounts/widgets/account_tile.dart
+26
-25
@@ -1,14 +1,13 @@
1
import 'package:flutter/material.dart';
2
3
class AccountTile extends StatelessWidget {
4
- AccountTile({
5
- required this.isCurrent,
6
- required this.accountName,
7
- this.accountBalance,
8
- required this.currency,
9
- required this.onTap,
10
- required this.onEdit
11
- });
4
+ AccountTile(
5
+ {required this.isCurrent,
6
+ required this.accountName,
7
+ this.accountBalance,
8
+ required this.currency,
9
+ required this.onTap,
10
+ required this.onEdit});
11
12
final bool isCurrent;
13
final String accountName;
@@ -32,11 +31,13 @@ class AccountTile extends StatelessWidget {
31
height: 77,
32
padding: EdgeInsets.only(left: 24, right: 24),
33
color: color,
35
- child: Row(
36
- mainAxisAlignment: MainAxisAlignment.spaceBetween,
34
+ child: Wrap(
35
+ direction: Axis.horizontal,
36
+ alignment: WrapAlignment.spaceBetween,
37
+ runAlignment: WrapAlignment.center,
38
+ crossAxisAlignment: WrapCrossAlignment.center,
39
children: [
38
- Expanded(
39
- flex: 2,
40
+ Container(
41
child: Text(
42
accountName,
43
style: TextStyle(
@@ -49,19 +50,19 @@ class AccountTile extends StatelessWidget {
50
),
51
),
52
if (accountBalance != null)
52
- Expanded(
53
- child: Text(
54
- '${accountBalance.toString()} $currency',
55
- textAlign: TextAlign.end,
56
- style: TextStyle(
57
- fontSize: 15,
58
- fontWeight: FontWeight.w600,
59
- fontFamily: 'Lato',
60
- color: Theme.of(context).textTheme!.headlineMedium!.color!,
61
- decoration: TextDecoration.none,
53
+ Container(
54
+ child: Text(
55
+ '${accountBalance.toString()} $currency',
56
+ textAlign: TextAlign.end,
57
+ style: TextStyle(
58
+ fontSize: 15,
59
+ fontWeight: FontWeight.w600,
60
+ fontFamily: 'Lato',
61
+ color: Theme.of(context).textTheme!.headlineMedium!.color!,
62
+ decoration: TextDecoration.none,
63
+ ),
64
),
63
- ),
64
- ),
65
+ ),
66
],
67
),
68
),
@@ -80,4 +81,4 @@ class AccountTile extends StatelessWidget {
81
// onTap: () => onEdit?.call())
82
// ]);
83
}
83
-}
\ No newline at end of file
84
+}
lib/src/widgets/picker_inner_wrapper_widget.dart
new
+91
@@ -0,0 +1,91 @@
1
+import 'package:cake_wallet/utils/responsive_layout_util.dart';
2
+import 'package:flutter/material.dart';
3
+import 'package:cake_wallet/src/widgets/picker_wrapper_widget.dart';
4
+
5
+class PickerInnerWrapperWidget extends StatelessWidget {
6
+ PickerInnerWrapperWidget(
7
+ {required this.children, this.title, this.itemsHeight});
8
+
9
+ final List<Widget> children;
10
+ final String? title;
11
+ final double? itemsHeight;
12
+
13
+ @override
14
+ Widget build(BuildContext context) {
15
+ final mq = MediaQuery.of(context);
16
+ final bottom = mq.viewInsets.bottom;
17
+ final height = mq.size.height - bottom;
18
+
19
+ double containerHeight = height * 0.65;
20
+ if (bottom > 0) {
21
+ // increase a bit or it gets too squished in the top
22
+ containerHeight = height * 0.75;
23
+ }
24
+
25
+ if (title != null) {
26
+ return PickerWrapperWidget(
27
+ hasTitle: true,
28
+ children: <Widget>[
29
+ Container(
30
+ padding: EdgeInsets.symmetric(horizontal: 24),
31
+ child: Text(
32
+ title!,
33
+ textAlign: TextAlign.center,
34
+ style: TextStyle(
35
+ fontSize: 18,
36
+ fontWeight: FontWeight.bold,
37
+ fontFamily: 'Lato',
38
+ decoration: TextDecoration.none,
39
+ color: Colors.white),
40
+ ),
41
+ ),
42
+ Padding(
43
+ padding: EdgeInsets.symmetric(horizontal: 24),
44
+ child: ClipRRect(
45
+ borderRadius: BorderRadius.all(Radius.circular(14)),
46
+ child: Container(
47
+ color: Theme.of(context).textTheme.displayLarge!.decorationColor!,
48
+ child: ConstrainedBox(
49
+ constraints: BoxConstraints(
50
+ maxHeight:
51
+ itemsHeight != null && itemsHeight! <= containerHeight
52
+ ? itemsHeight!
53
+ : containerHeight,
54
+ maxWidth: ResponsiveLayoutUtil.kPopupWidth,
55
+ ),
56
+ child: Column(
57
+ children: children,
58
+ ),
59
+ ),
60
+ ),
61
+ ),
62
+ )
63
+ ],
64
+ );
65
+ }
66
+
67
+ return PickerWrapperWidget(
68
+ hasTitle: false,
69
+ children: <Widget>[
70
+ Padding(
71
+ padding: EdgeInsets.symmetric(horizontal: 24),
72
+ child: ClipRRect(
73
+ borderRadius: BorderRadius.all(Radius.circular(14)),
74
+ child: Container(
75
+ color: Theme.of(context).textTheme.displayLarge!.decorationColor!,
76
+ child: ConstrainedBox(
77
+ constraints: BoxConstraints(
78
+ maxHeight: containerHeight,
79
+ maxWidth: ResponsiveLayoutUtil.kPopupWidth,
80
+ ),
81
+ child: Column(
82
+ children: children,
83
+ ),
84
+ ),
85
+ ),
86
+ ),
87
+ )
88
+ ],
89
+ );
90
+ }
91
+}