2025-08-12 17:15:16 +07:00

174 lines
5.3 KiB
Dart

import 'package:auto_route/auto_route.dart';
import 'package:flutter/material.dart';
import '../../../common/theme/theme.dart';
import '../../components/assets/assets.gen.dart';
import '../../router/app_router.gr.dart';
@RoutePage()
class SplashPage extends StatefulWidget {
const SplashPage({super.key});
@override
State<SplashPage> createState() => _SplashPageState();
}
class _SplashPageState extends State<SplashPage> with TickerProviderStateMixin {
late AnimationController _logoController;
late AnimationController _versionController;
late AnimationController _backgroundController;
late Animation<double> _logoAnimation;
late Animation<double> _versionAnimation;
late Animation<double> _backgroundAnimation;
@override
void initState() {
super.initState();
// Initialize animation controllers
_logoController = AnimationController(
duration: const Duration(milliseconds: 1200),
vsync: this,
);
_versionController = AnimationController(
duration: const Duration(milliseconds: 800),
vsync: this,
);
_backgroundController = AnimationController(
duration: const Duration(milliseconds: 1500),
vsync: this,
);
// Create animations
_logoAnimation = Tween<double>(begin: 0.0, end: 1.0).animate(
CurvedAnimation(parent: _logoController, curve: Curves.elasticOut),
);
_versionAnimation = Tween<double>(begin: 0.0, end: 1.0).animate(
CurvedAnimation(parent: _versionController, curve: Curves.easeInOut),
);
_backgroundAnimation = Tween<double>(begin: 0.0, end: 1.0).animate(
CurvedAnimation(parent: _backgroundController, curve: Curves.easeInOut),
);
// Start animations
_startAnimations();
}
void _startAnimations() async {
// Start background animation immediately
_backgroundController.forward();
// Wait a bit, then start logo animation
await Future.delayed(const Duration(milliseconds: 300));
if (mounted) _logoController.forward();
// Start version animation after logo starts
await Future.delayed(const Duration(milliseconds: 600));
if (mounted) _versionController.forward();
// Navigate to home screen after all animations complete
await Future.delayed(const Duration(milliseconds: 2000));
if (mounted) {
_navigateToHome();
}
}
void _navigateToHome() {
// Uncomment dan sesuaikan dengan route yang ada
context.router.replace(const LoginRoute());
}
@override
void dispose() {
_logoController.dispose();
_versionController.dispose();
_backgroundController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: AnimatedBuilder(
animation: Listenable.merge([
_logoController,
_versionController,
_backgroundController,
]),
builder: (context, child) {
// Clamp values to prevent opacity errors
final logoOpacity = _logoAnimation.value.clamp(0.0, 1.0);
final versionOpacity = _versionAnimation.value.clamp(0.0, 1.0);
final backgroundOpacity = _backgroundAnimation.value.clamp(0.0, 1.0);
return Container(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [
AppColor.primaryWithOpacity(backgroundOpacity),
AppColor.primaryWithOpacity(backgroundOpacity * 0.8),
],
),
),
child: Stack(
children: [
// Logo di tengah
Center(
child: Transform.scale(
scale: logoOpacity,
child: Opacity(
opacity: logoOpacity,
child: Container(
width: 150,
height: 150,
decoration: BoxDecoration(
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.1),
blurRadius: 30,
offset: const Offset(0, 15),
),
],
),
child: ClipRRect(
borderRadius: BorderRadius.circular(AppValue.radius),
child: Assets.images.logo.image(fit: BoxFit.cover),
),
),
),
),
),
// Version di bagian bawah
Positioned(
bottom: 60,
left: 0,
right: 0,
child: Transform.translate(
offset: Offset(0, 20 * (1 - versionOpacity)),
child: Opacity(
opacity: versionOpacity,
child: Text(
'Version 1.0.0',
style: AppStyle.md.copyWith(color: AppColor.textLight),
textAlign: TextAlign.center,
),
),
),
),
],
),
);
},
),
);
}
}