Redesign exchange currency picker (#402)

This commit is contained in:
Omar Hatem 2022-07-01 12:17:09 +02:00 committed by GitHub
parent 02533d68a0
commit 3bd9301be1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 259 additions and 306 deletions

View file

@ -150,6 +150,7 @@ class ContactPage extends BasePage {
contactViewModel.currencies.indexOf(contactViewModel.currency),
items: contactViewModel.currencies,
title: S.of(context).please_select,
hintText: S.of(context).search_currency,
onItemSelected: (CryptoCurrency item) =>
contactViewModel.currency = item),
context: context);

View file

@ -1,8 +1,8 @@
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_picker_item_widget.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:cake_wallet/src/widgets/alert_close_button.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:cw_core/crypto_currency.dart';
@ -13,8 +13,9 @@ class CurrencyPicker extends StatefulWidget {
CurrencyPicker(
{@required this.selectedAtIndex,
@required this.items,
@required this.title,
@required this.onItemSelected,
this.title,
this.hintText,
this.isMoneroWallet = false,
this.isConvertFrom = false});
@ -24,6 +25,7 @@ class CurrencyPicker extends StatefulWidget {
final Function(CryptoCurrency) onItemSelected;
final bool isMoneroWallet;
final bool isConvertFrom;
final String hintText;
@override
CurrencyPickerState createState() => CurrencyPickerState(items);
@ -34,11 +36,8 @@ class CurrencyPickerState extends State<CurrencyPicker> {
: isSearchBarActive = false,
textFieldValue = '',
subPickerItemsList = [],
appBarTextStyle = TextStyle(
fontSize: 20,
fontFamily: 'Lato',
backgroundColor: Colors.transparent,
color: Colors.white);
appBarTextStyle =
TextStyle(fontSize: 20, fontFamily: 'Lato', backgroundColor: Colors.transparent, color: Colors.white);
@override
void initState() {
@ -61,13 +60,10 @@ class CurrencyPickerState extends State<CurrencyPicker> {
TextStyle appBarTextStyle;
void cleanSubPickerItemsList() {
subPickerItemsList = pickerItemsList
.where((element) => items.contains(element.original))
.toList();
subPickerItemsList = pickerItemsList.where((element) => items.contains(element.original)).toList();
}
void currencySearchBySubstring(
String subString, List<PickerItem<CryptoCurrency>> list) {
void currencySearchBySubstring(String subString, List<PickerItem<CryptoCurrency>> list) {
setState(() {
if (subString.isNotEmpty) {
subPickerItemsList = subPickerItemsList
@ -84,118 +80,104 @@ class CurrencyPickerState extends State<CurrencyPicker> {
@override
Widget build(BuildContext context) {
return AlertBackground(
child: SafeArea(
child: Scaffold(
resizeToAvoidBottomInset: false,
backgroundColor: Colors.transparent,
body: Column(
child: Stack(
alignment: Alignment.center,
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();
});
}),
Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
if (widget.title?.isNotEmpty ?? false)
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,
padding: EdgeInsets.symmetric(horizontal: 24),
child: Text(
widget.title,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 18,
fontFamily: 'Lato',
fontWeight: FontWeight.bold,
decoration: TextDecoration.none,
color: Colors.white,
),
),
),
Padding(
padding: EdgeInsets.only(left: 24, right: 24, top: 24),
child: ClipRRect(
borderRadius: BorderRadius.all(Radius.circular(30)),
child: Container(
color: Theme.of(context).accentTextTheme.title.color,
child: ConstrainedBox(
constraints: BoxConstraints(
maxHeight: MediaQuery.of(context).size.height * 0.65,
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
if (widget.hintText != null)
Padding(
padding: const EdgeInsets.all(16),
child: TextFormField(
style: TextStyle(color: Theme.of(context).primaryTextTheme.title.color),
decoration: InputDecoration(
hintText: widget.hintText,
prefixIcon: Image.asset("assets/images/search_icon.png"),
filled: true,
fillColor: const Color(0xffF2F0FA),
alignLabelWithHint: false,
contentPadding: const EdgeInsets.symmetric(vertical: 4, horizontal: 16),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(14),
borderSide: const BorderSide(
color: Colors.transparent,
)),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(14),
borderSide: const BorderSide(
color: Colors.transparent,
)),
),
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;
});
currencySearchBySubstring(textFieldValue, subPickerItemsList);
},
)
]),
),
Expanded(
flex: 12,
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: 26.0, vertical: 26.0),
child: Container(
),
Divider(
color: Theme.of(context).accentTextTheme.title.backgroundColor,
height: 1,
),
if (widget.selectedAtIndex != -1)
AspectRatio(
aspectRatio: 6,
child: PickerItemWidget(
title: pickerItemsList[widget.selectedAtIndex].title,
iconPath: pickerItemsList[widget.selectedAtIndex].iconPath,
isSelected: true,
tag: pickerItemsList[widget.selectedAtIndex].tag,
),
),
Flexible(
child: CurrencyPickerWidget(
crossAxisCount: 2,
selectedAtIndex: widget.selectedAtIndex,
itemsCount: subPickerItemsList.length,
pickerItemsList: subPickerItemsList,
pickListItem: (int index) {
setState(() {
widget.selectedAtIndex = index;
});
widget
.onItemSelected(subPickerItemsList[index].original);
widget.onItemSelected(subPickerItemsList[index].original);
if (widget.isConvertFrom &&
!widget.isMoneroWallet &&
(subPickerItemsList[index].original ==
CryptoCurrency.xmr)) {
(subPickerItemsList[index].original == CryptoCurrency.xmr)) {
} else {
Navigator.of(context).pop();
}
},
),
),
),
),
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,
],
),
),
),
@ -203,7 +185,8 @@ class CurrencyPickerState extends State<CurrencyPicker> {
),
],
),
),
AlertCloseButton(),
],
),
);
}

