import 'package:flutter_contacts/flutter_contacts.dart'; import 'package:get/get.dart'; class ContactInfo { final String name; final String? avatarPath; ContactInfo({required this.name, this.avatarPath}); } class ContactsService extends GetxService { final RxMap _contactsMap = {}.obs; final RxBool permissionGranted = false.obs; Future init() async { await fetchContacts(); return this; } Future fetchContacts() async { try { // Check and request permission bool permission = await FlutterContacts.requestPermission(readonly: true); permissionGranted.value = permission; if (permission) { // Fetch contacts with photos and phone numbers final contacts = await FlutterContacts.getContacts(withProperties: true, withPhoto: true); final Map tempMap = {}; for (var contact in contacts) { final fullName = contact.displayName; if (fullName.isEmpty) continue; for (var phone in contact.phones) { final normalized = normalizePhoneNumber(phone.number); if (normalized.isNotEmpty) { tempMap[normalized] = ContactInfo( name: fullName, avatarPath: null, // Custom local avatar path can be handled if needed ); } } } _contactsMap.assignAll(tempMap); print('[CONTACTS] Successfully loaded ${_contactsMap.length} normalized phone contacts'); } } catch (e) { print('[CONTACTS ERROR] Failed to fetch system contacts: $e'); } } // Normalizes numbers to match them easily (e.g., removes spaces, dashes, brackets, and leading zeros) String normalizePhoneNumber(String number) { String clean = number.replaceAll(RegExp(r'[\s\-\(\)\+]'), ''); // If it starts with local country prefix or leading 0, we can do substring matches if (clean.startsWith('00')) { clean = clean.substring(2); } return clean; } String getContactName(String rawNumber, String fallback) { if (!permissionGranted.value || _contactsMap.isEmpty) return fallback; final clean = normalizePhoneNumber(rawNumber); if (clean.isEmpty) return fallback; // Direct match if (_contactsMap.containsKey(clean)) { return _contactsMap[clean]!.name; } // Partial match for varying country codes (match last 9 digits of the phone number) if (clean.length >= 9) { final suffix = clean.substring(clean.length - 9); for (var key in _contactsMap.keys) { if (key.endsWith(suffix)) { return _contactsMap[key]!.name; } } } return fallback; } }