TKK_E32230332/lib/pages/rfid_manager_page.dart

342 lines
11 KiB
Dart

import 'package:flutter/material.dart';
import 'package:firebase_database/firebase_database.dart';
class RFIDManagerPage extends StatefulWidget {
const RFIDManagerPage({super.key});
@override
State<RFIDManagerPage> createState() => _RFIDManagerPageState();
}
class _RFIDManagerPageState extends State<RFIDManagerPage> {
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<void> 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<void> 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<String, dynamic>.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<String, dynamic>.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),
),
),
);
},
);
},
),
),
],
),
);
}
}