make swap scrollable on smaller devices (#3139)

malik1004x committed Mar 27, 2026 at 16:50 UTC ba9e8d7b7fb188e35da92a485e60b186d28993dc
1 file changed +131 -125
lib/new-ui/pages/swap_page.dart
+131 -125
@@ -481,134 +481,140 @@ class _NewSwapPageState extends State<NewSwapPage> {
481 mainAxisAlignment: MainAxisAlignment.spaceBetween,
482 mainAxisSize: MainAxisSize.max,
483 children: [
484 - RepaintBoundary(
485 - child: Form(
486 - key: formKey,
487 - child: Column(
488 - children: [
489 - Observer(
490 - builder: (_) => SwapAmountBox(
491 - isReceiverCard: false,
492 - walletSwitcherViewModel: widget.walletSwitcherViewModel,
493 - exchangeViewModel: widget.exchangeViewModel,
494 - onDispose: disposeBestRateSync,
495 - hasAllAmount: widget.exchangeViewModel.hasAllAmount,
496 - allAmount: widget.exchangeViewModel.hasAllAmount
497 - ? () => widget.exchangeViewModel.enableSendAllAmount()
498 - : null,
499 - key: depositKey,
500 - title: S.of(context).send,
501 - initialCurrency: widget.exchangeViewModel.depositCurrency,
502 - hasRefundAddress: true,
503 - currencies: widget.exchangeViewModel.depositCurrencies,
504 - onCurrencySelected: (currency) {
505 - if (currency is CryptoCurrency) {
506 - widget.exchangeViewModel
507 - .changeDepositCurrency(currency: currency);
508 - }
509 - },
510 - currencyValueValidator: (value) {
511 - return !widget.exchangeViewModel.isFixedRateMode &&
512 - value != S.of(context).all
513 - ? AmountValidator(
514 - isAutovalidate: true,
515 - currency: widget.exchangeViewModel.isFixedRateMode
516 - ? widget.exchangeViewModel.receiveCurrency
517 - : widget.exchangeViewModel.depositCurrency,
518 - minValue: widget.exchangeViewModel.limits.min.toString(),
519 - maxValue: widget.exchangeViewModel.limits.max.toString(),
520 - amountParsingProxy:
521 - widget.exchangeViewModel.amountParsingProxy,
522 - ).call(value)
523 - : null;
524 - },
525 - addressTextFieldValidator: AddressValidator(
526 - type: widget.exchangeViewModel.depositCurrency),
527 - onPushPasteButton: (context) async {
528 - final clipboard = await Clipboard.getData('text/plain');
529 - widget.exchangeViewModel.depositAddress = clipboard?.text ?? '';
530 -
531 - final domain = widget.exchangeViewModel.depositAddress;
532 - widget.exchangeViewModel.depositAddress =
533 - await fetchParsedAddress(context, domain,
534 - widget.exchangeViewModel.depositCurrency);
535 - },
536 - onPushAddressBookButton: (context) async {
537 - final domain = widget.exchangeViewModel.depositAddress;
538 - widget.exchangeViewModel.depositAddress =
539 - await fetchParsedAddress(context, domain,
540 - widget.exchangeViewModel.depositCurrency);
541 - },
542 - ),
543 - ),
544 - SwapLimitPopup(exchangeViewModel: widget.exchangeViewModel),
545 - Padding(
546 - padding: const EdgeInsets.symmetric(vertical: 12.0),
547 - child: Stack(
548 - alignment: Alignment.center,
549 - children: [
550 - Container(
551 - height: 1,
552 - width: double.infinity,
553 - color: Theme.of(context).colorScheme.surfaceContainerHigh,
484 + Expanded(
485 + child: RepaintBoundary(
486 + child: Form(
487 + key: formKey,
488 + child: SingleChildScrollView(
489 + physics: ClampingScrollPhysics(),
490 + controller: ModalScrollController.of(context),
491 + child: Column(
492 + children: [
493 + Observer(
494 + builder: (_) => SwapAmountBox(
495 + isReceiverCard: false,
496 + walletSwitcherViewModel: widget.walletSwitcherViewModel,
497 + exchangeViewModel: widget.exchangeViewModel,
498 + onDispose: disposeBestRateSync,
499 + hasAllAmount: widget.exchangeViewModel.hasAllAmount,
500 + allAmount: widget.exchangeViewModel.hasAllAmount
501 + ? () => widget.exchangeViewModel.enableSendAllAmount()
502 + : null,
503 + key: depositKey,
504 + title: S.of(context).send,
505 + initialCurrency: widget.exchangeViewModel.depositCurrency,
506 + hasRefundAddress: true,
507 + currencies: widget.exchangeViewModel.depositCurrencies,
508 + onCurrencySelected: (currency) {
509 + if (currency is CryptoCurrency) {
510 + widget.exchangeViewModel
511 + .changeDepositCurrency(currency: currency);
512 + }
513 + },
514 + currencyValueValidator: (value) {
515 + return !widget.exchangeViewModel.isFixedRateMode &&
516 + value != S.of(context).all
517 + ? AmountValidator(
518 + isAutovalidate: true,
519 + currency: widget.exchangeViewModel.isFixedRateMode
520 + ? widget.exchangeViewModel.receiveCurrency
521 + : widget.exchangeViewModel.depositCurrency,
522 + minValue: widget.exchangeViewModel.limits.min.toString(),
523 + maxValue: widget.exchangeViewModel.limits.max.toString(),
524 + amountParsingProxy:
525 + widget.exchangeViewModel.amountParsingProxy,
526 + ).call(value)
527 + : null;
528 + },
529 + addressTextFieldValidator: AddressValidator(
530 + type: widget.exchangeViewModel.depositCurrency),
531 + onPushPasteButton: (context) async {
532 + final clipboard = await Clipboard.getData('text/plain');
533 + widget.exchangeViewModel.depositAddress = clipboard?.text ?? '';
534 +
535 + final domain = widget.exchangeViewModel.depositAddress;
536 + widget.exchangeViewModel.depositAddress =
537 + await fetchParsedAddress(context, domain,
538 + widget.exchangeViewModel.depositCurrency);
539 + },
540 + onPushAddressBookButton: (context) async {
541 + final domain = widget.exchangeViewModel.depositAddress;
542 + widget.exchangeViewModel.depositAddress =
543 + await fetchParsedAddress(context, domain,
544 + widget.exchangeViewModel.depositCurrency);
545 + },
546 ),
555 - ModernButton.svg(
556 - size: 36,
557 - iconSize: 24,
558 - svgPath: "assets/new-ui/swap_amounts.svg",
559 - onPressed: widget.exchangeViewModel.reverseSwapDirection,
547 + ),
548 + SwapLimitPopup(exchangeViewModel: widget.exchangeViewModel),
549 + Padding(
550 + padding: const EdgeInsets.symmetric(vertical: 12.0),
551 + child: Stack(
552 + alignment: Alignment.center,
553 + children: [
554 + Container(
555 + height: 1,
556 + width: double.infinity,
557 + color: Theme.of(context).colorScheme.surfaceContainerHigh,
558 + ),
559 + ModernButton.svg(
560 + size: 36,
561 + iconSize: 24,
562 + svgPath: "assets/new-ui/swap_amounts.svg",
563 + onPressed: widget.exchangeViewModel.reverseSwapDirection,
564 + ),
565 + ],
566 ),
561 - ],
562 - ),
567 + ),
568 + Observer(
569 + builder: (_) => SwapAmountBox(
570 + isReceiverCard: true,
571 + walletSwitcherViewModel: widget.walletSwitcherViewModel,
572 + exchangeViewModel: widget.exchangeViewModel,
573 + onDispose: disposeBestRateSync,
574 + key: receiveKey,
575 + title: S.of(context).receive,
576 + initialCurrency: widget.exchangeViewModel.receiveCurrency,
577 + currencies: widget.exchangeViewModel.receiveCurrencies,
578 + onCurrencySelected: (currency) {
579 + if (currency is CryptoCurrency) {
580 + widget.exchangeViewModel
581 + .changeReceiveCurrency(currency: currency);
582 + }
583 + },
584 + currencyValueValidator: (value) {
585 + return widget.exchangeViewModel.isFixedRateMode
586 + ? AmountValidator(
587 + isAutovalidate: true,
588 + currency: widget.exchangeViewModel.receiveCurrency,
589 + minValue: widget.exchangeViewModel.limits.min.toString(),
590 + maxValue: widget.exchangeViewModel.limits.max.toString(),
591 + amountParsingProxy:
592 + widget.exchangeViewModel.amountParsingProxy,
593 + ).call(value)
594 + : null;
595 + },
596 + addressTextFieldValidator: AddressValidator(
597 + type: widget.exchangeViewModel.receiveCurrency),
598 + onPushPasteButton: (context) async {
599 + final clipboard = await Clipboard.getData('text/plain');
600 + widget.exchangeViewModel.receiveAddress = clipboard?.text ?? '';
601 +
602 + final domain = widget.exchangeViewModel.receiveAddress;
603 + widget.exchangeViewModel.receiveAddress =
604 + await fetchParsedAddress(context, domain,
605 + widget.exchangeViewModel.receiveCurrency);
606 + },
607 + onPushAddressBookButton: (context) async {
608 + final domain = widget.exchangeViewModel.receiveAddress;
609 + widget.exchangeViewModel.receiveAddress =
610 + await fetchParsedAddress(context, domain,
611 + widget.exchangeViewModel.receiveCurrency);
612 + },
613 + ),
614 + )
615 + ],
616 ),
564 - Observer(
565 - builder: (_) => SwapAmountBox(
566 - isReceiverCard: true,
567 - walletSwitcherViewModel: widget.walletSwitcherViewModel,
568 - exchangeViewModel: widget.exchangeViewModel,
569 - onDispose: disposeBestRateSync,
570 - key: receiveKey,
571 - title: S.of(context).receive,
572 - initialCurrency: widget.exchangeViewModel.receiveCurrency,
573 - currencies: widget.exchangeViewModel.receiveCurrencies,
574 - onCurrencySelected: (currency) {
575 - if (currency is CryptoCurrency) {
576 - widget.exchangeViewModel
577 - .changeReceiveCurrency(currency: currency);
578 - }
579 - },
580 - currencyValueValidator: (value) {
581 - return widget.exchangeViewModel.isFixedRateMode
582 - ? AmountValidator(
583 - isAutovalidate: true,
584 - currency: widget.exchangeViewModel.receiveCurrency,
585 - minValue: widget.exchangeViewModel.limits.min.toString(),
586 - maxValue: widget.exchangeViewModel.limits.max.toString(),
587 - amountParsingProxy:
588 - widget.exchangeViewModel.amountParsingProxy,
589 - ).call(value)
590 - : null;
591 - },
592 - addressTextFieldValidator: AddressValidator(
593 - type: widget.exchangeViewModel.receiveCurrency),
594 - onPushPasteButton: (context) async {
595 - final clipboard = await Clipboard.getData('text/plain');
596 - widget.exchangeViewModel.receiveAddress = clipboard?.text ?? '';
597 -
598 - final domain = widget.exchangeViewModel.receiveAddress;
599 - widget.exchangeViewModel.receiveAddress =
600 - await fetchParsedAddress(context, domain,
601 - widget.exchangeViewModel.receiveCurrency);
602 - },
603 - onPushAddressBookButton: (context) async {
604 - final domain = widget.exchangeViewModel.receiveAddress;
605 - widget.exchangeViewModel.receiveAddress =
606 - await fetchParsedAddress(context, domain,
607 - widget.exchangeViewModel.receiveCurrency);
608 - },
609 - ),
610 - )
611 - ],
617 + ),
618 ),
619 ),
620 ),