From e0a937e231d9fac352f1d5970bdea05e71453877 Mon Sep 17 00:00:00 2001 From: Bartosz Date: Wed, 18 Dec 2024 20:41:59 +0000 Subject: [PATCH] add of details on history --- dialer/lib/features/history/history_page.dart | 264 +++++++++++++++--- 1 file changed, 232 insertions(+), 32 deletions(-) diff --git a/dialer/lib/features/history/history_page.dart b/dialer/lib/features/history/history_page.dart index 36be4e0..589a136 100644 --- a/dialer/lib/features/history/history_page.dart +++ b/dialer/lib/features/history/history_page.dart @@ -1,12 +1,8 @@ -// 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:intl/intl.dart'; +import 'package:url_launcher/url_launcher.dart'; 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'; @@ -33,11 +29,9 @@ class HistoryPage extends StatefulWidget { _HistoryPageState createState() => _HistoryPageState(); } -class _HistoryPageState extends State { +class _HistoryPageState extends State with SingleTickerProviderStateMixin { List histories = []; bool loading = true; - - // Track expanded items int? _expandedIndex; @override @@ -59,7 +53,6 @@ class _HistoryPageState extends State { } List contacts = contactState.contacts; - // Ensure there are enough contacts if (contacts.isEmpty) { setState(() { loading = false; @@ -67,7 +60,6 @@ class _HistoryPageState extends State { return; } - // Build histories using the contacts setState(() { histories = List.generate( contacts.length >= 10 ? 10 : contacts.length, @@ -83,6 +75,47 @@ class _HistoryPageState extends State { }); } + List _buildGroupedList(List historyList) { + // Sort histories by date (most recent first) + historyList.sort((a, b) => b.date.compareTo(a.date)); + + final now = DateTime.now(); + final today = DateTime(now.year, now.month, now.day); + final yesterday = today.subtract(const Duration(days: 1)); + + List todayHistories = []; + List yesterdayHistories = []; + List olderHistories = []; + + for (var history in historyList) { + final callDate = DateTime(history.date.year, history.date.month, history.date.day); + if (callDate == today) { + todayHistories.add(history); + } else if (callDate == yesterday) { + yesterdayHistories.add(history); + } else { + olderHistories.add(history); + } + } + + // Combine them with headers + final items = []; + if (todayHistories.isNotEmpty) { + items.add('Today'); + items.addAll(todayHistories); + } + if (yesterdayHistories.isNotEmpty) { + items.add('Yesterday'); + items.addAll(yesterdayHistories); + } + if (olderHistories.isNotEmpty) { + items.add('Older'); + items.addAll(olderHistories); + } + + return items; + } + @override Widget build(BuildContext context) { final contactState = ContactState.of(context); @@ -90,9 +123,6 @@ class _HistoryPageState extends State { if (loading || contactState.loading) { return Scaffold( backgroundColor: Colors.black, - appBar: AppBar( - title: const Text('History'), - ), body: const Center( child: CircularProgressIndicator(), ), @@ -102,9 +132,6 @@ class _HistoryPageState extends State { if (histories.isEmpty) { return Scaffold( backgroundColor: Colors.black, - appBar: AppBar( - title: const Text('History'), - ), body: const Center( child: Text( 'No call history available.', @@ -114,19 +141,66 @@ class _HistoryPageState extends State { ); } - return Scaffold( - backgroundColor: Colors.black, - appBar: AppBar( - title: const Text('History'), + // Filter missed calls + List missedCalls = histories.where((h) => h.callStatus == 'missed').toList(); + + final allItems = _buildGroupedList(histories); + final missedItems = _buildGroupedList(missedCalls); + + return DefaultTabController( + length: 2, + child: Scaffold( + backgroundColor: Colors.black, + appBar: PreferredSize( + preferredSize: const Size.fromHeight(kToolbarHeight), + child: Container( + color: Colors.black, + child: const TabBar( + tabs: [ + Tab(text: 'All Calls'), + Tab(text: 'Missed Calls'), + ], + indicatorColor: Colors.white, + ), + ), + ), + body: TabBarView( + children: [ + // All Calls + _buildListView(allItems), + // Missed Calls + _buildListView(missedItems), + ], + ), ), - body: ListView.builder( - itemCount: histories.length, - itemBuilder: (context, index) { - final history = histories[index]; + ); + } + + Widget _buildListView(List items) { + return ListView.builder( + itemCount: items.length, + itemBuilder: (context, index) { + final item = items[index]; + + if (item is String) { + // This is a header item + return Container( + padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 16), + color: Colors.grey[900], + child: Text( + item, + style: const TextStyle( + color: Colors.white70, + fontWeight: FontWeight.bold, + ), + ), + ); + } else if (item is History) { + final history = item; final contact = history.contact; final isExpanded = _expandedIndex == index; - // Generate the avatar color using the same logic as the contacts page + // Generate the avatar color Color avatarColor = generateColorFromName(contact.displayName); return Column( @@ -196,9 +270,9 @@ class _HistoryPageState extends State { children: [ TextButton.icon( onPressed: () async { - if (contact.phones.isNotEmpty) { + if (history.contact.phones.isNotEmpty) { final Uri smsUri = - Uri(scheme: 'sms', path: contact.phones.first.number); + Uri(scheme: 'sms', path: history.contact.phones.first.number); if (await canLaunchUrl(smsUri)) { await launchUrl(smsUri); } else { @@ -213,15 +287,28 @@ class _HistoryPageState extends State { } }, icon: const Icon(Icons.message, color: Colors.white), - label: - const Text('Message', style: TextStyle(color: Colors.white)), + label: const Text('Message', style: TextStyle(color: Colors.white)), + ), + TextButton.icon( + onPressed: () { + // Navigate to Call Details page + Navigator.push( + context, + MaterialPageRoute( + builder: (_) => CallDetailsPage(history: history), + ), + ); + }, + icon: const Icon(Icons.info, color: Colors.white), + label: const Text('Details', 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)')), + content: Text('Number blocked (functionality not implemented)'), + ), ); }, icon: const Icon(Icons.block, color: Colors.white), @@ -232,7 +319,120 @@ class _HistoryPageState extends State { ), ], ); - }, + } + + return const SizedBox.shrink(); + }, + ); + } +} + +class CallDetailsPage extends StatelessWidget { + final History history; + + const CallDetailsPage({Key? key, required this.history}) : super(key: key); + + @override + Widget build(BuildContext context) { + final contact = history.contact; + + return Scaffold( + backgroundColor: Colors.black, + appBar: AppBar( + title: const Text('Call Details'), + backgroundColor: Colors.black, + ), + body: Padding( + padding: const EdgeInsets.all(16.0), + child: Column( + children: [ + // Display Contact Name and Thumbnail + Row( + children: [ + (contact.thumbnail != null && contact.thumbnail!.isNotEmpty) + ? CircleAvatar( + backgroundImage: MemoryImage(contact.thumbnail!), + radius: 30, + ) + : CircleAvatar( + backgroundColor: Colors.grey[700], + radius: 30, + child: Text( + contact.displayName.isNotEmpty + ? contact.displayName[0].toUpperCase() + : '?', + style: const TextStyle(color: Colors.white), + ), + ), + const SizedBox(width: 16), + Expanded( + child: Text( + contact.displayName, + style: const TextStyle(color: Colors.white, fontSize: 24), + ), + ), + ], + ), + const SizedBox(height: 24), + + // Display call type, status, date, attempts + DetailRow( + label: 'Call Type:', + value: history.callType, + ), + DetailRow( + label: 'Call Status:', + value: history.callStatus, + ), + DetailRow( + label: 'Date:', + value: DateFormat('MMM dd, yyyy - hh:mm a').format(history.date), + ), + DetailRow( + label: 'Attempts:', + value: '${history.attempts}', + ), + + const SizedBox(height: 24), + + // If you have more details like duration, contact number, etc. + if (contact.phones.isNotEmpty) + DetailRow( + label: 'Number:', + value: contact.phones.first.number, + ), + ], + ), + ), + ); + } +} + +class DetailRow extends StatelessWidget { + final String label; + final String value; + + const DetailRow({Key? key, required this.label, required this.value}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Padding( + padding: const EdgeInsets.symmetric(vertical: 8.0), + child: Row( + children: [ + Text( + label, + style: const TextStyle(color: Colors.white70, fontWeight: FontWeight.bold), + ), + const SizedBox(width: 8), + Expanded( + child: Text( + value, + style: const TextStyle(color: Colors.white), + textAlign: TextAlign.right, + ), + ), + ], ), ); }