mirror of
https://github.com/Such-Software/hash-wallet.git
synced 2026-10-28 06:28:41 +01:00
CW-727/728-Automated-Integrated-Tests (#1514)
* feat: Integration tests setup and tests for Disclaimer, Welcome and Setup Pin Code pages * feat: Integration test flow from start to restoring a wallet successfully done * test: Dashboard view test and linking to flow * feat: Testing the Exchange flow section, selecting sending and receiving currencies * test: Successfully create an exchange section * feat: Implement flow up to sending section * test: Complete Exchange flow * fix dependency issue * test: Final cleanups * feat: Add CI to run automated integration tests withan android emulator * feat: Adjust Automated integration test CI to run on ubuntu 20.04-a * fix: Move integration test CI into PR test build CI * ci: Add automated test ci which is a streamlined replica of pr test build ci * ci: Re-add step to access branch name * ci: Add KVM * ci: Add filepath to trigger the test run from * ci: Add required key * ci: Add required key * ci: Add missing secret key * ci: Add missing secret key * ci: Add nano secrets to workflow * ci: Switch step to free space on runner * ci: Remove timeout from workflow * ci: Confirm impact that removing copy_monero_deps would have on entire workflow time * ci: Update CI and temporarily remove cache related to emulator * ci: Remove dynamic java version * ci: Temporarily switch CI * ci: Switch to 11.x jdk * ci: Temporarily switch CI * ci: Revert ubuntu version * ci: Add more api levels * ci: Add more target options * ci: Settled on stable emulator matrix options * ci: Add more target options * ci: Modify flow * ci: Streamline api levels to 28 and 29 * ci: One more trial * ci: Switch to flutter drive * ci: Reduce options * ci: Remove haven from test * ci: Check for solana in list * ci: Adjust amounts and currencies for exchange flow * ci: Set write response on failure to true * ci: Split ci to funds and non funds related tests * test: Test for Send flow scenario and minor restructuring for test folders and files * chore: cleanup * ci: Pause CI for now * ci: Pause CI for now * ci: Pause CI for now * Fix: Add keys back to currency amount textfield widget * fix: Switch variable name * fix: remove automation for now * test: Updating send page robot and also syncing branch with main --------- Co-authored-by: OmarHatem <omarh.ismail1@gmail.com>
This commit is contained in:
co-authored by
OmarHatem
parent
32e119e24f
commit
4adb81c4dc
@@ -147,6 +147,7 @@ class _DashboardPageView extends BasePage {
|
||||
return Observer(
|
||||
builder: (context) {
|
||||
return ServicesUpdatesWidget(
|
||||
key: ValueKey('dashboard_page_services_update_button_key'),
|
||||
dashboardViewModel.getServicesStatus(),
|
||||
enabled: dashboardViewModel.isEnabledBulletinAction,
|
||||
);
|
||||
@@ -157,6 +158,7 @@ class _DashboardPageView extends BasePage {
|
||||
@override
|
||||
Widget middle(BuildContext context) {
|
||||
return SyncIndicator(
|
||||
key: ValueKey('dashboard_page_sync_indicator_button_key'),
|
||||
dashboardViewModel: dashboardViewModel,
|
||||
onTap: () => Navigator.of(context, rootNavigator: true).pushNamed(Routes.connectionSync),
|
||||
);
|
||||
@@ -173,6 +175,7 @@ class _DashboardPageView extends BasePage {
|
||||
alignment: Alignment.centerRight,
|
||||
width: 40,
|
||||
child: TextButton(
|
||||
key: ValueKey('dashboard_page_wallet_menu_button_key'),
|
||||
// FIX-ME: Style
|
||||
//highlightColor: Colors.transparent,
|
||||
//splashColor: Colors.transparent,
|
||||
@@ -226,6 +229,7 @@ class _DashboardPageView extends BasePage {
|
||||
child: Observer(
|
||||
builder: (context) {
|
||||
return PageView.builder(
|
||||
key: ValueKey('dashboard_page_view_key'),
|
||||
controller: controller,
|
||||
itemCount: pages.length,
|
||||
itemBuilder: (context, index) => pages[index],
|
||||
@@ -291,6 +295,8 @@ class _DashboardPageView extends BasePage {
|
||||
button: true,
|
||||
enabled: (action.isEnabled?.call(dashboardViewModel) ?? true),
|
||||
child: ActionButton(
|
||||
key: ValueKey(
|
||||
'dashboard_page_${action.name(context)}_action_button_key'),
|
||||
image: Image.asset(
|
||||
action.image,
|
||||
height: 24,
|
||||
|
||||
@@ -2,13 +2,15 @@ import 'package:flutter/material.dart';
|
||||
import 'package:cake_wallet/themes/extensions/dashboard_page_theme.dart';
|
||||
|
||||
class ActionButton extends StatelessWidget {
|
||||
ActionButton(
|
||||
{required this.image,
|
||||
required this.title,
|
||||
this.route,
|
||||
this.onClick,
|
||||
this.alignment = Alignment.center,
|
||||
this.textColor});
|
||||
ActionButton({
|
||||
required this.image,
|
||||
required this.title,
|
||||
this.route,
|
||||
this.onClick,
|
||||
this.alignment = Alignment.center,
|
||||
this.textColor,
|
||||
super.key,
|
||||
});
|
||||
|
||||
final Image image;
|
||||
final String title;
|
||||
|
||||
@@ -7,7 +7,11 @@ import 'package:cw_core/sync_status.dart';
|
||||
import 'package:cake_wallet/src/screens/dashboard/widgets/sync_indicator_icon.dart';
|
||||
|
||||
class SyncIndicator extends StatelessWidget {
|
||||
SyncIndicator({required this.dashboardViewModel, required this.onTap});
|
||||
SyncIndicator({
|
||||
required this.dashboardViewModel,
|
||||
required this.onTap,
|
||||
super.key,
|
||||
});
|
||||
|
||||
final DashboardViewModel dashboardViewModel;
|
||||
final Function() onTap;
|
||||
|
||||
@@ -207,6 +207,7 @@ class DisclaimerBodyState extends State<DisclaimerPageBody> {
|
||||
padding: EdgeInsets.only(
|
||||
left: 24.0, top: 10.0, right: 24.0, bottom: 10.0),
|
||||
child: InkWell(
|
||||
key: ValueKey('disclaimer_check_key'),
|
||||
onTap: () {
|
||||
setState(() {
|
||||
_checked = !_checked;
|
||||
@@ -230,6 +231,7 @@ class DisclaimerBodyState extends State<DisclaimerPageBody> {
|
||||
color: Theme.of(context).colorScheme.background),
|
||||
child: _checked
|
||||
? Icon(
|
||||
key: ValueKey('disclaimer_check_icon_key'),
|
||||
Icons.check,
|
||||
color: Colors.blue,
|
||||
size: 20.0,
|
||||
@@ -253,6 +255,7 @@ class DisclaimerBodyState extends State<DisclaimerPageBody> {
|
||||
padding:
|
||||
EdgeInsets.only(left: 24.0, right: 24.0, bottom: 24.0),
|
||||
child: PrimaryButton(
|
||||
key: ValueKey('disclaimer_accept_button_key'),
|
||||
onPressed: _checked
|
||||
? () => Navigator.of(context)
|
||||
.popAndPushNamed(Routes.welcome)
|
||||
|
||||
@@ -228,6 +228,7 @@ class ExchangePage extends BasePage {
|
||||
),
|
||||
Observer(
|
||||
builder: (_) => LoadingPrimaryButton(
|
||||
key: ValueKey('exchange_page_exchange_button_key'),
|
||||
text: S.of(context).exchange,
|
||||
onPressed: () {
|
||||
if (_formKey.currentState != null &&
|
||||
@@ -430,6 +431,8 @@ class ExchangePage extends BasePage {
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertWithOneAction(
|
||||
key: ValueKey('exchange_page_trade_creation_failure_dialog_key'),
|
||||
buttonKey: ValueKey('exchange_page_trade_creation_failure_dialog_button_key'),
|
||||
alertTitle: S.of(context).provider_error(state.title),
|
||||
alertContent: state.error,
|
||||
buttonText: S.of(context).ok,
|
||||
@@ -612,6 +615,7 @@ class ExchangePage extends BasePage {
|
||||
Widget _exchangeCardsSection(BuildContext context) {
|
||||
final firstExchangeCard = Observer(
|
||||
builder: (_) => ExchangeCard(
|
||||
cardInstanceName: 'deposit_exchange_card',
|
||||
onDispose: disposeBestRateSync,
|
||||
hasAllAmount: exchangeViewModel.hasAllAmount,
|
||||
allAmount: exchangeViewModel.hasAllAmount
|
||||
@@ -681,6 +685,7 @@ class ExchangePage extends BasePage {
|
||||
|
||||
final secondExchangeCard = Observer(
|
||||
builder: (_) => ExchangeCard(
|
||||
cardInstanceName: 'receive_exchange_card',
|
||||
onDispose: disposeBestRateSync,
|
||||
amountFocusNode: _receiveAmountFocus,
|
||||
addressFocusNode: _receiveAddressFocus,
|
||||
|
||||
@@ -121,6 +121,7 @@ class ExchangeTemplatePage extends BasePage {
|
||||
padding: EdgeInsets.fromLTRB(24, 100, 24, 32),
|
||||
child: Observer(
|
||||
builder: (_) => ExchangeCard(
|
||||
cardInstanceName: 'deposit_exchange_template_card',
|
||||
amountFocusNode: _depositAmountFocus,
|
||||
key: depositKey,
|
||||
title: S.of(context).you_will_send,
|
||||
@@ -157,6 +158,7 @@ class ExchangeTemplatePage extends BasePage {
|
||||
padding: EdgeInsets.only(top: 29, left: 24, right: 24),
|
||||
child: Observer(
|
||||
builder: (_) => ExchangeCard(
|
||||
cardInstanceName: 'receive_exchange_template_card',
|
||||
amountFocusNode: _receiveAmountFocus,
|
||||
key: receiveKey,
|
||||
title: S.of(context).you_will_get,
|
||||
|
||||
@@ -12,7 +12,8 @@ class CurrencyPicker extends StatefulWidget {
|
||||
this.title,
|
||||
this.hintText,
|
||||
this.isMoneroWallet = false,
|
||||
this.isConvertFrom = false});
|
||||
this.isConvertFrom = false,
|
||||
super.key});
|
||||
|
||||
final int selectedAtIndex;
|
||||
final List<Currency> items;
|
||||
|
||||
@@ -19,34 +19,35 @@ import 'package:cake_wallet/src/screens/exchange/widgets/currency_picker.dart';
|
||||
import 'package:cake_wallet/themes/extensions/send_page_theme.dart';
|
||||
|
||||
class ExchangeCard extends StatefulWidget {
|
||||
ExchangeCard(
|
||||
{Key? key,
|
||||
required this.initialCurrency,
|
||||
required this.initialAddress,
|
||||
required this.initialWalletName,
|
||||
required this.initialIsAmountEditable,
|
||||
required this.isAmountEstimated,
|
||||
required this.currencies,
|
||||
required this.onCurrencySelected,
|
||||
this.imageArrow,
|
||||
this.currencyValueValidator,
|
||||
this.addressTextFieldValidator,
|
||||
this.title = '',
|
||||
this.initialIsAddressEditable = true,
|
||||
this.hasRefundAddress = false,
|
||||
this.isMoneroWallet = false,
|
||||
this.currencyButtonColor = Colors.transparent,
|
||||
this.addressButtonsColor = Colors.transparent,
|
||||
this.borderColor = Colors.transparent,
|
||||
this.hasAllAmount = false,
|
||||
this.isAllAmountEnabled = false,
|
||||
this.amountFocusNode,
|
||||
this.addressFocusNode,
|
||||
this.allAmount,
|
||||
this.onPushPasteButton,
|
||||
this.onPushAddressBookButton,
|
||||
this.onDispose})
|
||||
: super(key: key);
|
||||
ExchangeCard({
|
||||
Key? key,
|
||||
required this.initialCurrency,
|
||||
required this.initialAddress,
|
||||
required this.initialWalletName,
|
||||
required this.initialIsAmountEditable,
|
||||
required this.isAmountEstimated,
|
||||
required this.currencies,
|
||||
required this.onCurrencySelected,
|
||||
this.imageArrow,
|
||||
this.currencyValueValidator,
|
||||
this.addressTextFieldValidator,
|
||||
this.title = '',
|
||||
this.initialIsAddressEditable = true,
|
||||
this.hasRefundAddress = false,
|
||||
this.isMoneroWallet = false,
|
||||
this.currencyButtonColor = Colors.transparent,
|
||||
this.addressButtonsColor = Colors.transparent,
|
||||
this.borderColor = Colors.transparent,
|
||||
this.hasAllAmount = false,
|
||||
this.isAllAmountEnabled = false,
|
||||
this.amountFocusNode,
|
||||
this.addressFocusNode,
|
||||
this.allAmount,
|
||||
this.onPushPasteButton,
|
||||
this.onPushAddressBookButton,
|
||||
this.onDispose,
|
||||
required this.cardInstanceName,
|
||||
}) : super(key: key);
|
||||
|
||||
final List<CryptoCurrency> currencies;
|
||||
final Function(CryptoCurrency) onCurrencySelected;
|
||||
@@ -74,6 +75,7 @@ class ExchangeCard extends StatefulWidget {
|
||||
final void Function(BuildContext context)? onPushPasteButton;
|
||||
final void Function(BuildContext context)? onPushAddressBookButton;
|
||||
final Function()? onDispose;
|
||||
final String cardInstanceName;
|
||||
|
||||
@override
|
||||
ExchangeCardState createState() => ExchangeCardState();
|
||||
@@ -89,11 +91,13 @@ class ExchangeCardState extends State<ExchangeCard> {
|
||||
_walletName = '',
|
||||
_selectedCurrency = CryptoCurrency.btc,
|
||||
_isAmountEstimated = false,
|
||||
_isMoneroWallet = false;
|
||||
_isMoneroWallet = false,
|
||||
_cardInstanceName = '';
|
||||
|
||||
final addressController = TextEditingController();
|
||||
final amountController = TextEditingController();
|
||||
|
||||
String _cardInstanceName;
|
||||
String _title;
|
||||
String? _min;
|
||||
String? _max;
|
||||
@@ -106,6 +110,7 @@ class ExchangeCardState extends State<ExchangeCard> {
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
_cardInstanceName = widget.cardInstanceName;
|
||||
_title = widget.title;
|
||||
_isAmountEditable = widget.initialIsAmountEditable;
|
||||
_isAddressEditable = widget.initialIsAddressEditable;
|
||||
@@ -184,6 +189,7 @@ class ExchangeCardState extends State<ExchangeCard> {
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Text(
|
||||
key: ValueKey('${_cardInstanceName}_title_key'),
|
||||
_title,
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
@@ -193,17 +199,26 @@ class ExchangeCardState extends State<ExchangeCard> {
|
||||
],
|
||||
),
|
||||
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),
|
||||
currencyPickerButtonKey: ValueKey('${_cardInstanceName}_currency_picker_button_key'),
|
||||
selectedCurrencyTextKey: ValueKey('${_cardInstanceName}_selected_currency_text_key'),
|
||||
selectedCurrencyTagTextKey:
|
||||
ValueKey('${_cardInstanceName}_selected_currency_tag_text_key'),
|
||||
amountTextfieldKey: ValueKey('${_cardInstanceName}_amount_textfield_key'),
|
||||
sendAllButtonKey: ValueKey('${_cardInstanceName}_send_all_button_key'),
|
||||
currencyAmountTextFieldWidgetKey:
|
||||
ValueKey('${_cardInstanceName}_currency_amount_textfield_widget_key'),
|
||||
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),
|
||||
@@ -212,6 +227,7 @@ class ExchangeCardState extends State<ExchangeCard> {
|
||||
child: Row(mainAxisAlignment: MainAxisAlignment.start, children: <Widget>[
|
||||
_min != null
|
||||
? Text(
|
||||
key: ValueKey('${_cardInstanceName}_min_limit_text_key'),
|
||||
S.of(context).min_value(_min ?? '', _selectedCurrency.toString()),
|
||||
style: TextStyle(
|
||||
fontSize: 10,
|
||||
@@ -221,11 +237,15 @@ class ExchangeCardState extends State<ExchangeCard> {
|
||||
: Offstage(),
|
||||
_min != null ? SizedBox(width: 10) : Offstage(),
|
||||
_max != null
|
||||
? Text(S.of(context).max_value(_max ?? '', _selectedCurrency.toString()),
|
||||
? Text(
|
||||
key: ValueKey('${_cardInstanceName}_max_limit_text_key'),
|
||||
S.of(context).max_value(_max ?? '', _selectedCurrency.toString()),
|
||||
style: TextStyle(
|
||||
fontSize: 10,
|
||||
height: 1.2,
|
||||
color: Theme.of(context).extension<ExchangePageTheme>()!.hintTextColor))
|
||||
fontSize: 10,
|
||||
height: 1.2,
|
||||
color: Theme.of(context).extension<ExchangePageTheme>()!.hintTextColor,
|
||||
),
|
||||
)
|
||||
: Offstage(),
|
||||
])),
|
||||
),
|
||||
@@ -246,6 +266,7 @@ class ExchangeCardState extends State<ExchangeCard> {
|
||||
child: Padding(
|
||||
padding: EdgeInsets.only(top: 20),
|
||||
child: AddressTextField(
|
||||
addressKey: ValueKey('${_cardInstanceName}_editable_address_textfield_key'),
|
||||
focusNode: widget.addressFocusNode,
|
||||
controller: addressController,
|
||||
onURIScanned: (uri) {
|
||||
@@ -286,6 +307,8 @@ class ExchangeCardState extends State<ExchangeCard> {
|
||||
FocusTraversalOrder(
|
||||
order: NumericFocusOrder(3),
|
||||
child: BaseTextFormField(
|
||||
key: ValueKey(
|
||||
'${_cardInstanceName}_non_editable_address_textfield_key'),
|
||||
controller: addressController,
|
||||
borderColor: Colors.transparent,
|
||||
suffixIcon: SizedBox(width: _isMoneroWallet ? 80 : 36),
|
||||
@@ -309,6 +332,8 @@ class ExchangeCardState extends State<ExchangeCard> {
|
||||
child: Semantics(
|
||||
label: S.of(context).address_book,
|
||||
child: InkWell(
|
||||
key: ValueKey(
|
||||
'${_cardInstanceName}_address_book_button_key'),
|
||||
onTap: () async {
|
||||
final contact =
|
||||
await Navigator.of(context).pushNamed(
|
||||
@@ -346,6 +371,8 @@ class ExchangeCardState extends State<ExchangeCard> {
|
||||
child: Semantics(
|
||||
label: S.of(context).copy_address,
|
||||
child: InkWell(
|
||||
key: ValueKey(
|
||||
'${_cardInstanceName}_copy_refund_address_button_key'),
|
||||
onTap: () {
|
||||
Clipboard.setData(
|
||||
ClipboardData(text: addressController.text));
|
||||
@@ -369,6 +396,7 @@ class ExchangeCardState extends State<ExchangeCard> {
|
||||
showPopUp<void>(
|
||||
context: context,
|
||||
builder: (_) => CurrencyPicker(
|
||||
key: ValueKey('${_cardInstanceName}_currency_picker_dialog_button_key'),
|
||||
selectedAtIndex: widget.currencies.indexOf(_selectedCurrency),
|
||||
items: widget.currencies,
|
||||
hintText: S.of(context).search_currency,
|
||||
|
||||
@@ -83,6 +83,7 @@ class ExchangeConfirmPage extends BasePage {
|
||||
padding: EdgeInsets.fromLTRB(10, 0, 10, 10),
|
||||
child: Builder(
|
||||
builder: (context) => PrimaryButton(
|
||||
key: ValueKey('exchange_confirm_page_copy_to_clipboard_button_key'),
|
||||
onPressed: () {
|
||||
Clipboard.setData(ClipboardData(text: trade.id));
|
||||
showBar<void>(
|
||||
@@ -117,6 +118,7 @@ class ExchangeConfirmPage extends BasePage {
|
||||
],
|
||||
)),
|
||||
PrimaryButton(
|
||||
key: ValueKey('exchange_confirm_page_saved_id_button_key'),
|
||||
onPressed: () => Navigator.of(context)
|
||||
.pushReplacementNamed(Routes.exchangeTrade),
|
||||
text: S.of(context).saved_the_trade_id,
|
||||
|
||||
@@ -39,7 +39,9 @@ void showInformation(
|
||||
|
||||
showPopUp<void>(
|
||||
context: context,
|
||||
builder: (_) => InformationPage(information: information));
|
||||
builder: (_) => InformationPage(
|
||||
key: ValueKey('information_page_dialog_key'),
|
||||
information: information));
|
||||
}
|
||||
|
||||
class ExchangeTradePage extends BasePage {
|
||||
@@ -215,6 +217,7 @@ class ExchangeTradeState extends State<ExchangeTradeForm> {
|
||||
return widget.exchangeTradeViewModel.isSendable &&
|
||||
!(sendingState is TransactionCommitted)
|
||||
? LoadingPrimaryButton(
|
||||
key: ValueKey('exchange_trade_page_confirm_sending_button_key'),
|
||||
isDisabled: trade.inputAddress == null ||
|
||||
trade.inputAddress!.isEmpty,
|
||||
isLoading: sendingState is IsExecutingState,
|
||||
@@ -241,6 +244,8 @@ class ExchangeTradeState extends State<ExchangeTradeForm> {
|
||||
context: context,
|
||||
builder: (BuildContext popupContext) {
|
||||
return AlertWithOneAction(
|
||||
key: ValueKey('exchange_trade_page_send_failure_dialog_key'),
|
||||
buttonKey: ValueKey('exchange_trade_page_send_failure_dialog_button_key'),
|
||||
alertTitle: S.of(popupContext).error,
|
||||
alertContent: state.error,
|
||||
buttonText: S.of(popupContext).ok,
|
||||
@@ -255,6 +260,10 @@ class ExchangeTradeState extends State<ExchangeTradeForm> {
|
||||
context: context,
|
||||
builder: (BuildContext popupContext) {
|
||||
return ConfirmSendingAlert(
|
||||
key: ValueKey('exchange_trade_page_confirm_sending_dialog_key'),
|
||||
alertLeftActionButtonKey: ValueKey('exchange_trade_page_confirm_sending_dialog_cancel_button_key'),
|
||||
alertRightActionButtonKey:
|
||||
ValueKey('exchange_trade_page_confirm_sending_dialog_send_button_key'),
|
||||
alertTitle: S.of(popupContext).confirm_sending,
|
||||
amount: S.of(popupContext).send_amount,
|
||||
amountValue: widget.exchangeTradeViewModel.sendViewModel
|
||||
|
||||
@@ -10,7 +10,7 @@ import 'package:cake_wallet/src/widgets/alert_background.dart';
|
||||
import 'package:cake_wallet/themes/extensions/menu_theme.dart';
|
||||
|
||||
class InformationPage extends StatelessWidget {
|
||||
InformationPage({required this.information});
|
||||
InformationPage({required this.information, super.key});
|
||||
|
||||
final String information;
|
||||
|
||||
@@ -47,6 +47,7 @@ class InformationPage extends StatelessWidget {
|
||||
Padding(
|
||||
padding: EdgeInsets.fromLTRB(10, 0, 10, 10),
|
||||
child: PrimaryButton(
|
||||
key: ValueKey('information_page_got_it_button_key'),
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
text: S.of(context).got_it,
|
||||
color: Theme.of(context).extension<ExchangePageTheme>()!.buttonBackgroundColor,
|
||||
|
||||
@@ -131,6 +131,7 @@ class WalletTypeFormState extends State<WalletTypeForm> {
|
||||
Expanded(
|
||||
child: ScrollableWithBottomSection(
|
||||
contentPadding: EdgeInsets.only(left: 24, right: 24, bottom: 24),
|
||||
scrollableKey: ValueKey('new_wallet_type_scrollable_key'),
|
||||
content: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
@@ -138,6 +139,7 @@ class WalletTypeFormState extends State<WalletTypeForm> {
|
||||
(type) => Padding(
|
||||
padding: EdgeInsets.only(top: 12),
|
||||
child: SelectButton(
|
||||
key: ValueKey('new_wallet_type_${type.name}_button_key'),
|
||||
image: Image.asset(
|
||||
walletTypeToCryptoCurrency(type).iconPath ?? '',
|
||||
height: 24,
|
||||
@@ -158,6 +160,7 @@ class WalletTypeFormState extends State<WalletTypeForm> {
|
||||
),
|
||||
bottomSectionPadding: EdgeInsets.only(left: 24, right: 24, bottom: 24),
|
||||
bottomSection: PrimaryButton(
|
||||
key: ValueKey('new_wallet_type_next_button_key'),
|
||||
onPressed: () => onTypeSelected(),
|
||||
text: S.of(context).seed_language_next,
|
||||
color: Theme.of(context).primaryColor,
|
||||
|
||||
@@ -20,6 +20,7 @@ class SelectButton extends StatelessWidget {
|
||||
this.deviceConnectionTypes,
|
||||
this.borderRadius,
|
||||
this.padding,
|
||||
super.key,
|
||||
});
|
||||
|
||||
final Widget? image;
|
||||
|
||||
@@ -240,6 +240,7 @@ class PinCodeState<T extends PinCodeWidget> extends State<T> {
|
||||
return Container(
|
||||
margin: EdgeInsets.only(left: marginLeft, right: marginRight),
|
||||
child: TextButton(
|
||||
key: ValueKey('pin_code_button_${index}_key'),
|
||||
onPressed: () => _push(index),
|
||||
style: TextButton.styleFrom(
|
||||
backgroundColor: Theme.of(context).colorScheme.background,
|
||||
|
||||
@@ -24,8 +24,20 @@ class CurrencyAmountTextField extends StatelessWidget {
|
||||
this.tagBackgroundColor,
|
||||
this.currencyValueValidator,
|
||||
this.allAmountCallback,
|
||||
});
|
||||
this.sendAllButtonKey,
|
||||
this.amountTextfieldKey,
|
||||
this.currencyPickerButtonKey,
|
||||
this.selectedCurrencyTextKey,
|
||||
this.selectedCurrencyTagTextKey,
|
||||
this.currencyAmountTextFieldWidgetKey,
|
||||
}) : super(key: currencyAmountTextFieldWidgetKey);
|
||||
|
||||
final Key? sendAllButtonKey;
|
||||
final Key? amountTextfieldKey;
|
||||
final Key? currencyPickerButtonKey;
|
||||
final Key? selectedCurrencyTextKey;
|
||||
final Key? selectedCurrencyTagTextKey;
|
||||
final Key? currencyAmountTextFieldWidgetKey;
|
||||
final Widget? imageArrow;
|
||||
final String selectedCurrency;
|
||||
final String? tag;
|
||||
@@ -54,6 +66,7 @@ class CurrencyAmountTextField extends StatelessWidget {
|
||||
? Container(
|
||||
height: 32,
|
||||
child: InkWell(
|
||||
key: currencyPickerButtonKey,
|
||||
onTap: onTapPicker,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
@@ -65,6 +78,7 @@ class CurrencyAmountTextField extends StatelessWidget {
|
||||
Image.asset('assets/images/arrow_bottom_purple_icon.png',
|
||||
color: textColor, height: 8)),
|
||||
Text(
|
||||
key: selectedCurrencyTextKey,
|
||||
selectedCurrency,
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.w600,
|
||||
@@ -77,6 +91,7 @@ class CurrencyAmountTextField extends StatelessWidget {
|
||||
),
|
||||
)
|
||||
: Text(
|
||||
key: selectedCurrencyTextKey,
|
||||
selectedCurrency,
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.w600,
|
||||
@@ -98,6 +113,7 @@ class CurrencyAmountTextField extends StatelessWidget {
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(6.0),
|
||||
child: Text(
|
||||
key: selectedCurrencyTagTextKey,
|
||||
tag!,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
@@ -132,9 +148,9 @@ class CurrencyAmountTextField extends StatelessWidget {
|
||||
padding: EdgeInsets.symmetric(vertical: 4, horizontal: 8),
|
||||
margin: const EdgeInsets.only(right: 3),
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(
|
||||
color: textColor,
|
||||
),
|
||||
border: Border.all(
|
||||
color: textColor,
|
||||
),
|
||||
borderRadius: BorderRadius.circular(26),
|
||||
color: Theme.of(context).primaryColor))
|
||||
: _prefixContent,
|
||||
@@ -146,6 +162,7 @@ class CurrencyAmountTextField extends StatelessWidget {
|
||||
child: FocusTraversalOrder(
|
||||
order: NumericFocusOrder(1),
|
||||
child: BaseTextFormField(
|
||||
key: amountTextfieldKey,
|
||||
focusNode: amountFocusNode,
|
||||
controller: amountController,
|
||||
enabled: isAmountEditable,
|
||||
@@ -184,6 +201,7 @@ class CurrencyAmountTextField extends StatelessWidget {
|
||||
borderRadius: const BorderRadius.all(Radius.circular(6)),
|
||||
),
|
||||
child: InkWell(
|
||||
key: sendAllButtonKey,
|
||||
onTap: allAmountCallback,
|
||||
child: Center(
|
||||
child: Text(
|
||||
|
||||
@@ -59,8 +59,12 @@ class RestoreOptionsPage extends BasePage {
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
OptionTile(
|
||||
onPressed: () => Navigator.pushNamed(context, Routes.restoreWalletFromSeedKeys,
|
||||
arguments: isNewInstall),
|
||||
key: ValueKey('restore_options_from_seeds_button_key'),
|
||||
onPressed: () => Navigator.pushNamed(
|
||||
context,
|
||||
Routes.restoreWalletFromSeedKeys,
|
||||
arguments: isNewInstall,
|
||||
),
|
||||
image: imageSeedKeys,
|
||||
title: S.of(context).restore_title_from_seed_keys,
|
||||
description: S.of(context).restore_description_from_seed_keys,
|
||||
@@ -69,6 +73,7 @@ class RestoreOptionsPage extends BasePage {
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 24),
|
||||
child: OptionTile(
|
||||
key: ValueKey('restore_options_from_backup_button_key'),
|
||||
onPressed: () => Navigator.pushNamed(context, Routes.restoreFromBackup),
|
||||
image: imageBackup,
|
||||
title: S.of(context).restore_title_from_backup,
|
||||
@@ -79,6 +84,7 @@ class RestoreOptionsPage extends BasePage {
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 24),
|
||||
child: OptionTile(
|
||||
key: ValueKey('restore_options_from_hardware_wallet_button_key'),
|
||||
onPressed: () => Navigator.pushNamed(
|
||||
context, Routes.restoreWalletFromHardwareWallet,
|
||||
arguments: isNewInstall),
|
||||
@@ -90,10 +96,12 @@ class RestoreOptionsPage extends BasePage {
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 24),
|
||||
child: OptionTile(
|
||||
onPressed: () => _onScanQRCode(context),
|
||||
image: qrCode,
|
||||
title: S.of(context).scan_qr_code,
|
||||
description: S.of(context).cold_or_recover_wallet),
|
||||
key: ValueKey('restore_options_from_qr_button_key'),
|
||||
onPressed: () => _onScanQRCode(context),
|
||||
image: qrCode,
|
||||
title: S.of(context).scan_qr_code,
|
||||
description: S.of(context).cold_or_recover_wallet,
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
|
||||
@@ -112,10 +112,12 @@ class WalletRestoreFromKeysFromState extends State<WalletRestoreFromKeysFrom> {
|
||||
alignment: Alignment.centerRight,
|
||||
children: [
|
||||
BaseTextFormField(
|
||||
key: ValueKey('wallet_restore_from_keys_wallet_name_textfield_key'),
|
||||
controller: nameTextEditingController,
|
||||
hintText: S.of(context).wallet_name,
|
||||
validator: WalletNameValidator(),
|
||||
suffixIcon: IconButton(
|
||||
key: ValueKey('wallet_restore_from_keys_wallet_name_refresh_button_key'),
|
||||
onPressed: () async {
|
||||
final rName = await generateName();
|
||||
FocusManager.instance.primaryFocus?.unfocus();
|
||||
@@ -175,6 +177,7 @@ class WalletRestoreFromKeysFromState extends State<WalletRestoreFromKeysFrom> {
|
||||
bool nanoBased = widget.walletRestoreViewModel.type == WalletType.nano ||
|
||||
widget.walletRestoreViewModel.type == WalletType.banano;
|
||||
return AddressTextField(
|
||||
addressKey: ValueKey('wallet_restore_from_key_private_key_textfield_key'),
|
||||
controller: privateKeyController,
|
||||
placeholder: nanoBased ? S.of(context).seed_hex_form : S.of(context).private_key,
|
||||
options: [AddressTextFieldOption.paste],
|
||||
|
||||
@@ -151,11 +151,13 @@ class WalletRestoreFromSeedFormState extends State<WalletRestoreFromSeedForm> {
|
||||
alignment: Alignment.centerRight,
|
||||
children: [
|
||||
BaseTextFormField(
|
||||
key: ValueKey('wallet_restore_from_seed_wallet_name_textfield_key'),
|
||||
controller: nameTextEditingController,
|
||||
hintText: S
|
||||
.of(context)
|
||||
.wallet_name,
|
||||
suffixIcon: IconButton(
|
||||
key: ValueKey('wallet_restore_from_seed_wallet_name_refresh_button_key'),
|
||||
onPressed: () async {
|
||||
final rName = await generateName();
|
||||
FocusManager.instance.primaryFocus?.unfocus();
|
||||
@@ -190,10 +192,13 @@ class WalletRestoreFromSeedFormState extends State<WalletRestoreFromSeedForm> {
|
||||
)),
|
||||
Container(height: 20),
|
||||
SeedWidget(
|
||||
key: seedWidgetStateKey,
|
||||
language: language,
|
||||
type: widget.type,
|
||||
onSeedChange: onSeedChange),
|
||||
key: seedWidgetStateKey,
|
||||
language: language,
|
||||
type: widget.type,
|
||||
onSeedChange: onSeedChange,
|
||||
seedTextFieldKey: ValueKey('wallet_restore_from_seed_wallet_seeds_textfield_key'),
|
||||
pasteButtonKey: ValueKey('wallet_restore_from_seed_wallet_seeds_paste_button_key'),
|
||||
),
|
||||
if (widget.type == WalletType.monero || widget.type == WalletType.wownero)
|
||||
GestureDetector(
|
||||
onTap: () async {
|
||||
|
||||
@@ -213,6 +213,7 @@ class WalletRestorePage extends BasePage {
|
||||
Observer(
|
||||
builder: (context) {
|
||||
return LoadingPrimaryButton(
|
||||
key: ValueKey('wallet_restore_seed_or_key_restore_button_key'),
|
||||
onPressed: () async {
|
||||
await _confirmForm(context);
|
||||
},
|
||||
@@ -230,6 +231,7 @@ class WalletRestorePage extends BasePage {
|
||||
),
|
||||
const SizedBox(height: 25),
|
||||
GestureDetector(
|
||||
key: ValueKey('wallet_restore_advanced_settings_button_key'),
|
||||
onTap: () {
|
||||
Navigator.of(context)
|
||||
.pushNamed(Routes.advancedPrivacySettings, arguments: {
|
||||
|
||||
@@ -250,6 +250,7 @@ class SendPage extends BasePage {
|
||||
return Row(
|
||||
children: <Widget>[
|
||||
AddTemplateButton(
|
||||
key: ValueKey('send_page_add_template_button_key'),
|
||||
onTap: () => Navigator.of(context).pushNamed(Routes.sendTemplate),
|
||||
currentTemplatesLength: templates.length,
|
||||
),
|
||||
@@ -339,19 +340,22 @@ class SendPage extends BasePage {
|
||||
children: [
|
||||
if (sendViewModel.hasCurrecyChanger)
|
||||
Observer(
|
||||
builder: (_) => Padding(
|
||||
padding: EdgeInsets.only(bottom: 12),
|
||||
child: PrimaryButton(
|
||||
onPressed: () => presentCurrencyPicker(context),
|
||||
text: 'Change your asset (${sendViewModel.selectedCryptoCurrency})',
|
||||
color: Colors.transparent,
|
||||
textColor:
|
||||
Theme.of(context).extension<SeedWidgetTheme>()!.hintTextColor,
|
||||
))),
|
||||
builder: (_) => Padding(
|
||||
padding: EdgeInsets.only(bottom: 12),
|
||||
child: PrimaryButton(
|
||||
key: ValueKey('send_page_change_asset_button_key'),
|
||||
onPressed: () => presentCurrencyPicker(context),
|
||||
text: 'Change your asset (${sendViewModel.selectedCryptoCurrency})',
|
||||
color: Colors.transparent,
|
||||
textColor: Theme.of(context).extension<SeedWidgetTheme>()!.hintTextColor,
|
||||
),
|
||||
),
|
||||
),
|
||||
if (sendViewModel.sendTemplateViewModel.hasMultiRecipient)
|
||||
Padding(
|
||||
padding: EdgeInsets.only(bottom: 12),
|
||||
child: PrimaryButton(
|
||||
key: ValueKey('send_page_add_receiver_button_key'),
|
||||
onPressed: () {
|
||||
sendViewModel.addOutput();
|
||||
Future.delayed(const Duration(milliseconds: 250), () {
|
||||
@@ -368,6 +372,7 @@ class SendPage extends BasePage {
|
||||
Observer(
|
||||
builder: (_) {
|
||||
return LoadingPrimaryButton(
|
||||
key: ValueKey('send_page_send_button_key'),
|
||||
onPressed: () async {
|
||||
if (sendViewModel.state is IsExecutingState) return;
|
||||
if (_formKey.currentState != null && !_formKey.currentState!.validate()) {
|
||||
@@ -451,6 +456,8 @@ class SendPage extends BasePage {
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertWithOneAction(
|
||||
key: ValueKey('send_page_send_failure_dialog_key'),
|
||||
buttonKey: ValueKey('send_page_send_failure_dialog_button_key'),
|
||||
alertTitle: S.of(context).error,
|
||||
alertContent: state.error,
|
||||
buttonText: S.of(context).ok,
|
||||
@@ -466,6 +473,7 @@ class SendPage extends BasePage {
|
||||
context: context,
|
||||
builder: (BuildContext _dialogContext) {
|
||||
return ConfirmSendingAlert(
|
||||
key: ValueKey('send_page_confirm_sending_dialog_key'),
|
||||
alertTitle: S.of(_dialogContext).confirm_sending,
|
||||
amount: S.of(_dialogContext).send_amount,
|
||||
amountValue: sendViewModel.pendingTransaction!.amountFormatted,
|
||||
@@ -480,6 +488,10 @@ class SendPage extends BasePage {
|
||||
change: sendViewModel.pendingTransaction!.change,
|
||||
rightButtonText: S.of(_dialogContext).send,
|
||||
leftButtonText: S.of(_dialogContext).cancel,
|
||||
alertRightActionButtonKey:
|
||||
ValueKey('send_page_confirm_sending_dialog_send_button_key'),
|
||||
alertLeftActionButtonKey:
|
||||
ValueKey('send_page_confirm_sending_dialog_cancel_button_key'),
|
||||
actionRightButton: () async {
|
||||
Navigator.of(_dialogContext).pop();
|
||||
sendViewModel.commitTransaction();
|
||||
@@ -513,10 +525,15 @@ class SendPage extends BasePage {
|
||||
|
||||
if (newContactAddress != null) {
|
||||
return AlertWithTwoActions(
|
||||
alertDialogKey: ValueKey('send_page_sent_dialog_key'),
|
||||
alertTitle: '',
|
||||
alertContent: alertContent,
|
||||
rightButtonText: S.of(_dialogContext).add_contact,
|
||||
leftButtonText: S.of(_dialogContext).ignor,
|
||||
alertLeftActionButtonKey:
|
||||
ValueKey('send_page_sent_dialog_ignore_button_key'),
|
||||
alertRightActionButtonKey: ValueKey(
|
||||
'send_page_sent_dialog_add_contact_button_key'),
|
||||
actionRightButton: () {
|
||||
Navigator.of(_dialogContext).pop();
|
||||
RequestReviewHandler.requestReview();
|
||||
|
||||
@@ -9,30 +9,34 @@ import 'package:cake_wallet/src/widgets/cake_scrollbar.dart';
|
||||
import 'package:flutter/scheduler.dart';
|
||||
|
||||
class ConfirmSendingAlert extends BaseAlertDialog {
|
||||
ConfirmSendingAlert(
|
||||
{required this.alertTitle,
|
||||
this.paymentId,
|
||||
this.paymentIdValue,
|
||||
this.expirationTime,
|
||||
required this.amount,
|
||||
required this.amountValue,
|
||||
required this.fiatAmountValue,
|
||||
required this.fee,
|
||||
this.feeRate,
|
||||
required this.feeValue,
|
||||
required this.feeFiatAmount,
|
||||
required this.outputs,
|
||||
this.change,
|
||||
required this.leftButtonText,
|
||||
required this.rightButtonText,
|
||||
required this.actionLeftButton,
|
||||
required this.actionRightButton,
|
||||
this.alertBarrierDismissible = true,
|
||||
this.alertLeftActionButtonTextColor,
|
||||
this.alertRightActionButtonTextColor,
|
||||
this.alertLeftActionButtonColor,
|
||||
this.alertRightActionButtonColor,
|
||||
this.onDispose});
|
||||
ConfirmSendingAlert({
|
||||
required this.alertTitle,
|
||||
this.paymentId,
|
||||
this.paymentIdValue,
|
||||
this.expirationTime,
|
||||
required this.amount,
|
||||
required this.amountValue,
|
||||
required this.fiatAmountValue,
|
||||
required this.fee,
|
||||
this.feeRate,
|
||||
required this.feeValue,
|
||||
required this.feeFiatAmount,
|
||||
required this.outputs,
|
||||
this.change,
|
||||
required this.leftButtonText,
|
||||
required this.rightButtonText,
|
||||
required this.actionLeftButton,
|
||||
required this.actionRightButton,
|
||||
this.alertBarrierDismissible = true,
|
||||
this.alertLeftActionButtonTextColor,
|
||||
this.alertRightActionButtonTextColor,
|
||||
this.alertLeftActionButtonColor,
|
||||
this.alertRightActionButtonColor,
|
||||
this.onDispose,
|
||||
this.alertLeftActionButtonKey,
|
||||
this.alertRightActionButtonKey,
|
||||
Key? key,
|
||||
});
|
||||
|
||||
final String alertTitle;
|
||||
final String? paymentId;
|
||||
@@ -57,6 +61,8 @@ class ConfirmSendingAlert extends BaseAlertDialog {
|
||||
final Color? alertLeftActionButtonColor;
|
||||
final Color? alertRightActionButtonColor;
|
||||
final Function? onDispose;
|
||||
final Key? alertRightActionButtonKey;
|
||||
final Key? alertLeftActionButtonKey;
|
||||
|
||||
@override
|
||||
String get titleText => alertTitle;
|
||||
@@ -91,6 +97,12 @@ class ConfirmSendingAlert extends BaseAlertDialog {
|
||||
@override
|
||||
Color? get rightActionButtonColor => alertRightActionButtonColor;
|
||||
|
||||
@override
|
||||
Key? get leftActionButtonKey => alertLeftActionButtonKey;
|
||||
|
||||
@override
|
||||
Key? get rightActionButtonKey => alertLeftActionButtonKey;
|
||||
|
||||
@override
|
||||
Widget content(BuildContext context) => ConfirmSendingAlertContent(
|
||||
paymentId: paymentId,
|
||||
@@ -288,6 +300,7 @@ class ConfirmSendingAlertContentState extends State<ConfirmSendingAlertContent>
|
||||
crossAxisAlignment: CrossAxisAlignment.end,
|
||||
children: [
|
||||
Text(
|
||||
key: ValueKey('confirm_sending_dialog_amount_text_value_key'),
|
||||
amountValue,
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
|
||||
@@ -158,6 +158,7 @@ class SendCardState extends State<SendCard> with AutomaticKeepAliveClientMixin<S
|
||||
: sendViewModel.addressValidator;
|
||||
|
||||
return AddressTextField(
|
||||
addressKey: ValueKey('send_page_address_textfield_key'),
|
||||
focusNode: addressFocusNode,
|
||||
controller: addressController,
|
||||
onURIScanned: (uri) {
|
||||
@@ -209,6 +210,11 @@ class SendCardState extends State<SendCard> with AutomaticKeepAliveClientMixin<S
|
||||
fontSize: 14, fontWeight: FontWeight.w500, color: Colors.white),
|
||||
validator: sendViewModel.addressValidator)),
|
||||
CurrencyAmountTextField(
|
||||
currencyPickerButtonKey: ValueKey('send_page_currency_picker_button_key'),
|
||||
amountTextfieldKey: ValueKey('send_page_amount_textfield_key'),
|
||||
sendAllButtonKey: ValueKey('send_page_send_all_button_key'),
|
||||
currencyAmountTextFieldWidgetKey:
|
||||
ValueKey('send_page_crypto_currency_amount_textfield_widget_key'),
|
||||
selectedCurrency: sendViewModel.selectedCryptoCurrency.title,
|
||||
amountFocusNode: cryptoAmountFocus,
|
||||
amountController: cryptoAmountController,
|
||||
@@ -216,7 +222,8 @@ class SendCardState extends State<SendCard> with AutomaticKeepAliveClientMixin<S
|
||||
onTapPicker: () => _presentPicker(context),
|
||||
isPickerEnable: sendViewModel.hasMultipleTokens,
|
||||
tag: sendViewModel.selectedCryptoCurrency.tag,
|
||||
allAmountButton: !sendViewModel.isBatchSending && sendViewModel.shouldDisplaySendALL,
|
||||
allAmountButton:
|
||||
!sendViewModel.isBatchSending && sendViewModel.shouldDisplaySendALL,
|
||||
currencyValueValidator: output.sendAll
|
||||
? sendViewModel.allAmountValidator
|
||||
: sendViewModel.amountValidator,
|
||||
@@ -257,6 +264,9 @@ class SendCardState extends State<SendCard> with AutomaticKeepAliveClientMixin<S
|
||||
),
|
||||
if (!sendViewModel.isFiatDisabled)
|
||||
CurrencyAmountTextField(
|
||||
amountTextfieldKey: ValueKey('send_page_fiat_amount_textfield_key'),
|
||||
currencyAmountTextFieldWidgetKey:
|
||||
ValueKey('send_page_fiat_currency_amount_textfield_widget_key'),
|
||||
selectedCurrency: sendViewModel.fiat.title,
|
||||
amountFocusNode: fiatAmountFocus,
|
||||
amountController: fiatAmountController,
|
||||
@@ -269,6 +279,7 @@ class SendCardState extends State<SendCard> with AutomaticKeepAliveClientMixin<S
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 20),
|
||||
child: BaseTextFormField(
|
||||
key: ValueKey('send_page_note_textfield_key'),
|
||||
controller: noteController,
|
||||
keyboardType: TextInputType.multiline,
|
||||
maxLines: null,
|
||||
@@ -287,6 +298,7 @@ class SendCardState extends State<SendCard> with AutomaticKeepAliveClientMixin<S
|
||||
if (sendViewModel.hasFees)
|
||||
Observer(
|
||||
builder: (_) => GestureDetector(
|
||||
key: ValueKey('send_page_select_fee_priority_button_key'),
|
||||
onTap: sendViewModel.hasFeesPriority
|
||||
? () => pickTransactionPriority(context)
|
||||
: () {},
|
||||
@@ -360,6 +372,7 @@ class SendCardState extends State<SendCard> with AutomaticKeepAliveClientMixin<S
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 6),
|
||||
child: GestureDetector(
|
||||
key: ValueKey('send_page_unspent_coin_button_key'),
|
||||
onTap: () => Navigator.of(context).pushNamed(Routes.unspentCoinsList),
|
||||
child: Container(
|
||||
color: Colors.transparent,
|
||||
@@ -544,11 +557,13 @@ 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)),
|
||||
key: ValueKey('send_page_currency_picker_dialog_button_key'),
|
||||
selectedAtIndex: sendViewModel.currencies.indexOf(sendViewModel.selectedCryptoCurrency),
|
||||
items: sendViewModel.currencies,
|
||||
hintText: S.of(context).search_currency,
|
||||
onItemSelected: (Currency cur) =>
|
||||
sendViewModel.selectedCryptoCurrency = (cur as CryptoCurrency),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -52,6 +52,7 @@ class SetupPinCodePage extends BasePage {
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertWithOneAction(
|
||||
buttonKey: ValueKey('setup_pin_code_success_button_key'),
|
||||
alertTitle: S.current.setup_pin,
|
||||
alertContent: S.of(context).setup_successful,
|
||||
buttonText: S.of(context).ok,
|
||||
|
||||
@@ -133,6 +133,7 @@ class WelcomePage extends BasePage {
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 24),
|
||||
child: PrimaryImageButton(
|
||||
key: ValueKey('welcome_page_create_new_wallet_button_key'),
|
||||
onPressed: () => Navigator.pushNamed(context, Routes.newWalletFromWelcome),
|
||||
image: newWalletImage,
|
||||
text: S.of(context).create_new,
|
||||
@@ -146,6 +147,7 @@ class WelcomePage extends BasePage {
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 10),
|
||||
child: PrimaryImageButton(
|
||||
key: ValueKey('welcome_page_restore_wallet_button_key'),
|
||||
onPressed: () {
|
||||
Navigator.pushNamed(context, Routes.restoreOptions, arguments: true);
|
||||
},
|
||||
|
||||
@@ -15,28 +15,27 @@ import 'package:permission_handler/permission_handler.dart';
|
||||
enum AddressTextFieldOption { paste, qrCode, addressBook, walletAddresses }
|
||||
|
||||
class AddressTextField extends StatelessWidget {
|
||||
AddressTextField(
|
||||
{required this.controller,
|
||||
this.isActive = true,
|
||||
this.placeholder,
|
||||
this.options = const [
|
||||
AddressTextFieldOption.qrCode,
|
||||
AddressTextFieldOption.addressBook
|
||||
],
|
||||
this.onURIScanned,
|
||||
this.focusNode,
|
||||
this.isBorderExist = true,
|
||||
this.buttonColor,
|
||||
this.borderColor,
|
||||
this.iconColor,
|
||||
this.textStyle,
|
||||
this.hintStyle,
|
||||
this.validator,
|
||||
this.onPushPasteButton,
|
||||
this.onPushAddressBookButton,
|
||||
this.onPushAddressPickerButton,
|
||||
this.onSelectedContact,
|
||||
this.selectedCurrency});
|
||||
AddressTextField({
|
||||
required this.controller,
|
||||
this.isActive = true,
|
||||
this.placeholder,
|
||||
this.options = const [AddressTextFieldOption.qrCode, AddressTextFieldOption.addressBook],
|
||||
this.onURIScanned,
|
||||
this.focusNode,
|
||||
this.isBorderExist = true,
|
||||
this.buttonColor,
|
||||
this.borderColor,
|
||||
this.iconColor,
|
||||
this.textStyle,
|
||||
this.hintStyle,
|
||||
this.validator,
|
||||
this.onPushPasteButton,
|
||||
this.onPushAddressBookButton,
|
||||
this.onPushAddressPickerButton,
|
||||
this.onSelectedContact,
|
||||
this.selectedCurrency,
|
||||
this.addressKey,
|
||||
});
|
||||
|
||||
static const prefixIconWidth = 34.0;
|
||||
static const prefixIconHeight = 34.0;
|
||||
@@ -60,12 +59,14 @@ class AddressTextField extends StatelessWidget {
|
||||
final Function(BuildContext context)? onPushAddressPickerButton;
|
||||
final Function(ContactBase contact)? onSelectedContact;
|
||||
final CryptoCurrency? selectedCurrency;
|
||||
final Key? addressKey;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Stack(
|
||||
children: <Widget>[
|
||||
TextFormField(
|
||||
key: addressKey,
|
||||
enableIMEPersonalizedLearning: false,
|
||||
keyboardType: TextInputType.visiblePassword,
|
||||
onFieldSubmitted: (_) => FocusScope.of(context).unfocus(),
|
||||
|
||||
@@ -3,7 +3,12 @@ import 'package:cake_wallet/palette.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class AlertCloseButton extends StatelessWidget {
|
||||
AlertCloseButton({this.image, this.bottom, this.onTap});
|
||||
AlertCloseButton({
|
||||
this.image,
|
||||
this.bottom,
|
||||
this.onTap,
|
||||
super.key,
|
||||
});
|
||||
|
||||
final VoidCallback? onTap;
|
||||
|
||||
|
||||
@@ -9,7 +9,9 @@ class AlertWithOneAction extends BaseAlertDialog {
|
||||
required this.buttonAction,
|
||||
this.alertBarrierDismissible = true,
|
||||
this.headerTitleText,
|
||||
this.headerImageProfileUrl
|
||||
this.headerImageProfileUrl,
|
||||
this.buttonKey,
|
||||
Key? key,
|
||||
});
|
||||
|
||||
final String alertTitle;
|
||||
@@ -19,6 +21,7 @@ class AlertWithOneAction extends BaseAlertDialog {
|
||||
final bool alertBarrierDismissible;
|
||||
final String? headerTitleText;
|
||||
final String? headerImageProfileUrl;
|
||||
final Key? buttonKey;
|
||||
|
||||
@override
|
||||
String get titleText => alertTitle;
|
||||
@@ -45,6 +48,7 @@ class AlertWithOneAction extends BaseAlertDialog {
|
||||
child: ButtonTheme(
|
||||
minWidth: double.infinity,
|
||||
child: TextButton(
|
||||
key: buttonKey,
|
||||
onPressed: buttonAction,
|
||||
// FIX-ME: Style
|
||||
//highlightColor: Colors.transparent,
|
||||
@@ -62,4 +66,4 @@ class AlertWithOneAction extends BaseAlertDialog {
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,9 @@ class AlertWithTwoActions extends BaseAlertDialog {
|
||||
this.isDividerExist = false,
|
||||
// this.leftActionColor,
|
||||
// this.rightActionColor,
|
||||
this.alertRightActionButtonKey,
|
||||
this.alertLeftActionButtonKey,
|
||||
this.alertDialogKey,
|
||||
});
|
||||
|
||||
final String alertTitle;
|
||||
@@ -26,6 +29,9 @@ class AlertWithTwoActions extends BaseAlertDialog {
|
||||
// final Color leftActionColor;
|
||||
// final Color rightActionColor;
|
||||
final bool isDividerExist;
|
||||
final Key? alertRightActionButtonKey;
|
||||
final Key? alertLeftActionButtonKey;
|
||||
final Key? alertDialogKey;
|
||||
|
||||
@override
|
||||
String get titleText => alertTitle;
|
||||
@@ -47,4 +53,13 @@ class AlertWithTwoActions extends BaseAlertDialog {
|
||||
// Color get rightButtonColor => rightActionColor;
|
||||
@override
|
||||
bool get isDividerExists => isDividerExist;
|
||||
|
||||
@override
|
||||
Key? get dialogKey => alertDialogKey;
|
||||
|
||||
@override
|
||||
Key? get leftActionButtonKey => alertLeftActionButtonKey;
|
||||
|
||||
@override
|
||||
Key? get rightActionButtonKey => alertRightActionButtonKey;
|
||||
}
|
||||
|
||||
@@ -33,6 +33,12 @@ class BaseAlertDialog extends StatelessWidget {
|
||||
|
||||
String? get headerImageUrl => null;
|
||||
|
||||
Key? leftActionButtonKey;
|
||||
|
||||
Key? rightActionButtonKey;
|
||||
|
||||
Key? dialogKey;
|
||||
|
||||
Widget title(BuildContext context) {
|
||||
return Text(
|
||||
titleText,
|
||||
@@ -87,6 +93,7 @@ class BaseAlertDialog extends StatelessWidget {
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: TextButton(
|
||||
key: leftActionButtonKey,
|
||||
onPressed: actionLeft,
|
||||
style: TextButton.styleFrom(
|
||||
backgroundColor:
|
||||
@@ -109,6 +116,7 @@ class BaseAlertDialog extends StatelessWidget {
|
||||
const VerticalSectionDivider(),
|
||||
Expanded(
|
||||
child: TextButton(
|
||||
key: rightActionButtonKey,
|
||||
onPressed: actionRight,
|
||||
style: TextButton.styleFrom(
|
||||
backgroundColor:
|
||||
@@ -152,6 +160,7 @@ class BaseAlertDialog extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return GestureDetector(
|
||||
key: key,
|
||||
onTap: () => barrierDismissible ? Navigator.of(context).pop() : null,
|
||||
child: Container(
|
||||
color: Colors.transparent,
|
||||
|
||||
@@ -30,7 +30,8 @@ class BaseTextFormField extends StatelessWidget {
|
||||
this.focusNode,
|
||||
this.initialValue,
|
||||
this.onSubmit,
|
||||
this.borderWidth = 1.0});
|
||||
this.borderWidth = 1.0,
|
||||
super.key});
|
||||
|
||||
final TextEditingController? controller;
|
||||
final TextInputType? keyboardType;
|
||||
|
||||
@@ -6,7 +6,8 @@ class OptionTile extends StatelessWidget {
|
||||
{required this.onPressed,
|
||||
required this.image,
|
||||
required this.title,
|
||||
required this.description});
|
||||
required this.description,
|
||||
super.key});
|
||||
|
||||
final VoidCallback onPressed;
|
||||
final Image image;
|
||||
|
||||
@@ -4,6 +4,7 @@ import 'dart:math';
|
||||
|
||||
import 'package:cake_wallet/src/widgets/search_bar_widget.dart';
|
||||
import 'package:cake_wallet/utils/responsive_layout_util.dart';
|
||||
import 'package:cw_core/transaction_priority.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:cw_core/currency.dart';
|
||||
import 'package:cake_wallet/src/widgets/picker_wrapper_widget.dart';
|
||||
@@ -11,6 +12,7 @@ import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
|
||||
import 'package:cake_wallet/themes/extensions/cake_scrollbar_theme.dart';
|
||||
import 'package:cake_wallet/themes/extensions/picker_theme.dart';
|
||||
|
||||
//TODO(David): PickerWidget is intertwined and confusing as is, find a way to optimize?
|
||||
class Picker<Item> extends StatefulWidget {
|
||||
Picker({
|
||||
required this.selectedAtIndex,
|
||||
@@ -153,6 +155,7 @@ class _PickerState<Item> extends State<Picker<Item>> {
|
||||
Container(
|
||||
padding: EdgeInsets.symmetric(horizontal: padding),
|
||||
child: Text(
|
||||
key: ValueKey('picker_title_text_key'),
|
||||
widget.title!,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
@@ -189,7 +192,10 @@ class _PickerState<Item> extends State<Picker<Item>> {
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: SearchBarWidget(
|
||||
searchController: searchController, hintText: widget.hintText),
|
||||
key: ValueKey('picker_search_bar_key'),
|
||||
searchController: searchController,
|
||||
hintText: widget.hintText,
|
||||
),
|
||||
),
|
||||
Divider(
|
||||
color: Theme.of(context).extension<PickerTheme>()!.dividerColor,
|
||||
@@ -203,6 +209,7 @@ class _PickerState<Item> extends State<Picker<Item>> {
|
||||
children: <Widget>[
|
||||
filteredItems.length > 3
|
||||
? Scrollbar(
|
||||
key: ValueKey('picker_scrollbar_key'),
|
||||
controller: controller,
|
||||
child: itemsList(),
|
||||
)
|
||||
@@ -213,6 +220,7 @@ class _PickerState<Item> extends State<Picker<Item>> {
|
||||
left: padding,
|
||||
right: padding,
|
||||
child: Text(
|
||||
key: ValueKey('picker_descriptinon_text_key'),
|
||||
widget.description!,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
@@ -242,6 +250,7 @@ class _PickerState<Item> extends State<Picker<Item>> {
|
||||
|
||||
if (widget.isWrapped) {
|
||||
return PickerWrapperWidget(
|
||||
key: ValueKey('picker_wrapper_widget_key'),
|
||||
hasTitle: widget.title?.isNotEmpty ?? false,
|
||||
children: [content],
|
||||
);
|
||||
@@ -260,6 +269,7 @@ class _PickerState<Item> extends State<Picker<Item>> {
|
||||
color: Theme.of(context).extension<PickerTheme>()!.dividerColor,
|
||||
child: widget.isGridView
|
||||
? GridView.builder(
|
||||
key: ValueKey('picker_items_grid_view_key'),
|
||||
padding: EdgeInsets.zero,
|
||||
controller: controller,
|
||||
shrinkWrap: true,
|
||||
@@ -275,6 +285,7 @@ class _PickerState<Item> extends State<Picker<Item>> {
|
||||
: buildItem(index),
|
||||
)
|
||||
: ListView.separated(
|
||||
key: ValueKey('picker_items_list_view_key'),
|
||||
padding: EdgeInsets.zero,
|
||||
controller: controller,
|
||||
shrinkWrap: true,
|
||||
@@ -293,10 +304,25 @@ class _PickerState<Item> extends State<Picker<Item>> {
|
||||
);
|
||||
}
|
||||
|
||||
String _getItemName(Item item) {
|
||||
String itemName;
|
||||
if (item is Currency) {
|
||||
itemName = item.name;
|
||||
} else if (item is TransactionPriority) {
|
||||
itemName = item.title;
|
||||
} else {
|
||||
itemName = '';
|
||||
}
|
||||
|
||||
return itemName;
|
||||
}
|
||||
|
||||
Widget buildItem(int index) {
|
||||
final item = widget.headerEnabled ? filteredItems[index] : items[index];
|
||||
|
||||
final tag = item is Currency ? item.tag : null;
|
||||
final itemName = _getItemName(item);
|
||||
|
||||
final icon = _getItemIcon(item);
|
||||
|
||||
final image = images.isNotEmpty ? filteredImages[index] : icon;
|
||||
@@ -316,6 +342,7 @@ class _PickerState<Item> extends State<Picker<Item>> {
|
||||
children: [
|
||||
Flexible(
|
||||
child: Text(
|
||||
key: ValueKey('picker_items_index_${itemName}_text_key'),
|
||||
widget.displayItem?.call(item) ?? item.toString(),
|
||||
softWrap: true,
|
||||
style: TextStyle(
|
||||
@@ -335,6 +362,7 @@ class _PickerState<Item> extends State<Picker<Item>> {
|
||||
height: 18.0,
|
||||
child: Center(
|
||||
child: Text(
|
||||
key: ValueKey('picker_items_index_${index}_tag_key'),
|
||||
tag,
|
||||
style: TextStyle(
|
||||
fontSize: 7.0,
|
||||
@@ -358,6 +386,7 @@ class _PickerState<Item> extends State<Picker<Item>> {
|
||||
);
|
||||
|
||||
return GestureDetector(
|
||||
key: ValueKey('picker_items_index_${itemName}_button_key'),
|
||||
onTap: () {
|
||||
if (widget.closeOnItemSelected) Navigator.of(context).pop();
|
||||
onItemSelected(item!);
|
||||
@@ -383,6 +412,7 @@ class _PickerState<Item> extends State<Picker<Item>> {
|
||||
final item = items[index];
|
||||
|
||||
final tag = item is Currency ? item.tag : null;
|
||||
final itemName = _getItemName(item);
|
||||
final icon = _getItemIcon(item);
|
||||
|
||||
final image = images.isNotEmpty ? images[index] : icon;
|
||||
@@ -390,6 +420,7 @@ class _PickerState<Item> extends State<Picker<Item>> {
|
||||
final isCustomItem = widget.customItemIndex != null && index == widget.customItemIndex;
|
||||
|
||||
final itemContent = Row(
|
||||
key: ValueKey('picker_selected_item_row_key'),
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
mainAxisAlignment: widget.mainAxisAlignment,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
@@ -402,6 +433,7 @@ class _PickerState<Item> extends State<Picker<Item>> {
|
||||
children: [
|
||||
Flexible(
|
||||
child: Text(
|
||||
key: ValueKey('picker_items_index_${itemName}_selected_item_text_key'),
|
||||
widget.displayItem?.call(item) ?? item.toString(),
|
||||
softWrap: true,
|
||||
style: TextStyle(
|
||||
@@ -445,6 +477,7 @@ class _PickerState<Item> extends State<Picker<Item>> {
|
||||
);
|
||||
|
||||
return GestureDetector(
|
||||
key: ValueKey('picker_items_index_${itemName}_selected_item_button_key'),
|
||||
onTap: () {
|
||||
if (widget.closeOnItemSelected) Navigator.of(context).pop();
|
||||
},
|
||||
|
||||
@@ -4,7 +4,12 @@ import 'package:cake_wallet/src/widgets/alert_background.dart';
|
||||
import 'package:cake_wallet/src/widgets/alert_close_button.dart';
|
||||
|
||||
class PickerWrapperWidget extends StatelessWidget {
|
||||
PickerWrapperWidget({required this.children, this.hasTitle = false, this.onClose});
|
||||
PickerWrapperWidget({
|
||||
required this.children,
|
||||
this.hasTitle = false,
|
||||
this.onClose,
|
||||
super.key,
|
||||
});
|
||||
|
||||
final List<Widget> children;
|
||||
final bool hasTitle;
|
||||
@@ -29,8 +34,8 @@ class PickerWrapperWidget extends StatelessWidget {
|
||||
final containerBottom = screenCenter - containerCenter;
|
||||
|
||||
// position the close button right below the search container
|
||||
closeButtonBottom = closeButtonBottom -
|
||||
containerBottom + (!hasTitle ? padding : padding / 1.5);
|
||||
closeButtonBottom =
|
||||
closeButtonBottom - containerBottom + (!hasTitle ? padding : padding / 1.5);
|
||||
}
|
||||
|
||||
return AlertBackground(
|
||||
@@ -46,7 +51,11 @@ class PickerWrapperWidget extends StatelessWidget {
|
||||
children: children,
|
||||
),
|
||||
SizedBox(height: ResponsiveLayoutUtilBase.kPopupSpaceHeight),
|
||||
AlertCloseButton(bottom: closeButtonBottom, onTap: onClose),
|
||||
AlertCloseButton(
|
||||
key: ValueKey('picker_wrapper_close_button_key'),
|
||||
bottom: closeButtonBottom,
|
||||
onTap: onClose,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
@@ -4,15 +4,17 @@ import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class PrimaryButton extends StatelessWidget {
|
||||
const PrimaryButton(
|
||||
{required this.text,
|
||||
required this.color,
|
||||
required this.textColor,
|
||||
this.onPressed,
|
||||
this.isDisabled = false,
|
||||
this.isDottedBorder = false,
|
||||
this.borderColor = Colors.black,
|
||||
this.onDisabledPressed});
|
||||
const PrimaryButton({
|
||||
required this.text,
|
||||
required this.color,
|
||||
required this.textColor,
|
||||
this.onPressed,
|
||||
this.isDisabled = false,
|
||||
this.isDottedBorder = false,
|
||||
this.borderColor = Colors.black,
|
||||
this.onDisabledPressed,
|
||||
super.key,
|
||||
});
|
||||
|
||||
final VoidCallback? onPressed;
|
||||
final VoidCallback? onDisabledPressed;
|
||||
@@ -31,23 +33,23 @@ class PrimaryButton extends StatelessWidget {
|
||||
width: double.infinity,
|
||||
height: 52.0,
|
||||
child: TextButton(
|
||||
onPressed: isDisabled
|
||||
? (onDisabledPressed != null ? onDisabledPressed : null) : onPressed,
|
||||
style: ButtonStyle(backgroundColor: MaterialStateProperty.all(isDisabled ? color.withOpacity(0.5) : color),
|
||||
onPressed:
|
||||
isDisabled ? (onDisabledPressed != null ? onDisabledPressed : null) : onPressed,
|
||||
style: ButtonStyle(
|
||||
backgroundColor:
|
||||
MaterialStateProperty.all(isDisabled ? color.withOpacity(0.5) : color),
|
||||
shape: MaterialStateProperty.all<RoundedRectangleBorder>(
|
||||
RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(26.0),
|
||||
),
|
||||
),
|
||||
overlayColor: MaterialStateProperty.all(Colors.transparent)),
|
||||
overlayColor: MaterialStateProperty.all(Colors.transparent)),
|
||||
child: Text(text,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 15.0,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: isDisabled
|
||||
? textColor.withOpacity(0.5)
|
||||
: textColor)),
|
||||
color: isDisabled ? textColor.withOpacity(0.5) : textColor)),
|
||||
)),
|
||||
);
|
||||
|
||||
@@ -64,13 +66,15 @@ class PrimaryButton extends StatelessWidget {
|
||||
}
|
||||
|
||||
class LoadingPrimaryButton extends StatelessWidget {
|
||||
const LoadingPrimaryButton(
|
||||
{required this.onPressed,
|
||||
required this.text,
|
||||
required this.color,
|
||||
required this.textColor,
|
||||
this.isDisabled = false,
|
||||
this.isLoading = false});
|
||||
const LoadingPrimaryButton({
|
||||
required this.onPressed,
|
||||
required this.text,
|
||||
required this.color,
|
||||
required this.textColor,
|
||||
this.isDisabled = false,
|
||||
this.isLoading = false,
|
||||
super.key,
|
||||
});
|
||||
|
||||
final VoidCallback onPressed;
|
||||
final Color color;
|
||||
@@ -88,41 +92,38 @@ class LoadingPrimaryButton extends StatelessWidget {
|
||||
height: 52.0,
|
||||
child: TextButton(
|
||||
onPressed: (isLoading || isDisabled) ? null : onPressed,
|
||||
style: ButtonStyle(backgroundColor: MaterialStateProperty.all(isDisabled ? color.withOpacity(0.5) : color),
|
||||
shape: MaterialStateProperty.all<RoundedRectangleBorder>(
|
||||
RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(26.0),
|
||||
),
|
||||
)),
|
||||
|
||||
style: ButtonStyle(
|
||||
backgroundColor:
|
||||
MaterialStateProperty.all(isDisabled ? color.withOpacity(0.5) : color),
|
||||
shape: MaterialStateProperty.all<RoundedRectangleBorder>(
|
||||
RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(26.0),
|
||||
),
|
||||
)),
|
||||
child: isLoading
|
||||
? CupertinoActivityIndicator(animating: true)
|
||||
: Text(text,
|
||||
style: TextStyle(
|
||||
fontSize: 15.0,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: isDisabled
|
||||
? textColor.withOpacity(0.5)
|
||||
: textColor
|
||||
)),
|
||||
style: TextStyle(
|
||||
fontSize: 15.0,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: isDisabled ? textColor.withOpacity(0.5) : textColor)),
|
||||
)),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class PrimaryIconButton extends StatelessWidget {
|
||||
const PrimaryIconButton({
|
||||
required this.onPressed,
|
||||
required this.iconData,
|
||||
required this.text,
|
||||
required this.color,
|
||||
required this.borderColor,
|
||||
required this.iconColor,
|
||||
required this.iconBackgroundColor,
|
||||
required this.textColor,
|
||||
this.mainAxisAlignment = MainAxisAlignment.start,
|
||||
this.radius = 26
|
||||
});
|
||||
const PrimaryIconButton(
|
||||
{required this.onPressed,
|
||||
required this.iconData,
|
||||
required this.text,
|
||||
required this.color,
|
||||
required this.borderColor,
|
||||
required this.iconColor,
|
||||
required this.iconBackgroundColor,
|
||||
required this.textColor,
|
||||
this.mainAxisAlignment = MainAxisAlignment.start,
|
||||
this.radius = 26, super.key});
|
||||
|
||||
final VoidCallback onPressed;
|
||||
final IconData iconData;
|
||||
@@ -144,7 +145,8 @@ class PrimaryIconButton extends StatelessWidget {
|
||||
height: 52.0,
|
||||
child: TextButton(
|
||||
onPressed: onPressed,
|
||||
style: ButtonStyle(backgroundColor: MaterialStateProperty.all(color),
|
||||
style: ButtonStyle(
|
||||
backgroundColor: MaterialStateProperty.all(color),
|
||||
shape: MaterialStateProperty.all<RoundedRectangleBorder>(
|
||||
RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(radius),
|
||||
@@ -158,21 +160,15 @@ class PrimaryIconButton extends StatelessWidget {
|
||||
Container(
|
||||
width: 26.0,
|
||||
height: 52.0,
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle, color: iconBackgroundColor),
|
||||
child: Center(
|
||||
child: Icon(iconData, color: iconColor, size: 22.0)
|
||||
),
|
||||
decoration: BoxDecoration(shape: BoxShape.circle, color: iconBackgroundColor),
|
||||
child: Center(child: Icon(iconData, color: iconColor, size: 22.0)),
|
||||
),
|
||||
],
|
||||
),
|
||||
Container(
|
||||
height: 52.0,
|
||||
child: Center(
|
||||
child: Text(text,
|
||||
style: TextStyle(
|
||||
fontSize: 16.0,
|
||||
color: textColor)),
|
||||
child: Text(text, style: TextStyle(fontSize: 16.0, color: textColor)),
|
||||
),
|
||||
)
|
||||
],
|
||||
@@ -189,7 +185,7 @@ class PrimaryImageButton extends StatelessWidget {
|
||||
required this.text,
|
||||
required this.color,
|
||||
required this.textColor,
|
||||
this.borderColor = Colors.transparent});
|
||||
this.borderColor = Colors.transparent, super.key});
|
||||
|
||||
final VoidCallback onPressed;
|
||||
final Image image;
|
||||
@@ -206,31 +202,27 @@ class PrimaryImageButton extends StatelessWidget {
|
||||
width: double.infinity,
|
||||
height: 52.0,
|
||||
child: TextButton(
|
||||
onPressed: onPressed,
|
||||
style: ButtonStyle(backgroundColor: MaterialStateProperty.all(color),
|
||||
shape: MaterialStateProperty.all<RoundedRectangleBorder>(
|
||||
RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(26.0),
|
||||
),
|
||||
)),
|
||||
child:Center(
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: <Widget>[
|
||||
image,
|
||||
SizedBox(width: 15),
|
||||
Text(
|
||||
text,
|
||||
style: TextStyle(
|
||||
fontSize: 15,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: textColor
|
||||
onPressed: onPressed,
|
||||
style: ButtonStyle(
|
||||
backgroundColor: MaterialStateProperty.all(color),
|
||||
shape: MaterialStateProperty.all<RoundedRectangleBorder>(
|
||||
RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(26.0),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
)
|
||||
)),
|
||||
)),
|
||||
child: Center(
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: <Widget>[
|
||||
image,
|
||||
SizedBox(width: 15),
|
||||
Text(
|
||||
text,
|
||||
style: TextStyle(fontSize: 15, fontWeight: FontWeight.w600, color: textColor),
|
||||
)
|
||||
],
|
||||
),
|
||||
))),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ class ScrollableWithBottomSection extends StatefulWidget {
|
||||
this.contentPadding,
|
||||
this.bottomSectionPadding,
|
||||
this.topSectionPadding,
|
||||
this.scrollableKey,
|
||||
});
|
||||
|
||||
final Widget content;
|
||||
@@ -17,6 +18,7 @@ class ScrollableWithBottomSection extends StatefulWidget {
|
||||
final EdgeInsets? contentPadding;
|
||||
final EdgeInsets? bottomSectionPadding;
|
||||
final EdgeInsets? topSectionPadding;
|
||||
final Key? scrollableKey;
|
||||
|
||||
@override
|
||||
ScrollableWithBottomSectionState createState() => ScrollableWithBottomSectionState();
|
||||
@@ -35,6 +37,7 @@ class ScrollableWithBottomSectionState extends State<ScrollableWithBottomSection
|
||||
),
|
||||
Expanded(
|
||||
child: SingleChildScrollView(
|
||||
key: widget.scrollableKey,
|
||||
child: Padding(
|
||||
padding: widget.contentPadding ?? EdgeInsets.only(left: 20, right: 20),
|
||||
child: widget.content,
|
||||
|
||||
@@ -7,6 +7,7 @@ class SearchBarWidget extends StatelessWidget {
|
||||
required this.searchController,
|
||||
this.hintText,
|
||||
this.borderRadius = 14,
|
||||
super.key,
|
||||
});
|
||||
|
||||
final TextEditingController searchController;
|
||||
|
||||
@@ -9,11 +9,15 @@ import 'package:flutter/services.dart';
|
||||
|
||||
class SeedWidget extends StatefulWidget {
|
||||
SeedWidget({
|
||||
Key? key,
|
||||
required this.language,
|
||||
required this.type,
|
||||
this.onSeedChange}) : super(key: key);
|
||||
|
||||
this.onSeedChange,
|
||||
this.pasteButtonKey,
|
||||
this.seedTextFieldKey,
|
||||
super.key,
|
||||
});
|
||||
final Key? seedTextFieldKey;
|
||||
final Key? pasteButtonKey;
|
||||
final String language;
|
||||
final WalletType type;
|
||||
final void Function(String)? onSeedChange;
|
||||
@@ -78,11 +82,11 @@ class SeedWidgetState extends State<SeedWidget> {
|
||||
top: 10,
|
||||
left: 0,
|
||||
child: Text(S.of(context).enter_seed_phrase,
|
||||
style: TextStyle(
|
||||
fontSize: 16.0, color: Theme.of(context).hintColor))),
|
||||
style: TextStyle(fontSize: 16.0, color: Theme.of(context).hintColor))),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(right: 40, top: 10),
|
||||
child: ValidatableAnnotatedEditableText(
|
||||
key: widget.seedTextFieldKey,
|
||||
cursorColor: Colors.blue,
|
||||
backgroundCursorColor: Colors.blue,
|
||||
validStyle: TextStyle(
|
||||
@@ -112,15 +116,17 @@ class SeedWidgetState extends State<SeedWidget> {
|
||||
width: 32,
|
||||
height: 32,
|
||||
child: InkWell(
|
||||
key: widget.pasteButtonKey,
|
||||
onTap: () async => _pasteText(),
|
||||
child: Container(
|
||||
padding: EdgeInsets.all(8),
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).hintColor,
|
||||
borderRadius:
|
||||
BorderRadius.all(Radius.circular(6))),
|
||||
borderRadius: BorderRadius.all(Radius.circular(6))),
|
||||
child: Image.asset('assets/images/paste_ios.png',
|
||||
color: Theme.of(context).extension<SendPageTheme>()!.textFieldButtonIconColor)),
|
||||
color: Theme.of(context)
|
||||
.extension<SendPageTheme>()!
|
||||
.textFieldButtonIconColor)),
|
||||
)))
|
||||
]),
|
||||
Container(
|
||||
|
||||
Reference in New Issue
Block a user