108 lines
2.9 KiB
Dart
108 lines
2.9 KiB
Dart
|
|
import 'package:cached_network_image/cached_network_image.dart';
|
||
|
|
import 'package:flutter/material.dart';
|
||
|
|
|
||
|
|
class ServerAvatar extends StatelessWidget {
|
||
|
|
final String name;
|
||
|
|
final String iconUrl;
|
||
|
|
final double size;
|
||
|
|
final bool isActive;
|
||
|
|
final bool showActiveBorder;
|
||
|
|
|
||
|
|
|
||
|
|
final ServerAvatarShape shape;
|
||
|
|
|
||
|
|
const ServerAvatar({
|
||
|
|
super.key,
|
||
|
|
required this.name,
|
||
|
|
this.iconUrl = '',
|
||
|
|
this.size = 38,
|
||
|
|
this.isActive = false,
|
||
|
|
this.showActiveBorder = false,
|
||
|
|
this.shape = ServerAvatarShape.roundedSquare,
|
||
|
|
});
|
||
|
|
|
||
|
|
|
||
|
|
static const _avatarColors = [
|
||
|
|
Color(0xFF6366F1),
|
||
|
|
Color(0xFF3B82F6),
|
||
|
|
Color(0xFF22C55E),
|
||
|
|
Color(0xFFA855F7),
|
||
|
|
Color(0xFFF97316),
|
||
|
|
Color(0xFF14B8A6),
|
||
|
|
Color(0xFFEC4899),
|
||
|
|
Color(0xFF84CC16),
|
||
|
|
];
|
||
|
|
|
||
|
|
|
||
|
|
static Color seedColorFor(String name) =>
|
||
|
|
_avatarColors[name.hashCode.abs() % _avatarColors.length];
|
||
|
|
|
||
|
|
@override
|
||
|
|
Widget build(BuildContext context) {
|
||
|
|
final color = seedColorFor(name);
|
||
|
|
final initial = name.isNotEmpty ? name[0].toUpperCase() : '?';
|
||
|
|
final hasIcon = iconUrl.isNotEmpty;
|
||
|
|
|
||
|
|
final radius = shape == ServerAvatarShape.circle ? size / 2 : size * 0.26;
|
||
|
|
|
||
|
|
final borderRadius = BorderRadius.circular(radius);
|
||
|
|
|
||
|
|
final borderColor = showActiveBorder && isActive
|
||
|
|
? color.withValues(alpha: 0.55)
|
||
|
|
: color.withValues(alpha: 0.25);
|
||
|
|
|
||
|
|
return Container(
|
||
|
|
width: size,
|
||
|
|
height: size,
|
||
|
|
decoration: BoxDecoration(
|
||
|
|
color: hasIcon ? Colors.transparent : color.withValues(alpha: 0.15),
|
||
|
|
borderRadius: borderRadius,
|
||
|
|
border: Border.all(
|
||
|
|
color: hasIcon ? Colors.transparent : borderColor,
|
||
|
|
width: showActiveBorder && isActive ? 1.5 : 1,
|
||
|
|
),
|
||
|
|
),
|
||
|
|
clipBehavior: Clip.antiAlias,
|
||
|
|
child: hasIcon
|
||
|
|
? CachedNetworkImage(
|
||
|
|
imageUrl: iconUrl,
|
||
|
|
fit: BoxFit.contain,
|
||
|
|
memCacheWidth: 128,
|
||
|
|
fadeInDuration: const Duration(milliseconds: 180),
|
||
|
|
placeholder: (_, _) => Center(
|
||
|
|
child: Text(
|
||
|
|
initial,
|
||
|
|
style: TextStyle(
|
||
|
|
color: color,
|
||
|
|
fontWeight: FontWeight.w700,
|
||
|
|
fontSize: size * 0.42,
|
||
|
|
),
|
||
|
|
),
|
||
|
|
),
|
||
|
|
errorWidget: (_, _, _) => Center(
|
||
|
|
child: Text(
|
||
|
|
initial,
|
||
|
|
style: TextStyle(
|
||
|
|
color: color,
|
||
|
|
fontWeight: FontWeight.w700,
|
||
|
|
fontSize: size * 0.42,
|
||
|
|
),
|
||
|
|
),
|
||
|
|
),
|
||
|
|
)
|
||
|
|
: Center(
|
||
|
|
child: Text(
|
||
|
|
initial,
|
||
|
|
style: TextStyle(
|
||
|
|
color: color,
|
||
|
|
fontWeight: FontWeight.w700,
|
||
|
|
fontSize: size * 0.42,
|
||
|
|
),
|
||
|
|
),
|
||
|
|
),
|
||
|
|
);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
enum ServerAvatarShape { roundedSquare, circle }
|