align the hint with the prefix in the text field (#1571)

* Update send_card.dart

* update currency amount text field widget

* Update qr_widget.dart
This commit is contained in:
Serhii 2024-08-10 00:48:36 +03:00 committed by GitHub
parent fb33a6f23d
commit 14e99daa73
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 371 additions and 650 deletions

View file

@ -67,17 +67,6 @@ class ExchangePage extends BasePage {
Debounce _depositAmountDebounce = Debounce(Duration(milliseconds: 500)); Debounce _depositAmountDebounce = Debounce(Duration(milliseconds: 500));
var _isReactionsSet = false; var _isReactionsSet = false;
final arrowBottomPurple = Image.asset(
'assets/images/arrow_bottom_purple_icon.png',
color: Colors.white,
height: 8,
);
final arrowBottomCakeGreen = Image.asset(
'assets/images/arrow_bottom_cake_green.png',
color: Colors.white,
height: 8,
);
late final String? depositWalletName; late final String? depositWalletName;
late final String? receiveWalletName; late final String? receiveWalletName;
@ -101,11 +90,11 @@ class ExchangePage extends BasePage {
@override @override
Function(BuildContext)? get pushToNextWidget => (context) { Function(BuildContext)? get pushToNextWidget => (context) {
FocusScopeNode currentFocus = FocusScope.of(context); FocusScopeNode currentFocus = FocusScope.of(context);
if (!currentFocus.hasPrimaryFocus) { if (!currentFocus.hasPrimaryFocus) {
currentFocus.focusedChild?.unfocus(); currentFocus.focusedChild?.unfocus();
} }
}; };
@override @override
Widget middle(BuildContext context) => Row( Widget middle(BuildContext context) => Row(
@ -340,7 +329,6 @@ class ExchangePage extends BasePage {
void applyTemplate( void applyTemplate(
BuildContext context, ExchangeViewModel exchangeViewModel, ExchangeTemplate template) async { BuildContext context, ExchangeViewModel exchangeViewModel, ExchangeTemplate template) async {
final depositCryptoCurrency = CryptoCurrency.fromString(template.depositCurrency); final depositCryptoCurrency = CryptoCurrency.fromString(template.depositCurrency);
final receiveCryptoCurrency = CryptoCurrency.fromString(template.receiveCurrency); final receiveCryptoCurrency = CryptoCurrency.fromString(template.receiveCurrency);
@ -354,10 +342,12 @@ class ExchangePage extends BasePage {
exchangeViewModel.isFixedRateMode = false; exchangeViewModel.isFixedRateMode = false;
var domain = template.depositAddress; var domain = template.depositAddress;
exchangeViewModel.depositAddress = await fetchParsedAddress(context, domain, depositCryptoCurrency); exchangeViewModel.depositAddress =
await fetchParsedAddress(context, domain, depositCryptoCurrency);
domain = template.receiveAddress; domain = template.receiveAddress;
exchangeViewModel.receiveAddress = await fetchParsedAddress(context, domain, receiveCryptoCurrency); exchangeViewModel.receiveAddress =
await fetchParsedAddress(context, domain, receiveCryptoCurrency);
} }
void _setReactions(BuildContext context, ExchangeViewModel exchangeViewModel) { void _setReactions(BuildContext context, ExchangeViewModel exchangeViewModel) {
@ -529,14 +519,16 @@ class ExchangePage extends BasePage {
_depositAddressFocus.addListener(() async { _depositAddressFocus.addListener(() async {
if (!_depositAddressFocus.hasFocus && depositAddressController.text.isNotEmpty) { if (!_depositAddressFocus.hasFocus && depositAddressController.text.isNotEmpty) {
final domain = depositAddressController.text; final domain = depositAddressController.text;
exchangeViewModel.depositAddress = await fetchParsedAddress(context, domain, exchangeViewModel.depositCurrency); exchangeViewModel.depositAddress =
await fetchParsedAddress(context, domain, exchangeViewModel.depositCurrency);
} }
}); });
_receiveAddressFocus.addListener(() async { _receiveAddressFocus.addListener(() async {
if (!_receiveAddressFocus.hasFocus && receiveAddressController.text.isNotEmpty) { if (!_receiveAddressFocus.hasFocus && receiveAddressController.text.isNotEmpty) {
final domain = receiveAddressController.text; final domain = receiveAddressController.text;
exchangeViewModel.receiveAddress = await fetchParsedAddress(context, domain, exchangeViewModel.receiveCurrency); exchangeViewModel.receiveAddress =
await fetchParsedAddress(context, domain, exchangeViewModel.receiveCurrency);
} }
}); });
@ -589,7 +581,8 @@ class ExchangePage extends BasePage {
} }
} }
Future<String> fetchParsedAddress(BuildContext context, String domain, CryptoCurrency currency) async { Future<String> fetchParsedAddress(
BuildContext context, String domain, CryptoCurrency currency) async {
final parsedAddress = await getIt.get<AddressResolver>().resolve(context, domain, currency); final parsedAddress = await getIt.get<AddressResolver>().resolve(context, domain, currency);
final address = await extractAddressFromParsed(context, parsedAddress); final address = await extractAddressFromParsed(context, parsedAddress);
return address; return address;
@ -658,7 +651,6 @@ class ExchangePage extends BasePage {
exchangeViewModel.changeDepositCurrency(currency: currency); exchangeViewModel.changeDepositCurrency(currency: currency);
}, },
imageArrow: arrowBottomPurple,
currencyButtonColor: Colors.transparent, currencyButtonColor: Colors.transparent,
addressButtonsColor: addressButtonsColor:
Theme.of(context).extension<SendPageTheme>()!.textFieldButtonColor, Theme.of(context).extension<SendPageTheme>()!.textFieldButtonColor,
@ -705,7 +697,6 @@ class ExchangePage extends BasePage {
currencies: exchangeViewModel.receiveCurrencies, currencies: exchangeViewModel.receiveCurrencies,
onCurrencySelected: (currency) => onCurrencySelected: (currency) =>
exchangeViewModel.changeReceiveCurrency(currency: currency), exchangeViewModel.changeReceiveCurrency(currency: currency),
imageArrow: arrowBottomCakeGreen,
currencyButtonColor: Colors.transparent, currencyButtonColor: Colors.transparent,
addressButtonsColor: addressButtonsColor:
Theme.of(context).extension<SendPageTheme>()!.textFieldButtonColor, Theme.of(context).extension<SendPageTheme>()!.textFieldButtonColor,

View file

@ -1,5 +1,6 @@
import 'package:cake_wallet/core/amount_validator.dart'; import 'package:cake_wallet/core/amount_validator.dart';
import 'package:cake_wallet/entities/contact_base.dart'; import 'package:cake_wallet/entities/contact_base.dart';
import 'package:cake_wallet/src/screens/receive/widgets/currency_input_field.dart';
import 'package:cake_wallet/themes/extensions/qr_code_theme.dart'; import 'package:cake_wallet/themes/extensions/qr_code_theme.dart';
import 'package:cake_wallet/routes.dart'; import 'package:cake_wallet/routes.dart';
import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart'; import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
@ -27,7 +28,7 @@ class ExchangeCard extends StatefulWidget {
required this.isAmountEstimated, required this.isAmountEstimated,
required this.currencies, required this.currencies,
required this.onCurrencySelected, required this.onCurrencySelected,
required this.imageArrow, this.imageArrow,
this.currencyValueValidator, this.currencyValueValidator,
this.addressTextFieldValidator, this.addressTextFieldValidator,
this.title = '', this.title = '',
@ -58,7 +59,7 @@ class ExchangeCard extends StatefulWidget {
final bool isAmountEstimated; final bool isAmountEstimated;
final bool hasRefundAddress; final bool hasRefundAddress;
final bool isMoneroWallet; final bool isMoneroWallet;
final Image imageArrow; final Image? imageArrow;
final Color currencyButtonColor; final Color currencyButtonColor;
final Color? addressButtonsColor; final Color? addressButtonsColor;
final Color borderColor; final Color borderColor;
@ -191,120 +192,18 @@ class ExchangeCardState extends State<ExchangeCard> {
) )
], ],
), ),
Padding( CurrencyAmountTextField(
padding: EdgeInsets.only(top: 20), imageArrow: widget.imageArrow,
child: Row( selectedCurrency: _selectedCurrency.toString(),
children: [ amountFocusNode: widget.amountFocusNode,
Container( amountController: amountController,
padding: EdgeInsets.only(right: 8), onTapPicker: () => _presentPicker(context),
height: 32, isAmountEditable: _isAmountEditable,
color: widget.currencyButtonColor, isPickerEnable: true,
child: InkWell( allAmountButton: widget.hasAllAmount,
onTap: () => _presentPicker(context), currencyValueValidator: widget.currencyValueValidator,
child: Row( tag: _selectedCurrency.tag,
mainAxisAlignment: MainAxisAlignment.spaceBetween, allAmountCallback: widget.allAmount),
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Padding(
padding: EdgeInsets.only(right: 5),
child: widget.imageArrow,
),
Text(_selectedCurrency.toString(),
style: TextStyle(
fontWeight: FontWeight.w600, fontSize: 16, color: Colors.white))
]),
),
),
if (_selectedCurrency.tag != null)
Padding(
padding: const EdgeInsets.only(right: 3.0),
child: Container(
height: 32,
decoration: BoxDecoration(
color: widget.addressButtonsColor ??
Theme.of(context).extension<SendPageTheme>()!.textFieldButtonColor,
borderRadius: BorderRadius.all(Radius.circular(6))),
child: Center(
child: Padding(
padding: const EdgeInsets.all(6.0),
child: Text(_selectedCurrency.tag!,
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.bold,
color: Theme.of(context)
.extension<SendPageTheme>()!
.textFieldButtonIconColor)),
),
),
),
),
Padding(
padding: const EdgeInsets.only(right: 4.0),
child: Text(':',
style: TextStyle(
fontWeight: FontWeight.w600, fontSize: 16, color: Colors.white)),
),
Expanded(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Flexible(
child: FocusTraversalOrder(
order: NumericFocusOrder(1),
child: BaseTextFormField(
focusNode: widget.amountFocusNode,
controller: amountController,
enabled: _isAmountEditable,
textAlign: TextAlign.left,
keyboardType:
TextInputType.numberWithOptions(signed: false, decimal: true),
inputFormatters: [
FilteringTextInputFormatter.deny(RegExp('[\\-|\\ ]'))
],
hintText: '0.0000',
borderColor: Colors.transparent,
//widget.borderColor,
textStyle: TextStyle(
fontSize: 16, fontWeight: FontWeight.w600, color: Colors.white),
placeholderTextStyle: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
color: Theme.of(context)
.extension<ExchangePageTheme>()!
.hintTextColor),
validator: _isAmountEditable
? widget.currencyValueValidator
: null),
),
),
if (widget.hasAllAmount)
Container(
height: 32,
width: 32,
decoration: BoxDecoration(
color: Theme.of(context)
.extension<SendPageTheme>()!
.textFieldButtonColor,
borderRadius: BorderRadius.all(Radius.circular(6))),
child: InkWell(
onTap: () => widget.allAmount?.call(),
child: Center(
child: Text(S.of(context).all,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.bold,
color: Theme.of(context)
.extension<SendPageTheme>()!
.textFieldButtonIconColor)),
),
),
)
],
),
),
],
)),
Divider(height: 1, color: Theme.of(context).extension<SendPageTheme>()!.textFieldHintColor), Divider(height: 1, color: Theme.of(context).extension<SendPageTheme>()!.textFieldHintColor),
Padding( Padding(
padding: EdgeInsets.only(top: 5), padding: EdgeInsets.only(top: 5),

View file

@ -1,135 +1,210 @@
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/src/widgets/base_text_form_field.dart'; import 'package:cake_wallet/src/widgets/base_text_form_field.dart';
import 'package:cake_wallet/utils/responsive_layout_util.dart'; import 'package:cake_wallet/themes/extensions/exchange_page_theme.dart';
import 'package:cw_core/crypto_currency.dart'; import 'package:cake_wallet/themes/extensions/send_page_theme.dart';
import 'package:cw_core/currency.dart'; import 'package:cake_wallet/themes/theme_base.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:cake_wallet/themes/extensions/dashboard_page_theme.dart';
import 'package:cake_wallet/themes/extensions/picker_theme.dart';
import 'package:cake_wallet/themes/extensions/send_page_theme.dart';
class CurrencyInputField extends StatelessWidget { class CurrencyAmountTextField extends StatelessWidget {
const CurrencyInputField({ const CurrencyAmountTextField({
super.key,
required this.onTapPicker,
required this.selectedCurrency, required this.selectedCurrency,
this.focusNode, required this.amountFocusNode,
required this.controller, required this.amountController,
required this.isLight, required this.isAmountEditable,
this.allAmountButton = false,
this.isPickerEnable = false,
this.isSelected = false,
this.currentTheme = ThemeType.dark,
this.onTapPicker,
this.padding,
this.imageArrow,
this.hintText,
this.tag,
this.tagBackgroundColor,
this.currencyValueValidator,
this.allAmountCallback,
}); });
final Function() onTapPicker; final Widget? imageArrow;
final Currency selectedCurrency; final String selectedCurrency;
final FocusNode? focusNode; final String? tag;
final TextEditingController controller; final String? hintText;
final bool isLight; final Color? tagBackgroundColor;
final EdgeInsets? padding;
String get _currencyName { final FocusNode? amountFocusNode;
if (selectedCurrency is CryptoCurrency) { final TextEditingController amountController;
return (selectedCurrency as CryptoCurrency).title.toUpperCase(); final bool isAmountEditable;
} final FormFieldValidator<String>? currencyValueValidator;
return selectedCurrency.name.toUpperCase(); final bool isPickerEnable;
} final ThemeType currentTheme;
final bool isSelected;
final bool allAmountButton;
final VoidCallback? allAmountCallback;
final VoidCallback? onTapPicker;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final arrowBottomPurple = Image.asset( final textColor = currentTheme == ThemeType.light
'assets/images/arrow_bottom_purple_icon.png', ? Theme.of(context).appBarTheme.titleTextStyle!.color!
color: Theme.of(context).extension<DashboardPageTheme>()!.textColor, : Colors.white;
height: 8, final _prefixContent = Row(
);
// This magic number for wider screen sets the text input focus at center of the inputfield
final _width =
responsiveLayoutUtil.shouldRenderMobileUI ? MediaQuery.of(context).size.width : 500;
return Column(
children: [ children: [
Padding( isPickerEnable
padding: EdgeInsets.only(top: 20), ? Container(
child: SizedBox( height: 32,
height: 40, child: InkWell(
child: BaseTextFormField( onTap: onTapPicker,
focusNode: focusNode, child: Row(
controller: controller, mainAxisAlignment: MainAxisAlignment.spaceBetween,
keyboardType: TextInputType.numberWithOptions(signed: false, decimal: true), mainAxisSize: MainAxisSize.min,
inputFormatters: [FilteringTextInputFormatter.allow(RegExp(r'^\d+(\.|\,)?\d{0,8}'))], children: <Widget>[
hintText: '0.000', Padding(
placeholderTextStyle: isLight padding: const EdgeInsets.only(right: 5),
? null child: imageArrow ??
: TextStyle( Image.asset('assets/images/arrow_bottom_purple_icon.png',
color: Theme.of(context).extension<SendPageTheme>()!.textFieldBorderColor, color: textColor, height: 8)),
fontWeight: FontWeight.w600, Text(
), selectedCurrency,
borderColor: Theme.of(context).extension<PickerTheme>()!.dividerColor, style: TextStyle(
textColor: Theme.of(context).extension<DashboardPageTheme>()!.textColor, fontWeight: FontWeight.w600,
textStyle: TextStyle( fontSize: 16,
color: Theme.of(context).extension<DashboardPageTheme>()!.textColor, color: textColor,
), ),
prefixIcon: Padding( ),
padding: EdgeInsets.only( ],
left: _width / 4, ),
), ),
child: Container( )
padding: EdgeInsets.only(right: 8), : Text(
child: InkWell( selectedCurrency,
onTap: onTapPicker, style: TextStyle(
child: Row( fontWeight: FontWeight.w600,
mainAxisAlignment: MainAxisAlignment.spaceBetween, fontSize: 16,
mainAxisSize: MainAxisSize.min, color: textColor,
children: <Widget>[ ),
Padding( ),
padding: EdgeInsets.only(right: 5), if (tag != null)
child: arrowBottomPurple, Padding(
), padding: const EdgeInsets.symmetric(horizontal: 3.0),
Text( child: Container(
_currencyName, height: 32,
style: TextStyle( decoration: BoxDecoration(
fontWeight: FontWeight.w600, color: tagBackgroundColor ??
fontSize: 16, Theme.of(context).extension<SendPageTheme>()!.textFieldButtonColor,
color: Theme.of(context).extension<DashboardPageTheme>()!.textColor, borderRadius: const BorderRadius.all(Radius.circular(6)),
), ),
), child: Center(
if (selectedCurrency.tag != null) child: Padding(
Padding( padding: const EdgeInsets.all(6.0),
padding: const EdgeInsets.symmetric(horizontal: 3.0), child: Text(
child: Container( tag!,
decoration: BoxDecoration( style: TextStyle(
color: Theme.of(context).extension<SendPageTheme>()!.textFieldButtonColor, fontSize: 12,
borderRadius: BorderRadius.all( fontWeight: FontWeight.bold,
Radius.circular(6), color: Theme.of(context).extension<SendPageTheme>()!.textFieldButtonIconColor,
), ),
),
child: Center(
child: Text(
selectedCurrency.tag!,
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.bold,
color: Theme.of(context).extension<SendPageTheme>()!.textFieldButtonIconColor,
),
),
),
),
),
Padding(
padding: const EdgeInsets.only(bottom: 3.0),
child: Text(
':',
style: TextStyle(
fontWeight: FontWeight.w600,
fontSize: 20,
color: Theme.of(context).extension<DashboardPageTheme>()!.textColor,
),
),
),
]),
), ),
), ),
), ),
), ),
), ),
Padding(
padding: EdgeInsets.only(right: 4.0),
child: Text(
':',
style: TextStyle(
fontWeight: FontWeight.w600,
fontSize: 16,
color: textColor,
),
),
), ),
], ],
); );
return Padding(
padding: padding ?? const EdgeInsets.only(top: 20),
child: Row(
children: [
isSelected
? Container(
child: _prefixContent,
padding: EdgeInsets.symmetric(vertical: 4, horizontal: 8),
margin: const EdgeInsets.only(right: 3),
decoration: BoxDecoration(
border: Border.all(
color: textColor,
),
borderRadius: BorderRadius.circular(26),
color: Theme.of(context).primaryColor))
: _prefixContent,
Expanded(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Flexible(
child: FocusTraversalOrder(
order: NumericFocusOrder(1),
child: BaseTextFormField(
focusNode: amountFocusNode,
controller: amountController,
enabled: isAmountEditable,
textAlign: TextAlign.left,
keyboardType: const TextInputType.numberWithOptions(
signed: false,
decimal: true,
),
inputFormatters: [
FilteringTextInputFormatter.deny(RegExp('[\\-|\\ ]')),
],
hintText: hintText ?? '0.0000',
borderColor: Colors.transparent,
textStyle: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
color: textColor,
),
placeholderTextStyle: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
color: currentTheme == ThemeType.light
? Theme.of(context).appBarTheme.titleTextStyle!.color!
: Theme.of(context).extension<ExchangePageTheme>()!.hintTextColor,
),
validator: isAmountEditable ? currencyValueValidator : null,
),
),
),
if (allAmountButton)
Container(
height: 32,
width: 32,
decoration: BoxDecoration(
color: Theme.of(context).extension<SendPageTheme>()!.textFieldButtonColor,
borderRadius: const BorderRadius.all(Radius.circular(6)),
),
child: InkWell(
onTap: allAmountCallback,
child: Center(
child: Text(
S.of(context).all,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.bold,
color: Theme.of(context)
.extension<SendPageTheme>()!
.textFieldButtonIconColor,
),
),
),
),
),
],
),
),
],
),
);
} }
} }

