import 'package:flutter/material.dart'; import '../../../domain/services/obfuscate_service.dart'; import '../contacts/contact_page.dart'; import '../favorites/favorites_page.dart'; import '../history/history_page.dart'; import '../dialer/composition_page.dart'; import '../settings/settings_page.dart'; import '../voicemail/voicemail_page.dart'; import '../contacts/contact_state.dart'; import '../contacts/widgets/contact_modal.dart'; import 'package:flutter_contacts/flutter_contacts.dart'; class MyHomePage extends StatefulWidget { const MyHomePage({super.key}); @override _MyHomePageState createState() => _MyHomePageState(); } class _MyHomePageState extends State with SingleTickerProviderStateMixin { late TabController _tabController; List _allContacts = []; List _contactSuggestions = []; final ObfuscateService _obfuscateService = ObfuscateService(); final TextEditingController _searchController = TextEditingController(); bool _isInitialized = false; @override void initState() { super.initState(); _tabController = TabController(length: 4, vsync: this, initialIndex: 1); _tabController.addListener(_handleTabIndex); } @override void didChangeDependencies() { super.didChangeDependencies(); if (!_isInitialized) { // Use a post-frame callback to avoid setState during build WidgetsBinding.instance.addPostFrameCallback((_) { _fetchContacts(); }); _isInitialized = true; } } void _fetchContacts() async { final contactState = ContactState.of(context); // Wait for initial load to finish if it hasn't already if (contactState.loading) { await Future.delayed(const Duration(milliseconds: 100)); } // Then explicitly fetch contacts (which will call setState safely) await contactState.fetchContacts(); if (mounted) { setState(() { _allContacts = contactState.contacts; _contactSuggestions = _allContacts; }); } } void _clearSearch() { _searchController.clear(); _onSearchChanged(''); } void _onSearchChanged(String query) { setState(() { if (query.isEmpty) { _contactSuggestions = List.from(_allContacts); // Reset suggestions } else { _contactSuggestions = _allContacts.where((contact) { return contact.displayName .toLowerCase() .contains(query.toLowerCase()); }).toList(); } }); } @override void dispose() { _searchController.dispose(); _tabController.removeListener(_handleTabIndex); _tabController.dispose(); super.dispose(); } void _handleTabIndex() { setState(() {}); } 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); _fetchContacts(); } } } catch (e) { debugPrint("Error updating favorite status: $e"); ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text('Failed to update contact favorite status')), ); } } @override Widget build(BuildContext context) { return Scaffold( backgroundColor: Colors.black, body: Column( children: [ // Persistent Search Bar Padding( padding: const EdgeInsets.only( top: 24.0, bottom: 10.0, left: 16.0, right: 16.0, ), child: Row( children: [ Expanded( child: Container( decoration: BoxDecoration( color: const Color.fromARGB(255, 30, 30, 30), borderRadius: BorderRadius.circular(12.0), border: Border.all(color: Colors.grey.shade800, width: 1), ), child: TextField( controller: _searchController, decoration: InputDecoration( hintText: 'Search contacts', hintStyle: const TextStyle(color: Colors.grey), prefixIcon: const Icon(Icons.search, color: Colors.grey), suffixIcon: _searchController.text.isNotEmpty ? IconButton( icon: const Icon(Icons.clear, color: Colors.grey), onPressed: _clearSearch, ) : null, border: InputBorder.none, contentPadding: const EdgeInsets.symmetric( vertical: 12.0, horizontal: 16.0), ), style: const TextStyle(color: Colors.white), onChanged: _onSearchChanged, ), ), ), // 3-dot menu PopupMenuButton( icon: const Icon(Icons.more_vert, color: Colors.white), itemBuilder: (BuildContext context) => [ const PopupMenuItem( value: 'settings', child: Text('Settings'), ), ], onSelected: (String value) { if (value == 'settings') { Navigator.pushNamed(context, '/settings'); } }, ), ], ), ), // Main content with TabBarView Expanded( child: Stack( children: [ TabBarView( controller: _tabController, children: const [ FavoritesPage(), HistoryPage(), ContactPage(), VoicemailPage(), ], ), Positioned( right: 20, bottom: 20, child: FloatingActionButton( onPressed: () { Navigator.pushNamed(context, '/composition'); }, backgroundColor: Colors.blue, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(45), ), child: const Icon(Icons.dialpad, color: Colors.white), ), ), ], ), ), ], ), bottomNavigationBar: Container( color: Colors.black, child: TabBar( controller: _tabController, tabs: [ Tab( icon: Icon(_tabController.index == 0 ? Icons.star : Icons.star_border)), Tab( icon: Icon(_tabController.index == 1 ? Icons.access_time_filled : Icons.access_time_outlined)), Tab( icon: Icon(_tabController.index == 2 ? Icons.contacts : Icons.contacts_outlined)), Tab( icon: Icon(_tabController.index == 3 ? Icons.voicemail : Icons.voicemail_outlined), ), ], labelColor: Colors.white, unselectedLabelColor: const Color.fromARGB(255, 158, 158, 158), indicatorSize: TabBarIndicatorSize.label, indicatorColor: Colors.white, ), ), ); } }