From 64595a1755f90a487b0f2b05789365789dacfa31 Mon Sep 17 00:00:00 2001 From: Florian Griffon Date: Tue, 5 Nov 2024 23:39:48 +0100 Subject: [PATCH] feat: composition page finished, can search --- .../lib/features/composition/composition.dart | 322 ++++++++++-------- 1 file changed, 181 insertions(+), 141 deletions(-) diff --git a/dialer/lib/features/composition/composition.dart b/dialer/lib/features/composition/composition.dart index 3fb4743..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,22 +10,40 @@ class CompositionPage extends StatefulWidget { class _CompositionPageState extends State { String dialedNumber = ""; - final List contacts = [ - 'Alice Johnson', - 'Bob Smith', - 'Carol White', - 'David Brown', - 'Eve Black', - 'Frank Grey', - 'Grace Green', - 'Heidi Gold', - 'Ivan Silver', - 'Judy Blue' - ]; + 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(); }); } @@ -32,6 +51,7 @@ class _CompositionPageState extends State { setState(() { if (dialedNumber.isNotEmpty) { dialedNumber = dialedNumber.substring(0, dialedNumber.length - 1); + _filterContacts(); } }); } @@ -39,141 +59,179 @@ class _CompositionPageState extends State { void _onClearPress() { setState(() { dialedNumber = ""; + _filteredContacts = _allContacts; }); } - List _getFilteredContacts() { - return contacts - .where((contact) => - contact.toLowerCase().contains(dialedNumber.toLowerCase())) - .toList(); + // 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: [ - // Top half: Display contacts matching dialed number - Expanded( - flex: 2, - child: Container( - padding: const EdgeInsets.all(16.0), - color: Colors.black, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Expanded( - child: ListView( - children: _getFilteredContacts().map((contact) { - return ListTile( - title: Text(contact, - style: const TextStyle(color: Colors.white)), - onTap: () { - // Handle contact selection if needed - }, - ); - }).toList(), - ), - ), - ], - ), - ), - ), - - // 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, + 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: Align( - alignment: Alignment - .center, // Aligns text to the center of the screen - child: Text( - dialedNumber, - style: const TextStyle( - fontSize: 24, color: Colors.white), - overflow: TextOverflow.ellipsis, - ), + 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)))], ), ), - IconButton( - onPressed: _onClearPress, - icon: const Icon(Icons.backspace, color: Colors.white), - ), ], ), - const SizedBox(height: 10), + ), + ), - // Wrapping the dialpad in a SingleChildScrollView to prevent overflow - Expanded( - child: SingleChildScrollView( - child: Column( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, + // 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: [ - // First Row (1, 2, 3) - Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - _buildDialButton('1'), - _buildDialButton('2'), - _buildDialButton('3'), - ], + Expanded( + child: Align( + alignment: Alignment.center, + child: Text( + dialedNumber, + style: const TextStyle(fontSize: 24, color: Colors.white), + overflow: TextOverflow.ellipsis, + ), + ), ), - // Second Row (4, 5, 6) - Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - _buildDialButton('4'), - _buildDialButton('5'), - _buildDialButton('6'), - ], - ), - // Third Row (7, 8, 9) - Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - _buildDialButton('7'), - _buildDialButton('8'), - _buildDialButton('9'), - ], - ), - // Fourth Row (*, 0, #) - Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - _buildDialButton('*'), - _buildDialButton('0'), - _buildDialButton('#'), - ], + IconButton( + onPressed: _onClearPress, + icon: const Icon(Icons.backspace, color: Colors.white), ), ], ), - ), - ), - ], - ), - ), - ), + const SizedBox(height: 10), - // Bottom action: Call button with padding - Padding( - padding: const EdgeInsets.only(bottom: 20.0), - child: FloatingActionButton( - backgroundColor: Colors.green, + // 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('#'), + ], + ), + ], + ), + ), + ), + ], + ), + ), + ), + + // 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), + ), + ), + ], + ), + // Top Row with Back Arrow + Positioned( + top: 40.0, + left: 16.0, + child: IconButton( + icon: const Icon(Icons.arrow_back, color: Colors.white), onPressed: () { - // Handle call action + Navigator.pop(context); }, - child: const Icon(Icons.phone, color: Colors.white), ), ), ], @@ -187,8 +245,7 @@ class _CompositionPageState extends State { style: ElevatedButton.styleFrom( backgroundColor: Colors.black, shape: const CircleBorder(), - padding: - const EdgeInsets.all(16), // Adjusted padding to prevent overflow + padding: const EdgeInsets.all(16), ), child: Text( number, @@ -199,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(16), // Adjusted padding to prevent overflow - ), - child: const Icon( - Icons.backspace, - color: Colors.white, - size: 24, - ), - ); - } }