Cw 09 implement picker screen with ability to search (#250)
* Added new picker screen with search bar and currency icons
BIN
assets/images/ada_icon.png
Normal file
After Width: | Height: | Size: 5.5 KiB |
BIN
assets/images/bch_icon.png
Normal file
After Width: | Height: | Size: 3.4 KiB |
BIN
assets/images/bitcoin_icon.png
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
assets/images/bnb_icon.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
assets/images/btc.png
Normal file
After Width: | Height: | Size: 4.9 KiB |
BIN
assets/images/dai_icon.png
Normal file
After Width: | Height: | Size: 4.6 KiB |
BIN
assets/images/dash_icon.png
Normal file
After Width: | Height: | Size: 2.2 KiB |
BIN
assets/images/eos_icon.png
Normal file
After Width: | Height: | Size: 2.9 KiB |
BIN
assets/images/eth_icon.png
Normal file
After Width: | Height: | Size: 3.4 KiB |
BIN
assets/images/litecoin-ltc_icon.png
Normal file
After Width: | Height: | Size: 4.7 KiB |
BIN
assets/images/litecoin_img.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
assets/images/monero_icon.png
Normal file
After Width: | Height: | Size: 20 KiB |
BIN
assets/images/trx_icon.png
Normal file
After Width: | Height: | Size: 6.7 KiB |
BIN
assets/images/usdt_icon.png
Normal file
After Width: | Height: | Size: 2.1 KiB |
BIN
assets/images/usdterc20_icon.png
Normal file
After Width: | Height: | Size: 4.9 KiB |
BIN
assets/images/usdterc_icon.png
Normal file
After Width: | Height: | Size: 391 B |
BIN
assets/images/xlm_icon.png
Normal file
After Width: | Height: | Size: 2.4 KiB |
BIN
assets/images/xrp_icon.png
Normal file
After Width: | Height: | Size: 2.3 KiB |
|
@ -206,8 +206,8 @@ class ExchangePage extends BasePage {
|
|||
onCurrencySelected: (currency) {
|
||||
// FIXME: need to move it into view model
|
||||
if (currency == CryptoCurrency.xmr &&
|
||||
exchangeViewModel.wallet.type ==
|
||||
WalletType.bitcoin) {
|
||||
exchangeViewModel.wallet.type !=
|
||||
WalletType.monero) {
|
||||
showPopUp<void>(
|
||||
context: context,
|
||||
builder: (dialogContext) {
|
||||
|
|
|
@ -1,176 +1,210 @@
|
|||
import 'dart:ui';
|
||||
import 'package:cake_wallet/generated/i18n.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/material.dart';
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
import 'package:cake_wallet/src/widgets/alert_background.dart';
|
||||
import 'package:cake_wallet/src/widgets/alert_close_button.dart';
|
||||
import 'package:cake_wallet/src/widgets/cake_scrollbar.dart';
|
||||
import 'currency_picker_widget.dart';
|
||||
|
||||
class CurrencyPicker extends StatefulWidget {
|
||||
CurrencyPicker({
|
||||
@required this.selectedAtIndex,
|
||||
@required this.items,
|
||||
@required this.title,
|
||||
@required this.onItemSelected,
|
||||
});
|
||||
CurrencyPicker(
|
||||
{@required this.selectedAtIndex,
|
||||
@required this.items,
|
||||
@required this.title,
|
||||
@required this.onItemSelected,
|
||||
this.isMoneroWallet = false,
|
||||
this.isConvertFrom = false});
|
||||
|
||||
final int selectedAtIndex;
|
||||
int selectedAtIndex;
|
||||
final List<CryptoCurrency> items;
|
||||
final String title;
|
||||
final Function(CryptoCurrency) onItemSelected;
|
||||
final bool isMoneroWallet;
|
||||
final bool isConvertFrom;
|
||||
|
||||
@override
|
||||
CurrencyPickerState createState() => CurrencyPickerState(
|
||||
selectedAtIndex,
|
||||
items,
|
||||
title,
|
||||
onItemSelected
|
||||
);
|
||||
CurrencyPickerState createState() => CurrencyPickerState(items);
|
||||
}
|
||||
|
||||
class CurrencyPickerState extends State<CurrencyPicker> {
|
||||
CurrencyPickerState(
|
||||
this.selectedAtIndex,
|
||||
this.items,
|
||||
this.title,
|
||||
this.onItemSelected): itemsCount = items.length;
|
||||
CurrencyPickerState(this.items)
|
||||
: isSearchBarActive = false,
|
||||
textFieldValue = '',
|
||||
subPickerItemsList = [],
|
||||
appBarTextStyle = TextStyle(
|
||||
fontSize: 20,
|
||||
fontFamily: 'Lato',
|
||||
backgroundColor: Colors.transparent,
|
||||
color: Colors.white);
|
||||
|
||||
final int selectedAtIndex;
|
||||
final List<CryptoCurrency> items;
|
||||
final String title;
|
||||
final Function(CryptoCurrency) onItemSelected;
|
||||
@override
|
||||
void initState() {
|
||||
pickerItemsList = CryptoCurrency.all
|
||||
.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',
|
||||
color: Palette.darkBlueCraiola,
|
||||
);
|
||||
final int crossAxisCount = 3;
|
||||
final int maxNumberItemsInAlert = 12;
|
||||
final int itemsCount;
|
||||
final double backgroundHeight = 280;
|
||||
final double thumbHeight = 72;
|
||||
ScrollController controller = ScrollController();
|
||||
double fromTop = 0;
|
||||
List<PickerItem<CryptoCurrency>> pickerItemsList;
|
||||
List<CryptoCurrency> items;
|
||||
bool isSearchBarActive;
|
||||
String textFieldValue;
|
||||
List<PickerItem<CryptoCurrency>> subPickerItemsList;
|
||||
TextStyle appBarTextStyle;
|
||||
|
||||
void cleanSubPickerItemsList() {
|
||||
subPickerItemsList = pickerItemsList
|
||||
.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
|
||||
Widget build(BuildContext context) {
|
||||
controller.addListener(() {
|
||||
fromTop = controller.hasClients
|
||||
? (controller.offset / controller.position.maxScrollExtent * (backgroundHeight - thumbHeight))
|
||||
: 0;
|
||||
setState(() {});
|
||||
});
|
||||
|
||||
return AlertBackground(
|
||||
child: Stack(
|
||||
alignment: Alignment.center,
|
||||
children: <Widget>[
|
||||
Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: <Widget>[
|
||||
Container(
|
||||
padding: EdgeInsets.only(left: 24, right: 24),
|
||||
child: Text(
|
||||
title,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
fontFamily: 'Lato',
|
||||
fontWeight: FontWeight.bold,
|
||||
decoration: TextDecoration.none,
|
||||
color: Colors.white
|
||||
child: SafeArea(
|
||||
child: Scaffold(
|
||||
resizeToAvoidBottomInset: false,
|
||||
backgroundColor: Colors.transparent,
|
||||
body: Column(
|
||||
children: [
|
||||
Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 26.0, vertical: 0),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
isSearchBarActive
|
||||
? Expanded(
|
||||
child: Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.spaceBetween,
|
||||
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),
|
||||
child: GestureDetector(
|
||||
onTap: () => null,
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.all(Radius.circular(14)),
|
||||
child: Container(
|
||||
height: 320,
|
||||
width: 300,
|
||||
color: Theme.of(context).accentTextTheme.title.backgroundColor,
|
||||
child: Stack(
|
||||
alignment: Alignment.center,
|
||||
children: <Widget>[
|
||||
GridView.count(
|
||||
padding: EdgeInsets.all(0),
|
||||
controller: controller,
|
||||
crossAxisCount: crossAxisCount,
|
||||
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
|
||||
)
|
||||
],
|
||||
)
|
||||
),
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Container(
|
||||
width: 42.0,
|
||||
alignment: Alignment.topCenter,
|
||||
child: FittedBox(
|
||||
child: FloatingActionButton(
|
||||
elevation: 0,
|
||||
backgroundColor: Colors.white,
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
child: Icon(
|
||||
Icons.close_outlined,
|
||||
color: Palette.darkBlueCraiola,
|
||||
size: 30.0,
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
AlertCloseButton(image: closeButton)
|
||||
],
|
||||
)
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
int getExtraEmptyTilesCount(int crossAxisCount, int itemsCount) {
|
||||
final int tilesInNewRowCount = itemsCount % crossAxisCount;
|
||||
return tilesInNewRowCount == 0 ? 0 : crossAxisCount - tilesInNewRowCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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(),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
;
|
||||
}
|
||||
}
|
61
lib/src/screens/exchange/widgets/currency_picker_widget.dart
Normal 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,
|
||||
);
|
||||
}),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
99
lib/src/screens/exchange/widgets/currency_utils.dart
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -306,126 +306,121 @@ class ExchangeCardState extends State<ExchangeCard> {
|
|||
? Padding(
|
||||
padding: EdgeInsets.only(top: 20),
|
||||
child: AddressTextField(
|
||||
focusNode: widget.addressFocusNode,
|
||||
controller: addressController,
|
||||
placeholder: widget.hasRefundAddress
|
||||
? S.of(context).refund_address
|
||||
: null,
|
||||
options: [
|
||||
AddressTextFieldOption.paste,
|
||||
AddressTextFieldOption.qrCode,
|
||||
AddressTextFieldOption.addressBook,
|
||||
],
|
||||
isBorderExist: false,
|
||||
textStyle: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Colors.white),
|
||||
hintStyle: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Theme.of(context)
|
||||
.accentTextTheme
|
||||
.display4
|
||||
.decorationColor),
|
||||
buttonColor: widget.addressButtonsColor,
|
||||
validator: widget.addressTextFieldValidator,
|
||||
onPushPasteButton: widget.onPushPasteButton,
|
||||
onPushAddressBookButton: widget.onPushAddressBookButton
|
||||
),
|
||||
focusNode: widget.addressFocusNode,
|
||||
controller: addressController,
|
||||
placeholder: widget.hasRefundAddress
|
||||
? S.of(context).refund_address
|
||||
: null,
|
||||
options: [
|
||||
AddressTextFieldOption.paste,
|
||||
AddressTextFieldOption.qrCode,
|
||||
AddressTextFieldOption.addressBook,
|
||||
],
|
||||
isBorderExist: false,
|
||||
textStyle: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Colors.white),
|
||||
hintStyle: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Theme.of(context)
|
||||
.accentTextTheme
|
||||
.display4
|
||||
.decorationColor),
|
||||
buttonColor: widget.addressButtonsColor,
|
||||
validator: widget.addressTextFieldValidator,
|
||||
onPushPasteButton: widget.onPushPasteButton,
|
||||
onPushAddressBookButton: widget.onPushAddressBookButton),
|
||||
)
|
||||
: Padding(
|
||||
padding: EdgeInsets.only(top: 10),
|
||||
child: Builder(
|
||||
builder: (context) => Stack(
|
||||
children: <Widget> [
|
||||
BaseTextFormField(
|
||||
controller: addressController,
|
||||
readOnly: true,
|
||||
borderColor: Colors.transparent,
|
||||
suffixIcon: SizedBox(
|
||||
width: _isMoneroWallet ? 80 : 36
|
||||
),
|
||||
textStyle: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Colors.white),
|
||||
validator: widget.addressTextFieldValidator
|
||||
),
|
||||
Positioned(
|
||||
top: 2,
|
||||
right: 0,
|
||||
child: SizedBox(
|
||||
width: _isMoneroWallet ? 80 : 36,
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
if (_isMoneroWallet) Padding(
|
||||
padding: EdgeInsets.only(left: 10),
|
||||
child: Container(
|
||||
width: 34,
|
||||
height: 34,
|
||||
padding: EdgeInsets.only(top: 0),
|
||||
child: InkWell(
|
||||
onTap: () async {
|
||||
final contact = await Navigator
|
||||
.of(context, rootNavigator: true)
|
||||
.pushNamed(
|
||||
Routes.pickerAddressBook);
|
||||
builder: (context) => Stack(children: <Widget>[
|
||||
BaseTextFormField(
|
||||
controller: addressController,
|
||||
readOnly: true,
|
||||
borderColor: Colors.transparent,
|
||||
suffixIcon:
|
||||
SizedBox(width: _isMoneroWallet ? 80 : 36),
|
||||
textStyle: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Colors.white),
|
||||
validator: widget.addressTextFieldValidator),
|
||||
Positioned(
|
||||
top: 2,
|
||||
right: 0,
|
||||
child: SizedBox(
|
||||
width: _isMoneroWallet ? 80 : 36,
|
||||
child: Row(children: <Widget>[
|
||||
if (_isMoneroWallet)
|
||||
Padding(
|
||||
padding: EdgeInsets.only(left: 10),
|
||||
child: Container(
|
||||
width: 34,
|
||||
height: 34,
|
||||
padding: EdgeInsets.only(top: 0),
|
||||
child: InkWell(
|
||||
onTap: () async {
|
||||
final contact =
|
||||
await Navigator.of(context,
|
||||
rootNavigator: true)
|
||||
.pushNamed(Routes
|
||||
.pickerAddressBook);
|
||||
|
||||
if (contact is ContactBase &&
|
||||
contact.address != null) {
|
||||
setState(() =>
|
||||
addressController.text =
|
||||
contact.address);
|
||||
widget.onPushAddressBookButton
|
||||
?.call(context);
|
||||
}
|
||||
},
|
||||
child: Container(
|
||||
padding: EdgeInsets.all(8),
|
||||
decoration: BoxDecoration(
|
||||
color: widget
|
||||
.addressButtonsColor,
|
||||
borderRadius: BorderRadius
|
||||
.all(Radius.circular(6))),
|
||||
child: Image.asset(
|
||||
'assets/images/open_book.png',
|
||||
color: Theme.of(context)
|
||||
.primaryTextTheme
|
||||
.display1
|
||||
.decorationColor,
|
||||
)),
|
||||
)),
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(left: 2),
|
||||
child: Container(
|
||||
width: 34,
|
||||
height: 34,
|
||||
padding: EdgeInsets.only(top: 0),
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
Clipboard.setData(
|
||||
ClipboardData(
|
||||
text: addressController.text));
|
||||
showBar<void>(
|
||||
context, S.of(context)
|
||||
.copied_to_clipboard);
|
||||
},
|
||||
child: Container(
|
||||
padding: EdgeInsets
|
||||
.fromLTRB(8, 8, 0, 8),
|
||||
color: Colors.transparent,
|
||||
child: copyImage),
|
||||
))
|
||||
)
|
||||
]
|
||||
)
|
||||
)
|
||||
)
|
||||
]
|
||||
)
|
||||
),
|
||||
if (contact is ContactBase &&
|
||||
contact.address != null) {
|
||||
setState(() =>
|
||||
addressController.text =
|
||||
contact.address);
|
||||
widget.onPushAddressBookButton
|
||||
?.call(context);
|
||||
}
|
||||
},
|
||||
child: Container(
|
||||
padding: EdgeInsets.all(8),
|
||||
decoration: BoxDecoration(
|
||||
color: widget
|
||||
.addressButtonsColor,
|
||||
borderRadius:
|
||||
BorderRadius.all(
|
||||
Radius.circular(
|
||||
6))),
|
||||
child: Image.asset(
|
||||
'assets/images/open_book.png',
|
||||
color: Theme.of(context)
|
||||
.primaryTextTheme
|
||||
.display1
|
||||
.decorationColor,
|
||||
)),
|
||||
)),
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(left: 2),
|
||||
child: Container(
|
||||
width: 34,
|
||||
height: 34,
|
||||
padding: EdgeInsets.only(top: 0),
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
Clipboard.setData(ClipboardData(
|
||||
text: addressController
|
||||
.text));
|
||||
showBar<void>(
|
||||
context,
|
||||
S
|
||||
.of(context)
|
||||
.copied_to_clipboard);
|
||||
},
|
||||
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),
|
||||
items: widget.currencies,
|
||||
title: S.of(context).change_currency,
|
||||
isMoneroWallet: _isMoneroWallet,
|
||||
isConvertFrom: widget.hasRefundAddress,
|
||||
onItemSelected: (CryptoCurrency item) =>
|
||||
widget.onCurrencySelected != null
|
||||
? widget.onCurrencySelected(item)
|
||||
|
|
10
lib/src/screens/exchange/widgets/picker_item.dart
Normal 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;
|
||||
}
|
|
@ -69,18 +69,22 @@ class SectionHeaderListRow extends StatelessWidget {
|
|||
}
|
||||
|
||||
class StandardListSeparator extends StatelessWidget {
|
||||
StandardListSeparator({this.padding});
|
||||
|
||||
StandardListSeparator({this.padding,this.height=1});
|
||||
|
||||
final EdgeInsets padding;
|
||||
final double height;
|
||||
|
||||
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
height: 1,
|
||||
height: height,
|
||||
padding: padding,
|
||||
color: Theme.of(context).backgroundColor,
|
||||
child: Container(
|
||||
height: 1,
|
||||
height: height,
|
||||
color: Theme.of(context).primaryTextTheme.title.backgroundColor));
|
||||
}
|
||||
}
|
||||
|
@ -98,6 +102,7 @@ class StandardList extends StatelessWidget {
|
|||
StandardListSeparator(padding: EdgeInsets.only(left: 24)),
|
||||
itemCount: itemCount,
|
||||
itemBuilder: itemBuilder);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -524,7 +524,7 @@
|
|||
"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!",
|
||||
"learn_more" : "Erfahren Sie mehr",
|
||||
|
||||
"search": "Suche",
|
||||
"new_template" : "neue Vorlage",
|
||||
"electrum_address_disclaimer": "Wir generieren jedes Mal neue Adressen, wenn Sie eine verwenden, aber vorherige Adressen funktionieren weiterhin"
|
||||
}
|
||||
|
|
|
@ -524,7 +524,7 @@
|
|||
"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!",
|
||||
"learn_more" : "Learn More",
|
||||
|
||||
"search": "Search",
|
||||
"new_template" : "New Template",
|
||||
"electrum_address_disclaimer": "We generate new addresses each time you use one, but previous addresses continue to work"
|
||||
}
|
|
@ -524,7 +524,7 @@
|
|||
"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!",
|
||||
"learn_more" : "Aprende más",
|
||||
|
||||
"search": "Búsqueda",
|
||||
"new_template" : "Nueva plantilla",
|
||||
"electrum_address_disclaimer": "Generamos nuevas direcciones cada vez que usa una, pero las direcciones anteriores siguen funcionando"
|
||||
}
|
|
@ -524,7 +524,7 @@
|
|||
"third_intro_title" : "Yat दूसरों के साथ अच्छा खेलता है",
|
||||
"third_intro_content" : "Yats Cake Wallet के बाहर भी रहता है। धरती पर किसी भी वॉलेट पते को Yat से बदला जा सकता है!",
|
||||
"learn_more" : "और अधिक जानें",
|
||||
|
||||
"search": "खोज",
|
||||
"new_template" : "नया टेम्पलेट",
|
||||
"electrum_address_disclaimer": "हर बार जब आप एक का उपयोग करते हैं तो हम नए पते उत्पन्न करते हैं, लेकिन पिछले पते काम करना जारी रखते हैं"
|
||||
}
|
|
@ -524,7 +524,7 @@
|
|||
"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!",
|
||||
"learn_more" : "Saznajte više",
|
||||
|
||||
"search": "Traži",
|
||||
"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"
|
||||
}
|
|
@ -524,7 +524,7 @@
|
|||
"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!",
|
||||
"learn_more" : "Impara di più",
|
||||
|
||||
"search": "Ricerca",
|
||||
"new_template" : "Nuovo modello",
|
||||
"electrum_address_disclaimer": "Generiamo nuovi indirizzi ogni volta che ne utilizzi uno, ma gli indirizzi precedenti continuano a funzionare"
|
||||
}
|
|
@ -524,7 +524,7 @@
|
|||
"third_intro_title" : "Yatは他の人とうまく遊ぶ",
|
||||
"third_intro_content" : "YatsはCakeWalletの外にも住んでいます。 地球上のどのウォレットアドレスもYatに置き換えることができます!",
|
||||
"learn_more" : "もっと詳しく知る",
|
||||
|
||||
"search": "検索",
|
||||
"new_template" : "新しいテンプレート",
|
||||
"electrum_address_disclaimer": "使用するたびに新しいアドレスが生成されますが、以前のアドレスは引き続き機能します"
|
||||
}
|
|
@ -524,7 +524,7 @@
|
|||
"third_intro_title" : "Yat는 다른 사람들과 잘 놉니다.",
|
||||
"third_intro_content" : "Yats는 Cake Wallet 밖에서도 살고 있습니다. 지구상의 모든 지갑 주소는 Yat!",
|
||||
"learn_more" : "더 알아보기",
|
||||
|
||||
"search": "찾다",
|
||||
"new_template" : "새 템플릿",
|
||||
"electrum_address_disclaimer": "사용할 때마다 새 주소가 생성되지만 이전 주소는 계속 작동합니다."
|
||||
}
|
|
@ -524,7 +524,7 @@
|
|||
"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!",
|
||||
"learn_more" : "Kom meer te weten",
|
||||
|
||||
"search": "Zoekopdracht",
|
||||
"new_template" : "Nieuwe sjabloon",
|
||||
"electrum_address_disclaimer": "We generate new addresses each time you use one, but previous addresses continue to work"
|
||||
}
|
|
@ -527,7 +527,7 @@
|
|||
"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!",
|
||||
"learn_more" : "Ucz się więcej",
|
||||
|
||||
"search": "Szukaj",
|
||||
"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ą"
|
||||
}
|
|
@ -524,7 +524,7 @@
|
|||
"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!",
|
||||
"learn_more" : "Saber mais",
|
||||
|
||||
"search": "Procurar",
|
||||
"new_template" : "Novo modelo",
|
||||
"electrum_address_disclaimer": "Geramos novos endereços cada vez que você usa um, mas os endereços anteriores continuam funcionando"
|
||||
}
|
|
@ -524,7 +524,7 @@
|
|||
"third_intro_title" : "Yat хорошо взаимодействует с другими",
|
||||
"third_intro_content" : "Yat находятся за пределами Cake Wallet. Любой адрес кошелька на земле можно заменить на Yat!",
|
||||
"learn_more" : "Узнать больше",
|
||||
|
||||
"search": "Поиск",
|
||||
"new_template" : "Новый шаблон",
|
||||
"electrum_address_disclaimer": "Мы генерируем новые адреса каждый раз, когда вы их используете, но предыдущие адреса продолжают работать."
|
||||
}
|
|
@ -523,7 +523,7 @@
|
|||
"third_intro_title" : "Yat добре взаємодіє з іншими",
|
||||
"third_intro_content" : "Yat знаходиться за межами Cake Wallet. Будь-яку адресу гаманця на землі можна замінити на Yat!",
|
||||
"learn_more" : "Дізнатися більше",
|
||||
|
||||
"search": "Пошук",
|
||||
"new_template" : "Новий шаблон",
|
||||
"electrum_address_disclaimer": "Ми створюємо нові адреси щоразу, коли ви використовуєте їх, але попередні адреси продовжують працювати"
|
||||
}
|
|
@ -522,7 +522,7 @@
|
|||
"third_intro_title" : "Yat 和別人玩得很好",
|
||||
"third_intro_content" : "Yats 也住在 Cake Wallet 之外。 地球上任何一個錢包地址都可以用一個Yat來代替!",
|
||||
"learn_more" : "了解更多",
|
||||
|
||||
"search": "搜索",
|
||||
"new_template" : "新模板",
|
||||
"electrum_address_disclaimer": "每次您使用一个地址时,我们都会生成新地址,但之前的地址仍然有效"
|
||||
}
|