import 'package:flutter/material.dart'; import 'package:firebase_database/firebase_database.dart'; class SendScreen extends StatefulWidget { final String myRfid; const SendScreen({super.key, required this.myRfid}); @override State createState() => _SendScreenState(); } class _SendScreenState extends State { final rfidController = TextEditingController(); final nominalController = TextEditingController(); bool loading = false; static const Color primaryColor = Color(0xFFA5CC36); // ========================= // KEYBOARD CUSTOM // ========================= void addNumber(String number) { setState(() { nominalController.text += number; }); } void backspace() { setState(() { if (nominalController.text.isNotEmpty) { nominalController.text = nominalController.text.substring( 0, nominalController.text.length - 1, ); } }); } void clearNominal() { setState(() { nominalController.clear(); }); } // ========================= // ERROR DIALOG // ========================= void _showErrorDialog(String pesan) { showDialog( context: context, builder: (_) => Dialog( shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(25)), child: Padding( padding: const EdgeInsets.all(25), child: Column( mainAxisSize: MainAxisSize.min, children: [ Container( width: 90, height: 90, decoration: const BoxDecoration( color: Colors.red, shape: BoxShape.circle, ), child: const Icon(Icons.close, size: 60, color: Colors.white), ), const SizedBox(height: 20), const Text( "Transfer Gagal", style: TextStyle(fontSize: 22, fontWeight: FontWeight.bold), ), const SizedBox(height: 10), Text(pesan, textAlign: TextAlign.center), const SizedBox(height: 20), SizedBox( width: double.infinity, child: ElevatedButton( onPressed: () => Navigator.pop(context), child: const Text("OK"), ), ), ], ), ), ), ); } // ========================= // SUCCESS DIALOG // ========================= void _showSuccessDialog(int nominal, String tujuan) { showDialog( context: context, barrierDismissible: false, builder: (_) => Dialog( shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(30)), child: Padding( padding: const EdgeInsets.all(25), child: Column( mainAxisSize: MainAxisSize.min, children: [ TweenAnimationBuilder( duration: const Duration(milliseconds: 700), tween: Tween(begin: 0.0, end: 1.0), builder: (context, value, child) { return Transform.scale( scale: value, child: Container( width: 100, height: 100, decoration: const BoxDecoration( color: Color(0xFFA5CC36), shape: BoxShape.circle, ), child: const Icon( Icons.check, size: 65, color: Colors.black, ), ), ); }, ), const SizedBox(height: 20), const Text( "Transfer Berhasil", style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold), ), const SizedBox(height: 10), Text( "Rp $nominal berhasil dikirim ke", textAlign: TextAlign.center, ), const SizedBox(height: 5), Text( tujuan, style: const TextStyle( fontWeight: FontWeight.bold, fontSize: 18, ), ), const SizedBox(height: 25), SizedBox( width: double.infinity, child: ElevatedButton( style: ElevatedButton.styleFrom( backgroundColor: primaryColor, foregroundColor: Colors.black, ), onPressed: () { Navigator.pop(context); Navigator.pop(context); }, child: const Text("SELESAI"), ), ), ], ), ), ), ); } // ========================= // TRANSFER LOGIC // ========================= Future kirimSaldo() async { final tujuan = rfidController.text.trim(); final nominal = int.tryParse(nominalController.text) ?? 0; if (tujuan.isEmpty) { _showErrorDialog("RFID tujuan wajib diisi"); return; } if (tujuan == widget.myRfid) { _showErrorDialog("Tidak dapat transfer ke akun sendiri"); return; } if (nominal < 1000) { _showErrorDialog("Minimal transfer Rp1.000"); return; } setState(() => loading = true); try { final db = FirebaseDatabase.instance.ref(); final pengirimSnap = await db.child("users/${widget.myRfid}").get(); final penerimaSnap = await db.child("users/$tujuan").get(); if (!penerimaSnap.exists) { _showErrorDialog("RFID tujuan tidak ditemukan"); return; } final saldoPengirim = (pengirimSnap.child("saldo").value as num?)?.toInt() ?? 0; final saldoPenerima = (penerimaSnap.child("saldo").value as num?)?.toInt() ?? 0; if (saldoPengirim < nominal) { _showErrorDialog("Saldo tidak mencukupi"); return; } await db .child("users/${widget.myRfid}/saldo") .set(saldoPengirim - nominal); await db.child("users/$tujuan/saldo").set(saldoPenerima + nominal); final now = DateTime.now().toIso8601String(); await db.child("users/${widget.myRfid}/history").push().set({ "type": "transfer_keluar", "nilai": nominal, "tujuan": tujuan, "waktu": now, }); await db.child("users/$tujuan/history").push().set({ "type": "transfer_masuk", "nilai": nominal, "dari": widget.myRfid, "waktu": now, }); if (!mounted) return; _showSuccessDialog(nominal, tujuan); } catch (e) { _showErrorDialog(e.toString()); } finally { setState(() => loading = false); } } // ========================= // KEYPAD UI // ========================= Widget buildKeypad() { return Column( mainAxisAlignment: MainAxisAlignment.center, children: [ for (var row in [ ["1", "2", "3"], ["4", "5", "6"], ["7", "8", "9"], ["C", "0", "⌫"], ]) Padding( padding: const EdgeInsets.symmetric(vertical: 4), child: Row( children: row.map((e) { final bool isAction = e == "C" || e == "⌫"; return Expanded( child: Padding( padding: const EdgeInsets.symmetric(horizontal: 5), child: SizedBox( height: 60, // 🔥 penting: biar tidak terlalu tinggi child: ElevatedButton( style: ElevatedButton.styleFrom( backgroundColor: isAction ? (e == "C" ? Colors.redAccent : Colors.orangeAccent) : const Color(0xFF2C2C2C), foregroundColor: Colors.white, elevation: 2, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(14), side: const BorderSide(color: Color(0xFF3A3A3A)), ), ), onPressed: () { if (e == "C") { clearNominal(); } else if (e == "⌫") { backspace(); } else { addNumber(e); } }, child: Text( e, style: const TextStyle( fontSize: 22, fontWeight: FontWeight.bold, ), ), ), ), ), ); }).toList(), ), ), ], ); } @override Widget build(BuildContext context) { return Scaffold( backgroundColor: const Color(0xFF0B1600), appBar: AppBar( backgroundColor: primaryColor, title: const Text("Kirim Saldo"), ), body: Padding( padding: const EdgeInsets.all(20), child: Column( children: [ TextField( controller: rfidController, style: const TextStyle(color: Colors.white), decoration: const InputDecoration( labelText: "RFID UID Tujuan", labelStyle: TextStyle(color: Colors.white70), ), ), const SizedBox(height: 20), Container( width: double.infinity, padding: const EdgeInsets.all(15), decoration: BoxDecoration( color: const Color(0xFF1A1A1A), borderRadius: BorderRadius.circular(12), ), child: Text( nominalController.text.isEmpty ? "Rp 0" : "Rp ${nominalController.text}", style: const TextStyle( color: Colors.white, fontSize: 28, fontWeight: FontWeight.bold, ), ), ), const SizedBox(height: 20), Expanded(child: buildKeypad()), SizedBox( width: double.infinity, height: 55, child: ElevatedButton( style: ElevatedButton.styleFrom(backgroundColor: primaryColor), onPressed: loading ? null : kirimSaldo, child: loading ? const CircularProgressIndicator(color: Colors.black) : const Text("Kirim"), ), ), ], ), ), ); } }