CAKE-329 | reworked unspent_coins_list_page.dart and unspent_coins_list_item.dart; fixed standard_checkbox.dart; applied unspent coins control only to btc wallet

OleksandrSobol committed May 31, 2021 at 21:04 UTC b1add664ad5b762618190c3ad8e9e5f4c24600bf
7 files changed +209 -118
lib/palette.dart
+1
@@ -44,6 +44,7 @@ class Palette {
44 static const Color dullGray = Color.fromRGBO(98, 98, 98, 1.0);
45 static const Color protectiveBlue = Color.fromRGBO(33, 148, 255, 1.0);
46 static const Color darkBlue = Color.fromRGBO(109, 128, 178, 1.0);
47 + static const Color paleCornflowerBlue = Color.fromRGBO(185, 196, 237, 1.0);
48 }
49
50 class PaletteDark {
lib/src/screens/send/send_page.dart
+41 -30
@@ -425,7 +425,31 @@ class SendPage extends BasePage {
425 ],
426 ),
427 ),
428 - ))
428 + )),
429 + if (sendViewModel.isBitcoinWallet) Padding(
430 + padding: EdgeInsets.only(top: 6),
431 + child: GestureDetector(
432 + onTap: () => Navigator.of(context)
433 + .pushNamed(Routes.unspentCoinsList),
434 + child: Row(
435 + mainAxisAlignment:
436 + MainAxisAlignment.spaceBetween,
437 + children: [
438 + Text(
439 + 'Coin control (optional)',
440 + style: TextStyle(
441 + fontSize: 12,
442 + fontWeight: FontWeight.w600,
443 + color: Colors.white)),
444 + Icon(
445 + Icons.arrow_forward_ios,
446 + size: 12,
447 + color: Colors.white,
448 + )
449 + ],
450 + )
451 + )
452 + )
453 ],
454 ),
455 )
@@ -558,35 +582,22 @@ class SendPage extends BasePage {
582 ),
583 bottomSectionPadding:
584 EdgeInsets.only(left: 24, right: 24, bottom: 24),
561 - bottomSection: Column(
562 - children: [
563 - Observer(builder: (_) {
564 - return LoadingPrimaryButton(
565 - onPressed: () async {
566 - if (_formKey.currentState.validate()) {
567 - await sendViewModel.createTransaction();
568 - }
569 - },
570 - text: S.of(context).send,
571 - color: Theme.of(context).accentTextTheme.body2.color,
572 - textColor: Colors.white,
573 - isLoading: sendViewModel.state is IsExecutingState ||
574 - sendViewModel.state is TransactionCommitting,
575 - isDisabled:
576 - false // FIXME !(syncStore.status is SyncedSyncStatus),
577 - );
578 - }),
579 - Padding(
580 - padding: EdgeInsets.only(top: 12),
581 - child: PrimaryButton(
582 - onPressed: () => Navigator.of(context).pushNamed(Routes.unspentCoinsList),
583 - text: 'Unspent coins',
584 - color: Colors.green,
585 - textColor: Colors.white,
586 - )
587 - )
588 - ],
589 - )),
585 + bottomSection: Observer(builder: (_) {
586 + return LoadingPrimaryButton(
587 + onPressed: () async {
588 + if (_formKey.currentState.validate()) {
589 + await sendViewModel.createTransaction();
590 + }
591 + },
592 + text: S.of(context).send,
593 + color: Theme.of(context).accentTextTheme.body2.color,
594 + textColor: Colors.white,
595 + isLoading: sendViewModel.state is IsExecutingState ||
596 + sendViewModel.state is TransactionCommitting,
597 + isDisabled:
598 + false // FIXME !(syncStore.status is SyncedSyncStatus),
599 + );
600 + })),
601 ));
602 }
603
lib/src/screens/unspent_coins/unspent_coins_list_page.dart
+52 -18
@@ -1,10 +1,12 @@
1 import 'package:cake_wallet/src/screens/unspent_coins/widgets/unspent_coins_list_item.dart';
2 -import 'package:cake_wallet/src/widgets/standard_list.dart';
2 +import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
3 +import 'package:cake_wallet/utils/show_pop_up.dart';
4 import 'package:cake_wallet/view_model/unspent_coins/unspent_coins_list_view_model.dart';
5 import 'package:flutter/material.dart';
6 import 'package:flutter/cupertino.dart';
7 import 'package:cake_wallet/src/screens/base_page.dart';
8 import 'package:flutter_mobx/flutter_mobx.dart';
9 +import 'package:cake_wallet/generated/i18n.dart';
10
11 class UnspentCoinsListPage extends BasePage {
12 UnspentCoinsListPage({this.unspentCoinsListViewModel});
@@ -12,27 +14,59 @@ class UnspentCoinsListPage extends BasePage {
14 @override
15 String get title => 'Unspent coins';
16
17 + @override
18 + Widget trailing(BuildContext context) {
19 + final questionImage = Image.asset('assets/images/question_mark.png',
20 + color: Theme.of(context).primaryTextTheme.title.color);
21 +
22 + return SizedBox(
23 + height: 20.0,
24 + width: 20.0,
25 + child: ButtonTheme(
26 + minWidth: double.minPositive,
27 + child: FlatButton(
28 + highlightColor: Colors.transparent,
29 + splashColor: Colors.transparent,
30 + padding: EdgeInsets.all(0),
31 + onPressed: () => showPopUp<void>(
32 + context: context,
33 + builder: (BuildContext context) {
34 + return AlertWithOneAction(
35 + alertTitle: '',
36 + alertContent: 'Information about unspent coins',
37 + buttonText: S.of(context).ok,
38 + buttonAction: () => Navigator.of(context).pop());
39 + }),
40 + child: questionImage),
41 + ),
42 + );
43 + }
44 +
45 final UnspentCoinsListViewModel unspentCoinsListViewModel;
46
47 @override
48 Widget body(BuildContext context) {
19 - return Observer(builder: (_) => SectionStandardList(
20 - sectionCount: 1,
21 - itemCounter: (int _) => unspentCoinsListViewModel.items.length,
22 - itemBuilder: (_, __, index) {
23 - final item = unspentCoinsListViewModel.items[index];
49 + return Container(
50 + padding: EdgeInsets.fromLTRB(24, 12, 24, 24),
51 + child: Observer(
52 + builder: (_) => ListView.separated(
53 + itemCount: unspentCoinsListViewModel.items.length,
54 + separatorBuilder: (_, __) =>
55 + SizedBox(height: 15),
56 + itemBuilder: (_, int index) {
57 + final item = unspentCoinsListViewModel.items[index];
58
25 - return GestureDetector(
26 - onTap: () {print('Item taped');},
27 - child: UnspentCoinsListItem(
28 - address: item.address,
29 - amount: item.amount,
30 - isFrozen: item.isFrozen,
31 - note: item.note,
32 - isSending: item.isSending,
33 - onCheckBoxTap: (value) {print('CheckBox taped');},
34 - ));
35 - }));
59 + return GestureDetector(
60 + onTap: () {print('Item taped');},
61 + child: UnspentCoinsListItem(
62 + address: item.address,
63 + amount: item.amount,
64 + isSending: item.isSending,
65 + onCheckBoxTap: (value) {},
66 + ));
67 + }
68 + )
69 + )
70 + );
71 }
37 -
72 }
\ No newline at end of file
lib/src/screens/unspent_coins/widgets/unspent_coins_list_item.dart
+74 -47
@@ -1,74 +1,101 @@
1 import 'package:auto_size_text/auto_size_text.dart';
2 +import 'package:cake_wallet/palette.dart';
3 import 'package:cake_wallet/src/widgets/standard_checkbox.dart';
4 import 'package:flutter/material.dart';
5 import 'package:flutter/cupertino.dart';
6
6 -class UnspentCoinsListItem extends StatelessWidget {
7 +class UnspentCoinsListItem extends StatefulWidget {
8 UnspentCoinsListItem({
9 @required this.address,
10 @required this.amount,
10 - @required this.isFrozen,
11 - @required this.note,
11 @required this.isSending,
12 @required this.onCheckBoxTap,
14 -});
13 + });
14
15 final String address;
16 final String amount;
18 - final bool isFrozen;
19 - final String note;
17 final bool isSending;
18 final Function(bool) onCheckBoxTap;
19
20 + @override UnspentCoinsListItemState createState() =>
21 + UnspentCoinsListItemState(
22 + address: address,
23 + amount: amount,
24 + isSending: isSending,
25 + onCheckBoxTap: onCheckBoxTap
26 + );
27 +
28 +}
29 +
30 +class UnspentCoinsListItemState extends State<UnspentCoinsListItem> {
31 + UnspentCoinsListItemState({
32 + @required this.address,
33 + @required this.amount,
34 + @required this.isSending,
35 + @required this.onCheckBoxTap,
36 + }) : checkBoxValue = isSending;
37 +
38 + static const amountColor = Palette.darkBlueCraiola;
39 + static const addressColor = Palette.darkGray;
40 + static const selectedItemColor = Palette.paleCornflowerBlue;
41 + static const unselectedItemColor = Palette.moderateLavender;
42 +
43 + final String address;
44 + final String amount;
45 + final bool isSending;
46 + final Function(bool) onCheckBoxTap;
47 +
48 + bool checkBoxValue;
49 +
50 @override
51 Widget build(BuildContext context) {
25 - final textStyle = TextStyle(
26 - fontSize: 16,
27 - fontWeight: FontWeight.w500,
28 - color: Theme.of(context)
29 - .primaryTextTheme
30 - .title
31 - .color);
52 + final itemColor = checkBoxValue? selectedItemColor : unselectedItemColor;
53
54 return Container(
34 - padding: EdgeInsets.fromLTRB(24, 16, 24, 16),
35 - color: Theme.of(context).backgroundColor,
36 - child: Column(
37 - crossAxisAlignment: CrossAxisAlignment.start,
55 + height: 62,
56 + padding: EdgeInsets.all(12),
57 + decoration: BoxDecoration(
58 + borderRadius: BorderRadius.all(Radius.circular(12)),
59 + color: itemColor),
60 + child: Row(
61 + mainAxisSize: MainAxisSize.max,
62 + crossAxisAlignment: CrossAxisAlignment.center,
63 children: [
39 - Text(
40 - address ?? 'Address',
41 - style: textStyle,
42 - ),
43 - Padding(
44 - padding: EdgeInsets.only(top: 12),
45 - child: Text(
46 - amount ?? 'Amount',
47 - style: textStyle,
48 - )
49 - ),
50 - if (isFrozen ?? false) Padding(
51 - padding: EdgeInsets.only(top: 12),
52 - child: Text(
53 - 'Freeze',
54 - style: textStyle,
55 - )
56 - ),
57 - if (note?.isNotEmpty ?? false) Padding(
58 - padding: EdgeInsets.only(top: 12),
59 - child: AutoSizeText(
60 - note,
61 - style: textStyle,
62 - maxLines: 1
63 - )
64 - ),
64 Padding(
66 - padding: EdgeInsets.only(top: 12),
65 + padding: EdgeInsets.only(right: 12),
66 child: StandardCheckbox(
68 - value: isSending,
69 - caption: 'Sending',
70 - onChanged: onCheckBoxTap
67 + value: checkBoxValue,
68 + onChanged: (value) {
69 + onCheckBoxTap(value);
70 + checkBoxValue = value;
71 + setState(() {});
72 + }
73 )
74 + ),
75 + Expanded(
76 + child: Column(
77 + mainAxisAlignment: MainAxisAlignment.spaceBetween,
78 + crossAxisAlignment: CrossAxisAlignment.start,
79 + children: [
80 + AutoSizeText(
81 + amount ?? 'Amount',
82 + style: TextStyle(
83 + color: amountColor,
84 + fontSize: 16,
85 + fontWeight: FontWeight.w600
86 + ),
87 + maxLines: 1,
88 + ),
89 + AutoSizeText(
90 + address ?? 'Address',
91 + style: TextStyle(
92 + color: addressColor,
93 + fontSize: 12,
94 + ),
95 + maxLines: 1,
96 + )
97 + ]
98 + )
99 )
100 ],
101 )
lib/src/widgets/standard_checkbox.dart
+11 -11
@@ -44,9 +44,6 @@ class StandardCheckboxState extends State<StandardCheckbox> {
44 Container(
45 height: 24.0,
46 width: 24.0,
47 - margin: EdgeInsets.only(
48 - right: 10.0,
49 - ),
47 decoration: BoxDecoration(
48 border: Border.all(
49 color: Theme.of(context)
@@ -65,14 +62,17 @@ class StandardCheckboxState extends State<StandardCheckbox> {
62 )
63 : Offstage(),
64 ),
68 - Text(
69 - caption,
70 - style: TextStyle(
71 - fontSize: 16.0,
72 - color: Theme.of(context)
73 - .primaryTextTheme
74 - .title
75 - .color),
65 + if (caption.isNotEmpty) Padding(
66 + padding: EdgeInsets.only(left: 10),
67 + child: Text(
68 + caption,
69 + style: TextStyle(
70 + fontSize: 16.0,
71 + color: Theme.of(context)
72 + .primaryTextTheme
73 + .title
74 + .color),
75 + )
76 )
77 ],
78 ),
lib/view_model/send/send_view_model.dart
+5
@@ -55,6 +55,8 @@ abstract class SendViewModelBase with Store {
55 _settingsStore.priority[_wallet.type] = priorities.first;
56 }
57
58 + isBitcoinWallet = _wallet is BitcoinWallet;
59 +
60 _setCryptoNumMaximumFractionDigits();
61 }
62
@@ -182,6 +184,9 @@ abstract class SendViewModelBase with Store {
184 @observable
185 PendingTransaction pendingTransaction;
186
187 + @observable
188 + bool isBitcoinWallet;
189 +
190 @computed
191 String get balance => _wallet.balance.formattedAvailableBalance ?? '0.0';
192
lib/view_model/unspent_coins/unspent_coins_list_view_model.dart
+25 -12
@@ -5,32 +5,45 @@ part 'unspent_coins_list_view_model.g.dart';
5
6 const List<Map<String, dynamic>> unspentCoinsMap = [
7 <String, dynamic>{
8 - "address" : "11111111111111121111132432432432432432432443124324324234324324324324332424",
9 - "amount" : "222",
8 + "address" : "bc1qm80mu5p3mf04a7cj7teymasf04dwpc3av2fwtr",
9 + "amount" : "0.00358 BTC",
10 "isFrozen" : true,
11 "note" : "333cvgf23132132132132131321321314rwrtdggfdddewq ewqasfdxgdhgfgfszczcxgbhhhbcgbc"},
12 <String, dynamic>{
13 - "address" : "444",
14 - "amount" : "555",
13 + "address" : "bc1qm80mu5p3mf04a7cj7teymasf04dwpc3av2fwtr",
14 + "amount" : "0.00567894 BTC",
15 "note" : "sfjskf"},
16 <String, dynamic>{
17 - "address" : "777",
18 - "amount" : "888",
17 + "address" : "bc1qm80mu5p3mf04a7cj7teymasf04dwpc3av2fwtr",
18 + "amount" : "0.00087 BTC",
19 "isFrozen" : false},
20 <String, dynamic>{
21 - "address" : "11111111111111121111132432432432432432432443124324324234324324324324332424",
22 - "amount" : "222",
21 + "address" : "bc1qm80mu5p3mf04a7cj7teymasf04dwpc3av2fwtr",
22 + "amount" : "0.00012 BTC",
23 "isFrozen" : true,
24 "note" : "333cvgf23132132132132131321321314rwrtdggfdddewq ewqasfdxgdhgfgfszczcxgbhhhbcgbc"},
25 <String, dynamic>{
26 - "address" : "444",
27 - "amount" : "555",
26 + "address" : "bc1qm80mu5p3mf04a7cj7teymasf04dwpc3av2fwtr",
27 + "amount" : "0.00574 BTC",
28 "note" : "sffsfsdsgs"},
29 <String, dynamic>{
30 - "address" : "777",
31 - "amount" : "888",
30 + "address" : "bc1qm80mu5p3mf04a7cj7teymasf04dwpc3av2fwtr",
31 + "amount" : "0.000482 BTC",
32 "isFrozen" : false},
33 <String, dynamic>{},
34 + <String, dynamic>{
35 + "address" : "bc1qm80mu5p3mf04a7cj7teymasf04dwpc3av2fwtr",
36 + "amount" : "0.00012 BTC",
37 + "isFrozen" : true,
38 + "note" : "333cvgf23132132132132131321321314rwrtdggfdddewq ewqasfdxgdhgfgfszczcxgbhhhbcgbc"},
39 + <String, dynamic>{
40 + "address" : "bc1qm80mu5p3mf04a7cj7teymasf04dwpc3av2fwtr",
41 + "amount" : "0.00574 BTC",
42 + "note" : "sffsfsdsgs"},
43 + <String, dynamic>{
44 + "address" : "bc1qm80mu5p3mf04a7cj7teymasf04dwpc3av2fwtr",
45 + "amount" : "0.000482 BTC",
46 + "isFrozen" : false},
47 ];
48
49 class UnspentCoinsListViewModel = UnspentCoinsListViewModelBase with _$UnspentCoinsListViewModel;