import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import '../../../../shared/theme/app_theme.dart'; import '../../../../core/utils/responsive_utils.dart'; class ClickableKPICard extends StatefulWidget { final String title; final String value; final String change; final IconData icon; final Color color; final bool isPositiveChange; final VoidCallback? onTap; final String? actionText; const ClickableKPICard({ super.key, required this.title, required this.value, required this.change, required this.icon, required this.color, this.isPositiveChange = true, this.onTap, this.actionText, }); @override State createState() => _ClickableKPICardState(); } class _ClickableKPICardState extends State with SingleTickerProviderStateMixin { late AnimationController _animationController; late Animation _scaleAnimation; @override void initState() { super.initState(); _animationController = AnimationController( duration: const Duration(milliseconds: 150), vsync: this, ); _scaleAnimation = Tween( begin: 1.0, end: 0.95, ).animate(CurvedAnimation( parent: _animationController, curve: Curves.easeInOut, )); } @override void dispose() { _animationController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { // Initialiser ResponsiveUtils ResponsiveUtils.init(context); return AnimatedBuilder( animation: _scaleAnimation, builder: (context, child) { return Transform.scale( scale: _scaleAnimation.value, child: Material( color: Colors.transparent, child: InkWell( onTap: widget.onTap != null ? _handleTap : null, onTapDown: widget.onTap != null ? (_) => _animationController.forward() : null, onTapUp: widget.onTap != null ? (_) => _animationController.reverse() : null, onTapCancel: widget.onTap != null ? () => _animationController.reverse() : null, borderRadius: ResponsiveUtils.borderRadius(4), child: Container( padding: ResponsiveUtils.paddingAll(5), decoration: BoxDecoration( color: Colors.white, borderRadius: ResponsiveUtils.borderRadius(4), border: widget.onTap != null ? Border.all( color: widget.color.withOpacity(0.2), width: ResponsiveUtils.adaptive( small: 1, medium: 1.5, large: 2, ), ) : null, boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.08), blurRadius: 3.5.sp, offset: Offset(0, 1.hp), ), ], ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, children: [ // IcĂ´ne et indicateur de changement Flexible( child: Row( children: [ Container( padding: ResponsiveUtils.paddingAll(2.5), decoration: BoxDecoration( color: widget.color.withOpacity(0.15), borderRadius: ResponsiveUtils.borderRadius(2.5), ), child: Icon( widget.icon, color: widget.color, size: ResponsiveUtils.iconSize(5), ), ), const Spacer(), _buildChangeIndicator(), ], ), ), SizedBox(height: 2.hp), // Valeur principale Flexible( child: Text( widget.value, style: TextStyle( fontSize: ResponsiveUtils.adaptive( small: 4.5.fs, medium: 4.2.fs, large: 4.fs, ), fontWeight: FontWeight.bold, color: AppTheme.textPrimary, ), maxLines: 1, overflow: TextOverflow.ellipsis, ), ), SizedBox(height: 0.5.hp), // Titre et action Flexible( child: Row( children: [ Expanded( child: Text( widget.title, style: TextStyle( fontSize: ResponsiveUtils.adaptive( small: 3.fs, medium: 2.8.fs, large: 2.6.fs, ), color: AppTheme.textSecondary, fontWeight: FontWeight.w500, ), maxLines: 1, overflow: TextOverflow.ellipsis, ), ), if (widget.onTap != null) ...[ SizedBox(width: 1.5.wp), Flexible( child: Container( padding: ResponsiveUtils.paddingSymmetric( horizontal: 1.5, vertical: 0.3, ), decoration: BoxDecoration( color: widget.color.withOpacity(0.1), borderRadius: ResponsiveUtils.borderRadius(2.5), ), child: Row( mainAxisSize: MainAxisSize.min, children: [ Text( widget.actionText ?? 'Voir', style: TextStyle( color: widget.color, fontSize: 2.5.fs, fontWeight: FontWeight.w600, ), ), SizedBox(width: 0.5.wp), Icon( Icons.arrow_forward_ios, size: ResponsiveUtils.iconSize(2), color: widget.color, ), ], ), ), ), ], ], ), ), ], ), ), ), ), ); }, ); } Widget _buildChangeIndicator() { final changeColor = widget.isPositiveChange ? AppTheme.successColor : AppTheme.errorColor; final changeIcon = widget.isPositiveChange ? Icons.trending_up : Icons.trending_down; return Container( padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 6), decoration: BoxDecoration( color: changeColor.withOpacity(0.1), borderRadius: BorderRadius.circular(20), ), child: Row( mainAxisSize: MainAxisSize.min, children: [ Icon( changeIcon, size: 16, color: changeColor, ), const SizedBox(width: 4), Text( widget.change, style: TextStyle( color: changeColor, fontSize: 14, fontWeight: FontWeight.w600, ), ), ], ), ); } void _handleTap() { HapticFeedback.lightImpact(); widget.onTap?.call(); } }