import 'dart:async'; import 'package:equatable/equatable.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:syncrow_app/features/app_layout/bloc/home_cubit.dart'; import 'package:syncrow_app/features/auth/model/project_model.dart'; import 'package:syncrow_app/features/devices/model/device_control_model.dart'; import 'package:syncrow_app/features/scene/bloc/effective_period/effect_period_bloc.dart'; import 'package:syncrow_app/features/scene/bloc/effective_period/effect_period_event.dart'; import 'package:syncrow_app/features/scene/enum/create_scene_enum.dart'; import 'package:syncrow_app/features/scene/enum/operation_dialog_type.dart'; import 'package:syncrow_app/features/scene/helper/scene_operations_data_helper.dart'; import 'package:syncrow_app/features/scene/model/create_automation_model.dart'; import 'package:syncrow_app/features/scene/model/create_scene_model.dart'; import 'package:syncrow_app/features/scene/model/icon_model.dart'; import 'package:syncrow_app/features/scene/model/scene_static_function.dart'; import 'package:syncrow_app/navigation/navigation_service.dart'; import 'package:syncrow_app/services/api/scene_api.dart'; import 'package:syncrow_app/utils/helpers/snack_bar.dart'; part 'create_scene_event.dart'; part 'create_scene_state.dart'; class CreateSceneBloc extends Bloc with SceneOperationsDataHelper { CreateSceneBloc() : super(CreateSceneInitial()) { on(_createSceneWithTasks); on(_onAddSceneTask); on(_selectedValue); on(_removeTaskById); on(_clearTaskList); on(_clearTempTaskList); on(_fetchSceneTasks); on(_onTempHoldSceneTask); on(_removeTempTaskById); on(_removeFromSelectedValueById); on(_deleteScene); on(_updateTaskValue); on(_selectConditionRule); on(_sceneTypeEvent); on(_onEffectiveTimeEvent); on(_fetchIconScene); on(_iconSelected); on(_showInDeviceClicked); on(_clearTabToRunSetting); } CreateSceneEnum sceneType = CreateSceneEnum.none; /// tab to run values and list List tasksList = []; List tempTasksList = []; final Map selectedValues = {}; /// automation values and list List automationTasksList = []; List automationTempTasksList = []; final Map automationSelectedValues = {}; final Map automationComparatorValues = {}; String conditionRule = 'or'; EffectiveTime? effectiveTime; List iconModelList = []; String selectedIcon = ''; bool showInDeviceScreen = false; FutureOr _onAddSceneTask( AddTaskEvent event, Emitter emit) { emit(CreateSceneLoading()); if (event.isAutomation == true) { final copyList = List.from(automationTempTasksList); automationTasksList.addAll(copyList); automationTempTasksList.clear(); automationSelectedValues.clear(); automationComparatorValues.clear(); emit(AddSceneTask( automationTasksList: automationTasksList, tasksList: tasksList, condition: conditionRule, )); } else { final copyList = List.from(tempTasksList); tasksList.addAll(copyList); tempTasksList.clear(); selectedValues.clear(); emit(AddSceneTask( tasksList: tasksList, automationTasksList: automationTasksList, condition: conditionRule, )); } } FutureOr _onTempHoldSceneTask( TempHoldSceneTasksEvent event, Emitter emit) { if (event.isAutomation == true) { addToTempAutomationTaskList(event, emit); } else { addToTempTaskList(event, emit); } } void addToTempTaskList( TempHoldSceneTasksEvent event, Emitter emit) { emit(CreateSceneLoading()); bool updated = false; // Check and update if the task exists in tempTasksList for (var element in tempTasksList) { if (element.code == event.deviceControlModel.code) { var updatedElement = element.copyWith( deviceType: event.deviceType, operationName: event.operation, deviceName: event.deviceName, icon: event.icon, code: event.deviceControlModel.code ?? '', deviceId: event.deviceId, functionValue: event.deviceControlModel.value, operationDialogType: event.operationType, operationalValues: [ SceneOperationalValue( value: event.deviceControlModel.value, icon: '', ), ], ); tempTasksList[tempTasksList.indexOf(element)] = updatedElement; selectedValues[updatedElement.code] = event.deviceControlModel.value; updated = true; break; } } if (!updated) { /// for smart scene add to view for (var element in tasksList) { if (element.deviceId == event.deviceControlModel.deviceId && element.code == event.deviceControlModel.code) { var updatedElement = element.copyWith( deviceType: event.deviceType, operationName: event.operation, deviceName: event.deviceName, icon: event.icon, code: event.deviceControlModel.code ?? '', deviceId: event.deviceId, functionValue: event.deviceControlModel.value, operationDialogType: event.operationType, operationalValues: [ SceneOperationalValue( value: event.deviceControlModel.value, icon: '', ), ], ); tasksList[tasksList.indexOf(element)] = updatedElement; selectedValues[updatedElement.code] = event.deviceControlModel.value; updated = true; break; } } } // Add new element if it doesn't exist in either list if (!updated) { var newElement = SceneStaticFunction( deviceType: event.deviceType, operationName: event.operation, deviceName: event.deviceName, icon: event.icon, code: event.deviceControlModel.code ?? '', operationDialogType: event.operationType, deviceId: event.deviceId, functionValue: event.deviceControlModel.value, operationalValues: [ SceneOperationalValue( value: event.deviceControlModel.value, icon: '', ), ], ); tempTasksList.add(newElement); selectedValues[newElement.code] = event.deviceControlModel.value; } emit(AddSceneTask( tasksList: tasksList, automationTasksList: automationTasksList, condition: conditionRule, )); } void addToTempAutomationTaskList( TempHoldSceneTasksEvent event, Emitter emit) { emit(CreateSceneLoading()); bool updated = false; for (var element in automationTempTasksList) { if (element.code == event.deviceControlModel.code) { // Update the existing function with new values var updatedElement = element.copyWith( deviceType: element.deviceType, operationName: event.operation, deviceName: event.deviceName, icon: event.icon, code: event.deviceControlModel.code ?? '', deviceId: event.deviceId, functionValue: event.deviceControlModel.value, operationDialogType: event.operationType, operationalValues: [ SceneOperationalValue( value: event.deviceControlModel.value, icon: '', ), ], comparator: automationComparatorValues[element.code], ); automationTempTasksList[automationTempTasksList.indexOf(element)] = updatedElement; automationSelectedValues[updatedElement.code] = event.deviceControlModel.value; updated = true; break; } } if (!updated) { var newElement = SceneStaticFunction( deviceType: event.deviceType, operationName: event.operation, deviceName: event.deviceName, icon: event.icon, code: event.deviceControlModel.code ?? '', operationDialogType: event.operationType, deviceId: event.deviceId, functionValue: event.deviceControlModel.value, operationalValues: [ SceneOperationalValue( value: event.deviceControlModel.value, icon: '', ), ], comparator: automationComparatorValues[event.deviceControlModel.code] ?? '==', ); automationTempTasksList.add(newElement); automationSelectedValues[newElement.code] = event.deviceControlModel.value; } emit(AddSceneTask( tasksList: tasksList, automationTasksList: automationTasksList, condition: conditionRule, )); } FutureOr _selectedValue( SelectedValueEvent event, Emitter emit) { if (event.isAutomation == true) { automationSelectedValues[event.code] = event.value; automationComparatorValues[event.code] = event.comparator ?? '=='; // Update the comparator value for the specific task in automationTasksList for (int i = 0; i < automationTasksList.length; i++) { if (automationTasksList[i].code == event.code) { automationTasksList[i] = automationTasksList[i].copyWith( comparator: event.comparator ?? '==', functionValue: event.value, ); break; } } for (int i = 0; i < tasksList.length; i++) { if (tasksList[i].code == event.code) { tasksList[i] = tasksList[i].copyWith( comparator: event.comparator ?? '==', functionValue: event.value, ); break; } } } else { selectedValues[event.code] = event.value; } emit(SelectedTaskValueState(value: event.value)); emit(AddSceneTask( tasksList: List.from(tasksList), automationTasksList: List.from( automationTasksList, ), condition: conditionRule, )); } FutureOr _removeTaskById( RemoveTaskByIdEvent event, Emitter emit) { emit(CreateSceneLoading()); if (event.isAutomation == true) { for (var element in automationTasksList) { if (element.uniqueCustomId == event.taskId) { automationTasksList.remove(element); emit(AddSceneTask( tasksList: tasksList, automationTasksList: automationTasksList, condition: conditionRule, )); break; } } } else { for (var element in tasksList) { if (element.uniqueCustomId == event.taskId) { tasksList.remove(element); emit(AddSceneTask( tasksList: tasksList, automationTasksList: automationTasksList, condition: conditionRule, )); break; } } } } FutureOr _removeTempTaskById( RemoveTempTaskByIdEvent event, Emitter emit) { emit(CreateSceneLoading()); if (event.isAutomation == true) { for (var element in automationTempTasksList) { if (element.uniqueCustomId == event.code) { automationTempTasksList.remove(element); emit(AddSceneTask( tasksList: tasksList, automationTasksList: automationTasksList, condition: conditionRule, )); break; } } } else { for (var element in tempTasksList) { if (element.code == event.code) { tempTasksList.remove(element); emit(AddSceneTask( tasksList: tasksList, automationTasksList: automationTasksList, condition: conditionRule, )); break; } } } } FutureOr _createSceneWithTasks( CreateSceneWithTasksEvent event, Emitter emit) async { emit(CreateSceneLoading()); try { dynamic response; Project? project = HomeCubit.getInstance().project; if (event.createSceneModel != null) { response = event.updateScene ? await SceneApi.updateScene(event.createSceneModel!, event.sceneId) : await SceneApi.createScene(event.createSceneModel!); } else if (event.createAutomationModel != null) { response = event.updateScene ? await SceneApi.updateAutomation(event.createAutomationModel!, event.sceneId, project?.uuid ?? '') : await SceneApi.createAutomation( event.createAutomationModel!, project?.uuid ?? ''); } if (response['success'] == true) { tasksList.clear(); tempTasksList.clear(); selectedValues.clear(); automationTasksList.clear(); automationTempTasksList.clear(); automationSelectedValues.clear(); automationComparatorValues.clear(); selectedIcon = ''; showInDeviceScreen = false; effectiveTime = EffectiveTime(start: '00:00', end: '23:59', loops: '1111111'); sceneType = CreateSceneEnum.none; conditionRule = 'or'; emit(const CreateSceneWithTasks(success: true)); CustomSnackBar.greenSnackBar(event.updateScene ? 'Scene updated successfully' : 'Scene created successfully'); } else { emit(const CreateSceneError(message: 'Something went wrong')); } } catch (e) { emit(const CreateSceneError(message: 'Something went wrong')); emit(AddSceneTask( tasksList: tasksList, automationTasksList: automationTasksList, condition: conditionRule, )); } } FutureOr _clearTaskList( ClearTaskListEvent event, Emitter emit) { emit(CreateSceneLoading()); automationTasksList.clear(); tasksList.clear(); emit(AddSceneTask( tasksList: tasksList, automationTasksList: automationTasksList, condition: conditionRule, )); } FutureOr _clearTabToRunSetting( ClearTabToRunSetting event, Emitter emit) { emit(CreateSceneLoading()); selectedIcon = ''; showInDeviceScreen = false; emit(AddSceneTask( tasksList: tasksList, automationTasksList: automationTasksList, condition: conditionRule, showInDevice: showInDeviceScreen, selectedIcon: selectedIcon, iconModels: iconModelList)); } FutureOr _fetchSceneTasks( FetchSceneTasksEvent event, Emitter emit) async { emit(CreateSceneLoading()); try { Project? project = HomeCubit.getInstance().project; tasksList.clear(); tempTasksList.clear(); selectedValues.clear(); automationTasksList.clear(); automationTempTasksList.clear(); automationSelectedValues.clear(); automationComparatorValues.clear(); selectedIcon = ''; showInDeviceScreen = false; effectiveTime = EffectiveTime(start: '00:00', end: '23:59', loops: '1111111'); sceneType = CreateSceneEnum.none; conditionRule = 'or'; final response = event.isAutomation ? await SceneApi.getAutomationDetails( event.sceneId, project?.uuid ?? '') : await SceneApi.getSceneDetails(event.sceneId); if (response.id.isNotEmpty) { if (event.isAutomation) { automationTasksList = List.from( getTaskListFunctionsFromApi( actions: [], isAutomation: true, conditions: response.conditions)); tasksList = List.from( getTaskListFunctionsFromApi( actions: response.actions, isAutomation: false)); conditionRule = response.decisionExpr ?? conditionRule; effectiveTime = response.effectiveTime != null ? EffectiveTime( start: response.effectiveTime!.start, end: response.effectiveTime!.end, loops: response.effectiveTime!.loops, ) : EffectiveTime(start: '00:00', end: '23:59', loops: '1111111'); // Set the days directly from the API response BlocProvider.of( NavigationService.navigatorKey.currentContext!) .add(SetDays(response.effectiveTime?.loops ?? '1111111')); // Set Custom Time and reset days first BlocProvider.of( NavigationService.navigatorKey.currentContext!) .add(SetCustomTime(effectiveTime!.start, effectiveTime!.end)); emit(AddSceneTask( automationTasksList: automationTasksList, tasksList: tasksList, condition: conditionRule, iconModels: iconModelList, selectedIcon: selectedIcon, showInDevice: showInDeviceScreen)); } else { tasksList = List.from( getTaskListFunctionsFromApi( actions: response.actions, isAutomation: false)); selectedIcon = response.icon!; showInDeviceScreen = response.showInDevice!; emit(AddSceneTask( tasksList: tasksList, condition: conditionRule, iconModels: iconModelList, selectedIcon: selectedIcon, showInDevice: showInDeviceScreen)); } } else { emit(const CreateSceneError(message: 'Something went wrong')); } } catch (e) { emit(const CreateSceneError(message: 'Something went wrong')); } } FutureOr _fetchIconScene( SceneIconEvent event, Emitter emit) async { emit(CreateSceneLoading()); try { iconModelList = await SceneApi.getIcon(); emit(AddSceneTask( tasksList: tasksList, automationTasksList: automationTasksList, condition: conditionRule, showInDevice: showInDeviceScreen, selectedIcon: selectedIcon, iconModels: iconModelList)); } catch (e) { emit(const CreateSceneError(message: 'Something went wrong')); } } FutureOr _iconSelected( IconSelected event, Emitter emit) async { try { if (event.confirmSelection) { selectedIcon = event.iconId; } emit(CreateSceneLoading()); emit(AddSceneTask( tasksList: tasksList, automationTasksList: automationTasksList, showInDevice: showInDeviceScreen, condition: conditionRule, selectedIcon: event.iconId, iconModels: iconModelList)); } catch (e) { emit(const CreateSceneError(message: 'Something went wrong')); } } FutureOr _showInDeviceClicked( ShowOnDeviceClicked event, Emitter emit) async { try { emit(CreateSceneLoading()); showInDeviceScreen = event.value; emit(AddSceneTask( tasksList: tasksList, automationTasksList: automationTasksList, condition: conditionRule, selectedIcon: selectedIcon, iconModels: iconModelList, showInDevice: showInDeviceScreen)); } catch (e) { emit(const CreateSceneError(message: 'Something went wrong')); } } String _getDayFromIndex(int index) { const days = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']; return days[index]; } FutureOr _clearTempTaskList( ClearTempTaskListEvent event, Emitter emit) { emit(CreateSceneLoading()); if (event.isAutomation == true) { automationTempTasksList.clear(); automationSelectedValues.clear(); automationComparatorValues.clear(); } else { tempTasksList.clear(); selectedValues.clear(); } emit(AddSceneTask( tasksList: tasksList, automationTasksList: automationTasksList, condition: conditionRule, )); } FutureOr _removeFromSelectedValueById( RemoveFromSelectedValueById event, Emitter emit) { emit(CreateSceneLoading()); if (event.isAutomation == true) { if (automationSelectedValues.containsKey(event.code)) { automationSelectedValues.remove(event.code); automationComparatorValues.remove(event.code); emit(const SelectedTaskValueState(value: null)); emit(AddSceneTask( tasksList: tasksList, automationTasksList: automationTasksList, condition: conditionRule, )); } } else { if (selectedValues.containsKey(event.code)) { selectedValues.remove(event.code); emit(const SelectedTaskValueState(value: null)); emit(AddSceneTask( tasksList: tasksList, automationTasksList: automationTasksList, condition: conditionRule, )); } } } FutureOr _deleteScene( DeleteSceneEvent event, Emitter emit) async { emit(DeleteSceneLoading()); try { Project? project = HomeCubit.getInstance().project; final response = sceneType.name == CreateSceneEnum.deviceStatusChanges.name ? await SceneApi.deleteAutomation( automationId: event.sceneId, unitUuid: event.unitUuid, projectId: project?.uuid ?? '') : await SceneApi.deleteScene( sceneId: event.sceneId, ); if (response == true) { emit(const DeleteSceneSuccess(true)); } else { emit(const DeleteSceneError(message: 'Something went wrong')); } } catch (e) { emit(const DeleteSceneError(message: 'Something went wrong')); } } FutureOr _updateTaskValue( UpdateTaskEvent event, Emitter emit) { emit(CreateSceneLoading()); if (event.isAutomation == true) { for (var i = 0; i < automationTasksList.length; i++) { if (automationTasksList[i].uniqueCustomId == event.taskId) { automationTasksList[i] = automationTasksList[i].copyWith( functionValue: event.newValue, ); break; } } for (var i = 0; i < tasksList.length; i++) { if (tasksList[i].uniqueCustomId == event.taskId) { tasksList[i] = tasksList[i].copyWith( functionValue: event.newValue, ); break; } } } else { for (var i = 0; i < tasksList.length; i++) { if (tasksList[i].uniqueCustomId == event.taskId) { tasksList[i] = tasksList[i].copyWith( functionValue: event.newValue, ); break; } } } emit(AddSceneTask( tasksList: tasksList, automationTasksList: automationTasksList, condition: conditionRule, )); } FutureOr _selectConditionRule( SelectConditionEvent event, Emitter emit) { emit(CreateSceneInitial()); if (event.condition.contains('any')) { conditionRule = 'or'; } else { conditionRule = 'and'; } emit(AddSceneTask( tasksList: tasksList, automationTasksList: automationTasksList, condition: conditionRule, )); } FutureOr _sceneTypeEvent( SceneTypeEvent event, Emitter emit) { // emit(CreateSceneInitial()); if (event.type == CreateSceneEnum.tabToRun) { sceneType = CreateSceneEnum.tabToRun; } else if (event.type == CreateSceneEnum.deviceStatusChanges) { sceneType = CreateSceneEnum.deviceStatusChanges; } else { sceneType = CreateSceneEnum.none; } // emit(SceneTypeState(event.type)); } FutureOr _onEffectiveTimeEvent( EffectiveTimePeriodEvent event, Emitter emit) { effectiveTime = event.period; } }