From 44b1eec81db6d47ead7d49eae64010519815c77c Mon Sep 17 00:00:00 2001 From: Godwin Asuquo Date: Mon, 20 Feb 2023 23:24:19 +0200 Subject: [PATCH 1/2] Fix Popup width constraint and add focus orders --- lib/router.dart | 2 +- .../exchange/exchange_template_page.dart | 188 ++++++------- .../exchange/widgets/currency_picker.dart | 19 +- .../desktop_exchange_cards_section.dart | 25 +- .../exchange/widgets/exchange_card.dart | 201 +++++++------ lib/src/screens/send/send_page.dart | 264 +++++++++--------- lib/src/widgets/address_text_field.dart | 21 +- lib/src/widgets/alert_close_button.dart | 5 +- lib/src/widgets/base_text_form_field.dart | 9 +- lib/src/widgets/check_box_picker.dart | 110 ++++---- lib/src/widgets/picker.dart | 183 ++++++------ lib/utils/responsive_layout_util.dart | 3 + 12 files changed, 508 insertions(+), 522 deletions(-) diff --git a/lib/router.dart b/lib/router.dart index 91a5ac4e1..5d47f2ce2 100644 --- a/lib/router.dart +++ b/lib/router.dart @@ -334,7 +334,7 @@ Route createRoute(RouteSettings settings) { getIt.get()); case Routes.pickerAddressBook: - final selectedCurrency = settings.arguments as CryptoCurrency; + final selectedCurrency = settings.arguments as CryptoCurrency?; return MaterialPageRoute( builder: (_) => getIt.get(param1: selectedCurrency)); diff --git a/lib/src/screens/exchange/exchange_template_page.dart b/lib/src/screens/exchange/exchange_template_page.dart index c22b60ada..ca9c48f40 100644 --- a/lib/src/screens/exchange/exchange_template_page.dart +++ b/lib/src/screens/exchange/exchange_template_page.dart @@ -1,13 +1,9 @@ -import 'dart:ui'; import 'package:cake_wallet/exchange/exchange_provider.dart'; import 'package:cake_wallet/src/screens/base_page.dart'; import 'package:cake_wallet/src/widgets/keyboard_done_button.dart'; -import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_mobx/flutter_mobx.dart'; import 'package:keyboard_actions/keyboard_actions.dart'; -import 'package:keyboard_actions/keyboard_actions_config.dart'; -import 'package:keyboard_actions/keyboard_actions_item.dart'; import 'package:mobx/mobx.dart'; import 'package:cake_wallet/generated/i18n.dart'; import 'package:cw_core/crypto_currency.dart'; @@ -78,7 +74,7 @@ class ExchangeTemplatePage extends BasePage { config: KeyboardActionsConfig( keyboardActionsPlatform: KeyboardActionsPlatform.IOS, keyboardBarColor: - Theme.of(context).accentTextTheme!.bodyText1!.backgroundColor!, + Theme.of(context).accentTextTheme.bodyText1!.backgroundColor!, nextFocus: false, actions: [ KeyboardActionsItem( @@ -103,115 +99,114 @@ class ExchangeTemplatePage extends BasePage { ), gradient: LinearGradient( colors: [ - Theme.of(context).primaryTextTheme!.bodyText2!.color!, - Theme.of(context).primaryTextTheme!.bodyText2!.decorationColor!, + Theme.of(context).primaryTextTheme.bodyText2!.color!, + Theme.of(context).primaryTextTheme.bodyText2!.decorationColor!, ], stops: [0.35, 1.0], begin: Alignment.topLeft, end: Alignment.bottomRight), ), - child: Column( - children: [ - Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.only( - bottomLeft: Radius.circular(24), - bottomRight: Radius.circular(24) + child: FocusTraversalGroup( + policy: OrderedTraversalPolicy(), + child: Column( + children: [ + Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.only( + bottomLeft: Radius.circular(24), + bottomRight: Radius.circular(24) + ), + gradient: LinearGradient( + colors: [ + Theme.of(context) + .primaryTextTheme.subtitle2! + .color!, + Theme.of(context) + .primaryTextTheme.subtitle2! + .decorationColor!, + ], + begin: Alignment.topLeft, + end: Alignment.bottomRight), ), - gradient: LinearGradient( - colors: [ - Theme.of(context) - .primaryTextTheme! - .subtitle2! - .color!, - Theme.of(context) - .primaryTextTheme! - .subtitle2! - .decorationColor!, - ], - begin: Alignment.topLeft, - end: Alignment.bottomRight), - ), - padding: EdgeInsets.fromLTRB(24, 90, 24, 32), - child: Observer( - builder: (_) => ExchangeCard( - amountFocusNode: _depositAmountFocus, - key: depositKey, - title: S.of(context).you_will_send, - initialCurrency: - exchangeViewModel.depositCurrency, - initialWalletName: depositWalletName ?? '', - initialAddress: exchangeViewModel - .depositCurrency == - exchangeViewModel.wallet.currency - ? exchangeViewModel.wallet.walletAddresses.address - : exchangeViewModel.depositAddress, - initialIsAmountEditable: true, - initialIsAddressEditable: exchangeViewModel - .isDepositAddressEnabled, - isAmountEstimated: false, - hasRefundAddress: true, - isMoneroWallet: exchangeViewModel.isMoneroWallet, - currencies: CryptoCurrency.all, - onCurrencySelected: (currency) => - exchangeViewModel.changeDepositCurrency( - currency: currency), - imageArrow: arrowBottomPurple, - currencyButtonColor: Colors.transparent, - addressButtonsColor: - Theme.of(context).focusColor!, - borderColor: Theme.of(context) - .primaryTextTheme! - .bodyText1! - .color!, - currencyValueValidator: AmountValidator( - type: exchangeViewModel.wallet.type), - //addressTextFieldValidator: AddressValidator( - // type: exchangeViewModel.depositCurrency), - ), - ), - ), - Padding( - padding: EdgeInsets.only(top: 29, left: 24, right: 24), - child: Observer( + padding: EdgeInsets.fromLTRB(24, 90, 24, 32), + child: Observer( builder: (_) => ExchangeCard( - amountFocusNode: _receiveAmountFocus, - key: receiveKey, - title: S.of(context).you_will_get, + amountFocusNode: _depositAmountFocus, + key: depositKey, + title: S.of(context).you_will_send, initialCurrency: - exchangeViewModel.receiveCurrency, - initialWalletName: receiveWalletName ?? '', - initialAddress: - exchangeViewModel.receiveCurrency == + exchangeViewModel.depositCurrency, + initialWalletName: depositWalletName ?? '', + initialAddress: exchangeViewModel + .depositCurrency == exchangeViewModel.wallet.currency ? exchangeViewModel.wallet.walletAddresses.address - : exchangeViewModel.receiveAddress, - initialIsAmountEditable: - exchangeViewModel.provider is - XMRTOExchangeProvider ? true : false, - initialIsAddressEditable: - exchangeViewModel.isReceiveAddressEnabled, - isAmountEstimated: true, + : exchangeViewModel.depositAddress, + initialIsAmountEditable: true, + initialIsAddressEditable: exchangeViewModel + .isDepositAddressEnabled, + isAmountEstimated: false, + hasRefundAddress: true, isMoneroWallet: exchangeViewModel.isMoneroWallet, - currencies: exchangeViewModel.receiveCurrencies, + currencies: CryptoCurrency.all, onCurrencySelected: (currency) => - exchangeViewModel.changeReceiveCurrency( + exchangeViewModel.changeDepositCurrency( currency: currency), - imageArrow: arrowBottomCakeGreen, + imageArrow: arrowBottomPurple, currencyButtonColor: Colors.transparent, addressButtonsColor: - Theme.of(context).focusColor!, + Theme.of(context).focusColor, borderColor: Theme.of(context) - .primaryTextTheme! - .bodyText1! - .decorationColor!, + .primaryTextTheme.bodyText1! + .color!, currencyValueValidator: AmountValidator( type: exchangeViewModel.wallet.type), //addressTextFieldValidator: AddressValidator( - // type: exchangeViewModel.receiveCurrency), - )), - ) - ], + // type: exchangeViewModel.depositCurrency), + ), + ), + ), + Padding( + padding: EdgeInsets.only(top: 29, left: 24, right: 24), + child: Observer( + builder: (_) => ExchangeCard( + amountFocusNode: _receiveAmountFocus, + key: receiveKey, + title: S.of(context).you_will_get, + initialCurrency: + exchangeViewModel.receiveCurrency, + initialWalletName: receiveWalletName ?? '', + initialAddress: + exchangeViewModel.receiveCurrency == + exchangeViewModel.wallet.currency + ? exchangeViewModel.wallet.walletAddresses.address + : exchangeViewModel.receiveAddress, + initialIsAmountEditable: + exchangeViewModel.provider is + XMRTOExchangeProvider ? true : false, + initialIsAddressEditable: + exchangeViewModel.isReceiveAddressEnabled, + isAmountEstimated: true, + isMoneroWallet: exchangeViewModel.isMoneroWallet, + currencies: exchangeViewModel.receiveCurrencies, + onCurrencySelected: (currency) => + exchangeViewModel.changeReceiveCurrency( + currency: currency), + imageArrow: arrowBottomCakeGreen, + currencyButtonColor: Colors.transparent, + addressButtonsColor: + Theme.of(context).focusColor, + borderColor: Theme.of(context) + .primaryTextTheme.bodyText1! + .decorationColor!, + currencyValueValidator: AmountValidator( + type: exchangeViewModel.wallet.type), + //addressTextFieldValidator: AddressValidator( + // type: exchangeViewModel.receiveCurrency), + )), + ) + ], + ), ), ), bottomSectionPadding: @@ -230,8 +225,7 @@ class ExchangeTemplatePage extends BasePage { textAlign: TextAlign.center, style: TextStyle( color: Theme.of(context) - .primaryTextTheme! - .headline1! + .primaryTextTheme.headline1! .decorationColor!, fontWeight: FontWeight.w500, fontSize: 12), diff --git a/lib/src/screens/exchange/widgets/currency_picker.dart b/lib/src/screens/exchange/widgets/currency_picker.dart index 9f8b9e493..ff20acd7e 100644 --- a/lib/src/screens/exchange/widgets/currency_picker.dart +++ b/lib/src/screens/exchange/widgets/currency_picker.dart @@ -1,8 +1,7 @@ -import 'dart:ui'; import 'package:cake_wallet/src/screens/exchange/widgets/currency_picker_item_widget.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:cake_wallet/utils/responsive_layout_util.dart'; import 'package:flutter/material.dart'; import 'package:cw_core/crypto_currency.dart'; import 'package:cake_wallet/src/widgets/alert_background.dart'; @@ -54,7 +53,7 @@ class CurrencyPickerState extends State { if (subString.isNotEmpty) { subPickerItemsList = items .where((element) => - (element.title != null ? element.title.toLowerCase().contains(subString.toLowerCase()) : false) || + (element.title.toLowerCase().contains(subString.toLowerCase())) || (element.tag != null ? element.tag!.toLowerCase().contains(subString.toLowerCase()) : false) || (element.name != null ? element.name!.toLowerCase().contains(subString.toLowerCase()) : false)) .toList(); @@ -67,11 +66,9 @@ class CurrencyPickerState extends State { @override Widget build(BuildContext context) { return AlertBackground( - child: Stack( - alignment: Alignment.center, - children: [ - Column( + child: Column( mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.center, children: [ if (widget.title?.isNotEmpty ?? false) Container( @@ -93,10 +90,11 @@ class CurrencyPickerState extends State { child: ClipRRect( borderRadius: BorderRadius.all(Radius.circular(30)), child: Container( - color: Theme.of(context).accentTextTheme!.headline6!.color!, + color: Theme.of(context).accentTextTheme.headline6!.color!, child: ConstrainedBox( constraints: BoxConstraints( maxHeight: MediaQuery.of(context).size.height * 0.65, + maxWidth: ResponsiveLayoutUtil.kPopupWidth ), child: Column( mainAxisSize: MainAxisSize.min, @@ -132,7 +130,7 @@ class CurrencyPickerState extends State { ), ), Divider( - color: Theme.of(context).accentTextTheme!.headline6!.backgroundColor!, + color: Theme.of(context).accentTextTheme.headline6!.backgroundColor!, height: 1, ), if (widget.selectedAtIndex != -1) @@ -170,8 +168,7 @@ class CurrencyPickerState extends State { ), ), ), - ], - ), + SizedBox(height: ResponsiveLayoutUtil.kPopupSpaceHeight), AlertCloseButton(), ], ), diff --git a/lib/src/screens/exchange/widgets/desktop_exchange_cards_section.dart b/lib/src/screens/exchange/widgets/desktop_exchange_cards_section.dart index 2dc91624d..0a97d7bad 100644 --- a/lib/src/screens/exchange/widgets/desktop_exchange_cards_section.dart +++ b/lib/src/screens/exchange/widgets/desktop_exchange_cards_section.dart @@ -12,17 +12,20 @@ class DesktopExchangeCardsSection extends StatelessWidget { @override Widget build(BuildContext context) { - return Column( - children: [ - Padding( - padding: EdgeInsets.only(top: 55, left: 24, right: 24), - child: firstExchangeCard, - ), - Padding( - padding: EdgeInsets.only(top: 29, left: 24, right: 24), - child: secondExchangeCard, - ), - ], + return FocusTraversalGroup( + policy: OrderedTraversalPolicy(), + child: Column( + children: [ + Padding( + padding: EdgeInsets.only(top: 55, left: 24, right: 24), + child: firstExchangeCard, + ), + Padding( + padding: EdgeInsets.only(top: 29, left: 24, right: 24), + child: secondExchangeCard, + ), + ], + ), ); } } diff --git a/lib/src/screens/exchange/widgets/exchange_card.dart b/lib/src/screens/exchange/widgets/exchange_card.dart index 40aa679a4..67028b425 100644 --- a/lib/src/screens/exchange/widgets/exchange_card.dart +++ b/lib/src/screens/exchange/widgets/exchange_card.dart @@ -159,7 +159,7 @@ class ExchangeCardState extends State { final copyImage = Image.asset('assets/images/copy_content.png', height: 16, width: 16, - color: Theme.of(context).primaryTextTheme!.headline3!.color!); + color: Theme.of(context).primaryTextTheme.headline3!.color!); return Container( width: double.infinity, @@ -174,7 +174,7 @@ class ExchangeCardState extends State { style: TextStyle( fontSize: 18, fontWeight: FontWeight.w600, - color: Theme.of(context).textTheme!.headline5!.color!), + color: Theme.of(context).textTheme.headline5!.color!), ) ], ), @@ -209,7 +209,7 @@ class ExchangeCardState extends State { child: Container( height: 32, decoration: BoxDecoration( - color: widget.addressButtonsColor ?? Theme.of(context).primaryTextTheme!.headline4!.color!, + color: widget.addressButtonsColor ?? Theme.of(context).primaryTextTheme.headline4!.color!, borderRadius: BorderRadius.all(Radius.circular(6))), child: Center( @@ -220,8 +220,7 @@ class ExchangeCardState extends State { fontSize: 12, fontWeight: FontWeight.bold, color: Theme.of(context) - .primaryTextTheme! - .headline4! + .primaryTextTheme.headline4! .decorationColor!)), ), ), @@ -240,34 +239,36 @@ class ExchangeCardState extends State { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Flexible( - 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) - .accentTextTheme! - .headline1! - .decorationColor!), - validator: _isAmountEditable - ? widget.currencyValueValidator - : null), + 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) + .accentTextTheme.headline1! + .decorationColor!), + validator: _isAmountEditable + ? widget.currencyValueValidator + : null), + ), ), if (widget.hasAllAmount) Container( @@ -275,8 +276,7 @@ class ExchangeCardState extends State { width: 32, decoration: BoxDecoration( color: Theme.of(context) - .primaryTextTheme! - .headline4! + .primaryTextTheme.headline4! .color!, borderRadius: BorderRadius.all(Radius.circular(6))), @@ -289,8 +289,7 @@ class ExchangeCardState extends State { fontSize: 12, fontWeight: FontWeight.bold, color: Theme.of(context) - .primaryTextTheme! - .headline4! + .primaryTextTheme.headline4! .decorationColor!)), ), ), @@ -301,8 +300,7 @@ class ExchangeCardState extends State { ], )), Divider(height: 1,color: Theme.of(context) - .primaryTextTheme! - .headline5! + .primaryTextTheme.headline5! .decorationColor!), Padding( padding: EdgeInsets.only(top: 5), @@ -320,8 +318,7 @@ class ExchangeCardState extends State { fontSize: 10, height: 1.2, color: Theme.of(context) - .accentTextTheme! - .headline1! + .accentTextTheme.headline1! .decorationColor!), ) : Offstage(), @@ -335,8 +332,7 @@ class ExchangeCardState extends State { fontSize: 10, height: 1.2, color: Theme.of(context) - .accentTextTheme! - .headline1! + .accentTextTheme.headline1! .decorationColor!)) : Offstage(), ])), @@ -350,71 +346,75 @@ class ExchangeCardState extends State { fontSize: 14, fontWeight: FontWeight.w500, color: Theme.of(context) - .accentTextTheme! - .headline1! + .accentTextTheme.headline1! .decorationColor!), )) : Offstage(), _isAddressEditable - ? Padding( - padding: EdgeInsets.only(top: 20), - child: AddressTextField( - focusNode: widget.addressFocusNode, - controller: addressController, - onURIScanned: (uri) { - final paymentRequest = PaymentRequest.fromUri(uri); - addressController.text = paymentRequest.address; - - if (amountController.text.isNotEmpty) { - _showAmountPopup(context, paymentRequest); - return; - } - widget.amountFocusNode?.requestFocus(); - amountController.text = paymentRequest.amount; - }, - placeholder: widget.hasRefundAddress - ? S.of(context).refund_address - : null, - options: [ - AddressTextFieldOption.paste, - AddressTextFieldOption.qrCode, - AddressTextFieldOption.addressBook, - ], - isBorderExist: false, - textStyle: TextStyle( - fontSize: 16, - fontWeight: FontWeight.w600, - color: Colors.white), - hintStyle: TextStyle( - fontSize: 16, - fontWeight: FontWeight.w600, - color: Theme.of(context) - .accentTextTheme! - .headline1! - .decorationColor!), - buttonColor: widget.addressButtonsColor, - validator: widget.addressTextFieldValidator, - onPushPasteButton: widget.onPushPasteButton, - onPushAddressBookButton: widget.onPushAddressBookButton, - selectedCurrency: _selectedCurrency + ? FocusTraversalOrder( + order: NumericFocusOrder(2), + child: Padding( + padding: EdgeInsets.only(top: 20), + child: AddressTextField( + focusNode: widget.addressFocusNode, + controller: addressController, + onURIScanned: (uri) { + final paymentRequest = PaymentRequest.fromUri(uri); + addressController.text = paymentRequest.address; + + if (amountController.text.isNotEmpty) { + _showAmountPopup(context, paymentRequest); + return; + } + widget.amountFocusNode?.requestFocus(); + amountController.text = paymentRequest.amount; + }, + placeholder: widget.hasRefundAddress + ? S.of(context).refund_address + : null, + options: [ + AddressTextFieldOption.paste, + AddressTextFieldOption.qrCode, + AddressTextFieldOption.addressBook, + ], + isBorderExist: false, + textStyle: TextStyle( + fontSize: 16, + fontWeight: FontWeight.w600, + color: Colors.white), + hintStyle: TextStyle( + fontSize: 16, + fontWeight: FontWeight.w600, + color: Theme.of(context) + .accentTextTheme.headline1! + .decorationColor!), + buttonColor: widget.addressButtonsColor, + validator: widget.addressTextFieldValidator, + onPushPasteButton: widget.onPushPasteButton, + onPushAddressBookButton: widget.onPushAddressBookButton, + selectedCurrency: _selectedCurrency + ), + ), - - ) + ) : Padding( padding: EdgeInsets.only(top: 10), child: Builder( builder: (context) => Stack(children: [ - BaseTextFormField( - controller: addressController, - readOnly: true, - borderColor: Colors.transparent, - suffixIcon: - SizedBox(width: _isMoneroWallet ? 80 : 36), - textStyle: TextStyle( - fontSize: 16, - fontWeight: FontWeight.w600, - color: Colors.white), - validator: widget.addressTextFieldValidator), + FocusTraversalOrder( + order: NumericFocusOrder(3), + child: BaseTextFormField( + controller: addressController, + readOnly: true, + borderColor: Colors.transparent, + suffixIcon: + SizedBox(width: _isMoneroWallet ? 80 : 36), + textStyle: TextStyle( + fontSize: 16, + fontWeight: FontWeight.w600, + color: Colors.white), + validator: widget.addressTextFieldValidator), + ), Positioned( top: 2, right: 0, @@ -457,8 +457,7 @@ class ExchangeCardState extends State { child: Image.asset( 'assets/images/open_book.png', color: Theme.of(context) - .primaryTextTheme! - .headline4! + .primaryTextTheme.headline4! .decorationColor!, )), )), diff --git a/lib/src/screens/send/send_page.dart b/lib/src/screens/send/send_page.dart index 5d1f378d1..8534a1677 100644 --- a/lib/src/screens/send/send_page.dart +++ b/lib/src/screens/send/send_page.dart @@ -117,136 +117,137 @@ class SendPage extends BasePage { key: _formKey, child: ScrollableWithBottomSection( contentPadding: EdgeInsets.only(bottom: 24), - content: Column( - children: [ - Container( - height: _sendCardHeight(context), - child: Observer( - builder: (_) { - return PageView.builder( - scrollDirection: Axis.horizontal, - controller: controller, - itemCount: sendViewModel.outputs.length, - itemBuilder: (context, index) { - final output = sendViewModel.outputs[index]; - - return SendCard( - key: output.key, - output: output, - sendViewModel: sendViewModel, - initialPaymentRequest: initialPaymentRequest, - ); - }); - }, - )), - Padding( - padding: - EdgeInsets.only(top: 10, left: 24, right: 24, bottom: 10), - child: Container( - height: 10, - child: Observer( - builder: (_) { - final count = sendViewModel.outputs.length; - - return count > 1 - ? SmoothPageIndicator( - controller: controller, - count: count, - effect: ScrollingDotsEffect( - spacing: 6.0, - radius: 6.0, - dotWidth: 6.0, - dotHeight: 6.0, - dotColor: Theme.of(context) - .primaryTextTheme! - .headline3! - .backgroundColor!, - activeDotColor: Theme.of(context) - .primaryTextTheme! - .headline2! - .backgroundColor!), - ) - : Offstage(); - }, - ), - ), - ), - if (sendViewModel.hasMultiRecipient) - Container( - height: 40, - width: double.infinity, - padding: EdgeInsets.only(left: 24), - child: SingleChildScrollView( - scrollDirection: Axis.horizontal, - child: Observer( - builder: (_) { - final templates = sendViewModel.templates; - final itemCount = templates.length; - - return Row( - children: [ - AddTemplateButton( - onTap: () => Navigator.of(context).pushNamed(Routes.sendTemplate), - currentTemplatesLength: templates.length, - ), - ListView.builder( + content: FocusTraversalGroup( + policy: OrderedTraversalPolicy(), + child: Column( + children: [ + Container( + height: _sendCardHeight(context), + child: Observer( + builder: (_) { + return PageView.builder( scrollDirection: Axis.horizontal, - shrinkWrap: true, - physics: NeverScrollableScrollPhysics(), - itemCount: itemCount, + controller: controller, + itemCount: sendViewModel.outputs.length, itemBuilder: (context, index) { - final template = templates[index]; - return TemplateTile( - key: UniqueKey(), - to: template.name, - amount: template.isCurrencySelected ? template.amount : template.amountFiat, - from: template.isCurrencySelected ? template.cryptoCurrency : template.fiatCurrency, - onTap: () async { - final fiatFromTemplate = FiatCurrency.all.singleWhere((element) => element.title == template.fiatCurrency); - final output = _defineCurrentOutput(); - output.address = template.address; - if(template.isCurrencySelected){ - output.setCryptoAmount(template.amount); - }else{ - sendViewModel.setFiatCurrency(fiatFromTemplate); - output.setFiatAmount(template.amountFiat); - } - output.resetParsedAddress(); - await output.fetchParsedAddress(context); - }, - onRemove: () { - showPopUp( - context: context, - builder: (dialogContext) { - return AlertWithTwoActions( - alertTitle: S.of(context).template, - alertContent: S - .of(context) - .confirm_delete_template, - rightButtonText: S.of(context).delete, - leftButtonText: S.of(context).cancel, - actionRightButton: () { - Navigator.of(dialogContext).pop(); - sendViewModel.sendTemplateViewModel - .removeTemplate( - template: template); - }, - actionLeftButton: () => - Navigator.of(dialogContext) - .pop()); - }, - ); - }, + final output = sendViewModel.outputs[index]; + + return SendCard( + key: output.key, + output: output, + sendViewModel: sendViewModel, + initialPaymentRequest: initialPaymentRequest, ); - }, - ), - ], - ); - }, + }); + }, + )), + Padding( + padding: + EdgeInsets.only(top: 10, left: 24, right: 24, bottom: 10), + child: Container( + height: 10, + child: Observer( + builder: (_) { + final count = sendViewModel.outputs.length; + + return count > 1 + ? SmoothPageIndicator( + controller: controller, + count: count, + effect: ScrollingDotsEffect( + spacing: 6.0, + radius: 6.0, + dotWidth: 6.0, + dotHeight: 6.0, + dotColor: Theme.of(context) + .primaryTextTheme.headline3! + .backgroundColor!, + activeDotColor: Theme.of(context) + .primaryTextTheme.headline2! + .backgroundColor!), + ) + : Offstage(); + }, + ), ), ), - ) - ], + if (sendViewModel.hasMultiRecipient) + Container( + height: 40, + width: double.infinity, + padding: EdgeInsets.only(left: 24), + child: SingleChildScrollView( + scrollDirection: Axis.horizontal, + child: Observer( + builder: (_) { + final templates = sendViewModel.templates; + final itemCount = templates.length; + + return Row( + children: [ + AddTemplateButton( + onTap: () => Navigator.of(context).pushNamed(Routes.sendTemplate), + currentTemplatesLength: templates.length, + ), + ListView.builder( + scrollDirection: Axis.horizontal, + shrinkWrap: true, + physics: NeverScrollableScrollPhysics(), + itemCount: itemCount, + itemBuilder: (context, index) { + final template = templates[index]; + return TemplateTile( + key: UniqueKey(), + to: template.name, + amount: template.isCurrencySelected ? template.amount : template.amountFiat, + from: template.isCurrencySelected ? template.cryptoCurrency : template.fiatCurrency, + onTap: () async { + final fiatFromTemplate = FiatCurrency.all.singleWhere((element) => element.title == template.fiatCurrency); + final output = _defineCurrentOutput(); + output.address = template.address; + if(template.isCurrencySelected){ + output.setCryptoAmount(template.amount); + }else{ + sendViewModel.setFiatCurrency(fiatFromTemplate); + output.setFiatAmount(template.amountFiat); + } + output.resetParsedAddress(); + await output.fetchParsedAddress(context); + }, + onRemove: () { + showPopUp( + context: context, + builder: (dialogContext) { + return AlertWithTwoActions( + alertTitle: S.of(context).template, + alertContent: S + .of(context) + .confirm_delete_template, + rightButtonText: S.of(context).delete, + leftButtonText: S.of(context).cancel, + actionRightButton: () { + Navigator.of(dialogContext).pop(); + sendViewModel.sendTemplateViewModel + .removeTemplate( + template: template); + }, + actionLeftButton: () => + Navigator.of(dialogContext) + .pop()); + }, + ); + }, + ); + }, + ), + ], + ); + }, + ), + ), + ) + ], + ), ), bottomSectionPadding: EdgeInsets.only(left: 24, right: 24, bottom: 24), @@ -261,8 +262,7 @@ class SendPage extends BasePage { text: 'Change your asset (${sendViewModel.selectedCryptoCurrency})', color: Colors.transparent, textColor: Theme.of(context) - .accentTextTheme! - .headline3! + .accentTextTheme.headline3! .decorationColor!, ) ) @@ -280,13 +280,11 @@ class SendPage extends BasePage { text: S.of(context).add_receiver, color: Colors.transparent, textColor: Theme.of(context) - .accentTextTheme! - .headline3! + .accentTextTheme.headline3! .decorationColor!, isDottedBorder: true, borderColor: Theme.of(context) - .primaryTextTheme! - .headline3! + .primaryTextTheme.headline3! .decorationColor!, )), Observer( @@ -306,7 +304,7 @@ class SendPage extends BasePage { item.address.isEmpty || item.cryptoAmount.isEmpty) .toList(); - if (notValidItems?.isNotEmpty ?? false) { + if (notValidItems.isNotEmpty ?? false) { showErrorValidationAlert(context); return; } @@ -315,7 +313,7 @@ class SendPage extends BasePage { }, text: S.of(context).send, - color: Theme.of(context).accentTextTheme!.bodyText1!.color!, + color: Theme.of(context).accentTextTheme.bodyText1!.color!, textColor: Colors.white, isLoading: sendViewModel.state is IsExecutingState || sendViewModel.state is TransactionCommitting, diff --git a/lib/src/widgets/address_text_field.dart b/lib/src/widgets/address_text_field.dart index 7e0727312..283532031 100644 --- a/lib/src/widgets/address_text_field.dart +++ b/lib/src/widgets/address_text_field.dart @@ -58,12 +58,13 @@ class AddressTextField extends StatelessWidget { TextFormField( onFieldSubmitted: (_) => FocusScope.of(context).unfocus(), enabled: isActive, + autofocus: true, controller: controller, focusNode: focusNode, style: textStyle ?? TextStyle( fontSize: 16, - color: Theme.of(context).primaryTextTheme!.headline6!.color!), + color: Theme.of(context).primaryTextTheme.headline6!.color!), decoration: InputDecoration( suffixIcon: SizedBox( width: prefixIconWidth * options.length + @@ -115,8 +116,7 @@ class AddressTextField extends StatelessWidget { decoration: BoxDecoration( color: buttonColor ?? Theme.of(context) - .accentTextTheme! - .headline6! + .accentTextTheme.headline6! .color!, borderRadius: BorderRadius.all(Radius.circular(6))), @@ -124,8 +124,7 @@ class AddressTextField extends StatelessWidget { 'assets/images/paste_ios.png', color: iconColor ?? Theme.of(context) - .primaryTextTheme! - .headline4! + .primaryTextTheme.headline4! .decorationColor!, )), )), @@ -142,8 +141,7 @@ class AddressTextField extends StatelessWidget { decoration: BoxDecoration( color: buttonColor ?? Theme.of(context) - .accentTextTheme! - .headline6! + .accentTextTheme.headline6! .color!, borderRadius: BorderRadius.all(Radius.circular(6))), @@ -151,8 +149,7 @@ class AddressTextField extends StatelessWidget { 'assets/images/qr_code_icon.png', color: iconColor ?? Theme.of(context) - .primaryTextTheme! - .headline4! + .primaryTextTheme.headline4! .decorationColor!, )), )) @@ -171,8 +168,7 @@ class AddressTextField extends StatelessWidget { decoration: BoxDecoration( color: buttonColor ?? Theme.of(context) - .accentTextTheme! - .headline6! + .accentTextTheme.headline6! .color!, borderRadius: BorderRadius.all(Radius.circular(6))), @@ -180,8 +176,7 @@ class AddressTextField extends StatelessWidget { 'assets/images/open_book.png', color: iconColor ?? Theme.of(context) - .primaryTextTheme! - .headline4! + .primaryTextTheme.headline4! .decorationColor!, )), )) diff --git a/lib/src/widgets/alert_close_button.dart b/lib/src/widgets/alert_close_button.dart index 35a5cd45c..e8e20f125 100644 --- a/lib/src/widgets/alert_close_button.dart +++ b/lib/src/widgets/alert_close_button.dart @@ -13,9 +13,7 @@ class AlertCloseButton extends StatelessWidget { @override Widget build(BuildContext context) { - return Positioned( - bottom: 60, - child: GestureDetector( + return GestureDetector( onTap: () => Navigator.of(context).pop(), child: Container( height: 42, @@ -28,7 +26,6 @@ class AlertCloseButton extends StatelessWidget { child: image ?? closeButton, ), ), - ) ); } } \ No newline at end of file diff --git a/lib/src/widgets/base_text_form_field.dart b/lib/src/widgets/base_text_form_field.dart index 6c29f79ea..87134b449 100644 --- a/lib/src/widgets/base_text_form_field.dart +++ b/lib/src/widgets/base_text_form_field.dart @@ -64,6 +64,7 @@ class BaseTextFormField extends StatelessWidget { readOnly: readOnly, initialValue: initialValue, focusNode: focusNode, + autofocus: true, controller: controller, keyboardType: keyboardType, textInputAction: textInputAction, @@ -78,7 +79,7 @@ class BaseTextFormField extends StatelessWidget { TextStyle( fontSize: 16.0, color: - textColor ?? Theme.of(context).primaryTextTheme!.headline6!.color!), + textColor ?? Theme.of(context).primaryTextTheme.headline6!.color!), decoration: InputDecoration( prefix: prefix, prefixIcon: prefixIcon, @@ -92,17 +93,17 @@ class BaseTextFormField extends StatelessWidget { focusedBorder: UnderlineInputBorder( borderSide: BorderSide( color: borderColor ?? - Theme.of(context).primaryTextTheme!.headline6!.backgroundColor!, + Theme.of(context).primaryTextTheme.headline6!.backgroundColor!, width: borderWidth)), disabledBorder: UnderlineInputBorder( borderSide: BorderSide( color: borderColor ?? - Theme.of(context).primaryTextTheme!.headline6!.backgroundColor!, + Theme.of(context).primaryTextTheme.headline6!.backgroundColor!, width: borderWidth)), enabledBorder: UnderlineInputBorder( borderSide: BorderSide( color: borderColor ?? - Theme.of(context).primaryTextTheme!.headline6!.backgroundColor!, + Theme.of(context).primaryTextTheme.headline6!.backgroundColor!, width: borderWidth))), validator: validator, ); diff --git a/lib/src/widgets/check_box_picker.dart b/lib/src/widgets/check_box_picker.dart index e2f817fc4..8c73349ac 100644 --- a/lib/src/widgets/check_box_picker.dart +++ b/lib/src/widgets/check_box_picker.dart @@ -1,4 +1,5 @@ import 'package:cake_wallet/palette.dart'; +import 'package:cake_wallet/utils/responsive_layout_util.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'; @@ -32,77 +33,76 @@ class CheckBoxPickerState extends State { @override Widget build(BuildContext context) { return AlertBackground( - child: Stack( - alignment: Alignment.center, - children: [ - Column( - mainAxisSize: MainAxisSize.min, - children: [ - if (widget.title?.isNotEmpty ?? false) - Container( - 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, + child: Center( + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + if (widget.title.isNotEmpty) + Container( + 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!.headline6!.color!, - child: ConstrainedBox( - constraints: BoxConstraints( - maxHeight: MediaQuery.of(context).size.height * 0.65, - ), - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Flexible( - child: Stack( - alignment: Alignment.center, - children: [ - (items?.length ?? 0) > 3 - ? Scrollbar( - controller: controller, - child: itemsList(), - ) - : itemsList(), - ], + 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.headline6!.color!, + child: ConstrainedBox( + constraints: BoxConstraints( + maxHeight: MediaQuery.of(context).size.height * 0.65, + maxWidth: ResponsiveLayoutUtil.kPopupWidth, + ), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Flexible( + child: Stack( + alignment: Alignment.center, + children: [ + (items.length) > 3 + ? Scrollbar( + controller: controller, + child: itemsList(), + ) + : itemsList(), + ], + ), ), - ), - ], + ], + ), ), ), ), ), - ) - ], - ), - AlertCloseButton(), - ], + SizedBox(height: ResponsiveLayoutUtil.kPopupSpaceHeight), + AlertCloseButton(), + ], + ), ), ); } Widget itemsList() { return Container( - color: Theme.of(context).accentTextTheme!.headline6!.backgroundColor!, + color: Theme.of(context).accentTextTheme.headline6!.backgroundColor!, child: ListView.separated( padding: EdgeInsets.zero, controller: controller, shrinkWrap: true, separatorBuilder: (context, index) => widget.isSeparated ? Divider( - color: Theme.of(context).accentTextTheme!.headline6!.backgroundColor!, + color: Theme.of(context).accentTextTheme.headline6!.backgroundColor!, height: 1, ) : const SizedBox(), @@ -121,13 +121,13 @@ class CheckBoxPickerState extends State { }, child: Container( height: 55, - color: Theme.of(context).accentTextTheme!.headline6!.color!, + color: Theme.of(context).accentTextTheme.headline6!.color!, padding: EdgeInsets.only(left: 24, right: 24), child: CheckboxListTile( value: item.value, activeColor: item.value ? Palette.blueCraiola - : Theme.of(context).accentTextTheme!.subtitle1!.decorationColor!, + : Theme.of(context).accentTextTheme.subtitle1!.decorationColor!, checkColor: Colors.white, title: widget.displayItem?.call(item) ?? Text( @@ -138,7 +138,7 @@ class CheckBoxPickerState extends State { fontWeight: FontWeight.w600, color: item.isDisabled ? Colors.grey.withOpacity(0.5) - : Theme.of(context).primaryTextTheme!.headline6!.color!, + : Theme.of(context).primaryTextTheme.headline6!.color!, decoration: TextDecoration.none, ), ), diff --git a/lib/src/widgets/picker.dart b/lib/src/widgets/picker.dart index 36aafe5aa..edc87f971 100644 --- a/lib/src/widgets/picker.dart +++ b/lib/src/widgets/picker.dart @@ -1,5 +1,6 @@ // ignore_for_file: deprecated_member_use +import 'package:cake_wallet/utils/responsive_layout_util.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'; @@ -70,108 +71,106 @@ class _PickerState extends State { @override Widget build(BuildContext context) { return AlertBackground( - child: Stack( - alignment: Alignment.center, + child: Column( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.center, children: [ - Column( - mainAxisSize: MainAxisSize.min, - children: [ - if (widget.title?.isNotEmpty ?? false) - Container( - 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, - ), - ), + if (widget.title?.isNotEmpty ?? false) + Container( + 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.headline6!.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( - controller: searchController, - style: TextStyle(color: Theme.of(context).primaryTextTheme.headline6!.color!), - decoration: InputDecoration( - hintText: widget.hintText, - prefixIcon: Image.asset("assets/images/search_icon.png"), - filled: true, - fillColor: Theme.of(context).accentTextTheme.headline3!.color!, - 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, - )), - ), + ), + ), + 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.headline6!.color!, + child: ConstrainedBox( + constraints: BoxConstraints( + maxHeight: MediaQuery.of(context).size.height * 0.65, + maxWidth: ResponsiveLayoutUtil.kPopupWidth, + ), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + if (widget.hintText != null) + Padding( + padding: const EdgeInsets.all(16), + child: TextFormField( + controller: searchController, + style: TextStyle(color: Theme.of(context).primaryTextTheme.headline6!.color!), + decoration: InputDecoration( + hintText: widget.hintText, + prefixIcon: Image.asset("assets/images/search_icon.png"), + filled: true, + fillColor: Theme.of(context).accentTextTheme.headline3!.color!, + 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, + )), ), ), - Divider( - color: Theme.of(context).accentTextTheme.headline6!.backgroundColor!, - height: 1, ), - if (widget.selectedAtIndex != -1) buildSelectedItem(), - Flexible( - child: Stack( - alignment: Alignment.center, - children: [ - items.length > 3 ? Scrollbar( - controller: controller, - child: itemsList(), - ) : itemsList(), - (widget.description?.isNotEmpty ?? false) - ? Positioned( - bottom: 24, - left: 24, - right: 24, - child: Text( - widget.description!, - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 12, - fontWeight: FontWeight.w500, - fontFamily: 'Lato', - decoration: TextDecoration.none, - color: Theme.of(context).primaryTextTheme.headline6!.color!, - ), + Divider( + color: Theme.of(context).accentTextTheme.headline6!.backgroundColor!, + height: 1, + ), + if (widget.selectedAtIndex != -1) buildSelectedItem(), + Flexible( + child: Stack( + alignment: Alignment.center, + children: [ + items.length > 3 ? Scrollbar( + controller: controller, + child: itemsList(), + ) : itemsList(), + (widget.description?.isNotEmpty ?? false) + ? Positioned( + bottom: 24, + left: 24, + right: 24, + child: Text( + widget.description!, + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 12, + fontWeight: FontWeight.w500, + fontFamily: 'Lato', + decoration: TextDecoration.none, + color: Theme.of(context).primaryTextTheme.headline6!.color!, ), - ) - : Offstage(), - ], - ), + ), + ) + : Offstage(), + ], ), - ], - ), - ), + ), + ], ), ), - ) - ], + ), + ), ), + SizedBox(height: ResponsiveLayoutUtil.kPopupSpaceHeight), AlertCloseButton(), ], ), diff --git a/lib/utils/responsive_layout_util.dart b/lib/utils/responsive_layout_util.dart index d685b40d2..8ae76ca21 100644 --- a/lib/utils/responsive_layout_util.dart +++ b/lib/utils/responsive_layout_util.dart @@ -3,6 +3,9 @@ import 'package:flutter/material.dart'; class ResponsiveLayoutUtil { static const double _kMobileThreshold = 900; static const double kDesktopMaxWidthConstraint = 400; + static const double kPopupWidth = 400; + static const double kPopupSpaceHeight = 100; + const ResponsiveLayoutUtil._(); From bba0ce2ec64e25f313d1c7a7da995e932ccf9ef5 Mon Sep 17 00:00:00 2001 From: Godwin Asuquo Date: Thu, 23 Feb 2023 18:03:44 +0200 Subject: [PATCH 2/2] Remove autofocus --- lib/src/widgets/address_text_field.dart | 1 - lib/src/widgets/base_text_form_field.dart | 1 - 2 files changed, 2 deletions(-) diff --git a/lib/src/widgets/address_text_field.dart b/lib/src/widgets/address_text_field.dart index 283532031..f96f4e967 100644 --- a/lib/src/widgets/address_text_field.dart +++ b/lib/src/widgets/address_text_field.dart @@ -58,7 +58,6 @@ class AddressTextField extends StatelessWidget { TextFormField( onFieldSubmitted: (_) => FocusScope.of(context).unfocus(), enabled: isActive, - autofocus: true, controller: controller, focusNode: focusNode, style: textStyle ?? diff --git a/lib/src/widgets/base_text_form_field.dart b/lib/src/widgets/base_text_form_field.dart index 87134b449..ff2102843 100644 --- a/lib/src/widgets/base_text_form_field.dart +++ b/lib/src/widgets/base_text_form_field.dart @@ -64,7 +64,6 @@ class BaseTextFormField extends StatelessWidget { readOnly: readOnly, initialValue: initialValue, focusNode: focusNode, - autofocus: true, controller: controller, keyboardType: keyboardType, textInputAction: textInputAction,