From 2ea2c679b2d30a0b0ca1bd33271d1fbedb1aee1c Mon Sep 17 00:00:00 2001 From: Florian Griffon Date: Tue, 4 Mar 2025 13:10:42 +0000 Subject: [PATCH] fix: search bar upgrade (#42) Reviewed-on: https://git.gmoker.com/icing/monorepo/pulls/42 Co-authored-by: Florian Griffon Co-committed-by: Florian Griffon --- dialer/lib/features/home/home_page.dart | 159 ++++++++++++++++++------ 1 file changed, 120 insertions(+), 39 deletions(-) diff --git a/dialer/lib/features/home/home_page.dart b/dialer/lib/features/home/home_page.dart index 97e2c88..65adaa8 100644 --- a/dialer/lib/features/home/home_page.dart +++ b/dialer/lib/features/home/home_page.dart @@ -8,6 +8,7 @@ import 'package:flutter_contacts/flutter_contacts.dart'; import 'package:dialer/features/settings/settings.dart'; import '../../services/contact_service.dart'; import 'package:dialer/features/voicemail/voicemail_page.dart'; +import '../contacts/widgets/contact_modal.dart'; class _MyHomePageState extends State @@ -17,6 +18,8 @@ class _MyHomePageState extends State List _contactSuggestions = []; final ContactService _contactService = ContactService(); final ObfuscateService _obfuscateService = ObfuscateService(); + final TextEditingController _searchController = TextEditingController(); + @override void initState() { @@ -32,12 +35,15 @@ class _MyHomePageState extends State setState(() {}); } - void _onSearchChanged(String query) { - print("Search query: $query"); + void _clearSearch() { + _searchController.clear(); + _onSearchChanged(''); + } + void _onSearchChanged(String query) { setState(() { if (query.isEmpty) { - _contactSuggestions = List.from(_allContacts); + _contactSuggestions = List.from(_allContacts); // Reset suggestions } else { _contactSuggestions = _allContacts.where((contact) { return contact.displayName @@ -50,6 +56,7 @@ class _MyHomePageState extends State @override void dispose() { + _searchController.dispose(); _tabController.removeListener(_handleTabIndex); _tabController.dispose(); super.dispose(); @@ -59,6 +66,34 @@ class _MyHomePageState extends State 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); + setState(() { + // Updating the contact list after toggling the favorite + _fetchContacts(); + }); + } + } 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) { return Scaffold( @@ -80,63 +115,109 @@ class _MyHomePageState extends State decoration: BoxDecoration( color: const Color.fromARGB(255, 30, 30, 30), borderRadius: BorderRadius.circular(12.0), - border: Border( - top: BorderSide(color: Colors.grey.shade800, width: 1), - left: BorderSide(color: Colors.grey.shade800, width: 1), - right: BorderSide(color: Colors.grey.shade800, width: 1), - bottom: - BorderSide(color: Colors.grey.shade800, width: 2), - ), + border: Border.all(color: Colors.grey.shade800, width: 1), ), child: SearchAnchor( builder: (BuildContext context, SearchController controller) { - return SearchBar( - controller: controller, - padding: - WidgetStateProperty.all( - const EdgeInsets.only( - top: 6.0, - bottom: 6.0, - left: 16.0, - right: 16.0, - ), - ), + return GestureDetector( onTap: () { - controller.openView(); - _onSearchChanged(''); + controller.openView(); // Open the search view }, - backgroundColor: WidgetStateProperty.all( - const Color.fromARGB(255, 30, 30, 30)), - hintText: 'Search contacts', - hintStyle: WidgetStateProperty.all( - const TextStyle(color: Colors.grey, fontSize: 16.0), - ), - leading: const Icon( - Icons.search, - color: Colors.grey, - size: 24.0, - ), - shape: - WidgetStateProperty.all( - RoundedRectangleBorder( + 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( + _searchController.text.isEmpty + ? 'Search contacts' + : _searchController.text, + style: const TextStyle( + color: Colors.grey, fontSize: 16.0), + ), + const Spacer(), + if (_searchController.text.isNotEmpty) + GestureDetector( + onTap: _clearSearch, + child: const Icon( + Icons.clear, + color: Colors.grey, + size: 24.0, + ), + ), + ], ), ), ); }, viewOnChanged: (query) { - _onSearchChanged(query); + _onSearchChanged(query); // Update immediately }, suggestionsBuilder: (BuildContext context, SearchController controller) { return _contactSuggestions.map((contact) { - return ListTile( + 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();