oke
This commit is contained in:
parent
a6e74d4da0
commit
898c784359
|
|
@ -19,6 +19,7 @@ class WindSpeedBloc extends Bloc<WindSpeedEvent, WindSpeedState> {
|
|||
final MonitoringRepository _repository;
|
||||
final NotificationBloc _notificationBloc;
|
||||
StreamSubscription<MyWindSpeed>? _subscription;
|
||||
StreamSubscription<Map<String, MyWindSpeed>>? _historySubscription;
|
||||
|
||||
WindSpeedBloc({
|
||||
required MonitoringRepository repository,
|
||||
|
|
@ -35,6 +36,7 @@ class WindSpeedBloc extends Bloc<WindSpeedEvent, WindSpeedState> {
|
|||
on<WindSpeedDeleteByDateRequested>(_onDeleteByDate);
|
||||
on<WindSpeedDeleteByDateRangeRequested>(_onDeleteByDateRange);
|
||||
on<WindSpeedDeleteByHourRangeRequested>(_onDeleteByHourRange);
|
||||
on<_WindSpeedHistoryUpdated>(_onHistoryUpdated);
|
||||
}
|
||||
|
||||
Future<String> _getDeviceId() async {
|
||||
|
|
@ -49,42 +51,55 @@ class WindSpeedBloc extends Bloc<WindSpeedEvent, WindSpeedState> {
|
|||
WatchWindSpeedStarted event,
|
||||
Emitter<WindSpeedState> emit,
|
||||
) async {
|
||||
// Cancel stream lama dulu sebelum apapun
|
||||
await _subscription?.cancel();
|
||||
await _historySubscription?.cancel();
|
||||
_subscription = null;
|
||||
_historySubscription = null;
|
||||
|
||||
emit(state.copyWith(isLoading: true, currentSpeed: 0));
|
||||
final deviceId = await _getDeviceId();
|
||||
|
||||
final historyMap = await _repository.getSensorHistoryWithKeys(
|
||||
'anemometer/$deviceId/history',
|
||||
(json) => MyWindSpeed.fromJson(json),
|
||||
);
|
||||
// ── History stream (realtime, otomatis update) ──
|
||||
_historySubscription = _repository
|
||||
.getSensorHistoryStream(
|
||||
'anemometer/$deviceId/history',
|
||||
(json) => MyWindSpeed.fromJson(json),
|
||||
)
|
||||
.listen((newMap) => add(_WindSpeedHistoryUpdated(newMap)));
|
||||
|
||||
final history = _sortedList(historyMap);
|
||||
final graphs = _buildGraphs(history);
|
||||
|
||||
if (history.isNotEmpty) _emitWindAlert(history.last.speed);
|
||||
|
||||
emit(state.copyWith(
|
||||
historyMap: historyMap,
|
||||
history: history,
|
||||
filteredHistory: history,
|
||||
dailySpeeds: graphs['daily']!,
|
||||
weeklySpeeds: graphs['weekly']!,
|
||||
monthlySpeeds: graphs['monthly']!,
|
||||
isLoading: false,
|
||||
alertLevel:
|
||||
history.isNotEmpty ? _getAlertLevel(history.last.speed) : 'Normal',
|
||||
));
|
||||
|
||||
// Subscribe stream baru
|
||||
// ── Realtime stream ──
|
||||
_subscription = _repository
|
||||
.getSensorStream(
|
||||
'anemometer/$deviceId/realtime',
|
||||
(json) => MyWindSpeed.fromJson(json),
|
||||
)
|
||||
.listen((data) => add(_WindSpeedRealtimeUpdated(data)));
|
||||
|
||||
// ── Loading selesai, state awal kosong dulu ──
|
||||
// _onHistoryUpdated akan otomatis mengisi data begitu stream pertama emit
|
||||
emit(state.copyWith(isLoading: false));
|
||||
}
|
||||
|
||||
void _onHistoryUpdated(
|
||||
_WindSpeedHistoryUpdated event,
|
||||
Emitter<WindSpeedState> emit,
|
||||
) {
|
||||
final history = _sortedList(event.historyMap);
|
||||
final graphs = _buildGraphs(history);
|
||||
final filtered = state.selectedDate != null
|
||||
? history
|
||||
.where((e) => _isSameDate(e.timestamp, state.selectedDate!))
|
||||
.toList()
|
||||
: history;
|
||||
|
||||
emit(state.copyWith(
|
||||
historyMap: event.historyMap,
|
||||
history: history,
|
||||
filteredHistory: filtered,
|
||||
dailySpeeds: graphs['daily'],
|
||||
weeklySpeeds: graphs['weekly'],
|
||||
monthlySpeeds: graphs['monthly'],
|
||||
));
|
||||
}
|
||||
|
||||
// ════════════════════════════════════════════════════════════
|
||||
|
|
@ -429,6 +444,7 @@ class WindSpeedBloc extends Bloc<WindSpeedEvent, WindSpeedState> {
|
|||
@override
|
||||
Future<void> close() async {
|
||||
await _subscription?.cancel();
|
||||
await _historySubscription?.cancel();
|
||||
return super.close();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -76,3 +76,10 @@ class WindSpeedDeleteByHourRangeRequested extends WindSpeedEvent {
|
|||
@override
|
||||
List<Object?> get props => [date, startHour, endHour];
|
||||
}
|
||||
|
||||
class _WindSpeedHistoryUpdated extends WindSpeedEvent {
|
||||
final Map<String, MyWindSpeed> historyMap;
|
||||
const _WindSpeedHistoryUpdated(this.historyMap);
|
||||
@override
|
||||
List<Object?> get props => [historyMap];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -200,4 +200,21 @@ class FirebaseMonitoringRepo implements MonitoringRepository {
|
|||
Future<void> sendRemoteRestart(String deviceId) async {
|
||||
await _db.ref('anemometer/$deviceId/command/restart').set(true);
|
||||
}
|
||||
|
||||
@override
|
||||
Stream<Map<String, T>> getSensorHistoryStream<T>(
|
||||
String path,
|
||||
T Function(Map<dynamic, dynamic> json) mapper,
|
||||
) {
|
||||
return _db.ref(path).onValue.map((event) {
|
||||
if (!event.snapshot.exists || event.snapshot.value is! Map) return {};
|
||||
final data = event.snapshot.value as Map<dynamic, dynamic>;
|
||||
return {
|
||||
for (final entry in data.entries)
|
||||
entry.key.toString(): mapper(
|
||||
entry.value is Map ? entry.value as Map<dynamic, dynamic> : {},
|
||||
),
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,4 +41,10 @@ abstract class MonitoringRepository {
|
|||
);
|
||||
Future<void> deleteHistoryByKeys(String path, List<String> keys);
|
||||
Future<void> deleteAllHistory(String path);
|
||||
|
||||
// Tambah di abstract class MonitoringRepository:
|
||||
Stream<Map<String, T>> getSensorHistoryStream<T>(
|
||||
String path,
|
||||
T Function(Map<dynamic, dynamic> json) mapper,
|
||||
);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue