first commit

This commit is contained in:
DahoudG
2025-08-20 21:00:35 +00:00
commit b2a23bdf89
583 changed files with 243074 additions and 0 deletions

View File

@@ -0,0 +1,409 @@
import 'package:flutter/material.dart';
import '../../theme/app_theme.dart';
import '../badges/status_badge.dart';
import '../badges/count_badge.dart';
enum AvatarSize {
tiny,
small,
medium,
large,
extraLarge,
}
enum AvatarShape {
circle,
rounded,
square,
}
enum AvatarVariant {
standard,
gradient,
outlined,
glass,
}
class SophisticatedAvatar extends StatefulWidget {
final String? imageUrl;
final String? initials;
final IconData? icon;
final AvatarSize size;
final AvatarShape shape;
final AvatarVariant variant;
final Color? backgroundColor;
final Color? foregroundColor;
final Gradient? gradient;
final VoidCallback? onTap;
final Widget? badge;
final bool showOnlineStatus;
final bool isOnline;
final Widget? overlay;
final bool animated;
final List<BoxShadow>? customShadow;
final Border? border;
const SophisticatedAvatar({
super.key,
this.imageUrl,
this.initials,
this.icon,
this.size = AvatarSize.medium,
this.shape = AvatarShape.circle,
this.variant = AvatarVariant.standard,
this.backgroundColor,
this.foregroundColor,
this.gradient,
this.onTap,
this.badge,
this.showOnlineStatus = false,
this.isOnline = false,
this.overlay,
this.animated = true,
this.customShadow,
this.border,
});
@override
State<SophisticatedAvatar> createState() => _SophisticatedAvatarState();
}
class _SophisticatedAvatarState extends State<SophisticatedAvatar>
with SingleTickerProviderStateMixin {
late AnimationController _animationController;
late Animation<double> _scaleAnimation;
late Animation<double> _rotationAnimation;
@override
void initState() {
super.initState();
_animationController = AnimationController(
duration: const Duration(milliseconds: 300),
vsync: this,
);
_scaleAnimation = Tween<double>(
begin: 1.0,
end: 0.95,
).animate(CurvedAnimation(
parent: _animationController,
curve: Curves.easeInOut,
));
_rotationAnimation = Tween<double>(
begin: 0.0,
end: 0.1,
).animate(CurvedAnimation(
parent: _animationController,
curve: Curves.easeInOut,
));
}
@override
void dispose() {
_animationController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
final size = _getSize();
final borderRadius = _getBorderRadius(size);
Widget avatar = AnimatedBuilder(
animation: _animationController,
builder: (context, child) {
return Transform.scale(
scale: widget.animated ? _scaleAnimation.value : 1.0,
child: Transform.rotate(
angle: widget.animated ? _rotationAnimation.value : 0.0,
child: Container(
width: size,
height: size,
decoration: _getDecoration(size, borderRadius),
child: ClipRRect(
borderRadius: borderRadius,
child: Stack(
fit: StackFit.expand,
children: [
_buildContent(),
if (widget.overlay != null) widget.overlay!,
],
),
),
),
),
);
},
);
// Wrap with gesture detector if onTap is provided
if (widget.onTap != null) {
avatar = GestureDetector(
onTap: widget.onTap,
onTapDown: widget.animated ? (_) => _animationController.forward() : null,
onTapUp: widget.animated ? (_) => _animationController.reverse() : null,
onTapCancel: widget.animated ? () => _animationController.reverse() : null,
child: avatar,
);
}
// Add badges and status indicators
return Stack(
clipBehavior: Clip.none,
children: [
avatar,
// Online status indicator
if (widget.showOnlineStatus)
Positioned(
bottom: size * 0.05,
right: size * 0.05,
child: Container(
width: size * 0.25,
height: size * 0.25,
decoration: BoxDecoration(
color: widget.isOnline ? AppTheme.successColor : AppTheme.textHint,
shape: BoxShape.circle,
border: Border.all(
color: Colors.white,
width: size * 0.02,
),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.2),
blurRadius: 4,
offset: const Offset(0, 2),
),
],
),
),
),
// Custom badge
if (widget.badge != null)
Positioned(
top: -size * 0.1,
right: -size * 0.1,
child: widget.badge!,
),
],
);
}
double _getSize() {
switch (widget.size) {
case AvatarSize.tiny:
return 24;
case AvatarSize.small:
return 32;
case AvatarSize.medium:
return 48;
case AvatarSize.large:
return 64;
case AvatarSize.extraLarge:
return 96;
}
}
BorderRadius _getBorderRadius(double size) {
switch (widget.shape) {
case AvatarShape.circle:
return BorderRadius.circular(size / 2);
case AvatarShape.rounded:
return BorderRadius.circular(size * 0.2);
case AvatarShape.square:
return BorderRadius.zero;
}
}
double _getFontSize() {
switch (widget.size) {
case AvatarSize.tiny:
return 10;
case AvatarSize.small:
return 12;
case AvatarSize.medium:
return 18;
case AvatarSize.large:
return 24;
case AvatarSize.extraLarge:
return 36;
}
}
double _getIconSize() {
switch (widget.size) {
case AvatarSize.tiny:
return 12;
case AvatarSize.small:
return 16;
case AvatarSize.medium:
return 24;
case AvatarSize.large:
return 32;
case AvatarSize.extraLarge:
return 48;
}
}
Decoration _getDecoration(double size, BorderRadius borderRadius) {
switch (widget.variant) {
case AvatarVariant.standard:
return BoxDecoration(
color: widget.backgroundColor ?? AppTheme.primaryColor,
borderRadius: borderRadius,
border: widget.border,
boxShadow: widget.customShadow ?? [
BoxShadow(
color: Colors.black.withOpacity(0.1),
blurRadius: 8,
offset: const Offset(0, 4),
),
],
);
case AvatarVariant.gradient:
return BoxDecoration(
gradient: widget.gradient ?? LinearGradient(
colors: [
widget.backgroundColor ?? AppTheme.primaryColor,
(widget.backgroundColor ?? AppTheme.primaryColor).withOpacity(0.7),
],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
),
borderRadius: borderRadius,
border: widget.border,
boxShadow: [
BoxShadow(
color: (widget.backgroundColor ?? AppTheme.primaryColor)
.withOpacity(0.3),
blurRadius: 12,
offset: const Offset(0, 6),
),
],
);
case AvatarVariant.outlined:
return BoxDecoration(
color: Colors.transparent,
borderRadius: borderRadius,
border: widget.border ?? Border.all(
color: widget.backgroundColor ?? AppTheme.primaryColor,
width: 2,
),
);
case AvatarVariant.glass:
return BoxDecoration(
color: (widget.backgroundColor ?? Colors.white).withOpacity(0.2),
borderRadius: borderRadius,
border: Border.all(
color: Colors.white.withOpacity(0.3),
width: 1,
),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.1),
blurRadius: 20,
offset: const Offset(0, 8),
),
],
);
}
}
Widget _buildContent() {
final foregroundColor = widget.foregroundColor ?? Colors.white;
if (widget.imageUrl != null && widget.imageUrl!.isNotEmpty) {
return Image.network(
widget.imageUrl!,
fit: BoxFit.cover,
errorBuilder: (context, error, stackTrace) => _buildFallback(foregroundColor),
);
}
return _buildFallback(foregroundColor);
}
Widget _buildFallback(Color foregroundColor) {
if (widget.initials != null && widget.initials!.isNotEmpty) {
return Center(
child: Text(
widget.initials!.toUpperCase(),
style: TextStyle(
color: foregroundColor,
fontSize: _getFontSize(),
fontWeight: FontWeight.bold,
),
),
);
}
if (widget.icon != null) {
return Center(
child: Icon(
widget.icon,
color: foregroundColor,
size: _getIconSize(),
),
);
}
return Center(
child: Icon(
Icons.person,
color: foregroundColor,
size: _getIconSize(),
),
);
}
}
// Predefined avatar variants
class CircleAvatar extends SophisticatedAvatar {
const CircleAvatar({
super.key,
super.imageUrl,
super.initials,
super.icon,
super.size,
super.backgroundColor,
super.foregroundColor,
super.onTap,
super.badge,
super.showOnlineStatus,
super.isOnline,
}) : super(shape: AvatarShape.circle);
}
class RoundedAvatar extends SophisticatedAvatar {
const RoundedAvatar({
super.key,
super.imageUrl,
super.initials,
super.icon,
super.size,
super.backgroundColor,
super.foregroundColor,
super.onTap,
super.badge,
}) : super(shape: AvatarShape.rounded);
}
class GradientAvatar extends SophisticatedAvatar {
const GradientAvatar({
super.key,
super.imageUrl,
super.initials,
super.icon,
super.size,
super.gradient,
super.onTap,
super.badge,
super.showOnlineStatus,
super.isOnline,
}) : super(variant: AvatarVariant.gradient);
}