import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:supabase_flutter/supabase_flutter.dart'; import 'package:tugas_akhir_supabase/core/constants/app_constants.dart'; import 'package:tugas_akhir_supabase/di/service_locator.dart'; import 'package:tugas_akhir_supabase/core/routes/app_routes.dart'; import 'package:intl/date_symbol_data_local.dart'; import 'package:tugas_akhir_supabase/services/session_manager.dart'; import 'package:tugas_akhir_supabase/widgets/session_expired_dialog.dart'; // Tambahkan listener untuk hot reload bool _hasDoneHotReloadSetup = false; void main() async { // Langsung memulai aplikasi utama try { // Initialize Flutter binding WidgetsFlutterBinding.ensureInitialized(); // Tambahkan dukungan untuk hot reload if (!_hasDoneHotReloadSetup) { _hasDoneHotReloadSetup = true; // Set debug flags debugPrint('======= Setting up hot reload support ======='); // Pastikan semua yang memblokir hot reload dibersihkan final binding = WidgetsFlutterBinding.ensureInitialized(); binding.addPostFrameCallback((_) { // Execute after first frame is rendered debugPrint( '======= First frame rendered, hot reload should work =======', ); }); } // Debug log untuk pelacakan splash screen debugPrint('======= App Start: Loading TaniSMART application ======='); // Set orientation to portrait await SystemChrome.setPreferredOrientations([ DeviceOrientation.portraitUp, DeviceOrientation.portraitDown, ]); // Set up error handlers FlutterError.onError = (FlutterErrorDetails details) { debugPrint('Flutter error: ${details.exception}'); }; // Initialize date formatting await initializeDateFormatting('id_ID'); await initializeDateFormatting('en_US'); // Initialize Supabase await Supabase.initialize( url: AppConstants.supabaseUrl, anonKey: AppConstants.supabaseAnonKey, debug: false, ); // Initialize service locator await initServiceLocator(); // Initialize session management await SessionManager.initializeSession(); // Debug log sebelum menjalankan aplikasi debugPrint( '======= App initialized: Running TaniSMART application =======', ); // Run the app runApp(const RealApp()); } catch (e, stack) { debugPrint('Error starting full app: $e\n$stack'); // Show error screen runApp( MaterialApp( home: Scaffold( appBar: AppBar( title: const Text('TaniSMART Error'), backgroundColor: Colors.red, ), body: Center( child: Padding( padding: const EdgeInsets.all(20.0), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ const Icon(Icons.error_outline, color: Colors.red, size: 48), const SizedBox(height: 16), const Text( 'Aplikasi tidak dapat dimulai', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold), textAlign: TextAlign.center, ), const SizedBox(height: 8), Text( 'Error: ${e.toString()}', style: const TextStyle(color: Colors.red), textAlign: TextAlign.center, ), const SizedBox(height: 24), ElevatedButton( onPressed: () { main(); }, child: const Text('Coba Lagi'), ), ], ), ), ), ), ), ); } } class RealApp extends StatefulWidget { const RealApp({super.key}); @override State createState() => _RealAppState(); } class _RealAppState extends State with WidgetsBindingObserver { bool _showingSessionExpiredDialog = false; @override void initState() { super.initState(); WidgetsBinding.instance.addObserver(this); // Listen to session expired events SessionManager.sessionExpiredStream.listen((isExpired) { if (isExpired && !_showingSessionExpiredDialog) { _showSessionExpiredDialog(); } }); } @override void dispose() { WidgetsBinding.instance.removeObserver(this); SessionManager.dispose(); super.dispose(); } @override void didChangeAppLifecycleState(AppLifecycleState state) { debugPrint('App lifecycle state changed to: $state'); switch (state) { case AppLifecycleState.paused: case AppLifecycleState.inactive: case AppLifecycleState.detached: // App went to background SessionManager.onAppBackground(); break; case AppLifecycleState.resumed: // App came to foreground SessionManager.onAppForeground().then((_) { if (SessionManager.isExpired && !_showingSessionExpiredDialog) { _showSessionExpiredDialog(); } }); break; default: break; } } void _showSessionExpiredDialog() { if (_showingSessionExpiredDialog) return; _showingSessionExpiredDialog = true; // Use a post-frame callback to ensure the context is valid WidgetsBinding.instance.addPostFrameCallback((_) { if (!mounted) return; try { // Check if context is valid and has MaterialApp ancestor if (context.findAncestorWidgetOfExactType() == null) { debugPrint( 'Session: Cannot show dialog - no MaterialApp ancestor found', ); _showingSessionExpiredDialog = false; return; } showDialog( context: context, barrierDismissible: false, builder: (dialogContext) => const SessionExpiredDialog(), ).then((_) { _showingSessionExpiredDialog = false; }); } catch (e) { debugPrint('Session: Error showing session expired dialog: $e'); _showingSessionExpiredDialog = false; // Navigate to login screen directly if dialog can't be shown Navigator.of( context, rootNavigator: true, ).pushNamedAndRemoveUntil('/login', (route) => false).catchError((e) { debugPrint('Session: Error navigating to login: $e'); }); } }); } @override Widget build(BuildContext context) { return MaterialApp( debugShowCheckedModeBanner: false, title: 'TaniSMART', theme: ThemeData( primaryColor: const Color(0xFF056839), colorScheme: ColorScheme.fromSeed( seedColor: const Color(0xFF056839), primary: const Color(0xFF056839), secondary: const Color(0xFFF9B300), tertiary: const Color(0xFF78B057), ), scaffoldBackgroundColor: const Color(0xFFF5F5F5), cardColor: Colors.white, useMaterial3: true, appBarTheme: const AppBarTheme( backgroundColor: Color(0xFF056839), foregroundColor: Colors.white, elevation: 0, ), inputDecorationTheme: InputDecorationTheme( filled: true, fillColor: Colors.white, border: OutlineInputBorder(borderRadius: BorderRadius.circular(8)), ), ), initialRoute: '/', routes: AppRoutes.routes, ); } }