conversationCard function
Implementation
Widget conversationCard({
required String title,
required String message,
required String time,
required Color avatarIconColor,
required int unreadCount,
required bool isUnread,
bool isSelected = false,
VoidCallback? onTap,
IconData leadingIcon = Icons.groups_2_rounded,
Widget? leadingWidget,
}) {
return Builder(
builder: (context) {
final isDark = Theme.of(context).brightness == Brightness.dark;
final cardBg = isDark
? (isSelected
? const Color(0xFF653DAA).withValues(alpha: 0.28)
: (isUnread ? const Color(0xFF1E293B) : const Color(0xFF131D2E)))
: (isSelected
? const Color(0xFFF5F3FF)
: (isUnread ? Colors.white : const Color(0xFFFAFAFC)));
final borderColor = isDark
? (isSelected
? const Color(0xFFA78BFA)
: (isUnread
? const Color(0xFF475569).withValues(alpha: 0.8)
: const Color(0xFF334155).withValues(alpha: 0.4)))
: (isSelected
? const Color(0xFF7C3AED)
: (isUnread ? const Color(0xFFCBD5E1) : const Color(0xFFF1F5F9)));
final titleColor = isDark
? const Color(0xFFF8FAFC)
: const Color(0xFF0F172A);
final messageColor = isDark
? (isUnread ? const Color(0xFFE2E8F0) : const Color(0xFF94A3B8))
: (isUnread ? const Color(0xFF334155) : const Color(0xFF64748B));
final timeColor = isDark
? (isUnread ? const Color(0xFFE2E8F0) : const Color(0xFF94A3B8))
: (isUnread ? const Color(0xFF334155) : const Color(0xFF64748B));
final isMessageEmpty = message.trim().isEmpty;
final initials = _getInitials(title);
return Container(
margin: const EdgeInsets.only(bottom: 10),
decoration: BoxDecoration(
color: cardBg,
borderRadius: BorderRadius.circular(16),
border: Border.all(
color: borderColor,
width: isSelected ? 1.5 : 1.0,
),
boxShadow: [
if (!isDark)
BoxShadow(
color: isSelected
? const Color(0xFF7C3AED).withValues(alpha: 0.12)
: (isUnread
? Colors.black.withValues(alpha: 0.04)
: Colors.black.withValues(alpha: 0.02)),
blurRadius: isSelected ? 12 : 8,
offset: const Offset(0, 2),
spreadRadius: 0,
)
else if (isSelected)
BoxShadow(
color: const Color(0xFF7C3AED).withValues(alpha: 0.25),
blurRadius: 12,
offset: const Offset(0, 2),
),
],
),
child: Material(
color: Colors.transparent,
borderRadius: BorderRadius.circular(16),
clipBehavior: Clip.antiAlias,
child: InkWell(
onTap: onTap,
splashColor: (isDark ? const Color(0xFF8B5CF6) : const Color(0xFF653DAA))
.withValues(alpha: 0.1),
highlightColor: (isDark ? const Color(0xFF8B5CF6) : const Color(0xFF653DAA))
.withValues(alpha: 0.05),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 10),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
// Leading Avatar (2-letter initials or custom widget/icon)
leadingWidget ??
Container(
width: 48,
height: 48,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(15),
gradient: LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: [
avatarIconColor.withValues(alpha: isDark ? 0.25 : 0.15),
avatarIconColor.withValues(alpha: isDark ? 0.12 : 0.06),
],
),
border: Border.all(
color: avatarIconColor.withValues(alpha: isDark ? 0.35 : 0.2),
width: 1,
),
),
child: Center(
child: initials.isNotEmpty
? Text(
initials,
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w700,
color: avatarIconColor,
letterSpacing: -0.3,
),
)
: Icon(
leadingIcon,
color: avatarIconColor,
size: 24,
),
),
),
const SizedBox(width: 14),
// Content (Row 1: Title + Time, Row 2: Message + Badge)
Expanded(
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
// Row 1: Title & Timestamp
Row(
mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Expanded(
child: Text(
title,
maxLines: 1,
softWrap: false,
overflow: TextOverflow.ellipsis,
style: TextStyle(
fontSize: 15,
fontWeight: isUnread ? FontWeight.w700 : FontWeight.w600,
color: titleColor,
letterSpacing: -0.2,
),
),
),
if (time.isNotEmpty) ...[
const SizedBox(width: 8),
Text(
time,
maxLines: 1,
softWrap: false,
style: TextStyle(
fontSize: 11,
fontWeight: isUnread ? FontWeight.w600 : FontWeight.w400,
color: timeColor,
),
),
],
],
),
const SizedBox(height: 5),
// Row 2: Message & Unread Badge
Row(
mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Expanded(
child: Text(
isMessageEmpty ? 'No messages yet' : message,
maxLines: 1,
softWrap: false,
overflow: TextOverflow.ellipsis,
style: TextStyle(
fontSize: 13,
fontStyle: isMessageEmpty ? FontStyle.italic : FontStyle.normal,
fontWeight: isUnread && !isMessageEmpty
? FontWeight.w500
: FontWeight.w400,
color: isMessageEmpty
? (isDark ? const Color(0xFF64748B) : const Color(0xFF94A3B8))
: messageColor,
height: 1.25,
),
),
),
if (unreadCount > 0) ...[
const SizedBox(width: 8),
Container(
constraints: const BoxConstraints(
minWidth: 20,
minHeight: 20,
),
padding: const EdgeInsets.symmetric(
horizontal: 6,
vertical: 2,
),
alignment: Alignment.center,
decoration: BoxDecoration(
color: Colors.blue,
borderRadius: BorderRadius.circular(10),
),
child: Text(
unreadCount > 99 ? '99+' : '$unreadCount',
style: const TextStyle(
color: Colors.white,
fontSize: 10.5,
fontWeight: FontWeight.w700,
letterSpacing: -0.2,
),
),
),
] else if (isUnread) ...[
const SizedBox(width: 8),
Container(
width: 8,
height: 8,
decoration: BoxDecoration(
color: const Color(0xFF7C3AED),
shape: BoxShape.circle,
boxShadow: [
BoxShadow(
color: const Color(0xFF7C3AED).withValues(alpha: 0.4),
blurRadius: 4,
),
],
),
),
],
],
),
],
),
),
],
),
),
),
),
);
},
);
}