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

* Added new picker screen with search bar and currency icons
This commit is contained in:
Serhii 2022-03-31 17:16:42 +03:00 committed by GitHub
parent f3cf20c395
commit 1cd90cf57d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
40 changed files with 578 additions and 279 deletions

BIN
assets/images/ada_icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

BIN
assets/images/bch_icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

BIN
assets/images/bnb_icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

BIN
assets/images/btc.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

BIN
assets/images/dai_icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

BIN
assets/images/dash_icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

BIN
assets/images/eos_icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

BIN
assets/images/eth_icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

BIN
assets/images/trx_icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

BIN
assets/images/usdt_icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 391 B

BIN
assets/images/xlm_icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

BIN
assets/images/xrp_icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

View file

@ -206,8 +206,8 @@ class ExchangePage extends BasePage {
onCurrencySelected: (currency) { onCurrencySelected: (currency) {
// FIXME: need to move it into view model // FIXME: need to move it into view model
if (currency == CryptoCurrency.xmr && if (currency == CryptoCurrency.xmr &&
exchangeViewModel.wallet.type == exchangeViewModel.wallet.type !=
WalletType.bitcoin) { WalletType.monero) {
showPopUp<void>( showPopUp<void>(
context: context, context: context,
builder: (dialogContext) { builder: (dialogContext) {

View file

@ -1,176 +1,210 @@
import 'dart:ui'; import 'dart:ui';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/palette.dart'; import 'package:cake_wallet/palette.dart';
import 'package:cake_wallet/src/screens/exchange/widgets/currency_utils.dart';
import 'package:cake_wallet/src/screens/exchange/widgets/picker_item.dart';
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:cw_core/crypto_currency.dart'; import 'package:cw_core/crypto_currency.dart';
import 'package:cake_wallet/src/widgets/alert_background.dart'; import 'package:cake_wallet/src/widgets/alert_background.dart';
import 'package:cake_wallet/src/widgets/alert_close_button.dart'; import 'currency_picker_widget.dart';
import 'package:cake_wallet/src/widgets/cake_scrollbar.dart';
class CurrencyPicker extends StatefulWidget { class CurrencyPicker extends StatefulWidget {
CurrencyPicker({ CurrencyPicker(
@required this.selectedAtIndex, {@required this.selectedAtIndex,
@required this.items, @required this.items,
@required this.title, @required this.title,
@required this.onItemSelected, @required this.onItemSelected,
}); this.isMoneroWallet = false,
this.isConvertFrom = false});
final int selectedAtIndex; int selectedAtIndex;
final List<CryptoCurrency> items; final List<CryptoCurrency> items;
final String title; final String title;
final Function(CryptoCurrency) onItemSelected; final Function(CryptoCurrency) onItemSelected;
final bool isMoneroWallet;
final bool isConvertFrom;
@override @override
CurrencyPickerState createState() => CurrencyPickerState( CurrencyPickerState createState() => CurrencyPickerState(items);
selectedAtIndex,
items,
title,
onItemSelected
);
} }
class CurrencyPickerState extends State<CurrencyPicker> { class CurrencyPickerState extends State<CurrencyPicker> {
CurrencyPickerState( CurrencyPickerState(this.items)
this.selectedAtIndex, : isSearchBarActive = false,
this.items, textFieldValue = '',
this.title, subPickerItemsList = [],
this.onItemSelected): itemsCount = items.length; appBarTextStyle = TextStyle(
fontSize: 20,
fontFamily: 'Lato',
backgroundColor: Colors.transparent,
color: Colors.white);
final int selectedAtIndex; @override
final List<CryptoCurrency> items; void initState() {
final String title; pickerItemsList = CryptoCurrency.all
final Function(CryptoCurrency) onItemSelected; .map((CryptoCurrency cur) => PickerItem<CryptoCurrency>(cur,
title: CurrencyUtils.titleForCurrency(cur),
iconPath: CurrencyUtils.iconPathForCurrency(cur),
tag: CurrencyUtils.tagForCurrency(cur),
description: CurrencyUtils.descriptionForCurrency(cur)))
.toList();
cleanSubPickerItemsList();
super.initState();
}
final closeButton = Image.asset('assets/images/close.png', List<PickerItem<CryptoCurrency>> pickerItemsList;
color: Palette.darkBlueCraiola, List<CryptoCurrency> items;
); bool isSearchBarActive;
final int crossAxisCount = 3; String textFieldValue;
final int maxNumberItemsInAlert = 12; List<PickerItem<CryptoCurrency>> subPickerItemsList;
final int itemsCount; TextStyle appBarTextStyle;
final double backgroundHeight = 280;
final double thumbHeight = 72; void cleanSubPickerItemsList() {
ScrollController controller = ScrollController(); subPickerItemsList = pickerItemsList
double fromTop = 0; .where((element) => items.contains(element.original))
.toList();
}
void currencySearchBySubstring(
String subString, List<PickerItem<CryptoCurrency>> list) {
setState(() {
if (subString.isNotEmpty) {
subPickerItemsList = subPickerItemsList
.where((element) =>
element.title.contains(subString.toUpperCase()) ||
element.description.contains(subString.toLowerCase()))
.toList();
} else {
cleanSubPickerItemsList();
}
});
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
controller.addListener(() {
fromTop = controller.hasClients
? (controller.offset / controller.position.maxScrollExtent * (backgroundHeight - thumbHeight))
: 0;
setState(() {});
});
return AlertBackground( return AlertBackground(
child: Stack( child: SafeArea(
alignment: Alignment.center, child: Scaffold(
children: <Widget>[ resizeToAvoidBottomInset: false,
Column( backgroundColor: Colors.transparent,
mainAxisSize: MainAxisSize.min, body: Column(
children: <Widget>[ children: [
Container( Padding(
padding: EdgeInsets.only(left: 24, right: 24), padding: EdgeInsets.symmetric(horizontal: 26.0, vertical: 0),
child: Text( child: Row(
title, mainAxisAlignment: MainAxisAlignment.spaceBetween,
textAlign: TextAlign.center, children: [
style: TextStyle( isSearchBarActive
fontSize: 18, ? Expanded(
fontFamily: 'Lato', child: Row(
fontWeight: FontWeight.bold, mainAxisAlignment:
decoration: TextDecoration.none, MainAxisAlignment.spaceBetween,
color: Colors.white children: [
InkWell(
child: Text(
S.of(context).cancel,
style: appBarTextStyle,
),
onTap: () {
setState(() {
isSearchBarActive = false;
textFieldValue = '';
cleanSubPickerItemsList();
});
}),
Container(
width: 100.0,
child: CupertinoTextField(
autofocus: true,
placeholder:
S.of(context).search + '...',
placeholderStyle: appBarTextStyle,
decoration: BoxDecoration(
color: Colors.transparent),
cursorColor: Colors.white,
cursorHeight: 23.0,
style: appBarTextStyle,
onChanged: (value) {
this.textFieldValue = value;
cleanSubPickerItemsList();
currencySearchBySubstring(
textFieldValue,
subPickerItemsList);
}),
)
],
),
)
: Text(
widget.title,
style: appBarTextStyle,
),
IconButton(
splashRadius: 23,
icon: Icon(Icons.search, color: Colors.white),
onPressed: () {
setState(() {
isSearchBarActive = true;
});
},
)
]),
),
Expanded(
flex: 12,
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: 26.0, vertical: 26.0),
child: Container(
child: CurrencyPickerWidget(
crossAxisCount: 2,
selectedAtIndex: widget.selectedAtIndex,
itemsCount: subPickerItemsList.length,
pickerItemsList: subPickerItemsList,
pickListItem: (int index) {
setState(() {
widget.selectedAtIndex = index;
});
widget
.onItemSelected(subPickerItemsList[index].original);
if (widget.isConvertFrom &&
!widget.isMoneroWallet &&
(subPickerItemsList[index].original ==
CryptoCurrency.xmr)) {
} else {
Navigator.of(context).pop();
}
},
), ),
), ),
), ),
Padding( ),
padding: EdgeInsets.only(top: 24), Expanded(
child: GestureDetector( flex: 2,
onTap: () => null, child: Container(
child: ClipRRect( width: 42.0,
borderRadius: BorderRadius.all(Radius.circular(14)), alignment: Alignment.topCenter,
child: Container( child: FittedBox(
height: 320, child: FloatingActionButton(
width: 300, elevation: 0,
color: Theme.of(context).accentTextTheme.title.backgroundColor, backgroundColor: Colors.white,
child: Stack( onPressed: () {
alignment: Alignment.center, Navigator.of(context).pop();
children: <Widget>[ },
GridView.count( child: Icon(
padding: EdgeInsets.all(0), Icons.close_outlined,
controller: controller, color: Palette.darkBlueCraiola,
crossAxisCount: crossAxisCount, size: 30.0,
childAspectRatio: 1.25,
crossAxisSpacing: 1,
mainAxisSpacing: 1,
children: List.generate(
itemsCount
+ getExtraEmptyTilesCount(crossAxisCount, itemsCount),
(index) {
if (index >= itemsCount) {
return Container(
color: Theme.of(context).accentTextTheme.title.color,
);
}
final item = items[index];
final isItemSelected = index == selectedAtIndex;
final color = isItemSelected
? Theme.of(context).textTheme.body2.color
: Theme.of(context).accentTextTheme.title.color;
final textColor = isItemSelected
? Palette.blueCraiola
: Theme.of(context).primaryTextTheme.title.color;
return GestureDetector(
onTap: () {
if (onItemSelected == null) {
return;
}
Navigator.of(context).pop();
onItemSelected(item);
},
child: Container(
color: color,
child: Center(
child: Text(
item.toString(),
style: TextStyle(
fontSize: 15,
fontFamily: 'Lato',
fontWeight: FontWeight.w600,
decoration: TextDecoration.none,
color: textColor
),
),
),
),
);
})
),
if (itemsCount > maxNumberItemsInAlert)
CakeScrollbar(
backgroundHeight: backgroundHeight,
thumbHeight: thumbHeight,
fromTop: fromTop
)
],
)
), ),
), ),
), ),
) ),
], ),
), ],
AlertCloseButton(image: closeButton) ),
], ),
) ),
); );
} }
int getExtraEmptyTilesCount(int crossAxisCount, int itemsCount) {
final int tilesInNewRowCount = itemsCount % crossAxisCount;
return tilesInNewRowCount == 0 ? 0 : crossAxisCount - tilesInNewRowCount;
}
} }

View file

@ -0,0 +1,93 @@
import 'package:flutter/material.dart';
import 'package:cake_wallet/palette.dart';
class PickerItemWidget extends StatelessWidget {
const PickerItemWidget(
{this.iconPath, this.title, this.isSelected, this.tag, this.onTap});
final String iconPath;
final String title;
final bool isSelected;
final String tag;
final void Function() onTap;
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: onTap,
child: Container(
color: isSelected
? Theme.of(context).textTheme.bodyText1.color
: Theme.of(context).accentTextTheme.headline6.color,
child: Center(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Expanded(
child: Container(
child: Image.asset(
iconPath,
height: 32.0,
width: 32.0,
),
),
),
Expanded(
child: Stack(
clipBehavior: Clip.none,
alignment: Alignment.centerLeft,
children: [
Text(
title,
style: TextStyle(
color: isSelected
? Palette.blueCraiola
: Theme.of(context).primaryTextTheme.title.color,
fontSize: 18.0,
fontFamily: 'Lato',
),
),
tag != null
? Positioned(
top: -20.0,
right: 7.0,
child: Container(
width: 35.0,
height: 18.0,
child: Center(
child: Text(
tag,
style: TextStyle(
fontSize: 7.0,
fontFamily: 'Lato',
color: Theme.of(context)
.textTheme
.body1
.color),
),
),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(6.0),
//border: Border.all(color: ),
color: Theme.of(context)
.textTheme
.body1
.decorationColor,
),
),
)
: Container(),
],
),
),
],
),
),
),
),
);
;
}
}

