| 1 | import 'package:cake_wallet/di.dart'; |
| 2 | import 'package:cake_wallet/generated/i18n.dart'; |
| 3 | import 'package:cake_wallet/new-ui/widgets/new_primary_button.dart'; |
| 4 | import 'package:cake_wallet/src/screens/base_page.dart'; |
| 5 | import 'package:cake_wallet/src/screens/wallet_connect/services/walletkit_service.dart'; |
| 6 | import 'package:cake_wallet/src/screens/wallet_connect/utils/wc_permissions_mapper.dart'; |
| 7 | import 'package:cake_wallet/src/screens/wallet_connect/widgets/wc_dapp_card.dart'; |
| 8 | import 'package:cake_wallet/src/screens/wallet_connect/widgets/wc_permissions_card.dart'; |
| 9 | import 'package:cake_wallet/src/screens/wallet_connect/widgets/wc_wallet_card.dart'; |
| 10 | import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart'; |
| 11 | import 'package:cake_wallet/store/app_store.dart'; |
| 12 | import 'package:cake_wallet/utils/show_pop_up.dart'; |
| 13 | import 'package:flutter/material.dart'; |
| 14 | import 'package:reown_walletkit/reown_walletkit.dart'; |
| 15 | |
| 16 | class WalletConnectPairingDetailsPage extends StatefulWidget { |
| 17 | final PairingInfo pairing; |
| 18 | final WalletKitService walletKitService; |
| 19 | |
| 20 | const WalletConnectPairingDetailsPage({ |
| 21 | required this.pairing, |
| 22 | required this.walletKitService, |
| 23 | super.key, |
| 24 | }); |
| 25 | |
| 26 | @override |
| 27 | WalletConnectPairingDetailsPageState createState() => WalletConnectPairingDetailsPageState(); |
| 28 | } |
| 29 | |
| 30 | class WalletConnectPairingDetailsPageState extends State<WalletConnectPairingDetailsPage> { |
| 31 | late String expiryDate; |
| 32 | List<SessionData> sessions = const []; |
| 33 | |
| 34 | @override |
| 35 | void initState() { |
| 36 | super.initState(); |
| 37 | initDateTime(); |
| 38 | WidgetsBinding.instance.addPostFrameCallback((_) { |
| 39 | if (!mounted) return; |
| 40 | setState(() { |
| 41 | sessions = widget.walletKitService.getSessionsForPairingInfo(widget.pairing); |
| 42 | }); |
| 43 | }); |
| 44 | } |
| 45 | |
| 46 | void initDateTime() { |
| 47 | final dateTime = DateTime.fromMillisecondsSinceEpoch(widget.pairing.expiry * 1000); |
| 48 | expiryDate = '${dateTime.year}-' |
| 49 | '${dateTime.month.toString().padLeft(2, '0')}-' |
| 50 | '${dateTime.day.toString().padLeft(2, '0')}'; |
| 51 | } |
| 52 | |
| 53 | @override |
| 54 | Widget build(BuildContext context) { |
| 55 | return WCCDetailsWidget( |
| 56 | pairing: widget.pairing, |
| 57 | expiryDate: expiryDate, |
| 58 | sessions: sessions, |
| 59 | walletKitService: widget.walletKitService, |
| 60 | ); |
| 61 | } |
| 62 | } |
| 63 | |
| 64 | class WCCDetailsWidget extends BasePage { |
| 65 | WCCDetailsWidget({ |
| 66 | required this.pairing, |
| 67 | required this.expiryDate, |
| 68 | required this.sessions, |
| 69 | required this.walletKitService, |
| 70 | }); |
| 71 | |
| 72 | final PairingInfo pairing; |
| 73 | final String expiryDate; |
| 74 | final List<SessionData> sessions; |
| 75 | final WalletKitService walletKitService; |
| 76 | |
| 77 | @override |
| 78 | Widget body(BuildContext context) { |
| 79 | final colors = Theme.of(context).colorScheme; |
| 80 | final metadata = pairing.peerMetadata; |
| 81 | if (metadata == null) { |
| 82 | return const SizedBox.shrink(); |
| 83 | } |
| 84 | |
| 85 | final iconUrl = metadata.icons.isNotEmpty ? metadata.icons.first : null; |
| 86 | final walletName = getIt.get<AppStore>().wallet?.name ?? ''; |
| 87 | |
| 88 | return SafeArea( |
| 89 | child: SingleChildScrollView( |
| 90 | padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), |
| 91 | child: Column( |
| 92 | crossAxisAlignment: CrossAxisAlignment.stretch, |
| 93 | children: [ |
| 94 | WCDappCard( |
| 95 | name: metadata.name, |
| 96 | iconUrl: iconUrl, |
| 97 | subtitle: metadata.url, |
| 98 | action: WCDappCardAction.connected, |
| 99 | ), |
| 100 | const SizedBox(height: 12), |
| 101 | Text( |
| 102 | '${S.of(context).expiresOn}: $expiryDate', |
| 103 | textAlign: TextAlign.center, |
| 104 | style: Theme.of(context).textTheme.bodySmall!.copyWith( |
| 105 | color: colors.onSurfaceVariant, |
| 106 | ), |
| 107 | ), |
| 108 | const SizedBox(height: 24), |
| 109 | for (final session in sessions) ...[ |
| 110 | _SessionSection( |
| 111 | session: session, |
| 112 | walletName: walletName, |
| 113 | ), |
| 114 | const SizedBox(height: 24), |
| 115 | ], |
| 116 | const SizedBox(height: 24), |
| 117 | NewPrimaryButton( |
| 118 | onPressed: () => _onDeleteButtonPressed(context, metadata.name, walletKitService), |
| 119 | text: S.current.delete, |
| 120 | color: colors.error, |
| 121 | textColor: colors.onError, |
| 122 | ), |
| 123 | const SizedBox(height: 12), |
| 124 | ], |
| 125 | ), |
| 126 | ), |
| 127 | ); |
| 128 | } |
| 129 | |
| 130 | Future<void> _onDeleteButtonPressed( |
| 131 | BuildContext context, |
| 132 | String dAppName, |
| 133 | WalletKitService walletKitService, |
| 134 | ) async { |
| 135 | bool confirmed = false; |
| 136 | |
| 137 | await showPopUp<void>( |
| 138 | context: context, |
| 139 | builder: (BuildContext dialogContext) { |
| 140 | return AlertWithTwoActions( |
| 141 | alertTitle: S.of(context).delete, |
| 142 | alertContent: '${S.current.deleteConnectionConfirmationPrompt} $dAppName?', |
| 143 | leftButtonText: S.of(context).cancel, |
| 144 | rightButtonText: S.of(context).delete, |
| 145 | actionLeftButton: () => Navigator.of(dialogContext).pop(), |
| 146 | actionRightButton: () { |
| 147 | confirmed = true; |
| 148 | Navigator.of(dialogContext).pop(); |
| 149 | }, |
| 150 | ); |
| 151 | }, |
| 152 | ); |
| 153 | if (confirmed) { |
| 154 | try { |
| 155 | await walletKitService.deletePairing(topic: pairing.topic); |
| 156 | |
| 157 | if (Navigator.canPop(context)) { |
| 158 | Navigator.pop(context); |
| 159 | } |
| 160 | } catch (e) { |
| 161 | debugPrint(e.toString()); |
| 162 | } |
| 163 | } |
| 164 | } |
| 165 | } |
| 166 | |
| 167 | class _SessionSection extends StatelessWidget { |
| 168 | const _SessionSection({ |
| 169 | required this.session, |
| 170 | required this.walletName, |
| 171 | }); |
| 172 | |
| 173 | final SessionData session; |
| 174 | final String walletName; |
| 175 | |
| 176 | String _firstAddress() { |
| 177 | for (final namespace in session.namespaces.values) { |
| 178 | if (namespace.accounts.isNotEmpty) { |
| 179 | return NamespaceUtils.getAccount(namespace.accounts.first); |
| 180 | } |
| 181 | } |
| 182 | return ''; |
| 183 | } |
| 184 | |
| 185 | @override |
| 186 | Widget build(BuildContext context) { |
| 187 | final permissions = WCPermissionsMapper.fromGeneratedNamespaces(session.namespaces); |
| 188 | final address = _firstAddress(); |
| 189 | |
| 190 | return Column( |
| 191 | crossAxisAlignment: CrossAxisAlignment.stretch, |
| 192 | children: [ |
| 193 | WCWalletCard(walletName: walletName, address: address), |
| 194 | const SizedBox(height: 24), |
| 195 | WCPermissionsCard(permissions: permissions), |
| 196 | ], |
| 197 | ); |
| 198 | } |
| 199 | } |