View file

@ -1,11 +1,15 @@
import 'package:cake_wallet/entities/qr_view_data.dart'; import 'package:cake_wallet/entities/qr_view_data.dart';
import 'package:cake_wallet/themes/extensions/picker_theme.dart';
import 'package:cake_wallet/themes/extensions/qr_code_theme.dart'; import 'package:cake_wallet/themes/extensions/qr_code_theme.dart';
import 'package:cake_wallet/routes.dart'; import 'package:cake_wallet/routes.dart';
import 'package:cake_wallet/src/screens/exchange/widgets/currency_picker.dart'; import 'package:cake_wallet/src/screens/exchange/widgets/currency_picker.dart';
import 'package:cake_wallet/src/screens/receive/widgets/currency_input_field.dart'; import 'package:cake_wallet/src/screens/receive/widgets/currency_input_field.dart';
import 'package:cake_wallet/themes/theme_base.dart';
import 'package:cake_wallet/utils/brightness_util.dart'; import 'package:cake_wallet/utils/brightness_util.dart';
import 'package:cake_wallet/utils/responsive_layout_util.dart';
import 'package:cake_wallet/utils/show_bar.dart'; import 'package:cake_wallet/utils/show_bar.dart';
import 'package:cake_wallet/utils/show_pop_up.dart'; import 'package:cake_wallet/utils/show_pop_up.dart';
import 'package:cw_core/crypto_currency.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter_mobx/flutter_mobx.dart'; import 'package:flutter_mobx/flutter_mobx.dart';
@ -38,6 +42,10 @@ class QRWidget extends StatelessWidget {
final copyImage = Image.asset('assets/images/copy_address.png', final copyImage = Image.asset('assets/images/copy_address.png',
color: Theme.of(context).extension<QRCodeTheme>()!.qrWidgetCopyButtonColor); color: Theme.of(context).extension<QRCodeTheme>()!.qrWidgetCopyButtonColor);
// This magic number for wider screen sets the text input focus at center of the inputfield
final _width =
responsiveLayoutUtil.shouldRenderMobileUI ? MediaQuery.of(context).size.width : 500;
return Center( return Center(
child: SingleChildScrollView( child: SingleChildScrollView(
child: Column( child: Column(
@ -85,8 +93,9 @@ class QRWidget extends StatelessWidget {
decoration: BoxDecoration( decoration: BoxDecoration(
border: Border.all( border: Border.all(
width: 3, width: 3,
color: color: Theme.of(context)
Theme.of(context).extension<DashboardPageTheme>()!.textColor, .extension<DashboardPageTheme>()!
.textColor,
), ),
), ),
child: Container( child: Container(
@ -116,20 +125,23 @@ class QRWidget extends StatelessWidget {
children: <Widget>[ children: <Widget>[
Expanded( Expanded(
child: Form( child: Form(
key: formKey, key: formKey,
child: CurrencyInputField( child: CurrencyAmountTextField(
focusNode: amountTextFieldFocusNode, selectedCurrency: _currencyName,
controller: amountController, amountFocusNode: amountTextFieldFocusNode,
onTapPicker: () => _presentPicker(context), amountController: amountController,
selectedCurrency: addressListViewModel.selectedCurrency, padding: EdgeInsets.only(top: 20, left: _width / 4),
isLight: isLight, currentTheme: isLight ? ThemeType.light : ThemeType.dark,
), isAmountEditable: true,
), tag: addressListViewModel.selectedCurrency.tag,
onTapPicker: () => _presentPicker(context),
isPickerEnable: true)),
), ),
], ],
), ),
); );
}), }),
Divider(height: 1, color: Theme.of(context).extension<PickerTheme>()!.dividerColor),
Padding( Padding(
padding: EdgeInsets.only(top: 20, bottom: 8), padding: EdgeInsets.only(top: 20, bottom: 8),
child: Builder( child: Builder(
@ -150,7 +162,8 @@ class QRWidget extends StatelessWidget {
style: TextStyle( style: TextStyle(
fontSize: 15, fontSize: 15,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
color: Theme.of(context).extension<DashboardPageTheme>()!.textColor), color:
Theme.of(context).extension<DashboardPageTheme>()!.textColor),
), ),
), ),
Padding( Padding(
@ -169,6 +182,13 @@ class QRWidget extends StatelessWidget {
); );
} }
String get _currencyName {
if (addressListViewModel.selectedCurrency is CryptoCurrency) {
return (addressListViewModel.selectedCurrency as CryptoCurrency).title.toUpperCase();
}
return addressListViewModel.selectedCurrency.name.toUpperCase();
}
void _presentPicker(BuildContext context) async { void _presentPicker(BuildContext context) async {
await showPopUp<void>( await showPopUp<void>(
builder: (_) => CurrencyPicker( builder: (_) => CurrencyPicker(

View file

@ -144,7 +144,7 @@ class SendTemplatePage extends BasePage {
.toList(); .toList();
sendTemplateViewModel.addTemplate( sendTemplateViewModel.addTemplate(
isCurrencySelected: mainTemplate.isCurrencySelected, isCurrencySelected: mainTemplate.isCryptoSelected,
name: mainTemplate.name, name: mainTemplate.name,
address: mainTemplate.address, address: mainTemplate.address,
cryptoCurrency: mainTemplate.selectedCurrency.title, cryptoCurrency: mainTemplate.selectedCurrency.title,

View file

@ -1,65 +0,0 @@
import 'package:cake_wallet/themes/extensions/send_page_theme.dart';
import 'package:flutter/material.dart';
class PrefixCurrencyIcon extends StatelessWidget {
PrefixCurrencyIcon({
required this.isSelected,
required this.title,
this.onTap,
});
final bool isSelected;
final String title;
final Function()? onTap;
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: onTap,
child: Padding(
padding: EdgeInsets.fromLTRB(0, 6.0, 8.0, 0),
child: Column(
children: [
Container(
padding: EdgeInsets.symmetric(vertical: 4, horizontal: 8),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(26),
color: isSelected
? Theme.of(context)
.extension<SendPageTheme>()!
.templateSelectedCurrencyBackgroundColor
: Colors.transparent,
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
if (onTap != null)
Padding(
padding: EdgeInsets.only(right: 5),
child: Image.asset(
'assets/images/arrow_bottom_purple_icon.png',
color: Colors.white,
height: 8,
),
),
Text(
title + ':',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
color: isSelected
? Theme.of(context)
.extension<SendPageTheme>()!
.templateSelectedCurrencyTitleColor
: Colors.white,
),
),
],
),
),
],
),
),
);
}
}

View file

@ -1,4 +1,5 @@
import 'package:cake_wallet/entities/priority_for_wallet_type.dart'; import 'package:cake_wallet/entities/priority_for_wallet_type.dart';
import 'package:cake_wallet/src/screens/receive/widgets/currency_input_field.dart';
import 'package:cake_wallet/src/widgets/picker.dart'; import 'package:cake_wallet/src/widgets/picker.dart';
import 'package:cake_wallet/themes/extensions/keyboard_theme.dart'; import 'package:cake_wallet/themes/extensions/keyboard_theme.dart';
import 'package:cake_wallet/src/screens/exchange/widgets/currency_picker.dart'; import 'package:cake_wallet/src/screens/exchange/widgets/currency_picker.dart';
@ -207,166 +208,19 @@ class SendCardState extends State<SendCard> with AutomaticKeepAliveClientMixin<S
textStyle: TextStyle( textStyle: TextStyle(
fontSize: 14, fontWeight: FontWeight.w500, color: Colors.white), fontSize: 14, fontWeight: FontWeight.w500, color: Colors.white),
validator: sendViewModel.addressValidator)), validator: sendViewModel.addressValidator)),
Observer( CurrencyAmountTextField(
builder: (_) => Padding( selectedCurrency: sendViewModel.selectedCryptoCurrency.title,
padding: const EdgeInsets.only(top: 20), amountFocusNode: cryptoAmountFocus,
child: Row( amountController: cryptoAmountController,
children: [ isAmountEditable: true,
Padding( onTapPicker: () => _presentPicker(context),
padding: const EdgeInsets.only(bottom: 8.0), isPickerEnable: sendViewModel.hasMultipleTokens,
child: Row( tag: sendViewModel.selectedCryptoCurrency.tag,
children: [ allAmountButton: !sendViewModel.isBatchSending,
sendViewModel.hasMultipleTokens currencyValueValidator: output.sendAll
? Container( ? sendViewModel.allAmountValidator
padding: EdgeInsets.only(right: 8), : sendViewModel.amountValidator,
height: 32, allAmountCallback: () async => output.setSendAll(sendViewModel.balance)),
child: InkWell(
onTap: () => _presentPicker(context),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Padding(
padding: EdgeInsets.only(right: 5),
child: Image.asset(
'assets/images/arrow_bottom_purple_icon.png',
color: Colors.white,
height: 8,
),
),
Text(
sendViewModel.selectedCryptoCurrency.title,
style: TextStyle(
fontWeight: FontWeight.w600,
fontSize: 16,
color: Colors.white),
),
],
),
),
)
: Text(
sendViewModel.selectedCryptoCurrency.title,
style: TextStyle(
fontWeight: FontWeight.w600,
fontSize: 16,
color: Colors.white),
),
sendViewModel.selectedCryptoCurrency.tag != null
? Padding(
padding: const EdgeInsets.fromLTRB(3.0, 0, 3.0, 0),
child: Container(
height: 32,
decoration: BoxDecoration(
color: Theme.of(context)
.extension<SendPageTheme>()!
.textFieldButtonColor,
borderRadius: BorderRadius.all(
Radius.circular(6),
)),
child: Center(
child: Padding(
padding: const EdgeInsets.all(6.0),
child: Text(
sendViewModel.selectedCryptoCurrency.tag!,
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.bold,
color: Theme.of(context)
.extension<SendPageTheme>()!
.textFieldButtonIconColor),
),
),
),
),
)
: Container(),
Padding(
padding: const EdgeInsets.only(right: 10.0),
child: Text(
':',
style: TextStyle(
fontWeight: FontWeight.w600,
fontSize: 16,
color: Colors.white),
),
),
],
),
),
Expanded(
child: Stack(
children: [
BaseTextFormField(
focusNode: cryptoAmountFocus,
controller: cryptoAmountController,
keyboardType: TextInputType.numberWithOptions(
signed: false, decimal: true),
inputFormatters: [
FilteringTextInputFormatter.deny(RegExp('[\\-|\\ ]'))
],
suffixIcon: SizedBox(
width: prefixIconWidth,
),
hintText: '0.0000',
borderColor: Colors.transparent,
textStyle: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w500,
color: Colors.white),
placeholderTextStyle: TextStyle(
color: Theme.of(context)
.extension<SendPageTheme>()!
.textFieldHintColor,
fontWeight: FontWeight.w500,
fontSize: 14),
validator: output.sendAll
? sendViewModel.allAmountValidator
: sendViewModel.amountValidator,
),
if (!sendViewModel.isBatchSending)
Positioned(
top: 2,
right: 0,
child: Container(
width: prefixIconWidth,
height: prefixIconHeight,
child: InkWell(
onTap: () async {
output.setSendAll(sendViewModel.balance);
},
child: Container(
decoration: BoxDecoration(
color: Theme.of(context)
.extension<SendPageTheme>()!
.textFieldButtonColor,
borderRadius: BorderRadius.all(
Radius.circular(6),
),
),
child: Center(
child: Text(
S.of(context).all,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.bold,
color: Theme.of(context)
.extension<SendPageTheme>()!
.textFieldButtonIconColor,
),
),
),
),
),
),
),
],
),
),
],
)),
),
Divider( Divider(
height: 1, height: 1,
color: Theme.of(context).extension<SendPageTheme>()!.textFieldHintColor), color: Theme.of(context).extension<SendPageTheme>()!.textFieldHintColor),
@ -402,41 +256,16 @@ class SendCardState extends State<SendCard> with AutomaticKeepAliveClientMixin<S
), ),
), ),
if (!sendViewModel.isFiatDisabled) if (!sendViewModel.isFiatDisabled)
Padding( CurrencyAmountTextField(
padding: const EdgeInsets.only(top: 20), selectedCurrency: sendViewModel.fiat.title,
child: BaseTextFormField( amountFocusNode: fiatAmountFocus,
focusNode: fiatAmountFocus, amountController: fiatAmountController,
controller: fiatAmountController,
keyboardType:
TextInputType.numberWithOptions(signed: false, decimal: true),
inputFormatters: [
FilteringTextInputFormatter.deny(
RegExp('[\\-|\\ ]'),
)
],
prefixIcon: Padding(
padding: EdgeInsets.only(top: 9),
child: Text(
sendViewModel.fiat.title + ':',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
color: Colors.white,
),
),
),
hintText: '0.00', hintText: '0.00',
borderColor: isAmountEditable: true,
Theme.of(context).extension<SendPageTheme>()!.textFieldBorderColor, allAmountButton: false),
textStyle: TextStyle( Divider(
fontSize: 14, fontWeight: FontWeight.w500, color: Colors.white), height: 1,
placeholderTextStyle: TextStyle( color: Theme.of(context).extension<SendPageTheme>()!.textFieldHintColor),
color:
Theme.of(context).extension<SendPageTheme>()!.textFieldHintColor,
fontWeight: FontWeight.w500,
fontSize: 14),
),
),
Padding( Padding(
padding: EdgeInsets.only(top: 20), padding: EdgeInsets.only(top: 20),
child: BaseTextFormField( child: BaseTextFormField(
@ -715,12 +544,11 @@ class SendCardState extends State<SendCard> with AutomaticKeepAliveClientMixin<S
showPopUp<void>( showPopUp<void>(
context: context, context: context,
builder: (_) => CurrencyPicker( builder: (_) => CurrencyPicker(
selectedAtIndex: sendViewModel.currencies.indexOf(sendViewModel.selectedCryptoCurrency), selectedAtIndex: sendViewModel.currencies.indexOf(sendViewModel.selectedCryptoCurrency),
items: sendViewModel.currencies, items: sendViewModel.currencies,
hintText: S.of(context).search_currency, hintText: S.of(context).search_currency,
onItemSelected: (Currency cur) => onItemSelected: (Currency cur) =>
sendViewModel.selectedCryptoCurrency = (cur as CryptoCurrency), sendViewModel.selectedCryptoCurrency = (cur as CryptoCurrency)),
),
); );
} }

View file

@ -1,5 +1,5 @@
import 'package:cake_wallet/src/screens/exchange/widgets/currency_picker.dart'; import 'package:cake_wallet/src/screens/exchange/widgets/currency_picker.dart';
import 'package:cake_wallet/src/screens/send/widgets/prefix_currency_icon_widget.dart'; import 'package:cake_wallet/src/screens/receive/widgets/currency_input_field.dart';
import 'package:cake_wallet/themes/extensions/send_page_theme.dart'; import 'package:cake_wallet/themes/extensions/send_page_theme.dart';
import 'package:cake_wallet/utils/payment_request.dart'; import 'package:cake_wallet/utils/payment_request.dart';
import 'package:cake_wallet/utils/show_pop_up.dart'; import 'package:cake_wallet/utils/show_pop_up.dart';
@ -59,7 +59,8 @@ class SendTemplateCard extends StatelessWidget {
hintText: sendTemplateViewModel.recipients.length > 1 hintText: sendTemplateViewModel.recipients.length > 1
? S.of(context).template_name ? S.of(context).template_name
: S.of(context).send_name, : S.of(context).send_name,
borderColor: Theme.of(context).extension<SendPageTheme>()!.textFieldBorderColor, borderColor:
Theme.of(context).extension<SendPageTheme>()!.textFieldBorderColor,
textStyle: textStyle:
TextStyle(fontSize: 14, fontWeight: FontWeight.w500, color: Colors.white), TextStyle(fontSize: 14, fontWeight: FontWeight.w500, color: Colors.white),
placeholderTextStyle: TextStyle( placeholderTextStyle: TextStyle(
@ -69,107 +70,87 @@ class SendTemplateCard extends StatelessWidget {
validator: sendTemplateViewModel.templateValidator), validator: sendTemplateViewModel.templateValidator),
Padding( Padding(
padding: EdgeInsets.only(top: 20), padding: EdgeInsets.only(top: 20),
child: Observer( child: Observer(builder: (context) {
builder: (context) { return AddressTextField(
return AddressTextField( selectedCurrency: template.selectedCurrency,
selectedCurrency: template.selectedCurrency, controller: _addressController,
controller: _addressController, onURIScanned: (uri) {
onURIScanned: (uri) { final paymentRequest = PaymentRequest.fromUri(uri);
final paymentRequest = PaymentRequest.fromUri(uri); _addressController.text = paymentRequest.address;
_addressController.text = paymentRequest.address; _cryptoAmountController.text = paymentRequest.amount;
_cryptoAmountController.text = paymentRequest.amount; },
}, options: [
options: [ AddressTextFieldOption.paste,
AddressTextFieldOption.paste, AddressTextFieldOption.qrCode,
AddressTextFieldOption.qrCode, AddressTextFieldOption.addressBook
AddressTextFieldOption.addressBook ],
], onPushPasteButton: (context) async {
onPushPasteButton: (context) async { template.output.resetParsedAddress();
template.output.resetParsedAddress(); await template.output.fetchParsedAddress(context);
await template.output.fetchParsedAddress(context); },
}, onPushAddressBookButton: (context) async {
onPushAddressBookButton: (context) async { template.output.resetParsedAddress();
template.output.resetParsedAddress(); await template.output.fetchParsedAddress(context);
await template.output.fetchParsedAddress(context); },
}, buttonColor:
buttonColor: Theme.of(context).extension<SendPageTheme>()!.textFieldButtonColor, Theme.of(context).extension<SendPageTheme>()!.textFieldButtonColor,
borderColor: Theme.of(context).extension<SendPageTheme>()!.textFieldBorderColor, borderColor:
textStyle: TextStyle( Theme.of(context).extension<SendPageTheme>()!.textFieldBorderColor,
fontSize: 14, textStyle: TextStyle(
fontWeight: FontWeight.w500,
color: Colors.white,
),
hintStyle: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w500,
color: Theme.of(context).extension<SendPageTheme>()!.textFieldHintColor,
),
validator: sendTemplateViewModel.addressValidator,
);
}
),
),
Padding(
padding: const EdgeInsets.only(top: 20),
child: Focus(
onFocusChange: (hasFocus) {
if (hasFocus) {
template.selectCurrency();
}
},
child: BaseTextFormField(
focusNode: _cryptoAmountFocus,
controller: _cryptoAmountController,
keyboardType: TextInputType.numberWithOptions(signed: false, decimal: true),
inputFormatters: [FilteringTextInputFormatter.deny(RegExp('[\\-|\\ ]'))],
prefixIcon: Observer(
builder: (_) => PrefixCurrencyIcon(
title: template.selectedCurrency.title,
isSelected: template.isCurrencySelected,
onTap: sendTemplateViewModel.walletCurrencies.length > 1
? () => _presentPicker(context)
: null,
),
),
hintText: '0.0000',
borderColor: Theme.of(context).extension<SendPageTheme>()!.textFieldBorderColor,
textStyle:
TextStyle(fontSize: 14, fontWeight: FontWeight.w500, color: Colors.white),
placeholderTextStyle: TextStyle(
color: Theme.of(context).extension<SendPageTheme>()!.textFieldHintColor,
fontWeight: FontWeight.w500,
fontSize: 14),
validator: sendTemplateViewModel.amountValidator,
),
),
),
Padding(
padding: const EdgeInsets.only(top: 20),
child: Focus(
onFocusChange: (hasFocus) {
if (hasFocus) {
template.selectFiat();
}
},
child: BaseTextFormField(
focusNode: _fiatAmountFocus,
controller: _fiatAmountController,
keyboardType: TextInputType.numberWithOptions(signed: false, decimal: true),
inputFormatters: [FilteringTextInputFormatter.deny(RegExp('[\\-|\\ ]'))],
prefixIcon: Observer(
builder: (_) => PrefixCurrencyIcon(
title: sendTemplateViewModel.fiatCurrency,
isSelected: template.isFiatSelected)),
hintText: '0.00',
borderColor: Theme.of(context).extension<SendPageTheme>()!.textFieldBorderColor,
textStyle:
TextStyle(fontSize: 14, fontWeight: FontWeight.w500, color: Colors.white),
placeholderTextStyle: TextStyle(
color: Theme.of(context).extension<SendPageTheme>()!.textFieldHintColor,
fontWeight: FontWeight.w500,
fontSize: 14, fontSize: 14,
fontWeight: FontWeight.w500,
color: Colors.white,
), ),
), hintStyle: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w500,
color: Theme.of(context).extension<SendPageTheme>()!.textFieldHintColor,
),
validator: sendTemplateViewModel.addressValidator,
);
}),
),
Focus(
onFocusChange: (hasFocus) {
if (hasFocus) template.setCryptoCurrency(true);
},
child: Column(
children: [
Observer(
builder: (context) => CurrencyAmountTextField(
selectedCurrency: template.selectedCurrency.title,
amountFocusNode: _cryptoAmountFocus,
amountController: _cryptoAmountController,
isSelected: template.isCryptoSelected,
tag: template.selectedCurrency.tag,
isPickerEnable: sendTemplateViewModel.hasMultipleTokens,
onTapPicker: () => _presentPicker(context),
currencyValueValidator: sendTemplateViewModel.amountValidator,
isAmountEditable: true)),
Divider(
height: 1,
color: Theme.of(context).extension<SendPageTheme>()!.textFieldBorderColor)
],
),
),
Focus(
onFocusChange: (hasFocus) {
if (hasFocus) template.setCryptoCurrency(false);
},
child: Column(
children: [
Observer(
builder: (context) => CurrencyAmountTextField(
selectedCurrency: sendTemplateViewModel.fiatCurrency,
amountFocusNode: _fiatAmountFocus,
amountController: _fiatAmountController,
isSelected: !template.isCryptoSelected,
hintText: '0.00',
isAmountEditable: true)),
Divider(
height: 1,
color: Theme.of(context).extension<SendPageTheme>()!.textFieldBorderColor)
],
), ),
), ),
], ],

