| 1 | import 'dart:async'; |
| 2 | |
| 3 | import 'package:bbqrdart/bbqrdart.dart'; |
| 4 | import 'package:cake_wallet/bitcoin/bitcoin.dart'; |
| 5 | import 'package:cake_wallet/entities/qr_scanner.dart'; |
| 6 | import 'package:cake_wallet/generated/i18n.dart'; |
| 7 | import 'package:cake_wallet/monero/monero.dart'; |
| 8 | import 'package:cake_wallet/src/screens/base_page.dart'; |
| 9 | import 'package:cake_wallet/src/screens/ur/widgets/urqr.dart'; |
| 10 | import 'package:cake_wallet/src/widgets/alert_with_one_action.dart'; |
| 11 | import 'package:cake_wallet/src/widgets/primary_button.dart'; |
| 12 | import 'package:cake_wallet/utils/show_pop_up.dart'; |
| 13 | import 'package:cake_wallet/view_model/animated_ur_model.dart'; |
| 14 | import 'package:cw_core/wallet_type.dart'; |
| 15 | import 'package:flutter/material.dart'; |
| 16 | |
| 17 | class AnimatedURPage extends BasePage { |
| 18 | final bool isAll; |
| 19 | AnimatedURPage( |
| 20 | this.animatedURmodel, { |
| 21 | required Map<String, String> this.urQr, |
| 22 | this.isAll = false, |
| 23 | }) { |
| 24 | if (urQr.keys.first.startsWith("export-outputs") && |
| 25 | animatedURmodel.wallet.type == WalletType.monero) { |
| 26 | if (animatedURmodel.wallet.type == WalletType.monero) { |
| 27 | urQr = monero!.exportOutputsUR(animatedURmodel.wallet); |
| 28 | } else { |
| 29 | throw UnimplementedError("unable to handle UR: ${urQr.keys.first}"); |
| 30 | } |
| 31 | } |
| 32 | for (var key in urQr.keys) { |
| 33 | if (key.isEmpty || urQr[key]!.isEmpty) { |
| 34 | urQr.remove(key); |
| 35 | continue; |
| 36 | } |
| 37 | urQr[key] = urQr[key]!.trim(); |
| 38 | } |
| 39 | } |
| 40 | |
| 41 | Map<String, String> urQr = {}; |
| 42 | |
| 43 | final AnimatedURModel animatedURmodel; |
| 44 | |
| 45 | String get urQrType { |
| 46 | if (urQr.values.first.trim().substring(0, 2) == BBQR.header) { |
| 47 | return BBQR.header; |
| 48 | } |
| 49 | if (urQr.isEmpty) return "unknown"; |
| 50 | final first = urQr.values.first.trim().split("\n")[0]; |
| 51 | return first.split('/')[0]; |
| 52 | } |
| 53 | |
| 54 | @override |
| 55 | Widget body(BuildContext context) { |
| 56 | return Column( |
| 57 | mainAxisSize: MainAxisSize.min, |
| 58 | children: [ |
| 59 | Padding( |
| 60 | padding: const EdgeInsets.symmetric(horizontal: 32.0), |
| 61 | child: URQR( |
| 62 | urqr: urQr, |
| 63 | walletType: animatedURmodel.wallet.type, |
| 64 | hardwareWalletType: animatedURmodel.wallet.hardwareWalletType, |
| 65 | ), |
| 66 | ), |
| 67 | if (["ur:xmr-txunsigned", "ur:xmr-output", "ur:psbt", BBQR.header].contains(urQrType)) ...{ |
| 68 | Padding( |
| 69 | padding: const EdgeInsets.all(16.0), |
| 70 | child: SizedBox( |
| 71 | width: double.maxFinite, |
| 72 | child: PrimaryButton( |
| 73 | onPressed: () => _continue(context), |
| 74 | text: "Scan QR Code", |
| 75 | color: Theme.of(context).colorScheme.primary, |
| 76 | textColor: Theme.of(context).colorScheme.onPrimary, |
| 77 | ), |
| 78 | ), |
| 79 | ), |
| 80 | }, |
| 81 | ], |
| 82 | ); |
| 83 | } |
| 84 | |
| 85 | Future<void> _continue(BuildContext context) async { |
| 86 | try { |
| 87 | switch (urQrType) { |
| 88 | case "ur:xmr-txunsigned": // ur:xmr-txsigned |
| 89 | final ur = await presentQRScanner(context, showManualInput: false); |
| 90 | if (ur == null) return; |
| 91 | final result = await monero!.commitTransactionUR(animatedURmodel.wallet, ur); |
| 92 | if (result) { |
| 93 | Navigator.of(context).pop(true); |
| 94 | } |
| 95 | break; |
| 96 | case "ur:xmr-output": // xmr-keyimage |
| 97 | final ur = await presentQRScanner(context, showManualInput: false); |
| 98 | if (ur == null) return; |
| 99 | final result = await monero!.importKeyImagesUR(animatedURmodel.wallet, ur); |
| 100 | if (result) { |
| 101 | Navigator.of(context).pop(true); |
| 102 | } |
| 103 | break; |
| 104 | case "ur:psbt": // psbt |
| 105 | final ur = await presentQRScanner(context, showManualInput: false); |
| 106 | if (ur == null) return; |
| 107 | await bitcoin!.commitPsbtUR(animatedURmodel.wallet, ur.trim().split("\n")); |
| 108 | Navigator.of(context).pop(true); |
| 109 | default: |
| 110 | throw UnimplementedError("unable to handle UR: ${urQrType}"); |
| 111 | } |
| 112 | } catch (e) { |
| 113 | await showPopUp<void>( |
| 114 | context: context, |
| 115 | builder: (BuildContext context) { |
| 116 | return AlertWithOneAction( |
| 117 | alertTitle: S.of(context).error, |
| 118 | alertContent: e.toString(), |
| 119 | buttonText: S.of(context).ok, |
| 120 | buttonAction: () => Navigator.pop(context, true)); |
| 121 | }); |
| 122 | } |
| 123 | } |
| 124 | } |