CAKE-20 | updated send and send template pages; added send_template_store and exchange_template_store; created base_send_widget; applied send_template_store to send_view_model; applied base_send_widget to send and send template pages; added properties to address_text_field, base_text_field and template_tile

This commit is contained in:
Oleksandr Sobol
2020-07-29 19:55:42 +03:00
parent d5f707f652
commit fe9deecd03
35 changed files with 1272 additions and 1055 deletions
+122 -85
View File
@@ -1,26 +1,31 @@
import 'package:cake_wallet/palette.dart';
import 'package:cake_wallet/routes.dart';
import 'package:flutter/material.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/src/domain/common/contact.dart';
import 'package:cake_wallet/src/domain/monero/subaddress.dart';
import 'package:cake_wallet/src/domain/common/qr_scanner.dart';
import 'package:flutter/services.dart';
enum AddressTextFieldOption { qrCode, addressBook, subaddressList }
enum AddressTextFieldOption { paste, qrCode, addressBook, subaddressList }
class AddressTextField extends StatelessWidget {
AddressTextField(
{@required this.controller,
this.isActive = true,
this.placeholder,
this.options = const [
AddressTextFieldOption.qrCode,
AddressTextFieldOption.addressBook
],
this.onURIScanned,
this.focusNode,
this.isBorderExist = true,
this.buttonColor,
this.validator});
this.isActive = true,
this.placeholder,
this.options = const [
AddressTextFieldOption.qrCode,
AddressTextFieldOption.addressBook
],
this.onURIScanned,
this.focusNode,
this.isBorderExist = true,
this.buttonColor,
this.borderColor,
this.textStyle,
this.hintStyle,
this.validator});
static const prefixIconWidth = 34.0;
static const prefixIconHeight = 34.0;
@@ -34,6 +39,9 @@ class AddressTextField extends StatelessWidget {
final FormFieldValidator<String> validator;
final bool isBorderExist;
final Color buttonColor;
final Color borderColor;
final TextStyle textStyle;
final TextStyle hintStyle;
FocusNode focusNode;
@override
@@ -45,106 +53,125 @@ class AddressTextField extends StatelessWidget {
enabled: isActive,
controller: controller,
focusNode: focusNode,
style: TextStyle(
style: textStyle ?? TextStyle(
fontSize: 16,
color: Theme.of(context).primaryTextTheme.title.color
color: Colors.white
),
decoration: InputDecoration(
suffixIcon: SizedBox(
width: prefixIconWidth * options.length +
(spaceBetweenPrefixIcons * options.length),
),
hintStyle: TextStyle(
hintStyle: hintStyle ?? TextStyle(
fontSize: 16,
color: Theme.of(context).primaryTextTheme.caption.color
color: PaletteDark.darkCyanBlue
),
hintText: placeholder ?? S.current.widgets_address,
focusedBorder: isBorderExist
? UnderlineInputBorder(
borderSide: BorderSide(
color: Theme.of(context).dividerColor,
color: borderColor ?? Theme.of(context).dividerColor,
width: 1.0))
: InputBorder.none,
disabledBorder: isBorderExist
? UnderlineInputBorder(
borderSide:
BorderSide(color: Theme.of(context).dividerColor, width: 1.0))
BorderSide(color: borderColor ?? Theme.of(context).dividerColor, width: 1.0))
: InputBorder.none,
enabledBorder: isBorderExist
? UnderlineInputBorder(
borderSide:
BorderSide(color: Theme.of(context).dividerColor, width: 1.0))
BorderSide(color: borderColor ?? Theme.of(context).dividerColor, width: 1.0))
: InputBorder.none,
),
validator: validator,
),
Positioned(
bottom: 10,
right: 0,
child: SizedBox(
width: prefixIconWidth * options.length +
(spaceBetweenPrefixIcons * options.length),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
SizedBox(width: 5),
if (this.options.contains(AddressTextFieldOption.qrCode)) ...[
Container(
width: prefixIconWidth,
height: prefixIconHeight,
padding: EdgeInsets.only(top: 0),
child: InkWell(
onTap: () async => _presentQRScanner(context),
child: Container(
padding: EdgeInsets.all(8),
decoration: BoxDecoration(
color: buttonColor ?? Theme.of(context).accentTextTheme.title.color,
borderRadius:
BorderRadius.all(Radius.circular(6))),
child: Image.asset('assets/images/qr_code_icon.png')),
))
top: 2,
right: 0,
child: SizedBox(
width: prefixIconWidth * options.length +
(spaceBetweenPrefixIcons * options.length),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
SizedBox(width: 5),
if (this
.options
.contains(AddressTextFieldOption.paste)) ...[
Container(
width: prefixIconWidth,
height: prefixIconHeight,
padding: EdgeInsets.only(top: 0),
child: InkWell(
onTap: () async => _pasteAddress(context),
child: Container(
padding: EdgeInsets.all(8),
decoration: BoxDecoration(
color: buttonColor ?? Theme.of(context).accentTextTheme.title.color,
borderRadius:
BorderRadius.all(Radius.circular(6))),
child: Image.asset(
'assets/images/duplicate.png')),
)),
],
if (this.options.contains(AddressTextFieldOption.qrCode)) ...[
Container(
width: prefixIconWidth,
height: prefixIconHeight,
padding: EdgeInsets.only(top: 0),
child: InkWell(
onTap: () async => _presentQRScanner(context),
child: Container(
padding: EdgeInsets.all(8),
decoration: BoxDecoration(
color: buttonColor ?? Theme.of(context).accentTextTheme.title.color,
borderRadius:
BorderRadius.all(Radius.circular(6))),
child: Image.asset('assets/images/qr_code_icon.png')),
))
],
if (this
.options
.contains(AddressTextFieldOption.addressBook)) ...[
Container(
width: prefixIconWidth,
height: prefixIconHeight,
padding: EdgeInsets.only(top: 0),
child: InkWell(
onTap: () async => _presetAddressBookPicker(context),
child: Container(
padding: EdgeInsets.all(8),
decoration: BoxDecoration(
color: buttonColor ?? Theme.of(context).accentTextTheme.title.color,
borderRadius:
BorderRadius.all(Radius.circular(6))),
child: Image.asset(
'assets/images/open_book.png')),
))
],
if (this
.options
.contains(AddressTextFieldOption.subaddressList)) ...[
Container(
width: prefixIconWidth,
height: prefixIconHeight,
padding: EdgeInsets.only(top: 0),
child: InkWell(
onTap: () async => _presetSubaddressListPicker(context),
child: Container(
padding: EdgeInsets.all(8),
decoration: BoxDecoration(
color: buttonColor ?? Theme.of(context).accentTextTheme.title.color,
borderRadius:
BorderRadius.all(Radius.circular(6))),
child: Image.asset(
'assets/images/receive_icon_raw.png')),
)),
],
],
if (this
.options
.contains(AddressTextFieldOption.addressBook)) ...[
Container(
width: prefixIconWidth,
height: prefixIconHeight,
padding: EdgeInsets.only(top: 0),
child: InkWell(
onTap: () async => _presetAddressBookPicker(context),
child: Container(
padding: EdgeInsets.all(8),
decoration: BoxDecoration(
color: buttonColor ?? Theme.of(context).accentTextTheme.title.color,
borderRadius:
BorderRadius.all(Radius.circular(6))),
child: Image.asset(
'assets/images/open_book.png')),
))
],
if (this
.options
.contains(AddressTextFieldOption.subaddressList)) ...[
Container(
width: prefixIconWidth,
height: prefixIconHeight,
padding: EdgeInsets.only(top: 0),
child: InkWell(
onTap: () async => _presetSubaddressListPicker(context),
child: Container(
padding: EdgeInsets.all(8),
decoration: BoxDecoration(
color: buttonColor ?? Theme.of(context).accentTextTheme.title.color,
borderRadius:
BorderRadius.all(Radius.circular(6))),
child: Image.asset(
'assets/images/receive_icon_raw.png')),
))
],
],
),
)
),
)
)
],
);
@@ -189,4 +216,14 @@ class AddressTextField extends StatelessWidget {
controller.text = subaddress.address;
}
}
}
Future<void> _pasteAddress(BuildContext context) async {
String address;
await Clipboard.getData('text/plain').then((value) => address = value.text);
if (address.isNotEmpty) {
controller.text = address;
}
}
}
+6 -1
View File
@@ -15,10 +15,12 @@ class BaseTextFormField extends StatelessWidget {
this.hintColor,
this.borderColor,
this.prefix,
this.prefixIcon,
this.suffix,
this.suffixIcon,
this.enabled = true,
this.validator,
this.textStyle,
this.placeholderTextStyle});
final TextEditingController controller;
@@ -33,11 +35,13 @@ class BaseTextFormField extends StatelessWidget {
final Color hintColor;
final Color borderColor;
final Widget prefix;
final Widget prefixIcon;
final Widget suffix;
final Widget suffixIcon;
final bool enabled;
final FormFieldValidator<String> validator;
final TextStyle placeholderTextStyle;
final TextStyle textStyle;
@override
Widget build(BuildContext context) {
@@ -50,11 +54,12 @@ class BaseTextFormField extends StatelessWidget {
maxLines: maxLines,
inputFormatters: inputFormatters,
enabled: enabled,
style: TextStyle(
style: textStyle ?? TextStyle(
fontSize: 16.0,
color: textColor ?? Theme.of(context).primaryTextTheme.title.color),
decoration: InputDecoration(
prefix: prefix,
prefixIcon: prefixIcon,
suffix: suffix,
suffixIcon: suffixIcon,
hintStyle: placeholderTextStyle ??
+134 -57
View File
@@ -1,77 +1,154 @@
import 'package:flutter/material.dart';
import 'package:cake_wallet/palette.dart';
class TemplateTile extends StatelessWidget {
class TemplateTile extends StatefulWidget {
TemplateTile({
Key key,
@required this.to,
@required this.amount,
@required this.from,
@required this.onTap
});
@required this.onTap,
@required this.onRemove
}) : super(key: key);
final String to;
final String amount;
final String from;
final VoidCallback onTap;
final VoidCallback onRemove;
@override
TemplateTileState createState() => TemplateTileState(
to,
amount,
from,
onTap,
onRemove
);
}
class TemplateTileState extends State<TemplateTile> {
TemplateTileState(
this.to,
this.amount,
this.from,
this.onTap,
this.onRemove
);
final String to;
final String amount;
final String from;
final VoidCallback onTap;
final VoidCallback onRemove;
final trash = Image.asset('assets/images/trash.png', height: 16, width: 16, color: Colors.white);
bool isRemovable = false;
@override
Widget build(BuildContext context) {
final toIcon = Image.asset('assets/images/to_icon.png',
color: Theme.of(context).primaryTextTheme.title.color,
);
//final color = isRemovable ? Colors.white : Theme.of(context).primaryTextTheme.title.color;
final color = Colors.white;
final toIcon = Image.asset('assets/images/to_icon.png', color: color);
return Container(
padding: EdgeInsets.only(right: 10),
child: GestureDetector(
onTap: onTap,
child: Container(
height: 40,
padding: EdgeInsets.only(left: 24, right: 24),
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(20)),
color: Theme.of(context).accentTextTheme.title.backgroundColor
),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Text(
amount,
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
color: Theme.of(context).primaryTextTheme.title.color
),
),
Padding(
padding: EdgeInsets.only(left: 5),
child: Text(
from,
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
color: Theme.of(context).primaryTextTheme.title.color
),
),
),
Padding(
padding: EdgeInsets.only(left: 5),
child: toIcon,
),
Padding(
padding: EdgeInsets.only(left: 5),
child: Text(
to,
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
color: Theme.of(context).primaryTextTheme.title.color
),
),
),
],
final content = Row(
mainAxisAlignment: MainAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Text(
amount,
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
color: color
),
),
),
Padding(
padding: EdgeInsets.only(left: 5),
child: Text(
from,
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
color: color
),
),
),
Padding(
padding: EdgeInsets.only(left: 5),
child: toIcon,
),
Padding(
padding: EdgeInsets.only(left: 5),
child: Text(
to,
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
color: color
),
),
),
],
);
final tile = Container(
padding: EdgeInsets.only(right: 10),
child: ClipRRect(
borderRadius: BorderRadius.all(Radius.circular(20)),
child: GestureDetector(
onTap: onTap,
onLongPress: () {
setState(() {
isRemovable = true;
});
},
child: Container(
height: 40,
padding: EdgeInsets.only(left: 24, right: 24),
color: PaletteDark.darkVioletBlue,
child: content,
),
),
)
);
final removableTile = Container(
padding: EdgeInsets.only(right: 10),
child: ClipRRect(
borderRadius: BorderRadius.all(Radius.circular(20)),
child: Row(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
GestureDetector(
onTap: () {
setState(() {
isRemovable = false;
});
},
child: Container(
height: 40,
padding: EdgeInsets.only(left: 24, right: 10),
color: Colors.red,
child: content,
),
),
GestureDetector(
onTap: onRemove,
child: Container(
height: 40,
width: 44,
color: Palette.darkRed,
child: Center(
child: trash,
),
),
)
],
)
)
);
return isRemovable ? removableTile : tile;
}
}