import 'dart:async'; import 'package:flutter/material.dart'; import 'package:firebase_database/firebase_database.dart'; import 'package:firebase_auth/firebase_auth.dart'; import 'package:intl/intl.dart'; import 'dashboard.dart'; import 'notifikasi.dart'; import '../widgets/fade_in_up.dart'; import '../widgets/whatsapp_notification.dart'; import 'akun.dart'; import '../utils/knn_classifier.dart'; class RiwayatPage extends StatefulWidget { const RiwayatPage({super.key}); @override State createState() => _RiwayatPageState(); } class _RiwayatPageState extends State { final db = FirebaseDatabase.instance.ref(); List> riwayatList = []; String selectedFilter = "Semua"; StreamSubscription? _historySubscription; @override void initState() { super.initState(); WhatsAppNotificationService().startListening(); listenToHistory(); } @override void dispose() { _historySubscription?.cancel(); super.dispose(); } void listenToHistory() { _historySubscription?.cancel(); _historySubscription = db.child("sensor/history").onValue.listen((event) { final data = event.snapshot.value as Map?; if (data != null) { List> tempList = []; data.forEach((key, value) { double ppm = double.parse(value["ppm"].toString()); int timestamp = value["timestamp"]; DateTime date = DateTime.fromMillisecondsSinceEpoch(timestamp * 1000); String? rawStatus = value["keterangan"]; String status; if (rawStatus == "Bahaya") { status = "Berbahaya"; } else if (rawStatus == "Sedang") { status = "Formalin Sedang"; } else if (rawStatus == "Aman") { status = "Aman"; } else { String statusKnn = klasifikasiKNN(ppm); if (statusKnn == "Bahaya") { status = "Berbahaya"; } else if (statusKnn == "Sedang") { status = "Formalin Sedang"; } else { status = "Aman"; } } tempList.add({ "key": key, "nama": value["makanan"] ?? "-", "ppm": ppm, "status": status, "tanggal": DateFormat('dd-MM-yyyy').format(date), "jam": DateFormat('HH:mm').format(date), }); }); // urutkan terbaru di atas tempList.sort((a, b) => b["tanggal"].compareTo(a["tanggal"])); if (mounted) { setState(() { riwayatList = tempList; }); } } }); } void hapusSatu(String key) { db.child("sensor/history").child(key).remove(); } void hapusSemua() { db.child("sensor/history").remove(); setState(() { riwayatList.clear(); }); } Color getStatusColor(String status) { if (status == "Berbahaya") return Colors.red; if (status == "Formalin Sedang") return Colors.orangeAccent; return const Color(0xFF1565C0); } @override Widget build(BuildContext context) { final filteredList = selectedFilter == "Semua" ? riwayatList : riwayatList .where((item) { try { if (item == null) return false; final nama = item["nama"]; if (nama == null) return false; return nama.toString().toLowerCase() == selectedFilter.toLowerCase(); } catch (e) { return false; } }) .toList(); return Scaffold( appBar: AppBar( automaticallyImplyLeading: false, backgroundColor: Colors.white, elevation: 0, centerTitle: true, title: const Text( "History Pengujian", style: TextStyle(color: Color(0xFF1565C0), fontWeight: FontWeight.bold), ), iconTheme: const IconThemeData(color: Color(0xFF1565C0)), // in case of back button actions: [], ), body: Container( width: double.infinity, height: double.infinity, decoration: const BoxDecoration( gradient: LinearGradient( colors: [ Colors.white, Color(0xFFE3F2FD), // Light blue Color(0xFF42A5F5), // Medium blue Color(0xFF1565C0), // Dark blue ], begin: Alignment.topCenter, end: Alignment.bottomCenter, ), ), child: Column( children: [ // 🔥 STATISTIK (Vibrant, Premium & Modern Dashboard Stats Grid) FadeInUp( delay: 200, child: Padding( padding: const EdgeInsets.fromLTRB(20, 15, 20, 5), child: Row( children: [ Expanded( child: _buildStatCard( "Total Uji", "${riwayatList.length}", const Color(0xFF1565C0), Icons.analytics_outlined, ), ), const SizedBox(width: 10), Expanded( child: _buildStatCard( "Aman", "${riwayatList.where((e) => e['status'] == 'Aman').length}", const Color(0xFF00C853), Icons.check_circle_outline_rounded, ), ), const SizedBox(width: 10), Expanded( child: _buildStatCard( "Bahaya", "${riwayatList.where((e) => e['status'] == 'Berbahaya').length}", const Color(0xFFFF1744), Icons.warning_amber_rounded, ), ), ], ), ), ), // 🔥 FILTER DROPDOWN FadeInUp( delay: 300, child: _buildFilterDropdown(), ), Expanded( child: FadeInUp( delay: 400, child: filteredList.isEmpty ? Center( child: Text( "Belum ada riwayat $selectedFilter", style: const TextStyle(color: Colors.white, fontSize: 16), ), ) : ListView.builder( padding: const EdgeInsets.all(20), itemCount: filteredList.length, itemBuilder: (context, index) { final riwayat = filteredList[index]; return Dismissible( key: Key(riwayat['key']), direction: DismissDirection.endToStart, onDismissed: (direction) => hapusSatu(riwayat['key']), background: Container( alignment: Alignment.centerRight, padding: const EdgeInsets.only(right: 20), margin: const EdgeInsets.only(bottom: 15), decoration: BoxDecoration( color: Colors.red, borderRadius: BorderRadius.circular(20), ), child: const Icon(Icons.delete, color: Colors.white), ), child: _buildHistoryCard(riwayat), ); }, ), ), ), ], ), ), // NAVBAR bottomNavigationBar: BottomNavigationBar( currentIndex: 1, selectedItemColor: const Color(0xFF1565C0), unselectedItemColor: Colors.grey, type: BottomNavigationBarType.fixed, onTap: (index) { if (index == 0) { Navigator.pushReplacement( context, MaterialPageRoute(builder: (context) => const DashboardPage()), ); } else if (index == 2) { Navigator.pushReplacement( context, MaterialPageRoute(builder: (context) => const NotifikasiPage()), ); } else if (index == 3) { Navigator.pushReplacement( context, MaterialPageRoute(builder: (context) => const AkunPage()), ); } }, items: const [ BottomNavigationBarItem(icon: Icon(Icons.home), label: "Home"), BottomNavigationBarItem(icon: Icon(Icons.history), label: "History"), BottomNavigationBarItem(icon: Icon(Icons.notifications), label: "Notif"), BottomNavigationBarItem(icon: Icon(Icons.person), label: "Akun"), ], ), ); } Widget _buildFilterDropdown() { return Container( margin: const EdgeInsets.symmetric(vertical: 12, horizontal: 20), padding: const EdgeInsets.symmetric(horizontal: 16), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(15), boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.06), blurRadius: 8, offset: const Offset(0, 3), ), ], ), child: DropdownButtonHideUnderline( child: DropdownButton( value: selectedFilter, isExpanded: true, icon: const Icon(Icons.arrow_drop_down_circle_outlined, color: Color(0xFF1565C0)), style: const TextStyle( color: Colors.black87, fontSize: 15, fontWeight: FontWeight.w600, ), dropdownColor: Colors.white, borderRadius: BorderRadius.circular(15), onChanged: (String? newValue) { if (newValue != null) { setState(() { selectedFilter = newValue; }); } }, items: const [ DropdownMenuItem( value: "Semua", child: Row( children: [ Icon(Icons.restaurant_menu, color: Color(0xFF1565C0), size: 20), SizedBox(width: 10), Text("Semua Makanan"), ], ), ), DropdownMenuItem( value: "Mie Ayam", child: Row( children: [ Icon(Icons.ramen_dining, color: Color(0xFF1565C0), size: 20), SizedBox(width: 10), Text("Mie Ayam"), ], ), ), DropdownMenuItem( value: "Bakso", child: Row( children: [ Icon(Icons.soup_kitchen, color: Color(0xFF1565C0), size: 20), SizedBox(width: 10), Text("Bakso"), ], ), ), DropdownMenuItem( value: "Air Mineral", child: Row( children: [ Icon(Icons.local_drink_rounded, color: Color(0xFF1565C0), size: 20), SizedBox(width: 10), Text("Air Mineral"), ], ), ), ], ), ), ); } Widget _buildStatCard(String label, String value, Color themeColor, IconData icon) { return Container( padding: const EdgeInsets.symmetric(vertical: 16, horizontal: 10), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(20), border: Border.all( color: themeColor.withOpacity(0.12), width: 1.5, ), boxShadow: [ BoxShadow( color: themeColor.withOpacity(0.06), blurRadius: 10, offset: const Offset(0, 4), ), ], ), child: Column( children: [ Container( padding: const EdgeInsets.all(8), decoration: BoxDecoration( color: themeColor.withOpacity(0.1), shape: BoxShape.circle, ), child: Icon( icon, color: themeColor, size: 20, ), ), const SizedBox(height: 10), Text( value, style: TextStyle( fontSize: 22, fontWeight: FontWeight.bold, color: themeColor, ), ), const SizedBox(height: 2), Text( label, style: TextStyle( fontSize: 11, fontWeight: FontWeight.w600, color: Colors.grey.shade600, letterSpacing: 0.2, ), ), ], ), ); } Widget _buildHistoryCard(Map data) { String status = data["status"]; Color statusColor = getStatusColor(status); return Container( margin: const EdgeInsets.only(bottom: 15), padding: const EdgeInsets.all(15), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(20), boxShadow: const [BoxShadow(color: Colors.black12, blurRadius: 5)], ), child: Row( children: [ Icon( status == "Berbahaya" ? Icons.warning_rounded : (status == "Formalin Sedang" ? Icons.info_outline : Icons.check_circle_rounded), color: statusColor, size: 30, ), const SizedBox(width: 15), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( data["nama"], style: const TextStyle( fontWeight: FontWeight.bold, fontSize: 16), ), const SizedBox(height: 4), Text( "${data["tanggal"]} • ${data["jam"]}", style: const TextStyle(color: Colors.grey, fontSize: 12), ), ], ), ), Column( crossAxisAlignment: CrossAxisAlignment.end, children: [ Text( "${data["ppm"].toStringAsFixed(2)} PPM", style: const TextStyle(fontWeight: FontWeight.bold), ), const SizedBox(height: 5), Container( padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), decoration: BoxDecoration( color: statusColor, borderRadius: BorderRadius.circular(10), ), child: Text( status, style: const TextStyle( color: Colors.white, fontSize: 10, fontWeight: FontWeight.bold), ), ), ], ), ], ), ); } }