Add contact OK, working on qr scan
This commit is contained in:
parent
ca2521fe29
commit
7e2f2a5d3b
@ -1,6 +1,7 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<uses-permission android:name="android.permission.READ_CONTACTS"/>
|
||||
<uses-permission android:name="android.permission.WRITE_CONTACTS"/>
|
||||
<uses-feature android:name="android.hardware.camera" android:required="false" />
|
||||
<!-- The INTERNET permission is required for development. Specifically,
|
||||
the Flutter tool needs it to communicate with the running application
|
||||
to allow setting breakpoints, to provide hot reload, etc.
|
||||
|
@ -4,7 +4,8 @@
|
||||
<application
|
||||
android:label="com.example.dialer"
|
||||
android:name="${applicationName}"
|
||||
android:icon="@mipmap/ic_launcher">
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:enableOnBackInvokedCallback="true">
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:exported="true"
|
||||
|
@ -1,6 +1,8 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<uses-permission android:name="android.permission.READ_CONTACTS"/>
|
||||
<uses-permission android:name="android.permission.WRITE_CONTACTS"/>
|
||||
<uses-permission android:name="android.permission.CAMERA"/>
|
||||
<uses-feature android:name="android.hardware.camera" android:required="false" />
|
||||
<!-- The INTERNET permission is required for development. Specifically,
|
||||
the Flutter tool needs it to communicate with the running application
|
||||
to allow setting breakpoints, to provide hot reload, etc.
|
||||
|
@ -1,3 +1,4 @@
|
||||
org.gradle.jvmargs=-Xmx4G -XX:MaxMetaspaceSize=2G -XX:+HeapDumpOnOutOfMemoryError
|
||||
android.useAndroidX=true
|
||||
android.enableJetifier=true
|
||||
dev.steenbakker.mobile_scanner.useUnbundled=true
|
||||
|
@ -5,7 +5,7 @@ import 'contact_service.dart';
|
||||
class ContactState extends StatefulWidget {
|
||||
final Widget child;
|
||||
|
||||
const ContactState({Key? key, required this.child}) : super(key: key);
|
||||
const ContactState({super.key, required this.child});
|
||||
|
||||
static _ContactStateState of(BuildContext context) {
|
||||
return context.dependOnInheritedWidgetOfExactType<_InheritedContactState>()!.data;
|
||||
@ -92,8 +92,7 @@ class _ContactStateState extends State<ContactState> {
|
||||
class _InheritedContactState extends InheritedWidget {
|
||||
final _ContactStateState data;
|
||||
|
||||
const _InheritedContactState({Key? key, required this.data, required Widget child})
|
||||
: super(key: key, child: child);
|
||||
const _InheritedContactState({required this.data, required super.child});
|
||||
|
||||
@override
|
||||
bool updateShouldNotify(_InheritedContactState oldWidget) => true;
|
||||
|
@ -1,14 +1,23 @@
|
||||
import 'package:android_intent_plus/android_intent.dart';
|
||||
import 'package:dialer/widgets/qr_scanner.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class AddContactButton extends StatelessWidget {
|
||||
const AddContactButton({Key? key}) : super(key: key);
|
||||
const AddContactButton({super.key});
|
||||
|
||||
Future<void> 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),
|
||||
onPressed: () {
|
||||
// Show pop-up with two mock choices
|
||||
showDialog(
|
||||
context: context,
|
||||
barrierDismissible: true, // Allows dismissal by tapping outside
|
||||
@ -21,16 +30,20 @@ class AddContactButton extends StatelessWidget {
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
// Action for Option 1
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(builder: (context) => QRCodeScannerScreen()),
|
||||
);
|
||||
},
|
||||
child: Text("Option 1", style: TextStyle(color: Colors.white)),
|
||||
child: Text("Scan QR code", style: TextStyle(color: Colors.white)),
|
||||
),
|
||||
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
onPressed: () async {
|
||||
createNewContact();
|
||||
Navigator.of(context).pop();
|
||||
// Action for Option 2
|
||||
},
|
||||
child: Text("Option 2", style: TextStyle(color: Colors.white)),
|
||||
child: Text("Create new contact", style: TextStyle(color: Colors.white)),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
@ -1,5 +1,4 @@
|
||||
import 'package:dialer/widgets/username_color_generator.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_contacts/flutter_contacts.dart';
|
||||
import '../../../widgets/color_darkener.dart';
|
||||
@ -11,7 +10,7 @@ class AlphabetScrollPage extends StatefulWidget {
|
||||
final List<Contact> contacts;
|
||||
final double scrollOffset;
|
||||
|
||||
const AlphabetScrollPage({Key? key, required this.contacts, required this.scrollOffset}) : super(key: key);
|
||||
const AlphabetScrollPage({super.key, required this.contacts, required this.scrollOffset});
|
||||
|
||||
@override
|
||||
_AlphabetScrollPageState createState() => _AlphabetScrollPageState();
|
||||
|
@ -1,4 +1,3 @@
|
||||
import 'package:dialer/features/contacts/contact_service.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
|
||||
@ -24,6 +23,8 @@ class _HistoryPageState extends State<HistoryPage> {
|
||||
body: ListView.builder(
|
||||
itemCount: histories.length,
|
||||
itemBuilder: (context, index) {
|
||||
return null;
|
||||
|
||||
//
|
||||
},
|
||||
),
|
||||
|
@ -1,7 +1,7 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class LoadingIndicatorWidget extends StatelessWidget {
|
||||
const LoadingIndicatorWidget({Key? key}) : super(key: key);
|
||||
const LoadingIndicatorWidget({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
161
lib/widgets/qr_scanner.dart
Normal file
161
lib/widgets/qr_scanner.dart
Normal file
@ -0,0 +1,161 @@
|
||||
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);
|
||||
|
||||
@override
|
||||
_QRCodeScannerScreenState createState() => _QRCodeScannerScreenState();
|
||||
}
|
||||
|
||||
class _QRCodeScannerScreenState extends State<QRCodeScannerScreen> {
|
||||
MobileScannerController cameraController = MobileScannerController();
|
||||
|
||||
bool isScanning = true;
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
cameraController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
Future<void> _createContactFromVCard(String vCardData) async {
|
||||
// Parse VCard data
|
||||
final Map<String, dynamic> 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<String, dynamic> _parseVCard(String vCardData) {
|
||||
// Simple parser for VCard data
|
||||
final Map<String, dynamic> 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.'),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop(); // Close dialog
|
||||
isScanning = true; // Resume scanning
|
||||
},
|
||||
child: Text('Try Again'),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text('Scan Contact QR Code'),
|
||||
),
|
||||
body: MobileScanner(
|
||||
controller: cameraController,
|
||||
onDetect: (capture) {
|
||||
if (!isScanning) return;
|
||||
|
||||
isScanning = false; // Prevent multiple scans
|
||||
final List<Barcode> barcodes = capture.barcodes;
|
||||
|
||||
for (final barcode in barcodes) {
|
||||
final String? code = barcode.rawValue;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -36,9 +36,12 @@ dependencies:
|
||||
# Use with the CupertinoIcons class for iOS style icons.
|
||||
cupertino_icons: ^1.0.8
|
||||
flutter_contacts: ^1.1.9+2
|
||||
permission_handler: ^10.2.0 # For handling permissions
|
||||
permission_handler: ^11.3.1 # For handling permissions
|
||||
cached_network_image: ^3.2.3 # For caching contact images
|
||||
qr_flutter: ^4.1.0
|
||||
android_intent_plus: ^5.2.0
|
||||
camera: ^0.10.0+2
|
||||
mobile_scanner: ^6.0.2
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
|
Loading…
Reference in New Issue
Block a user