import 'dart:async'; import 'package:firebase_database/firebase_database.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:syncrow_app/features/app_layout/bloc/home_cubit.dart'; import 'package:syncrow_app/features/devices/bloc/curtain_bloc/curtain_event.dart'; import 'package:syncrow_app/features/devices/bloc/curtain_bloc/curtain_state.dart'; import 'package:syncrow_app/features/devices/model/curtain_model.dart'; import 'package:syncrow_app/features/devices/model/device_control_model.dart'; import 'package:syncrow_app/features/devices/model/device_model.dart'; import 'package:syncrow_app/features/devices/model/group_curtain_model.dart'; import 'package:syncrow_app/features/devices/model/status_model.dart'; import 'package:syncrow_app/services/api/devices_api.dart'; import 'package:syncrow_app/utils/resource_manager/constants.dart'; class CurtainBloc extends Bloc { double curtainWidth = 270; double curtainOpeningSpace = 195; double blindHeight = 310; double blindOpeningSpace = 245; double openPercentage = 0; bool isMoving = false; final String curtainId; CurtainBloc( this.curtainId, ) : super(CurtainInitial()) { on(_fetchStatus); on(_onOpenCurtain); on(_onCloseCurtain); on(_onPauseCurtain); on(_changeFirstWizardSwitch); on(_fetchWizardStatus); on(_groupAllOff); on(_groupAllOn); on(_updateCurtain); } Future _onOpenCurtain( OpenCurtain event, Emitter emit) async { isMoving = true; while (openPercentage < 100.0) { if (state is CurtainsClosing) { _pauseCurtain(emit); break; } emit(CurtainsOpening( curtainWidth: curtainWidth, blindHeight: blindHeight, openPercentage: openPercentage, )); if (isMoving) { await Future.delayed(const Duration(milliseconds: 200), () async { openPercentage += 10.0; event.deviceType == DeviceType.Curtain ? curtainWidth -= curtainOpeningSpace / 10 : blindHeight -= blindOpeningSpace / 10; if (openPercentage >= 100.0) { _pauseCurtain(emit); } }); if (openPercentage >= 100.0) { await DevicesAPI.controlDevice( DeviceControlModel( deviceId: curtainId, code: 'control', value: 'close', ), curtainId, ); await DevicesAPI.controlDevice( DeviceControlModel( deviceId: curtainId, code: 'percent_control', value: 100, ), curtainId, ); } } else { _pauseCurtain(emit); break; } } } Future _onCloseCurtain( CloseCurtain event, Emitter emit) async { isMoving = true; while (openPercentage > 0.0) { if (state is CurtainsOpening) { _pauseCurtain(emit); break; } emit(CurtainsClosing( curtainWidth: curtainWidth, blindHeight: blindHeight, openPercentage: openPercentage, )); if (isMoving) { await Future.delayed(const Duration(milliseconds: 200), () async { openPercentage -= 10.0; event.deviceType == DeviceType.Curtain ? curtainWidth += curtainOpeningSpace / 10 : blindHeight += blindOpeningSpace / 10; if (openPercentage <= 0.0) { _pauseCurtain(emit); } }); if (openPercentage == 0.0) { await DevicesAPI.controlDevice( DeviceControlModel( deviceId: curtainId, code: 'percent_control', value: 0, ), curtainId, ); await DevicesAPI.controlDevice( DeviceControlModel( deviceId: curtainId, code: 'control', value: 'open', ), curtainId, ); } } else { _pauseCurtain(emit); break; } } } Future _onPauseCurtain( PauseCurtain event, Emitter emit) async { _pauseCurtain(emit); await DevicesAPI.controlDevice( DeviceControlModel( deviceId: curtainId, code: 'control', value: 'stop', ), curtainId, ); await DevicesAPI.controlDevice( DeviceControlModel( deviceId: curtainId, code: 'percent_control', value: openPercentage.ceil(), ), curtainId, ); } Future _pauseCurtain(Emitter emit) async { isMoving = false; emit(CurtainsPaused( curtainWidth: curtainWidth, blindHeight: blindHeight, openPercentage: openPercentage, )); } void _fetchStatus(InitCurtain event, Emitter emit) async { try { emit(CurtainLoadingState()); _listenToChanges(curtainId); var response = await DevicesAPI.getDeviceStatus(curtainId); List statusModelList = []; for (var status in response['status']) { statusModelList.add(StatusModel.fromJson(status)); } openPercentage = double.tryParse(statusModelList[1].value.toString())!; curtainWidth = 270 - (openPercentage / 100) * curtainOpeningSpace; blindHeight = 310 - (openPercentage / 100) * blindOpeningSpace; emit(CurtainsOpening( curtainWidth: curtainWidth, blindHeight: blindHeight, openPercentage: openPercentage, )); } catch (e) { emit(FailedState()); return; } } StreamSubscription? _streamSubscription; void _listenToChanges(curtainId) { try { _streamSubscription?.cancel(); DatabaseReference ref = FirebaseDatabase.instance.ref('device-status/$curtainId'); Stream stream = ref.onValue; _streamSubscription = stream.listen((DatabaseEvent event) { Map usersMap = event.snapshot.value as Map; List statusList = []; usersMap['status'].forEach((element) { statusList .add(StatusModel(code: element['code'], value: element['value'])); }); openPercentage = double.tryParse(statusList[1].value.toString())!; curtainWidth = 270 - (openPercentage / 100) * curtainOpeningSpace; blindHeight = 310 - (openPercentage / 100) * blindOpeningSpace; add(UpdateCurtainEvent()); }); } catch (_) {} } @override Future close() async { _streamSubscription?.cancel(); _streamSubscription = null; return super.close(); } // _listenToChanges(curtainId) { // try { // print('curtainId=$curtainId'); // DatabaseReference ref = // FirebaseDatabase.instance.ref('device-status/$curtainId'); // Stream stream = ref.onValue; // stream.listen((DatabaseEvent event) async { // if (_timer != null) { // await Future.delayed(const Duration(seconds: 2)); // } // Map usersMap = // event.snapshot.value as Map; // List statusModelList = []; // for (var status in usersMap['status']) { // statusModelList.add(StatusModel.fromJson(status)); // print('statusModelList==${statusModelList}'); // } // openPercentage = double.tryParse(statusModelList[1].value.toString())!; // curtainWidth = 270 - (openPercentage / 100) * curtainOpeningSpace; // blindHeight = 310 - (openPercentage / 100) * blindOpeningSpace; // add(UpdateCurtainEvent()); // }); // } catch (_) {} // } _updateCurtain(UpdateCurtainEvent event, Emitter emit) { curtainWidth = 270 - (openPercentage / 100) * curtainOpeningSpace; blindHeight = 310 - (openPercentage / 100) * blindOpeningSpace; emit(CurtainsOpening( curtainWidth: curtainWidth, blindHeight: blindHeight, openPercentage: openPercentage, )); } List groupList = []; bool allSwitchesOn = true; List devicesList = []; CurtainModel deviceStatus = CurtainModel(control: 'stop', percent: 0); void _fetchWizardStatus( InitialWizardEvent event, Emitter emit) async { emit(LoadingInitialState()); try { devicesList = []; groupList = []; allSwitchesOn = true; devicesList = await DevicesAPI.getDeviceByGroupName( HomeCubit.getInstance().selectedSpace?.id ?? '', 'CUR'); for (int i = 0; i < devicesList.length; i++) { var response = await DevicesAPI.getDeviceStatus(devicesList[i].uuid ?? ''); List statusModelList = []; for (var status in response['status']) { statusModelList.add(StatusModel.fromJson(status)); } deviceStatus = CurtainModel.fromJson(statusModelList); groupList.add(GroupCurtainModel( deviceId: devicesList[i].uuid ?? '', deviceName: devicesList[i].name ?? '', firstSwitch: deviceStatus.control, percentControl: deviceStatus.percent)); } if (groupList.isNotEmpty) { groupList.firstWhere((element) { if (element.percentControl > 1) { allSwitchesOn = true; } return true; }); } emit( UpdateGroupState(curtainList: groupList, allSwitches: allSwitchesOn)); } catch (e) { emit(FailedState()); return; } } void _changeFirstWizardSwitch(ChangeFirstWizardSwitchStatusEvent event, Emitter emit) async { emit(LoadingNewSate(curtainModel: deviceStatus)); try { bool allSwitchesValue = true; // Update the firstSwitch value in the groupList based on the deviceId groupList.forEach((element) { if (element.deviceId == event.deviceId) { element.percentControl = event.value; // Set the new value from the event } if (element.percentControl > 1) { allSwitchesValue = true; // Check if any switch is not 'open' } }); final response = await DevicesAPI.deviceBatchController( code: 'percent_control', devicesUuid: [event.deviceId], value: event.value, // Use the value from the event ); emit(UpdateGroupState( curtainList: groupList, allSwitches: allSwitchesValue)); if (response['success']) { // Optionally add an initial event if needed. } } catch (_) { // Handle the error if needed. } } void _groupAllOn(GroupAllOnEvent event, Emitter emit) async { emit(LoadingNewSate(curtainModel: deviceStatus)); try { for (int i = 0; i < groupList.length; i++) { groupList[i].percentControl = 100; } emit(UpdateGroupState(curtainList: groupList, allSwitches: true)); List allDeviceIds = groupList.map((device) => device.deviceId).toList(); final response2 = await DevicesAPI.deviceBatchController( code: 'percent_control', devicesUuid: allDeviceIds, value: 100, ); if (response2['failedResults'].toString() != '[]') { await Future.delayed(const Duration(milliseconds: 500)); } } catch (_) { emit(FailedState()); await Future.delayed(const Duration(milliseconds: 500)); // Optionally add an initial event if needed. } } void _groupAllOff(GroupAllOffEvent event, Emitter emit) async { emit(LoadingNewSate(curtainModel: deviceStatus)); try { for (int i = 0; i < groupList.length; i++) { groupList[i].percentControl = 0; } emit(UpdateGroupState(curtainList: groupList, allSwitches: false)); List allDeviceIds = groupList.map((device) => device.deviceId).toList(); final response2 = await DevicesAPI.deviceBatchController( code: 'percent_control', devicesUuid: allDeviceIds, value: 0, ); if (response2['failedResults'].toString() != '[]') { await Future.delayed(const Duration(milliseconds: 500)); } } catch (_) { emit(FailedState()); await Future.delayed(const Duration(milliseconds: 500)); } } }