dev
dart 252 lines 10.1 KB
Raw
1 import "package:cake_wallet/core/execution_state.dart";
2 import "package:cake_wallet/generated/i18n.dart";
3 import "package:cake_wallet/src/screens/base_page.dart";
4 import "package:cake_wallet/src/screens/transaction_details/rbf_details_list_fee_picker_item.dart";
5 import "package:cake_wallet/src/screens/transaction_details/standart_list_item.dart";
6 import "package:cake_wallet/src/screens/transaction_details/textfield_list_item.dart";
7 import "package:cake_wallet/src/screens/transaction_details/transaction_expandable_list_item.dart";
8 import "package:cake_wallet/src/screens/transaction_details/widgets/textfield_list_row.dart";
9 import "package:cake_wallet/src/widgets/alert_with_one_action.dart";
10 import "package:cake_wallet/src/widgets/alert_with_two_actions.dart";
11 import "package:cake_wallet/src/widgets/bottom_sheet/base_bottom_sheet_widget.dart";
12 import "package:cake_wallet/src/widgets/bottom_sheet/confirm_sending_bottom_sheet_widget.dart";
13 import "package:cake_wallet/src/widgets/bottom_sheet/info_bottom_sheet_widget.dart";
14 import "package:cake_wallet/src/widgets/list_row.dart";
15 import "package:cake_wallet/src/widgets/primary_button.dart";
16 import "package:cake_wallet/src/widgets/standard_expandable_list.dart";
17 import "package:cake_wallet/src/widgets/standard_list.dart";
18 import "package:cake_wallet/src/widgets/standard_picker_list.dart";
19 import "package:cake_wallet/utils/show_bar.dart";
20 import "package:cake_wallet/utils/show_pop_up.dart";
21 import "package:cake_wallet/view_model/send/send_view_model_state.dart";
22 import "package:cake_wallet/view_model/transaction_details_view_model.dart";
23 import "package:flutter/material.dart";
24 import "package:flutter/services.dart";
25 import "package:flutter_mobx/flutter_mobx.dart";
26 import "package:mobx/mobx.dart";
27
28 class RBFDetailsPage extends BasePage {
29 RBFDetailsPage({required this.transactionDetailsViewModel, required this.rawTransaction}) {
30 transactionDetailsViewModel.addBumpFeesListItems(
31 transactionDetailsViewModel.transactionInfo,
32 rawTransaction,
33 );
34 }
35
36 @override
37 String get title => S.current.bump_fee;
38
39 final TransactionDetailsViewModel transactionDetailsViewModel;
40 final String rawTransaction;
41
42 bool _effectsInstalled = false;
43
44 @override
45 Widget body(BuildContext context) {
46 _setEffects(context);
47 return Column(
48 children: [
49 Expanded(
50 child: SectionStandardList(
51 sectionCount: 1,
52 itemCounter: (_) => transactionDetailsViewModel.rbfListItems.length,
53 itemBuilder: (__, index) {
54 final item = transactionDetailsViewModel.rbfListItems[index];
55
56 if (item is StandartListItem) {
57 return GestureDetector(
58 onTap: () {
59 Clipboard.setData(ClipboardData(text: item.value));
60 showBar<void>(context, S.of(context).transaction_details_copied(item.title));
61 },
62 child: ListRow(title: "${item.title}:", value: item.value),
63 );
64 }
65
66 if (item is StandardExpandableListItem) {
67 return StandardExpandableList(
68 title: "${item.title}: ${item.expandableItems.length}",
69 expandableItems: item.expandableItems,
70 );
71 }
72
73 if (item is StandardPickerListItem) {
74 return StandardPickerList(
75 title: item.title,
76 value: item.value,
77 items: item.items,
78 displayItem: item.displayItem,
79 onSliderChanged: item.onSliderChanged,
80 onItemSelected: item.onItemSelected,
81 selectedIdx: item.selectedIdx,
82 customItemIndex: item.customItemIndex,
83 customValue: item.customValue,
84 maxValue: item.maxValue,
85 );
86 }
87
88 if (item is TextFieldListItem) {
89 return TextFieldListRow(
90 title: item.title,
91 value: item.value,
92 onSubmitted: item.onSubmitted,
93 );
94 }
95
96 return Container();
97 },
98 ),
99 ),
100 Padding(
101 padding: const EdgeInsets.all(24),
102 child: Observer(
103 builder: (_) => LoadingPrimaryButton(
104 onPressed: () => transactionDetailsViewModel
105 .replaceByFee(transactionDetailsViewModel.newFee.toString()),
106 text: S.of(context).send,
107 isLoading: transactionDetailsViewModel.sendViewModel.state is IsExecutingState,
108 isDisabled:
109 transactionDetailsViewModel.sendViewModel.state is ExecutedSuccessfullyState,
110 color: Theme.of(context).colorScheme.primary,
111 textColor: Theme.of(context).colorScheme.onPrimary,
112 ),
113 ),
114 ),
115 ],
116 );
117 }
118
119 BuildContext? loadingBottomSheetContext;
120
121 void _setEffects(BuildContext context) {
122 if (_effectsInstalled) {
123 return;
124 }
125
126 reaction((_) => transactionDetailsViewModel.sendViewModel.state, (state) {
127 if (state is! IsExecutingState &&
128 loadingBottomSheetContext != null &&
129 loadingBottomSheetContext!.mounted) {
130 Navigator.of(loadingBottomSheetContext!).pop();
131 }
132
133 if (state is FailureState) {
134 WidgetsBinding.instance.addPostFrameCallback((_) {
135 showPopUp<void>(
136 context: context,
137 builder: (popupContext) => AlertWithOneAction(
138 alertTitle: S.of(popupContext).error,
139 alertContent: state.error,
140 buttonText: S.of(popupContext).ok,
141 buttonAction: () => Navigator.of(popupContext).pop(),
142 ),
143 );
144 });
145 }
146 if (state is AwaitingConfirmationState) {
147 WidgetsBinding.instance.addPostFrameCallback((_) {
148 showPopUp<void>(
149 context: context,
150 builder: (popupContext) => AlertWithTwoActions(
151 alertTitle: state.title ?? "",
152 alertContent: state.message ?? "",
153 rightButtonText: S.of(context).ok,
154 leftButtonText: S.of(context).cancel,
155 actionRightButton: () {
156 state.onConfirm?.call();
157 Navigator.of(popupContext).pop();
158 },
159 actionLeftButton: () {
160 state.onCancel?.call();
161 Navigator.of(popupContext).pop();
162 },
163 ),
164 );
165 });
166 }
167
168 if (state is IsExecutingState) {
169 WidgetsBinding.instance.addPostFrameCallback((_) {
170 if (context.mounted) {
171 showModalBottomSheet<void>(
172 context: context,
173 isDismissible: false,
174 builder: (context) {
175 loadingBottomSheetContext = context;
176 return LoadingBottomSheet(
177 titleText: S.of(context).generating_transaction,
178 );
179 },
180 );
181 }
182 });
183 }
184
185 if (state is ExecutedSuccessfullyState) {
186 WidgetsBinding.instance.addPostFrameCallback((_) async {
187 if (context.mounted) {
188 final result = await showModalBottomSheet<bool>(
189 context: context,
190 isDismissible: false,
191 isScrollControlled: true,
192 builder: (bottomSheetContext) => ConfirmSendingBottomSheet(
193 key: const ValueKey("rbf_confirm_sending_bottom_sheet"),
194 titleText: S.of(bottomSheetContext).confirm_transaction,
195 isSlideActionEnabled: transactionDetailsViewModel.sendViewModel.isReadyForSend,
196 walletType: transactionDetailsViewModel.sendViewModel.walletType,
197 titleIconPath:
198 transactionDetailsViewModel.sendViewModel.selectedCryptoCurrency.iconPath,
199 currency: transactionDetailsViewModel.sendViewModel.selectedCryptoCurrency,
200 amount: S.of(bottomSheetContext).send_amount,
201 amountValue:
202 transactionDetailsViewModel.sendViewModel.pendingTransaction!.amountFormatted,
203 fiatAmountValue:
204 transactionDetailsViewModel.sendViewModel.pendingTransactionFiatAmountFormatted,
205 fee: S.of(bottomSheetContext).send_fee,
206 feeValue:
207 transactionDetailsViewModel.sendViewModel.pendingTransaction!.feeFormatted,
208 feeFiatAmount: transactionDetailsViewModel
209 .sendViewModel.pendingTransactionFeeFiatAmountFormatted,
210 outputs: transactionDetailsViewModel.sendViewModel.outputs,
211 footerType: FooterType.slideActionButton,
212 accessibleNavigationModeSlideActionButtonText: S.of(context).send,
213 onSlideActionComplete: () async {
214 Navigator.of(bottomSheetContext).pop();
215 await transactionDetailsViewModel.sendViewModel.commitTransaction(context);
216 try {
217 if (bottomSheetContext.mounted) {
218 Navigator.of(bottomSheetContext).pop();
219 }
220 } catch (_) {}
221 },
222 change: transactionDetailsViewModel.sendViewModel.pendingTransaction!.change,
223 amountParsingProxy: transactionDetailsViewModel.sendViewModel.amountParsingProxy,
224 ),
225 );
226 if (result == null) {
227 await transactionDetailsViewModel.sendViewModel.dismissTransaction();
228 }
229 }
230 });
231 }
232
233 if (state is TransactionCommitted) {
234 WidgetsBinding.instance.addPostFrameCallback((_) {
235 if (context.mounted) {
236 showPopUp<void>(
237 context: context,
238 builder: (popupContext) => AlertWithOneAction(
239 alertTitle: S.of(popupContext).sending,
240 alertContent: S.of(popupContext).transaction_sent,
241 buttonText: S.of(popupContext).ok,
242 buttonAction: () => Navigator.of(popupContext).pop(),
243 ),
244 );
245 }
246 });
247 }
248 });
249
250 _effectsInstalled = true;
251 }
252 }