From 7b5448905c2f22da4f8b52210b3a67c26d40310c Mon Sep 17 00:00:00 2001 From: stcb <21@stcb.cc> Date: Sun, 12 Jan 2025 12:31:44 +0000 Subject: [PATCH] Fixing QrCode scan and related contact creation (#22) Reviewed-on: https://git.gmoker.com/icing/G-EIP-700-TLS-7-1-eip-stephane.corbiere/pulls/22 --- .../lib/features/contacts/contact_state.dart | 19 +++ .../contacts/widgets/add_contact_button.dart | 49 ++++--- dialer/lib/widgets/qr_scanner.dart | 121 +++--------------- 3 files changed, 63 insertions(+), 126 deletions(-) diff --git a/dialer/lib/features/contacts/contact_state.dart b/dialer/lib/features/contacts/contact_state.dart index 82e21c2..b6cf003 100644 --- a/dialer/lib/features/contacts/contact_state.dart +++ b/dialer/lib/features/contacts/contact_state.dart @@ -102,6 +102,25 @@ class _ContactStateState extends State { }); } + bool doesContactExist(Contact contact) { + // Example: consider it "existing" if there's a matching phone number + for (final existing in _allContacts) { + if (existing.toVCard() == contact.toVCard()) { + return true; + } + // for (final phone in existing.phones) { + // for (final newPhone in contact.phones) { + // // Simple exact match; you can do more advanced logic + // if (phone.normalizedNumber == newPhone.normalizedNumber) { + // return true; + // } + // } + // } We might switch to finer and smarter logic later, ex: remove trailing spaces, capitals + } + return false; + } + + @override Widget build(BuildContext context) { return _InheritedContactState( diff --git a/dialer/lib/features/contacts/widgets/add_contact_button.dart b/dialer/lib/features/contacts/widgets/add_contact_button.dart index e096a6c..399ab48 100644 --- a/dialer/lib/features/contacts/widgets/add_contact_button.dart +++ b/dialer/lib/features/contacts/widgets/add_contact_button.dart @@ -1,22 +1,14 @@ -import 'package:android_intent_plus/android_intent.dart'; import 'package:dialer/widgets/qr_scanner.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_contacts/flutter_contacts.dart'; class AddContactButton extends StatelessWidget { const AddContactButton({super.key}); - Future createNewContact() async { - AndroidIntent intent = AndroidIntent( - action: 'android.intent.action.INSERT', - type: 'vnd.android.cursor.dir/contact', - ); - await intent.launch(); - } - @override Widget build(BuildContext context) { return IconButton( - icon: Icon(Icons.add, color: Colors.blue), + icon: const Icon(Icons.add, color: Colors.blue), onPressed: () { showDialog( context: context, @@ -28,22 +20,37 @@ class AddContactButton extends StatelessWidget { mainAxisSize: MainAxisSize.min, children: [ TextButton( - onPressed: () { - Navigator.of(context).pop(); - Navigator.push( - context, - MaterialPageRoute(builder: (context) => QRCodeScannerScreen()), - ); - }, - child: Text("Scan QR code", style: TextStyle(color: Colors.white)), - ), + onPressed: () async { + Navigator.of(context).pop(); // close dialog + // Go to QR Scanner + final vCardString = await Navigator.push( + context, + MaterialPageRoute( + builder: (context) => const QRCodeScannerScreen(), + ), + ); + + if (vCardString != null && vCardString is String) { + await FlutterContacts.openExternalInsert(Contact + .fromVCard(vCardString)); + } + }, + child: const Text( + "Scan QR code", + style: TextStyle(color: Colors.white), + ), + ), TextButton( onPressed: () async { - createNewContact(); Navigator.of(context).pop(); + // Create a blank contact entry + await FlutterContacts.openExternalInsert(); }, - child: Text("Create new contact", style: TextStyle(color: Colors.white)), + child: const Text( + "Create new contact", + style: TextStyle(color: Colors.white), + ), ), ], ), diff --git a/dialer/lib/widgets/qr_scanner.dart b/dialer/lib/widgets/qr_scanner.dart index fcdf295..da0d80b 100644 --- a/dialer/lib/widgets/qr_scanner.dart +++ b/dialer/lib/widgets/qr_scanner.dart @@ -1,6 +1,5 @@ import 'package:flutter/material.dart'; import 'package:mobile_scanner/mobile_scanner.dart'; -import 'package:flutter_contacts/flutter_contacts.dart'; class QRCodeScannerScreen extends StatefulWidget { const QRCodeScannerScreen({Key? key}) : super(key: key); @@ -10,8 +9,7 @@ class QRCodeScannerScreen extends StatefulWidget { } class _QRCodeScannerScreenState extends State { - MobileScannerController cameraController = MobileScannerController(); - + final MobileScannerController cameraController = MobileScannerController(); bool isScanning = true; @override @@ -20,104 +18,22 @@ class _QRCodeScannerScreenState extends State { super.dispose(); } - Future _createContactFromVCard(String vCardData) async { - // Parse VCard data - final Map contactInfo = _parseVCard(vCardData); - - debugPrint("contactInfo: $contactInfo"); - - // // Create a new contact - // Contact newContact = Contact(); - // - // // Set contact's name - // newContact.name = Name( - // first: contactInfo['firstName'] ?? '', - // last: contactInfo['lastName'] ?? '', - // ); - // - // // Set contact's phone numbers - // if (contactInfo['phone'] != null) { - // newContact.phones = [ - // Phone(contactInfo['phone'], label: PhoneLabel.mobile), - // ]; - // } - // - // // Set contact's emails - // if (contactInfo['email'] != null) { - // newContact.emails = [ - // Email(contactInfo['email'], label: EmailLabel.home), - // ]; - // } - // - // // Request permission to write contacts - // bool permission = await FlutterContacts.requestPermission(readonly: false); - // if (!permission) { - // // Handle permission denied - // ScaffoldMessenger.of(context).showSnackBar( - // SnackBar(content: Text('Contacts permission denied')), - // ); - // return; - // } - // - // // Save the contact - // await newContact.insert(); - } - - Map _parseVCard(String vCardData) { - // Simple parser for VCard data - final Map contactInfo = {}; - - final lines = vCardData.split(RegExp(r'\r?\n')); - for (var line in lines) { - if (line.startsWith('FN:')) { - contactInfo['fullName'] = line.substring(3).trim(); - } else if (line.startsWith('N:')) { - final names = line.substring(2).split(';'); - contactInfo['lastName'] = names[0].trim(); - contactInfo['firstName'] = names.length > 1 ? names[1].trim() : ''; - } else if (line.startsWith('TEL:')) { - contactInfo['phone'] = line.substring(4).trim(); - } else if (line.startsWith('EMAIL:')) { - contactInfo['email'] = line.substring(6).trim(); - } - // Add more fields as needed - } - - return contactInfo; - } - - void _showContactAddedDialog() { - showDialog( - context: context, - builder: (context) => AlertDialog( - title: Text('Contact Added'), - content: Text('The contact has been added to your address book.'), - actions: [ - TextButton( - onPressed: () { - Navigator.of(context).pop(); // Close dialog - Navigator.of(context).pop(); // Go back to previous screen - }, - child: Text('OK'), - ), - ], - ), - ); - } - void _showInvalidQRDialog() { showDialog( context: context, builder: (context) => AlertDialog( - title: Text('Invalid QR Code'), - content: Text('The scanned QR code does not contain valid contact information.'), + title: const Text('Invalid QR Code'), + content: + const Text('The scanned QR code does not contain valid vCard data.'), actions: [ TextButton( onPressed: () { Navigator.of(context).pop(); // Close dialog - isScanning = true; // Resume scanning + setState(() { + isScanning = true; // Resume scanning + }); }, - child: Text('Try Again'), + child: const Text('Try Again'), ), ], ), @@ -128,32 +44,27 @@ class _QRCodeScannerScreenState extends State { Widget build(BuildContext context) { return Scaffold( appBar: AppBar( - title: Text('Scan Contact QR Code'), + title: const Text('Scan Contact QR Code'), ), body: MobileScanner( controller: cameraController, + // allowDuplicates: false, // or true, depending on your preference onDetect: (capture) { if (!isScanning) return; + isScanning = false; // Stop multiple triggers - isScanning = false; // Prevent multiple scans final List barcodes = capture.barcodes; - for (final barcode in barcodes) { final String? code = barcode.rawValue; + // If the QR code contains 'BEGIN:VCARD', let's assume it's a valid vCard if (code != null && code.contains('BEGIN:VCARD')) { - // Handle valid vCard QR code - _createContactFromVCard(code); - _showContactAddedDialog(); // TODO: Be a confirmation button "do you want to add XXX to your contacts?" - break; + Navigator.pop(context, code); // pop back with the full vCard text + return; } } - if (!barcodes.any((barcode) => - barcode.rawValue != null && barcode.rawValue!.contains('BEGIN:VCARD'))) { - // If no valid QR code is found - _showInvalidQRDialog(); - isScanning = true; // Allow scanning again for invalid QR codes - } + // If no valid vCard was found in any of the barcodes + _showInvalidQRDialog(); }, ), );