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 with SingleTickerProviderStateMixin { late AnimationController _animationController; late Animation _fadeAnimation; late Animation _scaleAnimation; late Animation _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(); } 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([ TweenSequenceItem(tween: Tween(begin: 0.0, end: 1.0), weight: 20), TweenSequenceItem(tween: Tween(begin: 1.0, end: 1.0), weight: 60), TweenSequenceItem(tween: Tween(begin: 1.0, end: 0.0), weight: 20), ]).animate( CurvedAnimation(parent: _animationController, curve: Curves.easeInOut), ); _scaleAnimation = TweenSequence([ TweenSequenceItem( tween: Tween( begin: 0.5, end: 1.0, ).chain(CurveTween(curve: Curves.elasticOut)), weight: 40, ), TweenSequenceItem(tween: Tween(begin: 1.0, end: 1.0), weight: 40), TweenSequenceItem(tween: Tween(begin: 1.0, end: 1.2), weight: 20), ]).animate(_animationController); _slideAnimation = Tween(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 _playDeepMaleVoice() async { if (_isAudioPlayed) return; _isAudioPlayed = true; debugPrint('Playing intro voice...'); try { // Gunakan Future.delayed untuk memastikan tidak memblokir thread utama Future.delayed(const Duration(milliseconds: 300), () { // Bungkus dalam try-catch terpisah untuk mengisolasi error audio _safePlayAudio(); }); } catch (e) { debugPrint('Error scheduling audio playback: $e'); // Jangan biarkan error audio mengganggu flow aplikasi } } // Metode terpisah untuk memutar audio dengan aman Future _safePlayAudio() async { try { await _audioPlayer.setReleaseMode(ReleaseMode.release); // Gunakan timeout untuk mencegah blocking await _audioPlayer .play(AssetSource('audio/introVoice.mp3'), volume: 0.8) .timeout( const Duration(seconds: 3), onTimeout: () { debugPrint('Timeout playing intro voice'); return; }, ); debugPrint('Intro voice started playing'); } catch (assetError) { debugPrint('Could not play intro voice: $assetError'); // Fallback to regular welcome audio try { debugPrint('Falling back to regular welcome audio...'); await _audioPlayer .play(AssetSource('audio/welcome.mp3'), volume: 0.8) .timeout( const Duration(seconds: 2), onTimeout: () { debugPrint('Timeout playing welcome audio'); return; }, ); } catch (welcomeError) { debugPrint('Could not play welcome audio: $welcomeError'); // Ignore audio errors to prevent app crash } } } // Improved auth checking with timeout handling Future _checkAuthAndNavigate() async { // Gunakan flag untuk menghindari multiple calls bool isNavigating = false; try { // Tambahkan timeout untuk menghindari hang bool isLoggedIn = false; bool isSessionValid = false; try { // Bungkus dalam Future.delayed untuk memastikan UI tetap responsif await Future.delayed(const Duration(milliseconds: 100), () async { // Check if user is logged in AND session is valid (not timed out) try { isLoggedIn = _authServices.isUserLoggedIn(); } catch (e) { debugPrint('Error checking login status: $e'); isLoggedIn = false; } }); // Berikan jeda sebelum memeriksa session await Future.delayed(const Duration(milliseconds: 200)); // Periksa session dengan timeout // Pada splash screen kita hanya perlu tau apakah user login, // bukan apakah session valid - ini akan diperiksa di SessionManager nanti try { // Sebagai fallback, gunakan status login karena di splash screen // kita hanya butuh tahu apakah harus ke intro atau home isSessionValid = isLoggedIn; // Lakukan pemeriksaan sederhana untuk user saat ini final user = _authServices.getCurrentUser(); isSessionValid = user != null; } catch (e) { debugPrint('Error checking user: $e'); isSessionValid = isLoggedIn; // Fallback ke status login } debugPrint( 'Auth check: isLoggedIn=$isLoggedIn, isSessionValid=$isSessionValid', ); } catch (authError) { debugPrint('Error checking auth status: $authError'); // Default ke false jika ada error isLoggedIn = false; isSessionValid = false; } if (!mounted) return; // Hindari multiple navigation if (isNavigating) { debugPrint('Already navigating, skipping duplicate navigation'); return; } isNavigating = true; if (isLoggedIn && isSessionValid) { // Valid session, navigate to home debugPrint('Navigating to home screen - valid session'); Navigator.pushReplacementNamed(context, '/home'); } else { // Session expired or no session, go to intro debugPrint('Navigating to intro screen - no valid session'); Navigator.pushReplacementNamed(context, '/intro'); } } catch (e) { // Handle any errors by directing to login if (mounted && !isNavigating) { 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, ), ), ), ), ], ), ), ), ), ); }, ), ), ), ); } }