Projet

Author: dada566Created Sep 23, 2025Updated Sep 23, 2025

import 'package:flutter/material.dart'; import 'dart:math' as math;

class AnalysesPage extends StatefulWidget { const AnalysesPage({super.key});

@override State createState() => _AnalysesPageState(); }

class _AnalysesPageState extends State with TickerProviderStateMixin { late AnimationController _gradientController; late AnimationController _cardAnimationController; late AnimationController _chartAnimationController; late AnimationController _tableAnimationController; late AnimationController _kpiAnimationController;

late Animation _cardSlideAnimation; late Animation _chartScaleAnimation; late Animation _tableOpacityAnimation; late Animation _kpiCounterAnimation;

String _selectedPeriod = 'Année en cours'; String _selectedAnalysisType = 'Vue d'ensemble'; String _selectedSector = '';

final List _periods = ['Année en cours', 'Trimestre', 'Semestre', 'Législature']; final List _analysisTypes = ['Vue d'ensemble', 'Efficacité législative', 'Participation', 'Thématiques', 'Tendances'];

@override void initState() { super.initState();

_gradientController = AnimationController(
  duration: const Duration(seconds: 8),
  vsync: this,
)..repeat();

_cardAnimationController = AnimationController(
  duration: const Duration(milliseconds: 1200),
  vsync: this,
);

_chartAnimationController = AnimationController(
  duration: const Duration(milliseconds: 1800),
  vsync: this,
);

_tableAnimationController = AnimationController(
  duration: const Duration(milliseconds: 900),
  vsync: this,
);

_kpiAnimationController = AnimationController(
  duration: const Duration(milliseconds: 2000),
  vsync: this,
);

_setupAnimations();

WidgetsBinding.instance.addPostFrameCallback((_) {
  _cardAnimationController.forward();
  _chartAnimationController.forward();
  _tableAnimationController.forward();
  _kpiAnimationController.forward();
});

}

void _setupAnimations() { _cardSlideAnimation = Tween(begin: 0.0, end: 1.0).animate( CurvedAnimation( parent: _cardAnimationController, curve: Curves.easeOutCubic, ), );

_chartScaleAnimation = Tween<double>(begin: 0.0, end: 1.0).animate(
  CurvedAnimation(
    parent: _chartAnimationController,
    curve: Curves.elasticOut,
  ),
);

_tableOpacityAnimation = Tween<double>(begin: 0.0, end: 1.0).animate(
  CurvedAnimation(
    parent: _tableAnimationController,
    curve: Curves.easeInOut,
  ),
);

_kpiCounterAnimation = Tween<double>(begin: 0.0, end: 1.0).animate(
  CurvedAnimation(
    parent: _kpiAnimationController,
    curve: Curves.easeOutCubic,
  ),
);

}

@override void dispose() { _gradientController.dispose(); _cardAnimationController.dispose(); _chartAnimationController.dispose(); _tableAnimationController.dispose(); _kpiAnimationController.dispose(); super.dispose(); }

void _showSectorDetails(String sector, double value, Color color) { final isDark = Theme.of(context).brightness == Brightness.dark;

showDialog(
  context: context,
  builder: (BuildContext context) {
    return Dialog(
      backgroundColor: isDark ? const Color(0xFF1E1E48) : Colors.white,
      shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)),
      child: Container(
        width: 400,
        padding: const EdgeInsets.all(24),
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            Row(
              children: [
                Container(
                  padding: const EdgeInsets.all(12),
                  decoration: BoxDecoration(
                    color: color.withOpacity(0.1),
                    borderRadius: BorderRadius.circular(12),
                  ),
                  child: Icon(Icons.analytics, color: color, size: 24),
                ),
                const SizedBox(width: 16),
                Expanded(
                  child: Column(
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: [
                      Text(
                        'Analyse - $sector',
                        style: TextStyle(
                          fontSize: 18,
                          fontWeight: FontWeight.bold,
                          color: isDark ? Colors.white : Colors.black,
                        ),
                      ),
                      Text(
                        'Efficacité: ${(value * 100).toInt()}%',
                        style: TextStyle(
                          fontSize: 14,
                          color: color,
                          fontWeight: FontWeight.w600,
                        ),
                      ),
                    ],
                  ),
                ),
              ],
            ),
            const SizedBox(height: 20),
            
            _buildDetailRow('Projets déposés', '${(value * 45).toInt()}', Icons.description),
            _buildDetailRow('Projets adoptés', '${(value * 32).toInt()}', Icons.check_circle),
            _buildDetailRow('Temps moyen', '${(value * 6.5).toStringAsFixed(1)} jours', Icons.schedule),
            _buildDetailRow('Amendements', '${(value * 156).toInt()}', Icons.edit),
            
            const SizedBox(height: 24),
            Row(
              children: [
                Expanded(
                  child: ElevatedButton(
                    onPressed: () => Navigator.pop(context),
                    style: ElevatedButton.styleFrom(
                      backgroundColor: Colors.grey[300],
                      foregroundColor: Colors.black,
                      shape: RoundedRectangleBorder(
                        borderRadius: BorderRadius.circular(12),
                      ),
                    ),
                    child: const Text('Fermer'),
                  ),
                ),
                const SizedBox(width: 12),
                Expanded(
                  child: ElevatedButton(
                    onPressed: () {
                      Navigator.pop(context);
                      setState(() {
                        _selectedSector = sector;
                      });
                    },
                    style: ElevatedButton.styleFrom(
                      backgroundColor: color,
                      foregroundColor: Colors.white,
                      shape: RoundedRectangleBorder(
                        borderRadius: BorderRadius.circular(12),
                      ),
                    ),
                    child: const Text('Détails complets'),
                  ),
                ),
              ],
            ),
          ],
        ),
      ),
    );
  },
);

}