View file

@ -0,0 +1,61 @@
import 'package:flutter/material.dart';
import 'package:cw_core/crypto_currency.dart';
import 'picker_item.dart';
import 'currency_picker_item_widget.dart';
class CurrencyPickerWidget extends StatelessWidget {
const CurrencyPickerWidget({
@required this.crossAxisCount,
@required this.selectedAtIndex,
@required this.itemsCount,
@required this.pickerItemsList,
@required this.pickListItem,
});
final int crossAxisCount;
final int selectedAtIndex;
final int itemsCount;
final Function pickListItem;
final List<PickerItem<CryptoCurrency>> pickerItemsList;
@override
Widget build(BuildContext context) {
return LayoutBuilder(
builder: (BuildContext context, BoxConstraints constraints) {
return Container(
decoration: BoxDecoration(
color: Theme.of(context).accentTextTheme.headline6.backgroundColor,
borderRadius: BorderRadius.circular(14.0),
),
child: ClipRRect(
borderRadius: BorderRadius.circular(14.0),
child: Scrollbar(
showTrackOnHover: true,
isAlwaysShown: true,
thickness: 6.0,
radius: Radius.circular(3),
child: GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: crossAxisCount,
crossAxisSpacing: 1,
mainAxisExtent: constraints.maxHeight / 8,
mainAxisSpacing: 1),
itemCount: pickerItemsList.length,
itemBuilder: (BuildContext ctx, index) {
return PickerItemWidget(
onTap: () {
pickListItem(index);
},
title: pickerItemsList[index].title,
iconPath: pickerItemsList[index].iconPath,
isSelected: index == selectedAtIndex,
tag: pickerItemsList[index].tag,
);
}),
),
),
);
},
);
}
}

