dev
dart 185 lines 6.6 KB
Raw
1 import 'package:cake_wallet/bitcoin/bitcoin.dart';
2 import 'package:cake_wallet/generated/i18n.dart';
3 import 'package:cake_wallet/routes.dart';
4 import 'package:cake_wallet/src/screens/base_page.dart';
5 import 'package:cake_wallet/src/screens/new_wallet/widgets/select_button.dart';
6 import 'package:cake_wallet/src/screens/transaction_details/blockexplorer_list_item.dart';
7 import 'package:cake_wallet/src/screens/transaction_details/standart_list_item.dart';
8 import 'package:cake_wallet/src/screens/transaction_details/textfield_list_item.dart';
9 import 'package:cake_wallet/src/screens/transaction_details/widgets/textfield_list_row.dart';
10 import 'package:cake_wallet/src/widgets/list_row.dart';
11 import 'package:cake_wallet/src/widgets/standard_list.dart';
12 import 'package:cake_wallet/utils/address_formatter.dart';
13 import 'package:cake_wallet/utils/show_bar.dart';
14 import 'package:cake_wallet/view_model/transaction_details_view_model.dart';
15 import 'package:cw_core/wallet_type.dart';
16 import 'package:flutter/material.dart';
17 import 'package:flutter/services.dart';
18 import 'package:flutter_mobx/flutter_mobx.dart';
19
20 class TransactionDetailsPage extends BasePage {
21 TransactionDetailsPage({required this.transactionDetailsViewModel}) {
22 if (transactionDetailsViewModel.sendViewModel.isElectrumWallet) {
23 bitcoin!.updateFeeRates(transactionDetailsViewModel.sendViewModel.wallet);
24 }
25 }
26
27 @override
28 String get title => S.current.transaction_details_title;
29
30 final TransactionDetailsViewModel transactionDetailsViewModel;
31
32 @override
33 Widget body(BuildContext context) {
34 return Column(
35 children: [
36 Expanded(
37 child: SectionStandardList(
38 sectionCount: 1,
39 itemCounter: (int _) => transactionDetailsViewModel.items.length,
40 itemBuilder: (__, index) {
41 final item = transactionDetailsViewModel.items[index];
42
43 if (item is StandartListItem) {
44 Widget? addressTextWidget;
45
46 if (item.title.toLowerCase() == 'recipient addresses' ||
47 item.title.toLowerCase() == 'source address') {
48 addressTextWidget = getFormattedAddress(
49 context: context,
50 value: item.value,
51 walletType: transactionDetailsViewModel.sendViewModel.walletType,
52 );
53 }
54
55 return GestureDetector(
56 key: item.key,
57 onTap: () {
58 final textToCopy = item.title.toLowerCase() ==
59 S.of(context).transaction_details_transaction_id.toLowerCase()
60 ? item.value.replaceAll(RegExp(r'_(incoming|outgoing)$'), '')
61 : item.value;
62 Clipboard.setData(ClipboardData(text: textToCopy));
63 showBar<void>(context, S.of(context).transaction_details_copied(item.title));
64 },
65 child: ListRow(
66 title: '${item.title}:',
67 value: item.value,
68 textWidget: addressTextWidget,
69 ),
70 );
71 }
72
73 if (item is BlockExplorerListItem) {
74 return GestureDetector(
75 key: item.key,
76 onTap: item.onTap,
77 child: ListRow(
78 title: '${item.title}:',
79 value: item.value,
80 mainTextColor: Theme.of(context).colorScheme.primary,
81 ),
82 );
83 }
84
85 if (item is TextFieldListItem) {
86 return TextFieldListRow(
87 key: item.key,
88 title: item.title,
89 value: item.value,
90 onSubmitted: item.onSubmitted,
91 );
92 }
93
94 return Container();
95 },
96 ),
97 ),
98 Observer(
99 builder: (_) {
100 if (transactionDetailsViewModel.canReplaceByFee) {
101 return Padding(
102 padding: const EdgeInsets.all(24),
103 child: SelectButton(
104 text: S.of(context).bump_fee,
105 onTap: () async {
106 Navigator.of(context).pushNamed(Routes.bumpFeePage, arguments: [
107 transactionDetailsViewModel.transactionInfo,
108 transactionDetailsViewModel.rawTransaction
109 ]);
110 },
111 ),
112 );
113 }
114
115 return const SizedBox();
116 },
117 ),
118 ],
119 );
120 }
121
122 Widget getFormattedAddress({
123 required BuildContext context,
124 required String value,
125 required WalletType walletType,
126 }) {
127 final textStyle = Theme.of(context).textTheme.bodyMedium!.copyWith(
128 fontSize: 16,
129 fontWeight: FontWeight.w500,
130 color: Theme.of(context).colorScheme.onSurface,
131 );
132 final List<Widget> children = [];
133 final bool hasDoubleNewline = value.contains('\n\n');
134
135 if (hasDoubleNewline) {
136 final blocks = value.split('\n\n').map((b) => b.trim()).where((b) => b.isNotEmpty).toList();
137 for (final block in blocks) {
138 final lines = block.split('\n').map((l) => l.trim()).where((l) => l.isNotEmpty).toList();
139 if (lines.length > 1) {
140 children.add(Text(lines.first, style: textStyle));
141 for (int i = 1; i < lines.length; i++) {
142 children.add(
143 AddressFormatter.buildSegmentedAddress(
144 address: lines[i],
145 walletType: walletType,
146 evenTextStyle: textStyle,
147 ),
148 );
149 }
150 } else {
151 children.add(
152 AddressFormatter.buildSegmentedAddress(
153 address: lines.first,
154 walletType: walletType,
155 evenTextStyle: textStyle,
156 ),
157 );
158 }
159 children.add(SizedBox(height: 8));
160 }
161 } else {
162 final lines = value.split('\n').map((l) => l.trim()).where((l) => l.isNotEmpty).toList();
163 bool firstLineIsContactName = (lines.length > 1 && lines.first.length < 20);
164 int startIndex = 0;
165 if (firstLineIsContactName) {
166 children.add(Text(lines.first, style: textStyle));
167 startIndex = 1;
168 }
169 for (int i = startIndex; i < lines.length; i++) {
170 children.add(
171 AddressFormatter.buildSegmentedAddress(
172 address: lines[i],
173 walletType: walletType,
174 evenTextStyle: textStyle,
175 ),
176 );
177 }
178 }
179
180 return Column(
181 crossAxisAlignment: CrossAxisAlignment.start,
182 children: children,
183 );
184 }
185 }