Widget _buildDetailRow(String label, String value, IconData icon) { final isDark = Theme.of(context).brightness == Brightness.dark;

return Padding(
  padding: const EdgeInsets.symmetric(vertical: 8),
  child: Row(
    children: [
      Icon(icon, size: 20, color: isDark ? Colors.white70 : Colors.grey[600]),
      const SizedBox(width: 12),
      Expanded(
        child: Text(
          label,
          style: TextStyle(
            fontSize: 14,
            color: isDark ? Colors.white70 : Colors.grey[700],
          ),
        ),
      ),
      Text(
        value,
        style: TextStyle(
          fontSize: 14,
          fontWeight: FontWeight.bold,
          color: isDark ? Colors.white : Colors.black,
        ),
      ),
    ],
  ),
);

}

void _showKpiDetails(String title, String value, String description) { final isDark = Theme.of(context).brightness == Brightness.dark;

showDialog(
  context: context,
  builder: (BuildContext context) {
    return Dialog(
      backgroundColor: isDark ? const Color(0xFF1E1E48) : Colors.white,
      shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)),
      child: Padding(
        padding: const EdgeInsets.all(24),
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            Text(
              title,
              style: TextStyle(
                fontSize: 20,
                fontWeight: FontWeight.bold,
                color: isDark ? Colors.white : Colors.black,
              ),
            ),
            const SizedBox(height: 16),
            Text(
              value,
              style: const TextStyle(
                fontSize: 32,
                fontWeight: FontWeight.bold,
                color: Color(0xFF6366F1),
              ),
            ),
            const SizedBox(height: 12),
            Text(
              description,
              textAlign: TextAlign.center,
              style: TextStyle(
                fontSize: 16,
                color: isDark ? Colors.white70 : Colors.grey[600],
              ),
            ),
            const SizedBox(height: 24),
            ElevatedButton(
              onPressed: () => Navigator.pop(context),
              style: ElevatedButton.styleFrom(
                backgroundColor: const Color(0xFF6366F1),
                foregroundColor: Colors.white,
                shape: RoundedRectangleBorder(
                  borderRadius: BorderRadius.circular(12),
                ),
              ),
              child: const Text('Fermer'),
            ),
          ],
        ),
      ),
    );
  },
);

}

Widget _buildKpiCard(String title, String value, String subtitle, IconData icon, Color color, double targetValue, int index) { final isDark = Theme.of(context).brightness == Brightness.dark;

return AnimatedBuilder(
  animation: _kpiAnimationController,
  builder: (context, child) {
    final animationDelay = index * 0.2;
    final delayedAnimation = math.max(0.0, _kpiCounterAnimation.value - animationDelay);
    final displayValue = (targetValue * delayedAnimation).toInt();
    
    return Transform.translate(
      offset: Offset(0, 30 * (1 - delayedAnimation.clamp(0.0, 1.0))),
      child: Opacity(
        opacity: delayedAnimation.clamp(0.0, 1.0),
        child: MouseRegion(
          cursor: SystemMouseCursors.click,
          child: GestureDetector(
            onTap: () => _showKpiDetails(title, value, subtitle),
            child: Container(
              padding: const EdgeInsets.all(20),
              decoration: BoxDecoration(
                color: isDark ? const Color(0xFF1E1E48) : Colors.white,
                borderRadius: BorderRadius.circular(16),
                boxShadow: [
                  BoxShadow(
                    color: Colors.black.withOpacity(0.1),
                    blurRadius: 12,
                    offset: const Offset(0, 4),
                  ),
                ],
                border: Border.all(
                  color: color.withOpacity(0.3),
                  width: 1.5,
                ),
              ),
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  Row(
                    children: [
                      Container(
                        padding: const EdgeInsets.all(12),
                        decoration: BoxDecoration(
                          color: color.withOpacity(0.1),
                          borderRadius: BorderRadius.circular(12),
                        ),
                        child: Icon(icon, color: color, size: 24),
                      ),
                      const Spacer(),
                      Container(
                        padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
                        decoration: BoxDecoration(
                          color: color.withOpacity(0.1),
                          borderRadius: BorderRadius.circular(12),
                        ),
                        child: Text(
                          '+${(displayValue * 0.12).toInt()}%',
                          style: TextStyle(
                            fontSize: 12,
                            fontWeight: FontWeight.bold,
                            color: color,
                          ),
                        ),
                      ),
                    ],
                  ),
                  const SizedBox(height: 16),
                  Text(
                    displayValue.toString(),
                    style: TextStyle(
                      fontSize: 28,
                      fontWeight: FontWeight.bold,
                      color: color,
                    ),
                  ),
                  const SizedBox(height: 4),
                  Text(
                    title,
                    style: TextStyle(
                      fontSize: 16,
                      fontWeight: FontWeight.w600,
                      color: isDark ? Colors.white : Colors.black,
                    ),
                  ),
                  Text(
                    subtitle,
                    style: TextStyle(
                      fontSize: 12,
                      color: isDark ? Colors.white60 : Colors.grey[600],
                    ),
                  ),
                ],
              ),
            ),
          ),
        ),
      ),
    );
  },
);

}