View file

@ -0,0 +1,99 @@
import 'package:cw_core/crypto_currency.dart';
class CurrencyUtils {
static String tagForCurrency(CryptoCurrency cur) {
switch (cur) {
case CryptoCurrency.bnb:
return 'BEP2';
case CryptoCurrency.dai:
return 'ETH';
case CryptoCurrency.usdt:
return 'OMNI';
case CryptoCurrency.usdterc20:
return 'ETH';
default:
return null;
}
}
static String iconPathForCurrency(CryptoCurrency cur) {
switch (cur) {
case CryptoCurrency.xmr:
return 'assets/images/monero_icon.png';
case CryptoCurrency.ada:
return 'assets/images/ada_icon.png';
case CryptoCurrency.bch:
return 'assets/images/bch_icon.png';
case CryptoCurrency.bnb:
return 'assets/images/bnb_icon.png';
case CryptoCurrency.btc:
return 'assets/images/btc.png';
case CryptoCurrency.dai:
return 'assets/images/dai_icon.png';
case CryptoCurrency.dash:
return 'assets/images/dash_icon.png';
case CryptoCurrency.eos:
return 'assets/images/eos_icon.png';
case CryptoCurrency.eth:
return 'assets/images/eth_icon.png';
case CryptoCurrency.ltc:
return 'assets/images/litecoin-ltc_icon.png';
case CryptoCurrency.trx:
return 'assets/images/trx_icon.png';
case CryptoCurrency.usdt:
return 'assets/images/usdt_icon.png';
case CryptoCurrency.usdterc20:
return 'assets/images/usdterc20_icon.png';
case CryptoCurrency.xlm:
return 'assets/images/xlm_icon.png';
case CryptoCurrency.xrp:
return 'assets/images/xrp_icon.png';
default:
return null;
}
}
static String titleForCurrency(CryptoCurrency cur) {
switch (cur) {
case CryptoCurrency.bnb:
return 'BNB';
case CryptoCurrency.usdterc20:
return 'USDT';
default:
return cur.title;
}
}
static String descriptionForCurrency(CryptoCurrency cur) {
switch (cur) {
case CryptoCurrency.xmr:
return 'monero';
case CryptoCurrency.ada:
return 'cardano';
case CryptoCurrency.bch:
return 'bitcoin cash';
case CryptoCurrency.bnb:
return 'binance bep2';
case CryptoCurrency.btc:
return 'bitcoin';
case CryptoCurrency.dai:
return 'dai eth';
case CryptoCurrency.eth:
return 'ethereum';
case CryptoCurrency.ltc:
return 'litecoin';
case CryptoCurrency.trx:
return 'tron';
case CryptoCurrency.usdt:
return 'usdt omni';
case CryptoCurrency.usdterc20:
return 'tether ERC20 eth';
case CryptoCurrency.xlm:
return 'lumens';
case CryptoCurrency.xrp:
return 'ripple';
default:
return cur.title;
}
}
}

