dev
dart 289 lines 13.8 KB
Raw
1 import 'package:cake_wallet/entities/fiat_currency.dart';
2 import 'package:cake_wallet/generated/i18n.dart';
3 import 'package:cake_wallet/new-ui/widgets/currency_picker/currency_picker_args.dart';
4 import 'package:cake_wallet/new-ui/widgets/currency_picker/currency_picker_sheet.dart';
5 import 'package:cake_wallet/new-ui/widgets/currency_picker/fiat_currency_picker_sheet.dart';
6 import 'package:cake_wallet/new-ui/widgets/coins_page/token_image_widget.dart';
7 import 'package:cake_wallet/new-ui/widgets/new_primary_button.dart';
8 import 'package:cake_wallet/new-ui/widgets/receive_page/receive_top_bar.dart';
9 import 'package:cake_wallet/src/widgets/cake_image_widget.dart';
10 import 'package:cake_wallet/utils/decimal_input_formatter.dart';
11 import 'package:cake_wallet/view_model/wallet_address_list/wallet_address_list_view_model.dart';
12 import 'package:cw_core/crypto_currency.dart';
13 import 'package:flutter/material.dart';
14 import 'package:flutter_mobx/flutter_mobx.dart';
15
16 class ReceiveAmountModal extends StatefulWidget {
17 const ReceiveAmountModal(
18 {super.key, required this.walletAddressListViewModel, required this.onSubmitted});
19
20 final WalletAddressListViewModel walletAddressListViewModel;
21 final Function(String) onSubmitted;
22
23 @override
24 State<ReceiveAmountModal> createState() => _ReceiveAmountModalState();
25 }
26
27 class _ReceiveAmountModalState extends State<ReceiveAmountModal> {
28 final TextEditingController _amountController = TextEditingController();
29
30 @override
31 void initState() {
32 super.initState();
33 if (widget.walletAddressListViewModel.selectedCurrency is FiatCurrency) {
34 _amountController.text = widget.walletAddressListViewModel.fiatAmount;
35 } else {
36 _amountController.text = widget.walletAddressListViewModel.displayAmount;
37 }
38 }
39
40 @override
41 Widget build(BuildContext context) {
42 return Padding(
43 padding: EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom),
44 child: SafeArea(
45 child: Container(
46 decoration: BoxDecoration(
47 borderRadius: BorderRadius.vertical(top: Radius.circular(18)),
48 color: Theme.of(context).colorScheme.surface,
49 ),
50 child: Column(
51 mainAxisSize: MainAxisSize.min,
52 crossAxisAlignment: CrossAxisAlignment.start,
53 children: [
54 ModalTopBar(
55 title: S.of(context).set_amount,
56 onLeadingPressed: Navigator.of(context).pop,
57 onTrailingPressed: () {},
58 leadingIcon: Icon(Icons.close),
59 leadingSemanticLabel: S.of(context).close,
60 ),
61 Padding(
62 padding: const EdgeInsets.all(18.0),
63 child: Column(
64 mainAxisSize: MainAxisSize.min,
65 crossAxisAlignment: CrossAxisAlignment.start,
66 spacing: 12,
67 children: [
68 if (widget.walletAddressListViewModel.hasTokensList) ...[
69 // The caption is reused as the picker's semantics label,
70 // so it must not be announced as a separate node.
71 ExcludeSemantics(child: Text(S.of(context).token)),
72 MergeSemantics(
73 child: Semantics(
74 button: true,
75 label: S.of(context).select_token,
76 child: GestureDetector(
77 onTap: () {
78 _presentTokenCurrencyPicker(context);
79 },
80 child: Observer(
81 builder: (_) => Container(
82 height: 60,
83 decoration: BoxDecoration(
84 color: Theme.of(context).colorScheme.surfaceContainerHigh,
85 borderRadius: BorderRadius.circular(16),
86 ),
87 child: Padding(
88 padding: const EdgeInsets.symmetric(horizontal: 16.0),
89 child: Row(
90 mainAxisSize: MainAxisSize.max,
91 mainAxisAlignment: MainAxisAlignment.spaceBetween,
92 children: [
93 Row(
94 spacing: 8,
95 children: [
96 ExcludeSemantics(
97 child: TokenImageWidget(
98 imageUrl: widget.walletAddressListViewModel
99 .tokenCurrency?.iconPath ??
100 widget.walletAddressListViewModel.currencies.first
101 .iconPath ??
102 "",
103 size: 32,
104 ),
105 ),
106 Text((widget.walletAddressListViewModel.tokenCurrency ??
107 widget.walletAddressListViewModel.currencies.first
108 as CryptoCurrency)
109 .title
110 .toUpperCase())
111 ],
112 ),
113 ExcludeSemantics(
114 child: RotatedBox(
115 quarterTurns: 2,
116 child: CakeImageWidget(
117 imageUrl: "assets/new-ui/dropdown_arrow.svg")),
118 )
119 ],
120 ),
121 ),
122 ),
123 ),
124 ),
125 ),
126 ),
127 ],
128 SizedBox(),
129 // The caption is reused as the field's semantics label.
130 ExcludeSemantics(child: Text(S.of(context).amount)),
131 Row(
132 mainAxisAlignment: MainAxisAlignment.center,
133 children: [
134 Expanded(
135 flex: 75,
136 child: AnimatedContainer(
137 duration: Duration(milliseconds: 300),
138 height: 60,
139 decoration: BoxDecoration(
140 color: Theme.of(context).colorScheme.surfaceContainer,
141 borderRadius: BorderRadius.only(
142 topLeft: Radius.circular(16),
143 bottomLeft: Radius.circular(16),
144 ),
145 border: Border.all(
146 color: Theme.of(context).colorScheme.surfaceContainer,
147 width: 2,
148 ),
149 ),
150 child: MergeSemantics(
151 child: Semantics(
152 label: S.of(context).amount,
153 child: TextField(
154 textAlign: TextAlign.left,
155 textAlignVertical: TextAlignVertical.center,
156 controller: _amountController,
157 keyboardType: TextInputType.numberWithOptions(
158 signed: false,
159 decimal:
160 widget.walletAddressListViewModel.selectedCurrencyDecimals >
161 0,
162 ),
163 inputFormatters: [
164 DecimalInputFormatter(
165 maxDecimals:
166 widget.walletAddressListViewModel.selectedCurrencyDecimals,
167 ),
168 ],
169 decoration: InputDecoration(
170 hint: Text(
171 widget.walletAddressListViewModel.useSatoshi
172 ? "0"
173 : "0.00000000",
174 textAlign: TextAlign.left,
175 style: TextStyle(
176 fontSize: 16,
177 color: Theme.of(
178 context,
179 ).colorScheme.onSurface.withValues(alpha: 0.5),
180 ),
181 ),
182 border: InputBorder.none,
183 filled: true,
184 fillColor: Colors.transparent,
185 ),
186 style:
187 TextStyle(color: Theme.of(context).colorScheme.onSurface),
188 ),
189 ),
190 ),
191 ),
192 ),
193 Expanded(
194 flex: 25,
195 child: MergeSemantics(
196 child: Semantics(
197 button: true,
198 label: S.of(context).select_fiat_currency_title,
199 child: GestureDetector(
200 onTap: () {
201 _presentFiatCurrencyPicker(context);
202 },
203 child: Container(
204 height: 60,
205 decoration: BoxDecoration(
206 borderRadius: BorderRadius.only(
207 topLeft: Radius.circular(0),
208 bottomLeft: Radius.circular(0),
209 topRight: Radius.circular(18),
210 bottomRight: Radius.circular(18),
211 ),
212 color: Theme.of(context).colorScheme.surfaceContainerHigh,
213 ),
214 child: Row(
215 mainAxisAlignment: MainAxisAlignment.center,
216 spacing: 4.0,
217 children: [
218 Observer(
219 builder: (_) => Text(
220 widget.walletAddressListViewModel.selectedCurrencySymbol,
221 style: TextStyle(
222 color: Theme.of(context).colorScheme.onSurface,
223 ),
224 ),
225 ),
226 ExcludeSemantics(
227 child: Icon(
228 Icons.keyboard_arrow_down,
229 color: Theme.of(context).colorScheme.primary,
230 ),
231 ),
232 ],
233 ),
234 ),
235 ),
236 ),
237 ),
238 ),
239 ],
240 ),
241 SizedBox(),
242 NewPrimaryButton(
243 text: S.of(context).continue_text,
244 onPressed: () {
245 if (double.tryParse(_amountController.text) != null) {
246 widget.walletAddressListViewModel.changeAmount(_amountController.text);
247 }
248 Navigator.of(context).pop();
249 },
250 color: Theme.of(context).colorScheme.primary,
251 textColor: Theme.of(context).colorScheme.onPrimary,
252 )
253 ],
254 ),
255 )
256 ],
257 ),
258 ),
259 ),
260 );
261 }
262
263 void _presentTokenCurrencyPicker(BuildContext context) {
264 final items =
265 widget.walletAddressListViewModel.tokenCurrencies.whereType<CryptoCurrency>().toList();
266 CurrencyPickerSheet.show(
267 context: context,
268 args: CurrencyPickerArgs(
269 items: items,
270 selected: widget.walletAddressListViewModel.tokenCurrency,
271 onSelected: widget.walletAddressListViewModel.setTokenCurrency,
272 symbolResolver: widget.walletAddressListViewModel.amountParsingProxy.getCryptoSymbol,
273 ),
274 );
275 }
276
277 void _presentFiatCurrencyPicker(BuildContext context) {
278 final selected = widget.walletAddressListViewModel.selectedCurrency;
279 final cryptoOption =
280 widget.walletAddressListViewModel.currencies.whereType<CryptoCurrency>().firstOrNull;
281 FiatCurrencyPickerSheet.show(
282 context: context,
283 selected: selected,
284 cryptoOption: cryptoOption,
285 onSelected: widget.walletAddressListViewModel.selectCurrency,
286 onCryptoSelected: widget.walletAddressListViewModel.selectCurrency,
287 );
288 }
289 }