TKK_E32231279/lib/screens/send_screen.dart

374 lines
11 KiB
Dart

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<SendScreen> createState() => _SendScreenState();
}
class _SendScreenState extends State<SendScreen> {
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<void> 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"),
),
),
],
),
),
);
}
}