feat: WIP contact-modal

This commit is contained in:
Florian Griffon 2024-12-11 21:54:20 +01:00
parent 21b6b0a29a
commit 6bed3f5ad9

View File

@ -5,11 +5,14 @@ import '../contact_state.dart';
import '../../../widgets/color_darkener.dart'; import '../../../widgets/color_darkener.dart';
import 'add_contact_button.dart'; import 'add_contact_button.dart';
import 'contact_modal.dart'; import 'contact_modal.dart';
import 'contact_modal.dart';
import 'share_own_qr.dart'; import 'share_own_qr.dart';
class AlphabetScrollPage extends StatefulWidget { class AlphabetScrollPage extends StatefulWidget {
final double scrollOffset; final double scrollOffset;
const AlphabetScrollPage(
{super.key, required this.contacts, required this.scrollOffset});
const AlphabetScrollPage({super.key, required this.scrollOffset}); const AlphabetScrollPage({super.key, required this.scrollOffset});
@override @override
@ -18,10 +21,14 @@ class AlphabetScrollPage extends StatefulWidget {
class _AlphabetScrollPageState extends State<AlphabetScrollPage> { class _AlphabetScrollPageState extends State<AlphabetScrollPage> {
late ScrollController _scrollController; late ScrollController _scrollController;
List<Contact> _contacts = []; // Local copy of contacts for updating
@override @override
void initState() { void initState() {
super.initState(); super.initState();
_scrollController =
ScrollController(initialScrollOffset: widget.scrollOffset);
_contacts = widget.contacts; // Initialize with the provided contacts
_scrollController = _scrollController =
ScrollController(initialScrollOffset: widget.scrollOffset); ScrollController(initialScrollOffset: widget.scrollOffset);
_scrollController.addListener(_onScroll); _scrollController.addListener(_onScroll);
@ -69,6 +76,142 @@ class _AlphabetScrollPageState extends State<AlphabetScrollPage> {
} }
} }
Future<void> _refreshContacts() async {
if (await FlutterContacts.requestPermission()) {
final updatedContacts = await FlutterContacts.getContacts(
withProperties: true, withThumbnail: true);
setState(() {
_contacts = updatedContacts;
});
}
}
// void _toggleFavorite(Contact contact) async {
// print(contact.id);
// if (await FlutterContacts.requestPermission()) {
// try {
// // Fetch all contacts (this can be slow if there are many contacts)
// List<Contact> allContacts = await FlutterContacts.getContacts(
// withProperties: true,
// withThumbnail: true,
// withAccounts: true,
// withPhoto: true
// );
// // Find the specific contact by matching contact.id
// // Use `orElse` to return a nullable Contact? or throw an exception if not found
// Contact? contactToUpdate = allContacts.firstWhere(
// (c) => c.id == contact.id,
// orElse: () => throw Exception(
// "Contact not found"), // Throw an exception if not found
// );
// if (contactToUpdate != null) {
// print("Contact fetched: ${contactToUpdate.displayName}");
// print("Current isStarred status: ${contactToUpdate.isStarred}");
// // Toggle the favorite status
// contactToUpdate.isStarred = !contactToUpdate.isStarred;
// print("Updated isStarred status: ${contactToUpdate.isStarred}");
// // Update the contact
// await FlutterContacts.updateContact(contactToUpdate);
// print("Contact updated successfully");
// // Refresh the UI by updating the state
// setState(() {
// contact.isStarred = contactToUpdate.isStarred;
// });
// }
// } catch (e) {
// print("Error updating favorite status: $e");
// }
// }
// }
// void _toggleFavorite(Contact contact) async {
// print(contact.id);
// try {
// // Fetch the contact with details
// final contactWithDetails = await FlutterContacts.getContact(contact.id,
// withProperties: true, withThumbnail: true, withAccounts: true);
// if (contactWithDetails != null) {
// print("Contact fetched: ${contactWithDetails.displayName}");
// print("Current isStarred status: ${contactWithDetails.isStarred}");
// // Toggle the favorite status
// contactWithDetails.isStarred = !contactWithDetails.isStarred;
// print("Updated isStarred status: ${contactWithDetails.isStarred}");
// // Update the contact
// await FlutterContacts.updateContact(contactWithDetails);
// print("Contact updated successfully");
// // Reset the contact state (optional)
// setState(() {
// contact.isStarred = contactWithDetails.isStarred;
// });
// // Re-fetch the contact to ensure UI reflects changes
// final updatedContact = await FlutterContacts.getContact(contact.id,
// withProperties: true, withThumbnail: true, withAccounts: true);
// if (updatedContact != null) {
// print("Re-fetched updated contact: ${updatedContact.displayName}");
// print("Re-fetched isStarred status: ${updatedContact.isStarred}");
// } else {
// print("Re-fetching contact failed.");
// }
// } else {
// print("Contact details are not available");
// }
// } catch (e) {
// print("Error updating favorite status: $e");
// }
// }
void _toggleFavorite(Contact contact) async {
print(contact.id);
try {
if (contact != null) {
print("Contact fetched: ${contact.displayName}");
print("Current isStarred status: ${contact.isStarred}");
// Toggle the favorite status
contact.isStarred = !contact.isStarred;
print("Updated isStarred status: ${contact.isStarred}");
// Update the contact
await FlutterContacts.updateContact(contact);
print("Contact updated successfully");
// Reset the contact state (optional)
setState(() {
contact.isStarred = contact.isStarred;
});
// Re-fetch the contact to ensure UI reflects changes
final updatedContact = await FlutterContacts.getContact(contact.id,
withProperties: true, withThumbnail: true, withAccounts: true);
if (updatedContact != null) {
print("Re-fetched updated contact: ${updatedContact.displayName}");
print("Re-fetched isStarred status: ${updatedContact.isStarred}");
} else {
print("Re-fetching contact failed.");
}
} else {
print("Contact details are not available");
}
} catch (e) {
print("Error updating favorite status: $e");
}
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final contactState = ContactState.of(context); final contactState = ContactState.of(context);
@ -76,7 +219,7 @@ class _AlphabetScrollPageState extends State<AlphabetScrollPage> {
final selfContact = contactState.selfContact; final selfContact = contactState.selfContact;
Map<String, List<Contact>> alphabetizedContacts = {}; Map<String, List<Contact>> alphabetizedContacts = {};
for (var contact in contacts) { for (var contact in _contacts) {
String firstLetter = contact.displayName.isNotEmpty String firstLetter = contact.displayName.isNotEmpty
? contact.displayName[0].toUpperCase() ? contact.displayName[0].toUpperCase()
: '#'; : '#';
@ -91,16 +234,21 @@ class _AlphabetScrollPageState extends State<AlphabetScrollPage> {
return Scaffold( return Scaffold(
backgroundColor: Colors.black, backgroundColor: Colors.black,
body: Column( body: Column(
children: [
// Top buttons row
children: [ children: [
// Top buttons row // Top buttons row
Container( Container(
color: Colors.black, color: Colors.black,
padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0), padding:
const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0),
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
AddContactButton(), AddContactButton(),
QRCodeButton(contacts: contacts, selfContact: selfContact), QRCodeButton(
contacts: _contacts,
selfContact: ContactState.of(context).selfContact),
], ],
), ),
), ),
@ -117,6 +265,8 @@ class _AlphabetScrollPageState extends State<AlphabetScrollPage> {
children: [ children: [
// Alphabet Letter Header // Alphabet Letter Header
Padding( Padding(
padding: const EdgeInsets.symmetric(
vertical: 8.0, horizontal: 16.0),
padding: const EdgeInsets.symmetric( padding: const EdgeInsets.symmetric(
vertical: 8.0, horizontal: 16.0), vertical: 8.0, horizontal: 16.0),
child: Text( child: Text(
@ -129,19 +279,24 @@ class _AlphabetScrollPageState extends State<AlphabetScrollPage> {
), ),
), ),
// Contact Entries // Contact Entries
...contactsForLetter.map((contact) { ...contacts.map((contact) {
String phoneNumber = contact.phones.isNotEmpty String phoneNumber = contact.phones.isNotEmpty
? contact.phones.first.number ? contact.phones.first.number
: 'No phone number'; : 'No phone number';
Color avatarColor = Color avatarColor =
generateColorFromName(contact.displayName); generateColorFromName(contact.displayName);
return ListTile( return ListTile(
leading: (contact.thumbnail != null &&
contact.thumbnail!.isNotEmpty)
leading: (contact.thumbnail != null && leading: (contact.thumbnail != null &&
contact.thumbnail!.isNotEmpty) contact.thumbnail!.isNotEmpty)
? CircleAvatar( ? CircleAvatar(
backgroundImage: backgroundImage:
MemoryImage(contact.thumbnail!), MemoryImage(contact.thumbnail!),
) )
backgroundImage:
MemoryImage(contact.thumbnail!),
)
: CircleAvatar( : CircleAvatar(
backgroundColor: avatarColor, backgroundColor: avatarColor,
child: Text( child: Text(
@ -154,6 +309,19 @@ class _AlphabetScrollPageState extends State<AlphabetScrollPage> {
), ),
title: Text(contact.displayName, title: Text(contact.displayName,
style: TextStyle(color: Colors.white)), style: TextStyle(color: Colors.white)),
subtitle: Text(phoneNumber,
style: TextStyle(color: Colors.white70)),
backgroundColor: avatarColor,
child: Text(
contact.displayName.isNotEmpty
? contact.displayName[0].toUpperCase()
: '?',
style: TextStyle(
color: darken(avatarColor, 0.4)),
),
),
title: Text(contact.displayName,
style: TextStyle(color: Colors.white)),
subtitle: Text(phoneNumber, subtitle: Text(phoneNumber,
style: TextStyle(color: Colors.white70)), style: TextStyle(color: Colors.white70)),
onTap: () { onTap: () {
@ -165,7 +333,9 @@ class _AlphabetScrollPageState extends State<AlphabetScrollPage> {
return ContactModal( return ContactModal(
contact: contact, contact: contact,
onEdit: () async { onEdit: () async {
if (await FlutterContacts.requestPermission()) { // Trigger edit logic and refresh contacts
if (await FlutterContacts
.requestPermission()) {
final updatedContact = final updatedContact =
await FlutterContacts.openExternalEdit( await FlutterContacts.openExternalEdit(
contact.id); contact.id);