187 lines
5.9 KiB
Dart
187 lines
5.9 KiB
Dart
import 'package:cloud_firestore/cloud_firestore.dart';
|
|
import 'package:firebase_database/firebase_database.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
|
|
import 'servo_button.dart';
|
|
import 'history_item.dart';
|
|
|
|
class DashboardScreen extends StatefulWidget {
|
|
const DashboardScreen({super.key});
|
|
|
|
@override
|
|
State<DashboardScreen> createState() => _DashboardScreenState();
|
|
}
|
|
|
|
class _DashboardScreenState extends State<DashboardScreen> {
|
|
final DatabaseReference servoRef = FirebaseDatabase.instance.ref('servo/');
|
|
final DatabaseReference statusRef = FirebaseDatabase.instance.ref(
|
|
'Gambar/status/',
|
|
);
|
|
final DatabaseReference urlGambarRef = FirebaseDatabase.instance.ref(
|
|
'Gambar/url/',
|
|
);
|
|
|
|
final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
|
|
FlutterLocalNotificationsPlugin();
|
|
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
initNotifications();
|
|
listenToStatus();
|
|
}
|
|
|
|
Future<void> initNotifications() async {
|
|
const AndroidInitializationSettings initializationSettingsAndroid =
|
|
AndroidInitializationSettings('@mipmap/ic_launcher');
|
|
|
|
const InitializationSettings initializationSettings =
|
|
InitializationSettings(android: initializationSettingsAndroid);
|
|
|
|
await flutterLocalNotificationsPlugin.initialize(initializationSettings);
|
|
}
|
|
|
|
Future<void> showNotification() async {
|
|
const AndroidNotificationDetails androidPlatformChannelSpecifics =
|
|
AndroidNotificationDetails(
|
|
'deteksi_channel',
|
|
'Deteksi Objek',
|
|
channelDescription: 'Notifikasi saat objek terdeteksi',
|
|
importance: Importance.max,
|
|
priority: Priority.high,
|
|
showWhen: true,
|
|
);
|
|
|
|
const NotificationDetails platformChannelSpecifics = NotificationDetails(
|
|
android: androidPlatformChannelSpecifics,
|
|
);
|
|
|
|
await flutterLocalNotificationsPlugin.show(
|
|
0,
|
|
'Notifikasi',
|
|
'ADA PAKETT!!!!!',
|
|
platformChannelSpecifics,
|
|
);
|
|
}
|
|
|
|
void listenToStatus() {
|
|
statusRef.onValue.listen((event) async {
|
|
final status = event.snapshot.value;
|
|
if (status == true) {
|
|
final urlSnapshot = await urlGambarRef.get();
|
|
final url = urlSnapshot.value?.toString();
|
|
|
|
if (url != null && url.isNotEmpty) {
|
|
await FirebaseFirestore.instance.collection('history').add({
|
|
'timestamp': Timestamp.now(),
|
|
'imageUrl': url,
|
|
});
|
|
|
|
await showNotification();
|
|
await statusRef.set(false);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
void sendServoCommand(bool state) {
|
|
servoRef.set(state);
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Scaffold(
|
|
appBar: AppBar(title: const Text('Dashboard Paket')),
|
|
body: Padding(
|
|
padding: const EdgeInsets.all(16.0),
|
|
child: Column(
|
|
children: [
|
|
const Text(
|
|
'Tombol Manual Servo',
|
|
style: TextStyle(fontSize: 18, fontWeight: FontWeight.w600),
|
|
),
|
|
const SizedBox(height: 12),
|
|
Row(
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
children: [
|
|
ServoButton(
|
|
label: 'BUKA',
|
|
color: Colors.green,
|
|
onPressed: () => sendServoCommand(true),
|
|
),
|
|
const SizedBox(width: 20),
|
|
ServoButton(
|
|
label: 'TUTUP',
|
|
color: Colors.red,
|
|
onPressed: () => sendServoCommand(false),
|
|
),
|
|
],
|
|
),
|
|
const SizedBox(height: 30),
|
|
const Divider(thickness: 1.5),
|
|
const Align(
|
|
alignment: Alignment.centerLeft,
|
|
child: Text(
|
|
'Riwayat Paket',
|
|
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
|
|
),
|
|
),
|
|
const SizedBox(height: 10),
|
|
Expanded(
|
|
child: StreamBuilder<QuerySnapshot>(
|
|
stream:
|
|
FirebaseFirestore.instance
|
|
.collection('history')
|
|
.orderBy('timestamp', descending: true)
|
|
.snapshots(),
|
|
builder: (context, snapshot) {
|
|
if (!snapshot.hasData) {
|
|
return const Center(child: CircularProgressIndicator());
|
|
}
|
|
|
|
final docs = snapshot.data!.docs;
|
|
|
|
if (docs.isEmpty) {
|
|
return const Center(
|
|
child: Text(
|
|
'Belum ada riwayat paket.',
|
|
style: TextStyle(color: Colors.grey),
|
|
),
|
|
);
|
|
}
|
|
|
|
return ListView.separated(
|
|
itemCount: docs.length,
|
|
separatorBuilder:
|
|
(context, index) => const SizedBox(height: 8),
|
|
itemBuilder: (context, index) {
|
|
final data = docs[index].data() as Map<String, dynamic>;
|
|
return Card(
|
|
elevation: 3,
|
|
shape: RoundedRectangleBorder(
|
|
borderRadius: BorderRadius.circular(12),
|
|
),
|
|
child: Padding(
|
|
padding: const EdgeInsets.symmetric(
|
|
vertical: 10,
|
|
horizontal: 16,
|
|
),
|
|
child: HistoryItem(
|
|
timestamp:
|
|
(data['timestamp'] as Timestamp).toDate(),
|
|
imageUrl: data['imageUrl'] ?? '',
|
|
),
|
|
),
|
|
);
|
|
},
|
|
);
|
|
},
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|