Refactor ThreeGangGlassSwitchBloc to integrate new service dependencies and utilize a factory for instantiation. Enhanced event handling methods for improved error management and state updates.

This commit is contained in:
Faris Armoush
2025-06-03 09:49:26 +03:00
parent b06a23cc60
commit a71a66034c
5 changed files with 143 additions and 142 deletions

View File

@ -1,11 +1,14 @@
import 'dart:async'; import 'dart:async';
import 'package:bloc/bloc.dart'; import 'package:equatable/equatable.dart';
import 'package:firebase_database/firebase_database.dart'; import 'package:firebase_database/firebase_database.dart';
import 'package:meta/meta.dart'; import 'package:flutter/foundation.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/all_devices/models/device_status.dart';
import 'package:syncrow_web/pages/device_managment/all_devices/models/factory_reset_model.dart'; import 'package:syncrow_web/pages/device_managment/all_devices/models/factory_reset_model.dart';
import 'package:syncrow_web/pages/device_managment/three_g_glass_switch/models/three_gang_glass_switch.dart'; import 'package:syncrow_web/pages/device_managment/three_g_glass_switch/models/three_gang_glass_switch.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';
part 'three_gang_glass_switch_event.dart'; part 'three_gang_glass_switch_event.dart';
@ -13,19 +16,16 @@ part 'three_gang_glass_switch_state.dart';
class ThreeGangGlassSwitchBloc class ThreeGangGlassSwitchBloc
extends Bloc<ThreeGangGlassSwitchEvent, ThreeGangGlassSwitchState> { extends Bloc<ThreeGangGlassSwitchEvent, ThreeGangGlassSwitchState> {
ThreeGangGlassStatusModel deviceStatus; late ThreeGangGlassStatusModel deviceStatus;
Timer? _timer; final String deviceId;
final ControlDeviceService controlDeviceService;
final BatchControlDevicesService batchControlDevicesService;
ThreeGangGlassSwitchBloc({required String deviceId}) ThreeGangGlassSwitchBloc({
: deviceStatus = ThreeGangGlassStatusModel( required this.deviceId,
uuid: deviceId, required this.controlDeviceService,
switch1: false, required this.batchControlDevicesService,
countDown1: 0, }) : super(ThreeGangGlassSwitchInitial()) {
switch2: false,
countDown2: 0,
switch3: false,
countDown3: 0),
super(ThreeGangGlassSwitchInitial()) {
on<ThreeGangGlassSwitchFetchDeviceEvent>(_onFetchDeviceStatus); on<ThreeGangGlassSwitchFetchDeviceEvent>(_onFetchDeviceStatus);
on<ThreeGangGlassSwitchControl>(_onControl); on<ThreeGangGlassSwitchControl>(_onControl);
on<ThreeGangGlassSwitchBatchControl>(_onBatchControl); on<ThreeGangGlassSwitchBatchControl>(_onBatchControl);
@ -34,188 +34,154 @@ class ThreeGangGlassSwitchBloc
on<StatusUpdated>(_onStatusUpdated); on<StatusUpdated>(_onStatusUpdated);
} }
Future<void> _onFetchDeviceStatus(ThreeGangGlassSwitchFetchDeviceEvent event, Future<void> _onFetchDeviceStatus(
Emitter<ThreeGangGlassSwitchState> emit) async { ThreeGangGlassSwitchFetchDeviceEvent event,
Emitter<ThreeGangGlassSwitchState> emit,
) async {
emit(ThreeGangGlassSwitchLoading()); emit(ThreeGangGlassSwitchLoading());
try { try {
final status = final status = await DevicesManagementApi().getDeviceStatus(event.deviceId);
await DevicesManagementApi().getDeviceStatus(event.deviceId); _listenToChanges(event.deviceId, emit);
deviceStatus = deviceStatus =
ThreeGangGlassStatusModel.fromJson(event.deviceId, status.status); ThreeGangGlassStatusModel.fromJson(event.deviceId, status.status);
_listenToChanges(event.deviceId);
emit(ThreeGangGlassSwitchStatusLoaded(deviceStatus)); emit(ThreeGangGlassSwitchStatusLoaded(deviceStatus));
} catch (e) { } catch (e) {
emit(ThreeGangGlassSwitchError(e.toString())); emit(ThreeGangGlassSwitchError(e.toString()));
} }
} }
_listenToChanges(deviceId) { void _listenToChanges(
String deviceId,
Emitter<ThreeGangGlassSwitchState> 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 = ThreeGangGlassStatusModel.fromJson( value: element['value'].toString(),
usersMap['productUuid'], statusList); ),
if (!isClosed) { );
add(StatusUpdated(deviceStatus)); }
}
if (statusList.isNotEmpty) {
final newStatus = ThreeGangGlassStatusModel.fromJson(deviceId, statusList);
if (newStatus != deviceStatus) {
deviceStatus = newStatus;
if (!isClosed) {
add(StatusUpdated(deviceStatus));
}
}
} }
}); });
} catch (_) {} } catch (e) {
emit(ThreeGangGlassSwitchError('Failed to listen to changes: $e'));
}
} }
void _onStatusUpdated( void _onStatusUpdated(
StatusUpdated event, Emitter<ThreeGangGlassSwitchState> emit) { StatusUpdated event,
Emitter<ThreeGangGlassSwitchState> emit,
) {
emit(ThreeGangGlassSwitchLoading());
deviceStatus = event.deviceStatus; deviceStatus = event.deviceStatus;
emit(ThreeGangGlassSwitchStatusLoaded(deviceStatus)); emit(ThreeGangGlassSwitchStatusLoaded(deviceStatus));
} }
Future<void> _onControl(ThreeGangGlassSwitchControl event, Future<void> _onControl(
Emitter<ThreeGangGlassSwitchState> emit) async { ThreeGangGlassSwitchControl event,
final oldValue = _getValueByCode(event.code); Emitter<ThreeGangGlassSwitchState> emit,
) async {
emit(ThreeGangGlassSwitchLoading());
_updateLocalValue(event.code, event.value); _updateLocalValue(event.code, event.value);
emit(ThreeGangGlassSwitchStatusLoaded(deviceStatus)); emit(ThreeGangGlassSwitchStatusLoaded(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(ThreeGangGlassSwitchError(e.toString()));
}
} }
Future<void> _onBatchControl(ThreeGangGlassSwitchBatchControl event, Future<void> _onBatchControl(
Emitter<ThreeGangGlassSwitchState> emit) async { ThreeGangGlassSwitchBatchControl event,
final oldValue = _getValueByCode(event.code); Emitter<ThreeGangGlassSwitchState> emit,
) async {
emit(ThreeGangGlassSwitchLoading());
_updateLocalValue(event.code, event.value); _updateLocalValue(event.code, event.value);
emit(ThreeGangGlassSwitchBatchStatusLoaded(deviceStatus)); emit(ThreeGangGlassSwitchBatchStatusLoaded(deviceStatus));
await _runDebounce( try {
deviceId: event.deviceIds, await batchControlDevicesService.batchControlDevices(
code: event.code, uuids: event.deviceIds,
value: event.value, code: event.code,
oldValue: oldValue, value: event.value,
emit: emit, );
isBatch: true, } catch (e) {
); _updateLocalValue(event.code, !event.value);
emit(ThreeGangGlassSwitchError(e.toString()));
}
} }
Future<void> _onFetchBatchStatus( Future<void> _onFetchBatchStatus(
ThreeGangGlassSwitchFetchBatchStatusEvent event, ThreeGangGlassSwitchFetchBatchStatusEvent event,
Emitter<ThreeGangGlassSwitchState> emit) async { Emitter<ThreeGangGlassSwitchState> emit,
) async {
emit(ThreeGangGlassSwitchLoading()); emit(ThreeGangGlassSwitchLoading());
try { try {
final status = final status = await DevicesManagementApi().getBatchStatus(event.deviceIds);
await DevicesManagementApi().getBatchStatus(event.deviceIds); deviceStatus =
deviceStatus = ThreeGangGlassStatusModel.fromJson( ThreeGangGlassStatusModel.fromJson(event.deviceIds.first, status.status);
event.deviceIds.first, status.status);
emit(ThreeGangGlassSwitchBatchStatusLoaded(deviceStatus)); emit(ThreeGangGlassSwitchBatchStatusLoaded(deviceStatus));
} catch (e) { } catch (e) {
emit(ThreeGangGlassSwitchError(e.toString())); emit(ThreeGangGlassSwitchError(e.toString()));
} }
} }
Future<void> _onFactoryReset(ThreeGangGlassFactoryReset event, Future<void> _onFactoryReset(
Emitter<ThreeGangGlassSwitchState> emit) async { ThreeGangGlassFactoryReset event,
Emitter<ThreeGangGlassSwitchState> emit,
) async {
emit(ThreeGangGlassSwitchLoading()); emit(ThreeGangGlassSwitchLoading());
try { try {
final response = await DevicesManagementApi() final response = await DevicesManagementApi().factoryReset(
.factoryReset(event.factoryReset, event.deviceId); event.factoryReset,
event.deviceId,
);
if (!response) { if (!response) {
emit(ThreeGangGlassSwitchError('Failed')); emit(ThreeGangGlassSwitchError('Failed to reset device'));
} else { } else {
emit(ThreeGangGlassSwitchStatusLoaded(deviceStatus)); add(ThreeGangGlassSwitchFetchDeviceEvent(event.deviceId));
} }
} catch (e) { } catch (e) {
emit(ThreeGangGlassSwitchError(e.toString())); emit(ThreeGangGlassSwitchError(e.toString()));
} }
} }
Future<void> _runDebounce({
required dynamic deviceId,
required String code,
required bool value,
required bool oldValue,
required Emitter<ThreeGangGlassSwitchState> 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<ThreeGangGlassSwitchState> emit) {
_updateLocalValue(code, oldValue);
emit(ThreeGangGlassSwitchStatusLoaded(deviceStatus));
}
void _updateLocalValue(String code, bool value) { void _updateLocalValue(String code, bool value) {
if (code == 'switch_1') {
deviceStatus = deviceStatus.copyWith(switch1: value);
} else if (code == 'switch_2') {
deviceStatus = deviceStatus.copyWith(switch2: value);
} else if (code == 'switch_3') {
deviceStatus = deviceStatus.copyWith(switch3: value);
}
}
bool _getValueByCode(String code) {
switch (code) { switch (code) {
case 'switch_1': case 'switch_1':
return deviceStatus.switch1; deviceStatus = deviceStatus.copyWith(switch1: value);
break;
case 'switch_2': case 'switch_2':
return deviceStatus.switch2; deviceStatus = deviceStatus.copyWith(switch2: value);
break;
case 'switch_3': case 'switch_3':
return deviceStatus.switch3; deviceStatus = deviceStatus.copyWith(switch3: value);
default: break;
return false;
} }
} }
@override
Future<void> close() {
_timer?.cancel();
return super.close();
}
} }

