import 'package:flutter/material.dart'; import 'package:intl/intl.dart'; import 'package:lottie/lottie.dart'; import 'package:firebase_database/firebase_database.dart'; class MonitoringPage extends StatefulWidget { @override _MonitoringPageState createState() => _MonitoringPageState(); } class _MonitoringPageState extends State { double temperature = 0.0; double humidity = 0.0; int gasLevel = 0; bool lampStatus = false; bool doorStatus = false; bool buzzerStatus = false; // ✅ Tambahan final int gasThreshold = 300; final double tempThreshold = 30.0; String getFormattedDate() { final now = DateTime.now(); final day = DateFormat('EEEE', 'id_ID').format(now); final date = DateFormat('dd MMMM yyyy', 'id_ID').format(now); return '$day, $date'; } @override void initState() { super.initState(); final dbRef = FirebaseDatabase.instance.ref(); dbRef.child('sensor').onValue.listen((event) { final data = event.snapshot.value as Map; setState(() { temperature = (data['suhu'] ?? 0).toDouble(); humidity = (data['kelembaban'] ?? 0).toDouble(); gasLevel = (data['mq2'] ?? 0).toInt(); }); }); dbRef.child('status').onValue.listen((event) { final data = event.snapshot.value as Map; setState(() { lampStatus = data['lampu'] == 1; doorStatus = data['pintu'] == 1; buzzerStatus = data['buzzer'] == 1; // ✅ Tambahan }); }); } @override Widget build(BuildContext context) { final bool isGasDanger = gasLevel > gasThreshold; final bool isHot = temperature > tempThreshold; return Scaffold( backgroundColor: const Color(0xFFF8F6FF), appBar: AppBar( backgroundColor: Colors.blue.shade900, leading: IconButton( icon: const Icon(Icons.arrow_back, color: Colors.white), onPressed: () => Navigator.pop(context), ), title: const Text('Monitoring', style: TextStyle(color: Colors.white)), ), body: Column( children: [ const SizedBox(height: 20), Center( child: Column( children: [ Lottie.asset('assets/animations/monitor.json', width: 80, height: 80), const SizedBox(height: 6), const Text('Monitoring', style: TextStyle(fontSize: 26, color: Colors.black87, fontWeight: FontWeight.bold)), const SizedBox(height: 4), Text(getFormattedDate(), style: const TextStyle(fontSize: 16, color: Colors.black54)), ], ), ), const SizedBox(height: 20), // Kadar Gas + Buzzer Padding( padding: const EdgeInsets.symmetric(horizontal: 16), child: Container( width: double.infinity, padding: const EdgeInsets.all(16), decoration: BoxDecoration( borderRadius: BorderRadius.circular(20), gradient: const LinearGradient( colors: [Color(0xFFE0F7FA), Colors.white], begin: Alignment.topLeft, end: Alignment.bottomRight, ), boxShadow: const [BoxShadow(color: Colors.black12, blurRadius: 6, offset: Offset(2, 2))], ), child: Column( children: [ Row( children: [ Lottie.asset('assets/animations/gas.json', width: 60, height: 60), const SizedBox(width: 10), Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text('Kadar Gas', style: TextStyle(fontSize: 18, fontWeight: FontWeight.w600)), const SizedBox(height: 6), Text('$gasLevel ppm', style: const TextStyle(fontSize: 28, fontWeight: FontWeight.bold, color: Colors.blue)), ], ), ], ), const SizedBox(height: 10), Center( child: Text( buzzerStatus ? 'Buzzer ON' : 'Buzzer Mati', style: TextStyle( color: buzzerStatus ? Colors.green : Colors.red, fontWeight: FontWeight.bold, fontSize: 16, ), ), ), ], ), ), ), const SizedBox(height: 20), // Grid Info Box Expanded( child: Container( margin: const EdgeInsets.symmetric(horizontal: 16), child: GridView.count( crossAxisCount: 2, crossAxisSpacing: 16, mainAxisSpacing: 16, children: [ _buildInfoBox( title: 'Temperature', iconPath: 'assets/animations/temperature.json', value: '${temperature.toStringAsFixed(1)}°C', statusText: isHot ? 'Blower ON' : 'Blower OFF', statusColor: isHot ? Colors.green : Colors.red, ), _buildInfoBox( title: 'Humidity', iconPath: 'assets/animations/humidity.json', value: '${humidity.toStringAsFixed(0)}%', ), _buildStatusBox( title: 'Lampu', iconPath: 'assets/animations/lamp.json', isActive: lampStatus, activeColor: Colors.green, inactiveColor: Colors.red, activeLabel: 'ON', inactiveLabel: 'OFF', ), _buildStatusBox( title: 'Pintu', iconPath: 'assets/animations/door.json', isActive: doorStatus, activeColor: Colors.red, inactiveColor: Colors.green, activeLabel: 'Terbuka', inactiveLabel: 'Tertutup', ), ], ), ), ), ], ), ); } // --- Info Box (Temperature, Humidity, Blower) Widget _buildInfoBox({ required String title, required String iconPath, required String value, String? statusText, Color? statusColor, }) { return Container( decoration: BoxDecoration( gradient: const LinearGradient(colors: [Color(0xFFE0F7FA), Colors.white], begin: Alignment.topLeft, end: Alignment.bottomRight), borderRadius: BorderRadius.circular(20), boxShadow: const [BoxShadow(color: Colors.black12, blurRadius: 6, offset: Offset(2, 2))], ), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Lottie.asset(iconPath, width: 60, height: 60), const SizedBox(height: 10), Text(title, style: const TextStyle(fontWeight: FontWeight.bold)), const SizedBox(height: 6), Text(value, style: const TextStyle(fontSize: 16, fontWeight: FontWeight.w500, color: Colors.blue)), if (statusText != null) ...[ const SizedBox(height: 6), Text(statusText, style: TextStyle(fontWeight: FontWeight.bold, color: statusColor ?? Colors.black)), ], ], ), ); } // --- Status Box (Lampu & Pintu) Widget _buildStatusBox({ required String title, required String iconPath, required bool isActive, required Color activeColor, required Color inactiveColor, required String activeLabel, required String inactiveLabel, }) { return Container( decoration: BoxDecoration( gradient: const LinearGradient(colors: [Color(0xFFE0F7FA), Colors.white], begin: Alignment.topLeft, end: Alignment.bottomRight), borderRadius: BorderRadius.circular(20), boxShadow: const [BoxShadow(color: Colors.black12, blurRadius: 6, offset: Offset(2, 2))], ), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Lottie.asset(iconPath, width: 60, height: 60, animate: isActive), const SizedBox(height: 10), Text(title, style: const TextStyle(fontWeight: FontWeight.bold)), const SizedBox(height: 6), Text( isActive ? activeLabel : inactiveLabel, style: TextStyle(fontSize: 14, fontWeight: FontWeight.bold, color: isActive ? activeColor : inactiveColor), ), ], ), ); } }