josss banget anjir

This commit is contained in:
kleponijo 2026-05-22 14:16:09 +07:00
parent c5413cdf95
commit 121d64798b
5 changed files with 79 additions and 0 deletions

View File

@ -34,6 +34,7 @@ class DeviceSetupBloc extends Bloc<DeviceSetupEvent, DeviceSetupState> {
(e, emit) => emit(state.copyWith(intervalHistoryMs: e.ms)));
on<DeviceSettingsSaved>(_onSettingsSaved);
on<DeviceLogsRefreshed>(_onLogsRefreshed);
on<DeviceRestartRequested>(_onRestartRequested);
}
//
@ -235,6 +236,22 @@ class DeviceSetupBloc extends Bloc<DeviceSetupEvent, DeviceSetupState> {
}
}
Future<void> _onRestartRequested(
DeviceRestartRequested event,
Emitter<DeviceSetupState> emit,
) async {
try {
await _repository.sendRemoteRestart(state.deviceId);
emit(state.copyWith(status: DeviceSetupStatus.settingsSaved));
// Reuse status settingsSaved untuk snackbar atau bisa buat status baru
} catch (e) {
emit(state.copyWith(
status: DeviceSetupStatus.settingsError,
errorMessage: 'Gagal kirim restart: $e',
));
}
}
// Reset state
void _onReset(
ResetDeviceSetupEvent event,

View File

@ -56,3 +56,5 @@ class DeviceSettingsSaved extends DeviceSetupEvent {}
/// Refresh logs dari Firebase
class DeviceLogsRefreshed extends DeviceSetupEvent {}
class DeviceRestartRequested extends DeviceSetupEvent {}

View File

@ -529,6 +529,42 @@ class _LogsTab extends StatelessWidget {
final DeviceSetupState state;
const _LogsTab({required this.state});
void _showRestartDialog(
BuildContext context, DeviceSetupBloc bloc, String deviceId) {
showDialog(
context: context,
builder: (ctx) => AlertDialog(
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)),
title: const Row(children: [
Icon(Icons.restart_alt_rounded, color: Colors.red),
SizedBox(width: 8),
Text('Remote Restart'),
]),
content: Text(
'ESP "$deviceId" akan restart dalam ~5 detik.\n\n'
'Data realtime akan berhenti sebentar lalu kembali normal.',
),
actions: [
TextButton(
onPressed: () => Navigator.pop(ctx),
child: Text('Batal', style: TextStyle(color: Colors.grey.shade600)),
),
ElevatedButton(
onPressed: () {
Navigator.pop(ctx);
bloc.add(DeviceRestartRequested());
},
style: ElevatedButton.styleFrom(
backgroundColor: Colors.red.shade600,
foregroundColor: Colors.white,
),
child: const Text('Restart'),
),
],
),
);
}
@override
Widget build(BuildContext context) {
final bloc = context.read<DeviceSetupBloc>();
@ -556,6 +592,21 @@ class _LogsTab extends StatelessWidget {
],
),
),
// restart esp
IconButton.filledTonal(
onPressed: () =>
_showRestartDialog(context, bloc, state.deviceId),
icon: const Icon(Icons.restart_alt_rounded),
tooltip: 'Remote Restart ESP',
style: IconButton.styleFrom(
backgroundColor: Colors.red.shade50,
foregroundColor: Colors.red.shade700,
),
),
const SizedBox(width: 8),
// refresh log serial
IconButton.filledTonal(
onPressed: state.logsLoading
? null

View File

@ -92,6 +92,7 @@ class FirebaseMonitoringRepo implements MonitoringRepository {
}
// Tulis settings ke Firebase (dari app)
@override
Future<void> updateAnemometerSettings({
double? kFaktor,
double? radiusM,
@ -110,6 +111,7 @@ class FirebaseMonitoringRepo implements MonitoringRepository {
}
// Ambil logs dari device tertentu
@override
Future<List<Map<String, dynamic>>> getDeviceLogs(
String deviceId, {
int limit = 50,
@ -142,4 +144,9 @@ class FirebaseMonitoringRepo implements MonitoringRepository {
} catch (_) {}
return [];
}
@override
Future<void> sendRemoteRestart(String deviceId) async {
await _db.ref('anemometer/$deviceId/command/restart').set(true);
}
}

View File

@ -38,4 +38,6 @@ abstract class MonitoringRepository {
String deviceId, {
int limit = 50,
});
Future<void> sendRemoteRestart(String deviceId);
}