feat: fetch Favorite, fix fetch redundancy
All checks were successful
/ mirror (push) Successful in 4s

This commit is contained in:
Florian Griffon 2024-12-13 10:00:20 +01:00
parent 508504fdbd
commit 3e7845d3d8
4 changed files with 52 additions and 45 deletions

View File

@ -18,7 +18,7 @@ class _ContactPageState extends State<ContactPage> {
body: contactState.loading
? const LoadingIndicatorWidget()
// : ContactListWidget(contacts: contactState.contacts),
: AlphabetScrollPage(contacts: contactState.contacts, scrollOffset: contactState.scrollOffset),
: AlphabetScrollPage(scrollOffset: contactState.scrollOffset),
);
}
}

View File

@ -8,7 +8,9 @@ class ContactState extends StatefulWidget {
const ContactState({super.key, required this.child});
static _ContactStateState of(BuildContext context) {
return context.dependOnInheritedWidgetOfExactType<_InheritedContactState>()!.data;
return context
.dependOnInheritedWidgetOfExactType<_InheritedContactState>()!
.data;
}
@override
@ -30,13 +32,13 @@ class _ContactStateState extends State<ContactState> {
@override
void initState() {
super.initState();
_fetchContacts();
fetchContacts();
// Add listener for contact changes
FlutterContacts.addListener(_onContactChange);
}
void _onContactChange() => _fetchContacts();
void _onContactChange() => fetchContacts();
@override
void dispose() {
@ -45,16 +47,20 @@ class _ContactStateState extends State<ContactState> {
super.dispose();
}
Future<void> _fetchContacts() async {
List<Contact> contacts = await _contactService.fetchContacts();
Future<void> fetchContacts({bool onlyStarred = false}) async {
List<Contact> contacts = onlyStarred
? await _contactService.fetchFavoriteContacts()
: await _contactService.fetchContacts();
debugPrint("Fetched ${contacts.length} contacts");
debugPrint(
"Fetched ${contacts.length} ${onlyStarred ? 'favorite' : ''} contacts");
// Find selfContact before filtering
_selfContact = contacts.firstWhere(
(contact) => contact.displayName.toLowerCase() == "user",
orElse: () => Contact(),
);
if (_selfContact!.phones.isEmpty) {
debugPrint("Self contact has no phone numbers");
_selfContact = null;
@ -62,6 +68,7 @@ class _ContactStateState extends State<ContactState> {
contacts = contacts.where((contact) => contact.phones.isNotEmpty).toList();
contacts.sort((a, b) => a.displayName.compareTo(b.displayName));
setState(() {
_contacts = contacts;
_loading = false;
@ -71,7 +78,7 @@ class _ContactStateState extends State<ContactState> {
Future<void> addNewContact(Contact contact) async {
await _contactService.addNewContact(contact);
await _fetchContacts();
await fetchContacts();
}
void setScrollOffset(double offset) {

View File

@ -1,19 +1,16 @@
import 'package:dialer/widgets/username_color_generator.dart';
import 'package:flutter/material.dart';
import 'package:flutter_contacts/flutter_contacts.dart';
import '../../../widgets/color_darkener.dart';
import '../contact_state.dart';
import '../../../widgets/contact_service.dart';
import '../../../widgets/color_darkener.dart';
import 'add_contact_button.dart';
import 'contact_modal.dart';
import 'share_own_qr.dart';
class AlphabetScrollPage extends StatefulWidget {
final List<Contact> contacts;
final double scrollOffset;
const AlphabetScrollPage(
{super.key, required this.contacts, required this.scrollOffset});
const AlphabetScrollPage({super.key, required this.scrollOffset});
@override
_AlphabetScrollPageState createState() => _AlphabetScrollPageState();
@ -21,13 +18,10 @@ class AlphabetScrollPage extends StatefulWidget {
class _AlphabetScrollPageState extends State<AlphabetScrollPage> {
late ScrollController _scrollController;
List<Contact> _contacts = []; // Local copy of contacts for updating
final ContactService _contactService = ContactService();
@override
void initState() {
super.initState();
_contacts = widget.contacts; // Initialize with the provided contacts
_scrollController =
ScrollController(initialScrollOffset: widget.scrollOffset);
_scrollController.addListener(_onScroll);
@ -39,28 +33,20 @@ class _AlphabetScrollPageState extends State<AlphabetScrollPage> {
}
Future<void> _refreshContacts() async {
final contactState = ContactState.of(context);
try {
// Use the fetchContacts method from ContactService
final updatedContacts = await _contactService.fetchContacts();
if (mounted) {
setState(() {
_contacts = updatedContacts;
});
}
await contactState.fetchContacts();
} catch (e) {
print('Error refreshing contacts: $e');
// Optionally show a user-friendly error message
ScaffoldMessenger.of(context)
.showSnackBar(SnackBar(content: Text('Failed to refresh contacts')));
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Failed to refresh contacts')),
);
}
}
void _toggleFavorite(Contact contact) async {
try {
// Request permission first
if (await FlutterContacts.requestPermission()) {
// Fetch the full contact details with all available properties
Contact? fullContact = await FlutterContacts.getContact(contact.id,
withProperties: true,
withAccounts: true,
@ -68,7 +54,6 @@ class _AlphabetScrollPageState extends State<AlphabetScrollPage> {
withThumbnail: true);
if (fullContact != null) {
// Update the contact
fullContact.isStarred = !fullContact.isStarred;
await FlutterContacts.updateContact(fullContact);
}
@ -78,16 +63,20 @@ class _AlphabetScrollPageState extends State<AlphabetScrollPage> {
}
} catch (e) {
print("Error updating favorite status: $e");
// Optional: Show a user-friendly error message
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Failed to update contact favorite status')));
SnackBar(content: Text('Failed to update contact favorite status')),
);
}
}
@override
Widget build(BuildContext context) {
final contactState = ContactState.of(context);
final contacts = contactState.contacts;
final selfContact = contactState.selfContact;
Map<String, List<Contact>> alphabetizedContacts = {};
for (var contact in _contacts) {
for (var contact in contacts) {
String firstLetter = contact.displayName.isNotEmpty
? contact.displayName[0].toUpperCase()
: '#';
@ -106,15 +95,12 @@ class _AlphabetScrollPageState extends State<AlphabetScrollPage> {
// Top buttons row
Container(
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(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
AddContactButton(),
QRCodeButton(
contacts: _contacts,
selfContact: ContactState.of(context).selfContact),
QRCodeButton(contacts: contacts, selfContact: selfContact),
],
),
),
@ -125,7 +111,7 @@ class _AlphabetScrollPageState extends State<AlphabetScrollPage> {
itemCount: alphabetKeys.length,
itemBuilder: (context, index) {
String letter = alphabetKeys[index];
List<Contact> contacts = alphabetizedContacts[letter]!;
List<Contact> contactsForLetter = alphabetizedContacts[letter]!;
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
@ -143,7 +129,7 @@ class _AlphabetScrollPageState extends State<AlphabetScrollPage> {
),
),
// Contact Entries
...contacts.map((contact) {
...contactsForLetter.map((contact) {
String phoneNumber = contact.phones.isNotEmpty
? contact.phones.first.number
: 'No phone number';
@ -179,9 +165,7 @@ class _AlphabetScrollPageState extends State<AlphabetScrollPage> {
return ContactModal(
contact: contact,
onEdit: () async {
// Trigger edit logic and refresh contacts
if (await FlutterContacts
.requestPermission()) {
if (await FlutterContacts.requestPermission()) {
final updatedContact =
await FlutterContacts.openExternalEdit(
contact.id);

View File

@ -4,12 +4,28 @@ import 'package:flutter_contacts/flutter_contacts.dart';
class ContactService {
Future<List<Contact>> fetchContacts() async {
if (await FlutterContacts.requestPermission()) {
return await FlutterContacts.getContacts(withProperties: true, withThumbnail: true, withAccounts: true, withGroups: true, withPhoto: true);
return await FlutterContacts.getContacts(
withProperties: true,
withThumbnail: true,
withAccounts: true,
withGroups: true,
withPhoto: true);
}
return [];
}
Future<List<Contact>> fetchFavoriteContacts() async {
// Fetch all contacts
List<Contact> contacts = await fetchContacts();
// Filter contacts to only include those with isStarred: true
List<Contact> favoriteContacts =
contacts.where((contact) => contact.isStarred).toList();
return favoriteContacts;
}
Future<void> addNewContact(Contact contact) async {
await FlutterContacts.insertContact(contact);
}
}
}