diff --git a/dialer/lib/presentation/features/home/home_page.dart b/dialer/lib/presentation/features/home/home_page.dart index 16f9487..f19fa01 100644 --- a/dialer/lib/presentation/features/home/home_page.dart +++ b/dialer/lib/presentation/features/home/home_page.dart @@ -4,7 +4,7 @@ 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 '../settings/settings.dart'; import '../voicemail/voicemail_page.dart'; import '../contacts/contact_state.dart'; import '../contacts/widgets/contact_modal.dart'; @@ -23,7 +23,7 @@ class _MyHomePageState extends State List _allContacts = []; List _contactSuggestions = []; final ObfuscateService _obfuscateService = ObfuscateService(); - final TextEditingController _searchController = TextEditingController(); + final SearchController _searchController = SearchController(); bool _isInitialized = false; @override @@ -61,11 +61,6 @@ class _MyHomePageState extends State } } - void _clearSearch() { - _searchController.clear(); - _onSearchChanged(''); - } - void _onSearchChanged(String query) { setState(() { if (query.isEmpty) { @@ -132,31 +127,105 @@ class _MyHomePageState extends State 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, - ), + child: SearchAnchor( + builder: (BuildContext context, SearchController controller) { + return GestureDetector( + onTap: () { + controller.openView(); // Open the search view + }, + 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), + ), + padding: const EdgeInsets.symmetric( + vertical: 12.0, horizontal: 16.0), + child: Row( + children: [ + const Icon(Icons.search, + color: Colors.grey, size: 24.0), + const SizedBox(width: 8.0), + Text( + controller.text.isEmpty + ? 'Search contacts' + : controller.text, + style: const TextStyle( + color: Colors.grey, fontSize: 16.0), + ), + const Spacer(), + if (controller.text.isNotEmpty) + GestureDetector( + onTap: () { + controller.clear(); + _onSearchChanged(''); + }, + child: const Icon( + Icons.clear, + color: Colors.grey, + size: 24.0, + ), + ), + ], + ), + ), + ); + }, + viewOnChanged: _onSearchChanged, // Update immediately + suggestionsBuilder: + (BuildContext context, SearchController controller) { + return _contactSuggestions.map((contact) { + return ListTile( + key: ValueKey(contact.id), + title: Text(_obfuscateService.obfuscateData(contact.displayName), + style: const TextStyle(color: Colors.white)), + onTap: () { + // Clear the search text input + controller.text = ''; + + // Close the search view + controller.closeView(contact.displayName); + + // Show the ContactModal when a contact is tapped + 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) { + _fetchContacts(); + 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, + ); + }, + ); + }, + ); + }).toList(); + }, ), ), // 3-dot menu @@ -170,7 +239,10 @@ class _MyHomePageState extends State ], onSelected: (String value) { if (value == 'settings') { - Navigator.pushNamed(context, '/settings'); + Navigator.push( + context, + MaterialPageRoute(builder: (context) => const SettingsPage()), + ); } }, ), @@ -195,7 +267,12 @@ class _MyHomePageState extends State bottom: 20, child: FloatingActionButton( onPressed: () { - Navigator.pushNamed(context, '/composition'); + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => const CompositionPage(), + ), + ); }, backgroundColor: Colors.blue, shape: RoundedRectangleBorder(