From 345c2c34f652f3633532fd55f121c7dc6ce5936c Mon Sep 17 00:00:00 2001 From: kleponijo <158453666+kleponijo@users.noreply.github.com> Date: Sat, 9 May 2026 15:45:15 +0700 Subject: [PATCH] oke --- lib/screens/home/views/home_screen.dart | 15 ++ .../evaporasi/blocs/evaporasi_bloc.dart | 47 ++-- .../evaporasi/blocs/evaporasi_state.dart | 18 +- .../evaporasi/views/evaporasi_screen.dart | 40 ++- .../views/widgets/evaporasi_chart_widget.dart | 250 ------------------ pubspec.lock | 16 -- 6 files changed, 52 insertions(+), 334 deletions(-) delete mode 100644 lib/screens/monitoring/evaporasi/views/widgets/evaporasi_chart_widget.dart diff --git a/lib/screens/home/views/home_screen.dart b/lib/screens/home/views/home_screen.dart index a495092..1a831fb 100644 --- a/lib/screens/home/views/home_screen.dart +++ b/lib/screens/home/views/home_screen.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:monitoring_repository/monitoring_repository.dart'; import '../../../blocs/authentication_bloc/authentication_bloc.dart'; +<<<<<<< HEAD import '../../../blocs/notification_bloc/notification_bloc.dart'; import '../../monitoring/wind_speed/blocs/wind_speed_bloc.dart'; import '../../monitoring/evaporasi/blocs/evaporasi_bloc.dart'; @@ -9,6 +10,8 @@ import '../../monitoring/atmospheric_conditions/blocs/atmospheric_conditions_blo import '../widgets/notification_panel.dart'; import '../widgets/sensor_grid.dart'; import '../widgets/dashboard_charts.dart'; +======= +>>>>>>> parent of 6f38d3b (update evaporsi) import 'main_drawer.dart'; class HomeScreen extends StatefulWidget { @@ -97,6 +100,7 @@ class _HomeScreenState extends State height: 90, fit: BoxFit.contain, ), +<<<<<<< HEAD actions: [ // Icon lonceng dengan badge BlocBuilder( @@ -174,6 +178,17 @@ class _HomeScreenState extends State ), ), ], +======= + const SizedBox(width: 10), + ], + ), + actions: [ + IconButton( + icon: const Icon(Icons.notifications_none, color: Colors.black), + onPressed: () { + // Aksi notifikasi + }, +>>>>>>> parent of 6f38d3b (update evaporsi) ), ), ), diff --git a/lib/screens/monitoring/evaporasi/blocs/evaporasi_bloc.dart b/lib/screens/monitoring/evaporasi/blocs/evaporasi_bloc.dart index 32cee33..8cf3748 100644 --- a/lib/screens/monitoring/evaporasi/blocs/evaporasi_bloc.dart +++ b/lib/screens/monitoring/evaporasi/blocs/evaporasi_bloc.dart @@ -4,7 +4,10 @@ import 'package:equatable/equatable.dart'; import 'package:monitoring_repository/monitoring_repository.dart'; import '../../../../core/utils/time_series_mapper.dart'; +<<<<<<< HEAD import '../../../../blocs/notification_bloc/notification_bloc.dart'; +======= +>>>>>>> parent of 6f38d3b (update evaporsi) part 'evaporasi_event.dart'; part 'evaporasi_state.dart'; @@ -44,9 +47,10 @@ class EvaporasiBloc extends Bloc { final dailyGraph = TimeSeriesMapper.toDaily( data: history, getTime: (e) => e.timestamp, - getValue: (e) => e.evaporasi, + getValue: (e) => e.evaporasi, // ⚠️ sesuaikan nama field ); +<<<<<<< HEAD final dailyTempGraph = TimeSeriesMapper.toDaily( data: history, getTime: (e) => e.timestamp, @@ -58,12 +62,11 @@ class EvaporasiBloc extends Bloc { final (status, rain) = _computeWeatherStatus(lastValue); _emitEvaporasiAlert(status, rain, lastValue); +======= +>>>>>>> parent of 6f38d3b (update evaporsi) emit(state.copyWith( history: history, dailyValues: dailyGraph, - dailyTemperatures: dailyTempGraph, - weatherStatus: status, - willRain: rain, isLoading: false, )); @@ -81,25 +84,28 @@ class EvaporasiBloc extends Bloc { Emitter emit, ) { final updated = List.from(state.dailyValues); +<<<<<<< HEAD final updatedTemp = List.from(state.dailyTemperatures); +======= + +>>>>>>> parent of 6f38d3b (update evaporsi) final index = DateTime.now().hour; if (index < updated.length) { - updated[index] = event.data.evaporasi; - updatedTemp[index] = event.data.suhu; + updated[index] = event.data.evaporasi; // ⚠️ sesuaikan field } +<<<<<<< HEAD final (status, rain) = _computeWeatherStatus(event.data.evaporasi); _emitEvaporasiAlert(status, rain, event.data.evaporasi); +======= +>>>>>>> parent of 6f38d3b (update evaporsi) emit(state.copyWith( currentValue: event.data.evaporasi, temperature: event.data.suhu, waterLevel: event.data.tinggiAir, dailyValues: updated, - dailyTemperatures: updatedTemp, - weatherStatus: status, - willRain: rain, )); } @@ -114,7 +120,6 @@ class EvaporasiBloc extends Bloc { final history = state.history; List updated; - List updatedTemp; if (event.period == "Minggu Ini") { updated = TimeSeriesMapper.toWeekly( @@ -122,39 +127,26 @@ class EvaporasiBloc extends Bloc { getTime: (e) => e.timestamp, getValue: (e) => e.evaporasi, ); - updatedTemp = TimeSeriesMapper.toWeekly( - data: history, - getTime: (e) => e.timestamp, - getValue: (e) => e.suhu, - ); } else if (event.period == "Bulan Ini") { updated = TimeSeriesMapper.toMonthly( data: history, getTime: (e) => e.timestamp, getValue: (e) => e.evaporasi, ); - updatedTemp = TimeSeriesMapper.toMonthly( - data: history, - getTime: (e) => e.timestamp, - getValue: (e) => e.suhu, - ); } else { updated = TimeSeriesMapper.toDaily( data: history, getTime: (e) => e.timestamp, getValue: (e) => e.evaporasi, ); - updatedTemp = TimeSeriesMapper.toDaily( - data: history, - getTime: (e) => e.timestamp, - getValue: (e) => e.suhu, - ); } +<<<<<<< HEAD // Pertahankan status cuaca saat ini (tidak berubah karena hanya ganti periode) +======= +>>>>>>> parent of 6f38d3b (update evaporsi) emit(state.copyWith( dailyValues: updated, - dailyTemperatures: updatedTemp, isLoading: false, )); } @@ -215,6 +207,7 @@ class EvaporasiBloc extends Bloc { await _subscription?.cancel(); return super.close(); } +<<<<<<< HEAD /// ========================= /// 🌤️ HELPER: Status Cuaca @@ -252,6 +245,8 @@ class EvaporasiBloc extends Bloc { ), )); } +======= +>>>>>>> parent of 6f38d3b (update evaporsi) } /// INTERNAL EVENT diff --git a/lib/screens/monitoring/evaporasi/blocs/evaporasi_state.dart b/lib/screens/monitoring/evaporasi/blocs/evaporasi_state.dart index 640d2dd..72e4a5c 100644 --- a/lib/screens/monitoring/evaporasi/blocs/evaporasi_state.dart +++ b/lib/screens/monitoring/evaporasi/blocs/evaporasi_state.dart @@ -10,13 +10,9 @@ class EvaporasiState extends Equatable { final DateTime? selectedDate; // tanggal spesifik untuk custom date final EvaporasiViewMode viewMode; // period vs custom date - final List dailyValues; // untuk grafik evaporasi - final List dailyTemperatures; // untuk grafik suhu + final List dailyValues; // untuk grafik final List history; - final String weatherStatus; // Baik / Sedang / Buruk - final bool willRain; // true jika status Sedang/Buruk - final bool isLoading; const EvaporasiState({ @@ -27,10 +23,7 @@ class EvaporasiState extends Equatable { this.selectedDate, this.viewMode = EvaporasiViewMode.period, this.dailyValues = const [], - this.dailyTemperatures = const [], this.history = const [], - this.weatherStatus = "Baik", - this.willRain = false, this.isLoading = true, }); @@ -42,10 +35,7 @@ EvaporasiState copyWith({ DateTime? selectedDate, EvaporasiViewMode? viewMode, List? dailyValues, - List? dailyTemperatures, List? history, - String? weatherStatus, - bool? willRain, bool? isLoading, }) { return EvaporasiState( @@ -56,10 +46,7 @@ EvaporasiState copyWith({ selectedDate: selectedDate ?? this.selectedDate, viewMode: viewMode ?? this.viewMode, dailyValues: dailyValues ?? this.dailyValues, - dailyTemperatures: dailyTemperatures ?? this.dailyTemperatures, history: history ?? this.history, - weatherStatus: weatherStatus ?? this.weatherStatus, - willRain: willRain ?? this.willRain, isLoading: isLoading ?? this.isLoading, ); } @@ -73,10 +60,7 @@ EvaporasiState copyWith({ selectedDate, viewMode, dailyValues, - dailyTemperatures, history, - weatherStatus, - willRain, isLoading, ]; } diff --git a/lib/screens/monitoring/evaporasi/views/evaporasi_screen.dart b/lib/screens/monitoring/evaporasi/views/evaporasi_screen.dart index eb3343a..8897ef1 100644 --- a/lib/screens/monitoring/evaporasi/views/evaporasi_screen.dart +++ b/lib/screens/monitoring/evaporasi/views/evaporasi_screen.dart @@ -2,8 +2,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:intl/intl.dart'; import '../blocs/evaporasi_bloc.dart'; -import 'widgets/evaporasi_chart_widget.dart'; -import 'widgets/evaporasi_period_selector.dart'; import '../../shared/utils/pdf/pdf_export_service.dart'; import '../../shared/widgets/export_pdf_button.dart'; @@ -47,6 +45,7 @@ class EvaporasiScreen extends StatelessWidget { const SizedBox(height: 25), _infoRow(state), const SizedBox(height: 25), +<<<<<<< HEAD _statusCard(state), const SizedBox(height: 25), const Text("Tren Evaporasi & Suhu", @@ -92,6 +91,9 @@ class EvaporasiScreen extends StatelessWidget { ); }, ), +======= + _trendSection(), +>>>>>>> parent of 6f38d3b (update evaporsi) const SizedBox(height: 25), ExportPdfButton( onExport: () => PdfExportService.evaporasi( @@ -193,36 +195,17 @@ class EvaporasiScreen extends StatelessWidget { } /// ========================= - /// 🌤️ STATUS CARD + /// 📈 TREND (SIMPLE PLACEHOLDER) /// ========================= - Widget _statusCard(EvaporasiState state) { - Color statusColor; - IconData statusIcon; - - switch (state.weatherStatus) { - case "Sedang": - statusColor = Colors.orange; - statusIcon = Icons.warning_amber_rounded; - break; - case "Buruk": - statusColor = Colors.red; - statusIcon = Icons.error_outline; - break; - case "Baik": - default: - statusColor = Colors.green; - statusIcon = Icons.check_circle_outline; - break; - } - + Widget _trendSection() { return Container( width: double.infinity, - padding: const EdgeInsets.all(20), + height: 200, decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(20), - border: Border.all(color: statusColor.withOpacity(0.3), width: 1.5), ), +<<<<<<< HEAD child: Row( children: [ Icon(statusIcon, color: statusColor, size: 40), @@ -257,6 +240,13 @@ class EvaporasiScreen extends StatelessWidget { ), ), ], +======= + child: const Center( + child: Text( + "Grafik Evaporasi", + style: TextStyle(color: Colors.grey), + ), +>>>>>>> parent of 6f38d3b (update evaporsi) ), ); } diff --git a/lib/screens/monitoring/evaporasi/views/widgets/evaporasi_chart_widget.dart b/lib/screens/monitoring/evaporasi/views/widgets/evaporasi_chart_widget.dart deleted file mode 100644 index fe0a686..0000000 --- a/lib/screens/monitoring/evaporasi/views/widgets/evaporasi_chart_widget.dart +++ /dev/null @@ -1,250 +0,0 @@ -import 'package:fl_chart/fl_chart.dart'; -import 'package:flutter/material.dart'; - -class EvaporasiChartWidget extends StatelessWidget { - final List dailyValues; - final List dailyTemperatures; - final String period; - - const EvaporasiChartWidget({ - super.key, - required this.dailyValues, - required this.dailyTemperatures, - required this.period, - }); - - double _getMaxY(List data) { - if (data.isEmpty) return 10; - final max = data.reduce((a, b) => a > b ? a : b); - return (max + 5).clamp(10, 100); - } - - List _safeData(List data) { - return data.map((e) { - if (e.isNaN || e.isInfinite) return 0.0; - return e < 0 ? 0.0 : e; - }).toList(); - } - - @override - Widget build(BuildContext context) { - final safeValues = _safeData(dailyValues); - final safeTemps = _safeData(dailyTemperatures); - - // Gunakan max dari kedua dataset agar skala Y sesuai - final maxY = _getMaxY([ - ...safeValues, - ...safeTemps, - ]); - - return Container( - height: 280, - padding: const EdgeInsets.fromLTRB(10, 20, 20, 10), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(25), - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.05), - blurRadius: 10, - offset: const Offset(0, 5), - ) - ], - ), - child: Column( - children: [ - // Legend - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - _legendItem(Colors.blue.shade700, "Evaporasi (mm)"), - const SizedBox(width: 20), - _legendItem(Colors.orange.shade600, "Suhu (°C)"), - ], - ), - const SizedBox(height: 10), - Expanded( - child: LineChart( - duration: const Duration(milliseconds: 600), - curve: Curves.easeOutCubic, - LineChartData( - minY: 0, - maxY: maxY, - gridData: const FlGridData(show: false), - borderData: FlBorderData(show: false), - titlesData: FlTitlesData( - show: true, - rightTitles: const AxisTitles( - sideTitles: SideTitles(showTitles: false)), - topTitles: const AxisTitles( - sideTitles: SideTitles(showTitles: false)), - leftTitles: const AxisTitles( - sideTitles: SideTitles(showTitles: false)), - bottomTitles: AxisTitles( - sideTitles: SideTitles( - showTitles: true, - reservedSize: 30, - interval: _getInterval(), - getTitlesWidget: (value, meta) { - return SideTitleWidget( - meta: meta, - space: 8, - child: Text( - _getBottomTitle(value), - style: const TextStyle( - color: Colors.grey, fontSize: 10), - ), - ); - }, - ), - ), - ), - lineBarsData: [ - // === Garis Evaporasi === - LineChartBarData( - spots: safeValues.asMap().entries.map((e) { - return FlSpot(e.key.toDouble(), e.value); - }).toList(), - isCurved: true, - curveSmoothness: 0.2, - preventCurveOverShooting: true, - color: Colors.blue.shade700, - barWidth: 3, - isStrokeCapRound: true, - dotData: FlDotData( - show: true, - getDotPainter: (spot, percent, bar, index) { - if (index == safeValues.length - 1) { - return FlDotCirclePainter( - radius: 5, - color: Colors.blue.shade900, - strokeWidth: 2, - strokeColor: Colors.white, - ); - } - return FlDotCirclePainter(radius: 0); - }, - ), - belowBarData: BarAreaData( - show: true, - gradient: LinearGradient( - colors: [ - Colors.blue.withOpacity(0.25), - Colors.blue.withOpacity(0.05), - Colors.transparent - ], - begin: Alignment.topCenter, - end: Alignment.bottomCenter, - ), - ), - ), - // === Garis Suhu === - LineChartBarData( - spots: safeTemps.asMap().entries.map((e) { - return FlSpot(e.key.toDouble(), e.value); - }).toList(), - isCurved: true, - curveSmoothness: 0.2, - preventCurveOverShooting: true, - color: Colors.orange.shade600, - barWidth: 3, - isStrokeCapRound: true, - dotData: FlDotData( - show: true, - getDotPainter: (spot, percent, bar, index) { - if (index == safeTemps.length - 1) { - return FlDotCirclePainter( - radius: 5, - color: Colors.orange.shade800, - strokeWidth: 2, - strokeColor: Colors.white, - ); - } - return FlDotCirclePainter(radius: 0); - }, - ), - belowBarData: BarAreaData( - show: true, - gradient: LinearGradient( - colors: [ - Colors.orange.withOpacity(0.25), - Colors.orange.withOpacity(0.05), - Colors.transparent - ], - begin: Alignment.topCenter, - end: Alignment.bottomCenter, - ), - ), - ), - ], - lineTouchData: LineTouchData( - handleBuiltInTouches: true, - touchTooltipData: LineTouchTooltipData( - getTooltipItems: (touchedSpots) { - return touchedSpots.map((spot) { - final isEvaporasi = spot.barIndex == 0; - final label = isEvaporasi ? "Evaporasi" : "Suhu"; - final unit = isEvaporasi ? "mm" : "°C"; - return LineTooltipItem( - "$label: ${spot.y.toStringAsFixed(1)} $unit", - TextStyle( - color: isEvaporasi - ? Colors.blue.shade100 - : Colors.orange.shade100, - fontWeight: FontWeight.bold, - ), - ); - }).toList(); - }, - ), - ), - ), - ), - ), - ], - ), - ); - } - - Widget _legendItem(Color color, String label) { - return Row( - children: [ - Container( - width: 12, - height: 12, - decoration: BoxDecoration( - color: color, - borderRadius: BorderRadius.circular(3), - ), - ), - const SizedBox(width: 6), - Text( - label, - style: const TextStyle(fontSize: 12, color: Colors.grey), - ), - ], - ); - } - - String _getBottomTitle(double value) { - int index = value.toInt(); - final len = dailyValues.length; - if (index < 0 || index >= len) return ''; - - if (period == "Hari Ini") { - return index % 4 == 0 ? "${index.toString().padLeft(2, '0')}:00" : ""; - } else if (period == "Minggu Ini") { - const days = ["Sen", "Sel", "Rab", "Kam", "Jum", "Sab", "Min"]; - return days[index % 7]; - } else { - return (index + 1) % 5 == 0 ? "${index + 1}" : ""; - } - } - - double _getInterval() { - if (period == "Hari Ini") return 1; - if (period == "Minggu Ini") return 1; - return 1; - } -} - diff --git a/pubspec.lock b/pubspec.lock index ae5f51c..4867820 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -695,14 +695,6 @@ packages: url: "https://pub.dev" source: hosted version: "0.27.7" - simple_gesture_detector: - dependency: transitive - description: - name: simple_gesture_detector - sha256: ba2cd5af24ff20a0b8d609cec3f40e5b0744d2a71804a2616ae086b9c19d19a3 - url: "https://pub.dev" - source: hosted - version: "0.2.1" sky_engine: dependency: transitive description: flutter @@ -748,14 +740,6 @@ packages: url: "https://pub.dev" source: hosted version: "1.4.1" - table_calendar: - dependency: "direct main" - description: - name: table_calendar - sha256: "0c0c6219878b363a2d5f40c7afb159d845f253d061dc3c822aa0d5fe0f721982" - url: "https://pub.dev" - source: hosted - version: "3.2.0" term_glyph: dependency: transitive description: