Cw 09 implement picker screen with ability to search (#250)

* Added new picker screen with search bar and currency icons

Serhii committed Mar 31, 2022 at 17:16 UTC 1cd90cf57d0149bd72f1ed77c5ed1bc320720421
40 files changed +578 -279
assets/images/ada_icon.png
Binary files /dev/null and b/assets/images/ada_icon.png differ
assets/images/bch_icon.png
Binary files /dev/null and b/assets/images/bch_icon.png differ
assets/images/bitcoin_icon.png
Binary files /dev/null and b/assets/images/bitcoin_icon.png differ
assets/images/bnb_icon.png
Binary files /dev/null and b/assets/images/bnb_icon.png differ
assets/images/btc.png
Binary files /dev/null and b/assets/images/btc.png differ
assets/images/dai_icon.png
Binary files /dev/null and b/assets/images/dai_icon.png differ
assets/images/dash_icon.png
Binary files /dev/null and b/assets/images/dash_icon.png differ
assets/images/eos_icon.png
Binary files /dev/null and b/assets/images/eos_icon.png differ
assets/images/eth_icon.png
Binary files /dev/null and b/assets/images/eth_icon.png differ
assets/images/litecoin-ltc_icon.png
Binary files /dev/null and b/assets/images/litecoin-ltc_icon.png differ
assets/images/litecoin_img.png
Binary files /dev/null and b/assets/images/litecoin_img.png differ
assets/images/monero_icon.png
Binary files /dev/null and b/assets/images/monero_icon.png differ
assets/images/trx_icon.png
Binary files /dev/null and b/assets/images/trx_icon.png differ
assets/images/usdt_icon.png
Binary files /dev/null and b/assets/images/usdt_icon.png differ
assets/images/usdterc20_icon.png
Binary files /dev/null and b/assets/images/usdterc20_icon.png differ
assets/images/usdterc_icon.png
Binary files /dev/null and b/assets/images/usdterc_icon.png differ
assets/images/xlm_icon.png
Binary files /dev/null and b/assets/images/xlm_icon.png differ
assets/images/xrp_icon.png
Binary files /dev/null and b/assets/images/xrp_icon.png differ
lib/src/screens/exchange/exchange_page.dart
+2 -2
@@ -206,8 +206,8 @@ class ExchangePage extends BasePage {
206 onCurrencySelected: (currency) {
207 // FIXME: need to move it into view model
208 if (currency == CryptoCurrency.xmr &&
209 - exchangeViewModel.wallet.type ==
210 - WalletType.bitcoin) {
209 + exchangeViewModel.wallet.type !=
210 + WalletType.monero) {
211 showPopUp<void>(
212 context: context,
213 builder: (dialogContext) {
lib/src/screens/exchange/widgets/currency_picker.dart
+179 -145
@@ -1,176 +1,210 @@
1 import 'dart:ui';
2 +import 'package:cake_wallet/generated/i18n.dart';
3 import 'package:cake_wallet/palette.dart';
4 +import 'package:cake_wallet/src/screens/exchange/widgets/currency_utils.dart';
5 +import 'package:cake_wallet/src/screens/exchange/widgets/picker_item.dart';
6 import 'package:flutter/cupertino.dart';
7 import 'package:flutter/material.dart';
8 import 'package:cw_core/crypto_currency.dart';
9 import 'package:cake_wallet/src/widgets/alert_background.dart';
7 -import 'package:cake_wallet/src/widgets/alert_close_button.dart';
8 -import 'package:cake_wallet/src/widgets/cake_scrollbar.dart';
10 +import 'currency_picker_widget.dart';
11
12 class CurrencyPicker extends StatefulWidget {
11 - CurrencyPicker({
12 - @required this.selectedAtIndex,
13 - @required this.items,
14 - @required this.title,
15 - @required this.onItemSelected,
16 - });
13 + CurrencyPicker(
14 + {@required this.selectedAtIndex,
15 + @required this.items,
16 + @required this.title,
17 + @required this.onItemSelected,
18 + this.isMoneroWallet = false,
19 + this.isConvertFrom = false});
20
18 - final int selectedAtIndex;
21 + int selectedAtIndex;
22 final List<CryptoCurrency> items;
23 final String title;
24 final Function(CryptoCurrency) onItemSelected;
25 + final bool isMoneroWallet;
26 + final bool isConvertFrom;
27
28 @override
24 - CurrencyPickerState createState() => CurrencyPickerState(
25 - selectedAtIndex,
26 - items,
27 - title,
28 - onItemSelected
29 - );
29 + CurrencyPickerState createState() => CurrencyPickerState(items);
30 }
31
32 class CurrencyPickerState extends State<CurrencyPicker> {
33 - CurrencyPickerState(
34 - this.selectedAtIndex,
35 - this.items,
36 - this.title,
37 - this.onItemSelected): itemsCount = items.length;
33 + CurrencyPickerState(this.items)
34 + : isSearchBarActive = false,
35 + textFieldValue = '',
36 + subPickerItemsList = [],
37 + appBarTextStyle = TextStyle(
38 + fontSize: 20,
39 + fontFamily: 'Lato',
40 + backgroundColor: Colors.transparent,
41 + color: Colors.white);
42
39 - final int selectedAtIndex;
40 - final List<CryptoCurrency> items;
41 - final String title;
42 - final Function(CryptoCurrency) onItemSelected;
43 + @override
44 + void initState() {
45 + pickerItemsList = CryptoCurrency.all
46 + .map((CryptoCurrency cur) => PickerItem<CryptoCurrency>(cur,
47 + title: CurrencyUtils.titleForCurrency(cur),
48 + iconPath: CurrencyUtils.iconPathForCurrency(cur),
49 + tag: CurrencyUtils.tagForCurrency(cur),
50 + description: CurrencyUtils.descriptionForCurrency(cur)))
51 + .toList();
52 + cleanSubPickerItemsList();
53 + super.initState();
54 + }
55
44 - final closeButton = Image.asset('assets/images/close.png',
45 - color: Palette.darkBlueCraiola,
46 - );
47 - final int crossAxisCount = 3;
48 - final int maxNumberItemsInAlert = 12;
49 - final int itemsCount;
50 - final double backgroundHeight = 280;
51 - final double thumbHeight = 72;
52 - ScrollController controller = ScrollController();
53 - double fromTop = 0;
56 + List<PickerItem<CryptoCurrency>> pickerItemsList;
57 + List<CryptoCurrency> items;
58 + bool isSearchBarActive;
59 + String textFieldValue;
60 + List<PickerItem<CryptoCurrency>> subPickerItemsList;
61 + TextStyle appBarTextStyle;
62
55 - @override
56 - Widget build(BuildContext context) {
57 - controller.addListener(() {
58 - fromTop = controller.hasClients
59 - ? (controller.offset / controller.position.maxScrollExtent * (backgroundHeight - thumbHeight))
60 - : 0;
61 - setState(() {});
63 + void cleanSubPickerItemsList() {
64 + subPickerItemsList = pickerItemsList
65 + .where((element) => items.contains(element.original))
66 + .toList();
67 + }
68 +
69 + void currencySearchBySubstring(
70 + String subString, List<PickerItem<CryptoCurrency>> list) {
71 + setState(() {
72 + if (subString.isNotEmpty) {
73 + subPickerItemsList = subPickerItemsList
74 + .where((element) =>
75 + element.title.contains(subString.toUpperCase()) ||
76 + element.description.contains(subString.toLowerCase()))
77 + .toList();
78 + } else {
79 + cleanSubPickerItemsList();
80 + }
81 });
82 + }
83
84 + @override
85 + Widget build(BuildContext context) {
86 return AlertBackground(
65 - child: Stack(
66 - alignment: Alignment.center,
67 - children: <Widget>[
68 - Column(
69 - mainAxisSize: MainAxisSize.min,
70 - children: <Widget>[
71 - Container(
72 - padding: EdgeInsets.only(left: 24, right: 24),
73 - child: Text(
74 - title,
75 - textAlign: TextAlign.center,
76 - style: TextStyle(
77 - fontSize: 18,
78 - fontFamily: 'Lato',
79 - fontWeight: FontWeight.bold,
80 - decoration: TextDecoration.none,
81 - color: Colors.white
87 + child: SafeArea(
88 + child: Scaffold(
89 + resizeToAvoidBottomInset: false,
90 + backgroundColor: Colors.transparent,
91 + body: Column(
92 + children: [
93 + Padding(
94 + padding: EdgeInsets.symmetric(horizontal: 26.0, vertical: 0),
95 + child: Row(
96 + mainAxisAlignment: MainAxisAlignment.spaceBetween,
97 + children: [
98 + isSearchBarActive
99 + ? Expanded(
100 + child: Row(
101 + mainAxisAlignment:
102 + MainAxisAlignment.spaceBetween,
103 + children: [
104 + InkWell(
105 + child: Text(
106 + S.of(context).cancel,
107 + style: appBarTextStyle,
108 + ),
109 + onTap: () {
110 + setState(() {
111 + isSearchBarActive = false;
112 + textFieldValue = '';
113 + cleanSubPickerItemsList();
114 + });
115 + }),
116 + Container(
117 + width: 100.0,
118 + child: CupertinoTextField(
119 + autofocus: true,
120 + placeholder:
121 + S.of(context).search + '...',
122 + placeholderStyle: appBarTextStyle,
123 + decoration: BoxDecoration(
124 + color: Colors.transparent),
125 + cursorColor: Colors.white,
126 + cursorHeight: 23.0,
127 + style: appBarTextStyle,
128 + onChanged: (value) {
129 + this.textFieldValue = value;
130 + cleanSubPickerItemsList();
131 + currencySearchBySubstring(
132 + textFieldValue,
133 + subPickerItemsList);
134 + }),
135 + )
136 + ],
137 + ),
138 + )
139 + : Text(
140 + widget.title,
141 + style: appBarTextStyle,
142 + ),
143 + IconButton(
144 + splashRadius: 23,
145 + icon: Icon(Icons.search, color: Colors.white),
146 + onPressed: () {
147 + setState(() {
148 + isSearchBarActive = true;
149 + });
150 + },
151 + )
152 + ]),
153 + ),
154 + Expanded(
155 + flex: 12,
156 + child: Padding(
157 + padding: const EdgeInsets.symmetric(
158 + horizontal: 26.0, vertical: 26.0),
159 + child: Container(
160 + child: CurrencyPickerWidget(
161 + crossAxisCount: 2,
162 + selectedAtIndex: widget.selectedAtIndex,
163 + itemsCount: subPickerItemsList.length,
164 + pickerItemsList: subPickerItemsList,
165 + pickListItem: (int index) {
166 + setState(() {
167 + widget.selectedAtIndex = index;
168 + });
169 + widget
170 + .onItemSelected(subPickerItemsList[index].original);
171 + if (widget.isConvertFrom &&
172 + !widget.isMoneroWallet &&
173 + (subPickerItemsList[index].original ==
174 + CryptoCurrency.xmr)) {
175 + } else {
176 + Navigator.of(context).pop();
177 + }
178 + },
179 ),
180 ),
181 ),
85 - Padding(
86 - padding: EdgeInsets.only(top: 24),
87 - child: GestureDetector(
88 - onTap: () => null,
89 - child: ClipRRect(
90 - borderRadius: BorderRadius.all(Radius.circular(14)),
91 - child: Container(
92 - height: 320,
93 - width: 300,
94 - color: Theme.of(context).accentTextTheme.title.backgroundColor,
95 - child: Stack(
96 - alignment: Alignment.center,
97 - children: <Widget>[
98 - GridView.count(
99 - padding: EdgeInsets.all(0),
100 - controller: controller,
101 - crossAxisCount: crossAxisCount,
102 - childAspectRatio: 1.25,
103 - crossAxisSpacing: 1,
104 - mainAxisSpacing: 1,
105 - children: List.generate(
106 - itemsCount
107 - + getExtraEmptyTilesCount(crossAxisCount, itemsCount),
108 - (index) {
109 -
110 - if (index >= itemsCount) {
111 - return Container(
112 - color: Theme.of(context).accentTextTheme.title.color,
113 - );
114 - }
115 -
116 - final item = items[index];
117 - final isItemSelected = index == selectedAtIndex;
118 -
119 - final color = isItemSelected
120 - ? Theme.of(context).textTheme.body2.color
121 - : Theme.of(context).accentTextTheme.title.color;
122 - final textColor = isItemSelected
123 - ? Palette.blueCraiola
124 - : Theme.of(context).primaryTextTheme.title.color;
125 -
126 - return GestureDetector(
127 - onTap: () {
128 - if (onItemSelected == null) {
129 - return;
130 - }
131 - Navigator.of(context).pop();
132 - onItemSelected(item);
133 - },
134 - child: Container(
135 - color: color,
136 - child: Center(
137 - child: Text(
138 - item.toString(),
139 - style: TextStyle(
140 - fontSize: 15,
141 - fontFamily: 'Lato',
142 - fontWeight: FontWeight.w600,
143 - decoration: TextDecoration.none,
144 - color: textColor
145 - ),
146 - ),
147 - ),
148 - ),
149 - );
150 - })
151 - ),
152 - if (itemsCount > maxNumberItemsInAlert)
153 - CakeScrollbar(
154 - backgroundHeight: backgroundHeight,
155 - thumbHeight: thumbHeight,
156 - fromTop: fromTop
157 - )
158 - ],
159 - )
182 + ),
183 + Expanded(
184 + flex: 2,
185 + child: Container(
186 + width: 42.0,
187 + alignment: Alignment.topCenter,
188 + child: FittedBox(
189 + child: FloatingActionButton(
190 + elevation: 0,
191 + backgroundColor: Colors.white,
192 + onPressed: () {
193 + Navigator.of(context).pop();
194 + },
195 + child: Icon(
196 + Icons.close_outlined,
197 + color: Palette.darkBlueCraiola,
198 + size: 30.0,
199 ),
200 ),
201 ),
163 - )
164 - ],
165 - ),
166 - AlertCloseButton(image: closeButton)
167 - ],
168 - )
202 + ),
203 + ),
204 + ],
205 + ),
206 + ),
207 + ),
208 );
209 }
171 -
172 - int getExtraEmptyTilesCount(int crossAxisCount, int itemsCount) {
173 - final int tilesInNewRowCount = itemsCount % crossAxisCount;
174 - return tilesInNewRowCount == 0 ? 0 : crossAxisCount - tilesInNewRowCount;
175 - }
176 -}
\ No newline at end of file
210 +}
lib/src/screens/exchange/widgets/currency_picker_item_widget.dart new
+93
@@ -0,0 +1,93 @@
1 +import 'package:flutter/material.dart';
2 +import 'package:cake_wallet/palette.dart';
3 +
4 +class PickerItemWidget extends StatelessWidget {
5 + const PickerItemWidget(
6 + {this.iconPath, this.title, this.isSelected, this.tag, this.onTap});
7 +
8 + final String iconPath;
9 + final String title;
10 + final bool isSelected;
11 + final String tag;
12 + final void Function() onTap;
13 +
14 + @override
15 + Widget build(BuildContext context) {
16 + return GestureDetector(
17 + onTap: onTap,
18 + child: Container(
19 + color: isSelected
20 + ? Theme.of(context).textTheme.bodyText1.color
21 + : Theme.of(context).accentTextTheme.headline6.color,
22 + child: Center(
23 + child: Padding(
24 + padding: const EdgeInsets.all(8.0),
25 + child: Row(
26 + mainAxisAlignment: MainAxisAlignment.center,
27 + children: [
28 + Expanded(
29 + child: Container(
30 + child: Image.asset(
31 + iconPath,
32 + height: 32.0,
33 + width: 32.0,
34 + ),
35 + ),
36 + ),
37 + Expanded(
38 + child: Stack(
39 + clipBehavior: Clip.none,
40 + alignment: Alignment.centerLeft,
41 + children: [
42 + Text(
43 + title,
44 + style: TextStyle(
45 + color: isSelected
46 + ? Palette.blueCraiola
47 + : Theme.of(context).primaryTextTheme.title.color,
48 + fontSize: 18.0,
49 + fontFamily: 'Lato',
50 + ),
51 + ),
52 + tag != null
53 + ? Positioned(
54 + top: -20.0,
55 + right: 7.0,
56 + child: Container(
57 + width: 35.0,
58 + height: 18.0,
59 + child: Center(
60 + child: Text(
61 + tag,
62 + style: TextStyle(
63 + fontSize: 7.0,
64 + fontFamily: 'Lato',
65 + color: Theme.of(context)
66 + .textTheme
67 + .body1
68 + .color),
69 + ),
70 + ),
71 + decoration: BoxDecoration(
72 + borderRadius: BorderRadius.circular(6.0),
73 + //border: Border.all(color: ),
74 + color: Theme.of(context)
75 + .textTheme
76 + .body1
77 + .decorationColor,
78 + ),
79 + ),
80 + )
81 + : Container(),
82 + ],
83 + ),
84 + ),
85 + ],
86 + ),
87 + ),
88 + ),
89 + ),
90 + );
91 + ;
92 + }
93 +}
lib/src/screens/exchange/widgets/currency_picker_widget.dart new
+61
@@ -0,0 +1,61 @@
1 +import 'package:flutter/material.dart';
2 +import 'package:cw_core/crypto_currency.dart';
3 +import 'picker_item.dart';
4 +import 'currency_picker_item_widget.dart';
5 +
6 +class CurrencyPickerWidget extends StatelessWidget {
7 + const CurrencyPickerWidget({
8 + @required this.crossAxisCount,
9 + @required this.selectedAtIndex,
10 + @required this.itemsCount,
11 + @required this.pickerItemsList,
12 + @required this.pickListItem,
13 + });
14 +
15 + final int crossAxisCount;
16 + final int selectedAtIndex;
17 + final int itemsCount;
18 + final Function pickListItem;
19 + final List<PickerItem<CryptoCurrency>> pickerItemsList;
20 +
21 + @override
22 + Widget build(BuildContext context) {
23 + return LayoutBuilder(
24 + builder: (BuildContext context, BoxConstraints constraints) {
25 + return Container(
26 + decoration: BoxDecoration(
27 + color: Theme.of(context).accentTextTheme.headline6.backgroundColor,
28 + borderRadius: BorderRadius.circular(14.0),
29 + ),
30 + child: ClipRRect(
31 + borderRadius: BorderRadius.circular(14.0),
32 + child: Scrollbar(
33 + showTrackOnHover: true,
34 + isAlwaysShown: true,
35 + thickness: 6.0,
36 + radius: Radius.circular(3),
37 + child: GridView.builder(
38 + gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
39 + crossAxisCount: crossAxisCount,
40 + crossAxisSpacing: 1,
41 + mainAxisExtent: constraints.maxHeight / 8,
42 + mainAxisSpacing: 1),
43 + itemCount: pickerItemsList.length,
44 + itemBuilder: (BuildContext ctx, index) {
45 + return PickerItemWidget(
46 + onTap: () {
47 + pickListItem(index);
48 + },
49 + title: pickerItemsList[index].title,
50 + iconPath: pickerItemsList[index].iconPath,
51 + isSelected: index == selectedAtIndex,
52 + tag: pickerItemsList[index].tag,
53 + );
54 + }),
55 + ),
56 + ),
57 + );
58 + },
59 + );
60 + }
61 +}
lib/src/screens/exchange/widgets/currency_utils.dart new
+99
@@ -0,0 +1,99 @@
1 +import 'package:cw_core/crypto_currency.dart';
2 +
3 +class CurrencyUtils {
4 + static String tagForCurrency(CryptoCurrency cur) {
5 + switch (cur) {
6 + case CryptoCurrency.bnb:
7 + return 'BEP2';
8 + case CryptoCurrency.dai:
9 + return 'ETH';
10 + case CryptoCurrency.usdt:
11 + return 'OMNI';
12 + case CryptoCurrency.usdterc20:
13 + return 'ETH';
14 + default:
15 + return null;
16 + }
17 + }
18 +
19 + static String iconPathForCurrency(CryptoCurrency cur) {
20 + switch (cur) {
21 + case CryptoCurrency.xmr:
22 + return 'assets/images/monero_icon.png';
23 + case CryptoCurrency.ada:
24 + return 'assets/images/ada_icon.png';
25 + case CryptoCurrency.bch:
26 + return 'assets/images/bch_icon.png';
27 + case CryptoCurrency.bnb:
28 + return 'assets/images/bnb_icon.png';
29 + case CryptoCurrency.btc:
30 + return 'assets/images/btc.png';
31 + case CryptoCurrency.dai:
32 + return 'assets/images/dai_icon.png';
33 + case CryptoCurrency.dash:
34 + return 'assets/images/dash_icon.png';
35 + case CryptoCurrency.eos:
36 + return 'assets/images/eos_icon.png';
37 + case CryptoCurrency.eth:
38 + return 'assets/images/eth_icon.png';
39 + case CryptoCurrency.ltc:
40 + return 'assets/images/litecoin-ltc_icon.png';
41 + case CryptoCurrency.trx:
42 + return 'assets/images/trx_icon.png';
43 + case CryptoCurrency.usdt:
44 + return 'assets/images/usdt_icon.png';
45 + case CryptoCurrency.usdterc20:
46 + return 'assets/images/usdterc20_icon.png';
47 + case CryptoCurrency.xlm:
48 + return 'assets/images/xlm_icon.png';
49 + case CryptoCurrency.xrp:
50 + return 'assets/images/xrp_icon.png';
51 + default:
52 + return null;
53 + }
54 + }
55 +
56 + static String titleForCurrency(CryptoCurrency cur) {
57 + switch (cur) {
58 + case CryptoCurrency.bnb:
59 + return 'BNB';
60 + case CryptoCurrency.usdterc20:
61 + return 'USDT';
62 + default:
63 + return cur.title;
64 + }
65 + }
66 +
67 + static String descriptionForCurrency(CryptoCurrency cur) {
68 + switch (cur) {
69 + case CryptoCurrency.xmr:
70 + return 'monero';
71 + case CryptoCurrency.ada:
72 + return 'cardano';
73 + case CryptoCurrency.bch:
74 + return 'bitcoin cash';
75 + case CryptoCurrency.bnb:
76 + return 'binance bep2';
77 + case CryptoCurrency.btc:
78 + return 'bitcoin';
79 + case CryptoCurrency.dai:
80 + return 'dai eth';
81 + case CryptoCurrency.eth:
82 + return 'ethereum';
83 + case CryptoCurrency.ltc:
84 + return 'litecoin';
85 + case CryptoCurrency.trx:
86 + return 'tron';
87 + case CryptoCurrency.usdt:
88 + return 'usdt omni';
89 + case CryptoCurrency.usdterc20:
90 + return 'tether ERC20 eth';
91 + case CryptoCurrency.xlm:
92 + return 'lumens';
93 + case CryptoCurrency.xrp:
94 + return 'ripple';
95 + default:
96 + return cur.title;
97 + }
98 + }
99 +}
lib/src/screens/exchange/widgets/exchange_card.dart
+112 -115
@@ -306,126 +306,121 @@ class ExchangeCardState extends State<ExchangeCard> {
306 ? Padding(
307 padding: EdgeInsets.only(top: 20),
308 child: AddressTextField(
309 - focusNode: widget.addressFocusNode,
310 - controller: addressController,
311 - placeholder: widget.hasRefundAddress
312 - ? S.of(context).refund_address
313 - : null,
314 - options: [
315 - AddressTextFieldOption.paste,
316 - AddressTextFieldOption.qrCode,
317 - AddressTextFieldOption.addressBook,
318 - ],
319 - isBorderExist: false,
320 - textStyle: TextStyle(
321 - fontSize: 16,
322 - fontWeight: FontWeight.w600,
323 - color: Colors.white),
324 - hintStyle: TextStyle(
325 - fontSize: 16,
326 - fontWeight: FontWeight.w600,
327 - color: Theme.of(context)
328 - .accentTextTheme
329 - .display4
330 - .decorationColor),
331 - buttonColor: widget.addressButtonsColor,
332 - validator: widget.addressTextFieldValidator,
333 - onPushPasteButton: widget.onPushPasteButton,
334 - onPushAddressBookButton: widget.onPushAddressBookButton
335 - ),
309 + focusNode: widget.addressFocusNode,
310 + controller: addressController,
311 + placeholder: widget.hasRefundAddress
312 + ? S.of(context).refund_address
313 + : null,
314 + options: [
315 + AddressTextFieldOption.paste,
316 + AddressTextFieldOption.qrCode,
317 + AddressTextFieldOption.addressBook,
318 + ],
319 + isBorderExist: false,
320 + textStyle: TextStyle(
321 + fontSize: 16,
322 + fontWeight: FontWeight.w600,
323 + color: Colors.white),
324 + hintStyle: TextStyle(
325 + fontSize: 16,
326 + fontWeight: FontWeight.w600,
327 + color: Theme.of(context)
328 + .accentTextTheme
329 + .display4
330 + .decorationColor),
331 + buttonColor: widget.addressButtonsColor,
332 + validator: widget.addressTextFieldValidator,
333 + onPushPasteButton: widget.onPushPasteButton,
334 + onPushAddressBookButton: widget.onPushAddressBookButton),
335 )
336 : Padding(
337 padding: EdgeInsets.only(top: 10),
338 child: Builder(
340 - builder: (context) => Stack(
341 - children: <Widget> [
342 - BaseTextFormField(
343 - controller: addressController,
344 - readOnly: true,
345 - borderColor: Colors.transparent,
346 - suffixIcon: SizedBox(
347 - width: _isMoneroWallet ? 80 : 36
348 - ),
349 - textStyle: TextStyle(
350 - fontSize: 16,
351 - fontWeight: FontWeight.w600,
352 - color: Colors.white),
353 - validator: widget.addressTextFieldValidator
354 - ),
355 - Positioned(
356 - top: 2,
357 - right: 0,
358 - child: SizedBox(
359 - width: _isMoneroWallet ? 80 : 36,
360 - child: Row(
361 - children: <Widget>[
362 - if (_isMoneroWallet) Padding(
363 - padding: EdgeInsets.only(left: 10),
364 - child: Container(
365 - width: 34,
366 - height: 34,
367 - padding: EdgeInsets.only(top: 0),
368 - child: InkWell(
369 - onTap: () async {
370 - final contact = await Navigator
371 - .of(context, rootNavigator: true)
372 - .pushNamed(
373 - Routes.pickerAddressBook);
339 + builder: (context) => Stack(children: <Widget>[
340 + BaseTextFormField(
341 + controller: addressController,
342 + readOnly: true,
343 + borderColor: Colors.transparent,
344 + suffixIcon:
345 + SizedBox(width: _isMoneroWallet ? 80 : 36),
346 + textStyle: TextStyle(
347 + fontSize: 16,
348 + fontWeight: FontWeight.w600,
349 + color: Colors.white),
350 + validator: widget.addressTextFieldValidator),
351 + Positioned(
352 + top: 2,
353 + right: 0,
354 + child: SizedBox(
355 + width: _isMoneroWallet ? 80 : 36,
356 + child: Row(children: <Widget>[
357 + if (_isMoneroWallet)
358 + Padding(
359 + padding: EdgeInsets.only(left: 10),
360 + child: Container(
361 + width: 34,
362 + height: 34,
363 + padding: EdgeInsets.only(top: 0),
364 + child: InkWell(
365 + onTap: () async {
366 + final contact =
367 + await Navigator.of(context,
368 + rootNavigator: true)
369 + .pushNamed(Routes
370 + .pickerAddressBook);
371
375 - if (contact is ContactBase &&
376 - contact.address != null) {
377 - setState(() =>
378 - addressController.text =
379 - contact.address);
380 - widget.onPushAddressBookButton
381 - ?.call(context);
382 - }
383 - },
384 - child: Container(
385 - padding: EdgeInsets.all(8),
386 - decoration: BoxDecoration(
387 - color: widget
388 - .addressButtonsColor,
389 - borderRadius: BorderRadius
390 - .all(Radius.circular(6))),
391 - child: Image.asset(
392 - 'assets/images/open_book.png',
393 - color: Theme.of(context)
394 - .primaryTextTheme
395 - .display1
396 - .decorationColor,
397 - )),
398 - )),
399 - ),
400 - Padding(
401 - padding: EdgeInsets.only(left: 2),
402 - child: Container(
403 - width: 34,
404 - height: 34,
405 - padding: EdgeInsets.only(top: 0),
406 - child: InkWell(
407 - onTap: () {
408 - Clipboard.setData(
409 - ClipboardData(
410 - text: addressController.text));
411 - showBar<void>(
412 - context, S.of(context)
413 - .copied_to_clipboard);
414 - },
415 - child: Container(
416 - padding: EdgeInsets
417 - .fromLTRB(8, 8, 0, 8),
418 - color: Colors.transparent,
419 - child: copyImage),
420 - ))
421 - )
422 - ]
423 - )
424 - )
425 - )
426 - ]
427 - )
428 - ),
372 + if (contact is ContactBase &&
373 + contact.address != null) {
374 + setState(() =>
375 + addressController.text =
376 + contact.address);
377 + widget.onPushAddressBookButton
378 + ?.call(context);
379 + }
380 + },
381 + child: Container(
382 + padding: EdgeInsets.all(8),
383 + decoration: BoxDecoration(
384 + color: widget
385 + .addressButtonsColor,
386 + borderRadius:
387 + BorderRadius.all(
388 + Radius.circular(
389 + 6))),
390 + child: Image.asset(
391 + 'assets/images/open_book.png',
392 + color: Theme.of(context)
393 + .primaryTextTheme
394 + .display1
395 + .decorationColor,
396 + )),
397 + )),
398 + ),
399 + Padding(
400 + padding: EdgeInsets.only(left: 2),
401 + child: Container(
402 + width: 34,
403 + height: 34,
404 + padding: EdgeInsets.only(top: 0),
405 + child: InkWell(
406 + onTap: () {
407 + Clipboard.setData(ClipboardData(
408 + text: addressController
409 + .text));
410 + showBar<void>(
411 + context,
412 + S
413 + .of(context)
414 + .copied_to_clipboard);
415 + },
416 + child: Container(
417 + padding: EdgeInsets.fromLTRB(
418 + 8, 8, 0, 8),
419 + color: Colors.transparent,
420 + child: copyImage),
421 + )))
422 + ])))
423 + ])),
424 ),
425 ]),
426 );
@@ -437,6 +432,8 @@ class ExchangeCardState extends State<ExchangeCard> {
432 selectedAtIndex: widget.currencies.indexOf(_selectedCurrency),
433 items: widget.currencies,
434 title: S.of(context).change_currency,
435 + isMoneroWallet: _isMoneroWallet,
436 + isConvertFrom: widget.hasRefundAddress,
437 onItemSelected: (CryptoCurrency item) =>
438 widget.onCurrencySelected != null
439 ? widget.onCurrencySelected(item)
lib/src/screens/exchange/widgets/picker_item.dart new
+10
@@ -0,0 +1,10 @@
1 +class PickerItem<T> {
2 + PickerItem(this.original,
3 + {this.title, this.iconPath, this.tag, this.description});
4 +
5 + final String title;
6 + final String iconPath;
7 + final String tag;
8 + final T original;
9 + final String description;
10 +}
lib/src/widgets/standard_list.dart
+8 -3
@@ -69,18 +69,22 @@ class SectionHeaderListRow extends StatelessWidget {
69 }
70
71 class StandardListSeparator extends StatelessWidget {
72 - StandardListSeparator({this.padding});
72 +
73 + StandardListSeparator({this.padding,this.height=1});
74
75 final EdgeInsets padding;
76 + final double height;
77 +
78 +
79
80 @override
81 Widget build(BuildContext context) {
82 return Container(
79 - height: 1,
83 + height: height,
84 padding: padding,
85 color: Theme.of(context).backgroundColor,
86 child: Container(
83 - height: 1,
87 + height: height,
88 color: Theme.of(context).primaryTextTheme.title.backgroundColor));
89 }
90 }
@@ -98,6 +102,7 @@ class StandardList extends StatelessWidget {
102 StandardListSeparator(padding: EdgeInsets.only(left: 24)),
103 itemCount: itemCount,
104 itemBuilder: itemBuilder);
105 +
106 }
107 }
108
res/values/strings_de.arb
+1 -1
@@ -524,7 +524,7 @@
524 "third_intro_title" : "Yat spielt gut mit anderen",
525 "third_intro_content" : "Yats leben auch außerhalb von Cake Wallet. Jede Wallet-Adresse auf der Welt kann durch ein Yat ersetzt werden!",
526 "learn_more" : "Erfahren Sie mehr",
527 -
527 + "search": "Suche",
528 "new_template" : "neue Vorlage",
529 "electrum_address_disclaimer": "Wir generieren jedes Mal neue Adressen, wenn Sie eine verwenden, aber vorherige Adressen funktionieren weiterhin"
530 }
res/values/strings_en.arb
+1 -1
@@ -524,7 +524,7 @@
524 "third_intro_title" : "Yat plays nicely with others",
525 "third_intro_content" : "Yats live outside of Cake Wallet, too. Any wallet address on earth can be replaced with a Yat!",
526 "learn_more" : "Learn More",
527 -
527 + "search": "Search",
528 "new_template" : "New Template",
529 "electrum_address_disclaimer": "We generate new addresses each time you use one, but previous addresses continue to work"
530 }
\ No newline at end of file
res/values/strings_es.arb
+1 -1
@@ -524,7 +524,7 @@
524 "third_intro_title" : "Yat juega muy bien con otras",
525 "third_intro_content" : "Los Yats también viven fuera de Cake Wallet. Cualquier dirección de billetera en la tierra se puede reemplazar con un Yat!",
526 "learn_more" : "Aprende más",
527 -
527 + "search": "Búsqueda",
528 "new_template" : "Nueva plantilla",
529 "electrum_address_disclaimer": "Generamos nuevas direcciones cada vez que usa una, pero las direcciones anteriores siguen funcionando"
530 }
\ No newline at end of file
res/values/strings_hi.arb
+1 -1
@@ -524,7 +524,7 @@
524 "third_intro_title" : "Yat दूसरों के साथ अच्छा खेलता है",
525 "third_intro_content" : "Yats Cake Wallet के बाहर भी रहता है। धरती पर किसी भी वॉलेट पते को Yat से बदला जा सकता है!",
526 "learn_more" : "और अधिक जानें",
527 -
527 + "search": "खोज",
528 "new_template" : "नया टेम्पलेट",
529 "electrum_address_disclaimer": "हर बार जब आप एक का उपयोग करते हैं तो हम नए पते उत्पन्न करते हैं, लेकिन पिछले पते काम करना जारी रखते हैं"
530 }
\ No newline at end of file
res/values/strings_hr.arb
+1 -1
@@ -524,7 +524,7 @@
524 "third_intro_title" : "Yat se lijepo igra s drugima",
525 "third_intro_content" : "Yats žive i izvan Cake Wallet -a. Bilo koja adresa novčanika na svijetu može se zamijeniti Yat!",
526 "learn_more" : "Saznajte više",
527 -
527 + "search": "Traži",
528 "new_template" : "novi predložak",
529 "electrum_address_disclaimer": "Minden egyes alkalommal új címeket generálunk, de a korábbi címek továbbra is működnek"
530 }
\ No newline at end of file
res/values/strings_it.arb
+1 -1
@@ -524,7 +524,7 @@
524 "third_intro_title" : "Yat gioca bene con gli altri",
525 "third_intro_content" : "Anche Yats vive fuori da Cake Wallet. Qualsiasi indirizzo di portafoglio sulla terra può essere sostituito con un Yat!",
526 "learn_more" : "Impara di più",
527 -
527 + "search": "Ricerca",
528 "new_template" : "Nuovo modello",
529 "electrum_address_disclaimer": "Generiamo nuovi indirizzi ogni volta che ne utilizzi uno, ma gli indirizzi precedenti continuano a funzionare"
530 }
\ No newline at end of file
res/values/strings_ja.arb
+1 -1
@@ -524,7 +524,7 @@
524 "third_intro_title" : "Yatは他の人とうまく遊ぶ",
525 "third_intro_content" : "YatsはCakeWalletの外にも住んでいます。 地球上のどのウォレットアドレスもYatに置き換えることができます!",
526 "learn_more" : "もっと詳しく知る",
527 -
527 + "search": "検索",
528 "new_template" : "新しいテンプレート",
529 "electrum_address_disclaimer": "使用するたびに新しいアドレスが生成されますが、以前のアドレスは引き続き機能します"
530 }
\ No newline at end of file
res/values/strings_ko.arb
+1 -1
@@ -524,7 +524,7 @@
524 "third_intro_title" : "Yat는 다른 사람들과 잘 놉니다.",
525 "third_intro_content" : "Yats는 Cake Wallet 밖에서도 살고 있습니다. 지구상의 모든 지갑 주소는 Yat!",
526 "learn_more" : "더 알아보기",
527 -
527 + "search": "찾다",
528 "new_template" : "새 템플릿",
529 "electrum_address_disclaimer": "사용할 때마다 새 주소가 생성되지만 이전 주소는 계속 작동합니다."
530 }
\ No newline at end of file
res/values/strings_nl.arb
+1 -1
@@ -524,7 +524,7 @@
524 "third_intro_title" : "Yat speelt leuk met anderen",
525 "third_intro_content" : "Yats wonen ook buiten Cake Wallet. Elk portemonnee-adres op aarde kan worden vervangen door een Yat!",
526 "learn_more" : "Kom meer te weten",
527 -
527 + "search": "Zoekopdracht",
528 "new_template" : "Nieuwe sjabloon",
529 "electrum_address_disclaimer": "We generate new addresses each time you use one, but previous addresses continue to work"
530 }
\ No newline at end of file
res/values/strings_pl.arb
+1 -1
@@ -527,7 +527,7 @@
527 "third_intro_title" : "Yat ładnie bawi się z innymi",
528 "third_intro_content" : "Yats mieszkają również poza Cake Wallet. Każdy adres portfela na ziemi można zastąpić Yat!",
529 "learn_more" : "Ucz się więcej",
530 -
530 + "search": "Szukaj",
531 "new_template" : "Nowy szablon",
532 "electrum_address_disclaimer": "Za każdym razem, gdy korzystasz z jednego z nich, generujemy nowe adresy, ale poprzednie adresy nadal działają"
533 }
\ No newline at end of file
res/values/strings_pt.arb
+1 -1
@@ -524,7 +524,7 @@
524 "third_intro_title" : "Yat joga bem com os outros",
525 "third_intro_content" : "Yats também mora fora da Cake Wallet. Qualquer endereço de carteira na Terra pode ser substituído por um Yat!",
526 "learn_more" : "Saber mais",
527 -
527 + "search": "Procurar",
528 "new_template" : "Novo modelo",
529 "electrum_address_disclaimer": "Geramos novos endereços cada vez que você usa um, mas os endereços anteriores continuam funcionando"
530 }
\ No newline at end of file
res/values/strings_ru.arb
+1 -1
@@ -524,7 +524,7 @@
524 "third_intro_title" : "Yat хорошо взаимодействует с другими",
525 "third_intro_content" : "Yat находятся за пределами Cake Wallet. Любой адрес кошелька на земле можно заменить на Yat!",
526 "learn_more" : "Узнать больше",
527 -
527 + "search": "Поиск",
528 "new_template" : "Новый шаблон",
529 "electrum_address_disclaimer": "Мы генерируем новые адреса каждый раз, когда вы их используете, но предыдущие адреса продолжают работать."
530 }
\ No newline at end of file
res/values/strings_uk.arb
+1 -1
@@ -523,7 +523,7 @@
523 "third_intro_title" : "Yat добре взаємодіє з іншими",
524 "third_intro_content" : "Yat знаходиться за межами Cake Wallet. Будь-яку адресу гаманця на землі можна замінити на Yat!",
525 "learn_more" : "Дізнатися більше",
526 -
526 + "search": "Пошук",
527 "new_template" : "Новий шаблон",
528 "electrum_address_disclaimer": "Ми створюємо нові адреси щоразу, коли ви використовуєте їх, але попередні адреси продовжують працювати"
529 }
\ No newline at end of file
res/values/strings_zh.arb
+1 -1
@@ -522,7 +522,7 @@
522 "third_intro_title" : "Yat 和別人玩得很好",
523 "third_intro_content" : "Yats 也住在 Cake Wallet 之外。 地球上任何一個錢包地址都可以用一個Yat來代替!",
524 "learn_more" : "了解更多",
525 -
525 + "search": "搜索",
526 "new_template" : "新模板",
527 "electrum_address_disclaimer": "每次您使用一个地址时,我们都会生成新地址,但之前的地址仍然有效"
528 }
\ No newline at end of file