TKK_E32220565/newata2/lib/main.dart

204 lines
7.4 KiB
Dart

// main.dart
import 'package:flutter/material.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:provider/provider.dart';
import 'package:supabase_flutter/supabase_flutter.dart';
import 'package:intl/date_symbol_data_local.dart';
// Providers
import 'providers/auth_provider.dart';
import 'providers/pantau_footage_provider.dart';
import 'providers/schedule_provider.dart';
// Screens
import 'screens/splash_screen.dart';
import 'screens/login_screen.dart';
import 'screens/register_screen.dart';
import 'screens/dashboard_screen.dart';
import 'screens/video_player_screen.dart'; // Pastikan path benar
import 'screens/image_viewer_screen.dart'; // Pastikan path benar
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
print("main: WidgetsFlutterBinding initialized."); // Log
try {
await dotenv.load(fileName: ".env");
print("main: .env file loaded successfully."); // Log
} catch (e) {
print("main: Error loading .env file: $e"); // Log error
}
final supabaseUrl = dotenv.env['SUPABASE_URL'];
final supabaseAnonKey = dotenv.env['SUPABASE_ANON_KEY'];
if (supabaseUrl == null || supabaseAnonKey == null) {
print(
"main: Supabase URL or Anon Key not found in .env file. App cannot initialize Supabase."); // Log error
return;
}
print("main: Supabase URL and Anon Key found."); // Log
try {
await Supabase.initialize(
url: supabaseUrl,
anonKey: supabaseAnonKey,
);
print("main: Supabase initialized successfully."); // Log
} catch (e) {
print("main: Error initializing Supabase: $e"); // Log error
return;
}
try {
await initializeDateFormatting('id_ID', null);
print("main: Date formatting initialized."); // Log
} catch (e) {
print("main: Error initializing date formatting: $e"); // Log error
}
runApp(const MyApp());
}
final supabase = Supabase.instance.client;
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
print("MyApp: Building..."); // Log
return MultiProvider(
providers: [
ChangeNotifierProvider(create: (_) => AuthProvider()),
ChangeNotifierProxyProvider<AuthProvider, FootageProvider>(
create: (_) => FootageProvider(null),
update: (_, auth, previousFootage) =>
FootageProvider(auth.currentUser?.id),
),
ChangeNotifierProxyProvider<AuthProvider, ScheduleProvider>(
create: (_) => ScheduleProvider(null),
update: (_, auth, previousSchedule) =>
ScheduleProvider(auth.currentUser?.id),
),
],
child: MaterialApp(
title: 'CCTV IoT App',
theme: ThemeData(
// Tema tetap sama
primarySwatch: Colors.teal,
visualDensity: VisualDensity.adaptivePlatformDensity,
fontFamily: 'Inter',
scaffoldBackgroundColor: Colors.grey[100],
appBarTheme: AppBarTheme(
backgroundColor: Colors.teal[600],
elevation: 2,
iconTheme:
const IconThemeData(color: Colors.white), // Warna ikon AppBar
titleTextStyle: const TextStyle(
color: Colors.white,
fontSize: 20,
fontWeight: FontWeight.w500) // Style title AppBar
),
bottomNavigationBarTheme: BottomNavigationBarThemeData(
selectedItemColor: Colors.teal[700],
unselectedItemColor: Colors.grey[600],
),
elevatedButtonTheme: ElevatedButtonThemeData(
style: ElevatedButton.styleFrom(
backgroundColor: Colors.teal[500],
foregroundColor: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
),
padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 20),
)),
cardTheme: CardTheme(
elevation: 1,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
),
margin: const EdgeInsets.symmetric(vertical: 6, horizontal: 8),
),
inputDecorationTheme: InputDecorationTheme(
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
borderSide: BorderSide(color: Colors.grey[400]!),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
borderSide: const BorderSide(color: Colors.teal),
),
filled: true,
fillColor: Colors.white,
contentPadding:
const EdgeInsets.symmetric(vertical: 14.0, horizontal: 12.0),
),
listTileTheme: ListTileThemeData(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
),
),
textButtonTheme: TextButtonThemeData(
style: TextButton.styleFrom(
foregroundColor: Colors.teal[600],
),
),
dialogTheme: DialogTheme(
// Style untuk dialog (misal loading)
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.0),
),
elevation: 5,
),
timePickerTheme: TimePickerThemeData(
// Style untuk TimePicker
backgroundColor: Colors.white,
hourMinuteShape: RoundedRectangleBorder(
borderRadius: const BorderRadius.all(Radius.circular(8)),
side: BorderSide(color: Colors.grey[300]!, width: 1),
),
dayPeriodShape: RoundedRectangleBorder(
borderRadius: const BorderRadius.all(Radius.circular(8)),
side: BorderSide(color: Colors.grey[300]!, width: 1),
),
dayPeriodColor: Colors.teal[50],
dayPeriodTextColor: Colors.teal[800],
hourMinuteColor: WidgetStateColor.resolveWith((states) =>
states.contains(WidgetState.selected)
? Colors.teal[100]!
: Colors.grey[100]!),
hourMinuteTextColor: WidgetStateColor.resolveWith((states) =>
states.contains(WidgetState.selected)
? Colors.teal[900]!
: Colors.black54),
dialHandColor: Colors.teal[300],
dialBackgroundColor: Colors.teal[50],
dialTextColor: WidgetStateColor.resolveWith((states) =>
states.contains(WidgetState.selected)
? Colors.white
: Colors.teal[900]!),
entryModeIconColor: Colors.teal[600],
helpTextStyle: TextStyle(color: Colors.teal[800]),
),
),
debugShowCheckedModeBanner: false,
home: SplashScreen(),
routes: {
'/login': (context) => const LoginScreen(),
'/register': (context) => const RegisterScreen(),
'/dashboard': (context) => const DashboardScreen(),
'/video_player': (context) => VideoPlayerScreen(
videoUrl:
ModalRoute.of(context)?.settings.arguments as String? ?? '',
),
'/image_viewer': (context) => ImageViewerScreen(
imageUrl:
ModalRoute.of(context)?.settings.arguments as String? ?? '',
),
},
),
);
}
}