306 lines
10 KiB
Dart
306 lines
10 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:flutter/services.dart';
|
|
import '../../../../shared/theme/app_theme.dart';
|
|
|
|
class SplashScreen extends StatefulWidget {
|
|
const SplashScreen({super.key});
|
|
|
|
@override
|
|
State<SplashScreen> createState() => _SplashScreenState();
|
|
}
|
|
|
|
class _SplashScreenState extends State<SplashScreen>
|
|
with TickerProviderStateMixin {
|
|
late AnimationController _logoController;
|
|
late AnimationController _progressController;
|
|
late AnimationController _textController;
|
|
|
|
late Animation<double> _logoScaleAnimation;
|
|
late Animation<double> _logoOpacityAnimation;
|
|
late Animation<double> _progressAnimation;
|
|
late Animation<double> _textOpacityAnimation;
|
|
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
_initializeAnimations();
|
|
_startSplashSequence();
|
|
}
|
|
|
|
void _initializeAnimations() {
|
|
// Animation du logo
|
|
_logoController = AnimationController(
|
|
duration: const Duration(milliseconds: 1000),
|
|
vsync: this,
|
|
);
|
|
|
|
_logoScaleAnimation = Tween<double>(
|
|
begin: 0.5,
|
|
end: 1.0,
|
|
).animate(CurvedAnimation(
|
|
parent: _logoController,
|
|
curve: Curves.elasticOut,
|
|
));
|
|
|
|
_logoOpacityAnimation = Tween<double>(
|
|
begin: 0.0,
|
|
end: 1.0,
|
|
).animate(CurvedAnimation(
|
|
parent: _logoController,
|
|
curve: const Interval(0.0, 0.6, curve: Curves.easeIn),
|
|
));
|
|
|
|
// Animation de la barre de progression
|
|
_progressController = AnimationController(
|
|
duration: const Duration(milliseconds: 2000),
|
|
vsync: this,
|
|
);
|
|
|
|
_progressAnimation = Tween<double>(
|
|
begin: 0.0,
|
|
end: 1.0,
|
|
).animate(CurvedAnimation(
|
|
parent: _progressController,
|
|
curve: Curves.easeInOut,
|
|
));
|
|
|
|
// Animation du texte
|
|
_textController = AnimationController(
|
|
duration: const Duration(milliseconds: 800),
|
|
vsync: this,
|
|
);
|
|
|
|
_textOpacityAnimation = Tween<double>(
|
|
begin: 0.0,
|
|
end: 1.0,
|
|
).animate(CurvedAnimation(
|
|
parent: _textController,
|
|
curve: Curves.easeIn,
|
|
));
|
|
}
|
|
|
|
void _startSplashSequence() async {
|
|
// Configuration de la barre de statut
|
|
SystemChrome.setSystemUIOverlayStyle(
|
|
const SystemUiOverlayStyle(
|
|
statusBarColor: Colors.transparent,
|
|
statusBarIconBrightness: Brightness.light,
|
|
),
|
|
);
|
|
|
|
// Séquence d'animations avec vérification mounted
|
|
await Future.delayed(const Duration(milliseconds: 300));
|
|
if (mounted) _logoController.forward();
|
|
|
|
await Future.delayed(const Duration(milliseconds: 500));
|
|
if (mounted) _textController.forward();
|
|
|
|
await Future.delayed(const Duration(milliseconds: 300));
|
|
if (mounted) _progressController.forward();
|
|
|
|
// Attendre la fin de toutes les animations + temps de chargement
|
|
await Future.delayed(const Duration(milliseconds: 2000));
|
|
|
|
// Le splash screen sera remplacé automatiquement par l'AppWrapper
|
|
// basé sur l'état d'authentification
|
|
}
|
|
|
|
@override
|
|
void dispose() {
|
|
_logoController.dispose();
|
|
_progressController.dispose();
|
|
_textController.dispose();
|
|
super.dispose();
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Scaffold(
|
|
body: Container(
|
|
decoration: BoxDecoration(
|
|
gradient: LinearGradient(
|
|
begin: Alignment.topLeft,
|
|
end: Alignment.bottomRight,
|
|
colors: [
|
|
AppTheme.primaryColor,
|
|
AppTheme.primaryDark,
|
|
const Color(0xFF0D47A1),
|
|
],
|
|
),
|
|
),
|
|
child: SafeArea(
|
|
child: Column(
|
|
children: [
|
|
Expanded(
|
|
flex: 3,
|
|
child: Center(
|
|
child: Column(
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
children: [
|
|
// Logo animé
|
|
AnimatedBuilder(
|
|
animation: _logoController,
|
|
builder: (context, child) {
|
|
return Transform.scale(
|
|
scale: _logoScaleAnimation.value,
|
|
child: Opacity(
|
|
opacity: _logoOpacityAnimation.value,
|
|
child: Container(
|
|
width: 120,
|
|
height: 120,
|
|
decoration: BoxDecoration(
|
|
color: Colors.white,
|
|
borderRadius: BorderRadius.circular(30),
|
|
boxShadow: [
|
|
BoxShadow(
|
|
color: Colors.black.withOpacity(0.2),
|
|
blurRadius: 20,
|
|
offset: const Offset(0, 10),
|
|
),
|
|
],
|
|
),
|
|
child: const Icon(
|
|
Icons.groups_rounded,
|
|
size: 60,
|
|
color: AppTheme.primaryColor,
|
|
),
|
|
),
|
|
),
|
|
);
|
|
},
|
|
),
|
|
|
|
const SizedBox(height: 32),
|
|
|
|
// Titre animé
|
|
AnimatedBuilder(
|
|
animation: _textController,
|
|
builder: (context, child) {
|
|
return Opacity(
|
|
opacity: _textOpacityAnimation.value,
|
|
child: Column(
|
|
children: [
|
|
const Text(
|
|
'UnionFlow',
|
|
style: TextStyle(
|
|
fontSize: 36,
|
|
fontWeight: FontWeight.bold,
|
|
color: Colors.white,
|
|
letterSpacing: 1.2,
|
|
),
|
|
),
|
|
const SizedBox(height: 8),
|
|
Text(
|
|
'Gestion d\'associations professionnelle',
|
|
style: TextStyle(
|
|
fontSize: 16,
|
|
color: Colors.white.withOpacity(0.9),
|
|
fontWeight: FontWeight.w300,
|
|
),
|
|
textAlign: TextAlign.center,
|
|
),
|
|
],
|
|
),
|
|
);
|
|
},
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
|
|
// Section de chargement
|
|
Expanded(
|
|
flex: 1,
|
|
child: Column(
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
children: [
|
|
// Barre de progression animée
|
|
Container(
|
|
width: 200,
|
|
margin: const EdgeInsets.symmetric(horizontal: 40),
|
|
child: Column(
|
|
children: [
|
|
AnimatedBuilder(
|
|
animation: _progressController,
|
|
builder: (context, child) {
|
|
return LinearProgressIndicator(
|
|
value: _progressAnimation.value,
|
|
backgroundColor: Colors.white.withOpacity(0.2),
|
|
valueColor: const AlwaysStoppedAnimation<Color>(
|
|
Colors.white,
|
|
),
|
|
minHeight: 3,
|
|
);
|
|
},
|
|
),
|
|
const SizedBox(height: 16),
|
|
AnimatedBuilder(
|
|
animation: _progressController,
|
|
builder: (context, child) {
|
|
return Text(
|
|
'${(_progressAnimation.value * 100).toInt()}%',
|
|
style: TextStyle(
|
|
color: Colors.white.withOpacity(0.8),
|
|
fontSize: 14,
|
|
fontWeight: FontWeight.w500,
|
|
),
|
|
);
|
|
},
|
|
),
|
|
],
|
|
),
|
|
),
|
|
|
|
const SizedBox(height: 24),
|
|
|
|
// Texte de chargement
|
|
AnimatedBuilder(
|
|
animation: _textController,
|
|
builder: (context, child) {
|
|
return Opacity(
|
|
opacity: _textOpacityAnimation.value,
|
|
child: Text(
|
|
'Initialisation...',
|
|
style: TextStyle(
|
|
color: Colors.white.withOpacity(0.7),
|
|
fontSize: 14,
|
|
),
|
|
),
|
|
);
|
|
},
|
|
),
|
|
],
|
|
),
|
|
),
|
|
|
|
// Footer
|
|
Padding(
|
|
padding: const EdgeInsets.only(bottom: 40),
|
|
child: Column(
|
|
children: [
|
|
Text(
|
|
'Version 1.0.0',
|
|
style: TextStyle(
|
|
color: Colors.white.withOpacity(0.6),
|
|
fontSize: 12,
|
|
),
|
|
),
|
|
const SizedBox(height: 8),
|
|
Text(
|
|
'© 2024 Lions Club International',
|
|
style: TextStyle(
|
|
color: Colors.white.withOpacity(0.5),
|
|
fontSize: 10,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
} |