The error make encountering indicates that the image_link field does not exist in some of the documents within the user_profile collection. This is causing the app to crash when I trying to access a non-existent field. I need to add error handling to check if the field exists before accessing it.and I need to fetch user profiles from the Firestore collection inside my ContactsPage,
User Profile Code
import 'dart:io';
import 'package:path/path.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:firebase_storage/firebase_storage.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
import 'package:proguard_86/screens/home_screen.dart'; // Ensure this import is correct
class UserProfile extends StatefulWidget {
static const String screenRoute = "userProfile";
final String email;
const UserProfile({Key? key, required this.email}) : super(key: key);
@override
State<UserProfile> createState() => _UserProfileState();
}
class _UserProfileState extends State<UserProfile> {
File? file;
String? url;
final TextEditingController _nameController = TextEditingController();
var emailcontroller = TextEditingController();
final FirebaseAuth _auth = FirebaseAuth.instance;
Future<void> getImage() async {
final ImagePicker picker = ImagePicker();
final XFile? image = await picker.pickImage(source: ImageSource.gallery);
if (image != null) {
file = File(image.path);
var imageName = basename(image.path);
var refStorage = FirebaseStorage.instance.ref(imageName);
await refStorage.putFile(file!);
url = await refStorage.getDownloadURL();
setState(() {});
}
}
Future<void> saveUserProfile(BuildContext context) async {
String uid = _auth.currentUser!.uid;
if (url != null && _nameController.text.isNotEmpty) {
await FirebaseFirestore.instance
.collection('signup')
.doc(widget.email)
.collection('user_profile')
.doc(uid) // You can use another identifier if needed
.set({
'name': _nameController.text,
'image_link': url,
});
// Navigate to the home screen after saving the profile
Navigator.pushNamed(context, Homescreen.screenroute); // Ensure the correct reference to HomeScreen
} else {
// Handle error, either url or name is not provided
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text("Please provide both name and image."),
backgroundColor: Colors.red,
),
);
}
}
@override
Widget build(BuildContext context) {
//String email=widget.email!;
return Scaffold(
backgroundColor: Colors.red,
appBar: AppBar(
backgroundColor: Colors.red,
title: const Text(
"Profile Info",
style: TextStyle(color: Colors.white),
),
centerTitle: true,
),
body: SingleChildScrollView(
padding: const EdgeInsets.symmetric(horizontal: 20),
child: Column(
children: [
const Text(
"Please provide your name and an optional profile photo",
style: TextStyle(color: Colors.white, fontSize: 12.5),
textAlign: TextAlign.center,
),
const SizedBox(height: 40),
Container(
padding: const EdgeInsets.all(26),
decoration: const BoxDecoration(
shape: BoxShape.circle,
color: Colors.white,
),
child: const Icon(Icons.add_a_photo_rounded),
),
const SizedBox(height: 40),
ElevatedButton(
onPressed: getImage,
child: const Text("Upload Image"),
),
if (url != null)
Image.network(
url!,
width: 100,
height: 100,
fit: BoxFit.fill,
),
Row(
children: [
Expanded(
child: TextFormField(
controller: _nameController,
decoration: const InputDecoration(
hintText: "Type your name here",
),
),
),
const Icon(
Icons.emoji_emotions_outlined,
color: Colors.white,
)
],
),
const SizedBox(height: 20),
ElevatedButton(
onPressed: () => saveUserProfile(context),
child: const Text("Save Profile"),
),
],
),
),
);
}
}
Contacts Page
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:contacts_service/contacts_service.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:proguard_86/Screens/ContactSearchDelegate.dart';
import 'package:proguard_86/Screens/individual_page.dart';
class ContactsPage extends StatefulWidget {
static const String screenroute = "ContactsPage";
const ContactsPage({Key? key}) : super(key: key);
@override
_ContactsPageState createState() => _ContactsPageState();
}
class _ContactsPageState extends State<ContactsPage> {
Set<Contact> _contacts = {};
bool _contactsLoaded = false;
TextEditingController _searchController = TextEditingController();
List<QueryDocumentSnapshot> data = [];
List<Map<String, dynamic>> userProfileData = [];
@override
void initState() {
super.initState();
_getContacts();
_askPermissions();
}
Future<void> _getContacts() async {
// Fetch user profiles from Firestore
QuerySnapshot userProfilesSnapshot = await FirebaseFirestore.instance.collection('signup').get();
for (var doc in userProfilesSnapshot.docs) {
String userId = doc.id;
QuerySnapshot userProfileSnapshot = await FirebaseFirestore.instance
.collection('signup')
.doc(userId)
.collection('user_profile')
.get();
setState(() {
data.addAll(userProfileSnapshot.docs);
});
}
}
Future<void> uploadContactToFirestore(Contact contact) async {
FirebaseAuth auth = FirebaseAuth.instance;
User? user = auth.currentUser;
if (user != null) {
FirebaseFirestore firestore = FirebaseFirestore.instance;
String userId = user.email!;
CollectionReference userCollection = firestore.collection('users').doc(userId).collection('contacts');
String phoneNumber = '';
if (contact.phones != null && contact.phones!.isNotEmpty) {
phoneNumber = contact.phones!.first.value!;
}
// Check if the contact with the same phone number already exists
QuerySnapshot existingContacts = await userCollection.where('phoneNumber', isEqualTo: phoneNumber).get();
if (existingContacts.docs.isNotEmpty) {
print('Contact already exists in Firestore: ${contact.displayName}');
return; // Do not upload the contact again
}
Map<String, dynamic> contactData = {
'name': contact.displayName ?? '',
'phoneNumber': phoneNumber,
'lastSeen': Timestamp.now(),
};
await userCollection.add(contactData);
print('Contact uploaded to Firestore: ${contact.displayName}');
} else {
print('User not logged in');
}
}
void navigateToIndividualPage(Contact contact) {
Navigator.pushNamed(
context,
Individualpage.screenroute,
arguments: {'title': contact.displayName ?? ''},
);
}
Future<void> _askPermissions() async {
PermissionStatus permissionStatus = await Permission.contacts.status;
if (permissionStatus != PermissionStatus.granted && permissionStatus != PermissionStatus.permanentlyDenied) {
permissionStatus = await Permission.contacts.request();
}
if (permissionStatus == PermissionStatus.granted) {
_loadContacts();
} else {
_handleInvalidPermissions(permissionStatus);
}
}
Future<void> _loadContacts() async {
List<Contact> contacts = await ContactsService.getContacts();
setState(() {
_contacts = contacts.toSet(); // Convert to Set to remove duplicates
_contactsLoaded = true;
});
}
void _handleInvalidPermissions(PermissionStatus permissionStatus) {
if (permissionStatus == PermissionStatus.denied) {
final snackBar = SnackBar(content: Text('Access to contacts denied'));
ScaffoldMessenger.of(context).showSnackBar(snackBar);
} else if (permissionStatus == PermissionStatus.permanentlyDenied) {
final snackBar = SnackBar(content: Text('Contact data not available on device'));
ScaffoldMessenger.of(context).showSnackBar(snackBar);
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: PreferredSize(
preferredSize: Size.fromHeight(70.0),
child: AppBar(
backgroundColor: Color(0xFF075E54),
automaticallyImplyLeading: false, // Don't show the leading button
title: Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
IconButton(
onPressed: () => Navigator.pop(context),
icon: Icon(Icons.arrow_back, color: Colors.white),
),
Flexible(
child: Container(
child: ListTile(
title: Text(
'Select contacts',
style: TextStyle(color: Colors.white, fontSize: 17, fontWeight: FontWeight.w500),
),
subtitle: Text('${_contacts.length} Contacts', style: TextStyle(color: Colors.white54, fontSize: 15)),
),
),
),
],
),
actions: <Widget>[
Container(
child: Row(
children: <Widget>[
Container(
width: 40,
child: IconButton(
icon: Icon(Icons.search),
onPressed: _contactsLoaded
? () {
showSearch(
context: context,
delegate: ContactSearchDelegate(
_contacts.toList(),
onContactSelected: navigateToIndividualPage,
),
);
}
: null,
),
),
Container(
width: 40,
child: IconButton(
icon: Icon(Icons.more_vert),
onPressed: () {},
),
),
],
),
),
],
),
),
body: ListView(
padding: EdgeInsets.only(top: 10),
children: <Widget>[
// Display user profiles from Firestore
for (var doc in data)
ListTile(
leading: CircleAvatar(
backgroundImage: doc.get('imageUrl') != null
? NetworkImage(doc.get('imageUrl'))
: AssetImage('images/default-avatar.png') as ImageProvider,
),
title: Text(
doc.get('name') ?? 'No name',
style: TextStyle(fontSize: 18, fontWeight: FontWeight.w500),
),
subtitle: Text(doc.get('email') ?? doc.get('phone') ?? 'No Contact Info'),
),
ListTile(
leading: Container(
height: 40,
width: 40,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(30),
color: Color(0xFF25D366),
),
child: IconButton(
icon: Icon(Icons.people),
onPressed: () {},
color: Colors.white,
),
),
title: Text(
'New Group',
style: TextStyle(fontSize: 18, fontWeight: FontWeight.w500),
),
),
ListTile(
leading: Container(
height: 40,
width: 40,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(30),
color: Color(0xFF25D366),
),
child: IconButton(
icon: Icon(Icons.person_add),
onPressed: () {},
color: Colors.white,
),
),
title: Text(
'New Contact',
style: TextStyle(fontSize: 18, fontWeight: FontWeight.w500),
),
),
// Add your contacts dynamically here
for (var contact in _contacts)
ListTile(
leading: Container(
height: 40,
width: 40,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(30),
color: Color(0xFF25D366),
),
child: CircleAvatar(
// backgroundImage: AssetImage(
// 'images/default_avatar.jpg', // Default avatar for contacts
// ),
),
),
title: Text(
contact.displayName ?? 'No Name',
style: TextStyle(fontSize: 18, fontWeight: FontWeight.w500),
),
subtitle: Text(contact.phones?.isNotEmpty == true ? contact.phones!.first.value! : 'No Number'),
onTap: ()async {
await uploadContactToFirestore(contact);
Navigator.pushNamed(
// ignore: use_build_context_synchronously
context,
Individualpage.screenroute,
arguments: {'title': '${contact.displayName}'},
);
},
),
],
),
);
}
}
The error make encountering indicates that the image_link field does not exist in some of the documents within the user_profile collection. This is causing the app to crash when I trying to access a non-existent field. I need to add error handling to check if the field exists before accessing it.and I need to fetch user profiles from the Firestore collection inside my ContactsPage,
to fetch user profiles documents from the Firestore collection inside my ContactsPage