Widget _buildAnalysisChart() { final isDark = Theme.of(context).brightness == Brightness.dark;

return AnimatedBuilder(
  animation: _chartAnimationController,
  builder: (context, child) {
    return Transform.scale(
      scale: _chartScaleAnimation.value.clamp(0.0, 1.0),
      child: Container(
        padding: const EdgeInsets.all(20),
        decoration: BoxDecoration(
          color: isDark ? const Color(0xFF1E1E48) : Colors.white,
          borderRadius: BorderRadius.circular(16),
          boxShadow: [
            BoxShadow(
              color: Colors.black.withOpacity(0.1),
              blurRadius: 8,
              offset: const Offset(0, 4),
            ),
          ],
        ),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Row(
              children: [
                Text(
                  'Efficacité législative par secteur',
                  style: TextStyle(
                    fontSize: 18,
                    fontWeight: FontWeight.bold,
                    color: isDark ? Colors.white : Colors.black,
                  ),
                ),
                const Spacer(),
                Container(
                  padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6),
                  decoration: BoxDecoration(
                    color: const Color(0xFF6366F1).withOpacity(0.1),
                    borderRadius: BorderRadius.circular(12),
                  ),
                  child: const Text(
                    'Données en temps réel',
                    style: TextStyle(
                      fontSize: 12,
                      color: Color(0xFF6366F1),
                      fontWeight: FontWeight.w600,
                    ),
                  ),
                ),
              ],
            ),
            const SizedBox(height: 20),
            Expanded(
              child: Row(
                children: [
                  Expanded(
                    flex: 2,
                    child: Column(
                      children: [
                        _buildClickableHorizontalBar('Économie', 0.85, const Color(0xFF6366F1)),
                        _buildClickableHorizontalBar('Justice', 0.72, const Color(0xFFF59E0B)),
                        _buildClickableHorizontalBar('Infrastructure', 0.65, const Color(0xFF10B981)),
                        _buildClickableHorizontalBar('Social', 0.58, const Color(0xFFEC4899)),
                        _buildClickableHorizontalBar('Éducation', 0.45, const Color(0xFF8B5CF6)),
                        _buildClickableHorizontalBar('Santé', 0.38, const Color(0xFF06B6D4)),
                      ],
                    ),
                  ),
                  const SizedBox(width: 20),
                  Expanded(
                    child: Column(
                      mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                      children: [
                        _buildClickableCircularIndicator('Taux adoption', 0.73, const Color(0xFF10B981)),
                        _buildClickableCircularIndicator('Temps moyen', 0.45, const Color(0xFFF59E0B)),
                        _buildClickableCircularIndicator('Qualité débats', 0.82, const Color(0xFF6366F1)),
                      ],
                    ),
                  ),
                ],
              ),
            ),
          ],
        ),
      ),
    );
  },
);

}

Widget _buildClickableHorizontalBar(String label, double value, Color color) { final isDark = Theme.of(context).brightness == Brightness.dark;

return AnimatedBuilder(
  animation: _chartAnimationController,
  builder: (context, child) {
    final animatedValue = (value * _chartScaleAnimation.value).clamp(0.0, 1.0);
    
    return MouseRegion(
      cursor: SystemMouseCursors.click,
      child: GestureDetector(
        onTap: () => _showSectorDetails(label, value, color),
        child: Container(
          margin: const EdgeInsets.symmetric(vertical: 4),
          padding: const EdgeInsets.all(8),
          decoration: BoxDecoration(
            borderRadius: BorderRadius.circular(8),
            color: _selectedSector == label 
                ? color.withOpacity(0.1) 
                : Colors.transparent,
          ),
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              Row(
                mainAxisAlignment: MainAxisAlignment.spaceBetween,
                children: [
                  Text(
                    label,
                    style: TextStyle(
                      fontSize: 14,
                      fontWeight: _selectedSector == label ? FontWeight.bold : FontWeight.w600,
                      color: _selectedSector == label 
                          ? color 
                          : (isDark ? Colors.white : Colors.black),
                    ),
                  ),
                  Text(
                    '${(value * 100).toInt()}%',

Source: Doriandarko/claude-engineer