import 'package:dialer/services/obfuscate_service.dart'; import 'package:dialer/widgets/username_color_generator.dart'; import 'package:flutter/material.dart'; import 'package:flutter_contacts/flutter_contacts.dart'; import '../contact_state.dart'; import 'add_contact_button.dart'; import 'contact_modal.dart'; import 'share_own_qr.dart'; class AlphabetScrollPage extends StatefulWidget { final double scrollOffset; final List contacts; const AlphabetScrollPage({ super.key, required this.scrollOffset, required this.contacts, }); @override _AlphabetScrollPageState createState() => _AlphabetScrollPageState(); } class _AlphabetScrollPageState extends State { late ScrollController _scrollController; final ObfuscateService _obfuscateService = ObfuscateService(); @override void initState() { super.initState(); _scrollController = ScrollController(initialScrollOffset: widget.scrollOffset); _scrollController.addListener(_onScroll); } void _onScroll() { final contactState = ContactState.of(context); contactState.setScrollOffset(_scrollController.offset); } Future _refreshContacts() async { final contactState = ContactState.of(context); try { await contactState.fetchContacts(); } catch (e) { print('Error refreshing contacts: $e'); ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text('Failed to refresh contacts')), ); } } void _toggleFavorite(Contact contact) async { try { if (await FlutterContacts.requestPermission()) { Contact? fullContact = await FlutterContacts.getContact(contact.id, withProperties: true, withAccounts: true, withPhoto: true, withThumbnail: true); if (fullContact != null) { fullContact.isStarred = !fullContact.isStarred; await FlutterContacts.updateContact(fullContact); } await _refreshContacts(); } else { print("Could not fetch contact details"); } } catch (e) { print("Error updating favorite status: $e"); ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text('Failed to update contact favorite status')), ); } } @override Widget build(BuildContext context) { final contacts = widget.contacts; final selfContact = ContactState.of(context).selfContact; Map> alphabetizedContacts = {}; for (var contact in contacts) { String firstLetter = contact.displayName.isNotEmpty ? contact.displayName[0].toUpperCase() : '#'; if (!alphabetizedContacts.containsKey(firstLetter)) { alphabetizedContacts[firstLetter] = []; } alphabetizedContacts[firstLetter]!.add(contact); } List alphabetKeys = alphabetizedContacts.keys.toList()..sort(); return Scaffold( backgroundColor: Colors.black, body: Column( children: [ // Top buttons row Container( color: Colors.black, padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ AddContactButton(), QRCodeButton(contacts: contacts, selfContact: selfContact), ], ), ), // Contact List Expanded( child: ListView.builder( controller: _scrollController, itemCount: alphabetKeys.length, itemBuilder: (context, index) { String letter = alphabetKeys[index]; List contactsForLetter = alphabetizedContacts[letter]!; return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // Alphabet Letter Header Padding( padding: const EdgeInsets.symmetric( vertical: 8.0, horizontal: 16.0), child: Text( letter, style: const TextStyle( fontSize: 28, fontWeight: FontWeight.bold, color: Colors.white, ), ), ), // Contact Entries ...contactsForLetter.map((contact) { String phoneNumber = contact.phones.isNotEmpty ? _obfuscateService.obfuscateData(contact.phones.first.number) : 'No phone number'; Color avatarColor = generateColorFromName(contact.displayName); return ListTile( leading: ObfuscatedAvatar( imageBytes: contact.thumbnail, radius: 25, backgroundColor: avatarColor, fallbackInitial: contact.displayName, ), title: Text( _obfuscateService.obfuscateData(contact.displayName), style: const TextStyle(color: Colors.white), ), subtitle: Text( phoneNumber, style: const TextStyle(color: Colors.white70), ), onTap: () { showModalBottomSheet( context: context, isScrollControlled: true, backgroundColor: Colors.transparent, builder: (context) { return ContactModal( contact: contact, onEdit: () async { if (await FlutterContacts.requestPermission()) { final updatedContact = await FlutterContacts.openExternalEdit( contact.id); if (updatedContact != null) { await _refreshContacts(); Navigator.of(context).pop(); ScaffoldMessenger.of(context) .showSnackBar( SnackBar( content: Text( '${contact.displayName} updated successfully!'), ), ); } else { ScaffoldMessenger.of(context) .showSnackBar( SnackBar( content: Text('Edit canceled or failed.'), ), ); } } }, onToggleFavorite: () { _toggleFavorite(contact); }, isFavorite: contact.isStarred, ); }, ); }, ); }), ], ); }, ), ), ], ), ); } @override void dispose() { _scrollController.dispose(); super.dispose(); } }