319 lines
9.9 KiB
Dart
319 lines
9.9 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:firebase_database/firebase_database.dart';
|
|
import 'schedule_screen.dart';
|
|
|
|
class Dashboard extends StatefulWidget {
|
|
const Dashboard({super.key});
|
|
|
|
@override
|
|
State<Dashboard> createState() => _DashboardState();
|
|
}
|
|
|
|
class _DashboardState extends State<Dashboard> {
|
|
|
|
final DatabaseReference dbRef =
|
|
FirebaseDatabase.instance.ref();
|
|
|
|
double humidity = 0;
|
|
bool pumpOn = false;
|
|
bool scheduleWatering = false;
|
|
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
|
|
/// LISTEN KELEMBAPAN
|
|
dbRef.child("sht/humidity").onValue.listen((event) {
|
|
final value = event.snapshot.value;
|
|
if (value != null) {
|
|
setState(() {
|
|
humidity = double.parse(value.toString());
|
|
});
|
|
}
|
|
});
|
|
|
|
/// LISTEN STATUS POMPA MANUAL
|
|
dbRef.child("pump/status").onValue.listen((event) {
|
|
final value = event.snapshot.value;
|
|
if (value != null) {
|
|
setState(() {
|
|
pumpOn = value as bool;
|
|
});
|
|
}
|
|
});
|
|
|
|
/// LISTEN STATUS SCHEDULE
|
|
dbRef.child("schedules").onValue.listen((event) {
|
|
final data = event.snapshot.value;
|
|
|
|
bool watering = false;
|
|
|
|
if (data != null) {
|
|
Map schedules = data as Map;
|
|
|
|
for (var item in schedules.values) {
|
|
if (item["status"] == "watering") {
|
|
watering = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
setState(() {
|
|
scheduleWatering = watering;
|
|
});
|
|
});
|
|
}
|
|
|
|
/// TOGGLE POMPA KE DATABASE
|
|
Future<void> togglePump() async {
|
|
bool newStatus = !pumpOn;
|
|
|
|
setState(() {
|
|
pumpOn = newStatus;
|
|
});
|
|
|
|
await dbRef.child("pump/status").set(newStatus);
|
|
}
|
|
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
|
|
bool finalPumpStatus = pumpOn || scheduleWatering;
|
|
|
|
return SafeArea(
|
|
child: Column(
|
|
children: [
|
|
|
|
/// ================= HEADER =================
|
|
Container(
|
|
width: double.infinity,
|
|
padding: const EdgeInsets.all(20),
|
|
decoration: const BoxDecoration(
|
|
color: Color(0xFF34C759),
|
|
borderRadius: BorderRadius.only(
|
|
bottomLeft: Radius.circular(25),
|
|
bottomRight: Radius.circular(25),
|
|
),
|
|
),
|
|
child: Container(
|
|
padding: const EdgeInsets.all(20),
|
|
decoration: BoxDecoration(
|
|
color: Colors.grey[200],
|
|
borderRadius: BorderRadius.circular(20),
|
|
),
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
const Text(
|
|
"Menu Utama",
|
|
style: TextStyle(
|
|
fontSize: 20,
|
|
fontWeight: FontWeight.bold),
|
|
),
|
|
const SizedBox(height: 15),
|
|
|
|
GestureDetector(
|
|
onTap: () {
|
|
Navigator.push(
|
|
context,
|
|
MaterialPageRoute(
|
|
builder: (_) => const ScheduleScreen()),
|
|
);
|
|
},
|
|
child: Column(
|
|
children: const [
|
|
CircleAvatar(
|
|
radius: 20,
|
|
backgroundColor: Colors.white,
|
|
child: Icon(Icons.assignment, size: 20),
|
|
),
|
|
SizedBox(height: 5),
|
|
Text(
|
|
"Jadwal\nPenyiraman",
|
|
textAlign: TextAlign.center,
|
|
)
|
|
],
|
|
),
|
|
)
|
|
],
|
|
),
|
|
),
|
|
),
|
|
|
|
/// ================= CONTENT =================
|
|
Expanded(
|
|
child: SingleChildScrollView(
|
|
padding: const EdgeInsets.only(bottom: 120),
|
|
child: Column(
|
|
children: [
|
|
|
|
const SizedBox(height: 20),
|
|
|
|
const Padding(
|
|
padding: EdgeInsets.symmetric(horizontal: 20),
|
|
child: Align(
|
|
alignment: Alignment.centerLeft,
|
|
child: Text(
|
|
"Update Hari Ini!!",
|
|
style: TextStyle(
|
|
fontSize: 18,
|
|
fontWeight: FontWeight.bold),
|
|
),
|
|
),
|
|
),
|
|
|
|
const SizedBox(height: 15),
|
|
|
|
/// KELEMBAPAN REALTIME
|
|
_infoCard(
|
|
title: "Kelembapan",
|
|
trailing: "${humidity.toStringAsFixed(2)} %",
|
|
color: Colors.green,
|
|
),
|
|
|
|
const SizedBox(height: 15),
|
|
|
|
/// STATUS POMPA
|
|
Container(
|
|
margin:
|
|
const EdgeInsets.symmetric(horizontal: 20),
|
|
padding: const EdgeInsets.all(16),
|
|
decoration: BoxDecoration(
|
|
color: Colors.grey[300],
|
|
borderRadius: BorderRadius.circular(15),
|
|
boxShadow: const [
|
|
BoxShadow(
|
|
color: Colors.black26,
|
|
blurRadius: 4,
|
|
offset: Offset(0, 3),
|
|
)
|
|
],
|
|
),
|
|
child: Column(
|
|
crossAxisAlignment:
|
|
CrossAxisAlignment.start,
|
|
children: [
|
|
Row(
|
|
mainAxisAlignment:
|
|
MainAxisAlignment.spaceBetween,
|
|
children: [
|
|
const Text(
|
|
"Status Pompa",
|
|
style: TextStyle(
|
|
fontSize: 16,
|
|
fontWeight:
|
|
FontWeight.bold),
|
|
),
|
|
Container(
|
|
padding:
|
|
const EdgeInsets.symmetric(
|
|
horizontal: 14,
|
|
vertical: 6),
|
|
decoration: BoxDecoration(
|
|
color: finalPumpStatus
|
|
? Colors.green
|
|
: Colors.red,
|
|
borderRadius:
|
|
BorderRadius.circular(8),
|
|
),
|
|
child: Text(
|
|
finalPumpStatus ? "ON" : "OFF",
|
|
style: const TextStyle(
|
|
color: Colors.white,
|
|
fontWeight:
|
|
FontWeight.bold),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
const Divider(height: 25),
|
|
const Text(
|
|
"Menyalakan Pompa Manual",
|
|
style: TextStyle(
|
|
fontSize: 16,
|
|
fontWeight:
|
|
FontWeight.bold),
|
|
),
|
|
const SizedBox(height: 20),
|
|
Center(
|
|
child: GestureDetector(
|
|
onTap: togglePump,
|
|
child: Container(
|
|
width: 90,
|
|
height: 90,
|
|
decoration: BoxDecoration(
|
|
color: pumpOn
|
|
? Colors.green
|
|
: Colors.red,
|
|
shape: BoxShape.circle,
|
|
),
|
|
child: Center(
|
|
child: Text(
|
|
pumpOn ? "ON" : "OFF",
|
|
style:
|
|
const TextStyle(
|
|
color: Colors.white,
|
|
fontSize: 18,
|
|
fontWeight:
|
|
FontWeight.bold,
|
|
),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
)
|
|
],
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
)
|
|
],
|
|
),
|
|
);
|
|
}
|
|
|
|
Widget _infoCard({
|
|
required String title,
|
|
required String trailing,
|
|
required Color color,
|
|
}) {
|
|
return Container(
|
|
margin: const EdgeInsets.symmetric(horizontal: 20),
|
|
padding: const EdgeInsets.all(16),
|
|
decoration: BoxDecoration(
|
|
color: Colors.grey[300],
|
|
borderRadius: BorderRadius.circular(15),
|
|
),
|
|
child: Row(
|
|
mainAxisAlignment:
|
|
MainAxisAlignment.spaceBetween,
|
|
children: [
|
|
Text(title,
|
|
style: const TextStyle(
|
|
fontSize: 16,
|
|
fontWeight: FontWeight.bold)),
|
|
Container(
|
|
padding:
|
|
const EdgeInsets.symmetric(
|
|
horizontal: 12,
|
|
vertical: 6),
|
|
decoration: BoxDecoration(
|
|
color: color,
|
|
borderRadius:
|
|
BorderRadius.circular(8),
|
|
),
|
|
child: Text(trailing,
|
|
style: const TextStyle(
|
|
color: Colors.white,
|
|
fontWeight:
|
|
FontWeight.bold)),
|
|
)
|
|
],
|
|
),
|
|
);
|
|
}
|
|
} |