View file

@ -306,126 +306,121 @@ class ExchangeCardState extends State<ExchangeCard> {
? Padding( ? Padding(
padding: EdgeInsets.only(top: 20), padding: EdgeInsets.only(top: 20),
child: AddressTextField( child: AddressTextField(
focusNode: widget.addressFocusNode, focusNode: widget.addressFocusNode,
controller: addressController, controller: addressController,
placeholder: widget.hasRefundAddress placeholder: widget.hasRefundAddress
? S.of(context).refund_address ? S.of(context).refund_address
: null, : null,
options: [ options: [
AddressTextFieldOption.paste, AddressTextFieldOption.paste,
AddressTextFieldOption.qrCode, AddressTextFieldOption.qrCode,
AddressTextFieldOption.addressBook, AddressTextFieldOption.addressBook,
], ],
isBorderExist: false, isBorderExist: false,
textStyle: TextStyle( textStyle: TextStyle(
fontSize: 16, fontSize: 16,
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
color: Colors.white), color: Colors.white),
hintStyle: TextStyle( hintStyle: TextStyle(
fontSize: 16, fontSize: 16,
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
color: Theme.of(context) color: Theme.of(context)
.accentTextTheme .accentTextTheme
.display4 .display4
.decorationColor), .decorationColor),
buttonColor: widget.addressButtonsColor, buttonColor: widget.addressButtonsColor,
validator: widget.addressTextFieldValidator, validator: widget.addressTextFieldValidator,
onPushPasteButton: widget.onPushPasteButton, onPushPasteButton: widget.onPushPasteButton,
onPushAddressBookButton: widget.onPushAddressBookButton onPushAddressBookButton: widget.onPushAddressBookButton),
),
) )
: Padding( : Padding(
padding: EdgeInsets.only(top: 10), padding: EdgeInsets.only(top: 10),
child: Builder( child: Builder(
builder: (context) => Stack( builder: (context) => Stack(children: <Widget>[
children: <Widget> [ BaseTextFormField(
BaseTextFormField( controller: addressController,
controller: addressController, readOnly: true,
readOnly: true, borderColor: Colors.transparent,
borderColor: Colors.transparent, suffixIcon:
suffixIcon: SizedBox( SizedBox(width: _isMoneroWallet ? 80 : 36),
width: _isMoneroWallet ? 80 : 36 textStyle: TextStyle(
), fontSize: 16,
textStyle: TextStyle( fontWeight: FontWeight.w600,
fontSize: 16, color: Colors.white),
fontWeight: FontWeight.w600, validator: widget.addressTextFieldValidator),
color: Colors.white), Positioned(
validator: widget.addressTextFieldValidator top: 2,
), right: 0,
Positioned( child: SizedBox(
top: 2, width: _isMoneroWallet ? 80 : 36,
right: 0, child: Row(children: <Widget>[
child: SizedBox( if (_isMoneroWallet)
width: _isMoneroWallet ? 80 : 36, Padding(
child: Row( padding: EdgeInsets.only(left: 10),
children: <Widget>[ child: Container(
if (_isMoneroWallet) Padding( width: 34,
padding: EdgeInsets.only(left: 10), height: 34,
child: Container( padding: EdgeInsets.only(top: 0),
width: 34, child: InkWell(
height: 34, onTap: () async {
padding: EdgeInsets.only(top: 0), final contact =
child: InkWell( await Navigator.of(context,
onTap: () async { rootNavigator: true)
final contact = await Navigator .pushNamed(Routes
.of(context, rootNavigator: true) .pickerAddressBook);
.pushNamed(
Routes.pickerAddressBook);
if (contact is ContactBase && if (contact is ContactBase &&
contact.address != null) { contact.address != null) {
setState(() => setState(() =>
addressController.text = addressController.text =
contact.address); contact.address);
widget.onPushAddressBookButton widget.onPushAddressBookButton
?.call(context); ?.call(context);
} }
}, },
child: Container( child: Container(
padding: EdgeInsets.all(8), padding: EdgeInsets.all(8),
decoration: BoxDecoration( decoration: BoxDecoration(
color: widget color: widget
.addressButtonsColor, .addressButtonsColor,
borderRadius: BorderRadius borderRadius:
.all(Radius.circular(6))), BorderRadius.all(
child: Image.asset( Radius.circular(
'assets/images/open_book.png', 6))),
color: Theme.of(context) child: Image.asset(
.primaryTextTheme 'assets/images/open_book.png',
.display1 color: Theme.of(context)
.decorationColor, .primaryTextTheme
)), .display1
)), .decorationColor,
), )),
Padding( )),
padding: EdgeInsets.only(left: 2), ),
child: Container( Padding(
width: 34, padding: EdgeInsets.only(left: 2),
height: 34, child: Container(
padding: EdgeInsets.only(top: 0), width: 34,
child: InkWell( height: 34,
onTap: () { padding: EdgeInsets.only(top: 0),
Clipboard.setData( child: InkWell(
ClipboardData( onTap: () {
text: addressController.text)); Clipboard.setData(ClipboardData(
showBar<void>( text: addressController
context, S.of(context) .text));
.copied_to_clipboard); showBar<void>(
}, context,
child: Container( S
padding: EdgeInsets .of(context)
.fromLTRB(8, 8, 0, 8), .copied_to_clipboard);
color: Colors.transparent, },
child: copyImage), child: Container(
)) padding: EdgeInsets.fromLTRB(
) 8, 8, 0, 8),
] color: Colors.transparent,
) child: copyImage),
) )))
) ])))
] ])),
)
),
), ),
]), ]),
); );
@ -437,6 +432,8 @@ class ExchangeCardState extends State<ExchangeCard> {
selectedAtIndex: widget.currencies.indexOf(_selectedCurrency), selectedAtIndex: widget.currencies.indexOf(_selectedCurrency),
items: widget.currencies, items: widget.currencies,
title: S.of(context).change_currency, title: S.of(context).change_currency,
isMoneroWallet: _isMoneroWallet,
isConvertFrom: widget.hasRefundAddress,
onItemSelected: (CryptoCurrency item) => onItemSelected: (CryptoCurrency item) =>
widget.onCurrencySelected != null widget.onCurrencySelected != null
? widget.onCurrencySelected(item) ? widget.onCurrencySelected(item)

View file

@ -0,0 +1,10 @@
class PickerItem<T> {
PickerItem(this.original,
{this.title, this.iconPath, this.tag, this.description});
final String title;
final String iconPath;
final String tag;
final T original;
final String description;
}

View file

@ -69,18 +69,22 @@ class SectionHeaderListRow extends StatelessWidget {
} }
class StandardListSeparator extends StatelessWidget { class StandardListSeparator extends StatelessWidget {
StandardListSeparator({this.padding});
StandardListSeparator({this.padding,this.height=1});
final EdgeInsets padding; final EdgeInsets padding;
final double height;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Container( return Container(
height: 1, height: height,
padding: padding, padding: padding,
color: Theme.of(context).backgroundColor, color: Theme.of(context).backgroundColor,
child: Container( child: Container(
height: 1, height: height,
color: Theme.of(context).primaryTextTheme.title.backgroundColor)); color: Theme.of(context).primaryTextTheme.title.backgroundColor));
} }
} }
@ -98,6 +102,7 @@ class StandardList extends StatelessWidget {
StandardListSeparator(padding: EdgeInsets.only(left: 24)), StandardListSeparator(padding: EdgeInsets.only(left: 24)),
itemCount: itemCount, itemCount: itemCount,
itemBuilder: itemBuilder); itemBuilder: itemBuilder);
} }
} }

