MIF_E31222656/lib/screens/intro/animation_splash_screen.dart

318 lines
12 KiB
Dart

import 'package:flutter/material.dart';
import 'package:tugas_akhir_supabase/services/auth_services.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:tugas_akhir_supabase/di/service_locator.dart';
import 'package:audioplayers/audioplayers.dart';
import 'package:tugas_akhir_supabase/services/session_manager.dart';
import 'dart:async';
// Import HomeScreen
class SplashScreen extends StatefulWidget {
const SplashScreen({super.key});
@override
_SplashScreenState createState() => _SplashScreenState();
}
class _SplashScreenState extends State<SplashScreen>
with SingleTickerProviderStateMixin {
late AnimationController _animationController;
late Animation<double> _fadeAnimation;
late Animation<double> _scaleAnimation;
late Animation<double> _slideAnimation;
late AuthServices _authServices;
final AudioPlayer _audioPlayer = AudioPlayer();
bool _isAudioPlayed = false;
@override
void initState() {
super.initState();
// Get auth service instance using the sl instance from service_locator.dart
try {
_authServices = sl<AuthServices>();
} catch (e) {
debugPrint('Error getting AuthServices from GetIt: $e');
// Create a local instance as fallback if GetIt fails
_authServices = AuthServices();
}
_animationController = AnimationController(
duration: const Duration(milliseconds: 2000), // Increased duration
vsync: this,
);
_fadeAnimation = TweenSequence<double>([
TweenSequenceItem(tween: Tween<double>(begin: 0.0, end: 1.0), weight: 20),
TweenSequenceItem(tween: Tween<double>(begin: 1.0, end: 1.0), weight: 60),
TweenSequenceItem(tween: Tween<double>(begin: 1.0, end: 0.0), weight: 20),
]).animate(
CurvedAnimation(parent: _animationController, curve: Curves.easeInOut),
);
_scaleAnimation = TweenSequence<double>([
TweenSequenceItem(
tween: Tween<double>(
begin: 0.5,
end: 1.0,
).chain(CurveTween(curve: Curves.elasticOut)),
weight: 40,
),
TweenSequenceItem(tween: Tween<double>(begin: 1.0, end: 1.0), weight: 40),
TweenSequenceItem(tween: Tween<double>(begin: 1.0, end: 1.2), weight: 20),
]).animate(_animationController);
_slideAnimation = Tween<double>(begin: 50.0, end: 0.0).animate(
CurvedAnimation(
parent: _animationController,
curve: const Interval(0.0, 0.5, curve: Curves.easeOut),
),
);
// Delay animation start for native splash to finish properly
Future.delayed(const Duration(milliseconds: 900), () {
if (mounted) {
_animationController.forward();
}
});
// Play sound after a short delay
Timer(const Duration(milliseconds: 1000), () {
_playDeepMaleVoice();
});
_animationController.addStatusListener((status) {
if (status == AnimationStatus.completed) {
// Langsung navigasi tanpa delay tambahan
if (mounted) {
_checkAuthAndNavigate();
}
}
});
}
Future<void> _playDeepMaleVoice() async {
if (_isAudioPlayed) return;
_isAudioPlayed = true;
debugPrint('Playing intro voice...');
try {
// Play the custom intro voice with delayed initialization
Future.delayed(const Duration(milliseconds: 200), () async {
try {
await _audioPlayer.setReleaseMode(ReleaseMode.release);
// Gunakan metode yang lebih sederhana untuk audio
try {
// Try to play custom intro voice
debugPrint('Playing introVoice.mp3...');
await _audioPlayer.play(
AssetSource('audio/introVoice.mp3'),
volume: 0.8,
);
debugPrint('Intro voice started playing');
} catch (assetError) {
debugPrint('Could not play intro voice: $assetError');
// Fallback to regular welcome audio only
try {
debugPrint('Falling back to regular welcome audio...');
await _audioPlayer.play(
AssetSource('audio/welcome.mp3'),
volume: 0.8,
);
debugPrint('Regular welcome audio started playing');
} catch (welcomeError) {
debugPrint('Could not play welcome audio: $welcomeError');
// Don't try URL audio as it can cause connectivity issues
}
}
} catch (e) {
debugPrint('Audio initialization error: $e');
}
});
} catch (e) {
debugPrint('Error in audio playback: $e');
}
}
// Improved auth checking with timeout handling
Future<void> _checkAuthAndNavigate() async {
try {
// Check if user is logged in AND session is valid (not timed out)
final isLoggedIn = _authServices.isUserLoggedIn();
final isSessionValid = SessionManager.isAuthenticated;
if (!mounted) return;
// Menghapus delay tambahan
// Langsung navigasi
if (isLoggedIn && isSessionValid) {
// Valid session, navigate to home
Navigator.pushReplacementNamed(context, '/home');
} else {
// Session expired or no session, go to intro
Navigator.pushReplacementNamed(context, '/intro');
}
} catch (e) {
// Handle any errors by directing to login
if (mounted) {
debugPrint('Auth error in splash screen: $e');
Navigator.pushReplacementNamed(context, '/intro');
}
}
}
@override
void dispose() {
_animationController.dispose();
_audioPlayer.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.black,
resizeToAvoidBottomInset: true,
body: SafeArea(
child: Container(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [
Colors.black,
Colors.black87,
const Color(0xFF056839).withOpacity(0.3),
],
stops: const [0.0, 0.5, 1.0],
),
),
child: AnimatedBuilder(
animation: _animationController,
builder: (context, child) {
return Opacity(
opacity: _fadeAnimation.value,
child: Transform.scale(
scale: _scaleAnimation.value,
child: Center(
child: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Transform.translate(
offset: Offset(0, _slideAnimation.value),
child: Container(
width: 180,
height: 180,
decoration: BoxDecoration(
color: Colors.transparent,
shape: BoxShape.circle,
),
child: Stack(
alignment: Alignment.center,
children: [
Container(
width: 160,
height: 160,
decoration: BoxDecoration(
shape: BoxShape.circle,
gradient: LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: [
const Color(
0xFF056839,
).withOpacity(0.8),
const Color(0xFF056839),
],
),
boxShadow: [
BoxShadow(
color: const Color(
0xFF056839,
).withOpacity(0.3),
blurRadius: 20,
spreadRadius: 5,
),
],
),
),
Image.asset(
'assets/images/logo.png',
width: 120,
height: 120,
color: Colors.white,
),
],
),
),
),
const SizedBox(height: 40),
Transform.translate(
offset: Offset(0, _slideAnimation.value),
child: Text(
'TaniSM4RT',
style: GoogleFonts.poppins(
fontSize: 48,
fontWeight: FontWeight.bold,
color: Colors.white,
letterSpacing: 2,
shadows: [
Shadow(
color: const Color(
0xFF056839,
).withOpacity(0.5),
offset: const Offset(0, 4),
blurRadius: 15,
),
],
),
),
),
const SizedBox(height: 16),
Transform.translate(
offset: Offset(0, _slideAnimation.value),
child: Container(
padding: const EdgeInsets.symmetric(
horizontal: 20,
vertical: 8,
),
decoration: BoxDecoration(
color: const Color(0xFF056839).withOpacity(0.1),
borderRadius: BorderRadius.circular(30),
border: Border.all(
color: const Color(
0xFF056839,
).withOpacity(0.3),
width: 1,
),
),
child: Text(
'Smart Farming Solution',
style: GoogleFonts.poppins(
fontSize: 16,
color: Colors.white.withOpacity(0.9),
letterSpacing: 1,
fontWeight: FontWeight.w500,
),
),
),
),
],
),
),
),
),
);
},
),
),
),
);
}
}