import 'dart:async'; import 'dart:io'; import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:connectivity_plus/connectivity_plus.dart'; import 'package:gen_rentals/Screens/BillDetailListScreen.dart'; import 'package:gen_rentals/Screens/DashboardScreen.dart'; import 'package:gen_rentals/Screens/ProductsDetailScreen.dart'; import 'package:gen_rentals/Screens/TransactionsScreen.dart'; import '../Utility/CustomSnackbar.dart'; import '../Utility/SharedpreferencesService.dart'; import 'authScreen/LoginScreen.dart'; class SplashScreen extends StatefulWidget { const SplashScreen({super.key}); @override State createState() => _SplashScreenState(); } class _SplashScreenState extends State with SingleTickerProviderStateMixin { late AnimationController _controller; late Animation _fadeAnimation; late Animation _scaleAnimation; late Animation _slideAnimation; late Animation _rotationAnimation; final prefs = SharedPreferencesService.instance; Timer? _connectivityTimer; bool _progressCheckCompleted = false; bool _hasInternet = true; @override void initState() { super.initState(); // Initialize connectivity check _initConnectivity(); _controller = AnimationController( vsync: this, duration: const Duration(milliseconds: 1500), ); // Multiple animations _fadeAnimation = Tween(begin: 0.0, end: 1.0).animate( CurvedAnimation( parent: _controller, curve: const Interval(0.0, 0.6, curve: Curves.easeInOut), ), ); _scaleAnimation = Tween(begin: 0.5, end: 1.0).animate( CurvedAnimation( parent: _controller, curve: const Interval(0.2, 0.8, curve: Curves.elasticOut), ), ); _slideAnimation = Tween( begin: const Offset(0, 0.5), end: Offset.zero, ).animate( CurvedAnimation( parent: _controller, curve: const Interval(0.3, 0.8, curve: Curves.easeOutCubic), ), ); _rotationAnimation = Tween(begin: 0.0, end: 1.0).animate( CurvedAnimation( parent: _controller, curve: const Interval(0.0, 0.4, curve: Curves.easeInOut), ), ); // Start animations _controller.forward(); // Navigate after delay Timer(const Duration(seconds: 3), () { _checkAccountAndNavigate(); }); } Future _checkAccountAndNavigate() async { try { // Check if account ID exists in shared preferences final String? savedAccId = await prefs.getString("accId"); if (savedAccId != null && savedAccId.isNotEmpty) { // Account ID exists, navigate directly to Dashboard _navigateToDashboard(); } else { // No account ID found, navigate to Login _navigateToLogin(); } } catch (e) { debugPrint("Error checking account ID: $e"); // Fallback to login screen on error _navigateToLogin(); } } Future _navigateToDashboard() async { final String? savedAccId = await prefs.getString("accId"); final String? savedSessionId = await prefs.getString("session_id"); // Check if accId is not null and not empty if (savedAccId != null && savedAccId.isNotEmpty) { Navigator.pushReplacement( context, PageRouteBuilder( pageBuilder: (_, __, ___) => DashboardScreen(accId: savedAccId, sessionId: savedSessionId.toString(),), transitionsBuilder: (_, animation, __, child) { return FadeTransition( opacity: animation, child: child, ); }, transitionDuration: const Duration(milliseconds: 800), ), ); } else { // If no valid accId, navigate to login _navigateToLogin(); } } void _navigateToLogin() { Navigator.pushReplacement( context, PageRouteBuilder( pageBuilder: (_, __, ___) => const LoginScreen(), transitionsBuilder: (_, animation, __, child) { return FadeTransition( opacity: animation, child: child, ); }, transitionDuration: const Duration(milliseconds: 800), ), ); } Future _initConnectivity() async { try { // Initial connectivity check await _checkConnectivity(); // Use periodic checks instead of stream _connectivityTimer = Timer.periodic(const Duration(seconds: 3), (timer) { _checkConnectivity(); }); } catch (e) { debugPrint("Connectivity initialization error: $e"); _updateConnectionStatus(false); } } Future _checkConnectivity() async { try { // Method 1: Using connectivity_plus final connectivity = Connectivity(); final results = await connectivity.checkConnectivity(); final hasInternet = results.any((result) => result != ConnectivityResult.none); // Method 2: Fallback with socket test if (hasInternet) { try { final result = await InternetAddress.lookup('google.com'); final socketCheck = result.isNotEmpty && result[0].rawAddress.isNotEmpty; _updateConnectionStatus(socketCheck); } catch (e) { _updateConnectionStatus(false); } } else { _updateConnectionStatus(false); } } catch (e) { debugPrint("Connectivity check error: $e"); _updateConnectionStatus(false); } } void _updateConnectionStatus(bool hasInternet) { if (mounted) { setState(() { _hasInternet = hasInternet; }); } if (!hasInternet) { _showNoInternetSnackbar(); } else { // Dismiss the warning snackbar if internet is restored ScaffoldMessenger.of(context).hideCurrentSnackBar(); } } void _showNoInternetSnackbar() { if (mounted) { WidgetsBinding.instance.addPostFrameCallback((_) { // Hide any existing snackbar ScaffoldMessenger.of(context).hideCurrentSnackBar(); CustomSnackBar.showError( context: context, message: "No internet connection! Please connect to the internet.", action: SnackBarAction( label: "RETRY", onPressed: () { _checkConnectivity(); }, ), ); }); } } @override void dispose() { _controller.dispose(); _connectivityTimer?.cancel(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( backgroundColor: const Color(0xFFF5F8FC), body: Container( decoration: const BoxDecoration( gradient: LinearGradient( begin: Alignment.topCenter, end: Alignment.bottomCenter, colors: [ Color(0xFFF5F8FC), Color(0xFFE3F2FD), Color(0xFFB3E5FC), ], stops: [0.0, 0.6, 1.0], ), ), child: Stack( children: [ // Animated background elements Positioned( top: -50, right: -50, child: AnimatedBuilder( animation: _rotationAnimation, builder: (context, child) { return Transform.rotate( angle: _rotationAnimation.value * 2 * 3.14159, child: Container( width: 200, height: 200, decoration: BoxDecoration( shape: BoxShape.circle, color: const Color(0xFF26BAE7).withOpacity(0.1), ), ), ); }, ), ), Positioned( bottom: -30, left: -30, child: AnimatedBuilder( animation: _rotationAnimation, builder: (context, child) { return Transform.rotate( angle: -_rotationAnimation.value * 2 * 3.14159, child: Container( width: 150, height: 150, decoration: BoxDecoration( shape: BoxShape.circle, color: const Color(0xFF26BAE7).withOpacity(0.08), ), ), ); }, ), ), // Main content Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ // Logo with multiple animations AnimatedBuilder( animation: _controller, builder: (context, child) { return Transform.translate( offset: _slideAnimation.value * 100, child: Transform.scale( scale: _scaleAnimation.value, child: Opacity( opacity: _fadeAnimation.value, child: Container( padding: const EdgeInsets.all(20), decoration: BoxDecoration( shape: BoxShape.circle, color: Colors.white, boxShadow: [ BoxShadow( color: const Color(0xFF26BAE7).withOpacity(0.3), blurRadius: 20, spreadRadius: 2, offset: const Offset(0, 5), ), ], ), child: RotationTransition( turns: _rotationAnimation, child: SvgPicture.network( "https://genrentals.in/assets/img/logo-black.svg", height: 80, ), ), ), ), ), ); }, ), const SizedBox(height: 30), // App name with animation AnimatedBuilder( animation: _controller, builder: (context, child) { return Transform.translate( offset: _slideAnimation.value * 50, child: Opacity( opacity: _fadeAnimation.value, child: Transform.scale( scale: _scaleAnimation.value, child: const Text( "Gen Rentals", style: TextStyle( fontSize: 32, fontWeight: FontWeight.w800, color: Color(0xFF26BAE7), letterSpacing: 1.2, ), ), ), ), ); }, ), const SizedBox(height: 10), // Tagline with animation AnimatedBuilder( animation: _controller, builder: (context, child) { return Opacity( opacity: _fadeAnimation.value, child: Transform.translate( offset: _slideAnimation.value * 30, child: const Text( "Premium Equipment Rentals", style: TextStyle( fontSize: 16, fontWeight: FontWeight.w500, color: Color(0xFF666666), letterSpacing: 0.5, ), ), ), ); }, ), const SizedBox(height: 50), // Loading indicator AnimatedBuilder( animation: _controller, builder: (context, child) { return Opacity( opacity: _fadeAnimation.value, child: Container( width: 100, height: 3, decoration: BoxDecoration( color: const Color(0xFF26BAE7).withOpacity(0.3), borderRadius: BorderRadius.circular(2), ), child: Stack( children: [ // Animated progress bar AnimatedContainer( duration: const Duration(milliseconds: 3000), width: 100 * _controller.value, decoration: BoxDecoration( gradient: const LinearGradient( colors: [ Color(0xFF26BAE7), Color(0xFF4FC3F7), ], ), borderRadius: BorderRadius.circular(2), ), ), ], ), ), ); }, ), ], ), ), // Bottom wave decoration Positioned( bottom: 0, left: 0, right: 0, child: AnimatedBuilder( animation: _controller, builder: (context, child) { return Transform.translate( offset: Offset(0, 20 * (1 - _controller.value)), child: Opacity( opacity: _fadeAnimation.value, child: CustomPaint( size: Size(MediaQuery.of(context).size.width, 80), painter: WavePainter(), ), ), ); }, ), ), ], ), ), ); } } // Custom wave painter for bottom decoration class WavePainter extends CustomPainter { @override void paint(Canvas canvas, Size size) { final paint = Paint() ..color = const Color(0xFF26BAE7).withOpacity(0.1) ..style = PaintingStyle.fill; final path = Path(); path.moveTo(0, size.height * 0.5); path.quadraticBezierTo( size.width * 0.25, size.height * 0.3, size.width * 0.5, size.height * 0.5, ); path.quadraticBezierTo( size.width * 0.75, size.height * 0.7, size.width, size.height * 0.5, ); path.lineTo(size.width, size.height); path.lineTo(0, size.height); path.close(); canvas.drawPath(path, paint); } @override bool shouldRepaint(covariant CustomPainter oldDelegate) => false; }