import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; /// Enhanced card widget with interactive animations class InteractiveCard extends StatefulWidget { final Widget child; final VoidCallback? onTap; final VoidCallback? onLongPress; final EdgeInsets? padding; final EdgeInsets? margin; final Color? backgroundColor; final double? elevation; final BorderRadius? borderRadius; final bool enableHoverEffect; final bool enableRipple; final Duration animationDuration; final Color? splashColor; final Color? highlightColor; const InteractiveCard({ super.key, required this.child, this.onTap, this.onLongPress, this.padding, this.margin, this.backgroundColor, this.elevation, this.borderRadius, this.enableHoverEffect = true, this.enableRipple = true, this.animationDuration = const Duration(milliseconds: 200), this.splashColor, this.highlightColor, }); @override State createState() => _InteractiveCardState(); } class _InteractiveCardState extends State with SingleTickerProviderStateMixin { late AnimationController _controller; late Animation _scaleAnimation; late Animation _elevationAnimation; bool _isPressed = false; @override void initState() { super.initState(); _controller = AnimationController( vsync: this, duration: widget.animationDuration, ); _scaleAnimation = Tween( begin: 1.0, end: 0.98, ).animate( CurvedAnimation(parent: _controller, curve: Curves.easeInOut), ); _elevationAnimation = Tween( begin: widget.elevation ?? 2.0, end: (widget.elevation ?? 2.0) + 4.0, ).animate( CurvedAnimation(parent: _controller, curve: Curves.easeInOut), ); } @override void dispose() { _controller.dispose(); super.dispose(); } void _handleTapDown(TapDownDetails details) { if (widget.onTap != null) { setState(() => _isPressed = true); _controller.forward(); } } void _handleTapUp(TapUpDetails details) { if (widget.onTap != null) { setState(() => _isPressed = false); _controller.reverse(); } } void _handleTapCancel() { if (widget.onTap != null) { setState(() => _isPressed = false); _controller.reverse(); } } @override Widget build(BuildContext context) { return AnimatedBuilder( animation: _controller, builder: (context, child) { return Transform.scale( scale: _scaleAnimation.value, child: Card( elevation: widget.enableHoverEffect && _isPressed ? _elevationAnimation.value : widget.elevation ?? 2.0, color: widget.backgroundColor, margin: widget.margin ?? EdgeInsets.symmetric(horizontal: 8.w, vertical: 4.h), shape: RoundedRectangleBorder( borderRadius: widget.borderRadius ?? BorderRadius.circular(16.r), ), child: Material( color: Colors.transparent, borderRadius: widget.borderRadius ?? BorderRadius.circular(16.r), child: InkWell( onTap: widget.onTap, onLongPress: widget.onLongPress, onTapDown: _handleTapDown, onTapUp: _handleTapUp, onTapCancel: _handleTapCancel, borderRadius: widget.borderRadius ?? BorderRadius.circular(16.r), splashColor: widget.splashColor ?? Theme.of(context).primaryColor.withOpacity(0.1), highlightColor: widget.highlightColor ?? Colors.transparent, enableFeedback: true, child: Padding( padding: widget.padding ?? EdgeInsets.all(16.w), child: child, ), ), ), ), ); }, child: widget.child, ); } } /// Stats card with interactive hover effect class InteractiveStatsCard extends StatelessWidget { final String title; final String value; final IconData icon; final Color color; final VoidCallback? onTap; final String? subtitle; final Widget? trailing; const InteractiveStatsCard({ super.key, required this.title, required this.value, required this.icon, required this.color, this.onTap, this.subtitle, this.trailing, }); @override Widget build(BuildContext context) { return InteractiveCard( onTap: onTap, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Container( padding: EdgeInsets.all(10.w), decoration: BoxDecoration( color: color.withOpacity(0.1), borderRadius: BorderRadius.circular(12.r), ), child: Icon( icon, color: color, size: 24.w, ), ), trailing ?? Icon( Icons.trending_up, color: Colors.green.shade600, size: 20.w, ), ], ), SizedBox(height: 12.h), Text( value, style: TextStyle( fontSize: 24.sp, fontWeight: FontWeight.bold, color: Colors.grey.shade800, ), ), SizedBox(height: 4.h), Text( title, style: TextStyle( fontSize: 14.sp, color: Colors.grey.shade600, ), overflow: TextOverflow.ellipsis, ), if (subtitle != null) ...[ SizedBox(height: 4.h), Text( subtitle!, style: TextStyle( fontSize: 12.sp, color: Colors.grey.shade500, ), overflow: TextOverflow.ellipsis, ), ], ], ), ); } } /// Quick action button card with icon class QuickActionCard extends StatelessWidget { final String title; final IconData icon; final Color color; final VoidCallback onTap; final String? subtitle; const QuickActionCard({ super.key, required this.title, required this.icon, required this.color, required this.onTap, this.subtitle, }); @override Widget build(BuildContext context) { return InteractiveCard( onTap: onTap, padding: EdgeInsets.symmetric(vertical: 16.h, horizontal: 16.w), margin: EdgeInsets.symmetric(vertical: 4.h), child: Row( children: [ Container( padding: EdgeInsets.all(12.w), decoration: BoxDecoration( color: color.withOpacity(0.1), borderRadius: BorderRadius.circular(12.r), ), child: Icon( icon, color: color, size: 24.w, ), ), SizedBox(width: 16.w), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( title, style: TextStyle( fontSize: 16.sp, fontWeight: FontWeight.w600, color: Colors.grey.shade800, ), ), if (subtitle != null) ...[ SizedBox(height: 2.h), Text( subtitle!, style: TextStyle( fontSize: 13.sp, color: Colors.grey.shade600, ), ), ], ], ), ), Icon( Icons.arrow_forward_ios_rounded, size: 16.w, color: Colors.grey.shade400, ), ], ), ); } } /// Activity card with timeline indicator class ActivityCard extends StatelessWidget { final String title; final String description; final String time; final IconData icon; final Color color; final VoidCallback? onTap; const ActivityCard({ super.key, required this.title, required this.description, required this.time, required this.icon, required this.color, this.onTap, }); @override Widget build(BuildContext context) { return InteractiveCard( onTap: onTap, padding: EdgeInsets.all(16.w), margin: EdgeInsets.symmetric(vertical: 6.h, horizontal: 0), child: Row( children: [ Container( padding: EdgeInsets.all(12.w), decoration: BoxDecoration( color: color.withOpacity(0.1), borderRadius: BorderRadius.circular(12.r), ), child: Icon( icon, color: color, size: 20.w, ), ), SizedBox(width: 16.w), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( title, style: TextStyle( fontSize: 16.sp, fontWeight: FontWeight.w600, color: Colors.grey.shade800, ), ), SizedBox(height: 4.h), Text( description, style: TextStyle( fontSize: 14.sp, color: Colors.grey.shade600, ), maxLines: 2, overflow: TextOverflow.ellipsis, ), ], ), ), SizedBox(width: 12.w), Text( time, style: TextStyle( fontSize: 12.sp, color: Colors.grey.shade500, fontWeight: FontWeight.w500, ), ), ], ), ); } }