diff --git a/mobile-app/lib/providers/route_intent_providers.dart b/mobile-app/lib/providers/route_intent_providers.dart index 4b211420..e26222a4 100644 --- a/mobile-app/lib/providers/route_intent_providers.dart +++ b/mobile-app/lib/providers/route_intent_providers.dart @@ -10,6 +10,15 @@ class PaymentIntent { final String? ref; const PaymentIntent({required this.to, required this.amount, this.ref}); + + static PaymentIntent? tryParseUrl(String input) { + final uri = Uri.tryParse(input); + if (uri == null || uri.pathSegments.isEmpty || uri.pathSegments.first != 'pay') return null; + final to = uri.queryParameters['to']; + final amount = uri.queryParameters['amount']; + if (to == null || to.isEmpty || amount == null || amount.isEmpty) return null; + return PaymentIntent(to: to, amount: amount, ref: uri.queryParameters['ref']); + } } final paymentIntentProvider = StateProvider((_) => null); diff --git a/mobile-app/lib/services/deep_link_service.dart b/mobile-app/lib/services/deep_link_service.dart index d58a8d8d..906569d8 100644 --- a/mobile-app/lib/services/deep_link_service.dart +++ b/mobile-app/lib/services/deep_link_service.dart @@ -54,12 +54,9 @@ class DeepLinkService { } if (uri.pathSegments.isNotEmpty && uri.pathSegments.first == 'pay') { - final to = uri.queryParameters['to']; - final amount = uri.queryParameters['amount']; - final ref = uri.queryParameters['ref']; - - if (to != null && to.isNotEmpty && amount != null && amount.isNotEmpty) { - _ref.read(paymentIntentProvider.notifier).state = PaymentIntent(to: to, amount: amount, ref: ref); + final payment = PaymentIntent.tryParseUrl(uri.toString()); + if (payment != null) { + _ref.read(paymentIntentProvider.notifier).state = payment; navigatorKey.currentState?.pushNamed('/account'); } else { print('Missing payment parameters'); diff --git a/mobile-app/lib/v2/components/qr_scanner_page.dart b/mobile-app/lib/v2/components/qr_scanner_page.dart index f9522700..516e525a 100644 --- a/mobile-app/lib/v2/components/qr_scanner_page.dart +++ b/mobile-app/lib/v2/components/qr_scanner_page.dart @@ -6,7 +6,8 @@ import 'package:resonance_network_wallet/v2/components/glass_icon_button.dart'; import 'package:resonance_network_wallet/v2/theme/app_colors.dart'; class QrScannerPage extends StatefulWidget { - const QrScannerPage({super.key}); + final bool Function(String)? validator; + const QrScannerPage({super.key, this.validator}); @override State createState() => _QrScannerPageState(); @@ -25,10 +26,10 @@ class _QrScannerPageState extends State { void _onDetect(BarcodeCapture capture) { if (_scanned) return; final code = capture.barcodes.firstOrNull?.rawValue; - if (code != null && code.isNotEmpty) { - _scanned = true; - Navigator.pop(context, code); - } + if (code == null || code.isEmpty) return; + if (widget.validator != null && !widget.validator!(code)) return; + _scanned = true; + Navigator.pop(context, code); } Future _pickImage() async { diff --git a/mobile-app/lib/v2/screens/send/send_sheet.dart b/mobile-app/lib/v2/screens/send/send_sheet.dart index f946eabc..be2b18ca 100644 --- a/mobile-app/lib/v2/screens/send/send_sheet.dart +++ b/mobile-app/lib/v2/screens/send/send_sheet.dart @@ -8,6 +8,7 @@ import 'package:quantus_sdk/quantus_sdk.dart'; import 'package:resonance_network_wallet/v2/screens/send/send_providers.dart'; import 'package:resonance_network_wallet/v2/screens/send/send_screen_logic.dart'; import 'package:resonance_network_wallet/providers/account_providers.dart'; +import 'package:resonance_network_wallet/providers/route_intent_providers.dart'; import 'package:resonance_network_wallet/providers/wallet_providers.dart'; import 'package:resonance_network_wallet/services/transaction_submission_service.dart'; import 'package:resonance_network_wallet/v2/components/success_check.dart'; @@ -120,12 +121,24 @@ class _SendSheetState extends ConsumerState { } Future _scanQr() async { - final address = await Navigator.push( + final substrate = ref.read(substrateServiceProvider); + final scanResult = await Navigator.push( context, - MaterialPageRoute(fullscreenDialog: true, builder: (_) => const QrScannerPage()), + MaterialPageRoute( + fullscreenDialog: true, + builder: (_) => QrScannerPage( + validator: (code) => substrate.isValidSS58Address(code) || PaymentIntent.tryParseUrl(code) != null, + ), + ), ); - if (address != null && mounted) { - _recipientController.text = address; + // scanResult is either a valid address or a valid payment intent or null + if (scanResult == null || !mounted) return; + final payment = PaymentIntent.tryParseUrl(scanResult); + if (payment != null) { + _recipientController.text = payment.to; + _amountController.text = payment.amount; + } else { + _recipientController.text = scanResult; } }