// history_page.dart import 'package:flutter/material.dart'; import 'package:flutter_contacts/flutter_contacts.dart'; import 'package:intl/intl.dart'; // For date formatting import 'package:url_launcher/url_launcher.dart'; // For launching URLs (phone calls, SMS) import 'package:dialer/features/contacts/contact_state.dart'; // Import the helper functions import 'package:dialer/widgets/username_color_generator.dart'; import 'package:dialer/widgets/color_darkener.dart'; class History { final Contact contact; final DateTime date; final String callType; // 'incoming' or 'outgoing' final String callStatus; // 'missed' or 'answered' final int attempts; History( this.contact, this.date, this.callType, this.callStatus, this.attempts, ); } class HistoryPage extends StatefulWidget { const HistoryPage({Key? key}) : super(key: key); @override _HistoryPageState createState() => _HistoryPageState(); } class _HistoryPageState extends State { List histories = []; bool loading = true; // Track expanded items int? _expandedIndex; @override void didChangeDependencies() { super.didChangeDependencies(); if (loading) { _buildHistories(); } } Future _buildHistories() async { final contactState = ContactState.of(context); if (contactState.loading) { // Wait for contacts to be loaded await Future.doWhile(() async { await Future.delayed(const Duration(milliseconds: 100)); return contactState.loading; }); } List contacts = contactState.contacts; // Ensure there are enough contacts if (contacts.isEmpty) { setState(() { loading = false; }); return; } // Build histories using the contacts setState(() { histories = List.generate( contacts.length >= 10 ? 10 : contacts.length, (index) => History( contacts[index], DateTime.now().subtract(Duration(hours: (index + 1) * 2)), index % 2 == 0 ? 'outgoing' : 'incoming', index % 3 == 0 ? 'missed' : 'answered', index % 3 + 1, ), ); loading = false; }); } @override Widget build(BuildContext context) { final contactState = ContactState.of(context); if (loading || contactState.loading) { return Scaffold( backgroundColor: Colors.black, appBar: AppBar( title: const Text('History'), ), body: const Center( child: CircularProgressIndicator(), ), ); } if (histories.isEmpty) { return Scaffold( backgroundColor: Colors.black, appBar: AppBar( title: const Text('History'), ), body: const Center( child: Text( 'No call history available.', style: TextStyle(color: Colors.white), ), ), ); } return Scaffold( backgroundColor: Colors.black, appBar: AppBar( title: const Text('History'), ), body: ListView.builder( itemCount: histories.length, itemBuilder: (context, index) { final history = histories[index]; final contact = history.contact; final isExpanded = _expandedIndex == index; // Generate the avatar color using the same logic as the contacts page Color avatarColor = generateColorFromName(contact.displayName); return Column( children: [ ListTile( leading: (contact.thumbnail != null && contact.thumbnail!.isNotEmpty) ? CircleAvatar( backgroundImage: MemoryImage(contact.thumbnail!), ) : CircleAvatar( backgroundColor: avatarColor, child: Text( contact.displayName.isNotEmpty ? contact.displayName[0].toUpperCase() : '?', style: TextStyle(color: darken(avatarColor, 0.4)), ), ), title: Text( contact.displayName, style: const TextStyle(color: Colors.white), ), subtitle: Text( '${history.callType} - ${history.callStatus} - ${DateFormat('MMM dd, hh:mm a').format(history.date)}', style: const TextStyle(color: Colors.grey), ), trailing: Row( mainAxisSize: MainAxisSize.min, children: [ Text( '${history.attempts}x', style: const TextStyle(color: Colors.white), ), IconButton( icon: const Icon(Icons.phone, color: Colors.green), onPressed: () async { if (contact.phones.isNotEmpty) { final Uri callUri = Uri(scheme: 'tel', path: contact.phones.first.number); if (await canLaunchUrl(callUri)) { await launchUrl(callUri); } else { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('Could not launch call')), ); } } else { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('Contact has no phone number')), ); } }, ), ], ), onTap: () { setState(() { _expandedIndex = isExpanded ? null : index; }); }, ), if (isExpanded) Container( color: Colors.grey[850], child: Row( mainAxisAlignment: MainAxisAlignment.spaceAround, children: [ TextButton.icon( onPressed: () async { if (contact.phones.isNotEmpty) { final Uri smsUri = Uri(scheme: 'sms', path: contact.phones.first.number); if (await canLaunchUrl(smsUri)) { await launchUrl(smsUri); } else { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('Could not send message')), ); } } else { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('Contact has no phone number')), ); } }, icon: const Icon(Icons.message, color: Colors.white), label: const Text('Message', style: TextStyle(color: Colors.white)), ), TextButton.icon( onPressed: () { // Implement block number functionality ScaffoldMessenger.of(context).showSnackBar( const SnackBar( content: Text('Number blocked (functionality not implemented)')), ); }, icon: const Icon(Icons.block, color: Colors.white), label: const Text('Block', style: TextStyle(color: Colors.white)), ), ], ), ), ], ); }, ), ); } }