View file

@ -2,8 +2,7 @@ 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});
const PickerItemWidget({this.iconPath, this.title, this.isSelected = false, this.tag, this.onTap});
final String iconPath;
final String title;
@ -16,43 +15,34 @@ class PickerItemWidget extends StatelessWidget {
return GestureDetector(
onTap: onTap,
child: Container(
color: isSelected
? Theme.of(context).textTheme.bodyText1.color
: Theme.of(context).accentTextTheme.headline6.color,
child: Center(
color: Theme.of(context).accentTextTheme.headline6.color,
child: Padding(
padding: const EdgeInsets.all(8.0),
padding: const EdgeInsets.symmetric(vertical: 8.0, horizontal: 24),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Expanded(
child: Container(
Container(
child: Image.asset(
iconPath,
height: 32.0,
width: 32.0,
),
height: 20.0,
width: 20.0,
),
),
const SizedBox(width: 6),
Expanded(
child: Stack(
clipBehavior: Clip.none,
alignment: Alignment.centerLeft,
child: Row(
children: [
Text(
title,
style: TextStyle(
color: isSelected
? Palette.blueCraiola
: Theme.of(context).primaryTextTheme.title.color,
fontSize: 18.0,
color: isSelected ? Palette.blueCraiola : Theme.of(context).primaryTextTheme.title.color,
fontSize: isSelected ? 16 : 14.0,
fontFamily: 'Lato',
fontWeight: FontWeight.w600,
),
),
tag != null
? Positioned(
top: -20.0,
right: 7.0,
if (tag != null)
Align(
alignment: Alignment.topCenter,
child: Container(
width: 35.0,
height: 18.0,
@ -60,31 +50,22 @@ class PickerItemWidget extends StatelessWidget {
child: Text(
tag,
style: TextStyle(
fontSize: 7.0,
fontFamily: 'Lato',
color: Theme.of(context)
.textTheme
.body1
.color),
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,
color: Theme.of(context).textTheme.body1.decorationColor,
),
),
)
: Container(),
],
),
),
],
),
),
if (isSelected) Icon(Icons.check_circle, color: Theme.of(context).accentTextTheme.body2.color)
],
),
),
),
);

View file

@ -4,42 +4,35 @@ import 'picker_item.dart';
import 'currency_picker_item_widget.dart';
class CurrencyPickerWidget extends StatelessWidget {
const CurrencyPickerWidget({
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;
final ScrollController _scrollController = ScrollController();
@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),
controller: _scrollController,
child: GridView.builder(
controller: _scrollController,
padding: EdgeInsets.zero,
shrinkWrap: true,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: crossAxisCount,
crossAxisSpacing: 1,
mainAxisExtent: constraints.maxHeight / 8,
mainAxisSpacing: 1),
crossAxisSpacing: 2,
childAspectRatio: 3,
),
itemCount: pickerItemsList.length,
itemBuilder: (BuildContext ctx, index) {
return PickerItemWidget(
@ -48,14 +41,10 @@ class CurrencyPickerWidget extends StatelessWidget {
},
title: pickerItemsList[index].title,
iconPath: pickerItemsList[index].iconPath,
isSelected: index == selectedAtIndex,
tag: pickerItemsList[index].tag,
);
}),
),
),
);
},
);
}
}