View File

@ -1,7 +1,10 @@
part of 'three_gang_glass_switch_bloc.dart'; part of 'three_gang_glass_switch_bloc.dart';
@immutable @immutable
abstract class ThreeGangGlassSwitchEvent {} abstract class ThreeGangGlassSwitchEvent extends Equatable {
@override
List<Object?> get props => [];
}
class ThreeGangGlassSwitchFetchDeviceEvent extends ThreeGangGlassSwitchEvent { class ThreeGangGlassSwitchFetchDeviceEvent extends ThreeGangGlassSwitchEvent {
final String deviceId; final String deviceId;
@ -19,6 +22,9 @@ class ThreeGangGlassSwitchControl extends ThreeGangGlassSwitchEvent {
required this.code, required this.code,
required this.value, required this.value,
}); });
@override
List<Object?> get props => [deviceId, code, value];
} }
class ThreeGangGlassSwitchBatchControl extends ThreeGangGlassSwitchEvent { class ThreeGangGlassSwitchBatchControl extends ThreeGangGlassSwitchEvent {
@ -31,6 +37,9 @@ class ThreeGangGlassSwitchBatchControl extends ThreeGangGlassSwitchEvent {
required this.code, required this.code,
required this.value, required this.value,
}); });
@override
List<Object?> get props => [deviceIds, code, value];
} }
class ThreeGangGlassSwitchFetchBatchStatusEvent class ThreeGangGlassSwitchFetchBatchStatusEvent
@ -38,6 +47,9 @@ class ThreeGangGlassSwitchFetchBatchStatusEvent
final List<String> deviceIds; final List<String> deviceIds;
ThreeGangGlassSwitchFetchBatchStatusEvent(this.deviceIds); ThreeGangGlassSwitchFetchBatchStatusEvent(this.deviceIds);
@override
List<Object?> get props => [deviceIds];
} }
class ThreeGangGlassFactoryReset extends ThreeGangGlassSwitchEvent { class ThreeGangGlassFactoryReset extends ThreeGangGlassSwitchEvent {
@ -48,6 +60,9 @@ class ThreeGangGlassFactoryReset extends ThreeGangGlassSwitchEvent {
required this.deviceId, required this.deviceId,
required this.factoryReset, required this.factoryReset,
}); });
@override
List<Object?> get props => [deviceId, factoryReset];
} }
class StatusUpdated extends ThreeGangGlassSwitchEvent { class StatusUpdated extends ThreeGangGlassSwitchEvent {

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/three_g_glass_switch/bloc/three_gang_glass_switch_bloc.dart';
abstract final class ThreeGangGlassSwitchBlocFactory {
const ThreeGangGlassSwitchBlocFactory._();
static ThreeGangGlassSwitchBloc create({
required String deviceId,
}) {
return ThreeGangGlassSwitchBloc(
deviceId: deviceId,
controlDeviceService:
DeviceBlocDependenciesFactory.createControlDeviceService(),
batchControlDevicesService:
DeviceBlocDependenciesFactory.createBatchControlDevicesService(),
);
}
}

View File

@ -5,6 +5,7 @@ import 'package:syncrow_web/pages/device_managment/shared/batch_control/factory_
// import 'package:syncrow_web/pages/device_managment/shared/batch_control/firmware_update.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/pages/device_managment/three_g_glass_switch/bloc/three_gang_glass_switch_bloc.dart'; import 'package:syncrow_web/pages/device_managment/three_g_glass_switch/bloc/three_gang_glass_switch_bloc.dart';
import 'package:syncrow_web/pages/device_managment/three_g_glass_switch/factories/three_gang_glass_switch_bloc_factory.dart';
import 'package:syncrow_web/pages/device_managment/three_g_glass_switch/models/three_gang_glass_switch.dart'; import 'package:syncrow_web/pages/device_managment/three_g_glass_switch/models/three_gang_glass_switch.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';
@ -16,7 +17,7 @@ class ThreeGangGlassSwitchBatchControlView extends StatelessWidget with HelperRe
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return BlocProvider( return BlocProvider(
create: (context) => ThreeGangGlassSwitchBloc(deviceId: deviceIds.first) create: (context) => ThreeGangGlassSwitchBlocFactory.create(deviceId: deviceIds.first)
..add(ThreeGangGlassSwitchFetchBatchStatusEvent(deviceIds)), ..add(ThreeGangGlassSwitchFetchBatchStatusEvent(deviceIds)),
child: BlocBuilder<ThreeGangGlassSwitchBloc, ThreeGangGlassSwitchState>( child: BlocBuilder<ThreeGangGlassSwitchBloc, ThreeGangGlassSwitchState>(
builder: (context, state) { builder: (context, state) {

View File

@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.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/pages/device_managment/three_g_glass_switch/bloc/three_gang_glass_switch_bloc.dart'; import 'package:syncrow_web/pages/device_managment/three_g_glass_switch/bloc/three_gang_glass_switch_bloc.dart';
import 'package:syncrow_web/pages/device_managment/three_g_glass_switch/factories/three_gang_glass_switch_bloc_factory.dart';
import 'package:syncrow_web/utils/constants/assets.dart'; import 'package:syncrow_web/utils/constants/assets.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';
@ -16,7 +17,7 @@ class ThreeGangGlassSwitchControlView extends StatelessWidget with HelperRespons
Widget build(BuildContext context) { Widget build(BuildContext context) {
return BlocProvider( return BlocProvider(
create: (context) => create: (context) =>
ThreeGangGlassSwitchBloc(deviceId: deviceId)..add(ThreeGangGlassSwitchFetchDeviceEvent(deviceId)), ThreeGangGlassSwitchBlocFactory.create(deviceId: deviceId)..add(ThreeGangGlassSwitchFetchDeviceEvent(deviceId)),
child: BlocBuilder<ThreeGangGlassSwitchBloc, ThreeGangGlassSwitchState>( child: BlocBuilder<ThreeGangGlassSwitchBloc, ThreeGangGlassSwitchState>(
builder: (context, state) { builder: (context, state) {
if (state is ThreeGangGlassSwitchLoading) { if (state is ThreeGangGlassSwitchLoading) {