dev
dart 260 lines 11.6 KB
Raw
1 import 'package:cake_wallet/generated/i18n.dart';
2 import 'package:cake_wallet/new-ui/widgets/copy_wrapper.dart';
3 import 'package:cake_wallet/new-ui/widgets/new_primary_button.dart';
4 import 'package:cake_wallet/new-ui/widgets/receive_page/receive_top_bar.dart';
5 import 'package:cake_wallet/new-ui/widgets/swap_page/swap_modal_header.dart';
6 import 'package:cake_wallet/src/screens/receive/widgets/qr_image.dart';
7 import 'package:cake_wallet/utils/address_formatter.dart';
8 import 'package:cake_wallet/utils/clipboard_util.dart';
9 import 'package:cake_wallet/view_model/exchange/exchange_trade_view_model.dart';
10 import 'package:cw_core/crypto_currency.dart';
11 import 'package:cw_core/payment_uris.dart';
12 import 'package:flutter/material.dart';
13 import 'package:flutter/services.dart';
14
15 class SwapSendExternalModal extends StatefulWidget {
16 const SwapSendExternalModal(
17 {super.key,
18 required this.amount,
19 required this.from,
20 required this.to,
21 required this.address,
22 required this.exchangeTradeViewModel});
23
24 final String amount;
25 final ExchangeTradeViewModel exchangeTradeViewModel;
26 final CryptoCurrency from;
27 final CryptoCurrency to;
28 final String address;
29
30 @override
31 State<SwapSendExternalModal> createState() => _SwapSendExternalModalState();
32 }
33
34 class _SwapSendExternalModalState extends State<SwapSendExternalModal> {
35 PaymentURI? uri;
36 bool largeQrMode = false;
37 static const warningTextColor = Color(0xFFFFB84E);
38 static const warningBackgroundColor = Color(0xFF8E5800);
39
40 @override
41 void initState() {
42 super.initState();
43 final newUri = widget.exchangeTradeViewModel.paymentUri;
44 setState(() {
45 uri = newUri;
46 });
47 }
48
49 @override
50 Widget build(BuildContext context) {
51 if (widget.address.isEmpty) return SizedBox.shrink();
52 final resolvedSize = MediaQuery.of(context).size.width * (largeQrMode ? 0.8 : 0.54);
53
54 return PopScope(
55 onPopInvokedWithResult: (didPop, result) {
56 Navigator.of(context, rootNavigator: true).pop();
57 },
58 child: Container(
59 decoration: BoxDecoration(
60 color: Theme.of(context).colorScheme.surface,
61 borderRadius: BorderRadius.vertical(top: Radius.circular(16)),
62 ),
63 child: SafeArea(
64 child: Column(
65 mainAxisSize: MainAxisSize.min,
66 children: [
67 ModalTopBar(
68 title: "",
69 leadingWidget: SwapModalHeader(
70 fromIconPath: widget.from.iconPath ?? "", toIconPath: widget.to.iconPath ?? ""),
71 trailingIcon: Icon(Icons.close),
72 trailingSemanticLabel: S.of(context).close,
73 onTrailingPressed: Navigator.of(context).pop,
74 ),
75 Padding(
76 padding: EdgeInsets.symmetric(horizontal: 16),
77 child: Column(
78 spacing: 24,
79 children: [
80 Row(
81 mainAxisAlignment: MainAxisAlignment.center,
82 spacing: 12,
83 children: [
84 Text(
85 S.of(context).send_exactly,
86 style: TextStyle(
87 fontSize: 16,
88 color: Theme.of(context).colorScheme.onSurface,
89 fontWeight: FontWeight.w500),
90 ),
91 Container(
92 decoration: BoxDecoration(
93 color: Theme.of(context).colorScheme.surfaceContainer,
94 borderRadius: BorderRadius.circular(12)),
95 child: Padding(
96 padding: const EdgeInsets.all(8.0),
97 child: Row(
98 spacing: 8,
99 children: [
100 Text(
101 widget.amount,
102 style: TextStyle(
103 fontWeight: FontWeight.w500,
104 fontSize: 16,
105 color: Theme.of(context).colorScheme.primary),
106 ),
107 Text(
108 widget.from.title,
109 style: TextStyle(
110 fontWeight: FontWeight.w400,
111 fontSize: 16,
112 color: Theme.of(context).colorScheme.primary),
113 ),
114 ],
115 ),
116 )),
117 Text("${S.of(context).to}:",
118 style: TextStyle(
119 fontSize: 16,
120 color: Theme.of(context).colorScheme.onSurface,
121 fontWeight: FontWeight.w500))
122 ],
123 ),
124 GestureDetector(
125 onTap: () {
126 setState(() {
127 largeQrMode = !largeQrMode;
128 });
129 },
130 child: TweenAnimationBuilder<double>(
131 duration: const Duration(milliseconds: 400),
132 curve: Curves.easeOutCubic,
133 tween: Tween<double>(
134 begin: resolvedSize,
135 end: resolvedSize,
136 ),
137 builder: (context, animatedSize, child) {
138 return SizedBox(
139 width: animatedSize,
140 height: animatedSize,
141 child: ClipRRect(
142 borderRadius: BorderRadius.circular(16),
143 child: QrImage(
144 size: animatedSize,
145 embeddedImagePath: widget.from.iconPath,
146 data: uri?.toString() ?? widget.address,
147 ),
148 ),
149 );
150 },
151 ),
152 ),
153 AddressFormatter.buildSegmentedAddress(
154 address: widget.address,
155 evenTextStyle: TextStyle(color: Theme.of(context).colorScheme.onSurface),
156 textAlign: TextAlign.center),
157 Container(
158 decoration: BoxDecoration(
159 color: warningBackgroundColor,
160 borderRadius: BorderRadius.circular(16),
161 ),
162 child: Padding(
163 padding: EdgeInsets.all(20),
164 child: Text(
165 S.of(context).send_external_desc,
166 textAlign: TextAlign.center,
167 style: TextStyle(
168 color: warningTextColor, fontSize: 14, fontWeight: FontWeight.w500),
169 ),
170 )),
171 if (widget.exchangeTradeViewModel.trade.extraId != null)
172 CopyWrapper(
173 data: ClipboardData(
174 text: widget.exchangeTradeViewModel.trade.extraId!),
175 builder: (context, copied) => Container(
176 width: double.infinity,
177 decoration: BoxDecoration(
178 color: Theme.of(context).colorScheme.surfaceContainer,
179 borderRadius: BorderRadius.circular(12),
180 ),
181 child: Padding(
182 padding: const EdgeInsets.all(16),
183 child: Column(
184 mainAxisSize: MainAxisSize.min,
185 spacing: 8,
186 children: [
187 Text(
188 S.of(context).destination_tag,
189 textAlign: TextAlign.center,
190 style: TextStyle(
191 fontSize: 14,
192 fontWeight: FontWeight.w500,
193 color: Theme.of(context).colorScheme.onSurfaceVariant),
194 ),
195 Row(
196 mainAxisAlignment: MainAxisAlignment.center,
197 crossAxisAlignment: CrossAxisAlignment.start,
198 spacing: 8,
199 children: [
200 Flexible(
201 child: Text(
202 widget.exchangeTradeViewModel.trade.extraId!,
203 textAlign: TextAlign.center,
204 style: TextStyle(
205 fontSize: 18,
206 fontWeight: FontWeight.w600,
207 color: Theme.of(context).colorScheme.primary),
208 ),
209 ),
210 AnimatedSwitcher(
211 duration: const Duration(milliseconds: 200),
212 child: Icon(
213 copied ? Icons.check : Icons.copy,
214 key: ValueKey(copied),
215 // Only the icon changes here, so label
216 // the copied state for CopyWrapper's
217 // live region to announce.
218 semanticLabel: copied ? S.of(context).copied : null,
219 size: 18,
220 color: Theme.of(context).colorScheme.primary,
221 ),
222 ),
223 ],
224 ),
225 ],
226 ),
227 ),
228 ),
229 ),
230 Row(
231 spacing: 8,
232 children: [
233 Flexible(
234 child: NewPrimaryButton(
235 onPressed: () =>
236 ClipboardUtil.copyToClipboard(context, widget.address),
237 text: S.of(context).copy,
238 color: Theme.of(context).colorScheme.primary,
239 textColor: Theme.of(context).colorScheme.onPrimary),
240 ),
241 Flexible(
242 child: NewPrimaryButton(
243 onPressed: Navigator.of(context).pop,
244 text: S.of(context).sent_the_funds,
245 color: Theme.of(context).colorScheme.surfaceContainer,
246 textColor: Theme.of(context).colorScheme.primary),
247 ),
248 ],
249 ),
250 SizedBox()
251 ],
252 ),
253 ),
254 ],
255 ),
256 ),
257 ),
258 );
259 }
260 }