import 'package:flutter/material.dart'; import 'package:flutter_contacts/flutter_contacts.dart'; import '../../services/contact_service.dart'; class ContactState extends StatefulWidget { final Widget child; const ContactState({super.key, required this.child}); static _ContactStateState of(BuildContext context) { return context .dependOnInheritedWidgetOfExactType<_InheritedContactState>()! .data; } @override _ContactStateState createState() => _ContactStateState(); } class _ContactStateState extends State { final ContactService _contactService = ContactService(); List _allContacts = []; List _favoriteContacts = []; bool _loading = true; double _scrollOffset = 0.0; Contact? _selfContact = Contact(); // Getters for all contacts and favorites List get contacts => _allContacts; List get favoriteContacts => _favoriteContacts; bool get loading => _loading; double get scrollOffset => _scrollOffset; Contact? get selfContact => _selfContact; @override void initState() { super.initState(); fetchContacts(); // Fetch all contacts by default FlutterContacts.addListener(_onContactChange); } void _onContactChange() => fetchContacts(); @override void dispose() { FlutterContacts.removeListener(_onContactChange); super.dispose(); } // Fetch all contacts Future fetchContacts() async { setState(() => _loading = true); try { List contacts = await _contactService.fetchContacts(); _processContacts(contacts); } finally { setState(() => _loading = false); } } // Fetch only favorite contacts Future fetchFavoriteContacts() async { setState(() => _loading = true); try { List contacts = await _contactService.fetchFavoriteContacts(); setState(() => _favoriteContacts = contacts); } finally { setState(() => _loading = false); } } void _processContacts(List contacts) { _selfContact = contacts.firstWhere( (contact) => contact.displayName.toLowerCase() == "user", orElse: () => Contact(), ); if (_selfContact!.phones.isEmpty) { debugPrint("Self contact has no phone numbers"); _selfContact = null; } contacts = contacts.where((contact) => contact.phones.isNotEmpty).toList(); contacts.sort((a, b) => a.displayName.compareTo(b.displayName)); setState(() { _allContacts = contacts; _favoriteContacts = contacts.where((contact) => contact.isStarred).toList(); _selfContact = _selfContact; }); } Future addNewContact(Contact contact) async { await _contactService.addNewContact(contact); await fetchContacts(); } void setScrollOffset(double offset) { setState(() { _scrollOffset = offset; }); } bool doesContactExist(Contact contact) { // Example: consider it "existing" if there's a matching phone number for (final existing in _allContacts) { if (existing.toVCard() == contact.toVCard()) { return true; } // for (final phone in existing.phones) { // for (final newPhone in contact.phones) { // // Simple exact match; you can do more advanced logic // if (phone.normalizedNumber == newPhone.normalizedNumber) { // return true; // } // } // } We might switch to finer and smarter logic later, ex: remove trailing spaces, capitals } return false; } @override Widget build(BuildContext context) { return _InheritedContactState( data: this, child: widget.child, ); } } class _InheritedContactState extends InheritedWidget { final _ContactStateState data; const _InheritedContactState({required this.data, required super.child}); @override bool updateShouldNotify(_InheritedContactState oldWidget) => true; }