import 'package:flutter/material.dart'; import 'package:firebase_database/firebase_database.dart'; class RFIDManagerPage extends StatefulWidget { const RFIDManagerPage({super.key}); @override State createState() => _RFIDManagerPageState(); } class _RFIDManagerPageState extends State { final nameController = TextEditingController(); String currentUID = ""; bool isScanning = false; final db = FirebaseDatabase.instance.ref(); // 🎨 THEME GLOBAL (KONSISTEN APP) static const Color primaryColor = Color(0xff4E7C34); static const Color secondaryColor = Color(0xff6A994E); static const Color backgroundColor = Color(0xffFFF8E8); @override void initState() { super.initState(); db.child("rfid/uid").onValue.listen((event) { final data = event.snapshot.value; if (data != null) { final uid = data.toString().toLowerCase().trim(); setState(() { currentUID = uid; }); if (isScanning && nameController.text.isNotEmpty) { saveCardAuto(uid); } } }); } Future saveCardAuto(String uid) async { final snapshot = await db.child("cards/$uid").get(); if (snapshot.exists) { ScaffoldMessenger.of( context, ).showSnackBar(const SnackBar(content: Text("Kartu sudah terdaftar"))); return; } await db.child("cards").child(uid).set({ "uid": uid, "name": nameController.text.trim(), "nilai": 0, }); ScaffoldMessenger.of( context, ).showSnackBar(const SnackBar(content: Text("Kartu berhasil didaftarkan"))); setState(() { isScanning = false; currentUID = ""; }); nameController.clear(); } Future deleteCard(String uid) async { await db.child("cards").child(uid).remove(); ScaffoldMessenger.of( context, ).showSnackBar(const SnackBar(content: Text("Kartu berhasil dihapus"))); } @override Widget build(BuildContext context) { return Scaffold( backgroundColor: backgroundColor, // 🔥 APPBAR appBar: AppBar( backgroundColor: primaryColor, foregroundColor: Colors.white, elevation: 2, title: const Text("Manajemen RFID"), centerTitle: true, ), body: Column( children: [ // 🔥 FORM CARD Padding( padding: const EdgeInsets.all(16), child: Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(16), boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.05), blurRadius: 10, ), ], ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text( "Tambah Kartu Siswa", style: TextStyle( fontSize: 18, fontWeight: FontWeight.bold, color: primaryColor, ), ), const SizedBox(height: 16), // 🔥 RFID CARD Container( width: double.infinity, padding: const EdgeInsets.all(20), decoration: BoxDecoration( gradient: const LinearGradient( colors: [primaryColor, secondaryColor], ), borderRadius: BorderRadius.circular(20), boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.15), blurRadius: 12, offset: const Offset(0, 5), ), ], ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ const Text( "RFID CARD", style: TextStyle( color: Colors.white70, fontSize: 14, letterSpacing: 1.5, ), ), const Icon( Icons.credit_card, color: Colors.white70, ), ], ), const SizedBox(height: 25), Text( currentUID.isEmpty ? "Tap kartu untuk scan" : currentUID.toUpperCase(), style: const TextStyle( color: Colors.white, fontSize: 18, fontWeight: FontWeight.bold, letterSpacing: 2, ), ), const SizedBox(height: 20), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( isScanning ? "SCANNING..." : "READY", style: TextStyle( color: isScanning ? Colors.yellow : Colors.white70, fontWeight: FontWeight.bold, ), ), const Icon( Icons.wifi_tethering, color: Colors.white70, ), ], ), ], ), ), const SizedBox(height: 20), TextField( controller: nameController, decoration: InputDecoration( labelText: "Nama Siswa", labelStyle: const TextStyle(color: primaryColor), focusedBorder: OutlineInputBorder( borderSide: const BorderSide(color: primaryColor), borderRadius: BorderRadius.circular(12), ), border: OutlineInputBorder( borderRadius: BorderRadius.circular(12), ), ), ), const SizedBox(height: 16), SizedBox( width: double.infinity, child: ElevatedButton( style: ElevatedButton.styleFrom( backgroundColor: primaryColor, minimumSize: const Size.fromHeight(50), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(14), ), ), onPressed: () { if (nameController.text.isEmpty) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text("Isi nama dulu")), ); return; } setState(() { isScanning = true; }); ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text("Silakan scan kartu")), ); }, child: const Text( "Scan Kartu", style: TextStyle(color: Colors.white), ), ), ), ], ), ), ), const Padding( padding: EdgeInsets.symmetric(horizontal: 16), child: Align( alignment: Alignment.centerLeft, child: Text( "Daftar Kartu", style: TextStyle( fontSize: 18, fontWeight: FontWeight.bold, color: primaryColor, ), ), ), ), const SizedBox(height: 10), // 🔥 LIST Expanded( child: StreamBuilder( stream: db.child("cards").onValue, builder: (context, snapshot) { if (!snapshot.hasData || snapshot.data!.snapshot.value == null) { return const Center(child: Text("Belum ada kartu")); } final cards = Map.from( snapshot.data!.snapshot.value as Map, ); final entries = cards.entries.toList(); return ListView.builder( padding: const EdgeInsets.all(16), itemCount: entries.length, itemBuilder: (context, index) { final uid = entries[index].key; final card = Map.from( entries[index].value, ); return Container( margin: const EdgeInsets.only(bottom: 12), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(16), boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.05), blurRadius: 8, ), ], ), child: ListTile( leading: Container( width: 44, height: 44, decoration: BoxDecoration( gradient: const LinearGradient( colors: [primaryColor, secondaryColor], ), borderRadius: BorderRadius.circular(12), ), child: const Icon(Icons.person, color: Colors.white), ), title: Text(card["name"] ?? "-"), subtitle: Text("UID: $uid"), trailing: IconButton( icon: const Icon(Icons.delete, color: Colors.red), onPressed: () => deleteCard(uid), ), ), ); }, ); }, ), ), ], ), ); } }