diff --git a/dialer/lib/features/composition/composition.dart b/dialer/lib/features/composition/composition.dart index 774cc49..bdaf048 100644 --- a/dialer/lib/features/composition/composition.dart +++ b/dialer/lib/features/composition/composition.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:flutter_contacts/flutter_contacts.dart'; class CompositionPage extends StatefulWidget { const CompositionPage({super.key}); @@ -9,80 +10,228 @@ class CompositionPage extends StatefulWidget { class _CompositionPageState extends State { String dialedNumber = ""; + List _allContacts = []; + List _filteredContacts = []; + @override + void initState() { + super.initState(); + _fetchContacts(); + } + + Future _fetchContacts() async { + if (await FlutterContacts.requestPermission()) { + _allContacts = await FlutterContacts.getContacts(withProperties: true); + _filteredContacts = _allContacts; + setState(() {}); + } + } + + void _filterContacts() { + setState(() { + _filteredContacts = _allContacts.where((contact) { + final phoneMatch = contact.phones.any((phone) => + phone.number.replaceAll(RegExp(r'\D'), '').contains(dialedNumber)); + final nameMatch = contact.displayName + .toLowerCase() + .contains(dialedNumber.toLowerCase()); + return phoneMatch || nameMatch; + }).toList(); + }); + } void _onNumberPress(String number) { setState(() { dialedNumber += number; + _filterContacts(); }); } - void _onDeletePress() { setState(() { if (dialedNumber.isNotEmpty) { dialedNumber = dialedNumber.substring(0, dialedNumber.length - 1); + _filterContacts(); } }); } + void _onClearPress() { + setState(() { + dialedNumber = ""; + _filteredContacts = _allContacts; + }); + } + + // Placeholder function for adding contact + void addContact(String number) { + // This function is empty for now + } + @override Widget build(BuildContext context) { return Scaffold( backgroundColor: Colors.black, - body: Column( + body: Stack( children: [ - Expanded( - flex: 1, - child: Center( - child: Text( - dialedNumber, - style: const TextStyle( - fontSize: 32, - color: Colors.white, - letterSpacing: 2.0, + Column( + children: [ + // Top half: Display contacts matching dialed number + Expanded( + flex: 2, + child: + Container( + padding: const EdgeInsets.only(top: 42.0, left: 16.0, right: 16.0, bottom: 16.0), + color: Colors.black, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Expanded( + child: ListView( + children: _filteredContacts.isNotEmpty + ? _filteredContacts.map((contact) { + return ListTile( + title: Text( + contact.displayName, + style: const TextStyle(color: Colors.white), + ), + subtitle: contact.phones.isNotEmpty + ? Text( + contact.phones.first.number, + style: const TextStyle(color: Colors.grey), + ) + : null, + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + // Call button + IconButton( + icon: Icon(Icons.phone, color: Colors.green[300], size: 20), + onPressed: () { + print('Calling ${contact.displayName}'); + }, + ), + // Text button + IconButton( + icon: Icon(Icons.message, color: Colors.blue[300], size: 20), + onPressed: () { + print('Texting ${contact.displayName}'); + }, + ), + ], + ), + onTap: () { + // Handle contact selection if needed + }, + ); + }).toList() + : [Center(child: Text('No contacts found', style: TextStyle(color: Colors.white)))], + ), + ), + ], + ), ), ), - ), - ), - Expanded( - flex: 3, - child: Padding( - padding: const EdgeInsets.all(16.0), - child: GridView.builder( - gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: 3, - mainAxisSpacing: 10, - crossAxisSpacing: 10, - childAspectRatio: 1, + + // Bottom half: Dialpad and Dialed number display with erase button + Expanded( + flex: 2, + child: Container( + padding: const EdgeInsets.symmetric(horizontal: 16.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + // Display dialed number with erase button + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Expanded( + child: Align( + alignment: Alignment.center, + child: Text( + dialedNumber, + style: const TextStyle(fontSize: 24, color: Colors.white), + overflow: TextOverflow.ellipsis, + ), + ), + ), + IconButton( + onPressed: _onClearPress, + icon: const Icon(Icons.backspace, color: Colors.white), + ), + ], + ), + const SizedBox(height: 10), + + // Dialpad + Expanded( + child: SingleChildScrollView( + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + _buildDialButton('1'), + _buildDialButton('2'), + _buildDialButton('3'), + ], + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + _buildDialButton('4'), + _buildDialButton('5'), + _buildDialButton('6'), + ], + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + _buildDialButton('7'), + _buildDialButton('8'), + _buildDialButton('9'), + ], + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + _buildDialButton('*'), + _buildDialButton('0'), + _buildDialButton('#'), + ], + ), + ], + ), + ), + ), + ], + ), ), - itemCount: 12, - itemBuilder: (context, index) { - if (index < 9) { - - return _buildDialButton((index + 1).toString()); - } else if (index == 9) { - - return const SizedBox.shrink(); - } else if (index == 10) { - - return _buildDialButton('0'); - } else { - - return _buildDeleteButton(); - } - }, ), - ), + + // Add Contact Button with empty function call + Padding( + padding: const EdgeInsets.only(bottom: 20.0), + child: FloatingActionButton( + backgroundColor: Colors.blue, + onPressed: () { + addContact(dialedNumber); + }, + child: const Icon(Icons.person_add, color: Colors.white), + ), + ), + ], ), - Padding( - padding: const EdgeInsets.only(bottom: 20.0), - child: FloatingActionButton( - backgroundColor: Colors.green, + // Top Row with Back Arrow + Positioned( + top: 40.0, + left: 16.0, + child: IconButton( + icon: const Icon(Icons.arrow_back, color: Colors.white), onPressed: () { - + Navigator.pop(context); }, - child: const Icon(Icons.phone, color: Colors.white), ), ), ], @@ -90,14 +239,13 @@ class _CompositionPageState extends State { ); } - Widget _buildDialButton(String number) { return ElevatedButton( onPressed: () => _onNumberPress(number), style: ElevatedButton.styleFrom( backgroundColor: Colors.black, shape: const CircleBorder(), - padding: const EdgeInsets.all(20), + padding: const EdgeInsets.all(16), ), child: Text( number, @@ -108,21 +256,4 @@ class _CompositionPageState extends State { ), ); } - - - Widget _buildDeleteButton() { - return ElevatedButton( - onPressed: _onDeletePress, - style: ElevatedButton.styleFrom( - backgroundColor: Colors.black, - shape: const CircleBorder(), - padding: const EdgeInsets.all(20), - ), - child: const Icon( - Icons.backspace, - color: Colors.white, - size: 24, - ), - ); - } } diff --git a/dialer/lib/features/home/home_page.dart b/dialer/lib/features/home/home_page.dart index 26d2f7f..09ded0c 100644 --- a/dialer/lib/features/home/home_page.dart +++ b/dialer/lib/features/home/home_page.dart @@ -3,17 +3,43 @@ import 'package:dialer/features/contacts/contact_page.dart'; import 'package:dialer/features/favorites/favorites_page.dart'; import 'package:dialer/features/history/history_page.dart'; import 'package:dialer/features/composition/composition.dart'; +import 'package:flutter_contacts/flutter_contacts.dart'; class _MyHomePageState extends State with SingleTickerProviderStateMixin { late TabController _tabController; - final SearchController _searchController = SearchController(); + List _allContacts = []; + List _contactSuggestions = []; @override void initState() { super.initState(); _tabController = TabController(length: 3, vsync: this, initialIndex: 1); _tabController.addListener(_handleTabIndex); + _fetchContacts(); + } + + void _fetchContacts() async { + if (await FlutterContacts.requestPermission()) { + _allContacts = await FlutterContacts.getContacts(withProperties: true); + setState(() {}); + } + } + + void _onSearchChanged(String query) { + print("Search query: $query"); + + setState(() { + if (query.isEmpty) { + _contactSuggestions = List.from(_allContacts); + } else { + _contactSuggestions = _allContacts.where((contact) { + return contact.displayName + .toLowerCase() + .contains(query.toLowerCase()); + }).toList(); + } + }); } @override @@ -27,10 +53,6 @@ class _MyHomePageState extends State setState(() {}); } - void _onSearchChanged(String query) { - // Use this method to manage search actions if needed - } - @override Widget build(BuildContext context) { return Scaffold( @@ -40,15 +62,14 @@ class _MyHomePageState extends State // Persistent Search Bar Padding( padding: const EdgeInsets.only( - top: 24.0, // Outside top padding - bottom: 10.0, // Outside bottom padding - left: 16.0, // Outside left padding - right: 16.0, // Outside right padding + top: 24.0, + bottom: 10.0, + left: 16.0, + right: 16.0, ), child: Container( decoration: BoxDecoration( - color: const Color.fromARGB( - 255, 30, 30, 30), // Background of the SearchBar + color: const Color.fromARGB(255, 30, 30, 30), borderRadius: BorderRadius.circular(12.0), border: Border( top: BorderSide(color: Colors.grey.shade800, width: 1), @@ -63,15 +84,15 @@ class _MyHomePageState extends State controller: controller, padding: MaterialStateProperty.all( EdgeInsets.only( - top: 10.0, // Inside top padding - bottom: 10.0, // Inside bottom padding - left: 16.0, // Inside left padding - right: 16.0, // Inside right padding + top: 6.0, + bottom: 6.0, + left: 16.0, + right: 16.0, ), ), - onChanged: _onSearchChanged, onTap: () { controller.openView(); + _onSearchChanged(''); }, backgroundColor: MaterialStateProperty.all( const Color.fromARGB(255, 30, 30, 30)), @@ -91,18 +112,21 @@ class _MyHomePageState extends State ), ); }, + viewOnChanged: (query) { + _onSearchChanged(query); + }, suggestionsBuilder: (BuildContext context, SearchController controller) { - return List.generate(5, (int index) { - final String item = 'Suggestion $index'; + return _contactSuggestions.map((contact) { return ListTile( - title: Text(item), + key: ValueKey(contact.id), + title: Text(contact.displayName, + style: const TextStyle(color: Colors.white)), onTap: () { - // Close the search view and select suggestion - controller.closeView(item); + controller.closeView(contact.displayName); }, ); - }); + }).toList(); }, ), ),