From b06a23cc60332a11353abd4be454894871ab083e Mon Sep 17 00:00:00 2001 From: Faris Armoush Date: Mon, 2 Jun 2025 16:40:13 +0300 Subject: [PATCH] Refactor `WallLightSwitchBloc` to integrate new service dependencies and utilize a factory for instantiation. Improved event handling methods for better error management and state updates. --- .../bloc/wall_light_switch_bloc.dart | 236 ++++++++---------- .../wall_light_switch_bloc_factory.dart | 18 ++ .../view/wall_light_batch_control.dart | 4 +- .../view/wall_light_device_control.dart | 3 +- 4 files changed, 122 insertions(+), 139 deletions(-) create mode 100644 lib/pages/device_managment/one_gang_switch/factories/wall_light_switch_bloc_factory.dart diff --git a/lib/pages/device_managment/one_gang_switch/bloc/wall_light_switch_bloc.dart b/lib/pages/device_managment/one_gang_switch/bloc/wall_light_switch_bloc.dart index c2038330..59eccfe9 100644 --- a/lib/pages/device_managment/one_gang_switch/bloc/wall_light_switch_bloc.dart +++ b/lib/pages/device_managment/one_gang_switch/bloc/wall_light_switch_bloc.dart @@ -6,12 +6,21 @@ import 'package:syncrow_web/pages/device_managment/all_devices/models/device_sta import 'package:syncrow_web/pages/device_managment/one_gang_switch/bloc/wall_light_switch_event.dart'; import 'package:syncrow_web/pages/device_managment/one_gang_switch/bloc/wall_light_switch_state.dart'; import 'package:syncrow_web/pages/device_managment/one_gang_switch/models/wall_light_status_model.dart'; +import 'package:syncrow_web/services/batch_control_devices_service.dart'; +import 'package:syncrow_web/services/control_device_service.dart'; import 'package:syncrow_web/services/devices_mang_api.dart'; -class WallLightSwitchBloc - extends Bloc { - WallLightSwitchBloc({required this.deviceId}) - : super(WallLightSwitchInitial()) { +class WallLightSwitchBloc extends Bloc { + late WallLightStatusModel deviceStatus; + final String deviceId; + final ControlDeviceService controlDeviceService; + final BatchControlDevicesService batchControlDevicesService; + + WallLightSwitchBloc({ + required this.deviceId, + required this.controlDeviceService, + required this.batchControlDevicesService, + }) : super(WallLightSwitchInitial()) { on(_onFetchDeviceStatus); on(_onControl); on(_onFetchBatchStatus); @@ -20,143 +29,114 @@ class WallLightSwitchBloc on(_onStatusUpdated); } - late WallLightStatusModel deviceStatus; - final String deviceId; - Timer? _timer; - - FutureOr _onFetchDeviceStatus(WallLightSwitchFetchDeviceEvent event, - Emitter emit) async { + Future _onFetchDeviceStatus( + WallLightSwitchFetchDeviceEvent event, + Emitter emit, + ) async { emit(WallLightSwitchLoading()); try { - final status = - await DevicesManagementApi().getDeviceStatus(event.deviceId); - - deviceStatus = - WallLightStatusModel.fromJson(event.deviceId, status.status); - _listenToChanges(event.deviceId); + final status = await DevicesManagementApi().getDeviceStatus(event.deviceId); + _listenToChanges(event.deviceId, emit); + deviceStatus = WallLightStatusModel.fromJson(event.deviceId, status.status); emit(WallLightSwitchStatusLoaded(deviceStatus)); } catch (e) { emit(WallLightSwitchError(e.toString())); } } - _listenToChanges(deviceId) { + void _listenToChanges( + String deviceId, + Emitter emit, + ) { try { - DatabaseReference ref = - FirebaseDatabase.instance.ref('device-status/$deviceId'); - Stream stream = ref.onValue; + final ref = FirebaseDatabase.instance.ref('device-status/$deviceId'); + final stream = ref.onValue; stream.listen((DatabaseEvent event) { - Map usersMap = - event.snapshot.value as Map; + final data = event.snapshot.value as Map?; + if (data == null) return; - List statusList = []; - usersMap['status'].forEach((element) { - statusList - .add(Status(code: element['code'], value: element['value'])); - }); - - deviceStatus = - WallLightStatusModel.fromJson(usersMap['productUuid'], statusList); - if (!isClosed) { - add(StatusUpdated(deviceStatus)); + final statusList = []; + if (data['status'] != null) { + for (var element in data['status']) { + statusList.add( + Status( + code: element['code'].toString(), + value: element['value'].toString(), + ), + ); + } + } + if (statusList.isNotEmpty) { + final newStatus = WallLightStatusModel.fromJson(deviceId, statusList); + if (newStatus != deviceStatus) { + deviceStatus = newStatus; + if (!isClosed) { + add(StatusUpdated(deviceStatus)); + } + } } }); - } catch (_) {} + } catch (e) { + emit(WallLightSwitchError('Failed to listen to changes: $e')); + } } void _onStatusUpdated( - StatusUpdated event, Emitter emit) { + StatusUpdated event, + Emitter emit, + ) { + emit(WallLightSwitchLoading()); deviceStatus = event.deviceStatus; emit(WallLightSwitchStatusLoaded(deviceStatus)); } - FutureOr _onControl( - WallLightSwitchControl event, Emitter emit) async { - final oldValue = _getValueByCode(event.code); - + Future _onControl( + WallLightSwitchControl event, + Emitter emit, + ) async { + emit(WallLightSwitchLoading()); _updateLocalValue(event.code, event.value); - emit(WallLightSwitchStatusLoaded(deviceStatus)); - await _runDebounce( - deviceId: event.deviceId, - code: event.code, - value: event.value, - oldValue: oldValue, - emit: emit, - isBatch: false, - ); + try { + await controlDeviceService.controlDevice( + deviceUuid: event.deviceId, + status: Status(code: event.code, value: event.value), + ); + } catch (e) { + _updateLocalValue(event.code, !event.value); + emit(WallLightSwitchError(e.toString())); + } } - Future _runDebounce({ - required dynamic deviceId, - required String code, - required bool value, - required bool oldValue, - required Emitter emit, - required bool isBatch, - }) async { - late String id; - - if (deviceId is List) { - id = deviceId.first; - } else { - id = deviceId; - } - - if (_timer != null) { - _timer!.cancel(); - } - - _timer = Timer(const Duration(milliseconds: 500), () async { - try { - late bool response; - - if (isBatch) { - response = await DevicesManagementApi() - .deviceBatchControl(deviceId, code, value); - } else { - response = await DevicesManagementApi() - .deviceControl(deviceId, Status(code: code, value: value)); - } - - if (!response) { - _revertValueAndEmit(id, code, oldValue, emit); - } - } catch (e) { - _revertValueAndEmit(id, code, oldValue, emit); - } - }); - } - - void _revertValueAndEmit(String deviceId, String code, bool oldValue, - Emitter emit) { - _updateLocalValue(code, oldValue); + Future _onBatchControl( + WallLightSwitchBatchControl event, + Emitter emit, + ) async { + emit(WallLightSwitchLoading()); + _updateLocalValue(event.code, event.value); emit(WallLightSwitchStatusLoaded(deviceStatus)); - } - void _updateLocalValue(String code, bool value) { - if (code == 'switch_1') { - deviceStatus = deviceStatus.copyWith(switch1: value); + try { + await batchControlDevicesService.batchControlDevices( + uuids: event.devicesIds, + code: event.code, + value: event.value, + ); + } catch (e) { + _updateLocalValue(event.code, !event.value); + emit(WallLightSwitchError(e.toString())); } } - bool _getValueByCode(String code) { - switch (code) { - case 'switch_1': - return deviceStatus.switch1; - default: - return false; - } - } - - Future _onFetchBatchStatus(WallLightSwitchFetchBatchEvent event, - Emitter emit) async { + Future _onFetchBatchStatus( + WallLightSwitchFetchBatchEvent event, + Emitter emit, + ) async { emit(WallLightSwitchLoading()); try { - final status = - await DevicesManagementApi().getBatchStatus(event.devicesIds); + final status = await DevicesManagementApi().getBatchStatus(event.devicesIds); deviceStatus = WallLightStatusModel.fromJson(event.devicesIds.first, status.status); emit(WallLightSwitchStatusLoaded(deviceStatus)); @@ -165,32 +145,10 @@ class WallLightSwitchBloc } } - @override - Future close() { - _timer?.cancel(); - return super.close(); - } - - FutureOr _onBatchControl(WallLightSwitchBatchControl event, - Emitter emit) async { - final oldValue = _getValueByCode(event.code); - - _updateLocalValue(event.code, event.value); - - emit(WallLightSwitchStatusLoaded(deviceStatus)); - - await _runDebounce( - deviceId: event.devicesIds, - code: event.code, - value: event.value, - oldValue: oldValue, - emit: emit, - isBatch: true, - ); - } - - FutureOr _onFactoryReset( - WallLightFactoryReset event, Emitter emit) async { + Future _onFactoryReset( + WallLightFactoryReset event, + Emitter emit, + ) async { emit(WallLightSwitchLoading()); try { final response = await DevicesManagementApi().factoryReset( @@ -198,12 +156,18 @@ class WallLightSwitchBloc event.deviceId, ); if (!response) { - emit(WallLightSwitchError('Failed')); + emit(WallLightSwitchError('Failed to reset device')); } else { - emit(WallLightSwitchStatusLoaded(deviceStatus)); + add(WallLightSwitchFetchDeviceEvent(event.deviceId)); } } catch (e) { emit(WallLightSwitchError(e.toString())); } } + + void _updateLocalValue(String code, bool value) { + if (code == 'switch_1') { + deviceStatus = deviceStatus.copyWith(switch1: value); + } + } } diff --git a/lib/pages/device_managment/one_gang_switch/factories/wall_light_switch_bloc_factory.dart b/lib/pages/device_managment/one_gang_switch/factories/wall_light_switch_bloc_factory.dart new file mode 100644 index 00000000..fbbe13dc --- /dev/null +++ b/lib/pages/device_managment/one_gang_switch/factories/wall_light_switch_bloc_factory.dart @@ -0,0 +1,18 @@ +import 'package:syncrow_web/pages/device_managment/factories/device_bloc_dependencies_factory.dart'; +import 'package:syncrow_web/pages/device_managment/one_gang_switch/bloc/wall_light_switch_bloc.dart'; + +abstract final class WallLightSwitchBlocFactory { + const WallLightSwitchBlocFactory._(); + + static WallLightSwitchBloc create({ + required String deviceId, + }) { + return WallLightSwitchBloc( + deviceId: deviceId, + controlDeviceService: + DeviceBlocDependenciesFactory.createControlDeviceService(), + batchControlDevicesService: + DeviceBlocDependenciesFactory.createBatchControlDevicesService(), + ); + } +} diff --git a/lib/pages/device_managment/one_gang_switch/view/wall_light_batch_control.dart b/lib/pages/device_managment/one_gang_switch/view/wall_light_batch_control.dart index 7094b506..7fe57429 100644 --- a/lib/pages/device_managment/one_gang_switch/view/wall_light_batch_control.dart +++ b/lib/pages/device_managment/one_gang_switch/view/wall_light_batch_control.dart @@ -4,9 +4,9 @@ import 'package:syncrow_web/pages/device_managment/all_devices/models/factory_re import 'package:syncrow_web/pages/device_managment/one_gang_switch/bloc/wall_light_switch_bloc.dart'; import 'package:syncrow_web/pages/device_managment/one_gang_switch/bloc/wall_light_switch_event.dart'; import 'package:syncrow_web/pages/device_managment/one_gang_switch/bloc/wall_light_switch_state.dart'; +import 'package:syncrow_web/pages/device_managment/one_gang_switch/factories/wall_light_switch_bloc_factory.dart'; import 'package:syncrow_web/pages/device_managment/one_gang_switch/models/wall_light_status_model.dart'; import 'package:syncrow_web/pages/device_managment/shared/batch_control/factory_reset.dart'; -// import 'package:syncrow_web/pages/device_managment/shared/batch_control/firmware_update.dart'; import 'package:syncrow_web/pages/device_managment/shared/toggle_widget.dart'; import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart'; @@ -18,7 +18,7 @@ class WallLightBatchControlView extends StatelessWidget with HelperResponsiveLay @override Widget build(BuildContext context) { return BlocProvider( - create: (context) => WallLightSwitchBloc(deviceId: deviceIds.first) + create: (context) => WallLightSwitchBlocFactory.create(deviceId: deviceIds.first) ..add(WallLightSwitchFetchBatchEvent(deviceIds)), child: BlocBuilder( builder: (context, state) { diff --git a/lib/pages/device_managment/one_gang_switch/view/wall_light_device_control.dart b/lib/pages/device_managment/one_gang_switch/view/wall_light_device_control.dart index a9e6ebbb..f1861c55 100644 --- a/lib/pages/device_managment/one_gang_switch/view/wall_light_device_control.dart +++ b/lib/pages/device_managment/one_gang_switch/view/wall_light_device_control.dart @@ -3,6 +3,7 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:syncrow_web/pages/device_managment/one_gang_switch/bloc/wall_light_switch_bloc.dart'; import 'package:syncrow_web/pages/device_managment/one_gang_switch/bloc/wall_light_switch_event.dart'; import 'package:syncrow_web/pages/device_managment/one_gang_switch/bloc/wall_light_switch_state.dart'; +import 'package:syncrow_web/pages/device_managment/one_gang_switch/factories/wall_light_switch_bloc_factory.dart'; import 'package:syncrow_web/pages/device_managment/one_gang_switch/models/wall_light_status_model.dart'; import 'package:syncrow_web/pages/device_managment/shared/toggle_widget.dart'; import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart'; @@ -15,7 +16,7 @@ class WallLightDeviceControl extends StatelessWidget @override Widget build(BuildContext context) { return BlocProvider( - create: (context) => WallLightSwitchBloc(deviceId: deviceId) + create: (context) => WallLightSwitchBlocFactory.create(deviceId: deviceId) ..add(WallLightSwitchFetchDeviceEvent(deviceId)), child: BlocBuilder( builder: (context, state) {