View file

@ -524,7 +524,7 @@
"third_intro_title" : "Yat spielt gut mit anderen", "third_intro_title" : "Yat spielt gut mit anderen",
"third_intro_content" : "Yats leben auch außerhalb von Cake Wallet. Jede Wallet-Adresse auf der Welt kann durch ein Yat ersetzt werden!", "third_intro_content" : "Yats leben auch außerhalb von Cake Wallet. Jede Wallet-Adresse auf der Welt kann durch ein Yat ersetzt werden!",
"learn_more" : "Erfahren Sie mehr", "learn_more" : "Erfahren Sie mehr",
"search": "Suche",
"new_template" : "neue Vorlage", "new_template" : "neue Vorlage",
"electrum_address_disclaimer": "Wir generieren jedes Mal neue Adressen, wenn Sie eine verwenden, aber vorherige Adressen funktionieren weiterhin" "electrum_address_disclaimer": "Wir generieren jedes Mal neue Adressen, wenn Sie eine verwenden, aber vorherige Adressen funktionieren weiterhin"
} }

View file

@ -524,7 +524,7 @@
"third_intro_title" : "Yat plays nicely with others", "third_intro_title" : "Yat plays nicely with others",
"third_intro_content" : "Yats live outside of Cake Wallet, too. Any wallet address on earth can be replaced with a Yat!", "third_intro_content" : "Yats live outside of Cake Wallet, too. Any wallet address on earth can be replaced with a Yat!",
"learn_more" : "Learn More", "learn_more" : "Learn More",
"search": "Search",
"new_template" : "New Template", "new_template" : "New Template",
"electrum_address_disclaimer": "We generate new addresses each time you use one, but previous addresses continue to work" "electrum_address_disclaimer": "We generate new addresses each time you use one, but previous addresses continue to work"
} }

