tasq/lib/widgets/profile_avatar.dart

86 lines
2.1 KiB
Dart

import 'package:flutter/material.dart';
/// Native Flutter profile avatar that displays either:
/// 1. User's avatar image URL (if provided)
/// 2. Initials derived from full name (fallback)
class ProfileAvatar extends StatelessWidget {
const ProfileAvatar({
super.key,
required this.fullName,
this.avatarUrl,
this.radius = 18,
});
final String fullName;
final String? avatarUrl;
final double radius;
String _getInitials() {
final trimmed = fullName.trim();
if (trimmed.isEmpty) return 'U';
final parts = trimmed.split(RegExp(r'\s+'));
if (parts.length == 1) {
return parts[0].substring(0, 1).toUpperCase();
}
// Get first letter of first and last name
return '${parts.first[0]}${parts.last[0]}'.toUpperCase();
}
Color _getInitialsColor(String initials) {
// Generate a deterministic color based on initials
final hash =
initials.codeUnitAt(0) +
(initials.length > 1 ? initials.codeUnitAt(1) * 256 : 0);
final colors = [
Colors.red,
Colors.pink,
Colors.purple,
Colors.deepPurple,
Colors.indigo,
Colors.blue,
Colors.lightBlue,
Colors.cyan,
Colors.teal,
Colors.green,
Colors.lightGreen,
Colors.orange,
Colors.deepOrange,
Colors.brown,
];
return colors[hash % colors.length];
}
@override
Widget build(BuildContext context) {
final initials = _getInitials();
// If avatar URL is provided, attempt to load the image
if (avatarUrl != null && avatarUrl!.isNotEmpty) {
return CircleAvatar(
radius: radius,
backgroundImage: NetworkImage(avatarUrl!),
onBackgroundImageError: (_, __) {
// Silently fall back to initials if image fails
},
child: null, // Image will display if loaded successfully
);
}
// Fallback to initials
return CircleAvatar(
radius: radius,
backgroundColor: _getInitialsColor(initials),
child: Text(
initials,
style: TextStyle(
color: Colors.white,
fontSize: radius * 0.8,
fontWeight: FontWeight.w600,
),
),
);
}
}