diff --git a/analyze_log.txt b/analyze_log.txt
new file mode 100644
index 0000000..fe29a4a
Binary files /dev/null and b/analyze_log.txt differ
diff --git a/android/build/reports/problems/problems-report.html b/android/build/reports/problems/problems-report.html
new file mode 100644
index 0000000..9ff7a95
--- /dev/null
+++ b/android/build/reports/problems/problems-report.html
@@ -0,0 +1,663 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ Gradle Configuration Cache
+
+
+
+
+
+
+ Loading...
+
+
+
+
+
+
+
diff --git a/build_log.txt b/build_log.txt
new file mode 100644
index 0000000..1b849d5
Binary files /dev/null and b/build_log.txt differ
diff --git a/build_log2.txt b/build_log2.txt
new file mode 100644
index 0000000..8da8340
Binary files /dev/null and b/build_log2.txt differ
diff --git a/lib/core/utils/time_series_mapper.dart b/lib/core/utils/time_series_mapper.dart
index 0fa54cb..1300b84 100644
--- a/lib/core/utils/time_series_mapper.dart
+++ b/lib/core/utils/time_series_mapper.dart
@@ -1,3 +1,5 @@
+import 'package:monitoring_repository/monitoring_repository.dart';
+
class TimeSeriesMapper {
/// =========================
/// 📅 DAILY (24 JAM)
@@ -142,4 +144,30 @@ class TimeSeriesMapper {
return result;
}
+
+ // ── Tambahkan ini setelah method smooth() ──────────────────────
+
+ /// Shortcut untuk model yang implement HasTimestamp.
+ /// Dari: TimeSeriesMapper.toDaily(data: h, getTime: (e) => e.timestamp, getValue: (e) => e.speed)
+ /// Ke: TimeSeriesMapper.dailyFrom(h, (e) => e.speed)
+ static List dailyFrom(
+ List data,
+ double Function(T) getValue,
+ ) =>
+ smooth(
+ toDaily(data: data, getTime: (e) => e.timestamp, getValue: getValue));
+
+ static List weeklyFrom(
+ List data,
+ double Function(T) getValue,
+ ) =>
+ smooth(toWeekly(
+ data: data, getTime: (e) => e.timestamp, getValue: getValue));
+
+ static List monthlyFrom(
+ List data,
+ double Function(T) getValue,
+ ) =>
+ smooth(toMonthly(
+ data: data, getTime: (e) => e.timestamp, getValue: getValue));
}
diff --git a/lib/screens/monitoring/wind_speed/blocs/wind_speed_bloc.dart b/lib/screens/monitoring/wind_speed/blocs/wind_speed_bloc.dart
index 9a995a7..05f0616 100644
--- a/lib/screens/monitoring/wind_speed/blocs/wind_speed_bloc.dart
+++ b/lib/screens/monitoring/wind_speed/blocs/wind_speed_bloc.dart
@@ -48,32 +48,16 @@ class WindSpeedBloc extends Bloc {
final history = await _repository.getSensorHistory(
'anemometer/history',
(json) => MyWindSpeed.fromJson(json),
+ orderByChild: 'timestamp',
+ limit: 500,
);
- // ✅ Ini saja yang benar
- final dailyGraph = TimeSeriesMapper.smooth(
- TimeSeriesMapper.toDaily(
- data: history,
- getTime: (e) => e.timestamp,
- getValue: (e) => e.speed,
- ),
- );
-
- final weekly = TimeSeriesMapper.smooth(
- TimeSeriesMapper.toWeekly(
- data: history,
- getTime: (e) => e.timestamp,
- getValue: (e) => e.speed,
- ),
- );
-
- final monthly = TimeSeriesMapper.smooth(
- TimeSeriesMapper.toMonthly(
- data: history,
- getTime: (e) => e.timestamp,
- getValue: (e) => e.speed,
- ),
- );
+ final dailyGraph =
+ TimeSeriesMapper.dailyFrom(history, (e) => e.speed);
+ final weekly =
+ TimeSeriesMapper.weeklyFrom(history, (e) => e.speed);
+ final monthly =
+ TimeSeriesMapper.monthlyFrom(history, (e) => e.speed);
// Cek kondisi awal dari history
if (history.isNotEmpty) {
@@ -141,48 +125,11 @@ class WindSpeedBloc extends Bloc {
/// =========================
/// 📊 CHANGE PERIOD
/// =========================
- Future _onPeriodChanged(
+ void _onPeriodChanged(
WindSpeedPeriodChanged event,
Emitter emit,
- ) async {
+ ) {
emit(state.copyWith(selectedPeriod: event.period));
-
- final history = state.history;
-
- List raw;
-
- if (event.period == "Minggu Ini") {
- raw = TimeSeriesMapper.toWeekly(
- data: history,
- getTime: (e) => e.timestamp,
- getValue: (e) => e.speed,
- );
- } else if (event.period == "Bulan Ini") {
- raw = TimeSeriesMapper.toMonthly(
- data: history,
- getTime: (e) => e.timestamp,
- getValue: (e) => e.speed,
- );
- } else {
- raw = TimeSeriesMapper.toDaily(
- data: history,
- getTime: (e) => e.timestamp,
- getValue: (e) => e.speed,
- );
- }
-
- /// 🔥 baru di-smooth
- final updatedGraph = TimeSeriesMapper.smooth(raw);
-
- emit(state.copyWith(
- dailySpeeds:
- event.period == "Hari Ini" ? updatedGraph : state.dailySpeeds,
- weeklySpeeds:
- event.period == "Minggu Ini" ? updatedGraph : state.weeklySpeeds,
- monthlySpeeds:
- event.period == "Bulan Ini" ? updatedGraph : state.monthlySpeeds,
- isLoading: false,
- ));
}
@override
diff --git a/packages/monitoring_repository/lib/monitoring_repository.dart b/packages/monitoring_repository/lib/monitoring_repository.dart
index e5ff71e..b69e0b2 100644
--- a/packages/monitoring_repository/lib/monitoring_repository.dart
+++ b/packages/monitoring_repository/lib/monitoring_repository.dart
@@ -3,3 +3,4 @@ library monitoring_repository;
export 'src/monitoring_repo.dart';
export 'src/firebase_monitoring_repo.dart';
export 'src/models/models.dart';
+export 'src/utils/timestamp_parser.dart';
diff --git a/packages/monitoring_repository/lib/src/firebase_monitoring_repo.dart b/packages/monitoring_repository/lib/src/firebase_monitoring_repo.dart
index f7cf78c..a8f54eb 100644
--- a/packages/monitoring_repository/lib/src/firebase_monitoring_repo.dart
+++ b/packages/monitoring_repository/lib/src/firebase_monitoring_repo.dart
@@ -1,72 +1,61 @@
-// import 'dart:developer';
import 'dart:async';
-// import 'package:rxdart/rxdart.dart';
import 'package:firebase_database/firebase_database.dart';
-import 'package:monitoring_repository/monitoring_repository.dart';
+import 'monitoring_repo.dart';
+import 'models/has_timestamp.dart';
+import 'models/models.dart';
-/// === ambil data dari realtime database firebase === ///
class FirebaseMonitoringRepo implements MonitoringRepository {
final FirebaseDatabase _db = FirebaseDatabase.instance;
- // Satu fungsi untuk semua jenis sensor
- // Kamu cukup masukkan "path" database-nya saja
@override
Stream getSensorStream(
String path,
T Function(Map json) mapper,
) {
- /// === ambil data mentah dari firebase === ///
return _db.ref(path).onValue.map((event) {
- final Object? value = event.snapshot.value;
-
- if (value is Map) {
- return mapper(value);
- } else {
- // Jika data kosong atau bukan Map, berikan Map kosong agar mapper tidak crash
- return mapper({});
- }
+ final value = event.snapshot.value;
+ return mapper(value is Map ? value : {});
});
}
@override
- // Jika ingin mengambil data sekali saja (bukan stream)
Future getSensorSnapshot(
String path,
T Function(Map json) mapper,
) async {
final snapshot = await _db.ref(path).get();
- final data = snapshot.value as Map? ?? {};
- return mapper(data);
+ return mapper(snapshot.value as Map? ?? {});
}
@override
- Future> getSensorHistory(
+ Future> getSensorHistory(
String path,
- T Function(Map json) mapper,
- ) async {
+ T Function(Map json) mapper, {
+ String? orderByChild,
+ int limit = 500,
+ }) async {
try {
- // Ambil data dari path history
- final snapshot = await _db.ref(path).get();
+ Query query = _db.ref(path);
- if (snapshot.exists && snapshot.value is Map) {
- final Map data = snapshot.value as Map;
-
- final list = data.values.map((item) {
- return mapper(item as Map);
- }).toList();
-
- // ✅ Sort by timestamp — Firebase push tidak jamin urutan
- list.sort((a, b) {
- if (a is MyWindSpeed && b is MyWindSpeed) {
- return a.timestamp.compareTo(b.timestamp);
- }
- return 0;
- });
-
- return list;
+ if (orderByChild != null) {
+ query = query.orderByChild(orderByChild).limitToLast(limit);
+ } else {
+ query = query.limitToLast(limit);
}
- return [];
- } catch (e) {
+
+ final snapshot = await query.get();
+ if (!snapshot.exists || snapshot.value is! Map) return [];
+
+ final data = snapshot.value as Map;
+ final list = data.values
+ .whereType