View file

@ -524,7 +524,7 @@
"third_intro_title" : "Yat juega muy bien con otras", "third_intro_title" : "Yat juega muy bien con otras",
"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!", "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!",
"learn_more" : "Aprende más", "learn_more" : "Aprende más",
"search": "Búsqueda",
"new_template" : "Nueva plantilla", "new_template" : "Nueva plantilla",
"electrum_address_disclaimer": "Generamos nuevas direcciones cada vez que usa una, pero las direcciones anteriores siguen funcionando" "electrum_address_disclaimer": "Generamos nuevas direcciones cada vez que usa una, pero las direcciones anteriores siguen funcionando"
} }

View file

@ -524,7 +524,7 @@
"third_intro_title" : "Yat दूसरों के साथ अच्छा खेलता है", "third_intro_title" : "Yat दूसरों के साथ अच्छा खेलता है",
"third_intro_content" : "Yats Cake Wallet के बाहर भी रहता है। धरती पर किसी भी वॉलेट पते को Yat से बदला जा सकता है!", "third_intro_content" : "Yats Cake Wallet के बाहर भी रहता है। धरती पर किसी भी वॉलेट पते को Yat से बदला जा सकता है!",
"learn_more" : "और अधिक जानें", "learn_more" : "और अधिक जानें",
"search": "खोज",
"new_template" : "नया टेम्पलेट", "new_template" : "नया टेम्पलेट",
"electrum_address_disclaimer": "हर बार जब आप एक का उपयोग करते हैं तो हम नए पते उत्पन्न करते हैं, लेकिन पिछले पते काम करना जारी रखते हैं" "electrum_address_disclaimer": "हर बार जब आप एक का उपयोग करते हैं तो हम नए पते उत्पन्न करते हैं, लेकिन पिछले पते काम करना जारी रखते हैं"
} }

