import 'dart:async'; import 'package:dio/dio.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:syncrow_web/pages/device_managment/all_devices/models/device_status.dart'; import 'package:syncrow_web/pages/device_managment/ac/bloc/ac_event.dart'; import 'package:syncrow_web/pages/device_managment/ac/bloc/ac_state.dart'; import 'package:syncrow_web/pages/device_managment/ac/model/ac_model.dart'; import 'package:syncrow_web/services/devices_mang_api.dart'; class AcBloc extends Bloc { late AcStatusModel deviceStatus; final String deviceId; Timer? _timer; AcBloc({required this.deviceId}) : super(AcsInitialState()) { on(_onFetchAcStatus); on(_onAcControl); } FutureOr _onFetchAcStatus( AcFetchDeviceStatus event, Emitter emit) async { emit(AcsLoadingState()); try { final status = await DevicesManagementApi().getDeviceStatus(event.deviceId); deviceStatus = AcStatusModel.fromJson(event.deviceId, status.status); emit(ACStatusLoaded(deviceStatus)); } catch (e) { emit(AcsFailedState(error: e.toString())); } } FutureOr _onAcControl(AcControl event, Emitter emit) async { final oldValue = _getValueByCode(event.code); _updateLocalValue(event.code, event.value); emit(ACStatusLoaded(deviceStatus)); await _runDebounce( deviceId: event.deviceId, code: event.code, value: event.value, oldValue: oldValue, emit: emit, ); } Future _runDebounce({ required String deviceId, required String code, required dynamic value, required dynamic oldValue, required Emitter emit, }) async { if (_timer != null) { _timer!.cancel(); } _timer = Timer(const Duration(seconds: 1), () async { try { final response = await DevicesManagementApi() .deviceControl(deviceId, Status(code: code, value: value)); if (!response) { _revertValueAndEmit(deviceId, code, oldValue, emit); } } catch (e) { if (e is DioException && e.response != null) { debugPrint('Error response: ${e.response?.data}'); } _revertValueAndEmit(deviceId, code, oldValue, emit); } }); } void _revertValueAndEmit( String deviceId, String code, dynamic oldValue, Emitter emit) { _updateLocalValue(code, oldValue); emit(ACStatusLoaded(deviceStatus)); emit(const AcsFailedState(error: 'Failed to control the device.')); } void _updateLocalValue(String code, dynamic value) { switch (code) { case 'switch': if (value is bool) { deviceStatus = deviceStatus.copyWith(acSwitch: value); } break; case 'temp_set': if (value is int) { deviceStatus = deviceStatus.copyWith(tempSet: value); } break; case 'mode': if (value is String) { deviceStatus = deviceStatus.copyWith( modeString: value, ); } break; case 'level': if (value is String) { deviceStatus = deviceStatus.copyWith( fanSpeedsString: value, ); } break; case 'child_lock': if (value is bool) { deviceStatus = deviceStatus.copyWith(childLock: value); } break; default: break; } emit(ACStatusLoaded(deviceStatus)); } dynamic _getValueByCode(String code) { switch (code) { case 'switch': return deviceStatus.acSwitch; case 'temp_set': return deviceStatus.tempSet; case 'mode': return deviceStatus.modeString; case 'level': return deviceStatus.fanSpeedsString; case 'child_lock': return deviceStatus.childLock; default: return null; } } }