mirror of
https://github.com/cake-tech/cake_wallet.git
synced 2024-11-16 17:27:37 +00:00
feat: Testing the Exchange flow section, selecting sending and receiving currencies
This commit is contained in:
parent
8ec38e10ff
commit
66af74f0c0
16 changed files with 315 additions and 64 deletions
|
@ -1,5 +1,5 @@
|
|||
|
||||
import 'package:cake_wallet/main.dart' as app;
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
@ -7,6 +7,7 @@ import 'package:integration_test/integration_test.dart';
|
|||
|
||||
import 'robots/dashboard_page_robot.dart';
|
||||
import 'robots/disclaimer_page_robot.dart';
|
||||
import 'robots/exchange_page_robot.dart';
|
||||
import 'robots/new_wallet_type_page_robot.dart';
|
||||
import 'robots/restore_from_seed_or_key_robot.dart';
|
||||
import 'robots/restore_options_page_robot.dart';
|
||||
|
@ -32,6 +33,7 @@ void main() {
|
|||
NewWalletTypePageRobot newWalletTypePageRobot;
|
||||
RestoreFromSeedOrKeysPageRobot restoreFromSeedOrKeysPageRobot;
|
||||
DashboardPageRobot dashboardPageRobot;
|
||||
ExchangePageRobot exchangePageRobot;
|
||||
|
||||
group('Startup Test', () {
|
||||
testWidgets('Test for Exchange flow using Restore Wallet - Exchanging USDT(Sol) to SOL',
|
||||
|
@ -43,6 +45,7 @@ void main() {
|
|||
newWalletTypePageRobot = NewWalletTypePageRobot(tester);
|
||||
restoreFromSeedOrKeysPageRobot = RestoreFromSeedOrKeysPageRobot(tester);
|
||||
dashboardPageRobot = DashboardPageRobot(tester);
|
||||
exchangePageRobot = ExchangePageRobot(tester);
|
||||
|
||||
await app.main();
|
||||
await tester.pumpAndSettle();
|
||||
|
@ -139,14 +142,28 @@ void main() {
|
|||
await restoreFromSeedOrKeysPageRobot.onRestoreWalletButtonTapped();
|
||||
|
||||
// ----------- RestoreFromSeedOrKeys Page -------------
|
||||
await dashboardPageRobot.isDashboardPage();
|
||||
dashboardPageRobot.confirmServiceUpdateButtonDisplays();
|
||||
dashboardPageRobot.confirmMenuButtonDisplays();
|
||||
dashboardPageRobot.confirmSyncIndicatorButtonDisplays();
|
||||
await dashboardPageRobot.confirmRightCryptoAssetTitleDisplaysPerPageView(WalletType.solana);
|
||||
// await dashboardPageRobot.isDashboardPage();
|
||||
// dashboardPageRobot.confirmServiceUpdateButtonDisplays();
|
||||
// dashboardPageRobot.confirmMenuButtonDisplays();
|
||||
// dashboardPageRobot.confirmSyncIndicatorButtonDisplays();
|
||||
// await dashboardPageRobot.confirmRightCryptoAssetTitleDisplaysPerPageView(WalletType.solana);
|
||||
|
||||
await dashboardPageRobot.navigateToExchangePage();
|
||||
await Future.delayed(Duration(seconds: 5));
|
||||
await Future.delayed(Duration(seconds: 2));
|
||||
|
||||
// ----------- Exchange Page -------------
|
||||
await exchangePageRobot.isExchangePage();
|
||||
exchangePageRobot.hasTitle();
|
||||
exchangePageRobot.hasResetButton();
|
||||
await exchangePageRobot.displayBothExchangeCards();
|
||||
exchangePageRobot.confirmRightComponentsDisplayOnDepositExchangeCards();
|
||||
exchangePageRobot.confirmRightComponentsDisplayOnReceiveExchangeCards();
|
||||
|
||||
await exchangePageRobot.selectDepositCurrency(CryptoCurrency.btc);
|
||||
|
||||
await exchangePageRobot.selectReceiveCurrency(CryptoCurrency.usdtSol);
|
||||
|
||||
await Future.delayed(Duration(seconds: 10));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ class CommonTestCases {
|
|||
expect(typeWidget, findsOneWidget);
|
||||
}
|
||||
|
||||
void hasKey(String key) {
|
||||
void hasValueKey(String key) {
|
||||
final typeWidget = find.byKey(ValueKey(key));
|
||||
expect(typeWidget, findsOneWidget);
|
||||
}
|
||||
|
@ -51,5 +51,19 @@ class CommonTestCases {
|
|||
await tester.pumpAndSettle();
|
||||
}
|
||||
|
||||
Future<void> defaultSleepTime({int seconds = 2})async => await Future.delayed(Duration(seconds: seconds));
|
||||
Future<void> scrollUntilVisible(String childKey, String parentScrollableKey, {double delta = 300}) async {
|
||||
final scrollableWidget = find.descendant(
|
||||
of: find.byKey(Key(parentScrollableKey)),
|
||||
matching: find.byType(Scrollable),
|
||||
);
|
||||
|
||||
await tester.scrollUntilVisible(
|
||||
find.byKey(ValueKey(childKey)),
|
||||
delta,
|
||||
scrollable: scrollableWidget,
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> defaultSleepTime({int seconds = 2}) async =>
|
||||
await Future.delayed(Duration(seconds: seconds));
|
||||
}
|
||||
|
|
|
@ -16,15 +16,15 @@ class DashboardPageRobot {
|
|||
}
|
||||
|
||||
void confirmServiceUpdateButtonDisplays() {
|
||||
commonTestCases.hasKey('dashboard_page_services_update_button_key');
|
||||
commonTestCases.hasValueKey('dashboard_page_services_update_button_key');
|
||||
}
|
||||
|
||||
void confirmSyncIndicatorButtonDisplays() {
|
||||
commonTestCases.hasKey('dashboard_page_sync_indicator_button_key');
|
||||
commonTestCases.hasValueKey('dashboard_page_sync_indicator_button_key');
|
||||
}
|
||||
|
||||
void confirmMenuButtonDisplays() {
|
||||
commonTestCases.hasKey('dashboard_page_wallet_menu_button_key');
|
||||
commonTestCases.hasValueKey('dashboard_page_wallet_menu_button_key');
|
||||
}
|
||||
|
||||
Future<void> confirmRightCryptoAssetTitleDisplaysPerPageView(WalletType type,
|
||||
|
|
|
@ -0,0 +1,152 @@
|
|||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/src/screens/exchange/exchange_page.dart';
|
||||
import 'package:cake_wallet/src/screens/exchange/widgets/currency_picker.dart';
|
||||
import 'package:cake_wallet/src/screens/exchange/widgets/exchange_card.dart';
|
||||
import 'package:cake_wallet/src/screens/exchange/widgets/present_provider_picker.dart';
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
import '../components/common_checks.dart';
|
||||
|
||||
class ExchangePageRobot {
|
||||
ExchangePageRobot(this.tester) : commonTestCases = CommonTestCases(tester);
|
||||
|
||||
final WidgetTester tester;
|
||||
late CommonTestCases commonTestCases;
|
||||
|
||||
Future<void> isExchangePage() async {
|
||||
await commonTestCases.isSpecificPage<ExchangePage>();
|
||||
}
|
||||
|
||||
void hasTitle() {
|
||||
// commonTestCases.hasText(S.current.exchange);
|
||||
}
|
||||
|
||||
void hasResetButton() {
|
||||
commonTestCases.hasText(S.current.reset);
|
||||
}
|
||||
|
||||
void displaysPresentProviderPicker() {
|
||||
commonTestCases.hasType<PresentProviderPicker>();
|
||||
}
|
||||
|
||||
Future<void> displayBothExchangeCards() async {
|
||||
final ExchangePage exchangeCard = tester.widget<ExchangePage>(
|
||||
find.byType(ExchangePage),
|
||||
);
|
||||
|
||||
final depositKey = exchangeCard.depositKey;
|
||||
final receiveKey = exchangeCard.receiveKey;
|
||||
|
||||
final depositExchangeCard = find.byKey(depositKey);
|
||||
expect(depositExchangeCard, findsOneWidget);
|
||||
|
||||
final receiveExchangeCard = find.byKey(receiveKey);
|
||||
expect(receiveExchangeCard, findsOneWidget);
|
||||
}
|
||||
|
||||
void confirmRightComponentsDisplayOnDepositExchangeCards() {
|
||||
ExchangePage exchangePage = tester.widget(find.byType(ExchangePage));
|
||||
final exchangeViewModel = exchangePage.exchangeViewModel;
|
||||
final depositCardPrefix = 'deposit_exchange_card';
|
||||
|
||||
commonTestCases.hasValueKey('${depositCardPrefix}_title_key');
|
||||
commonTestCases.hasValueKey('${depositCardPrefix}_currency_picker_button_key');
|
||||
commonTestCases.hasValueKey('${depositCardPrefix}_selected_currency_text_key');
|
||||
commonTestCases.hasValueKey('${depositCardPrefix}_amount_textfield_key');
|
||||
commonTestCases.hasValueKey('${depositCardPrefix}_min_limit_text_key');
|
||||
|
||||
final initialCurrency = exchangeViewModel.depositCurrency;
|
||||
if (initialCurrency.tag != null) {
|
||||
commonTestCases.hasValueKey('${depositCardPrefix}_selected_currency_tag_text_key');
|
||||
}
|
||||
|
||||
if (exchangeViewModel.hasAllAmount) {
|
||||
commonTestCases.hasValueKey('${depositCardPrefix}_send_all_button_key');
|
||||
}
|
||||
|
||||
if (exchangeViewModel.isMoneroWallet) {
|
||||
commonTestCases.hasValueKey('${depositCardPrefix}_address_book_button_key');
|
||||
}
|
||||
|
||||
if (exchangeViewModel.isDepositAddressEnabled) {
|
||||
commonTestCases.hasValueKey('${depositCardPrefix}_editable_address_textfield_key');
|
||||
} else {
|
||||
commonTestCases.hasValueKey('${depositCardPrefix}_non_editable_address_textfield_key');
|
||||
commonTestCases.hasValueKey('${depositCardPrefix}_copy_refund_address_button_key');
|
||||
}
|
||||
|
||||
// commonTestCases.hasValueKey('${depositCardPrefix}_max_limit_text_key');
|
||||
}
|
||||
|
||||
void confirmRightComponentsDisplayOnReceiveExchangeCards() {
|
||||
ExchangePage exchangePage = tester.widget(find.byType(ExchangePage));
|
||||
final exchangeViewModel = exchangePage.exchangeViewModel;
|
||||
final receiveCardPrefix = 'receive_exchange_card';
|
||||
|
||||
commonTestCases.hasValueKey('${receiveCardPrefix}_title_key');
|
||||
commonTestCases.hasValueKey('${receiveCardPrefix}_currency_picker_button_key');
|
||||
commonTestCases.hasValueKey('${receiveCardPrefix}_selected_currency_text_key');
|
||||
commonTestCases.hasValueKey('${receiveCardPrefix}_amount_textfield_key');
|
||||
commonTestCases.hasValueKey('${receiveCardPrefix}_min_limit_text_key');
|
||||
|
||||
final initialCurrency = exchangeViewModel.receiveCurrency;
|
||||
if (initialCurrency.tag != null) {
|
||||
commonTestCases.hasValueKey('${receiveCardPrefix}_selected_currency_tag_text_key');
|
||||
}
|
||||
|
||||
if (exchangeViewModel.hasAllAmount) {
|
||||
commonTestCases.hasValueKey('${receiveCardPrefix}_send_all_button_key');
|
||||
}
|
||||
|
||||
if (exchangeViewModel.isMoneroWallet) {
|
||||
commonTestCases.hasValueKey('${receiveCardPrefix}_address_book_button_key');
|
||||
}
|
||||
|
||||
commonTestCases.hasValueKey('${receiveCardPrefix}_editable_address_textfield_key');
|
||||
}
|
||||
|
||||
Future<void> selectDepositCurrency(CryptoCurrency depositCurrency) async {
|
||||
final depositPrefix = 'deposit_exchange_card';
|
||||
final currencyPickerKey = '${depositPrefix}_currency_picker_button_key';
|
||||
final currencyPickerDialogKey = '${depositPrefix}_currency_picker_dialog_button_key';
|
||||
|
||||
await commonTestCases.tapItemByKey(currencyPickerKey);
|
||||
commonTestCases.hasValueKey(currencyPickerDialogKey);
|
||||
|
||||
await commonTestCases.scrollUntilVisible(
|
||||
'picker_items_index_${depositCurrency.name}_button_key',
|
||||
'picker_scrollbar_key',
|
||||
);
|
||||
await commonTestCases.defaultSleepTime();
|
||||
|
||||
await commonTestCases.tapItemByKey('picker_items_index_${depositCurrency.name}_button_key');
|
||||
await commonTestCases.defaultSleepTime();
|
||||
}
|
||||
|
||||
Future<void> selectReceiveCurrency(CryptoCurrency receiveCurrency) async {
|
||||
final receivePrefix = 'receive_exchange_card';
|
||||
final currencyPickerKey = '${receivePrefix}_currency_picker_button_key';
|
||||
final currencyPickerDialogKey = '${receivePrefix}_currency_picker_dialog_button_key';
|
||||
|
||||
await commonTestCases.tapItemByKey(currencyPickerKey);
|
||||
|
||||
commonTestCases.hasValueKey(currencyPickerDialogKey);
|
||||
|
||||
await commonTestCases.scrollUntilVisible(
|
||||
'picker_items_index_${receiveCurrency.name}_button_key',
|
||||
'picker_scrollbar_key',
|
||||
);
|
||||
await commonTestCases.defaultSleepTime();
|
||||
|
||||
await commonTestCases.tapItemByKey('picker_items_index_${receiveCurrency.name}_button_key');
|
||||
await commonTestCases.defaultSleepTime();
|
||||
}
|
||||
|
||||
Future<void> enterDepositAddress(String depositAddress) async {
|
||||
final amountTextField = find.byKey(ValueKey('deposit_exchange_card_amount_textfield_key'));
|
||||
}
|
||||
|
||||
Future<void> enterReceiveAddress(String receiveAddress) async {}
|
||||
}
|
|
@ -21,10 +21,10 @@ class RestoreFromSeedOrKeysPageRobot {
|
|||
commonTestCases.hasText(S.current.enter_seed_phrase);
|
||||
commonTestCases.hasText(S.current.restore_title_from_seed);
|
||||
|
||||
commonTestCases.hasKey('wallet_restore_from_seed_wallet_name_textfield_key');
|
||||
commonTestCases.hasKey('wallet_restore_from_seed_wallet_name_refresh_button_key');
|
||||
commonTestCases.hasKey('wallet_restore_from_seed_wallet_seeds_paste_button_key');
|
||||
commonTestCases.hasKey('wallet_restore_from_seed_wallet_seeds_textfield_key');
|
||||
commonTestCases.hasValueKey('wallet_restore_from_seed_wallet_name_textfield_key');
|
||||
commonTestCases.hasValueKey('wallet_restore_from_seed_wallet_name_refresh_button_key');
|
||||
commonTestCases.hasValueKey('wallet_restore_from_seed_wallet_seeds_paste_button_key');
|
||||
commonTestCases.hasValueKey('wallet_restore_from_seed_wallet_seeds_textfield_key');
|
||||
|
||||
commonTestCases.hasText(S.current.private_key, hasWidget: false);
|
||||
commonTestCases.hasText(S.current.restore_title_from_keys, hasWidget: false);
|
||||
|
@ -43,11 +43,11 @@ class RestoreFromSeedOrKeysPageRobot {
|
|||
}
|
||||
|
||||
void confirmRestoreButtonDisplays() {
|
||||
commonTestCases.hasKey('wallet_restore_seed_or_key_restore_button_key');
|
||||
commonTestCases.hasValueKey('wallet_restore_seed_or_key_restore_button_key');
|
||||
}
|
||||
|
||||
void confirmAdvancedSettingButtonDisplays() {
|
||||
commonTestCases.hasKey('wallet_restore_advanced_settings_button_key');
|
||||
commonTestCases.hasValueKey('wallet_restore_advanced_settings_button_key');
|
||||
}
|
||||
|
||||
Future<void> enterWalletNameText(String walletName) async {
|
||||
|
@ -76,6 +76,6 @@ class RestoreFromSeedOrKeysPageRobot {
|
|||
|
||||
Future<void> onRestoreWalletButtonTapped() async {
|
||||
await commonTestCases.tapItemByKey('wallet_restore_seed_or_key_restore_button_key');
|
||||
await commonTestCases.defaultSleepTime(seconds: 15);
|
||||
// await commonTestCases.defaultSleepTime(seconds: 15);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,10 +14,10 @@ class RestoreOptionsPageRobot {
|
|||
}
|
||||
|
||||
void hasRestoreOptionsButton() {
|
||||
commonTestCases.hasKey('restore_options_from_seeds_button_key');
|
||||
commonTestCases.hasKey('restore_options_from_backup_button_key');
|
||||
commonTestCases.hasKey('restore_options_from_hardware_wallet_button_key');
|
||||
commonTestCases.hasKey('restore_options_from_qr_button_key');
|
||||
commonTestCases.hasValueKey('restore_options_from_seeds_button_key');
|
||||
commonTestCases.hasValueKey('restore_options_from_backup_button_key');
|
||||
commonTestCases.hasValueKey('restore_options_from_hardware_wallet_button_key');
|
||||
commonTestCases.hasValueKey('restore_options_from_qr_button_key');
|
||||
}
|
||||
|
||||
Future<void> navigateToRestoreFromSeedsPage() async {
|
||||
|
|
|
@ -28,11 +28,11 @@ class SetupPinCodeRobot {
|
|||
void hasNumberButtonsVisible() {
|
||||
// Confirmation for buttons 1-9
|
||||
for (var i = 1; i < 10; i++) {
|
||||
commonTestCases.hasKey('pin_code_button_${i}_key');
|
||||
commonTestCases.hasValueKey('pin_code_button_${i}_key');
|
||||
}
|
||||
|
||||
// Confirmation for 0 button
|
||||
commonTestCases.hasKey('pin_code_button_0_key');
|
||||
commonTestCases.hasValueKey('pin_code_button_0_key');
|
||||
}
|
||||
|
||||
Future<void> pushPinButton(int index) async {
|
||||
|
|
|
@ -101,11 +101,11 @@ class ExchangePage extends BasePage {
|
|||
|
||||
@override
|
||||
Function(BuildContext)? get pushToNextWidget => (context) {
|
||||
FocusScopeNode currentFocus = FocusScope.of(context);
|
||||
if (!currentFocus.hasPrimaryFocus) {
|
||||
currentFocus.focusedChild?.unfocus();
|
||||
}
|
||||
};
|
||||
FocusScopeNode currentFocus = FocusScope.of(context);
|
||||
if (!currentFocus.hasPrimaryFocus) {
|
||||
currentFocus.focusedChild?.unfocus();
|
||||
}
|
||||
};
|
||||
|
||||
@override
|
||||
Widget middle(BuildContext context) => Row(
|
||||
|
@ -239,6 +239,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 &&
|
||||
|
@ -340,7 +341,6 @@ class ExchangePage extends BasePage {
|
|||
|
||||
void applyTemplate(
|
||||
BuildContext context, ExchangeViewModel exchangeViewModel, ExchangeTemplate template) async {
|
||||
|
||||
final depositCryptoCurrency = CryptoCurrency.fromString(template.depositCurrency);
|
||||
final receiveCryptoCurrency = CryptoCurrency.fromString(template.receiveCurrency);
|
||||
|
||||
|
@ -354,10 +354,12 @@ class ExchangePage extends BasePage {
|
|||
exchangeViewModel.isFixedRateMode = false;
|
||||
|
||||
var domain = template.depositAddress;
|
||||
exchangeViewModel.depositAddress = await fetchParsedAddress(context, domain, depositCryptoCurrency);
|
||||
exchangeViewModel.depositAddress =
|
||||
await fetchParsedAddress(context, domain, depositCryptoCurrency);
|
||||
|
||||
domain = template.receiveAddress;
|
||||
exchangeViewModel.receiveAddress = await fetchParsedAddress(context, domain, receiveCryptoCurrency);
|
||||
exchangeViewModel.receiveAddress =
|
||||
await fetchParsedAddress(context, domain, receiveCryptoCurrency);
|
||||
}
|
||||
|
||||
void _setReactions(BuildContext context, ExchangeViewModel exchangeViewModel) {
|
||||
|
@ -529,14 +531,16 @@ class ExchangePage extends BasePage {
|
|||
_depositAddressFocus.addListener(() async {
|
||||
if (!_depositAddressFocus.hasFocus && depositAddressController.text.isNotEmpty) {
|
||||
final domain = depositAddressController.text;
|
||||
exchangeViewModel.depositAddress = await fetchParsedAddress(context, domain, exchangeViewModel.depositCurrency);
|
||||
exchangeViewModel.depositAddress =
|
||||
await fetchParsedAddress(context, domain, exchangeViewModel.depositCurrency);
|
||||
}
|
||||
});
|
||||
|
||||
_receiveAddressFocus.addListener(() async {
|
||||
if (!_receiveAddressFocus.hasFocus && receiveAddressController.text.isNotEmpty) {
|
||||
final domain = receiveAddressController.text;
|
||||
exchangeViewModel.receiveAddress = await fetchParsedAddress(context, domain, exchangeViewModel.receiveCurrency);
|
||||
exchangeViewModel.receiveAddress =
|
||||
await fetchParsedAddress(context, domain, exchangeViewModel.receiveCurrency);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -589,7 +593,8 @@ class ExchangePage extends BasePage {
|
|||
}
|
||||
}
|
||||
|
||||
Future<String> fetchParsedAddress(BuildContext context, String domain, CryptoCurrency currency) async {
|
||||
Future<String> fetchParsedAddress(
|
||||
BuildContext context, String domain, CryptoCurrency currency) async {
|
||||
final parsedAddress = await getIt.get<AddressResolver>().resolve(context, domain, currency);
|
||||
final address = await extractAddressFromParsed(context, parsedAddress);
|
||||
return address;
|
||||
|
@ -619,6 +624,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
|
||||
|
@ -689,6 +695,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;
|
||||
|
|
|
@ -44,8 +44,9 @@ class ExchangeCard extends StatefulWidget {
|
|||
this.allAmount,
|
||||
this.onPushPasteButton,
|
||||
this.onPushAddressBookButton,
|
||||
this.onDispose})
|
||||
: super(key: key);
|
||||
this.onDispose,
|
||||
required this.cardInstanceName,
|
||||
}) : super(key: key);
|
||||
|
||||
final List<CryptoCurrency> currencies;
|
||||
final Function(CryptoCurrency) onCurrencySelected;
|
||||
|
@ -73,6 +74,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();
|
||||
|
@ -88,11 +90,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;
|
||||
|
@ -105,6 +109,7 @@ class ExchangeCardState extends State<ExchangeCard> {
|
|||
|
||||
@override
|
||||
void initState() {
|
||||
_cardInstanceName = widget.cardInstanceName;
|
||||
_title = widget.title;
|
||||
_isAmountEditable = widget.initialIsAmountEditable;
|
||||
_isAddressEditable = widget.initialIsAddressEditable;
|
||||
|
@ -183,6 +188,7 @@ class ExchangeCardState extends State<ExchangeCard> {
|
|||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Text(
|
||||
key: ValueKey('${_cardInstanceName}_title_key'),
|
||||
_title,
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
|
@ -200,6 +206,7 @@ class ExchangeCardState extends State<ExchangeCard> {
|
|||
height: 32,
|
||||
color: widget.currencyButtonColor,
|
||||
child: InkWell(
|
||||
key: ValueKey('${_cardInstanceName}_currency_picker_button_key'),
|
||||
onTap: () => _presentPicker(context),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
|
@ -209,9 +216,12 @@ class ExchangeCardState extends State<ExchangeCard> {
|
|||
padding: EdgeInsets.only(right: 5),
|
||||
child: widget.imageArrow,
|
||||
),
|
||||
Text(_selectedCurrency.toString(),
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.w600, fontSize: 16, color: Colors.white))
|
||||
Text(
|
||||
key: ValueKey('${_cardInstanceName}_selected_currency_text_key'),
|
||||
_selectedCurrency.toString(),
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.w600, fontSize: 16, color: Colors.white),
|
||||
)
|
||||
]),
|
||||
),
|
||||
),
|
||||
|
@ -227,13 +237,16 @@ class ExchangeCardState extends State<ExchangeCard> {
|
|||
child: Center(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(6.0),
|
||||
child: Text(_selectedCurrency.tag!,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Theme.of(context)
|
||||
.extension<SendPageTheme>()!
|
||||
.textFieldButtonIconColor)),
|
||||
child: Text(
|
||||
key: ValueKey('${_cardInstanceName}_selected_currency_tag_text_key'),
|
||||
_selectedCurrency.tag!,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Theme.of(context)
|
||||
.extension<SendPageTheme>()!
|
||||
.textFieldButtonIconColor),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
@ -252,6 +265,7 @@ class ExchangeCardState extends State<ExchangeCard> {
|
|||
child: FocusTraversalOrder(
|
||||
order: NumericFocusOrder(1),
|
||||
child: BaseTextFormField(
|
||||
key: ValueKey('${_cardInstanceName}_amount_textfield_key'),
|
||||
focusNode: widget.amountFocusNode,
|
||||
controller: amountController,
|
||||
enabled: _isAmountEditable,
|
||||
|
@ -272,9 +286,7 @@ class ExchangeCardState extends State<ExchangeCard> {
|
|||
color: Theme.of(context)
|
||||
.extension<ExchangePageTheme>()!
|
||||
.hintTextColor),
|
||||
validator: _isAmountEditable
|
||||
? widget.currencyValueValidator
|
||||
: null),
|
||||
validator: _isAmountEditable ? widget.currencyValueValidator : null),
|
||||
),
|
||||
),
|
||||
if (widget.hasAllAmount)
|
||||
|
@ -287,6 +299,7 @@ class ExchangeCardState extends State<ExchangeCard> {
|
|||
.textFieldButtonColor,
|
||||
borderRadius: BorderRadius.all(Radius.circular(6))),
|
||||
child: InkWell(
|
||||
key: ValueKey('${_cardInstanceName}_send_all_button_key'),
|
||||
onTap: () => widget.allAmount?.call(),
|
||||
child: Center(
|
||||
child: Text(S.of(context).all,
|
||||
|
@ -313,6 +326,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,
|
||||
|
@ -322,11 +336,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(),
|
||||
])),
|
||||
),
|
||||
|
@ -347,6 +365,7 @@ class ExchangeCardState extends State<ExchangeCard> {
|
|||
child: Padding(
|
||||
padding: EdgeInsets.only(top: 20),
|
||||
child: AddressTextField(
|
||||
key: ValueKey('${_cardInstanceName}_editable_address_textfield_key'),
|
||||
focusNode: widget.addressFocusNode,
|
||||
controller: addressController,
|
||||
onURIScanned: (uri) {
|
||||
|
@ -387,6 +406,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),
|
||||
|
@ -410,6 +431,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(
|
||||
|
@ -447,6 +470,7 @@ 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));
|
||||
|
@ -470,6 +494,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,
|
||||
|
|
|
@ -32,7 +32,7 @@ class AddressTextField extends StatelessWidget {
|
|||
this.onPushPasteButton,
|
||||
this.onPushAddressBookButton,
|
||||
this.onSelectedContact,
|
||||
this.selectedCurrency});
|
||||
this.selectedCurrency, super.key});
|
||||
|
||||
static const prefixIconWidth = 34.0;
|
||||
static const prefixIconHeight = 34.0;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -11,6 +11,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 +154,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 +191,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 +208,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 +219,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 +249,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 +268,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 +284,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,
|
||||
|
@ -297,6 +307,7 @@ class _PickerState<Item> extends State<Picker<Item>> {
|
|||
final item = widget.headerEnabled ? filteredItems[index] : items[index];
|
||||
|
||||
final tag = item is Currency ? item.tag : null;
|
||||
final currencyName = item is Currency ? item.name : '';
|
||||
final icon = _getItemIcon(item);
|
||||
|
||||
final image = images.isNotEmpty ? filteredImages[index] : icon;
|
||||
|
@ -316,6 +327,7 @@ class _PickerState<Item> extends State<Picker<Item>> {
|
|||
children: [
|
||||
Flexible(
|
||||
child: Text(
|
||||
key: ValueKey('picker_items_index_${currencyName}_text_key'),
|
||||
widget.displayItem?.call(item) ?? item.toString(),
|
||||
softWrap: true,
|
||||
style: TextStyle(
|
||||
|
@ -335,6 +347,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 +371,7 @@ class _PickerState<Item> extends State<Picker<Item>> {
|
|||
);
|
||||
|
||||
return GestureDetector(
|
||||
key: ValueKey('picker_items_index_${currencyName}_button_key'),
|
||||
onTap: () {
|
||||
if (widget.closeOnItemSelected) Navigator.of(context).pop();
|
||||
onItemSelected(item!);
|
||||
|
@ -383,6 +397,7 @@ class _PickerState<Item> extends State<Picker<Item>> {
|
|||
final item = items[index];
|
||||
|
||||
final tag = item is Currency ? item.tag : null;
|
||||
final currencyName = item is Currency ? item.name : '';
|
||||
final icon = _getItemIcon(item);
|
||||
|
||||
final image = images.isNotEmpty ? images[index] : icon;
|
||||
|
@ -390,6 +405,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 +418,7 @@ class _PickerState<Item> extends State<Picker<Item>> {
|
|||
children: [
|
||||
Flexible(
|
||||
child: Text(
|
||||
key: ValueKey('picker_items_index_${currencyName}_selected_item_text_key'),
|
||||
widget.displayItem?.call(item) ?? item.toString(),
|
||||
softWrap: true,
|
||||
style: TextStyle(
|
||||
|
@ -445,6 +462,7 @@ class _PickerState<Item> extends State<Picker<Item>> {
|
|||
);
|
||||
|
||||
return GestureDetector(
|
||||
key: ValueKey('picker_items_index_${currencyName}_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,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
|
|
@ -7,6 +7,7 @@ class SearchBarWidget extends StatelessWidget {
|
|||
required this.searchController,
|
||||
this.hintText,
|
||||
this.borderRadius = 14,
|
||||
super.key,
|
||||
});
|
||||
|
||||
final TextEditingController searchController;
|
||||
|
|
Loading…
Reference in a new issue