import 'package:flutter/material.dart'; import 'package:flutter_contacts/flutter_contacts.dart'; import 'package:url_launcher/url_launcher.dart'; import '../../services/contact_service.dart'; import '../../services/obfuscate_service.dart'; import '../../services/call_service.dart'; class CompositionPage extends StatefulWidget { const CompositionPage({super.key}); @override _CompositionPageState createState() => _CompositionPageState(); } class _CompositionPageState extends State { String dialedNumber = ""; List _allContacts = []; List _filteredContacts = []; final ContactService _contactService = ContactService(); final ObfuscateService _obfuscateService = ObfuscateService(); final CallService _callService = CallService(); @override void initState() { super.initState(); _fetchContacts(); } Future _fetchContacts() async { _allContacts = await _contactService.fetchContacts(); _filteredContacts = _allContacts; setState(() {}); } void _filterContacts() { setState(() { _filteredContacts = _allContacts.where((contact) { bool phoneMatch = contact.phones.any((phone) { final rawPhoneNumber = phone.number; final strippedPhoneNumber = rawPhoneNumber.replaceAll(RegExp(r'\D'), ''); final strippedDialedNumber = dialedNumber.replaceAll(RegExp(r'\D'), ''); return rawPhoneNumber.contains(dialedNumber) || strippedPhoneNumber.contains(strippedDialedNumber); }); final nameMatch = contact.displayName .toLowerCase() .contains(dialedNumber.toLowerCase()); return phoneMatch || nameMatch; }).toList(); }); } void _onNumberPress(String number) { setState(() { dialedNumber += number; _filterContacts(); }); } void _onPlusPress() { setState(() { dialedNumber += '+'; _filterContacts(); }); } void _onDeletePress() { setState(() { if (dialedNumber.isNotEmpty) { dialedNumber = dialedNumber.substring(0, dialedNumber.length - 1); _filterContacts(); } }); } void _onClearPress() { setState(() { dialedNumber = ""; _filteredContacts = _allContacts; }); } void _makeCall(String phoneNumber) async { try { await _callService.makeGsmCall(context, phoneNumber: phoneNumber); setState(() { dialedNumber = phoneNumber; }); } catch (e) { debugPrint("Error making call: $e"); ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text('Failed to make call: $e')), ); } } void _launchSms(String phoneNumber) async { final uri = Uri(scheme: 'sms', path: phoneNumber); if (await canLaunchUrl(uri)) { await launchUrl(uri); } else { debugPrint('Could not send SMS to $phoneNumber'); } } void _addContact() async { if (await FlutterContacts.requestPermission()) { final newContact = Contact() ..phones = [Phone(dialedNumber.isNotEmpty ? dialedNumber : '')]; final updatedContact = await FlutterContacts.openExternalInsert(newContact); if (updatedContact != null) { _fetchContacts(); ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text('Contact added successfully!')), ); } } } @override Widget build(BuildContext context) { return Scaffold( backgroundColor: Colors.black, body: Stack( children: [ Column( children: [ 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.map((contact) { final phoneNumber = contact.phones.isNotEmpty ? contact.phones.first.number : 'No phone number'; return ListTile( title: Text( _obfuscateService.obfuscateData(contact.displayName), style: const TextStyle(color: Colors.white), ), subtitle: Text( _obfuscateService.obfuscateData(phoneNumber), style: const TextStyle(color: Colors.grey), ), trailing: Row( mainAxisSize: MainAxisSize.min, children: [ IconButton( icon: Icon(Icons.phone, color: Colors.green[300], size: 20), onPressed: () => _makeCall(phoneNumber), ), IconButton( icon: Icon(Icons.message, color: Colors.blue[300], size: 20), onPressed: () => _launchSms(phoneNumber), ), ], ), onTap: () {}, ); }).toList(), ListTile( title: const Text( 'Add a contact', style: TextStyle(color: Colors.white), ), trailing: Icon(Icons.add, color: Colors.grey[600]), onTap: _addContact, ), ], ), ), ], ), ), ), Expanded( flex: 2, child: Container( padding: const EdgeInsets.symmetric(horizontal: 16.0), child: Column( mainAxisAlignment: MainAxisAlignment.start, children: [ 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, ), ), ), GestureDetector( onTap: _onDeletePress, onLongPress: _onClearPress, child: const Padding( padding: EdgeInsets.all(8.0), child: Icon(Icons.backspace, color: Colors.white), ), ), ], ), const SizedBox(height: 10), Expanded( child: SingleChildScrollView( child: Column( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ _buildDialButton('1', Colors.white), _buildDialButton('2', Colors.white), _buildDialButton('3', Colors.white), ], ), Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ _buildDialButton('4', Colors.white), _buildDialButton('5', Colors.white), _buildDialButton('6', Colors.white), ], ), Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ _buildDialButton('7', Colors.white), _buildDialButton('8', Colors.white), _buildDialButton('9', Colors.white), ], ), Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ _buildDialButton('*', const Color.fromRGBO(117, 117, 117, 1)), _buildDialButtonWithPlus('0'), _buildDialButton('#', const Color.fromRGBO(117, 117, 117, 1)), ], ), ], ), ), ), ], ), ), ), ], ), Positioned( bottom: 20.0, left: 0, right: 0, child: Center( child: ElevatedButton( onPressed: dialedNumber.isNotEmpty ? () => _makeCall(dialedNumber) : null, style: ElevatedButton.styleFrom( backgroundColor: Colors.green[700], shape: const CircleBorder(), padding: const EdgeInsets.all(20), ), child: const Icon(Icons.phone, color: Colors.white, size: 30), ), ), ), Positioned( top: 40.0, left: 16.0, child: IconButton( icon: const Icon(Icons.arrow_back, color: Colors.white), onPressed: () => Navigator.pop(context), ), ), ], ), ); } Widget _buildDialButton(String number, Color textColor) { return ElevatedButton( onPressed: () => _onNumberPress(number), style: ElevatedButton.styleFrom( backgroundColor: Colors.black, shape: const CircleBorder(), padding: const EdgeInsets.all(16), ), child: Text( number, style: TextStyle(fontSize: 24, color: textColor), ), ); } Widget _buildDialButtonWithPlus(String number) { return Stack( alignment: Alignment.center, children: [ GestureDetector( onLongPress: _onPlusPress, child: ElevatedButton( onPressed: () => _onNumberPress(number), style: ElevatedButton.styleFrom( backgroundColor: Colors.black, shape: const CircleBorder(), padding: const EdgeInsets.all(16), ), child: Text( number, style: const TextStyle(fontSize: 24, color: Colors.white), ), ), ), Positioned( bottom: 8, child: Text( '+', style: TextStyle(fontSize: 12, color: Colors.grey[600]), ), ), ], ); } }