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));
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? receiveWalletName;
@ -101,11 +90,11 @@ class ExchangePage extends BasePage {
@override
Function(BuildContext)? get pushToNextWidget => (context) {
FocusScopeNode currentFocus = FocusScope.of(context);
if (!currentFocus.hasPrimaryFocus) {
currentFocus.focusedChild?.unfocus();
}
};
FocusScopeNode currentFocus = FocusScope.of(context);
if (!currentFocus.hasPrimaryFocus) {
currentFocus.focusedChild?.unfocus();
}
};
@override
Widget middle(BuildContext context) => Row(
@ -340,7 +329,6 @@ class ExchangePage extends BasePage {
void applyTemplate(
BuildContext context, ExchangeViewModel exchangeViewModel, ExchangeTemplate template) async {
final depositCryptoCurrency = CryptoCurrency.fromString(template.depositCurrency);
final receiveCryptoCurrency = CryptoCurrency.fromString(template.receiveCurrency);
@ -354,10 +342,12 @@ class ExchangePage extends BasePage {
exchangeViewModel.isFixedRateMode = false;
var domain = template.depositAddress;
exchangeViewModel.depositAddress = await fetchParsedAddress(context, domain, depositCryptoCurrency);
exchangeViewModel.depositAddress =
await fetchParsedAddress(context, domain, depositCryptoCurrency);
domain = template.receiveAddress;
exchangeViewModel.receiveAddress = await fetchParsedAddress(context, domain, receiveCryptoCurrency);
exchangeViewModel.receiveAddress =
await fetchParsedAddress(context, domain, receiveCryptoCurrency);
}
void _setReactions(BuildContext context, ExchangeViewModel exchangeViewModel) {
@ -529,14 +519,16 @@ class ExchangePage extends BasePage {
_depositAddressFocus.addListener(() async {
if (!_depositAddressFocus.hasFocus && depositAddressController.text.isNotEmpty) {
final domain = depositAddressController.text;
exchangeViewModel.depositAddress = await fetchParsedAddress(context, domain, exchangeViewModel.depositCurrency);
exchangeViewModel.depositAddress =
await fetchParsedAddress(context, domain, exchangeViewModel.depositCurrency);
}
});
_receiveAddressFocus.addListener(() async {
if (!_receiveAddressFocus.hasFocus && receiveAddressController.text.isNotEmpty) {
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 address = await extractAddressFromParsed(context, parsedAddress);
return address;
@ -658,7 +651,6 @@ class ExchangePage extends BasePage {
exchangeViewModel.changeDepositCurrency(currency: currency);
},
imageArrow: arrowBottomPurple,
currencyButtonColor: Colors.transparent,
addressButtonsColor:
Theme.of(context).extension<SendPageTheme>()!.textFieldButtonColor,
@ -705,7 +697,6 @@ class ExchangePage extends BasePage {
currencies: exchangeViewModel.receiveCurrencies,
onCurrencySelected: (currency) =>
exchangeViewModel.changeReceiveCurrency(currency: currency),
imageArrow: arrowBottomCakeGreen,
currencyButtonColor: Colors.transparent,
addressButtonsColor:
Theme.of(context).extension<SendPageTheme>()!.textFieldButtonColor,

View file

@ -1,5 +1,6 @@
import 'package:cake_wallet/core/amount_validator.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/routes.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.currencies,
required this.onCurrencySelected,
required this.imageArrow,
this.imageArrow,
this.currencyValueValidator,
this.addressTextFieldValidator,
this.title = '',
@ -58,7 +59,7 @@ class ExchangeCard extends StatefulWidget {
final bool isAmountEstimated;
final bool hasRefundAddress;
final bool isMoneroWallet;
final Image imageArrow;
final Image? imageArrow;
final Color currencyButtonColor;
final Color? addressButtonsColor;
final Color borderColor;
@ -191,120 +192,18 @@ class ExchangeCardState extends State<ExchangeCard> {
)
],
),
Padding(
padding: EdgeInsets.only(top: 20),
child: Row(
children: [
Container(
padding: EdgeInsets.only(right: 8),
height: 32,
color: widget.currencyButtonColor,
child: InkWell(
onTap: () => _presentPicker(context),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
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)),
),
),
)
],
),
),
],
)),
CurrencyAmountTextField(
imageArrow: widget.imageArrow,
selectedCurrency: _selectedCurrency.toString(),
amountFocusNode: widget.amountFocusNode,
amountController: amountController,
onTapPicker: () => _presentPicker(context),
isAmountEditable: _isAmountEditable,
isPickerEnable: true,
allAmountButton: widget.hasAllAmount,
currencyValueValidator: widget.currencyValueValidator,
tag: _selectedCurrency.tag,
allAmountCallback: widget.allAmount),
Divider(height: 1, color: Theme.of(context).extension<SendPageTheme>()!.textFieldHintColor),
Padding(
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/utils/responsive_layout_util.dart';
import 'package:cw_core/crypto_currency.dart';
import 'package:cw_core/currency.dart';
import 'package:cake_wallet/themes/extensions/exchange_page_theme.dart';
import 'package:cake_wallet/themes/extensions/send_page_theme.dart';
import 'package:cake_wallet/themes/theme_base.dart';
import 'package:flutter/material.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 {
const CurrencyInputField({
super.key,
required this.onTapPicker,
class CurrencyAmountTextField extends StatelessWidget {
const CurrencyAmountTextField({
required this.selectedCurrency,
this.focusNode,
required this.controller,
required this.isLight,
required this.amountFocusNode,
required this.amountController,
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 Currency selectedCurrency;
final FocusNode? focusNode;
final TextEditingController controller;
final bool isLight;
String get _currencyName {
if (selectedCurrency is CryptoCurrency) {
return (selectedCurrency as CryptoCurrency).title.toUpperCase();
}
return selectedCurrency.name.toUpperCase();
}
final Widget? imageArrow;
final String selectedCurrency;
final String? tag;
final String? hintText;
final Color? tagBackgroundColor;
final EdgeInsets? padding;
final FocusNode? amountFocusNode;
final TextEditingController amountController;
final bool isAmountEditable;
final FormFieldValidator<String>? currencyValueValidator;
final bool isPickerEnable;
final ThemeType currentTheme;
final bool isSelected;
final bool allAmountButton;
final VoidCallback? allAmountCallback;
final VoidCallback? onTapPicker;
@override
Widget build(BuildContext context) {
final arrowBottomPurple = Image.asset(
'assets/images/arrow_bottom_purple_icon.png',
color: Theme.of(context).extension<DashboardPageTheme>()!.textColor,
height: 8,
);
// 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(
final textColor = currentTheme == ThemeType.light
? Theme.of(context).appBarTheme.titleTextStyle!.color!
: Colors.white;
final _prefixContent = Row(
children: [
Padding(
padding: EdgeInsets.only(top: 20),
child: SizedBox(
height: 40,
child: BaseTextFormField(
focusNode: focusNode,
controller: controller,
keyboardType: TextInputType.numberWithOptions(signed: false, decimal: true),
inputFormatters: [FilteringTextInputFormatter.allow(RegExp(r'^\d+(\.|\,)?\d{0,8}'))],
hintText: '0.000',
placeholderTextStyle: isLight
? null
: TextStyle(
color: Theme.of(context).extension<SendPageTheme>()!.textFieldBorderColor,
fontWeight: FontWeight.w600,
),
borderColor: Theme.of(context).extension<PickerTheme>()!.dividerColor,
textColor: Theme.of(context).extension<DashboardPageTheme>()!.textColor,
textStyle: TextStyle(
color: Theme.of(context).extension<DashboardPageTheme>()!.textColor,
),
prefixIcon: Padding(
padding: EdgeInsets.only(
left: _width / 4,
isPickerEnable
? Container(
height: 32,
child: InkWell(
onTap: onTapPicker,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Padding(
padding: const EdgeInsets.only(right: 5),
child: imageArrow ??
Image.asset('assets/images/arrow_bottom_purple_icon.png',
color: textColor, height: 8)),
Text(
selectedCurrency,
style: TextStyle(
fontWeight: FontWeight.w600,
fontSize: 16,
color: textColor,
),
),
],
),
),
child: Container(
padding: EdgeInsets.only(right: 8),
child: InkWell(
onTap: onTapPicker,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Padding(
padding: EdgeInsets.only(right: 5),
child: arrowBottomPurple,
),
Text(
_currencyName,
style: TextStyle(
fontWeight: FontWeight.w600,
fontSize: 16,
color: Theme.of(context).extension<DashboardPageTheme>()!.textColor,
),
),
if (selectedCurrency.tag != null)
Padding(
padding: const EdgeInsets.symmetric(horizontal: 3.0),
child: Container(
decoration: BoxDecoration(
color: Theme.of(context).extension<SendPageTheme>()!.textFieldButtonColor,
borderRadius: BorderRadius.all(
Radius.circular(6),
),
),
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,
),
),
),
]),
)
: Text(
selectedCurrency,
style: TextStyle(
fontWeight: FontWeight.w600,
fontSize: 16,
color: textColor,
),
),
if (tag != null)
Padding(
padding: const EdgeInsets.symmetric(horizontal: 3.0),
child: Container(
height: 32,
decoration: BoxDecoration(
color: tagBackgroundColor ??
Theme.of(context).extension<SendPageTheme>()!.textFieldButtonColor,
borderRadius: const BorderRadius.all(Radius.circular(6)),
),
child: Center(
child: Padding(
padding: const EdgeInsets.all(6.0),
child: Text(
tag!,
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.bold,
color: Theme.of(context).extension<SendPageTheme>()!.textFieldButtonIconColor,
),
),
),
),
),
),
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/themes/extensions/picker_theme.dart';
import 'package:cake_wallet/themes/extensions/qr_code_theme.dart';
import 'package:cake_wallet/routes.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/themes/theme_base.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_pop_up.dart';
import 'package:cw_core/crypto_currency.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.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',
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(
child: SingleChildScrollView(
child: Column(
@ -85,8 +93,9 @@ class QRWidget extends StatelessWidget {
decoration: BoxDecoration(
border: Border.all(
width: 3,
color:
Theme.of(context).extension<DashboardPageTheme>()!.textColor,
color: Theme.of(context)
.extension<DashboardPageTheme>()!
.textColor,
),
),
child: Container(
@ -116,20 +125,23 @@ class QRWidget extends StatelessWidget {
children: <Widget>[
Expanded(
child: Form(
key: formKey,
child: CurrencyInputField(
focusNode: amountTextFieldFocusNode,
controller: amountController,
onTapPicker: () => _presentPicker(context),
selectedCurrency: addressListViewModel.selectedCurrency,
isLight: isLight,
),
),
key: formKey,
child: CurrencyAmountTextField(
selectedCurrency: _currencyName,
amountFocusNode: amountTextFieldFocusNode,
amountController: amountController,
padding: EdgeInsets.only(top: 20, left: _width / 4),
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: EdgeInsets.only(top: 20, bottom: 8),
child: Builder(
@ -150,7 +162,8 @@ class QRWidget extends StatelessWidget {
style: TextStyle(
fontSize: 15,
fontWeight: FontWeight.w500,
color: Theme.of(context).extension<DashboardPageTheme>()!.textColor),
color:
Theme.of(context).extension<DashboardPageTheme>()!.textColor),
),
),
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 {
await showPopUp<void>(
builder: (_) => CurrencyPicker(

View file

@ -144,7 +144,7 @@ class SendTemplatePage extends BasePage {
.toList();
sendTemplateViewModel.addTemplate(
isCurrencySelected: mainTemplate.isCurrencySelected,
isCurrencySelected: mainTemplate.isCryptoSelected,
name: mainTemplate.name,
address: mainTemplate.address,
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/src/screens/receive/widgets/currency_input_field.dart';
import 'package:cake_wallet/src/widgets/picker.dart';
import 'package:cake_wallet/themes/extensions/keyboard_theme.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(
fontSize: 14, fontWeight: FontWeight.w500, color: Colors.white),
validator: sendViewModel.addressValidator)),
Observer(
builder: (_) => Padding(
padding: const EdgeInsets.only(top: 20),
child: Row(
children: [
Padding(
padding: const EdgeInsets.only(bottom: 8.0),
child: Row(
children: [
sendViewModel.hasMultipleTokens
? Container(
padding: EdgeInsets.only(right: 8),
height: 32,
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,
),
),
),
),
),
),
),
],
),
),
],
)),
),
CurrencyAmountTextField(
selectedCurrency: sendViewModel.selectedCryptoCurrency.title,
amountFocusNode: cryptoAmountFocus,
amountController: cryptoAmountController,
isAmountEditable: true,
onTapPicker: () => _presentPicker(context),
isPickerEnable: sendViewModel.hasMultipleTokens,
tag: sendViewModel.selectedCryptoCurrency.tag,
allAmountButton: !sendViewModel.isBatchSending,
currencyValueValidator: output.sendAll
? sendViewModel.allAmountValidator
: sendViewModel.amountValidator,
allAmountCallback: () async => output.setSendAll(sendViewModel.balance)),
Divider(
height: 1,
color: Theme.of(context).extension<SendPageTheme>()!.textFieldHintColor),
@ -402,41 +256,16 @@ class SendCardState extends State<SendCard> with AutomaticKeepAliveClientMixin<S
),
),
if (!sendViewModel.isFiatDisabled)
Padding(
padding: const EdgeInsets.only(top: 20),
child: BaseTextFormField(
focusNode: fiatAmountFocus,
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,
),
),
),
CurrencyAmountTextField(
selectedCurrency: sendViewModel.fiat.title,
amountFocusNode: fiatAmountFocus,
amountController: fiatAmountController,
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),
),
),
isAmountEditable: true,
allAmountButton: false),
Divider(
height: 1,
color: Theme.of(context).extension<SendPageTheme>()!.textFieldHintColor),
Padding(
padding: EdgeInsets.only(top: 20),
child: BaseTextFormField(
@ -715,12 +544,11 @@ class SendCardState extends State<SendCard> with AutomaticKeepAliveClientMixin<S
showPopUp<void>(
context: context,
builder: (_) => CurrencyPicker(
selectedAtIndex: sendViewModel.currencies.indexOf(sendViewModel.selectedCryptoCurrency),
items: sendViewModel.currencies,
hintText: S.of(context).search_currency,
onItemSelected: (Currency cur) =>
sendViewModel.selectedCryptoCurrency = (cur as CryptoCurrency),
),
selectedAtIndex: sendViewModel.currencies.indexOf(sendViewModel.selectedCryptoCurrency),
items: sendViewModel.currencies,
hintText: S.of(context).search_currency,
onItemSelected: (Currency cur) =>
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/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/utils/payment_request.dart';
import 'package:cake_wallet/utils/show_pop_up.dart';
@ -59,7 +59,8 @@ class SendTemplateCard extends StatelessWidget {
hintText: sendTemplateViewModel.recipients.length > 1
? S.of(context).template_name
: S.of(context).send_name,
borderColor: Theme.of(context).extension<SendPageTheme>()!.textFieldBorderColor,
borderColor:
Theme.of(context).extension<SendPageTheme>()!.textFieldBorderColor,
textStyle:
TextStyle(fontSize: 14, fontWeight: FontWeight.w500, color: Colors.white),
placeholderTextStyle: TextStyle(
@ -69,107 +70,87 @@ class SendTemplateCard extends StatelessWidget {
validator: sendTemplateViewModel.templateValidator),
Padding(
padding: EdgeInsets.only(top: 20),
child: Observer(
builder: (context) {
return AddressTextField(
selectedCurrency: template.selectedCurrency,
controller: _addressController,
onURIScanned: (uri) {
final paymentRequest = PaymentRequest.fromUri(uri);
_addressController.text = paymentRequest.address;
_cryptoAmountController.text = paymentRequest.amount;
},
options: [
AddressTextFieldOption.paste,
AddressTextFieldOption.qrCode,
AddressTextFieldOption.addressBook
],
onPushPasteButton: (context) async {
template.output.resetParsedAddress();
await template.output.fetchParsedAddress(context);
},
onPushAddressBookButton: (context) async {
template.output.resetParsedAddress();
await template.output.fetchParsedAddress(context);
},
buttonColor: Theme.of(context).extension<SendPageTheme>()!.textFieldButtonColor,
borderColor: Theme.of(context).extension<SendPageTheme>()!.textFieldBorderColor,
textStyle: TextStyle(
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,
);
}
),
),
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,
child: Observer(builder: (context) {
return AddressTextField(
selectedCurrency: template.selectedCurrency,
controller: _addressController,
onURIScanned: (uri) {
final paymentRequest = PaymentRequest.fromUri(uri);
_addressController.text = paymentRequest.address;
_cryptoAmountController.text = paymentRequest.amount;
},
options: [
AddressTextFieldOption.paste,
AddressTextFieldOption.qrCode,
AddressTextFieldOption.addressBook
],
onPushPasteButton: (context) async {
template.output.resetParsedAddress();
await template.output.fetchParsedAddress(context);
},
onPushAddressBookButton: (context) async {
template.output.resetParsedAddress();
await template.output.fetchParsedAddress(context);
},
buttonColor:
Theme.of(context).extension<SendPageTheme>()!.textFieldButtonColor,
borderColor:
Theme.of(context).extension<SendPageTheme>()!.textFieldBorderColor,
textStyle: TextStyle(
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:cw_core/crypto_currency.dart';
import 'package:cw_core/wallet_type.dart';
@ -97,4 +98,8 @@ abstract class SendTemplateViewModelBase with Store {
@computed
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;
@observable
bool isCurrencySelected = true;
@observable
bool isFiatSelected = false;
bool isCryptoSelected = true;
@action
void selectCurrency() {
isCurrencySelected = true;
isFiatSelected = false;
}
@action
void selectFiat() {
isFiatSelected = true;
isCurrencySelected = false;
}
void setCryptoCurrency(bool value) => isCryptoSelected = value;
@action
void reset() {
name = '';
address = '';
isCurrencySelected = true;
isFiatSelected = false;
isCryptoSelected = true;
output.reset();
}
Template toTemplate({required String cryptoCurrency, required String fiatCurrency}) {
return Template(
isCurrencySelectedRaw: isCurrencySelected,
isCurrencySelectedRaw: isCryptoSelected,
nameRaw: name,
addressRaw: address,
cryptoCurrencyRaw: cryptoCurrency,
@ -79,7 +66,7 @@ abstract class TemplateViewModelBase with Store {
@action
void changeSelectedCurrency(CryptoCurrency currency) {
isCurrencySelected = true;
isCryptoSelected = true;
_currency = currency;
}