Compare commits

...

2 Commits

Author SHA1 Message Date
AlexisDanlos
110020bb4b WIP: toogle favorite fix
All checks were successful
/ mirror (push) Successful in 8s
/ build-stealth (push) Successful in 8m23s
/ build (push) Successful in 8m26s
set favorites -> works
unset favorites -> unstable
2025-03-07 17:52:10 +01:00
AlexisDanlos
7ff9418e06 bug fix: enhance contact fetching with permission handling
Some checks failed
/ mirror (push) Successful in 4s
/ build (push) Has been cancelled
/ build-stealth (push) Has been cancelled
2025-03-06 15:44:03 +01:00
5 changed files with 150 additions and 50 deletions

View File

@ -1,5 +1,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_contacts/flutter_contacts.dart'; import 'package:flutter_contacts/flutter_contacts.dart';
import 'package:permission_handler/permission_handler.dart';
import '../../services/contact_service.dart'; import '../../services/contact_service.dart';
class ContactState extends StatefulWidget { class ContactState extends StatefulWidget {
@ -24,6 +25,7 @@ class _ContactStateState extends State<ContactState> {
bool _loading = true; bool _loading = true;
double _scrollOffset = 0.0; double _scrollOffset = 0.0;
Contact? _selfContact = Contact(); Contact? _selfContact = Contact();
bool _permissionRequestInProgress = false;
// Getters for all contacts and favorites // Getters for all contacts and favorites
List<Contact> get contacts => _allContacts; List<Contact> get contacts => _allContacts;
@ -35,8 +37,26 @@ class _ContactStateState extends State<ContactState> {
@override @override
void initState() { void initState() {
super.initState(); super.initState();
fetchContacts(); // Fetch all contacts by default _initializeContacts();
FlutterContacts.addListener(_onContactChange); }
Future<void> _initializeContacts() async {
try {
final status = await Permission.contacts.status;
if (status.isGranted) {
await fetchContacts();
} else {
final result = await Permission.contacts.request();
if (result.isGranted) {
await fetchContacts();
} else {
setState(() => _loading = false);
}
}
} catch (e) {
debugPrint('Error initializing contacts: $e');
setState(() => _loading = false);
}
} }
void _onContactChange() => fetchContacts(); void _onContactChange() => fetchContacts();
@ -96,6 +116,38 @@ class _ContactStateState extends State<ContactState> {
await fetchContacts(); await fetchContacts();
} }
// Add this new method to update a single contact in state without reloading all contacts
Future<void> updateContactInState(Contact updatedContact) async {
setState(() {
// Find and update in the all contacts list
final allIndex = _allContacts.indexWhere((c) => c.id == updatedContact.id);
if (allIndex != -1) {
_allContacts[allIndex] = updatedContact;
}
// Update the favorites list based on the star status
if (updatedContact.isStarred) {
// Add to favorites if not already there
if (!_favoriteContacts.any((c) => c.id == updatedContact.id)) {
_favoriteContacts.add(updatedContact);
} else {
// If already in favorites, update it
final favIndex = _favoriteContacts.indexWhere((c) => c.id == updatedContact.id);
if (favIndex != -1) {
_favoriteContacts[favIndex] = updatedContact;
}
}
} else {
// Remove from favorites if it's there
_favoriteContacts.removeWhere((c) => c.id == updatedContact.id);
}
// Re-sort both lists to maintain alphabetical order
_allContacts.sort((a, b) => a.displayName.compareTo(b.displayName));
_favoriteContacts.sort((a, b) => a.displayName.compareTo(b.displayName));
});
}
void setScrollOffset(double offset) { void setScrollOffset(double offset) {
setState(() { setState(() {
_scrollOffset = offset; _scrollOffset = offset;

View File

@ -52,20 +52,42 @@ class _AlphabetScrollPageState extends State<AlphabetScrollPage> {
void _toggleFavorite(Contact contact) async { void _toggleFavorite(Contact contact) async {
try { try {
if (await FlutterContacts.requestPermission()) { // Check permission only once
Contact? fullContact = await FlutterContacts.getContact(contact.id, if (!await FlutterContacts.requestPermission()) {
withProperties: true, print("Could not get contact permission");
withAccounts: true, ScaffoldMessenger.of(context).showSnackBar(
withPhoto: true, SnackBar(content: Text('Contact permission not granted')),
withThumbnail: true); );
return;
}
Contact? fullContact = await FlutterContacts.getContact(contact.id,
withProperties: true,
withAccounts: true,
withPhoto: true,
withThumbnail: true);
if (fullContact != null) { if (fullContact != null) {
fullContact.isStarred = !fullContact.isStarred; // Toggle the favorite status
await FlutterContacts.updateContact(fullContact); fullContact.isStarred = !fullContact.isStarred;
} // Update in database
await _refreshContacts(); await FlutterContacts.updateContact(fullContact);
} else {
print("Could not fetch contact details"); // Update the UI immediately - we need to update the ContactState
final contactState = ContactState.of(context);
await contactState.updateContactInState(fullContact);
// Show feedback to the user
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(
fullContact.isStarred
? '${fullContact.displayName} added to favorites'
: '${fullContact.displayName} removed from favorites'
),
duration: Duration(seconds: 1),
),
);
} }
} catch (e) { } catch (e) {
print("Error updating favorite status: $e"); print("Error updating favorite status: $e");

View File

@ -68,25 +68,24 @@ class _HistoryPageState extends State<HistoryPage>
void _toggleFavorite(Contact contact) async { void _toggleFavorite(Contact contact) async {
try { try {
if (await FlutterContacts.requestPermission()) { Contact? fullContact = await FlutterContacts.getContact(contact.id,
Contact? fullContact = await FlutterContacts.getContact(contact.id, withProperties: true,
withProperties: true, withAccounts: true,
withAccounts: true, withPhoto: true,
withPhoto: true, withThumbnail: true);
withThumbnail: true);
if (fullContact != null) { if (fullContact != null) {
fullContact.isStarred = !fullContact.isStarred; fullContact.isStarred = !fullContact.isStarred;
await FlutterContacts.updateContact(fullContact); await FlutterContacts.updateContact(fullContact);
}
await _refreshContacts(); await _refreshContacts();
} else {
print("Could not fetch contact details");
} }
} catch (e) { } catch (e) {
print("Error updating favorite status: $e"); debugPrint("Error updating favorite status: $e");
ScaffoldMessenger.of(context).showSnackBar( if (mounted) {
SnackBar(content: Text('Failed to update favorite status'))); ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Failed to update contact favorite status')),
);
}
} }
} }

View File

@ -25,7 +25,7 @@ class _MyHomePageState extends State<MyHomePage>
void initState() { void initState() {
super.initState(); super.initState();
// Set the TabController length to 4 // Set the TabController length to 4
_tabController = TabController(length: 4, vsync: this, initialIndex: 1); _tabController = TabController(length: 4, vsync: this, initialIndex: 2);
_tabController.addListener(_handleTabIndex); _tabController.addListener(_handleTabIndex);
_fetchContacts(); _fetchContacts();
} }
@ -68,23 +68,42 @@ class _MyHomePageState extends State<MyHomePage>
void _toggleFavorite(Contact contact) async { void _toggleFavorite(Contact contact) async {
try { try {
if (await FlutterContacts.requestPermission()) { // Check permission only once at the beginning
Contact? fullContact = await FlutterContacts.getContact(contact.id, if (!await FlutterContacts.requestPermission()) {
withProperties: true, print("Could not get contact permission");
withAccounts: true, ScaffoldMessenger.of(context).showSnackBar(
withPhoto: true, const SnackBar(content: Text('Contact permission not granted')),
withThumbnail: true); );
return;
if (fullContact != null) { }
fullContact.isStarred = !fullContact.isStarred;
await FlutterContacts.updateContact(fullContact); // Get the full contact with all properties
setState(() { Contact? fullContact = await FlutterContacts.getContact(contact.id,
// Updating the contact list after toggling the favorite withProperties: true,
_fetchContacts(); withAccounts: true,
}); withPhoto: true,
} withThumbnail: true);
} else {
print("Could not fetch contact details"); if (fullContact != null) {
// Toggle the starred status
fullContact.isStarred = !fullContact.isStarred;
// Update in the database
await FlutterContacts.updateContact(fullContact);
// Update UI immediately with the new state
setState(() {
// Find and update the contact in our local list
final index = _allContacts.indexWhere((c) => c.id == contact.id);
if (index != -1) {
_allContacts[index] = fullContact;
}
// Update contact suggestions if needed
final suggestionIndex = _contactSuggestions.indexWhere((c) => c.id == contact.id);
if (suggestionIndex != -1) {
_contactSuggestions[suggestionIndex] = fullContact;
}
});
} }
} catch (e) { } catch (e) {
print("Error updating favorite status: $e"); print("Error updating favorite status: $e");

View File

@ -1,19 +1,27 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_contacts/flutter_contacts.dart'; import 'package:flutter_contacts/flutter_contacts.dart';
import 'package:qr_flutter/qr_flutter.dart'; import 'package:qr_flutter/qr_flutter.dart';
import 'package:permission_handler/permission_handler.dart';
// Service to manage contact-related operations // Service to manage contact-related operations
class ContactService { class ContactService {
Future<List<Contact>> fetchContacts() async { Future<List<Contact>> fetchContacts() async {
if (await FlutterContacts.requestPermission()) { final hasPermission = await Permission.contacts.status;
if (!hasPermission.isGranted) {
return [];
}
try {
return await FlutterContacts.getContacts( return await FlutterContacts.getContacts(
withProperties: true, withProperties: true,
withThumbnail: true, withThumbnail: true,
withAccounts: true, withAccounts: true,
withGroups: true, withGroups: true,
withPhoto: true); withPhoto: true);
} catch (e) {
debugPrint('Error fetching contacts: $e');
return [];
} }
return [];
} }
Future<List<Contact>> fetchFavoriteContacts() async { Future<List<Contact>> fetchFavoriteContacts() async {