Refactor WallLightSwitchBloc to integrate new service dependencies and utilize a factory for instantiation. Improved event handling methods for better error management and state updates.

This commit is contained in:
Faris Armoush
2025-06-02 16:40:13 +03:00
parent 5595bb7f25
commit b06a23cc60
4 changed files with 122 additions and 139 deletions

View File

@ -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_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/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/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'; import 'package:syncrow_web/services/devices_mang_api.dart';
class WallLightSwitchBloc class WallLightSwitchBloc extends Bloc<WallLightSwitchEvent, WallLightSwitchState> {
extends Bloc<WallLightSwitchEvent, WallLightSwitchState> { late WallLightStatusModel deviceStatus;
WallLightSwitchBloc({required this.deviceId}) final String deviceId;
: super(WallLightSwitchInitial()) { final ControlDeviceService controlDeviceService;
final BatchControlDevicesService batchControlDevicesService;
WallLightSwitchBloc({
required this.deviceId,
required this.controlDeviceService,
required this.batchControlDevicesService,
}) : super(WallLightSwitchInitial()) {
on<WallLightSwitchFetchDeviceEvent>(_onFetchDeviceStatus); on<WallLightSwitchFetchDeviceEvent>(_onFetchDeviceStatus);
on<WallLightSwitchControl>(_onControl); on<WallLightSwitchControl>(_onControl);
on<WallLightSwitchFetchBatchEvent>(_onFetchBatchStatus); on<WallLightSwitchFetchBatchEvent>(_onFetchBatchStatus);
@ -20,143 +29,114 @@ class WallLightSwitchBloc
on<StatusUpdated>(_onStatusUpdated); on<StatusUpdated>(_onStatusUpdated);
} }
late WallLightStatusModel deviceStatus; Future<void> _onFetchDeviceStatus(
final String deviceId; WallLightSwitchFetchDeviceEvent event,
Timer? _timer; Emitter<WallLightSwitchState> emit,
) async {
FutureOr<void> _onFetchDeviceStatus(WallLightSwitchFetchDeviceEvent event,
Emitter<WallLightSwitchState> emit) async {
emit(WallLightSwitchLoading()); emit(WallLightSwitchLoading());
try { try {
final status = final status = await DevicesManagementApi().getDeviceStatus(event.deviceId);
await DevicesManagementApi().getDeviceStatus(event.deviceId); _listenToChanges(event.deviceId, emit);
deviceStatus = WallLightStatusModel.fromJson(event.deviceId, status.status);
deviceStatus =
WallLightStatusModel.fromJson(event.deviceId, status.status);
_listenToChanges(event.deviceId);
emit(WallLightSwitchStatusLoaded(deviceStatus)); emit(WallLightSwitchStatusLoaded(deviceStatus));
} catch (e) { } catch (e) {
emit(WallLightSwitchError(e.toString())); emit(WallLightSwitchError(e.toString()));
} }
} }
_listenToChanges(deviceId) { void _listenToChanges(
String deviceId,
Emitter<WallLightSwitchState> emit,
) {
try { try {
DatabaseReference ref = final ref = FirebaseDatabase.instance.ref('device-status/$deviceId');
FirebaseDatabase.instance.ref('device-status/$deviceId'); final stream = ref.onValue;
Stream<DatabaseEvent> stream = ref.onValue;
stream.listen((DatabaseEvent event) { stream.listen((DatabaseEvent event) {
Map<dynamic, dynamic> usersMap = final data = event.snapshot.value as Map<dynamic, dynamic>?;
event.snapshot.value as Map<dynamic, dynamic>; if (data == null) return;
List<Status> statusList = []; final statusList = <Status>[];
usersMap['status'].forEach((element) { if (data['status'] != null) {
statusList for (var element in data['status']) {
.add(Status(code: element['code'], value: element['value'])); statusList.add(
}); Status(
code: element['code'].toString(),
deviceStatus = value: element['value'].toString(),
WallLightStatusModel.fromJson(usersMap['productUuid'], statusList); ),
if (!isClosed) { );
add(StatusUpdated(deviceStatus)); }
}
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( void _onStatusUpdated(
StatusUpdated event, Emitter<WallLightSwitchState> emit) { StatusUpdated event,
Emitter<WallLightSwitchState> emit,
) {
emit(WallLightSwitchLoading());
deviceStatus = event.deviceStatus; deviceStatus = event.deviceStatus;
emit(WallLightSwitchStatusLoaded(deviceStatus)); emit(WallLightSwitchStatusLoaded(deviceStatus));
} }
FutureOr<void> _onControl( Future<void> _onControl(
WallLightSwitchControl event, Emitter<WallLightSwitchState> emit) async { WallLightSwitchControl event,
final oldValue = _getValueByCode(event.code); Emitter<WallLightSwitchState> emit,
) async {
emit(WallLightSwitchLoading());
_updateLocalValue(event.code, event.value); _updateLocalValue(event.code, event.value);
emit(WallLightSwitchStatusLoaded(deviceStatus)); emit(WallLightSwitchStatusLoaded(deviceStatus));
await _runDebounce( try {
deviceId: event.deviceId, await controlDeviceService.controlDevice(
code: event.code, deviceUuid: event.deviceId,
value: event.value, status: Status(code: event.code, value: event.value),
oldValue: oldValue, );
emit: emit, } catch (e) {
isBatch: false, _updateLocalValue(event.code, !event.value);
); emit(WallLightSwitchError(e.toString()));
}
} }
Future<void> _runDebounce({ Future<void> _onBatchControl(
required dynamic deviceId, WallLightSwitchBatchControl event,
required String code, Emitter<WallLightSwitchState> emit,
required bool value, ) async {
required bool oldValue, emit(WallLightSwitchLoading());
required Emitter<WallLightSwitchState> emit, _updateLocalValue(event.code, event.value);
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<WallLightSwitchState> emit) {
_updateLocalValue(code, oldValue);
emit(WallLightSwitchStatusLoaded(deviceStatus)); emit(WallLightSwitchStatusLoaded(deviceStatus));
}
void _updateLocalValue(String code, bool value) { try {
if (code == 'switch_1') { await batchControlDevicesService.batchControlDevices(
deviceStatus = deviceStatus.copyWith(switch1: value); uuids: event.devicesIds,
code: event.code,
value: event.value,
);
} catch (e) {
_updateLocalValue(event.code, !event.value);
emit(WallLightSwitchError(e.toString()));
} }
} }
bool _getValueByCode(String code) { Future<void> _onFetchBatchStatus(
switch (code) { WallLightSwitchFetchBatchEvent event,
case 'switch_1': Emitter<WallLightSwitchState> emit,
return deviceStatus.switch1; ) async {
default:
return false;
}
}
Future<void> _onFetchBatchStatus(WallLightSwitchFetchBatchEvent event,
Emitter<WallLightSwitchState> emit) async {
emit(WallLightSwitchLoading()); emit(WallLightSwitchLoading());
try { try {
final status = final status = await DevicesManagementApi().getBatchStatus(event.devicesIds);
await DevicesManagementApi().getBatchStatus(event.devicesIds);
deviceStatus = deviceStatus =
WallLightStatusModel.fromJson(event.devicesIds.first, status.status); WallLightStatusModel.fromJson(event.devicesIds.first, status.status);
emit(WallLightSwitchStatusLoaded(deviceStatus)); emit(WallLightSwitchStatusLoaded(deviceStatus));
@ -165,32 +145,10 @@ class WallLightSwitchBloc
} }
} }
@override Future<void> _onFactoryReset(
Future<void> close() { WallLightFactoryReset event,
_timer?.cancel(); Emitter<WallLightSwitchState> emit,
return super.close(); ) async {
}
FutureOr<void> _onBatchControl(WallLightSwitchBatchControl event,
Emitter<WallLightSwitchState> 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<void> _onFactoryReset(
WallLightFactoryReset event, Emitter<WallLightSwitchState> emit) async {
emit(WallLightSwitchLoading()); emit(WallLightSwitchLoading());
try { try {
final response = await DevicesManagementApi().factoryReset( final response = await DevicesManagementApi().factoryReset(
@ -198,12 +156,18 @@ class WallLightSwitchBloc
event.deviceId, event.deviceId,
); );
if (!response) { if (!response) {
emit(WallLightSwitchError('Failed')); emit(WallLightSwitchError('Failed to reset device'));
} else { } else {
emit(WallLightSwitchStatusLoaded(deviceStatus)); add(WallLightSwitchFetchDeviceEvent(event.deviceId));
} }
} catch (e) { } catch (e) {
emit(WallLightSwitchError(e.toString())); emit(WallLightSwitchError(e.toString()));
} }
} }
void _updateLocalValue(String code, bool value) {
if (code == 'switch_1') {
deviceStatus = deviceStatus.copyWith(switch1: value);
}
}
} }

View File

@ -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(),
);
}
}

View File

@ -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_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_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/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/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/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/pages/device_managment/shared/toggle_widget.dart';
import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.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 @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return BlocProvider( return BlocProvider(
create: (context) => WallLightSwitchBloc(deviceId: deviceIds.first) create: (context) => WallLightSwitchBlocFactory.create(deviceId: deviceIds.first)
..add(WallLightSwitchFetchBatchEvent(deviceIds)), ..add(WallLightSwitchFetchBatchEvent(deviceIds)),
child: BlocBuilder<WallLightSwitchBloc, WallLightSwitchState>( child: BlocBuilder<WallLightSwitchBloc, WallLightSwitchState>(
builder: (context, state) { builder: (context, state) {

View File

@ -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_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_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/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/one_gang_switch/models/wall_light_status_model.dart';
import 'package:syncrow_web/pages/device_managment/shared/toggle_widget.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'; import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart';
@ -15,7 +16,7 @@ class WallLightDeviceControl extends StatelessWidget
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return BlocProvider( return BlocProvider(
create: (context) => WallLightSwitchBloc(deviceId: deviceId) create: (context) => WallLightSwitchBlocFactory.create(deviceId: deviceId)
..add(WallLightSwitchFetchDeviceEvent(deviceId)), ..add(WallLightSwitchFetchDeviceEvent(deviceId)),
child: BlocBuilder<WallLightSwitchBloc, WallLightSwitchState>( child: BlocBuilder<WallLightSwitchBloc, WallLightSwitchState>(
builder: (context, state) { builder: (context, state) {