oke
This commit is contained in:
parent
a6e74d4da0
commit
898c784359
|
|
@ -19,6 +19,7 @@ class WindSpeedBloc extends Bloc<WindSpeedEvent, WindSpeedState> {
|
||||||
final MonitoringRepository _repository;
|
final MonitoringRepository _repository;
|
||||||
final NotificationBloc _notificationBloc;
|
final NotificationBloc _notificationBloc;
|
||||||
StreamSubscription<MyWindSpeed>? _subscription;
|
StreamSubscription<MyWindSpeed>? _subscription;
|
||||||
|
StreamSubscription<Map<String, MyWindSpeed>>? _historySubscription;
|
||||||
|
|
||||||
WindSpeedBloc({
|
WindSpeedBloc({
|
||||||
required MonitoringRepository repository,
|
required MonitoringRepository repository,
|
||||||
|
|
@ -35,6 +36,7 @@ class WindSpeedBloc extends Bloc<WindSpeedEvent, WindSpeedState> {
|
||||||
on<WindSpeedDeleteByDateRequested>(_onDeleteByDate);
|
on<WindSpeedDeleteByDateRequested>(_onDeleteByDate);
|
||||||
on<WindSpeedDeleteByDateRangeRequested>(_onDeleteByDateRange);
|
on<WindSpeedDeleteByDateRangeRequested>(_onDeleteByDateRange);
|
||||||
on<WindSpeedDeleteByHourRangeRequested>(_onDeleteByHourRange);
|
on<WindSpeedDeleteByHourRangeRequested>(_onDeleteByHourRange);
|
||||||
|
on<_WindSpeedHistoryUpdated>(_onHistoryUpdated);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<String> _getDeviceId() async {
|
Future<String> _getDeviceId() async {
|
||||||
|
|
@ -49,42 +51,55 @@ class WindSpeedBloc extends Bloc<WindSpeedEvent, WindSpeedState> {
|
||||||
WatchWindSpeedStarted event,
|
WatchWindSpeedStarted event,
|
||||||
Emitter<WindSpeedState> emit,
|
Emitter<WindSpeedState> emit,
|
||||||
) async {
|
) async {
|
||||||
// Cancel stream lama dulu sebelum apapun
|
|
||||||
await _subscription?.cancel();
|
await _subscription?.cancel();
|
||||||
|
await _historySubscription?.cancel();
|
||||||
_subscription = null;
|
_subscription = null;
|
||||||
|
_historySubscription = null;
|
||||||
|
|
||||||
emit(state.copyWith(isLoading: true, currentSpeed: 0));
|
emit(state.copyWith(isLoading: true, currentSpeed: 0));
|
||||||
final deviceId = await _getDeviceId();
|
final deviceId = await _getDeviceId();
|
||||||
|
|
||||||
final historyMap = await _repository.getSensorHistoryWithKeys(
|
// ── History stream (realtime, otomatis update) ──
|
||||||
'anemometer/$deviceId/history',
|
_historySubscription = _repository
|
||||||
(json) => MyWindSpeed.fromJson(json),
|
.getSensorHistoryStream(
|
||||||
);
|
'anemometer/$deviceId/history',
|
||||||
|
(json) => MyWindSpeed.fromJson(json),
|
||||||
|
)
|
||||||
|
.listen((newMap) => add(_WindSpeedHistoryUpdated(newMap)));
|
||||||
|
|
||||||
final history = _sortedList(historyMap);
|
// ── Realtime stream ──
|
||||||
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
|
|
||||||
_subscription = _repository
|
_subscription = _repository
|
||||||
.getSensorStream(
|
.getSensorStream(
|
||||||
'anemometer/$deviceId/realtime',
|
'anemometer/$deviceId/realtime',
|
||||||
(json) => MyWindSpeed.fromJson(json),
|
(json) => MyWindSpeed.fromJson(json),
|
||||||
)
|
)
|
||||||
.listen((data) => add(_WindSpeedRealtimeUpdated(data)));
|
.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
|
@override
|
||||||
Future<void> close() async {
|
Future<void> close() async {
|
||||||
await _subscription?.cancel();
|
await _subscription?.cancel();
|
||||||
|
await _historySubscription?.cancel();
|
||||||
return super.close();
|
return super.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -76,3 +76,10 @@ class WindSpeedDeleteByHourRangeRequested extends WindSpeedEvent {
|
||||||
@override
|
@override
|
||||||
List<Object?> get props => [date, startHour, endHour];
|
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 {
|
Future<void> sendRemoteRestart(String deviceId) async {
|
||||||
await _db.ref('anemometer/$deviceId/command/restart').set(true);
|
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> deleteHistoryByKeys(String path, List<String> keys);
|
||||||
Future<void> deleteAllHistory(String path);
|
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