import 'dart:async'; import 'package:bloc/bloc.dart'; import 'package:equatable/equatable.dart'; import 'package:flutter/material.dart'; import 'package:syncrow_web/pages/device_managment/all_devices/models/devices_model.dart'; import 'package:syncrow_web/pages/routiens/models/create_scene_and_autoamtion/create_automation_model.dart'; import 'package:syncrow_web/pages/routiens/models/create_scene_and_autoamtion/create_scene_model.dart'; import 'package:syncrow_web/pages/routiens/models/delay/delay_fucntions.dart'; import 'package:syncrow_web/pages/routiens/models/device_functions.dart'; import 'package:syncrow_web/pages/routiens/models/routine_details_model.dart'; import 'package:syncrow_web/pages/routiens/models/routine_model.dart'; import 'package:syncrow_web/services/devices_mang_api.dart'; import 'package:syncrow_web/services/routines_api.dart'; import 'package:syncrow_web/utils/constants/assets.dart'; import 'package:uuid/uuid.dart'; part 'routine_event.dart'; part 'routine_state.dart'; const spaceId = '25c96044-fadf-44bb-93c7-3c079e527ce6'; const communityId = 'aff21a57-2f91-4e5c-b99b-0182c3ab65a9'; class RoutineBloc extends Bloc { RoutineBloc() : super(const RoutineState()) { on(_onAddToIfContainer); on(_onAddToThenContainer); on(_onLoadScenes); on(_onLoadAutomation); on(_onAddFunctionsToRoutine); on(_onSearchRoutines); on(_onAddSelectedIcon); on(_onCreateScene); on(_onRemoveDragCard); on(_changeOperatorOperator); on(_onEffectiveTimeEvent); on(_onCreateAutomation); on(_onSetRoutineName); on(_onResetRoutineState); on(_onGetSceneDetails); on(_onGetAutomationDetails); on(_deleteScene); on(_deleteAutomation); on(_fetchDevices); on(_onUpdateScene); on(_onUpdateAutomation); } void _onAddToIfContainer(AddToIfContainer event, Emitter emit) { final updatedIfItems = List>.from(state.ifItems); // Find the index of the item in teh current itemsList int index = updatedIfItems.indexWhere( (map) => map['uniqueCustomId'] == event.item['uniqueCustomId']); // Replace the map if the index is valid if (index != -1) { updatedIfItems[index] = event.item; } else { updatedIfItems.add(event.item); } if (event.isTabToRun) { emit(state.copyWith( ifItems: updatedIfItems, isTabToRun: true, isAutomation: false)); } else { emit(state.copyWith( ifItems: updatedIfItems, isTabToRun: false, isAutomation: true)); } } void _onAddToThenContainer( AddToThenContainer event, Emitter emit) { final currentItems = List>.from(state.thenItems); // Find the index of the item in teh current itemsList int index = currentItems.indexWhere( (map) => map['uniqueCustomId'] == event.item['uniqueCustomId']); // Replace the map if the index is valid if (index != -1) { currentItems[index] = event.item; } else { currentItems.add(event.item); } emit(state.copyWith(thenItems: currentItems)); } void _onAddFunctionsToRoutine( AddFunctionToRoutine event, Emitter emit) { try { if (event.functions.isEmpty) return; List selectedFunction = List.from(event.functions); Map> currentSelectedFunctions = Map>.from(state.selectedFunctions); if (currentSelectedFunctions.containsKey(event.uniqueCustomId)) { List currentFunctions = List.from( currentSelectedFunctions[event.uniqueCustomId] ?? []); List functionCode = []; for (int i = 0; i < selectedFunction.length; i++) { for (int j = 0; j < currentFunctions.length; j++) { if (selectedFunction[i].functionCode == currentFunctions[j].functionCode) { currentFunctions[j] = selectedFunction[i]; if (!functionCode.contains(currentFunctions[j].functionCode)) { functionCode.add(currentFunctions[j].functionCode); } } } } for (int i = 0; i < functionCode.length; i++) { selectedFunction .removeWhere((code) => code.functionCode == functionCode[i]); } currentSelectedFunctions[event.uniqueCustomId] = List.from(currentFunctions)..addAll(selectedFunction); } else { currentSelectedFunctions[event.uniqueCustomId] = List.from(event.functions); } emit(state.copyWith(selectedFunctions: currentSelectedFunctions)); } catch (e) { debugPrint('Error adding functions: $e'); } } Future _onLoadScenes( LoadScenes event, Emitter emit) async { emit(state.copyWith(isLoading: true, errorMessage: null)); try { final scenes = await SceneApi.getScenesByUnitId(event.unitId, event.communityId); emit(state.copyWith( scenes: scenes, isLoading: false, )); } catch (e) { emit(state.copyWith( isLoading: false, loadScenesErrorMessage: 'Failed to load scenes', errorMessage: '', loadAutomationErrorMessage: '', )); } } Future _onLoadAutomation( LoadAutomation event, Emitter emit) async { emit(state.copyWith(isLoading: true, errorMessage: null)); try { final automations = await SceneApi.getAutomationByUnitId(event.unitId); if (automations.isNotEmpty) { emit(state.copyWith( automations: automations, isLoading: false, )); } else { emit(state.copyWith( isLoading: false, loadAutomationErrorMessage: 'Failed to load automations', errorMessage: '', loadScenesErrorMessage: '', )); } } catch (e) { emit(state.copyWith( isLoading: false, loadAutomationErrorMessage: 'Failed to load automations', errorMessage: '', loadScenesErrorMessage: '', )); } } FutureOr _onSearchRoutines( SearchRoutines event, Emitter emit) async { emit(state.copyWith(isLoading: true, errorMessage: null)); await Future.delayed(const Duration(seconds: 1)); emit(state.copyWith(isLoading: false, errorMessage: null)); emit(state.copyWith(searchText: event.query)); } FutureOr _onAddSelectedIcon( AddSelectedIcon event, Emitter emit) { emit(state.copyWith(selectedIcon: event.icon)); } bool _isFirstActionDelay(List> actions) { if (actions.isEmpty) return false; return actions.first['deviceId'] == 'delay'; } Future _onCreateScene( CreateSceneEvent event, Emitter emit) async { try { // Check if first action is delay if (_isFirstActionDelay(state.thenItems)) { emit(state.copyWith( errorMessage: 'Cannot have delay as the first action', isLoading: false, )); return; } emit(state.copyWith(isLoading: true)); final actions = state.thenItems.expand((item) { final functions = state.selectedFunctions[item['uniqueCustomId']] ?? []; return functions.map((function) { if (function.functionCode == 'automation') { return CreateSceneAction( entityId: function.entityId, actionExecutor: function.value, executorProperty: null, ); } if (item['deviceId'] == 'delay') { return CreateSceneAction( entityId: function.entityId, actionExecutor: 'delay', executorProperty: CreateSceneExecutorProperty( functionCode: '', functionValue: '', delaySeconds: int.tryParse(function.value.toString()) ?? 0, ), ); } return CreateSceneAction( entityId: function.entityId, actionExecutor: 'device_issue', executorProperty: CreateSceneExecutorProperty( functionCode: function.functionCode, functionValue: function.value, delaySeconds: 0, ), ); }); }).toList(); final createSceneModel = CreateSceneModel( spaceUuid: spaceId, iconId: state.selectedIcon ?? '', showInDevice: true, sceneName: state.routineName!, decisionExpr: 'and', actions: actions, ); final result = await SceneApi.createScene(createSceneModel); if (result['success']) { emit(_resetState()); add(const LoadScenes(spaceId, communityId)); } else { emit(state.copyWith( isLoading: false, errorMessage: result['message'], )); } } catch (e) { emit(state.copyWith( isLoading: false, errorMessage: 'Something went wrong', )); } } Future _onCreateAutomation( CreateAutomationEvent event, Emitter emit) async { try { if (state.routineName == null || state.routineName!.isEmpty) { emit(state.copyWith( errorMessage: 'Automation name is required', )); return; } emit(state.copyWith(isLoading: true)); final conditions = state.ifItems.expand((item) { final functions = state.selectedFunctions[item['uniqueCustomId']] ?? []; return functions.map((function) { return Condition( code: state.selectedFunctions[item['uniqueCustomId']]!.indexOf( function, ) + 1, entityId: function.entityId, entityType: 'device_report', expr: ConditionExpr( statusCode: function.functionCode, comparator: function.condition ?? '==', statusValue: function.value, ), ); }); }).toList(); if (conditions.isEmpty) { emit(state.copyWith( isLoading: false, errorMessage: 'At least one condition is required', )); return; } final actions = state.thenItems.expand((item) { final functions = state.selectedFunctions[item['uniqueCustomId']] ?? []; return functions.map((function) { if (function.functionCode == 'automation') { return AutomationAction( entityId: function.entityId, actionExecutor: function.value, ); } if (item['deviceId'] == 'delay') { return AutomationAction( entityId: function.entityId, actionExecutor: 'delay', executorProperty: ExecutorProperty( delaySeconds: int.tryParse(function.value.toString()) ?? 0, ), ); } return AutomationAction( entityId: function.entityId, actionExecutor: 'device_issue', executorProperty: ExecutorProperty( functionCode: function.functionCode, functionValue: function.value, ), ); }); }).toList(); final createAutomationModel = CreateAutomationModel( spaceUuid: spaceId, automationName: state.routineName!, decisionExpr: state.selectedAutomationOperator, effectiveTime: EffectiveTime( start: state.effectiveTime?.start ?? '00:00', end: state.effectiveTime?.end ?? '23:59', loops: state.effectiveTime?.loops ?? '1111111', ), conditions: conditions, actions: actions, ); final result = await SceneApi.createAutomation(createAutomationModel); if (result['success']) { emit(_resetState()); add(const LoadAutomation(spaceId)); } else { emit(state.copyWith( isLoading: false, errorMessage: result['message'], )); } } catch (e) { emit(state.copyWith( isLoading: false, errorMessage: 'Something went wrong', )); } } FutureOr _onRemoveDragCard( RemoveDragCard event, Emitter emit) { if (event.isFromThen) { final thenItems = List>.from(state.thenItems); final selectedFunctions = Map>.from(state.selectedFunctions); thenItems.removeAt(event.index); selectedFunctions.remove(event.key); emit(state.copyWith( thenItems: thenItems, selectedFunctions: selectedFunctions)); } else { final ifItems = List>.from(state.ifItems); final selectedFunctions = Map>.from(state.selectedFunctions); ifItems.removeAt(event.index); selectedFunctions.remove(event.key); if (ifItems.isEmpty && state.thenItems.isEmpty) { emit(state.copyWith( ifItems: ifItems, selectedFunctions: selectedFunctions, isAutomation: false, isTabToRun: false)); } else { emit(state.copyWith( ifItems: ifItems, selectedFunctions: selectedFunctions)); } } } FutureOr _changeOperatorOperator( ChangeAutomationOperator event, Emitter emit) { emit(state.copyWith( selectedAutomationOperator: event.operator, )); } FutureOr _onEffectiveTimeEvent( EffectiveTimePeriodEvent event, Emitter emit) { emit(state.copyWith(effectiveTime: event.effectiveTime)); } FutureOr _onSetRoutineName( SetRoutineName event, Emitter emit) { emit(state.copyWith(routineName: event.name)); } ( List>, List>, Map> ) _createCardData( List actions, List? conditions, Map> currentFunctions, bool isTabToRun, ) { final ifItems = isTabToRun ? [ { 'entityId': 'tab_to_run', 'uniqueCustomId': const Uuid().v4(), 'deviceId': 'tab_to_run', 'title': 'Tab to run', 'productType': 'tab_to_run', 'imagePath': Assets.tabToRun, } ] : conditions?.map((condition) { final matchingDevice = state.devices.firstWhere( (device) => device.uuid == condition.entityId, orElse: () => AllDevicesModel( uuid: condition.entityId, name: condition.entityId, productType: condition.entityType, ), ); final cardData = { 'entityId': condition.entityId, 'uniqueCustomId': const Uuid().v4(), 'deviceId': condition.entityId, 'title': matchingDevice.name ?? condition.entityId, 'productType': condition.entityType, 'imagePath': matchingDevice.getDefaultIcon(condition.entityType), }; final functions = matchingDevice.functions; for (var function in functions) { if (function.code == condition.expr.statusCode) { currentFunctions[cardData['uniqueCustomId'] ?? ''] = [ DeviceFunctionData( entityId: condition.entityId, functionCode: condition.expr.statusCode, value: condition.expr.statusValue, operationName: function.operationName, ), ]; break; } } return cardData; }).toList() ?? []; final thenItems = actions.map((action) { final matchingDevice = state.devices.firstWhere( (device) => device.uuid == action.entityId, orElse: () => AllDevicesModel( uuid: action.entityId, name: action.entityId, productType: action.productType, ), ); final cardData = { 'entityId': action.entityId, 'uniqueCustomId': const Uuid().v4(), 'deviceId': action.actionExecutor == 'delay' ? 'delay' : action.entityId, 'title': action.actionExecutor == 'delay' ? 'Delay' : (matchingDevice.name ?? 'Device'), 'productType': action.productType, 'imagePath': matchingDevice.getDefaultIcon(action.productType), }; final functions = matchingDevice.functions; if (action.executorProperty != null && action.actionExecutor != 'delay') { final functionCode = action.executorProperty!.functionCode; for (var function in functions) { if (function.code == functionCode) { currentFunctions[cardData['uniqueCustomId'] ?? ''] = [ DeviceFunctionData( entityId: action.entityId, functionCode: functionCode ?? '', value: action.executorProperty!.functionValue, operationName: function.operationName, ), ]; break; } } } else if (action.actionExecutor == 'delay') { final delayFunction = DelayFunction( deviceId: action.entityId, deviceName: 'Delay', ); currentFunctions[cardData['uniqueCustomId'] ?? ''] = [ DeviceFunctionData( entityId: action.entityId, functionCode: 'delay', value: action.executorProperty?.delaySeconds ?? 0, operationName: delayFunction.operationName, ), ]; } return cardData; }).toList(); return (thenItems, ifItems, currentFunctions); } Future _onGetSceneDetails( GetSceneDetails event, Emitter emit) async { try { emit(state.copyWith( isLoading: true, isTabToRun: event.isTabToRun, isUpdate: true, sceneId: event.sceneId, isAutomation: false, ifItems: [], thenItems: [], )); final sceneDetails = await SceneApi.getSceneDetails(event.sceneId); final List> thenItems; final List> ifItems; final Map> updatedFunctions = Map>.from(state.selectedFunctions); if (event.isTabToRun) { thenItems = sceneDetails.actions.map((action) { late AllDevicesModel? matchingDevice; for (var device in state.devices) { if (device.uuid == action.entityId) { matchingDevice = device; break; } } final cardData = { 'entityId': action.entityId, 'uniqueCustomId': const Uuid().v4(), 'deviceId': action.actionExecutor == 'delay' ? 'delay' : action.entityId, 'title': action.actionExecutor == 'delay' ? 'Delay' : action.type == 'automation' ? action.name ?? 'Automation' : (matchingDevice?.name ?? 'Device'), 'productType': action.productType, 'functions': matchingDevice?.functions, 'imagePath': matchingDevice?.getDefaultIcon(action.productType), 'device': matchingDevice, }; if (action.type == 'automation') { updatedFunctions[cardData['uniqueCustomId'].toString()] = [ DeviceFunctionData( entityId: action.entityId, functionCode: 'rule', value: action.actionExecutor, operationName: action.name ?? 'Automation', ), ]; } else if (action.executorProperty != null && action.actionExecutor != 'delay') { final functions = matchingDevice?.functions; final functionCode = action.executorProperty!.functionCode; for (var function in functions ?? []) { if (function.code == functionCode) { updatedFunctions[cardData['uniqueCustomId'].toString()] = [ DeviceFunctionData( entityId: action.entityId, functionCode: functionCode ?? '', value: action.executorProperty!.functionValue, operationName: function.operationName, ), ]; break; } } } else if (action.actionExecutor == 'delay') { final delayFunction = DelayFunction( deviceId: action.entityId, deviceName: 'Delay', ); updatedFunctions[cardData['uniqueCustomId'].toString()] = [ DeviceFunctionData( entityId: action.entityId, functionCode: 'delay', value: action.executorProperty?.delaySeconds ?? 0, operationName: delayFunction.operationName, ), ]; } return cardData; }).toList(); ifItems = [ { 'entityId': 'tab_to_run', 'uniqueCustomId': const Uuid().v4(), 'deviceId': 'tab_to_run', 'title': 'Tab to run', 'productType': 'tab_to_run', 'imagePath': Assets.tabToRun, } ]; } else { final result = _createCardData( sceneDetails.actions, sceneDetails.conditions, updatedFunctions, false, ); thenItems = result.$1; ifItems = result.$2; } emit(state.copyWith( isLoading: false, routineName: sceneDetails.name, selectedIcon: sceneDetails.iconId, selectedAutomationOperator: sceneDetails.decisionExpr, effectiveTime: sceneDetails.effectiveTime, isAutomation: false, isTabToRun: event.isTabToRun, thenItems: thenItems, ifItems: ifItems, selectedFunctions: updatedFunctions, sceneId: sceneDetails.sceneId, )); } catch (e) { emit(state.copyWith( isLoading: false, errorMessage: 'Failed to load scene details: $e', )); } } Future _onGetAutomationDetails( GetAutomationDetails event, Emitter emit) async { try { emit(state.copyWith( isLoading: true, isUpdate: true, isTabToRun: false, automationId: event.automationId, isAutomation: true, ifItems: [], thenItems: [], )); final automationDetails = await SceneApi.getAutomationDetails(event.automationId); final List> thenItems; final List> ifItems; final Map> updatedFunctions = Map>.from(state.selectedFunctions); ifItems = automationDetails.conditions?.map((condition) { late AllDevicesModel? matchingDevice; for (var device in state.devices) { if (device.uuid == condition.entityId) { matchingDevice = device; break; } } final cardData = { 'entityId': condition.entityId, 'uniqueCustomId': const Uuid().v4(), 'deviceId': condition.expr.statusCode == 'delay' ? 'delay' : condition.entityId, 'title': condition.expr.statusCode == 'delay' ? 'Delay' : (matchingDevice?.name ?? 'Device'), 'productType': condition.productType, 'functions': matchingDevice?.functions, 'imagePath': matchingDevice?.getDefaultIcon(condition.productType), 'device': matchingDevice, }; final functions = matchingDevice?.functions; for (var function in functions ?? []) { if (function.code == condition.expr.statusCode) { updatedFunctions[cardData['uniqueCustomId'].toString()] = [ DeviceFunctionData( entityId: condition.entityId, functionCode: condition.expr.statusCode, value: condition.expr.statusValue, operationName: function.operationName, ), ]; break; } } return cardData; }).toList() ?? []; // Create then items from actions thenItems = automationDetails.actions.map((action) { final matchingDevice = state.devices.firstWhere( (device) => device.uuid == action.entityId, orElse: () => AllDevicesModel( uuid: action.entityId, name: action.entityId, productType: action.productType, ), ); final cardData = { 'entityId': action.entityId, 'uniqueCustomId': const Uuid().v4(), 'deviceId': action.actionExecutor == 'delay' ? 'delay' : action.entityId, 'title': action.actionExecutor == 'delay' ? 'Delay' : (matchingDevice.name ?? 'Device'), 'productType': action.productType, 'functions': matchingDevice.functions, 'imagePath': matchingDevice.getDefaultIcon(action.productType), 'device': matchingDevice, }; if (action.executorProperty != null && action.actionExecutor != 'delay') { final functions = matchingDevice.functions; final functionCode = action.executorProperty!.functionCode; for (var function in functions) { if (function.code == functionCode) { updatedFunctions[cardData['uniqueCustomId'].toString()] = [ DeviceFunctionData( entityId: action.entityId, functionCode: functionCode ?? '', value: action.executorProperty!.functionValue, operationName: function.operationName, ), ]; break; } } } else if (action.actionExecutor == 'delay') { final delayFunction = DelayFunction( deviceId: action.entityId, deviceName: 'Delay', ); updatedFunctions[cardData['uniqueCustomId'].toString()] = [ DeviceFunctionData( entityId: action.entityId, functionCode: 'delay', value: action.executorProperty?.delaySeconds ?? 0, operationName: delayFunction.operationName, ), ]; } else if (action.actionExecutor == 'rule_disable' || action.actionExecutor == 'rule_enable') { updatedFunctions[cardData['uniqueCustomId'].toString()] = [ DeviceFunctionData( entityId: action.entityId, functionCode: 'automation', value: action.actionExecutor, operationName: action.name ?? 'Automation', ), ]; } return cardData; }).toList(); emit(state.copyWith( isLoading: false, routineName: automationDetails.name, selectedAutomationOperator: automationDetails.decisionExpr, effectiveTime: automationDetails.effectiveTime, isAutomation: true, thenItems: thenItems, ifItems: ifItems, selectedFunctions: updatedFunctions, automationId: automationDetails.automationId, )); } catch (e) { emit(state.copyWith( isLoading: false, errorMessage: 'Failed to load automation details: $e', )); } } RoutineState _resetState() { return const RoutineState( ifItems: [], thenItems: [], selectedFunctions: {}, scenes: [], automations: [], isLoading: false, errorMessage: null, loadScenesErrorMessage: null, loadAutomationErrorMessage: null, searchText: '', selectedIcon: null, isTabToRun: false, isAutomation: false, selectedAutomationOperator: 'or', effectiveTime: null, routineName: null, ); } FutureOr _onResetRoutineState( ResetRoutineState event, Emitter emit) { emit(_resetState()); } FutureOr _deleteScene(DeleteScene event, Emitter emit) { try { SceneApi.deleteScene(unitUuid: spaceId, sceneId: event.sceneId); add(const LoadScenes(spaceId, communityId)); } catch (e) { emit(state.copyWith( isLoading: false, errorMessage: 'Failed to delete scene', )); } } FutureOr _deleteAutomation( DeleteAutomation event, Emitter emit) { try { SceneApi.deleteAutomation( unitUuid: spaceId, automationId: event.automationId); add(const LoadAutomation(spaceId)); } catch (e) { emit(state.copyWith( isLoading: false, errorMessage: 'Failed to delete automation', )); } } FutureOr _fetchDevices( FetchDevicesInRoutine event, Emitter emit) async { emit(state.copyWith(isLoading: true)); try { final devices = await DevicesManagementApi().fetchDevices(); emit(state.copyWith(isLoading: false, devices: devices)); } catch (e) { emit(state.copyWith(isLoading: false)); } } FutureOr _onUpdateScene( UpdateScene event, Emitter emit) async { try { // Check if first action is delay if (_isFirstActionDelay(state.thenItems)) { emit(state.copyWith( errorMessage: 'Cannot have delay as the first action', isLoading: false, )); return; } emit(state.copyWith(isLoading: true)); final actions = state.thenItems.expand((item) { final functions = state.selectedFunctions[item['uniqueCustomId']] ?? []; return functions.map((function) { if (function.functionCode == 'automation') { return CreateSceneAction( entityId: function.entityId, actionExecutor: function.value, executorProperty: null, ); } if (item['deviceId'] == 'delay') { return CreateSceneAction( entityId: function.entityId, actionExecutor: 'delay', executorProperty: CreateSceneExecutorProperty( functionCode: '', functionValue: '', delaySeconds: int.tryParse(function.value.toString()) ?? 0, ), ); } return CreateSceneAction( entityId: function.entityId, actionExecutor: 'device_issue', executorProperty: CreateSceneExecutorProperty( functionCode: function.functionCode, functionValue: function.value, delaySeconds: 0, ), ); }); }).toList(); final createSceneModel = CreateSceneModel( spaceUuid: state.sceneId ?? '', iconId: state.selectedIcon ?? '', showInDevice: true, sceneName: state.routineName ?? '', decisionExpr: 'and', actions: actions, ); final result = await SceneApi.updateScene(createSceneModel, state.sceneId ?? ''); if (result['success']) { emit(_resetState()); add(const LoadScenes(spaceId, communityId)); } else { emit(state.copyWith( isLoading: false, errorMessage: result['message'], )); } } catch (e) { emit(state.copyWith( isLoading: false, errorMessage: 'Something went wrong', )); } } FutureOr _onUpdateAutomation( UpdateAutomation event, Emitter emit) async { if (_isFirstActionDelay(state.thenItems)) { emit(state.copyWith( errorMessage: 'Cannot have delay as the first action', isLoading: false, )); return; } emit(state.copyWith(isLoading: true)); try { final conditions = state.ifItems .map((item) { final functions = state.selectedFunctions[item['uniqueCustomId']] ?? []; if (functions.isEmpty) return null; final function = functions.first; return Condition( code: state.ifItems.indexOf(item) + 1, entityId: function.entityId, entityType: item['productType'], expr: ConditionExpr( statusCode: function.functionCode, statusValue: function.value, comparator: function.condition ?? '==', ), ); }) .whereType() .toList(); final actions = state.thenItems .map((item) { final functions = state.selectedFunctions[item['uniqueCustomId']] ?? []; if (functions.isEmpty) return null; final function = functions.first; return AutomationAction( entityId: function.entityId, actionExecutor: function.actionExecutor, executorProperty: ExecutorProperty( functionCode: function.functionCode, functionValue: function.value, delaySeconds: function.functionCode == 'delay' ? (function.value as num).toInt() : null, ), ); }) .whereType() .toList(); final createAutomationModel = CreateAutomationModel( spaceUuid: spaceId, automationName: state.routineName ?? '', decisionExpr: state.selectedAutomationOperator, effectiveTime: state.effectiveTime ?? EffectiveTime(start: '', end: '', loops: ''), conditions: conditions, actions: actions, ); await SceneApi.updateAutomation( createAutomationModel, state.automationId ?? ''); add(const LoadAutomation(spaceId)); emit(state.copyWith(isLoading: false)); } catch (e) { emit(state.copyWith( isLoading: false, errorMessage: 'Failed to update automation: $e', )); } } }