import 'package:flutter/material.dart'; import 'dart:ui'; /// Widget d'overlay de chargement amélioré qui affiche une barre de progression /// avec un effet de flou sur l'arrière-plan et un message détaillé sur l'étape en cours class LoadingProgressOverlay extends StatefulWidget { final String? message; final double progress; final String? stepDescription; final Color backgroundColor; final Color progressColor; final Color textColor; final double blurAmount; final bool showPercentage; const LoadingProgressOverlay({ Key? key, this.message, required this.progress, this.stepDescription, this.backgroundColor = Colors.black54, this.progressColor = Colors.white, this.textColor = Colors.white, this.blurAmount = 5.0, this.showPercentage = true, }) : super(key: key); @override State createState() => _LoadingProgressOverlayState(); } class _LoadingProgressOverlayState extends State with SingleTickerProviderStateMixin { late AnimationController _animationController; late Animation _progressAnimation; @override void initState() { super.initState(); _animationController = AnimationController( vsync: this, duration: const Duration(milliseconds: 300), ); _progressAnimation = Tween(begin: 0, end: widget.progress).animate( CurvedAnimation(parent: _animationController, curve: Curves.easeInOut), ); _animationController.forward(); } @override void didUpdateWidget(LoadingProgressOverlay oldWidget) { super.didUpdateWidget(oldWidget); if (oldWidget.progress != widget.progress) { _progressAnimation = Tween( begin: oldWidget.progress, end: widget.progress, ).animate( CurvedAnimation(parent: _animationController, curve: Curves.easeInOut), ); _animationController.reset(); _animationController.forward(); } } @override void dispose() { _animationController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return BackdropFilter( filter: ImageFilter.blur( sigmaX: widget.blurAmount, sigmaY: widget.blurAmount), child: Container( color: widget.backgroundColor, child: Center( child: Container( width: MediaQuery.of(context).size.width * 0.85, padding: const EdgeInsets.all(30), decoration: BoxDecoration( color: Colors.black.withOpacity(0.9), borderRadius: BorderRadius.circular(20), boxShadow: [ BoxShadow( color: Colors.black45, blurRadius: 15, spreadRadius: 5, offset: const Offset(0, 5), ), ], border: Border.all( color: Colors.white.withOpacity(0.1), width: 1.5, ), ), child: Column( mainAxisSize: MainAxisSize.min, children: [ if (widget.message != null) ...[ Text( widget.message!, style: TextStyle( fontSize: 22, fontWeight: FontWeight.bold, color: widget.textColor, letterSpacing: 0.5, ), textAlign: TextAlign.center, ), const SizedBox(height: 24), ], AnimatedBuilder( animation: _progressAnimation, builder: (context, child) { return Column( children: [ LinearProgressIndicator( value: _progressAnimation.value, backgroundColor: widget.progressColor.withOpacity(0.3), valueColor: AlwaysStoppedAnimation( widget.progressColor), minHeight: 15, borderRadius: BorderRadius.circular(8), ), if (widget.showPercentage) ...[ const SizedBox(height: 8), Text( '${(_progressAnimation.value * 100).toInt()}%', style: TextStyle( fontSize: 20, fontWeight: FontWeight.bold, color: widget.textColor, letterSpacing: 1.2, ), ), ], ], ); }, ), if (widget.stepDescription != null) ...[ const SizedBox(height: 16), Text( widget.stepDescription!, style: TextStyle( fontSize: 16, color: widget.textColor.withOpacity(0.9), fontStyle: FontStyle.italic, ), textAlign: TextAlign.center, ), ], ], ), ), ), ), ); } } /// Classe utilitaire pour gérer l'overlay de chargement avec progression class LoadingProgressOverlayUtils { /// Méthode pour afficher l'overlay de chargement avec progression static OverlayEntry show({ required BuildContext context, String? message, double progress = 0.0, String? stepDescription, double blurAmount = 5.0, bool showPercentage = true, }) { final overlayEntry = OverlayEntry( builder: (context) => LoadingProgressOverlay( message: message, progress: progress, stepDescription: stepDescription, blurAmount: blurAmount, showPercentage: showPercentage, ), ); Overlay.of(context).insert(overlayEntry); return overlayEntry; } /// Méthode pour mettre à jour l'overlay existant static void update({ required OverlayEntry overlayEntry, String? message, required double progress, String? stepDescription, }) { overlayEntry.markNeedsBuild(); } }