Initial commit with Flutter and Node.js code
This commit is contained in:
149
whatsapp_app/lib/widgets/conversation_tile.dart
Normal file
149
whatsapp_app/lib/widgets/conversation_tile.dart
Normal file
@@ -0,0 +1,149 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import '../models/conversation_model.dart';
|
||||
import '../theme/app_theme.dart';
|
||||
|
||||
class ConversationTile extends StatelessWidget {
|
||||
final ConversationModel conversation;
|
||||
final VoidCallback onTap;
|
||||
|
||||
const ConversationTile({
|
||||
super.key,
|
||||
required this.conversation,
|
||||
required this.onTap,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final lastMsg = conversation.lastMessage;
|
||||
final hasUnread = conversation.unreadCount > 0;
|
||||
|
||||
return ListTile(
|
||||
onTap: onTap,
|
||||
contentPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 4),
|
||||
leading: _buildAvatar(),
|
||||
title: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Text(
|
||||
conversation.name,
|
||||
style: const TextStyle(
|
||||
color: AppTheme.textPrimary,
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Text(
|
||||
_formatTime(conversation.timestamp),
|
||||
style: TextStyle(
|
||||
color: hasUnread ? AppTheme.primary : AppTheme.textSecondary,
|
||||
fontSize: 12,
|
||||
fontWeight: hasUnread ? FontWeight.bold : FontWeight.normal,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
subtitle: Padding(
|
||||
padding: const EdgeInsets.only(top: 4.0),
|
||||
child: Row(
|
||||
children: [
|
||||
if (lastMsg != null && lastMsg.fromMe) ...[
|
||||
const Icon(Icons.done_all, size: 16, color: AppTheme.primary), // Or proper ACK double tick
|
||||
const SizedBox(width: 4),
|
||||
],
|
||||
Expanded(
|
||||
child: Text(
|
||||
_getSubtitleText(lastMsg),
|
||||
style: const TextStyle(
|
||||
color: AppTheme.textSecondary,
|
||||
fontSize: 14,
|
||||
),
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
if (conversation.isMuted) ...[
|
||||
const SizedBox(width: 8),
|
||||
const Icon(Icons.volume_off, size: 16, color: AppTheme.textSecondary),
|
||||
],
|
||||
if (conversation.pinned) ...[
|
||||
const SizedBox(width: 8),
|
||||
const Icon(Icons.push_pin, size: 16, color: AppTheme.textSecondary),
|
||||
],
|
||||
if (hasUnread) ...[
|
||||
const SizedBox(width: 8),
|
||||
Container(
|
||||
padding: const EdgeInsets.all(6),
|
||||
decoration: const BoxDecoration(
|
||||
color: AppTheme.primary,
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
child: Text(
|
||||
conversation.unreadCount.toString(),
|
||||
style: const TextStyle(
|
||||
color: Colors.black,
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildAvatar() {
|
||||
if (conversation.avatar != null) {
|
||||
return CircleAvatar(
|
||||
radius: 26,
|
||||
backgroundImage: NetworkImage(conversation.avatar!),
|
||||
backgroundColor: AppTheme.surfaceLight,
|
||||
);
|
||||
}
|
||||
return CircleAvatar(
|
||||
radius: 26,
|
||||
backgroundColor: AppTheme.primaryDark,
|
||||
child: Text(
|
||||
conversation.name.isNotEmpty ? conversation.name[0].toUpperCase() : '?',
|
||||
style: const TextStyle(
|
||||
color: Colors.white,
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
String _getSubtitleText(LastMessageModel? lastMsg) {
|
||||
if (lastMsg == null) return '';
|
||||
if (lastMsg.hasMedia) {
|
||||
return '📷 Photo'; // or other media indicator
|
||||
}
|
||||
return lastMsg.body;
|
||||
}
|
||||
|
||||
String _formatTime(int timestamp) {
|
||||
if (timestamp == 0) return '';
|
||||
final dt = DateTime.fromMillisecondsSinceEpoch(timestamp * 1000);
|
||||
final now = DateTime.now();
|
||||
final today = DateTime(now.year, now.month, now.day);
|
||||
final yesterday = today.subtract(const Duration(days: 1));
|
||||
final msgDate = DateTime(dt.year, dt.month, dt.day);
|
||||
|
||||
if (msgDate == today) {
|
||||
return DateFormat('hh:mm a').format(dt);
|
||||
} else if (msgDate == yesterday) {
|
||||
return 'Yesterday';
|
||||
} else if (now.difference(dt).inDays < 7) {
|
||||
return DateFormat('EEEE').format(dt); // e.g. "Monday"
|
||||
} else {
|
||||
return DateFormat('MM/dd/yy').format(dt);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user