View file

@ -445,7 +445,7 @@ class ExchangeCardState extends State<ExchangeCard> {
builder: (_) => CurrencyPicker(
selectedAtIndex: widget.currencies.indexOf(_selectedCurrency),
items: widget.currencies,
title: S.of(context).change_currency,
hintText: S.of(context).search_currency,
isMoneroWallet: _isMoneroWallet,
isConvertFrom: widget.hasRefundAddress,
onItemSelected: (CryptoCurrency item) =>

View file

@ -1,10 +1,16 @@
import 'package:cake_wallet/palette.dart';
import 'package:flutter/material.dart';
class AlertCloseButton extends StatelessWidget {
AlertCloseButton({@required this.image});
AlertCloseButton({this.image});
final Image image;
final closeButton = Image.asset(
'assets/images/close.png',
color: Palette.darkBlueCraiola,
);
@override
Widget build(BuildContext context) {
return Positioned(
@ -19,7 +25,7 @@ class AlertCloseButton extends StatelessWidget {
shape: BoxShape.circle
),
child: Center(
child: image,
child: image ?? closeButton,
),
),
)

View file

@ -3,7 +3,6 @@ import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:cake_wallet/src/widgets/alert_background.dart';
import 'package:cake_wallet/src/widgets/alert_close_button.dart';
import 'package:cake_wallet/palette.dart';
class Picker<Item extends Object> extends StatefulWidget {
Picker({
@ -49,10 +48,6 @@ class PickerState<Item> extends State<Picker> {
final TextEditingController searchController = TextEditingController();
final closeButton = Image.asset(
'assets/images/close.png',
color: Palette.darkBlueCraiola,
);
ScrollController controller = ScrollController();
@override
@ -98,8 +93,6 @@ class PickerState<Item> extends State<Picker> {
),
Padding(
padding: EdgeInsets.only(left: 24, right: 24, top: 24),
child: GestureDetector(
onTap: () => null,
child: ClipRRect(
borderRadius: BorderRadius.all(Radius.circular(30)),
child: Container(
@ -176,11 +169,10 @@ class PickerState<Item> extends State<Picker> {
),
),
),
),
)
],
),
AlertCloseButton(image: closeButton)
AlertCloseButton(),
],
),
);
@ -193,6 +185,7 @@ class PickerState<Item> extends State<Picker> {
? GridView.builder(
padding: EdgeInsets.zero,
controller: controller,
shrinkWrap: true,
itemCount: items == null || items.isEmpty ? 0 : items.length,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,