View file

@ -524,7 +524,7 @@
"third_intro_title" : "Yat se lijepo igra s drugima", "third_intro_title" : "Yat se lijepo igra s drugima",
"third_intro_content" : "Yats žive i izvan Cake Wallet -a. Bilo koja adresa novčanika na svijetu može se zamijeniti Yat!", "third_intro_content" : "Yats žive i izvan Cake Wallet -a. Bilo koja adresa novčanika na svijetu može se zamijeniti Yat!",
"learn_more" : "Saznajte više", "learn_more" : "Saznajte više",
"search": "Traži",
"new_template" : "novi predložak", "new_template" : "novi predložak",
"electrum_address_disclaimer": "Minden egyes alkalommal új címeket generálunk, de a korábbi címek továbbra is működnek" "electrum_address_disclaimer": "Minden egyes alkalommal új címeket generálunk, de a korábbi címek továbbra is működnek"
} }

View file

@ -524,7 +524,7 @@
"third_intro_title" : "Yat gioca bene con gli altri", "third_intro_title" : "Yat gioca bene con gli altri",
"third_intro_content" : "Anche Yats vive fuori da Cake Wallet. Qualsiasi indirizzo di portafoglio sulla terra può essere sostituito con un Yat!", "third_intro_content" : "Anche Yats vive fuori da Cake Wallet. Qualsiasi indirizzo di portafoglio sulla terra può essere sostituito con un Yat!",
"learn_more" : "Impara di più", "learn_more" : "Impara di più",
"search": "Ricerca",
"new_template" : "Nuovo modello", "new_template" : "Nuovo modello",
"electrum_address_disclaimer": "Generiamo nuovi indirizzi ogni volta che ne utilizzi uno, ma gli indirizzi precedenti continuano a funzionare" "electrum_address_disclaimer": "Generiamo nuovi indirizzi ogni volta che ne utilizzi uno, ma gli indirizzi precedenti continuano a funzionare"
} }

View file

@ -524,7 +524,7 @@
"third_intro_title" : "Yatは他の人とうまく遊ぶ", "third_intro_title" : "Yatは他の人とうまく遊ぶ",
"third_intro_content" : "YatsはCakeWalletの外にも住んでいます。 地球上のどのウォレットアドレスもYatに置き換えることができます", "third_intro_content" : "YatsはCakeWalletの外にも住んでいます。 地球上のどのウォレットアドレスもYatに置き換えることができます",
"learn_more" : "もっと詳しく知る", "learn_more" : "もっと詳しく知る",
"search": "検索",
"new_template" : "新しいテンプレート", "new_template" : "新しいテンプレート",
"electrum_address_disclaimer": "使用するたびに新しいアドレスが生成されますが、以前のアドレスは引き続き機能します" "electrum_address_disclaimer": "使用するたびに新しいアドレスが生成されますが、以前のアドレスは引き続き機能します"
} }

View file

@ -524,7 +524,7 @@
"third_intro_title" : "Yat는 다른 사람들과 잘 놉니다.", "third_intro_title" : "Yat는 다른 사람들과 잘 놉니다.",
"third_intro_content" : "Yats는 Cake Wallet 밖에서도 살고 있습니다. 지구상의 모든 지갑 주소는 Yat!", "third_intro_content" : "Yats는 Cake Wallet 밖에서도 살고 있습니다. 지구상의 모든 지갑 주소는 Yat!",
"learn_more" : "더 알아보기", "learn_more" : "더 알아보기",
"search": "찾다",
"new_template" : "새 템플릿", "new_template" : "새 템플릿",
"electrum_address_disclaimer": "사용할 때마다 새 주소가 생성되지만 이전 주소는 계속 작동합니다." "electrum_address_disclaimer": "사용할 때마다 새 주소가 생성되지만 이전 주소는 계속 작동합니다."
} }

View file

@ -524,7 +524,7 @@
"third_intro_title" : "Yat speelt leuk met anderen", "third_intro_title" : "Yat speelt leuk met anderen",
"third_intro_content" : "Yats wonen ook buiten Cake Wallet. Elk portemonnee-adres op aarde kan worden vervangen door een Yat!", "third_intro_content" : "Yats wonen ook buiten Cake Wallet. Elk portemonnee-adres op aarde kan worden vervangen door een Yat!",
"learn_more" : "Kom meer te weten", "learn_more" : "Kom meer te weten",
"search": "Zoekopdracht",
"new_template" : "Nieuwe sjabloon", "new_template" : "Nieuwe sjabloon",
"electrum_address_disclaimer": "We generate new addresses each time you use one, but previous addresses continue to work" "electrum_address_disclaimer": "We generate new addresses each time you use one, but previous addresses continue to work"
} }

