From c15cb7fc9f659696ef558a83a920cf686f57fe63 Mon Sep 17 00:00:00 2001 From: Matthew Fosse Date: Fri, 31 Jan 2025 14:15:58 -0800 Subject: [PATCH 1/9] [skip-ci] wip --- lib/src/screens/send/widgets/send_card.dart | 38 +++++++++++++++++++++ lib/view_model/send/send_view_model.dart | 12 +++++-- res/values/strings_ar.arb | 1 + res/values/strings_bg.arb | 1 + res/values/strings_cs.arb | 1 + res/values/strings_de.arb | 1 + res/values/strings_en.arb | 1 + res/values/strings_es.arb | 1 + res/values/strings_fr.arb | 1 + res/values/strings_ha.arb | 1 + res/values/strings_hi.arb | 1 + res/values/strings_hr.arb | 1 + res/values/strings_hy.arb | 1 + res/values/strings_id.arb | 1 + res/values/strings_it.arb | 1 + res/values/strings_ja.arb | 1 + res/values/strings_ko.arb | 1 + res/values/strings_my.arb | 1 + res/values/strings_nl.arb | 1 + res/values/strings_pl.arb | 1 + res/values/strings_pt.arb | 1 + res/values/strings_ru.arb | 1 + res/values/strings_th.arb | 1 + res/values/strings_tl.arb | 1 + res/values/strings_tr.arb | 1 + res/values/strings_uk.arb | 1 + res/values/strings_ur.arb | 1 + res/values/strings_vi.arb | 1 + res/values/strings_yo.arb | 1 + res/values/strings_zh.arb | 1 + 30 files changed, 76 insertions(+), 2 deletions(-) diff --git a/lib/src/screens/send/widgets/send_card.dart b/lib/src/screens/send/widgets/send_card.dart index 0713fb8c45..472f707e3a 100644 --- a/lib/src/screens/send/widgets/send_card.dart +++ b/lib/src/screens/send/widgets/send_card.dart @@ -12,6 +12,7 @@ import 'package:cake_wallet/routes.dart'; import 'package:cake_wallet/src/widgets/keyboard_done_button.dart'; import 'package:cake_wallet/view_model/send/output.dart'; import 'package:cw_core/transaction_priority.dart'; +import 'package:cw_core/unspent_coin_type.dart'; import 'package:cw_core/wallet_type.dart'; import 'package:flutter/material.dart'; import 'package:flutter_mobx/flutter_mobx.dart'; @@ -398,6 +399,43 @@ class SendCardState extends State with AutomaticKeepAliveClientMixin Padding( + padding: EdgeInsets.only(top: 6), + child: GestureDetector( + key: ValueKey('send_page_unspent_coin_button_key'), + onTap: () { + bool value = + widget.sendViewModel.coinTypeToSpendFrom == UnspentCoinType.any; + print("setting allow mweb coins to ${!value}"); + sendViewModel.setAllowMwebCoins(!value); + }, + child: Container( + color: Colors.transparent, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + S.of(context).litecoin_mweb_allow_coins, + style: TextStyle( + fontSize: 12, + fontWeight: FontWeight.w600, + color: Colors.white), + ), + Checkbox( + value: widget.sendViewModel.coinTypeToSpendFrom == + UnspentCoinType.any, + onChanged: (bool? value) { + sendViewModel.setAllowMwebCoins(value ?? false); + }, + ), + ], + ), + ), + ), + ), + ), ], ), ), diff --git a/lib/view_model/send/send_view_model.dart b/lib/view_model/send/send_view_model.dart index 53c52aa1e7..4d9af5894b 100644 --- a/lib/view_model/send/send_view_model.dart +++ b/lib/view_model/send/send_view_model.dart @@ -77,7 +77,7 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor this.transactionDescriptionBox, this.ledgerViewModel, this.unspentCoinsListViewModel, { - this.coinTypeToSpendFrom = UnspentCoinType.any, + this.coinTypeToSpendFrom = UnspentCoinType.nonMweb, }) : state = InitialExecutionState(), currencies = appStore.wallet!.balance.keys.toList(), selectedCryptoCurrency = appStore.wallet!.currency, @@ -110,7 +110,8 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor ObservableList outputs; - final UnspentCoinType coinTypeToSpendFrom; + @observable + UnspentCoinType coinTypeToSpendFrom; bool get showAddressBookPopup => _settingsStore.showAddressBookPopupEnabled; @@ -133,6 +134,13 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor addOutput(); } + @action + void setAllowMwebCoins(bool allow) { + if (wallet.type == WalletType.litecoin) { + coinTypeToSpendFrom = allow ? UnspentCoinType.any : UnspentCoinType.nonMweb; + } + } + @computed bool get isBatchSending => outputs.length > 1; diff --git a/res/values/strings_ar.arb b/res/values/strings_ar.arb index 0deacecdb9..12427359b7 100644 --- a/res/values/strings_ar.arb +++ b/res/values/strings_ar.arb @@ -392,6 +392,7 @@ "light_theme": "فاتح", "litecoin_enable_mweb_sync": "تمكين MWEB المسح الضوئي", "litecoin_mweb": "mweb", + "litecoin_mweb_allow_coins": "السماح للعملات المعدنية MWEB", "litecoin_mweb_always_scan": "اضبط MWEB دائمًا على المسح الضوئي", "litecoin_mweb_description": "MWEB هو بروتوكول جديد يجلب معاملات أسرع وأرخص وأكثر خصوصية إلى Litecoin", "litecoin_mweb_dismiss": "رفض", diff --git a/res/values/strings_bg.arb b/res/values/strings_bg.arb index 5b4dc54509..3c106f450d 100644 --- a/res/values/strings_bg.arb +++ b/res/values/strings_bg.arb @@ -392,6 +392,7 @@ "light_theme": "Светло", "litecoin_enable_mweb_sync": "Активирайте сканирането на MWeb", "litecoin_mweb": "Mweb", + "litecoin_mweb_allow_coins": "Позволете на MWeb монети", "litecoin_mweb_always_scan": "Задайте MWeb винаги сканиране", "litecoin_mweb_description": "MWeb е нов протокол, който носи по -бърз, по -евтин и повече частни транзакции на Litecoin", "litecoin_mweb_dismiss": "Уволнение", diff --git a/res/values/strings_cs.arb b/res/values/strings_cs.arb index 14028a9574..fd4e26d13a 100644 --- a/res/values/strings_cs.arb +++ b/res/values/strings_cs.arb @@ -392,6 +392,7 @@ "light_theme": "Světlý", "litecoin_enable_mweb_sync": "Povolit skenování MWeb", "litecoin_mweb": "MWeb", + "litecoin_mweb_allow_coins": "Povolte mweb mince", "litecoin_mweb_always_scan": "Nastavit MWeb vždy skenování", "litecoin_mweb_description": "MWEB je nový protokol, který do Litecoin přináší rychlejší, levnější a více soukromých transakcí", "litecoin_mweb_dismiss": "Propustit", diff --git a/res/values/strings_de.arb b/res/values/strings_de.arb index cbb55edcb4..c7d2cfe7e5 100644 --- a/res/values/strings_de.arb +++ b/res/values/strings_de.arb @@ -392,6 +392,7 @@ "light_theme": "Hell", "litecoin_enable_mweb_sync": "Aktivieren Sie das MWEB-Scannen", "litecoin_mweb": "MWeb", + "litecoin_mweb_allow_coins": "MWEB -Münzen zulassen", "litecoin_mweb_always_scan": "Setzen Sie MWeb immer scannen", "litecoin_mweb_description": "MWWB ist ein neues Protokoll, das schnellere, billigere und privatere Transaktionen zu Litecoin bringt", "litecoin_mweb_dismiss": "Zurückweisen", diff --git a/res/values/strings_en.arb b/res/values/strings_en.arb index 4a56bd1536..495e7bf6af 100644 --- a/res/values/strings_en.arb +++ b/res/values/strings_en.arb @@ -392,6 +392,7 @@ "light_theme": "Light", "litecoin_enable_mweb_sync": "Enable MWEB scanning", "litecoin_mweb": "MWEB", + "litecoin_mweb_allow_coins": "Allow MWEB coins", "litecoin_mweb_always_scan": "Set MWEB always scanning", "litecoin_mweb_description": "MWEB is a new protocol that brings faster, cheaper, and more private transactions to Litecoin", "litecoin_mweb_dismiss": "Dismiss", diff --git a/res/values/strings_es.arb b/res/values/strings_es.arb index bd324a979f..51ae172aa9 100644 --- a/res/values/strings_es.arb +++ b/res/values/strings_es.arb @@ -392,6 +392,7 @@ "light_theme": "Ligero", "litecoin_enable_mweb_sync": "Habilitar el escaneo mweb", "litecoin_mweb": "Mweb", + "litecoin_mweb_allow_coins": "Permitir monedas mweb", "litecoin_mweb_always_scan": "Establecer mweb siempre escaneo", "litecoin_mweb_description": "Mweb es un nuevo protocolo que trae transacciones más rápidas, más baratas y más privadas a Litecoin", "litecoin_mweb_dismiss": "Despedir", diff --git a/res/values/strings_fr.arb b/res/values/strings_fr.arb index edb79d5b4e..8048f9f41e 100644 --- a/res/values/strings_fr.arb +++ b/res/values/strings_fr.arb @@ -392,6 +392,7 @@ "light_theme": "Clair", "litecoin_enable_mweb_sync": "Activer la numérisation MWEB", "litecoin_mweb": "Mweb", + "litecoin_mweb_allow_coins": "Autoriser les pièces MWeb", "litecoin_mweb_always_scan": "Définir MWEB Score Scanning", "litecoin_mweb_description": "MWEB est un nouveau protocole qui apporte des transactions plus rapides, moins chères et plus privées à Litecoin", "litecoin_mweb_dismiss": "Rejeter", diff --git a/res/values/strings_ha.arb b/res/values/strings_ha.arb index 5a364a597d..5f8271c95b 100644 --- a/res/values/strings_ha.arb +++ b/res/values/strings_ha.arb @@ -392,6 +392,7 @@ "light_theme": "Haske", "litecoin_enable_mweb_sync": "Kunna binciken Mweb", "litecoin_mweb": "Mweb", + "litecoin_mweb_allow_coins": "Bada izinin Coins na Mweb", "litecoin_mweb_always_scan": "Saita Mweb koyaushe", "litecoin_mweb_description": "Mweb shine sabon tsarin yarjejeniya da ya kawo da sauri, mai rahusa, da kuma ma'amaloli masu zaman kansu zuwa Litecoin", "litecoin_mweb_dismiss": "Tuɓe \\ sallama", diff --git a/res/values/strings_hi.arb b/res/values/strings_hi.arb index 5d03cedd24..faf2de9b75 100644 --- a/res/values/strings_hi.arb +++ b/res/values/strings_hi.arb @@ -392,6 +392,7 @@ "light_theme": "रोशनी", "litecoin_enable_mweb_sync": "MWEB स्कैनिंग सक्षम करें", "litecoin_mweb": "मावली", + "litecoin_mweb_allow_coins": "MWEB सिक्कों की अनुमति दें", "litecoin_mweb_always_scan": "MWEB हमेशा स्कैनिंग सेट करें", "litecoin_mweb_description": "MWEB एक नया प्रोटोकॉल है जो लिटकोइन के लिए तेजी से, सस्ता और अधिक निजी लेनदेन लाता है", "litecoin_mweb_dismiss": "नकार देना", diff --git a/res/values/strings_hr.arb b/res/values/strings_hr.arb index d98716592f..ce92bee491 100644 --- a/res/values/strings_hr.arb +++ b/res/values/strings_hr.arb @@ -392,6 +392,7 @@ "light_theme": "Svijetla", "litecoin_enable_mweb_sync": "Omogućite MWEB skeniranje", "litecoin_mweb": "MWeb", + "litecoin_mweb_allow_coins": "Dopustite MWeb kovanice", "litecoin_mweb_always_scan": "Postavite MWeb uvijek skeniranje", "litecoin_mweb_description": "MWEB je novi protokol koji u Litecoin donosi brže, jeftinije i privatnije transakcije", "litecoin_mweb_dismiss": "Odbaciti", diff --git a/res/values/strings_hy.arb b/res/values/strings_hy.arb index 5a445f4807..f461b1251a 100644 --- a/res/values/strings_hy.arb +++ b/res/values/strings_hy.arb @@ -392,6 +392,7 @@ "light_theme": "Լուսավոր", "litecoin_enable_mweb_sync": "Միացնել MWEB սկան", "litecoin_mweb": "Մուեբ", + "litecoin_mweb_allow_coins": "Թույլ տվեք MWeb մետաղադրամներ", "litecoin_mweb_always_scan": "Սահմանեք Mweb Միշտ սկանավորում", "litecoin_mweb_description": "Mweb- ը նոր արձանագրություն է, որը բերում է ավելի արագ, ավելի էժան եւ ավելի մասնավոր գործարքներ դեպի LITECOIN", "litecoin_mweb_dismiss": "Հեռացնել", diff --git a/res/values/strings_id.arb b/res/values/strings_id.arb index 9694648f92..c1fb77c6df 100644 --- a/res/values/strings_id.arb +++ b/res/values/strings_id.arb @@ -392,6 +392,7 @@ "light_theme": "Terang", "litecoin_enable_mweb_sync": "Aktifkan pemindaian MWEB", "litecoin_mweb": "Mweb", + "litecoin_mweb_allow_coins": "Izinkan koin mWeb", "litecoin_mweb_always_scan": "Atur mWeb selalu memindai", "litecoin_mweb_description": "MWEB adalah protokol baru yang membawa transaksi yang lebih cepat, lebih murah, dan lebih pribadi ke Litecoin", "litecoin_mweb_dismiss": "Membubarkan", diff --git a/res/values/strings_it.arb b/res/values/strings_it.arb index deb4966ff3..4e753b3dbe 100644 --- a/res/values/strings_it.arb +++ b/res/values/strings_it.arb @@ -393,6 +393,7 @@ "light_theme": "Bianco", "litecoin_enable_mweb_sync": "Abilita la scansione MWeb", "litecoin_mweb": "MWeb", + "litecoin_mweb_allow_coins": "Consenti monete mWeb", "litecoin_mweb_always_scan": "Imposta MWeb per scansionare sempre", "litecoin_mweb_description": "MWeb è un nuovo protocollo che porta transazioni più veloci, più economiche e più private a Litecoin", "litecoin_mweb_dismiss": "Congedare", diff --git a/res/values/strings_ja.arb b/res/values/strings_ja.arb index ce09474fb9..fb8a3a6399 100644 --- a/res/values/strings_ja.arb +++ b/res/values/strings_ja.arb @@ -393,6 +393,7 @@ "light_theme": "光", "litecoin_enable_mweb_sync": "MWEBスキャンを有効にします", "litecoin_mweb": "mweb", + "litecoin_mweb_allow_coins": "MWEBコインを許可します", "litecoin_mweb_always_scan": "MWEBを常にスキャンします", "litecoin_mweb_description": "MWEBは、Litecoinにより速く、より安価で、よりプライベートなトランザクションをもたらす新しいプロトコルです", "litecoin_mweb_dismiss": "却下する", diff --git a/res/values/strings_ko.arb b/res/values/strings_ko.arb index d91cfd5db9..2e0650d973 100644 --- a/res/values/strings_ko.arb +++ b/res/values/strings_ko.arb @@ -392,6 +392,7 @@ "light_theme": "빛", "litecoin_enable_mweb_sync": "mweb 스캔을 활성화합니다", "litecoin_mweb": "mweb", + "litecoin_mweb_allow_coins": "mweb 코인을 허용하십시오", "litecoin_mweb_always_scan": "mweb는 항상 스캔을 설정합니다", "litecoin_mweb_description": "MWEB는 Litecoin에 더 빠르고 저렴하며 개인 거래를 제공하는 새로운 프로토콜입니다.", "litecoin_mweb_dismiss": "해고하다", diff --git a/res/values/strings_my.arb b/res/values/strings_my.arb index 66adf87cfe..955587a1f5 100644 --- a/res/values/strings_my.arb +++ b/res/values/strings_my.arb @@ -392,6 +392,7 @@ "light_theme": "အလင်း", "litecoin_enable_mweb_sync": "mweb scanning ဖွင့်ပါ", "litecoin_mweb": "မင်္ဂလာပါ", + "litecoin_mweb_allow_coins": "mweb ဒင်္ဂါးများကိုခွင့်ပြုပါ", "litecoin_mweb_always_scan": "Mweb အမြဲစကင်ဖတ်စစ်ဆေးပါ", "litecoin_mweb_description": "Mweb သည် Protocol အသစ်ဖြစ်ပြီး LitCoin သို့ပိုမိုဈေးချိုသာသော, စျေးသက်သက်သာသာသုံးခြင်းနှင့်ပိုမိုများပြားသောပုဂ္ဂလိကငွေပို့ဆောင်မှုများကိုဖြစ်ပေါ်စေသည်", "litecoin_mweb_dismiss": "ထုတ်ပစ်", diff --git a/res/values/strings_nl.arb b/res/values/strings_nl.arb index 4efae69e0c..95e216d388 100644 --- a/res/values/strings_nl.arb +++ b/res/values/strings_nl.arb @@ -392,6 +392,7 @@ "light_theme": "Licht", "litecoin_enable_mweb_sync": "MWEB -scanning inschakelen", "litecoin_mweb": "Mweb", + "litecoin_mweb_allow_coins": "Sta mweb munten toe", "litecoin_mweb_always_scan": "Stel mweb altijd op scannen", "litecoin_mweb_description": "MWEB is een nieuw protocol dat snellere, goedkopere en meer privé -transacties naar Litecoin brengt", "litecoin_mweb_dismiss": "Afwijzen", diff --git a/res/values/strings_pl.arb b/res/values/strings_pl.arb index dee3de98f9..085b69cfe5 100644 --- a/res/values/strings_pl.arb +++ b/res/values/strings_pl.arb @@ -392,6 +392,7 @@ "light_theme": "Jasny", "litecoin_enable_mweb_sync": "Włącz skanowanie MWEB", "litecoin_mweb": "MWEB", + "litecoin_mweb_allow_coins": "Zezwalaj na monety MWEB", "litecoin_mweb_always_scan": "Ustaw MWEB zawsze skanowanie", "litecoin_mweb_description": "MWEB to nowy protokół, który przynosi szybciej, tańsze i bardziej prywatne transakcje do Litecoin", "litecoin_mweb_dismiss": "Odrzucać", diff --git a/res/values/strings_pt.arb b/res/values/strings_pt.arb index c6ca230081..987496f1d3 100644 --- a/res/values/strings_pt.arb +++ b/res/values/strings_pt.arb @@ -392,6 +392,7 @@ "light_theme": "Luz", "litecoin_enable_mweb_sync": "Ativar digitalização do MWEB", "litecoin_mweb": "Mweb", + "litecoin_mweb_allow_coins": "Permitir moedas MWEB", "litecoin_mweb_always_scan": "Definir mweb sempre digitalizando", "litecoin_mweb_description": "MWEB é um novo protocolo que traz transações mais rápidas, baratas e mais privadas para o Litecoin", "litecoin_mweb_dismiss": "Liberar", diff --git a/res/values/strings_ru.arb b/res/values/strings_ru.arb index 0d73e11595..61bd1c8418 100644 --- a/res/values/strings_ru.arb +++ b/res/values/strings_ru.arb @@ -392,6 +392,7 @@ "light_theme": "Светлая", "litecoin_enable_mweb_sync": "Включить MWEB сканирование", "litecoin_mweb": "Мвеб", + "litecoin_mweb_allow_coins": "Разрешить монеты MWEB", "litecoin_mweb_always_scan": "Установить MWEB всегда сканирование", "litecoin_mweb_description": "MWEB - это новый протокол, который приносит быстрее, дешевле и более частные транзакции в Litecoin", "litecoin_mweb_dismiss": "Увольнять", diff --git a/res/values/strings_th.arb b/res/values/strings_th.arb index cba8349035..e5349823dd 100644 --- a/res/values/strings_th.arb +++ b/res/values/strings_th.arb @@ -392,6 +392,7 @@ "light_theme": "สว่าง", "litecoin_enable_mweb_sync": "เปิดใช้งานการสแกน MWEB", "litecoin_mweb": "mweb", + "litecoin_mweb_allow_coins": "อนุญาตให้เหรียญ MWEB", "litecoin_mweb_always_scan": "ตั้งค่าการสแกน MWEB เสมอ", "litecoin_mweb_description": "MWEB เป็นโปรโตคอลใหม่ที่นำการทำธุรกรรมที่เร็วกว่าราคาถูกกว่าและเป็นส่วนตัวมากขึ้นไปยัง Litecoin", "litecoin_mweb_dismiss": "อนุญาตให้ออกไป", diff --git a/res/values/strings_tl.arb b/res/values/strings_tl.arb index a033bd26c1..08aa264a0c 100644 --- a/res/values/strings_tl.arb +++ b/res/values/strings_tl.arb @@ -392,6 +392,7 @@ "light_theme": "Light", "litecoin_enable_mweb_sync": "Paganahin ang pag -scan ng MWeb", "litecoin_mweb": "Mweb", + "litecoin_mweb_allow_coins": "Payagan ang mga barya ng MWEB", "litecoin_mweb_always_scan": "Itakda ang MWeb na laging nag -scan", "litecoin_mweb_description": "Ang MWeb ay isang bagong protocol na nagdadala ng mas mabilis, mas mura, at mas maraming pribadong mga transaksyon sa Litecoin", "litecoin_mweb_dismiss": "Tanggalin", diff --git a/res/values/strings_tr.arb b/res/values/strings_tr.arb index 6ba032d786..1bdda3b110 100644 --- a/res/values/strings_tr.arb +++ b/res/values/strings_tr.arb @@ -392,6 +392,7 @@ "light_theme": "Aydınlık", "litecoin_enable_mweb_sync": "MWEB taramasını etkinleştir", "litecoin_mweb": "Mweb", + "litecoin_mweb_allow_coins": "MWEB Coins'e izin ver", "litecoin_mweb_always_scan": "MWEB'i her zaman taramayı ayarlayın", "litecoin_mweb_description": "MWEB, Litecoin'e daha hızlı, daha ucuz ve daha fazla özel işlem getiren yeni bir protokoldür", "litecoin_mweb_dismiss": "Azletmek", diff --git a/res/values/strings_uk.arb b/res/values/strings_uk.arb index 6a3d72ad35..24f6a0448c 100644 --- a/res/values/strings_uk.arb +++ b/res/values/strings_uk.arb @@ -392,6 +392,7 @@ "light_theme": "Світла", "litecoin_enable_mweb_sync": "Увімкнути сканування MWEB", "litecoin_mweb": "Мвеб", + "litecoin_mweb_allow_coins": "Дозволити монети MWEB", "litecoin_mweb_always_scan": "Встановити mweb завжди сканувати", "litecoin_mweb_description": "MWEB - це новий протокол, який приносить швидкі, дешевші та більш приватні транзакції Litecoin", "litecoin_mweb_dismiss": "Звільнити", diff --git a/res/values/strings_ur.arb b/res/values/strings_ur.arb index ae129b8990..b86a4213b9 100644 --- a/res/values/strings_ur.arb +++ b/res/values/strings_ur.arb @@ -392,6 +392,7 @@ "light_theme": "روشنی", "litecoin_enable_mweb_sync": "MWEB اسکیننگ کو فعال کریں", "litecoin_mweb": "MWEB", + "litecoin_mweb_allow_coins": "MWEB سکے کی اجازت دیں", "litecoin_mweb_always_scan": "MWEB ہمیشہ اسکیننگ سیٹ کریں", "litecoin_mweb_description": "MWEB ایک نیا پروٹوکول ہے جو لیٹیکوئن میں تیز ، سستا اور زیادہ نجی لین دین لاتا ہے", "litecoin_mweb_dismiss": "خارج", diff --git a/res/values/strings_vi.arb b/res/values/strings_vi.arb index 5a9f39947d..be1bdfbcf5 100644 --- a/res/values/strings_vi.arb +++ b/res/values/strings_vi.arb @@ -391,6 +391,7 @@ "light_theme": "Chủ đề sáng", "litecoin_enable_mweb_sync": "Bật quét MWEB", "litecoin_mweb": "Mweb", + "litecoin_mweb_allow_coins": "Cho phép tiền xu MWEB", "litecoin_mweb_always_scan": "Đặt MWEB luôn quét", "litecoin_mweb_description": "MWEB là một giao thức mới mang lại các giao dịch nhanh hơn, rẻ hơn và riêng tư hơn cho Litecoin", "litecoin_mweb_dismiss": "Miễn nhiệm", diff --git a/res/values/strings_yo.arb b/res/values/strings_yo.arb index a962a66d77..26c34cf634 100644 --- a/res/values/strings_yo.arb +++ b/res/values/strings_yo.arb @@ -393,6 +393,7 @@ "light_theme": "Funfun bí eérú", "litecoin_enable_mweb_sync": "Mu mweb ọlọjẹ", "litecoin_mweb": "Mweb", + "litecoin_mweb_allow_coins": "Gba awọn owo Mweb gba", "litecoin_mweb_always_scan": "Ṣeto mweb nigbagbogbo n ṣayẹwo", "litecoin_mweb_description": "Mweb jẹ ilana ilana tuntun ti o mu iyara wa yiyara, din owo, ati awọn iṣowo ikọkọ diẹ sii si Livcoin", "litecoin_mweb_dismiss": "Tuka", diff --git a/res/values/strings_zh.arb b/res/values/strings_zh.arb index f0a5e390ff..22fb074a86 100644 --- a/res/values/strings_zh.arb +++ b/res/values/strings_zh.arb @@ -392,6 +392,7 @@ "light_theme": "艳丽", "litecoin_enable_mweb_sync": "启用MWEB扫描", "litecoin_mweb": "MWEB", + "litecoin_mweb_allow_coins": "允许MWEB硬币", "litecoin_mweb_always_scan": "设置MWEB总是扫描", "litecoin_mweb_description": "MWEB是一项新协议,它将更快,更便宜和更多的私人交易带给Litecoin", "litecoin_mweb_dismiss": "解雇", From 8f232f1c155404aadf7eb3308d4bcca6f44f4247 Mon Sep 17 00:00:00 2001 From: Matthew Fosse Date: Fri, 31 Jan 2025 14:41:35 -0800 Subject: [PATCH 2/9] [skip-ci] styles still need updating --- lib/src/screens/send/widgets/send_card.dart | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/lib/src/screens/send/widgets/send_card.dart b/lib/src/screens/send/widgets/send_card.dart index 472f707e3a..caed9e779e 100644 --- a/lib/src/screens/send/widgets/send_card.dart +++ b/lib/src/screens/send/widgets/send_card.dart @@ -1,6 +1,7 @@ import 'package:cake_wallet/entities/priority_for_wallet_type.dart'; import 'package:cake_wallet/src/screens/receive/widgets/currency_input_field.dart'; import 'package:cake_wallet/src/widgets/picker.dart'; +import 'package:cake_wallet/src/widgets/standard_checkbox.dart'; import 'package:cake_wallet/themes/extensions/keyboard_theme.dart'; import 'package:cake_wallet/src/screens/exchange/widgets/currency_picker.dart'; import 'package:cake_wallet/src/widgets/alert_with_one_action.dart'; @@ -416,14 +417,15 @@ class SendCardState extends State with AutomaticKeepAliveClientMixin Date: Fri, 31 Jan 2025 14:49:58 -0800 Subject: [PATCH 3/9] working but needs style updates --- lib/src/screens/send/widgets/send_card.dart | 8 -------- 1 file changed, 8 deletions(-) diff --git a/lib/src/screens/send/widgets/send_card.dart b/lib/src/screens/send/widgets/send_card.dart index caed9e779e..a2bbbe2d00 100644 --- a/lib/src/screens/send/widgets/send_card.dart +++ b/lib/src/screens/send/widgets/send_card.dart @@ -409,7 +409,6 @@ class SendCardState extends State with AutomaticKeepAliveClientMixin with AutomaticKeepAliveClientMixin Date: Mon, 3 Feb 2025 13:40:35 -0800 Subject: [PATCH 4/9] fix checkbox caption color --- lib/src/screens/send/widgets/send_card.dart | 3 ++- lib/src/widgets/standard_checkbox.dart | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/src/screens/send/widgets/send_card.dart b/lib/src/screens/send/widgets/send_card.dart index a2bbbe2d00..d82dce470d 100644 --- a/lib/src/screens/send/widgets/send_card.dart +++ b/lib/src/screens/send/widgets/send_card.dart @@ -403,7 +403,7 @@ class SendCardState extends State with AutomaticKeepAliveClientMixin Padding( - padding: EdgeInsets.only(top: 6), + padding: EdgeInsets.only(top: 10), child: GestureDetector( key: ValueKey('send_page_unspent_coin_button_key'), onTap: () { @@ -418,6 +418,7 @@ class SendCardState extends State with AutomaticKeepAliveClientMixin()!.titleColor, + color: captionColor ?? Theme.of(context).extension()!.titleColor, decoration: TextDecoration.none, ), ), From 9f9ad3058441c2c53c84e686e9d0d589a5345eef Mon Sep 17 00:00:00 2001 From: Matthew Fosse Date: Tue, 11 Feb 2025 09:01:49 -0800 Subject: [PATCH 5/9] sort mweb coins to be last when selecting inputs --- cw_bitcoin/lib/electrum_wallet.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cw_bitcoin/lib/electrum_wallet.dart b/cw_bitcoin/lib/electrum_wallet.dart index e7b8be1560..80d732e603 100644 --- a/cw_bitcoin/lib/electrum_wallet.dart +++ b/cw_bitcoin/lib/electrum_wallet.dart @@ -632,8 +632,8 @@ abstract class ElectrumWalletBase }).toList(); final unconfirmedCoins = availableInputs.where((utx) => utx.confirmations == 0).toList(); - // sort the unconfirmed coins so that mweb coins are first: - availableInputs.sort((a, b) => a.bitcoinAddressRecord.type == SegwitAddresType.mweb ? -1 : 1); + // sort the unconfirmed coins so that mweb coins are last: + availableInputs.sort((a, b) => a.bitcoinAddressRecord.type == SegwitAddresType.mweb ? 1 : -1); for (int i = 0; i < availableInputs.length; i++) { final utx = availableInputs[i]; From a900a81076dd47eebae6e0f0cd8d0e7e84a17433 Mon Sep 17 00:00:00 2001 From: Matthew Fosse Date: Tue, 11 Feb 2025 09:25:32 -0800 Subject: [PATCH 6/9] ui fixes --- lib/src/screens/send/send_page.dart | 34 ++++++++++----------- lib/src/screens/send/widgets/send_card.dart | 4 +-- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/lib/src/screens/send/send_page.dart b/lib/src/screens/send/send_page.dart index 2d64c55a37..67774982d3 100644 --- a/lib/src/screens/send/send_page.dart +++ b/lib/src/screens/send/send_page.dart @@ -114,11 +114,15 @@ class SendPage extends BasePage { AppBarStyle get appBarStyle => AppBarStyle.transparent; double _sendCardHeight(BuildContext context) { - double initialHeight = 480; + double initialHeight = 495; if (sendViewModel.hasCoinControl) { initialHeight += 55; } + if (sendViewModel.walletType == WalletType.litecoin) { + initialHeight += 20;// for the allow mweb coins checkbox + } + if (!responsiveLayoutUtil.shouldRenderMobileUI) { return initialHeight - 66; } @@ -397,19 +401,16 @@ class SendPage extends BasePage { if (sendViewModel.wallet.isHardwareWallet) { if (!sendViewModel.ledgerViewModel!.isConnected) { - await Navigator.of(context).pushNamed( - Routes.connectDevices, + await Navigator.of(context).pushNamed(Routes.connectDevices, arguments: ConnectDevicePageParams( walletType: sendViewModel.walletType, onConnectDevice: (BuildContext context, _) { - sendViewModel.ledgerViewModel! - .setLedger(sendViewModel.wallet); + sendViewModel.ledgerViewModel!.setLedger(sendViewModel.wallet); Navigator.of(context).pop(); }, )); } else { - sendViewModel.ledgerViewModel! - .setLedger(sendViewModel.wallet); + sendViewModel.ledgerViewModel!.setLedger(sendViewModel.wallet); } } @@ -419,8 +420,10 @@ class SendPage extends BasePage { amount += item.formattedCryptoAmount; } if (monero!.needExportOutputs(sendViewModel.wallet, amount)) { - await Navigator.of(context).pushNamed(Routes.urqrAnimatedPage, arguments: 'export-outputs'); - await Future.delayed(Duration(seconds: 1)); // wait for monero to refresh the state + await Navigator.of(context) + .pushNamed(Routes.urqrAnimatedPage, arguments: 'export-outputs'); + await Future.delayed( + Duration(seconds: 1)); // wait for monero to refresh the state } if (monero!.needExportOutputs(sendViewModel.wallet, amount)) { return; @@ -524,13 +527,12 @@ class SendPage extends BasePage { if (state is TransactionCommitted) { WidgetsBinding.instance.addPostFrameCallback((_) async { - if (!context.mounted) { return; } - final successMessage = S.of(context).send_success( - sendViewModel.selectedCryptoCurrency.toString()); + final successMessage = + S.of(context).send_success(sendViewModel.selectedCryptoCurrency.toString()); final waitMessage = sendViewModel.walletType == WalletType.solana ? '. ${S.of(context).waitFewSecondForTxUpdate}' @@ -538,10 +540,8 @@ class SendPage extends BasePage { String alertContent = "$successMessage$waitMessage"; - await Navigator.of(context).pushNamed( - Routes.transactionSuccessPage, - arguments: alertContent - ); + await Navigator.of(context) + .pushNamed(Routes.transactionSuccessPage, arguments: alertContent); newContactAddress = newContactAddress ?? sendViewModel.newContactAddress(); if (sendViewModel.coinTypeToSpendFrom != UnspentCoinType.any) newContactAddress = null; @@ -557,7 +557,7 @@ class SendPage extends BasePage { leftButtonText: S.of(_dialogContext).ignor, alertLeftActionButtonKey: ValueKey('send_page_sent_dialog_ignore_button_key'), alertRightActionButtonKey: - ValueKey('send_page_sent_dialog_add_contact_button_key'), + ValueKey('send_page_sent_dialog_add_contact_button_key'), actionRightButton: () { Navigator.of(_dialogContext).pop(); RequestReviewHandler.requestReview(); diff --git a/lib/src/screens/send/widgets/send_card.dart b/lib/src/screens/send/widgets/send_card.dart index d82dce470d..62f5ec8b0b 100644 --- a/lib/src/screens/send/widgets/send_card.dart +++ b/lib/src/screens/send/widgets/send_card.dart @@ -144,7 +144,7 @@ class SendCardState extends State with AutomaticKeepAliveClientMixin with AutomaticKeepAliveClientMixin Padding( - padding: EdgeInsets.only(top: 10), + padding: EdgeInsets.only(top: 14), child: GestureDetector( key: ValueKey('send_page_unspent_coin_button_key'), onTap: () { From d3b0a7dc03d5ca9cdddc672aee913b81e6d9c6c5 Mon Sep 17 00:00:00 2001 From: Matthew Fosse Date: Wed, 12 Feb 2025 16:31:28 -0800 Subject: [PATCH 7/9] [skip-ci] default to mweb-checkbox being off --- lib/di.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/di.dart b/lib/di.dart index 9f22563045..a49d7e7fe9 100644 --- a/lib/di.dart +++ b/lib/di.dart @@ -748,7 +748,7 @@ Future setup({ getIt.get(), _transactionDescriptionBox, getIt.get().wallet!.isHardwareWallet ? getIt.get() : null, - coinTypeToSpendFrom: coinTypeToSpendFrom ?? UnspentCoinType.any, + coinTypeToSpendFrom: coinTypeToSpendFrom ?? UnspentCoinType.nonMweb, getIt.get(param1: coinTypeToSpendFrom), ), ); From bd270316fa373ad5bed76795e2afa79ce7b31371 Mon Sep 17 00:00:00 2001 From: Matthew Fosse Date: Thu, 13 Feb 2025 14:59:17 -0800 Subject: [PATCH 8/9] adaptable page view builder + workaround for keyboard actions --- lib/src/screens/send/send_page.dart | 590 +++++++++--------- lib/src/screens/send/widgets/send_card.dart | 624 ++++++++++---------- lib/src/widgets/adaptable_page_view.dart | 202 +++++++ 3 files changed, 817 insertions(+), 599 deletions(-) create mode 100644 lib/src/widgets/adaptable_page_view.dart diff --git a/lib/src/screens/send/send_page.dart b/lib/src/screens/send/send_page.dart index 67774982d3..2c3b2a72d7 100644 --- a/lib/src/screens/send/send_page.dart +++ b/lib/src/screens/send/send_page.dart @@ -13,14 +13,17 @@ import 'package:cake_wallet/src/screens/connect_device/connect_device_page.dart' import 'package:cake_wallet/src/screens/dashboard/widgets/sync_indicator_icon.dart'; import 'package:cake_wallet/src/screens/send/widgets/confirm_sending_alert.dart'; import 'package:cake_wallet/src/screens/send/widgets/send_card.dart'; +import 'package:cake_wallet/src/widgets/adaptable_page_view.dart'; import 'package:cake_wallet/src/widgets/add_template_button.dart'; import 'package:cake_wallet/src/widgets/alert_with_one_action.dart'; import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart'; +import 'package:cake_wallet/src/widgets/keyboard_done_button.dart'; import 'package:cake_wallet/src/widgets/picker.dart'; import 'package:cake_wallet/src/widgets/primary_button.dart'; import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart'; import 'package:cake_wallet/src/widgets/template_tile.dart'; import 'package:cake_wallet/src/widgets/trail_button.dart'; +import 'package:cake_wallet/themes/extensions/keyboard_theme.dart'; import 'package:cake_wallet/themes/extensions/seed_widget_theme.dart'; import 'package:cake_wallet/themes/extensions/send_page_theme.dart'; import 'package:cake_wallet/themes/theme_base.dart'; @@ -37,6 +40,7 @@ import 'package:cake_wallet/view_model/send/send_view_model_state.dart'; import 'package:cw_core/crypto_currency.dart'; import 'package:flutter/material.dart'; import 'package:flutter_mobx/flutter_mobx.dart'; +import 'package:keyboard_actions/keyboard_actions.dart'; import 'package:mobx/mobx.dart'; import 'package:smooth_page_indicator/smooth_page_indicator.dart'; import 'package:url_launcher/url_launcher.dart'; @@ -113,22 +117,6 @@ class SendPage extends BasePage { @override AppBarStyle get appBarStyle => AppBarStyle.transparent; - double _sendCardHeight(BuildContext context) { - double initialHeight = 495; - if (sendViewModel.hasCoinControl) { - initialHeight += 55; - } - - if (sendViewModel.walletType == WalletType.litecoin) { - initialHeight += 20;// for the allow mweb coins checkbox - } - - if (!responsiveLayoutUtil.shouldRenderMobileUI) { - return initialHeight - 66; - } - return initialHeight; - } - @override void onClose(BuildContext context) { sendViewModel.onClose(); @@ -177,284 +165,316 @@ class SendPage extends BasePage { Widget body(BuildContext context) { _setEffects(context); - return GestureDetector( - onLongPress: () => - sendViewModel.balanceViewModel.isReversing = !sendViewModel.balanceViewModel.isReversing, - onLongPressUp: () => - sendViewModel.balanceViewModel.isReversing = !sendViewModel.balanceViewModel.isReversing, - child: Form( - key: _formKey, - child: ScrollableWithBottomSection( - contentPadding: EdgeInsets.only(bottom: 24), - content: FocusTraversalGroup( - policy: OrderedTraversalPolicy(), - child: Column( - children: [ - Container( - height: _sendCardHeight(context), - child: Observer( - builder: (_) { - return PageView.builder( - scrollDirection: Axis.horizontal, - controller: controller, - itemCount: sendViewModel.outputs.length, - itemBuilder: (context, index) { - final output = sendViewModel.outputs[index]; - - return SendCard( - key: output.key, - output: output, - sendViewModel: sendViewModel, - initialPaymentRequest: initialPaymentRequest, + return Observer(builder: (_) { + List sendCards = []; + List keyboardActions = []; + for (var output in sendViewModel.outputs) { + var cryptoAmountFocus = FocusNode(); + var fiatAmountFocus = FocusNode(); + sendCards.add(SendCard( + key: output.key, + output: output, + sendViewModel: sendViewModel, + initialPaymentRequest: initialPaymentRequest, + cryptoAmountFocus: cryptoAmountFocus, + fiatAmountFocus: fiatAmountFocus, + )); + keyboardActions.add(KeyboardActionsItem( + focusNode: cryptoAmountFocus, toolbarButtons: [(_) => KeyboardDoneButton()])); + keyboardActions.add(KeyboardActionsItem( + focusNode: fiatAmountFocus, toolbarButtons: [(_) => KeyboardDoneButton()])); + } + return Stack( + children: [ + KeyboardActions( + config: KeyboardActionsConfig( + keyboardActionsPlatform: KeyboardActionsPlatform.ALL, + keyboardBarColor: Theme.of(context).extension()!.keyboardBarColor, + nextFocus: false, + actions: keyboardActions, + ), + child: Container( + height: 0, + color: Colors.transparent, + ), + ), + GestureDetector( + onLongPress: () => sendViewModel.balanceViewModel.isReversing = + !sendViewModel.balanceViewModel.isReversing, + onLongPressUp: () => sendViewModel.balanceViewModel.isReversing = + !sendViewModel.balanceViewModel.isReversing, + child: Form( + key: _formKey, + child: ScrollableWithBottomSection( + contentPadding: EdgeInsets.only(bottom: 24), + content: FocusTraversalGroup( + policy: OrderedTraversalPolicy(), + child: Column( + children: [ + SizedBox(height: 20), + PageViewHeightAdaptable( + controller: controller, + children: sendCards, + ), + SizedBox(height: 10), + Padding( + padding: EdgeInsets.only(left: 24, right: 24, bottom: 10), + child: Container( + height: 10, + child: Observer( + builder: (_) { + final count = sendViewModel.outputs.length; + + return count > 1 + ? Semantics( + label: 'Page Indicator', + hint: 'Swipe to change receiver', + excludeSemantics: true, + child: SmoothPageIndicator( + controller: controller, + count: count, + effect: ScrollingDotsEffect( + spacing: 6.0, + radius: 6.0, + dotWidth: 6.0, + dotHeight: 6.0, + dotColor: Theme.of(context) + .extension()! + .indicatorDotColor, + activeDotColor: Theme.of(context) + .extension()! + .templateBackgroundColor), + )) + : Offstage(); + }, + ), + ), + ), + Container( + height: 40, + width: double.infinity, + padding: EdgeInsets.only(left: 24), + child: SingleChildScrollView( + scrollDirection: Axis.horizontal, + child: Observer( + builder: (_) { + final templates = sendViewModel.templates; + final itemCount = templates.length; + + return Row( + children: [ + AddTemplateButton( + key: ValueKey('send_page_add_template_button_key'), + onTap: () => + Navigator.of(context).pushNamed(Routes.sendTemplate), + currentTemplatesLength: templates.length, + ), + ListView.builder( + scrollDirection: Axis.horizontal, + shrinkWrap: true, + physics: NeverScrollableScrollPhysics(), + itemCount: itemCount, + itemBuilder: (context, index) { + final template = templates[index]; + return TemplateTile( + key: UniqueKey(), + to: template.name, + hasMultipleRecipients: + template.additionalRecipients != null && + template.additionalRecipients!.length > 1, + amount: template.isCurrencySelected + ? template.amount + : template.amountFiat, + from: template.isCurrencySelected + ? template.cryptoCurrency + : template.fiatCurrency, + onTap: () async { + sendViewModel.state = IsExecutingState(); + if (template.additionalRecipients?.isNotEmpty ?? + false) { + sendViewModel.clearOutputs(); + + for (int i = 0; + i < template.additionalRecipients!.length; + i++) { + Output output; + try { + output = sendViewModel.outputs[i]; + } catch (e) { + sendViewModel.addOutput(); + output = sendViewModel.outputs[i]; + } + + await _setInputsFromTemplate( + context, + output: output, + template: template.additionalRecipients![i], + ); + } + } else { + final output = _defineCurrentOutput(); + await _setInputsFromTemplate( + context, + output: output, + template: template, + ); + } + sendViewModel.state = InitialExecutionState(); + }, + onRemove: () { + showPopUp( + context: context, + builder: (dialogContext) { + return AlertWithTwoActions( + alertTitle: S.of(context).template, + alertContent: + S.of(context).confirm_delete_template, + rightButtonText: S.of(context).delete, + leftButtonText: S.of(context).cancel, + actionRightButton: () { + Navigator.of(dialogContext).pop(); + sendViewModel.sendTemplateViewModel + .removeTemplate(template: template); + }, + actionLeftButton: () => + Navigator.of(dialogContext).pop()); + }, + ); + }, + ); + }, + ), + ], ); - }); - }, - )), - Padding( - padding: EdgeInsets.only(left: 24, right: 24, bottom: 10), - child: Container( - height: 10, - child: Observer( - builder: (_) { - final count = sendViewModel.outputs.length; - - return count > 1 - ? Semantics( - label: 'Page Indicator', - hint: 'Swipe to change receiver', - excludeSemantics: true, - child: SmoothPageIndicator( - controller: controller, - count: count, - effect: ScrollingDotsEffect( - spacing: 6.0, - radius: 6.0, - dotWidth: 6.0, - dotHeight: 6.0, - dotColor: Theme.of(context) - .extension()! - .indicatorDotColor, - activeDotColor: Theme.of(context) - .extension()! - .templateBackgroundColor), - )) - : Offstage(); - }, - ), + }, + ), + ), + ), + ], ), ), - Container( - height: 40, - width: double.infinity, - padding: EdgeInsets.only(left: 24), - child: SingleChildScrollView( - scrollDirection: Axis.horizontal, - child: Observer( + bottomSectionPadding: EdgeInsets.only(left: 24, right: 24, bottom: 24), + bottomSection: Column( + children: [ + if (sendViewModel.hasCurrecyChanger) + Observer( + 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()!.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), () { + controller.jumpToPage(sendViewModel.outputs.length - 1); + }); + }, + text: S.of(context).add_receiver, + color: Colors.transparent, + textColor: + Theme.of(context).extension()!.hintTextColor, + isDottedBorder: true, + borderColor: Theme.of(context) + .extension()! + .templateDottedBorderColor, + )), + Observer( builder: (_) { - final templates = sendViewModel.templates; - final itemCount = templates.length; - - return Row( - children: [ - AddTemplateButton( - key: ValueKey('send_page_add_template_button_key'), - onTap: () => Navigator.of(context).pushNamed(Routes.sendTemplate), - currentTemplatesLength: templates.length, - ), - ListView.builder( - scrollDirection: Axis.horizontal, - shrinkWrap: true, - physics: NeverScrollableScrollPhysics(), - itemCount: itemCount, - itemBuilder: (context, index) { - final template = templates[index]; - return TemplateTile( - key: UniqueKey(), - to: template.name, - hasMultipleRecipients: template.additionalRecipients != null && - template.additionalRecipients!.length > 1, - amount: template.isCurrencySelected - ? template.amount - : template.amountFiat, - from: template.isCurrencySelected - ? template.cryptoCurrency - : template.fiatCurrency, - onTap: () async { - sendViewModel.state = IsExecutingState(); - if (template.additionalRecipients?.isNotEmpty ?? false) { - sendViewModel.clearOutputs(); - - for (int i = 0; - i < template.additionalRecipients!.length; - i++) { - Output output; - try { - output = sendViewModel.outputs[i]; - } catch (e) { - sendViewModel.addOutput(); - output = sendViewModel.outputs[i]; - } - - await _setInputsFromTemplate( - context, - output: output, - template: template.additionalRecipients![i], - ); - } - } else { - final output = _defineCurrentOutput(); - await _setInputsFromTemplate( - context, - output: output, - template: template, - ); - } - sendViewModel.state = InitialExecutionState(); - }, - onRemove: () { - showPopUp( - context: context, - builder: (dialogContext) { - return AlertWithTwoActions( - alertTitle: S.of(context).template, - alertContent: S.of(context).confirm_delete_template, - rightButtonText: S.of(context).delete, - leftButtonText: S.of(context).cancel, - actionRightButton: () { - Navigator.of(dialogContext).pop(); - sendViewModel.sendTemplateViewModel - .removeTemplate(template: template); - }, - actionLeftButton: () => - Navigator.of(dialogContext).pop()); + return LoadingPrimaryButton( + key: ValueKey('send_page_send_button_key'), + onPressed: () async { + if (sendViewModel.state is IsExecutingState) return; + if (_formKey.currentState != null && + !_formKey.currentState!.validate()) { + if (sendViewModel.outputs.length > 1) { + showErrorValidationAlert(context); + } + + return; + } + + final notValidItems = sendViewModel.outputs + .where( + (item) => item.address.isEmpty || item.cryptoAmount.isEmpty) + .toList(); + + if (notValidItems.isNotEmpty) { + showErrorValidationAlert(context); + return; + } + + if (sendViewModel.wallet.isHardwareWallet) { + if (!sendViewModel.ledgerViewModel!.isConnected) { + await Navigator.of(context).pushNamed(Routes.connectDevices, + arguments: ConnectDevicePageParams( + walletType: sendViewModel.walletType, + onConnectDevice: (BuildContext context, _) { + sendViewModel.ledgerViewModel! + .setLedger(sendViewModel.wallet); + Navigator.of(context).pop(); }, - ); - }, - ); + )); + } else { + sendViewModel.ledgerViewModel!.setLedger(sendViewModel.wallet); + } + } + + if (sendViewModel.wallet.type == WalletType.monero) { + int amount = 0; + for (var item in sendViewModel.outputs) { + amount += item.formattedCryptoAmount; + } + if (monero!.needExportOutputs(sendViewModel.wallet, amount)) { + await Navigator.of(context).pushNamed(Routes.urqrAnimatedPage, + arguments: 'export-outputs'); + await Future.delayed( + Duration(seconds: 1)); // wait for monero to refresh the state + } + if (monero!.needExportOutputs(sendViewModel.wallet, amount)) { + return; + } + } + + final check = sendViewModel.shouldDisplayTotp(); + authService.authenticateAction( + context, + conditionToDetermineIfToUse2FA: check, + onAuthSuccess: (value) async { + if (value) { + await sendViewModel.createTransaction(); + } }, - ), - ], + ); + }, + text: S.of(context).send, + color: Theme.of(context).primaryColor, + textColor: Colors.white, + isLoading: sendViewModel.state is IsExecutingState || + sendViewModel.state is TransactionCommitting || + sendViewModel.state is IsAwaitingDeviceResponseState, + isDisabled: !sendViewModel.isReadyForSend, ); }, - ), - ), - ), - ], - ), + ) + ], + )), ), - bottomSectionPadding: EdgeInsets.only(left: 24, right: 24, bottom: 24), - bottomSection: Column( - children: [ - if (sendViewModel.hasCurrecyChanger) - Observer( - 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()!.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), () { - controller.jumpToPage(sendViewModel.outputs.length - 1); - }); - }, - text: S.of(context).add_receiver, - color: Colors.transparent, - textColor: Theme.of(context).extension()!.hintTextColor, - isDottedBorder: true, - borderColor: - Theme.of(context).extension()!.templateDottedBorderColor, - )), - 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()) { - if (sendViewModel.outputs.length > 1) { - showErrorValidationAlert(context); - } - - return; - } - - final notValidItems = sendViewModel.outputs - .where((item) => item.address.isEmpty || item.cryptoAmount.isEmpty) - .toList(); - - if (notValidItems.isNotEmpty) { - showErrorValidationAlert(context); - return; - } - - if (sendViewModel.wallet.isHardwareWallet) { - if (!sendViewModel.ledgerViewModel!.isConnected) { - await Navigator.of(context).pushNamed(Routes.connectDevices, - arguments: ConnectDevicePageParams( - walletType: sendViewModel.walletType, - onConnectDevice: (BuildContext context, _) { - sendViewModel.ledgerViewModel!.setLedger(sendViewModel.wallet); - Navigator.of(context).pop(); - }, - )); - } else { - sendViewModel.ledgerViewModel!.setLedger(sendViewModel.wallet); - } - } - - if (sendViewModel.wallet.type == WalletType.monero) { - int amount = 0; - for (var item in sendViewModel.outputs) { - amount += item.formattedCryptoAmount; - } - if (monero!.needExportOutputs(sendViewModel.wallet, amount)) { - await Navigator.of(context) - .pushNamed(Routes.urqrAnimatedPage, arguments: 'export-outputs'); - await Future.delayed( - Duration(seconds: 1)); // wait for monero to refresh the state - } - if (monero!.needExportOutputs(sendViewModel.wallet, amount)) { - return; - } - } - - final check = sendViewModel.shouldDisplayTotp(); - authService.authenticateAction( - context, - conditionToDetermineIfToUse2FA: check, - onAuthSuccess: (value) async { - if (value) { - await sendViewModel.createTransaction(); - } - }, - ); - }, - text: S.of(context).send, - color: Theme.of(context).primaryColor, - textColor: Colors.white, - isLoading: sendViewModel.state is IsExecutingState || - sendViewModel.state is TransactionCommitting || - sendViewModel.state is IsAwaitingDeviceResponseState, - isDisabled: !sendViewModel.isReadyForSend, - ); - }, - ) - ], - )), - ), - ); + ), + ], + ); + }); } BuildContext? dialogContext; diff --git a/lib/src/screens/send/widgets/send_card.dart b/lib/src/screens/send/widgets/send_card.dart index d9a9b2684c..c6d66cdeec 100644 --- a/lib/src/screens/send/widgets/send_card.dart +++ b/lib/src/screens/send/widgets/send_card.dart @@ -32,29 +32,38 @@ class SendCard extends StatefulWidget { required this.output, required this.sendViewModel, this.initialPaymentRequest, + this.cryptoAmountFocus, + this.fiatAmountFocus, }) : super(key: key); final Output output; final SendViewModel sendViewModel; final PaymentRequest? initialPaymentRequest; + final FocusNode? cryptoAmountFocus; + final FocusNode? fiatAmountFocus; @override SendCardState createState() => SendCardState( output: output, sendViewModel: sendViewModel, initialPaymentRequest: initialPaymentRequest, + // cryptoAmountFocus: cryptoAmountFocus ?? FocusNode(), + // fiatAmountFocus: fiatAmountFocus ?? FocusNode(), + // cryptoAmountFocus: FocusNode(), + // fiatAmountFocus: FocusNode(), ); } class SendCardState extends State with AutomaticKeepAliveClientMixin { - SendCardState({required this.output, required this.sendViewModel, this.initialPaymentRequest}) - : addressController = TextEditingController(), + SendCardState({ + required this.output, + required this.sendViewModel, + this.initialPaymentRequest, + }) : addressController = TextEditingController(), cryptoAmountController = TextEditingController(), fiatAmountController = TextEditingController(), noteController = TextEditingController(), extractedAddressController = TextEditingController(), - cryptoAmountFocus = FocusNode(), - fiatAmountFocus = FocusNode(), addressFocusNode = FocusNode(); static const prefixIconWidth = 34.0; @@ -69,8 +78,6 @@ class SendCardState extends State with AutomaticKeepAliveClientMixin with AutomaticKeepAliveClientMixin()!.keyboardBarColor, - nextFocus: false, - actions: [ - KeyboardActionsItem( - focusNode: cryptoAmountFocus, - toolbarButtons: [(_) => KeyboardDoneButton()], + // return Stack( + // children: [ + // return KeyboardActions( + // config: KeyboardActionsConfig( + // keyboardActionsPlatform: KeyboardActionsPlatform.IOS, + // keyboardBarColor: Theme.of(context).extension()!.keyboardBarColor, + // nextFocus: false, + // actions: [ + // KeyboardActionsItem( + // focusNode: cryptoAmountFocus, + // toolbarButtons: [(_) => KeyboardDoneButton()], + // ), + // KeyboardActionsItem( + // focusNode: fiatAmountFocus, + // toolbarButtons: [(_) => KeyboardDoneButton()], + // ) + // ], + // ), + // // child: Container( + // // height: 0, + // // color: Colors.transparent, + // // ), child: + // child: SizedBox( + // height: 100, + // width: 100, + // child: Text('Send Card'), + // ), + // ); + return Container( + decoration: responsiveLayoutUtil.shouldRenderMobileUI + ? BoxDecoration( + borderRadius: BorderRadius.only( + bottomLeft: Radius.circular(24), bottomRight: Radius.circular(24)), + gradient: LinearGradient( + colors: [ + Theme.of(context).extension()!.firstGradientColor, + Theme.of(context).extension()!.secondGradientColor, + ], + begin: Alignment.topLeft, + end: Alignment.bottomRight, ), - KeyboardActionsItem( - focusNode: fiatAmountFocus, - toolbarButtons: [(_) => KeyboardDoneButton()], - ) - ], - ), - child: Container( - height: 0, - color: Colors.transparent, - ), + ) + : null, + child: Padding( + padding: EdgeInsets.fromLTRB( + 24, + responsiveLayoutUtil.shouldRenderMobileUI ? 110 : 55, + 24, + responsiveLayoutUtil.shouldRenderMobileUI ? 32 : 0, ), - Container( - decoration: responsiveLayoutUtil.shouldRenderMobileUI - ? BoxDecoration( - borderRadius: BorderRadius.only( - bottomLeft: Radius.circular(24), bottomRight: Radius.circular(24)), - gradient: LinearGradient( - colors: [ - Theme.of(context).extension()!.firstGradientColor, - Theme.of(context).extension()!.secondGradientColor, - ], - begin: Alignment.topLeft, - end: Alignment.bottomRight, - ), - ) - : null, - child: Padding( - padding: EdgeInsets.fromLTRB( - 24, - responsiveLayoutUtil.shouldRenderMobileUI ? 110 : 55, - 24, - responsiveLayoutUtil.shouldRenderMobileUI ? 32 : 0, - ), - child: SingleChildScrollView( - child: Observer( - builder: (_) => Column( - mainAxisSize: MainAxisSize.min, - children: [ - Observer(builder: (_) { - final validator = output.isParsedAddress - ? sendViewModel.textValidator - : sendViewModel.addressValidator; - - return AddressTextField( - addressKey: ValueKey('send_page_address_textfield_key'), - focusNode: addressFocusNode, - controller: addressController, - onURIScanned: (uri) { - final paymentRequest = PaymentRequest.fromUri(uri); - addressController.text = paymentRequest.address; - cryptoAmountController.text = paymentRequest.amount; - noteController.text = paymentRequest.note; - }, - options: [ - AddressTextFieldOption.paste, - AddressTextFieldOption.qrCode, - AddressTextFieldOption.addressBook - ], - buttonColor: - Theme.of(context).extension()!.textFieldButtonColor, + child: Observer( + builder: (_) => Column( + mainAxisSize: MainAxisSize.min, + children: [ + Observer(builder: (_) { + final validator = output.isParsedAddress + ? sendViewModel.textValidator + : sendViewModel.addressValidator; + + return AddressTextField( + addressKey: ValueKey('send_page_address_textfield_key'), + focusNode: addressFocusNode, + controller: addressController, + onURIScanned: (uri) { + final paymentRequest = PaymentRequest.fromUri(uri); + addressController.text = paymentRequest.address; + cryptoAmountController.text = paymentRequest.amount; + noteController.text = paymentRequest.note; + }, + options: [ + AddressTextFieldOption.paste, + AddressTextFieldOption.qrCode, + AddressTextFieldOption.addressBook + ], + buttonColor: Theme.of(context).extension()!.textFieldButtonColor, + borderColor: Theme.of(context).extension()!.textFieldBorderColor, + textStyle: + TextStyle(fontSize: 14, fontWeight: FontWeight.w500, color: Colors.white), + hintStyle: TextStyle( + fontSize: 14, + fontWeight: FontWeight.w500, + color: Theme.of(context).extension()!.textFieldHintColor), + onPushPasteButton: (context) async { + output.resetParsedAddress(); + await output.fetchParsedAddress(context); + }, + onPushAddressBookButton: (context) async { + output.resetParsedAddress(); + }, + onSelectedContact: (contact) { + output.loadContact(contact); + }, + validator: validator, + selectedCurrency: sendViewModel.selectedCryptoCurrency, + ); + }), + if (output.isParsedAddress) + Padding( + padding: const EdgeInsets.only(top: 20), + child: BaseTextFormField( + controller: extractedAddressController, + readOnly: true, borderColor: Theme.of(context).extension()!.textFieldBorderColor, textStyle: TextStyle( fontSize: 14, fontWeight: FontWeight.w500, color: Colors.white), - hintStyle: TextStyle( - fontSize: 14, - fontWeight: FontWeight.w500, - color: - Theme.of(context).extension()!.textFieldHintColor), - onPushPasteButton: (context) async { - output.resetParsedAddress(); - await output.fetchParsedAddress(context); - }, - onPushAddressBookButton: (context) async { - output.resetParsedAddress(); - }, - onSelectedContact: (contact) { - output.loadContact(contact); - }, - validator: validator, - selectedCurrency: sendViewModel.selectedCryptoCurrency, - ); - }), - if (output.isParsedAddress) - Padding( - padding: const EdgeInsets.only(top: 20), - child: BaseTextFormField( - controller: extractedAddressController, - readOnly: true, - borderColor: Theme.of(context) - .extension()! - .textFieldBorderColor, - textStyle: TextStyle( - 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, - isAmountEditable: true, - onTapPicker: () => _presentPicker(context), - isPickerEnable: sendViewModel.hasMultipleTokens, - tag: sendViewModel.selectedCryptoCurrency.tag, - allAmountButton: - !sendViewModel.isBatchSending && sendViewModel.shouldDisplaySendALL, - currencyValueValidator: output.sendAll - ? sendViewModel.allAmountValidator - : sendViewModel.amountValidator, - allAmountCallback: () async => output.setSendAll(sendViewModel.balance)), - Divider( - height: 1, - color: Theme.of(context).extension()!.textFieldHintColor), - Observer( - builder: (_) => Padding( - padding: EdgeInsets.only(top: 10), - child: Row( - mainAxisSize: MainAxisSize.max, - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Expanded( - child: Text( - S.of(context).available_balance + ':', - style: TextStyle( - fontSize: 12, - fontWeight: FontWeight.w600, - color: Theme.of(context) - .extension()! - .textFieldHintColor), - ), - ), - Text( - sendViewModel.balance, - style: TextStyle( - fontSize: 12, - fontWeight: FontWeight.w600, - color: Theme.of(context) - .extension()! - .textFieldHintColor), - ) - ], + 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: widget.cryptoAmountFocus, + amountController: cryptoAmountController, + isAmountEditable: true, + onTapPicker: () => _presentPicker(context), + isPickerEnable: sendViewModel.hasMultipleTokens, + tag: sendViewModel.selectedCryptoCurrency.tag, + allAmountButton: + !sendViewModel.isBatchSending && sendViewModel.shouldDisplaySendALL, + currencyValueValidator: output.sendAll + ? sendViewModel.allAmountValidator + : sendViewModel.amountValidator, + allAmountCallback: () async => output.setSendAll(sendViewModel.balance)), + Divider( + height: 1, + color: Theme.of(context).extension()!.textFieldHintColor), + Observer( + builder: (_) => Padding( + padding: EdgeInsets.only(top: 10), + child: Row( + mainAxisSize: MainAxisSize.max, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Expanded( + child: Text( + S.of(context).available_balance + ':', + style: TextStyle( + fontSize: 12, + fontWeight: FontWeight.w600, + color: + Theme.of(context).extension()!.textFieldHintColor), ), ), - ), - 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, - hintText: '0.00', - isAmountEditable: true, - allAmountButton: false), - Divider( - height: 1, - color: Theme.of(context).extension()!.textFieldHintColor), - Padding( - padding: EdgeInsets.only(top: 20), - child: BaseTextFormField( - key: ValueKey('send_page_note_textfield_key'), - controller: noteController, - keyboardType: TextInputType.multiline, - maxLines: null, - borderColor: - Theme.of(context).extension()!.textFieldBorderColor, - textStyle: TextStyle( - fontSize: 14, fontWeight: FontWeight.w500, color: Colors.white), - hintText: S.of(context).note_optional, - placeholderTextStyle: TextStyle( - fontSize: 14, - fontWeight: FontWeight.w500, + Text( + sendViewModel.balance, + style: TextStyle( + fontSize: 12, + fontWeight: FontWeight.w600, color: Theme.of(context).extension()!.textFieldHintColor), - ), - ), - if (sendViewModel.hasFees) - Observer( - builder: (_) => GestureDetector( - key: ValueKey('send_page_select_fee_priority_button_key'), - onTap: sendViewModel.hasFeesPriority - ? () => pickTransactionPriority(context) - : () {}, - child: Container( - padding: EdgeInsets.only(top: 24), + ) + ], + ), + ), + ), + 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: widget.fiatAmountFocus, + amountController: fiatAmountController, + hintText: '0.00', + isAmountEditable: true, + allAmountButton: false), + Divider( + height: 1, + color: Theme.of(context).extension()!.textFieldHintColor), + Padding( + padding: EdgeInsets.only(top: 20), + child: BaseTextFormField( + key: ValueKey('send_page_note_textfield_key'), + controller: noteController, + keyboardType: TextInputType.multiline, + maxLines: null, + borderColor: Theme.of(context).extension()!.textFieldBorderColor, + textStyle: + TextStyle(fontSize: 14, fontWeight: FontWeight.w500, color: Colors.white), + hintText: S.of(context).note_optional, + placeholderTextStyle: TextStyle( + fontSize: 14, + fontWeight: FontWeight.w500, + color: Theme.of(context).extension()!.textFieldHintColor), + ), + ), + if (sendViewModel.hasFees) + Observer( + builder: (_) => GestureDetector( + key: ValueKey('send_page_select_fee_priority_button_key'), + onTap: sendViewModel.hasFeesPriority + ? () => pickTransactionPriority(context) + : () {}, + child: Container( + padding: EdgeInsets.only(top: 24), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + S.of(context).send_estimated_fee, + style: TextStyle( + fontSize: 12, fontWeight: FontWeight.w500, color: Colors.white), + ), + Container( child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text( - S.of(context).send_estimated_fee, - style: TextStyle( - fontSize: 12, - fontWeight: FontWeight.w500, - color: Colors.white), - ), - Container( - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - Text( - output.estimatedFee.toString() + - ' ' + - sendViewModel.currency.toString(), - style: TextStyle( - fontSize: 12, - fontWeight: FontWeight.w600, - color: Colors.white, - ), - ), - Padding( - padding: EdgeInsets.only(top: 5), - child: sendViewModel.isFiatDisabled - ? const SizedBox(height: 14) - : Text( - output.estimatedFeeFiatAmount + - ' ' + - sendViewModel.fiat.title, - style: TextStyle( - fontSize: 12, - fontWeight: FontWeight.w600, - color: Theme.of(context) - .extension()! - .textFieldHintColor, - ), - ), - ), - ], + Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + Text( + output.estimatedFee.toString() + + ' ' + + sendViewModel.currency.toString(), + style: TextStyle( + fontSize: 12, + fontWeight: FontWeight.w600, + color: Colors.white, ), - Padding( - padding: EdgeInsets.only(top: 2, left: 5), - child: Icon( - Icons.arrow_forward_ios, - size: 12, - color: Colors.white, - ), - ) - ], + ), + Padding( + padding: EdgeInsets.only(top: 5), + child: sendViewModel.isFiatDisabled + ? const SizedBox(height: 14) + : Text( + output.estimatedFeeFiatAmount + + ' ' + + sendViewModel.fiat.title, + style: TextStyle( + fontSize: 12, + fontWeight: FontWeight.w600, + color: Theme.of(context) + .extension()! + .textFieldHintColor, + ), + ), + ), + ], + ), + Padding( + padding: EdgeInsets.only(top: 2, left: 5), + child: Icon( + Icons.arrow_forward_ios, + size: 12, + color: Colors.white, ), ) ], ), - ), - ), + ) + ], ), - if (sendViewModel.hasCoinControl) - Padding( - padding: EdgeInsets.only(top: 6), - child: GestureDetector( - key: ValueKey('send_page_unspent_coin_button_key'), - onTap: () => Navigator.of(context).pushNamed( - Routes.unspentCoinsList, - arguments: widget.sendViewModel.coinTypeToSpendFrom, + ), + ), + ), + if (sendViewModel.hasCoinControl) + Padding( + padding: EdgeInsets.only(top: 6), + child: GestureDetector( + key: ValueKey('send_page_unspent_coin_button_key'), + onTap: () => Navigator.of(context).pushNamed( + Routes.unspentCoinsList, + arguments: widget.sendViewModel.coinTypeToSpendFrom, + ), + child: Container( + color: Colors.transparent, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + S.of(context).coin_control, + style: TextStyle( + fontSize: 12, fontWeight: FontWeight.w600, color: Colors.white), ), - child: Container( - color: Colors.transparent, - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - S.of(context).coin_control, - style: TextStyle( - fontSize: 12, - fontWeight: FontWeight.w600, - color: Colors.white), - ), - Icon( - Icons.arrow_forward_ios, - size: 12, - color: Colors.white, - ), - ], - ), + Icon( + Icons.arrow_forward_ios, + size: 12, + color: Colors.white, ), - ), + ], ), - if (sendViewModel.currency == CryptoCurrency.ltc) - Observer( - builder: (_) => Padding( - padding: EdgeInsets.only(top: 14), - child: GestureDetector( - key: ValueKey('send_page_unspent_coin_button_key'), - onTap: () { - bool value = - widget.sendViewModel.coinTypeToSpendFrom == UnspentCoinType.any; - sendViewModel.setAllowMwebCoins(!value); - }, - child: Container( - color: Colors.transparent, - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - StandardCheckbox( - caption: S.of(context).litecoin_mweb_allow_coins, - captionColor: Colors.white, - value: widget.sendViewModel.coinTypeToSpendFrom == - UnspentCoinType.any, - onChanged: (bool? value) { - sendViewModel.setAllowMwebCoins(value ?? false); - }, - ), - ], - ), + ), + ), + ), + if (sendViewModel.currency == CryptoCurrency.ltc) + Observer( + builder: (_) => Padding( + padding: EdgeInsets.only(top: 14), + child: GestureDetector( + key: ValueKey('send_page_unspent_coin_button_key'), + onTap: () { + bool value = + widget.sendViewModel.coinTypeToSpendFrom == UnspentCoinType.any; + sendViewModel.setAllowMwebCoins(!value); + }, + child: Container( + color: Colors.transparent, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + StandardCheckbox( + caption: S.of(context).litecoin_mweb_allow_coins, + captionColor: Colors.white, + value: + widget.sendViewModel.coinTypeToSpendFrom == UnspentCoinType.any, + onChanged: (bool? value) { + sendViewModel.setAllowMwebCoins(value ?? false); + }, ), - ), + ], ), ), - ], + ), + ), ), - ), - ), + ], ), - ) - ], + ), + ), ); } diff --git a/lib/src/widgets/adaptable_page_view.dart b/lib/src/widgets/adaptable_page_view.dart new file mode 100644 index 0000000000..c6800ae226 --- /dev/null +++ b/lib/src/widgets/adaptable_page_view.dart @@ -0,0 +1,202 @@ +import 'dart:ui'; + +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; + +const _firstLayoutMaxHeight = 10000.0; + +class PageViewHeightAdaptable extends StatefulWidget { + const PageViewHeightAdaptable({ + super.key, + required this.controller, + required this.children, + }) : assert(children.length > 0, 'children must not be empty'); + + final PageController controller; + final List children; + + @override + State createState() => _PageViewHeightAdaptableState(); +} + +class _PageViewHeightAdaptableState extends State { + final _sizes = {}; + + @override + void didUpdateWidget(PageViewHeightAdaptable oldWidget) { + super.didUpdateWidget(oldWidget); + + _sizes.clear(); + } + + @override + Widget build(BuildContext context) { + return ListenableBuilder( + listenable: widget.controller, + builder: (context, child) => _SizingContainer( + sizes: _sizes, + page: widget.controller.hasClients ? widget.controller.page ?? 0 : 0, + child: child!, + ), + child: LayoutBuilder( + builder: (context, constraints) => PageView( + controller: widget.controller, + children: [ + for (final (i, child) in widget.children.indexed) + Stack( + alignment: Alignment.topCenter, + clipBehavior: Clip.hardEdge, + children: [ + SizedBox.fromSize(size: _sizes[i]), + Positioned( + left: 0, + top: 0, + right: 0, + child: _SizeAware( + child: child, + // don't setState, we'll use it in the layout phase + onSizeLaidOut: (size) { + _sizes[i] = size; + }, + ), + ), + ], + ), + ], + ), + ), + ); + } +} + +typedef _OnSizeLaidOutCallback = void Function(Size); + +class _SizingContainer extends SingleChildRenderObjectWidget { + const _SizingContainer({ + super.child, + required this.sizes, + required this.page, + }); + + final Map sizes; + final double page; + + @override + _RenderSizingContainer createRenderObject(BuildContext context) { + return _RenderSizingContainer( + sizes: sizes, + page: page, + ); + } + + @override + void updateRenderObject( + BuildContext context, + _RenderSizingContainer renderObject, + ) { + renderObject + ..sizes = sizes + ..page = page; + } +} + +class _RenderSizingContainer extends RenderProxyBox { + _RenderSizingContainer({ + RenderBox? child, + required Map sizes, + required double page, + }) : _sizes = sizes, + _page = page, + super(child); + + Map _sizes; + Map get sizes => _sizes; + set sizes(Map value) { + if (_sizes == value) return; + _sizes = value; + markNeedsLayout(); + } + + double _page; + double get page => _page; + set page(double value) { + if (_page == value) return; + _page = value; + markNeedsLayout(); + } + + @override + void performLayout() { + if (child case final child?) { + child.layout( + constraints.copyWith( + minWidth: constraints.maxWidth, + minHeight: 0, + maxHeight: constraints.hasBoundedHeight ? null : _firstLayoutMaxHeight, + ), + parentUsesSize: true, + ); + + final a = sizes[page.floor()]!; + final b = sizes[page.ceil()]!; + + final height = lerpDouble(a.height, b.height, page - page.floor()); + + child.layout( + constraints.copyWith(minHeight: height, maxHeight: height), + parentUsesSize: true, + ); + size = child.size; + } else { + size = computeSizeForNoChild(constraints); + } + } +} + +class _SizeAware extends SingleChildRenderObjectWidget { + const _SizeAware({ + required Widget child, + required this.onSizeLaidOut, + }) : super(child: child); + + final _OnSizeLaidOutCallback onSizeLaidOut; + + @override + _RenderSizeAware createRenderObject(BuildContext context) { + return _RenderSizeAware( + onSizeLaidOut: onSizeLaidOut, + ); + } + + @override + void updateRenderObject(BuildContext context, _RenderSizeAware renderObject) { + renderObject.onSizeLaidOut = onSizeLaidOut; + } +} + +class _RenderSizeAware extends RenderProxyBox { + _RenderSizeAware({ + RenderBox? child, + required _OnSizeLaidOutCallback onSizeLaidOut, + }) : _onSizeLaidOut = onSizeLaidOut, + super(child); + + _OnSizeLaidOutCallback? _onSizeLaidOut; + _OnSizeLaidOutCallback get onSizeLaidOut => _onSizeLaidOut!; + set onSizeLaidOut(_OnSizeLaidOutCallback value) { + if (_onSizeLaidOut == value) return; + _onSizeLaidOut = value; + markNeedsLayout(); + } + + @override + void performLayout() { + super.performLayout(); + + onSizeLaidOut( + getDryLayout( + constraints.copyWith(maxHeight: double.infinity), + ), + ); + } +} \ No newline at end of file From 509ed4cf95652a4514e5ec264e8c110b0278d755 Mon Sep 17 00:00:00 2001 From: tuxpizza Date: Fri, 14 Feb 2025 02:48:18 -0500 Subject: [PATCH 9/9] Fix checkbox themeing and send card sizing --- lib/src/screens/send/send_page.dart | 4 ++-- lib/src/screens/send/widgets/send_card.dart | 16 ++++++++++++++++ 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/lib/src/screens/send/send_page.dart b/lib/src/screens/send/send_page.dart index 2c3b2a72d7..845dfd5521 100644 --- a/lib/src/screens/send/send_page.dart +++ b/lib/src/screens/send/send_page.dart @@ -96,7 +96,7 @@ class SendPage extends BasePage { return MergeSemantics( child: SizedBox( height: isMobileView ? 37 : 45, - width: isMobileView ? 37 : 45, + width: isMobileView ? 47: 45, child: ButtonTheme( minWidth: double.minPositive, child: Semantics( @@ -172,6 +172,7 @@ class SendPage extends BasePage { var cryptoAmountFocus = FocusNode(); var fiatAmountFocus = FocusNode(); sendCards.add(SendCard( + currentTheme: currentTheme, key: output.key, output: output, sendViewModel: sendViewModel, @@ -211,7 +212,6 @@ class SendPage extends BasePage { policy: OrderedTraversalPolicy(), child: Column( children: [ - SizedBox(height: 20), PageViewHeightAdaptable( controller: controller, children: sendCards, diff --git a/lib/src/screens/send/widgets/send_card.dart b/lib/src/screens/send/widgets/send_card.dart index c6d66cdeec..5931f15bec 100644 --- a/lib/src/screens/send/widgets/send_card.dart +++ b/lib/src/screens/send/widgets/send_card.dart @@ -26,11 +26,15 @@ import 'package:cake_wallet/generated/i18n.dart'; import 'package:cake_wallet/src/widgets/base_text_form_field.dart'; import 'package:cake_wallet/themes/extensions/send_page_theme.dart'; +import '../../../../themes/extensions/cake_text_theme.dart'; +import '../../../../themes/theme_base.dart'; + class SendCard extends StatefulWidget { SendCard({ Key? key, required this.output, required this.sendViewModel, + required this.currentTheme, this.initialPaymentRequest, this.cryptoAmountFocus, this.fiatAmountFocus, @@ -41,12 +45,15 @@ class SendCard extends StatefulWidget { final PaymentRequest? initialPaymentRequest; final FocusNode? cryptoAmountFocus; final FocusNode? fiatAmountFocus; + final ThemeBase currentTheme; + @override SendCardState createState() => SendCardState( output: output, sendViewModel: sendViewModel, initialPaymentRequest: initialPaymentRequest, + currentTheme: currentTheme // cryptoAmountFocus: cryptoAmountFocus ?? FocusNode(), // fiatAmountFocus: fiatAmountFocus ?? FocusNode(), // cryptoAmountFocus: FocusNode(), @@ -59,6 +66,7 @@ class SendCardState extends State with AutomaticKeepAliveClientMixin with AutomaticKeepAliveClientMixin with AutomaticKeepAliveClientMixin Padding( padding: EdgeInsets.only(top: 14), @@ -418,6 +428,12 @@ class SendCardState extends State with AutomaticKeepAliveClientMixin()!.secondaryTextColor, + iconColor: currentTheme.type == ThemeType.bright + ? Colors.white + : Theme.of(context).primaryColor, value: widget.sendViewModel.coinTypeToSpendFrom == UnspentCoinType.any, onChanged: (bool? value) {