158 lines
5.5 KiB
Dart
158 lines
5.5 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:fl_chart/fl_chart.dart';
|
|
import '../services/supabase_service.dart';
|
|
|
|
class AnalyticsScreen extends StatefulWidget {
|
|
const AnalyticsScreen({super.key});
|
|
|
|
@override
|
|
State<AnalyticsScreen> createState() => _AnalyticsScreenState();
|
|
}
|
|
|
|
class _AnalyticsScreenState extends State<AnalyticsScreen> {
|
|
List<Map<String, dynamic>> _logs = [];
|
|
bool _isLoading = true;
|
|
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
_fetchLogs();
|
|
}
|
|
|
|
Future<void> _fetchLogs() async {
|
|
try {
|
|
final data = await SupabaseService().getFotoDataset();
|
|
setState(() {
|
|
_logs = data;
|
|
_isLoading = false;
|
|
});
|
|
} catch (e) {
|
|
debugPrint('Error fetching logs: $e');
|
|
setState(() => _isLoading = false);
|
|
}
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final args = (ModalRoute.of(context)?.settings.arguments as Map<String, dynamic>?) ?? {};
|
|
final String title = args['title'] ?? 'Grafik';
|
|
final Color color = args['color'] ?? Colors.green;
|
|
final String sensorKey = title.contains('Suhu') ? 'suhu' : title.contains('Kelembaban') ? 'kelembapan' : 'intensitas';
|
|
|
|
return Scaffold(
|
|
backgroundColor: Colors.black,
|
|
appBar: AppBar(
|
|
backgroundColor: Colors.black,
|
|
title: Text(title, style: const TextStyle(color: Colors.white)),
|
|
leading: IconButton(
|
|
icon: const Icon(Icons.arrow_back, color: Colors.grey),
|
|
onPressed: () => Navigator.pop(context),
|
|
),
|
|
),
|
|
body: _isLoading
|
|
? const Center(child: CircularProgressIndicator(color: Colors.green))
|
|
: Padding(
|
|
padding: const EdgeInsets.all(20.0),
|
|
child: Column(
|
|
children: [
|
|
_buildChartCard(title, color, _logs, sensorKey),
|
|
const SizedBox(height: 20),
|
|
Row(
|
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
children: [
|
|
const Text('Riwayat Data', style: TextStyle(color: Colors.white, fontSize: 18, fontWeight: FontWeight.bold)),
|
|
IconButton(icon: const Icon(Icons.refresh, color: Colors.green), onPressed: _fetchLogs),
|
|
],
|
|
),
|
|
const SizedBox(height: 10),
|
|
Expanded(
|
|
child: Container(
|
|
decoration: BoxDecoration(
|
|
color: const Color(0xFF1A1A1A),
|
|
borderRadius: BorderRadius.circular(20),
|
|
),
|
|
child: ListView.separated(
|
|
padding: const EdgeInsets.all(15),
|
|
itemCount: _logs.length,
|
|
separatorBuilder: (context, index) => const Divider(color: Colors.grey),
|
|
itemBuilder: (context, index) {
|
|
final log = _logs[index];
|
|
return Padding(
|
|
padding: const EdgeInsets.symmetric(vertical: 8.0),
|
|
child: Row(
|
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
children: [
|
|
Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Text(log['timestamp'] ?? '', style: const TextStyle(color: Colors.grey, fontSize: 10)),
|
|
Text('Fans: ${log['kipas1']}/${log['kipas2']}', style: const TextStyle(color: Colors.green, fontSize: 10)),
|
|
],
|
|
),
|
|
Text('${log[sensorKey]}', style: TextStyle(color: color, fontWeight: FontWeight.bold)),
|
|
],
|
|
),
|
|
);
|
|
},
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
Widget _buildChartCard(String title, Color color, List<Map<String, dynamic>> logs, String key) {
|
|
List<FlSpot> spots = [];
|
|
if (logs.isNotEmpty) {
|
|
final reversedLogs = logs.reversed.toList();
|
|
for (int i = 0; i < reversedLogs.length; i++) {
|
|
spots.add(FlSpot(i.toDouble(), double.tryParse(reversedLogs[i][key].toString()) ?? 0));
|
|
}
|
|
}
|
|
|
|
return Container(
|
|
height: 250,
|
|
padding: const EdgeInsets.all(20),
|
|
decoration: BoxDecoration(
|
|
color: const Color(0xFF1A1A1A),
|
|
borderRadius: BorderRadius.circular(20),
|
|
),
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Text(title, style: const TextStyle(color: Colors.white, fontWeight: FontWeight.bold)),
|
|
const SizedBox(height: 20),
|
|
Expanded(
|
|
child: LineChart(
|
|
LineChartData(
|
|
gridData: FlGridData(show: false),
|
|
titlesData: FlTitlesData(show: false),
|
|
borderData: FlBorderData(show: false),
|
|
lineBarsData: [
|
|
LineChartBarData(
|
|
spots: spots.isEmpty ? [const FlSpot(0, 0)] : spots,
|
|
isCurved: true,
|
|
color: color,
|
|
barWidth: 4,
|
|
dotData: FlDotData(show: false),
|
|
belowBarData: BarAreaData(show: true, color: color.withOpacity(0.1)),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
Align(
|
|
alignment: Alignment.bottomRight,
|
|
child: Text(
|
|
'Terakhir: ${logs.isNotEmpty ? logs.first[key] : "-"}',
|
|
style: TextStyle(color: color, fontSize: 12)
|
|
),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
}
|