305 lines
9.3 KiB
Dart
305 lines
9.3 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:firebase_database/firebase_database.dart';
|
|
import 'package:firebase_core/firebase_core.dart';
|
|
import 'package:tugas_akhir/screens/notifikasi_page.dart';
|
|
import 'dart:async';
|
|
|
|
import '../services/notif_service.dart';
|
|
|
|
/// 🔥 GLOBAL
|
|
String globalLastStatus = "";
|
|
DateTime? lastNotifTime;
|
|
|
|
class KontrolPage extends StatefulWidget {
|
|
const KontrolPage({super.key});
|
|
|
|
@override
|
|
State<KontrolPage> createState() => _KontrolPageState();
|
|
}
|
|
|
|
class _KontrolPageState extends State<KontrolPage> {
|
|
bool isManual = false;
|
|
|
|
late DatabaseReference db;
|
|
|
|
StreamSubscription<DatabaseEvent>? modeSubscription;
|
|
StreamSubscription<DatabaseEvent>? deteksiSubscription;
|
|
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
|
|
db = FirebaseDatabase.instanceFor(
|
|
app: Firebase.app(),
|
|
databaseURL:
|
|
"https://tugas-akhir-9947b-default-rtdb.asia-southeast1.firebasedatabase.app",
|
|
).ref();
|
|
|
|
// =================================================
|
|
// MODE MANUAL
|
|
// =================================================
|
|
modeSubscription = db.child("kontrol/mode").onValue.listen((event) {
|
|
final data = event.snapshot.value;
|
|
|
|
print("MODE DATA: $data");
|
|
|
|
if (data != null && mounted) {
|
|
setState(() {
|
|
isManual = data.toString() == "1";
|
|
});
|
|
}
|
|
});
|
|
|
|
// =================================================
|
|
// STATUS / NOTIFIKASI
|
|
// =================================================
|
|
deteksiSubscription = db.child("Kebun/Status").onValue.listen((event) {
|
|
final data = event.snapshot.value;
|
|
|
|
if (data == null) return;
|
|
|
|
String status = data.toString().trim().toLowerCase();
|
|
|
|
print("STATUS: $status");
|
|
|
|
// =============================================
|
|
// NOTIF HANYA SAAT BAHAYA
|
|
// =============================================
|
|
if (status == "bahaya" && !isManual) {
|
|
bool bolehNotif = false;
|
|
|
|
if (lastNotifTime == null) {
|
|
bolehNotif = true;
|
|
} else {
|
|
final selisih = DateTime.now().difference(lastNotifTime!);
|
|
|
|
if (selisih.inSeconds > 15) {
|
|
bolehNotif = true;
|
|
}
|
|
}
|
|
|
|
if (bolehNotif) {
|
|
lastNotifTime = DateTime.now();
|
|
|
|
NotifService.showNotif(
|
|
"⚠️ Hama Burung!",
|
|
"Burung terdeteksi di kebun",
|
|
);
|
|
}
|
|
}
|
|
|
|
globalLastStatus = status;
|
|
});
|
|
}
|
|
|
|
@override
|
|
void dispose() {
|
|
modeSubscription?.cancel();
|
|
deteksiSubscription?.cancel();
|
|
|
|
super.dispose();
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Scaffold(
|
|
appBar: AppBar(
|
|
title: const Text(
|
|
"Kontrol Alat",
|
|
style: TextStyle(color: Colors.white),
|
|
),
|
|
backgroundColor: const Color(0xFF6FCF97),
|
|
iconTheme: const IconThemeData(color: Colors.white),
|
|
actions: [
|
|
IconButton(
|
|
icon: const Icon(Icons.notifications),
|
|
onPressed: () {
|
|
Navigator.push(
|
|
context,
|
|
MaterialPageRoute(builder: (context) => const NotifikasiPage()),
|
|
);
|
|
},
|
|
),
|
|
],
|
|
),
|
|
|
|
body: Padding(
|
|
padding: const EdgeInsets.all(16),
|
|
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
|
|
children: [
|
|
// =========================================
|
|
// MODE SWITCH
|
|
// =========================================
|
|
Container(
|
|
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 14),
|
|
|
|
decoration: BoxDecoration(
|
|
color: const Color(0xFFBFD8C6),
|
|
borderRadius: BorderRadius.circular(12),
|
|
),
|
|
|
|
child: Row(
|
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
|
|
children: [
|
|
const Text("Mode Manual"),
|
|
|
|
Switch(
|
|
value: isManual,
|
|
|
|
onChanged: (value) async {
|
|
await db.child("kontrol/mode").set(value ? 1 : 0);
|
|
},
|
|
),
|
|
],
|
|
),
|
|
),
|
|
|
|
const SizedBox(height: 30),
|
|
|
|
const Text(
|
|
"Kontrol Perangkat",
|
|
style: TextStyle(fontWeight: FontWeight.bold),
|
|
),
|
|
|
|
const SizedBox(height: 15),
|
|
|
|
Row(
|
|
children: [
|
|
// =====================================
|
|
// SERVO -> SEKARANG: GERAKAN
|
|
// =====================================
|
|
Expanded(
|
|
child: GestureDetector(
|
|
onTap: isManual
|
|
? () async {
|
|
await db.child("kontrol/servo").set(1);
|
|
|
|
ScaffoldMessenger.of(context).showSnackBar(
|
|
const SnackBar(content: Text("Servo Aktif")),
|
|
);
|
|
}
|
|
: null,
|
|
|
|
child: Container(
|
|
height: 100,
|
|
|
|
decoration: BoxDecoration(
|
|
color: isManual
|
|
? const Color(0xFF6FCF97)
|
|
: Colors.grey.shade400,
|
|
|
|
borderRadius: BorderRadius.circular(12),
|
|
boxShadow: isManual
|
|
? [
|
|
BoxShadow(
|
|
color: Colors.black12,
|
|
blurRadius: 4,
|
|
offset: const Offset(0, 2),
|
|
),
|
|
]
|
|
: [],
|
|
),
|
|
|
|
child: Column(
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
children: [
|
|
Icon(
|
|
Icons.screen_rotation_alt_rounded,
|
|
color: isManual
|
|
? Colors.white
|
|
: Colors.grey.shade600,
|
|
size: 32,
|
|
),
|
|
const SizedBox(height: 8),
|
|
Text(
|
|
"GERAKAN",
|
|
style: TextStyle(
|
|
color: isManual
|
|
? Colors.white
|
|
: Colors.grey.shade600,
|
|
fontWeight: FontWeight.bold,
|
|
letterSpacing: 1.2,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
),
|
|
|
|
const SizedBox(width: 16),
|
|
|
|
// =====================================
|
|
// BUZZER -> SEKARANG: SUARA
|
|
// =====================================
|
|
Expanded(
|
|
child: GestureDetector(
|
|
onTap: isManual
|
|
? () async {
|
|
await db.child("kontrol/buzzer").set(1);
|
|
|
|
ScaffoldMessenger.of(context).showSnackBar(
|
|
const SnackBar(content: Text("Buzzer Aktif")),
|
|
);
|
|
}
|
|
: null,
|
|
|
|
child: Container(
|
|
height: 100,
|
|
|
|
decoration: BoxDecoration(
|
|
color: isManual
|
|
? const Color(0xFF6FCF97)
|
|
: Colors.grey.shade400,
|
|
|
|
borderRadius: BorderRadius.circular(12),
|
|
boxShadow: isManual
|
|
? [
|
|
BoxShadow(
|
|
color: Colors.black12,
|
|
blurRadius: 4,
|
|
offset: const Offset(0, 2),
|
|
),
|
|
]
|
|
: [],
|
|
),
|
|
|
|
child: Column(
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
children: [
|
|
Icon(
|
|
Icons.volume_up_rounded,
|
|
color: isManual
|
|
? Colors.white
|
|
: Colors.grey.shade600,
|
|
size: 32,
|
|
),
|
|
const SizedBox(height: 8),
|
|
Text(
|
|
"SUARA",
|
|
style: TextStyle(
|
|
color: isManual
|
|
? Colors.white
|
|
: Colors.grey.shade600,
|
|
fontWeight: FontWeight.bold,
|
|
letterSpacing: 1.2,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|