import 'package:flutter/material.dart'; import 'package:firebase_core/firebase_core.dart'; import 'package:firebase_database/firebase_database.dart'; import 'package:firebase_messaging/firebase_messaging.dart'; import 'package:flutter_local_notifications/flutter_local_notifications.dart'; import 'firebase_options.dart'; import 'dashboard.dart'; // 🔔 LOCAL NOTIFICATION final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin(); // 🔥 REALTIME DATABASE final dbRef = FirebaseDatabase.instance.ref("sensor"); // 🔥 ANTI SPAM bool notifHabisSudahMuncul = false; bool notifKosongSudahMuncul = false; bool notifFullSudahMuncul = false; bool notifBerhasilSudahMuncul = false; final statusRef = FirebaseDatabase.instance.ref("status"); int lastHeartbeat = 0; DateTime lastHeartbeatTime = DateTime.now(); bool notifOfflineSudahMuncul = false; void main() async { WidgetsFlutterBinding.ensureInitialized(); await Firebase.initializeApp( options: DefaultFirebaseOptions.currentPlatform, ); FirebaseMessaging messaging = FirebaseMessaging.instance; await messaging.requestPermission( alert: true, badge: true, sound: true, ); const AndroidInitializationSettings androidSettings = AndroidInitializationSettings('@mipmap/ic_launcher'); const InitializationSettings settings = InitializationSettings( android: androidSettings, ); await flutterLocalNotificationsPlugin.initialize(settings); startRealtimeNotif(); monitorHeartbeat(); runApp(const MyApp()); } // 🔥 MONITOR HEARTBEAT void monitorHeartbeat() { statusRef.child("heartbeat").onValue.listen((event) { int heartbeat = 0; if (event.snapshot.value != null) { heartbeat = (event.snapshot.value as num).toInt(); } if (heartbeat != lastHeartbeat) { lastHeartbeat = heartbeat; lastHeartbeatTime = DateTime.now(); notifOfflineSudahMuncul = false; } }); Stream.periodic( const Duration(seconds: 1), ).listen((_) { int selisih = DateTime.now() .difference(lastHeartbeatTime) .inSeconds; if (selisih >= 5 && !notifOfflineSudahMuncul) { notifOfflineSudahMuncul = true; showNotif( "⚠️ Perangkat Offline", "Jaringan lemah atau perangkat tidak terhubung.", ); } }); } // 🔥 REALTIME LISTENER void startRealtimeNotif() { dbRef.onValue.listen((event) { final data = event.snapshot.value as Map?; if (data != null) { double jarak = (data['jarak'] ?? 0).toDouble(); double berat1 = (data['berat1'] ?? 0).toDouble(); double berat2 = (data['berat2'] ?? 0).toDouble(); // 🔥 HITUNG PERSEN double persen = ((12 - jarak) / 8) * 100; if (persen < 0) persen = 0; if (persen > 100) persen = 100; // ================================ // 🔔 PAKAN FULL (100%) // ================================ if (persen >= 100 && !notifFullSudahMuncul) { notifFullSudahMuncul = true; showNotif( "Pakan Full", "Wadah penampung pakan penuh.", ); } // RESET if (persen < 100) { notifFullSudahMuncul = false; } // ================================ // 🔔 PAKAN HAMPIR HABIS (25%) // ================================ if (persen <= 25 && persen > 0 && !notifHabisSudahMuncul) { notifHabisSudahMuncul = true; showNotif( "Pakan Hampir Habis", "Segera isi ulang wadah penampung pakan.", ); } // RESET if (persen > 25 || persen <= 0) { notifHabisSudahMuncul = false; } // ================================ // 🔔 PAKAN HABIS (0%) // ================================ if (persen <= 0 && !notifKosongSudahMuncul) { notifKosongSudahMuncul = true; showNotif( "Pakan Habis", "Wadah penampung pakan sudah kosong.", ); } // RESET if (persen > 0) { notifKosongSudahMuncul = false; } // ================================ // 🔔 PEMBERIAN PAKAN BERHASIL // ================================ bool pakanBerhasil = berat1 > 0 || berat2 > 0; if (pakanBerhasil && !notifBerhasilSudahMuncul) { notifBerhasilSudahMuncul = true; showNotif( "Pemberian Pakan Berhasil", "Pakan berhasil diberikan ke wadah pakan.", ); } // RESET if (!pakanBerhasil) { notifBerhasilSudahMuncul = false; } } }); } // 🔔 FUNGSI TAMPILKAN NOTIFIKASI Future showNotif( String title, String body, ) async { const AndroidNotificationDetails androidDetails = AndroidNotificationDetails( 'pakan_channel', 'Notifikasi Pakan', importance: Importance.max, priority: Priority.high, ); const NotificationDetails details = NotificationDetails( android: androidDetails, ); await flutterLocalNotificationsPlugin.show( 0, title, body, details, ); } class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( debugShowCheckedModeBanner: false, home: Dashboard(), ); } }