View file

@ -1,3 +1,4 @@
import 'package:cake_wallet/reactions/wallet_connect.dart';
import 'package:cake_wallet/view_model/send/template_view_model.dart'; import 'package:cake_wallet/view_model/send/template_view_model.dart';
import 'package:cw_core/crypto_currency.dart'; import 'package:cw_core/crypto_currency.dart';
import 'package:cw_core/wallet_type.dart'; import 'package:cw_core/wallet_type.dart';
@ -97,4 +98,8 @@ abstract class SendTemplateViewModelBase with Store {
@computed @computed
List<CryptoCurrency> get walletCurrencies => _wallet.balance.keys.toList(); List<CryptoCurrency> get walletCurrencies => _wallet.balance.keys.toList();
bool get hasMultipleTokens => isEVMCompatibleChain(_wallet.type) ||
_wallet.type == WalletType.solana ||
_wallet.type == WalletType.tron;
} }

View file

@ -40,35 +40,22 @@ abstract class TemplateViewModelBase with Store {
CryptoCurrency _currency; CryptoCurrency _currency;
@observable @observable
bool isCurrencySelected = true; bool isCryptoSelected = true;
@observable
bool isFiatSelected = false;
@action @action
void selectCurrency() { void setCryptoCurrency(bool value) => isCryptoSelected = value;
isCurrencySelected = true;
isFiatSelected = false;
}
@action
void selectFiat() {
isFiatSelected = true;
isCurrencySelected = false;
}
@action @action
void reset() { void reset() {
name = ''; name = '';
address = ''; address = '';
isCurrencySelected = true; isCryptoSelected = true;
isFiatSelected = false;
output.reset(); output.reset();
} }
Template toTemplate({required String cryptoCurrency, required String fiatCurrency}) { Template toTemplate({required String cryptoCurrency, required String fiatCurrency}) {
return Template( return Template(
isCurrencySelectedRaw: isCurrencySelected, isCurrencySelectedRaw: isCryptoSelected,
nameRaw: name, nameRaw: name,
addressRaw: address, addressRaw: address,
cryptoCurrencyRaw: cryptoCurrency, cryptoCurrencyRaw: cryptoCurrency,
@ -79,7 +66,7 @@ abstract class TemplateViewModelBase with Store {
@action @action
void changeSelectedCurrency(CryptoCurrency currency) { void changeSelectedCurrency(CryptoCurrency currency) {
isCurrencySelected = true; isCryptoSelected = true;
_currency = currency; _currency = currency;
} }