Files
apskel-owner-flutter/lib/presentation/pages/splash/splash_page.dart
T

199 lines
6.5 KiB
Dart
Raw Normal View History

2025-08-12 15:18:38 +07:00
import 'package:auto_route/auto_route.dart';
import 'package:flutter/material.dart';
2025-08-16 17:48:49 +07:00
import 'package:flutter_bloc/flutter_bloc.dart';
2025-08-12 15:18:38 +07:00
2025-08-16 17:48:49 +07:00
import '../../../application/auth/auth_bloc.dart';
2025-08-12 17:15:16 +07:00
import '../../../common/theme/theme.dart';
import '../../components/assets/assets.gen.dart';
import '../../router/app_router.gr.dart';
2025-08-12 16:12:36 +07:00
2025-08-12 15:18:38 +07:00
@RoutePage()
class SplashPage extends StatefulWidget {
const SplashPage({super.key});
@override
State<SplashPage> createState() => _SplashPageState();
}
2025-08-12 16:12:36 +07:00
class _SplashPageState extends State<SplashPage> with TickerProviderStateMixin {
late AnimationController _logoController;
2026-06-23 21:40:08 +07:00
late AnimationController _taglineController;
late AnimationController _poweredByController;
2025-08-12 16:12:36 +07:00
2026-06-23 21:40:08 +07:00
late Animation<double> _logoFadeAnimation;
late Animation<double> _logoScaleAnimation;
late Animation<double> _taglineFadeAnimation;
late Animation<Offset> _taglineSlideAnimation;
late Animation<double> _poweredByFadeAnimation;
2025-08-12 16:12:36 +07:00
@override
void initState() {
super.initState();
_logoController = AnimationController(
2026-06-23 21:40:08 +07:00
duration: const Duration(milliseconds: 1000),
2025-08-12 16:12:36 +07:00
vsync: this,
);
2026-06-23 21:40:08 +07:00
_taglineController = AnimationController(
2025-08-12 16:12:36 +07:00
duration: const Duration(milliseconds: 800),
vsync: this,
);
2026-06-23 21:40:08 +07:00
_poweredByController = AnimationController(
duration: const Duration(milliseconds: 600),
2025-08-12 16:12:36 +07:00
vsync: this,
);
2026-06-23 21:40:08 +07:00
_logoFadeAnimation = Tween<double>(
begin: 0.0,
end: 1.0,
).animate(CurvedAnimation(parent: _logoController, curve: Curves.easeOut));
_logoScaleAnimation = Tween<double>(begin: 0.8, end: 1.0).animate(
CurvedAnimation(parent: _logoController, curve: Curves.easeOutBack),
2025-08-12 16:12:36 +07:00
);
2026-06-23 21:40:08 +07:00
_taglineFadeAnimation = Tween<double>(begin: 0.0, end: 1.0).animate(
CurvedAnimation(parent: _taglineController, curve: Curves.easeOut),
2025-08-12 16:12:36 +07:00
);
2026-06-23 21:40:08 +07:00
_taglineSlideAnimation =
Tween<Offset>(begin: const Offset(0, 0.3), end: Offset.zero).animate(
CurvedAnimation(parent: _taglineController, curve: Curves.easeOut),
);
_poweredByFadeAnimation = Tween<double>(begin: 0.0, end: 1.0).animate(
CurvedAnimation(parent: _poweredByController, curve: Curves.easeIn),
2025-08-12 16:12:36 +07:00
);
_startAnimations();
}
void _startAnimations() async {
await Future.delayed(const Duration(milliseconds: 300));
if (mounted) _logoController.forward();
await Future.delayed(const Duration(milliseconds: 600));
2026-06-23 21:40:08 +07:00
if (mounted) _taglineController.forward();
2025-08-12 16:12:36 +07:00
2026-06-23 21:40:08 +07:00
await Future.delayed(const Duration(milliseconds: 400));
if (mounted) _poweredByController.forward();
await Future.delayed(const Duration(milliseconds: 1500));
2025-08-12 16:12:36 +07:00
if (mounted) {
2025-08-16 17:48:49 +07:00
context.read<AuthBloc>().add(const AuthEvent.fetchCurrentUser());
2025-08-12 16:12:36 +07:00
}
}
@override
void dispose() {
_logoController.dispose();
2026-06-23 21:40:08 +07:00
_taglineController.dispose();
_poweredByController.dispose();
2025-08-12 16:12:36 +07:00
super.dispose();
}
2025-08-12 15:18:38 +07:00
@override
Widget build(BuildContext context) {
2025-08-16 17:48:49 +07:00
return BlocListener<AuthBloc, AuthState>(
listenWhen: (previous, current) => previous.status != current.status,
listener: (context, state) {
if (state.isAuthenticated) {
context.router.replace(const MainRoute());
} else {
context.router.replace(const LoginRoute());
}
},
child: Scaffold(
2026-06-23 21:40:08 +07:00
body: Container(
width: double.infinity,
height: double.infinity,
decoration: const BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [Color(0xFFE81E1E), Color(0xFFC40202)],
),
),
child: SafeArea(
child: Column(
children: [
// Main content - Logo & Tagline di tengah
Expanded(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
// Logo
AnimatedBuilder(
animation: _logoController,
builder: (context, child) {
return Opacity(
opacity: _logoFadeAnimation.value.clamp(0.0, 1.0),
child: Transform.scale(
scale: _logoScaleAnimation.value,
child: child,
2025-08-16 17:48:49 +07:00
),
2026-06-23 21:40:08 +07:00
);
},
child: SizedBox(
width: 180,
child: Assets.images.logo.image(fit: BoxFit.contain),
2025-08-16 17:48:49 +07:00
),
),
2026-06-23 21:40:08 +07:00
const SizedBox(height: 32),
2025-08-16 17:48:49 +07:00
2026-06-23 21:40:08 +07:00
// Tagline
SlideTransition(
position: _taglineSlideAnimation,
child: FadeTransition(
opacity: _taglineFadeAnimation,
child: Text(
'Pantau kondisi bisnismu, dari genggaman',
style: AppStyle.lg.copyWith(
color: AppColor.white.withOpacity(0.9),
fontWeight: FontWeight.w400,
letterSpacing: 0.3,
),
textAlign: TextAlign.center,
2025-08-16 17:48:49 +07:00
),
),
),
2026-06-23 21:40:08 +07:00
],
),
),
// Powered by di bawah
FadeTransition(
opacity: _poweredByFadeAnimation,
child: Padding(
padding: const EdgeInsets.only(bottom: 24),
child: RichText(
textAlign: TextAlign.center,
text: TextSpan(
style: AppStyle.sm.copyWith(
color: AppColor.white.withOpacity(0.7),
),
children: [
const TextSpan(text: 'powered by '),
TextSpan(
text: 'PT Selalu Ada Keberuntungan',
style: AppStyle.sm.copyWith(
color: AppColor.white,
fontWeight: FontWeight.w700,
),
),
],
),
2025-08-16 17:48:49 +07:00
),
),
2026-06-23 21:40:08 +07:00
),
],
),
),
2025-08-16 17:48:49 +07:00
),
2025-08-12 15:18:38 +07:00
),
);
}
}