View file

@ -527,7 +527,7 @@
"third_intro_title" : "Yat ładnie bawi się z innymi", "third_intro_title" : "Yat ładnie bawi się z innymi",
"third_intro_content" : "Yats mieszkają również poza Cake Wallet. Każdy adres portfela na ziemi można zastąpić Yat!", "third_intro_content" : "Yats mieszkają również poza Cake Wallet. Każdy adres portfela na ziemi można zastąpić Yat!",
"learn_more" : "Ucz się więcej", "learn_more" : "Ucz się więcej",
"search": "Szukaj",
"new_template" : "Nowy szablon", "new_template" : "Nowy szablon",
"electrum_address_disclaimer": "Za każdym razem, gdy korzystasz z jednego z nich, generujemy nowe adresy, ale poprzednie adresy nadal działają" "electrum_address_disclaimer": "Za każdym razem, gdy korzystasz z jednego z nich, generujemy nowe adresy, ale poprzednie adresy nadal działają"
} }

View file

@ -524,7 +524,7 @@
"third_intro_title" : "Yat joga bem com os outros", "third_intro_title" : "Yat joga bem com os outros",
"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!", "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!",
"learn_more" : "Saber mais", "learn_more" : "Saber mais",
"search": "Procurar",
"new_template" : "Novo modelo", "new_template" : "Novo modelo",
"electrum_address_disclaimer": "Geramos novos endereços cada vez que você usa um, mas os endereços anteriores continuam funcionando" "electrum_address_disclaimer": "Geramos novos endereços cada vez que você usa um, mas os endereços anteriores continuam funcionando"
} }

View file

@ -524,7 +524,7 @@
"third_intro_title" : "Yat хорошо взаимодействует с другими", "third_intro_title" : "Yat хорошо взаимодействует с другими",
"third_intro_content" : "Yat находятся за пределами Cake Wallet. Любой адрес кошелька на земле можно заменить на Yat!", "third_intro_content" : "Yat находятся за пределами Cake Wallet. Любой адрес кошелька на земле можно заменить на Yat!",
"learn_more" : "Узнать больше", "learn_more" : "Узнать больше",
"search": "Поиск",
"new_template" : "Новый шаблон", "new_template" : "Новый шаблон",
"electrum_address_disclaimer": "Мы генерируем новые адреса каждый раз, когда вы их используете, но предыдущие адреса продолжают работать." "electrum_address_disclaimer": "Мы генерируем новые адреса каждый раз, когда вы их используете, но предыдущие адреса продолжают работать."
} }

View file

@ -523,7 +523,7 @@
"third_intro_title" : "Yat добре взаємодіє з іншими", "third_intro_title" : "Yat добре взаємодіє з іншими",
"third_intro_content" : "Yat знаходиться за межами Cake Wallet. Будь-яку адресу гаманця на землі можна замінити на Yat!", "third_intro_content" : "Yat знаходиться за межами Cake Wallet. Будь-яку адресу гаманця на землі можна замінити на Yat!",
"learn_more" : "Дізнатися більше", "learn_more" : "Дізнатися більше",
"search": "Пошук",
"new_template" : "Новий шаблон", "new_template" : "Новий шаблон",
"electrum_address_disclaimer": "Ми створюємо нові адреси щоразу, коли ви використовуєте їх, але попередні адреси продовжують працювати" "electrum_address_disclaimer": "Ми створюємо нові адреси щоразу, коли ви використовуєте їх, але попередні адреси продовжують працювати"
} }

View file

@ -522,7 +522,7 @@
"third_intro_title" : "Yat 和別人玩得很好", "third_intro_title" : "Yat 和別人玩得很好",
"third_intro_content" : "Yats 也住在 Cake Wallet 之外。 地球上任何一個錢包地址都可以用一個Yat來代替", "third_intro_content" : "Yats 也住在 Cake Wallet 之外。 地球上任何一個錢包地址都可以用一個Yat來代替",
"learn_more" : "了解更多", "learn_more" : "了解更多",
"search": "搜索",
"new_template" : "新模板", "new_template" : "新模板",
"electrum_address_disclaimer": "每次您使用一个地址时,我们都会生成新地址,但之前的地址仍然有效" "electrum_address_disclaimer": "每次您使用一个地址时,我们都会生成新地址,但之前的地址仍然有效"
} }