feat: update ui splash
Some checks are pending
Build & Deploy iOS to TestFlight / build-and-deploy (push) Waiting to run
Some checks are pending
Build & Deploy iOS to TestFlight / build-and-deploy (push) Waiting to run
This commit is contained in:
parent
b98462ee8c
commit
7137cd2335
@ -1,12 +1,9 @@
|
||||
import 'package:auto_route/auto_route.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:package_info_plus/package_info_plus.dart';
|
||||
|
||||
import '../../../application/auth/auth_bloc.dart';
|
||||
import '../../../common/extension/extension.dart';
|
||||
import '../../../common/theme/theme.dart';
|
||||
import '../../../injection.dart';
|
||||
import '../../components/assets/assets.gen.dart';
|
||||
import '../../router/app_router.gr.dart';
|
||||
|
||||
@ -20,64 +17,70 @@ class SplashPage extends StatefulWidget {
|
||||
|
||||
class _SplashPageState extends State<SplashPage> with TickerProviderStateMixin {
|
||||
late AnimationController _logoController;
|
||||
late AnimationController _versionController;
|
||||
late AnimationController _backgroundController;
|
||||
late AnimationController _taglineController;
|
||||
late AnimationController _poweredByController;
|
||||
|
||||
late Animation<double> _logoAnimation;
|
||||
late Animation<double> _versionAnimation;
|
||||
late Animation<double> _backgroundAnimation;
|
||||
late Animation<double> _logoFadeAnimation;
|
||||
late Animation<double> _logoScaleAnimation;
|
||||
late Animation<double> _taglineFadeAnimation;
|
||||
late Animation<Offset> _taglineSlideAnimation;
|
||||
late Animation<double> _poweredByFadeAnimation;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
|
||||
// Initialize animation controllers
|
||||
_logoController = AnimationController(
|
||||
duration: const Duration(milliseconds: 1200),
|
||||
duration: const Duration(milliseconds: 1000),
|
||||
vsync: this,
|
||||
);
|
||||
|
||||
_versionController = AnimationController(
|
||||
_taglineController = AnimationController(
|
||||
duration: const Duration(milliseconds: 800),
|
||||
vsync: this,
|
||||
);
|
||||
|
||||
_backgroundController = AnimationController(
|
||||
duration: const Duration(milliseconds: 1500),
|
||||
_poweredByController = AnimationController(
|
||||
duration: const Duration(milliseconds: 600),
|
||||
vsync: this,
|
||||
);
|
||||
|
||||
// Create animations
|
||||
_logoAnimation = Tween<double>(begin: 0.0, end: 1.0).animate(
|
||||
CurvedAnimation(parent: _logoController, curve: Curves.elasticOut),
|
||||
_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),
|
||||
);
|
||||
|
||||
_versionAnimation = Tween<double>(begin: 0.0, end: 1.0).animate(
|
||||
CurvedAnimation(parent: _versionController, curve: Curves.easeInOut),
|
||||
_taglineFadeAnimation = Tween<double>(begin: 0.0, end: 1.0).animate(
|
||||
CurvedAnimation(parent: _taglineController, curve: Curves.easeOut),
|
||||
);
|
||||
|
||||
_backgroundAnimation = Tween<double>(begin: 0.0, end: 1.0).animate(
|
||||
CurvedAnimation(parent: _backgroundController, curve: Curves.easeInOut),
|
||||
_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),
|
||||
);
|
||||
|
||||
// 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();
|
||||
if (mounted) _taglineController.forward();
|
||||
|
||||
// Navigate to home screen after all animations complete
|
||||
await Future.delayed(const Duration(milliseconds: 2000));
|
||||
await Future.delayed(const Duration(milliseconds: 400));
|
||||
if (mounted) _poweredByController.forward();
|
||||
|
||||
await Future.delayed(const Duration(milliseconds: 1500));
|
||||
if (mounted) {
|
||||
context.read<AuthBloc>().add(const AuthEvent.fetchCurrentUser());
|
||||
}
|
||||
@ -86,14 +89,13 @@ class _SplashPageState extends State<SplashPage> with TickerProviderStateMixin {
|
||||
@override
|
||||
void dispose() {
|
||||
_logoController.dispose();
|
||||
_versionController.dispose();
|
||||
_backgroundController.dispose();
|
||||
_taglineController.dispose();
|
||||
_poweredByController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final packageInfo = getIt<PackageInfo>();
|
||||
return BlocListener<AuthBloc, AuthState>(
|
||||
listenWhen: (previous, current) => previous.status != current.status,
|
||||
listener: (context, state) {
|
||||
@ -104,86 +106,91 @@ class _SplashPageState extends State<SplashPage> with TickerProviderStateMixin {
|
||||
}
|
||||
},
|
||||
child: 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: 200,
|
||||
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,
|
||||
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,
|
||||
),
|
||||
child: Assets.images.logo.image(fit: BoxFit.cover),
|
||||
),
|
||||
);
|
||||
},
|
||||
child: SizedBox(
|
||||
width: 180,
|
||||
child: Assets.images.logo.image(fit: BoxFit.contain),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 32),
|
||||
|
||||
// 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(
|
||||
'${context.lang.version} ${packageInfo.version}+${packageInfo.buildNumber}',
|
||||
style: AppStyle.md.copyWith(
|
||||
color: AppColor.textLight,
|
||||
// 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,
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
// 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,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user