From e50a6d4c4b0d2b2512af50852510c1e0a32d65f6 Mon Sep 17 00:00:00 2001 From: ashraf_personal Date: Thu, 28 Nov 2024 01:11:31 +0300 Subject: [PATCH] added routines details apis --- .../bloc/routine_bloc/routine_bloc.dart | 212 +++++++++++++++--- .../bloc/routine_bloc/routine_event.dart | 33 +++ .../bloc/routine_bloc/routine_state.dart | 26 ++- lib/pages/routiens/models/routine_model.dart | 9 +- .../view/create_new_routine_view.dart | 10 +- .../fetch_routine_scenes_automation.dart | 2 + lib/services/routines_api.dart | 2 +- 7 files changed, 256 insertions(+), 38 deletions(-) diff --git a/lib/pages/routiens/bloc/routine_bloc/routine_bloc.dart b/lib/pages/routiens/bloc/routine_bloc/routine_bloc.dart index d857de76..9870819a 100644 --- a/lib/pages/routiens/bloc/routine_bloc/routine_bloc.dart +++ b/lib/pages/routiens/bloc/routine_bloc/routine_bloc.dart @@ -6,8 +6,11 @@ import 'package:flutter/material.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/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/routines_api.dart'; +import 'package:syncrow_web/utils/constants/assets.dart'; +import 'package:uuid/uuid.dart'; part 'routine_event.dart'; part 'routine_state.dart'; @@ -31,6 +34,9 @@ class RoutineBloc extends Bloc { on(_onCreateAutomation); on(_onSetRoutineName); on(_onResetRoutineState); + on(_onGetSceneDetails); + on(_onGetAutomationDetails); + on(_onInitializeRoutineState); // on(_onRemoveFunction); // on(_onClearFunctions); } @@ -39,8 +45,8 @@ class RoutineBloc extends Bloc { 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']); + 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; @@ -49,18 +55,21 @@ class RoutineBloc extends Bloc { } if (event.isTabToRun) { - emit(state.copyWith(ifItems: updatedIfItems, isTabToRun: true, isAutomation: false)); + emit(state.copyWith( + ifItems: updatedIfItems, isTabToRun: true, isAutomation: false)); } else { - emit(state.copyWith(ifItems: updatedIfItems, isTabToRun: false, isAutomation: true)); + emit(state.copyWith( + ifItems: updatedIfItems, isTabToRun: false, isAutomation: true)); } } - void _onAddToThenContainer(AddToThenContainer event, Emitter emit) { + 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']); + 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; @@ -71,22 +80,26 @@ class RoutineBloc extends Bloc { emit(state.copyWith(thenItems: currentItems)); } - void _onAddFunctionsToRoutine(AddFunctionToRoutine event, Emitter emit) { + void _onAddFunctionsToRoutine( + AddFunctionToRoutine event, Emitter emit) { try { if (event.functions.isEmpty) return; - List selectedFunction = List.from(event.functions); + 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.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) { + if (selectedFunction[i].functionCode == + currentFunctions[j].functionCode) { currentFunctions[j] = selectedFunction[i]; if (!functionCode.contains(currentFunctions[j].functionCode)) { functionCode.add(currentFunctions[j].functionCode); @@ -96,13 +109,15 @@ class RoutineBloc extends Bloc { } for (int i = 0; i < functionCode.length; i++) { - selectedFunction.removeWhere((code) => code.functionCode == functionCode[i]); + selectedFunction + .removeWhere((code) => code.functionCode == functionCode[i]); } - currentSelectedFunctions[event.uniqueCustomId] = List.from(currentFunctions) - ..addAll(selectedFunction); + currentSelectedFunctions[event.uniqueCustomId] = + List.from(currentFunctions)..addAll(selectedFunction); } else { - currentSelectedFunctions[event.uniqueCustomId] = List.from(event.functions); + currentSelectedFunctions[event.uniqueCustomId] = + List.from(event.functions); } emit(state.copyWith(selectedFunctions: currentSelectedFunctions)); @@ -111,11 +126,13 @@ class RoutineBloc extends Bloc { } } - Future _onLoadScenes(LoadScenes event, Emitter emit) async { + Future _onLoadScenes( + LoadScenes event, Emitter emit) async { emit(state.copyWith(isLoading: true, errorMessage: null)); try { - final scenes = await SceneApi.getScenesByUnitId(event.unitId, event.communityId); + final scenes = + await SceneApi.getScenesByUnitId(event.unitId, event.communityId); emit(state.copyWith( scenes: scenes, isLoading: false, @@ -130,7 +147,8 @@ class RoutineBloc extends Bloc { } } - Future _onLoadAutomation(LoadAutomation event, Emitter emit) async { + Future _onLoadAutomation( + LoadAutomation event, Emitter emit) async { emit(state.copyWith(isLoading: true, errorMessage: null)); try { @@ -158,14 +176,16 @@ class RoutineBloc extends Bloc { } } - FutureOr _onSearchRoutines(SearchRoutines event, Emitter emit) async { + 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) { + FutureOr _onAddSelectedIcon( + AddSelectedIcon event, Emitter emit) { emit(state.copyWith(selectedIcon: event.icon)); } @@ -174,7 +194,8 @@ class RoutineBloc extends Bloc { return actions.first['deviceId'] == 'delay'; } - Future _onCreateScene(CreateSceneEvent event, Emitter emit) async { + Future _onCreateScene( + CreateSceneEvent event, Emitter emit) async { try { // Check if first action is delay if (_isFirstActionDelay(state.thenItems)) { @@ -249,7 +270,8 @@ class RoutineBloc extends Bloc { } } - Future _onCreateAutomation(CreateAutomationEvent event, Emitter emit) async { + Future _onCreateAutomation( + CreateAutomationEvent event, Emitter emit) async { try { if (state.routineName == null || state.routineName!.isEmpty) { emit(state.copyWith( @@ -349,38 +371,165 @@ class RoutineBloc extends Bloc { } } - FutureOr _onRemoveDragCard(RemoveDragCard event, Emitter emit) { + FutureOr _onRemoveDragCard( + RemoveDragCard event, Emitter emit) { if (event.isFromThen) { final thenItems = List>.from(state.thenItems); - final selectedFunctions = Map>.from(state.selectedFunctions); + final selectedFunctions = + Map>.from(state.selectedFunctions); thenItems.removeAt(event.index); selectedFunctions.remove(event.key); - emit(state.copyWith(thenItems: thenItems, selectedFunctions: selectedFunctions)); + emit(state.copyWith( + thenItems: thenItems, selectedFunctions: selectedFunctions)); } else { final ifItems = List>.from(state.ifItems); - final selectedFunctions = Map>.from(state.selectedFunctions); + final selectedFunctions = + Map>.from(state.selectedFunctions); ifItems.removeAt(event.index); selectedFunctions.remove(event.key); - emit(state.copyWith(ifItems: ifItems, selectedFunctions: selectedFunctions)); + emit(state.copyWith( + ifItems: ifItems, selectedFunctions: selectedFunctions)); } } - FutureOr _changeOperatorOperator(ChangeAutomationOperator event, Emitter emit) { + FutureOr _changeOperatorOperator( + ChangeAutomationOperator event, Emitter emit) { emit(state.copyWith( selectedAutomationOperator: event.operator, )); } - FutureOr _onEffectiveTimeEvent(EffectiveTimePeriodEvent event, Emitter emit) { + FutureOr _onEffectiveTimeEvent( + EffectiveTimePeriodEvent event, Emitter emit) { emit(state.copyWith(effectiveTime: event.effectiveTime)); } - FutureOr _onSetRoutineName(SetRoutineName event, Emitter emit) { + FutureOr _onSetRoutineName( + SetRoutineName event, Emitter emit) { emit(state.copyWith(routineName: event.name)); } + Future _onGetSceneDetails( + GetSceneDetails event, Emitter emit) async { + try { + emit(state.copyWith( + isLoading: true, + isTabToRun: event.isTabToRun, + isUpdate: true, + sceneId: event.sceneId, + isAutomation: false)); + final sceneDetails = await SceneApi.getSceneDetails(event.sceneId); + add(InitializeRoutineState(sceneDetails)); + } catch (e) { + emit(state.copyWith( + isLoading: false, + errorMessage: 'Failed to load scene details', + )); + } + } + + Future _onGetAutomationDetails( + GetAutomationDetails event, Emitter emit) async { + try { + emit(state.copyWith( + isLoading: true, + isAutomation: event.isAutomation, + automationId: event.automationId, + isTabToRun: false, + isUpdate: true, + )); + final automationDetails = + await SceneApi.getAutomationDetails(event.automationId); + add(InitializeRoutineState(automationDetails)); + } catch (e) { + emit(state.copyWith( + isLoading: false, + errorMessage: 'Failed to load automation details', + )); + } + } + + void _onInitializeRoutineState( + InitializeRoutineState event, Emitter emit) { + final routineDetails = event.routineDetails; + + // Convert actions to draggable cards for the THEN container + final thenItems = routineDetails.actions.map((action) { + final Map cardData = { + 'entityId': action.entityId, + 'uniqueCustomId': const Uuid().v4(), + 'deviceId': + action.actionExecutor == 'delay' ? 'delay' : action.entityId, + 'title': action.actionExecutor == 'delay' ? 'Delay' : 'Device', + // fix this + 'imagePath': + action.actionExecutor == 'delay' ? Assets.delay : Assets.logo, + }; + + // Add functions to selectedFunctions + if (action.executorProperty != null) { + final functions = [ + DeviceFunctionData( + entityId: action.entityId, + functionCode: action.executorProperty!.functionCode ?? '', + value: action.executorProperty!.functionValue, + + /// fix this + operationName: action.executorProperty?.functionCode ?? ''), + ]; + state.selectedFunctions[cardData['uniqueCustomId']] = functions; + } + + return cardData; + }).toList() ?? + []; + + // Convert conditions to draggable cards for the IF container + final ifItems = routineDetails.conditions?.map((condition) { + final Map cardData = { + 'entityId': condition.entityId, + 'uniqueCustomId': const Uuid().v4(), + 'deviceId': condition.entityId, + + /// fix this + 'title': 'Device', + + /// fix this + 'imagePath': Assets.logo, + }; + + // Add functions to selectedFunctions + final functions = [ + DeviceFunctionData( + entityId: condition.entityId, + functionCode: condition.expr.statusCode, + value: condition.expr.statusValue, + condition: condition.expr.comparator, + operationName: condition.expr.comparator, + ), + ]; + state.selectedFunctions[cardData['uniqueCustomId']] = functions; + + return cardData; + }).toList() ?? + []; + + emit(state.copyWith( + isLoading: false, + routineName: routineDetails.name, + selectedIcon: routineDetails.iconId, + selectedAutomationOperator: routineDetails.decisionExpr, + effectiveTime: routineDetails.effectiveTime, + isAutomation: routineDetails.conditions != null, + isTabToRun: routineDetails.conditions == null, + thenItems: thenItems, + ifItems: ifItems, + selectedFunctions: Map.from(state.selectedFunctions), + )); + } + RoutineState _resetState() { return const RoutineState( ifItems: [], @@ -402,7 +551,8 @@ class RoutineBloc extends Bloc { ); } - FutureOr _onResetRoutineState(ResetRoutineState event, Emitter emit) { + FutureOr _onResetRoutineState( + ResetRoutineState event, Emitter emit) { emit(_resetState()); } } diff --git a/lib/pages/routiens/bloc/routine_bloc/routine_event.dart b/lib/pages/routiens/bloc/routine_bloc/routine_event.dart index 909e458d..ad93a5ac 100644 --- a/lib/pages/routiens/bloc/routine_bloc/routine_event.dart +++ b/lib/pages/routiens/bloc/routine_bloc/routine_event.dart @@ -125,6 +125,39 @@ class SetRoutineName extends RoutineEvent { List get props => [name]; } +class GetSceneDetails extends RoutineEvent { + final String sceneId; + final bool isUpdate; + final bool isTabToRun; + const GetSceneDetails({ + required this.sceneId, + required this.isUpdate, + required this.isTabToRun, + }); + @override + List get props => [sceneId]; +} + +class GetAutomationDetails extends RoutineEvent { + final String automationId; + final bool isUpdate; + final bool isAutomation; + const GetAutomationDetails({ + required this.automationId, + this.isUpdate = false, + this.isAutomation = false, + }); + @override + List get props => [automationId]; +} + +class InitializeRoutineState extends RoutineEvent { + final RoutineDetailsModel routineDetails; + const InitializeRoutineState(this.routineDetails); + @override + List get props => [routineDetails]; +} + class ResetRoutineState extends RoutineEvent {} class ClearFunctions extends RoutineEvent {} diff --git a/lib/pages/routiens/bloc/routine_bloc/routine_state.dart b/lib/pages/routiens/bloc/routine_bloc/routine_state.dart index b0689f0d..8f8d9b5c 100644 --- a/lib/pages/routiens/bloc/routine_bloc/routine_state.dart +++ b/lib/pages/routiens/bloc/routine_bloc/routine_state.dart @@ -18,6 +18,9 @@ class RoutineState extends Equatable { final bool isAutomation; final String selectedAutomationOperator; final EffectiveTime? effectiveTime; + final String? sceneId; + final String? automationId; + final bool? isUpdate; const RoutineState({ this.ifItems = const [], @@ -37,6 +40,9 @@ class RoutineState extends Equatable { this.isAutomation = false, this.selectedAutomationOperator = 'or', this.effectiveTime, + this.sceneId, + this.automationId, + this.isUpdate, }); RoutineState copyWith({ @@ -56,6 +62,9 @@ class RoutineState extends Equatable { bool? isAutomation, String? selectedAutomationOperator, EffectiveTime? effectiveTime, + String? sceneId, + String? automationId, + bool? isUpdate, }) { return RoutineState( ifItems: ifItems ?? this.ifItems, @@ -67,13 +76,19 @@ class RoutineState extends Equatable { errorMessage: errorMessage ?? this.errorMessage, routineName: routineName ?? this.routineName, selectedIcon: selectedIcon ?? this.selectedIcon, - loadScenesErrorMessage: loadScenesErrorMessage ?? this.loadScenesErrorMessage, - loadAutomationErrorMessage: loadAutomationErrorMessage ?? this.loadAutomationErrorMessage, + loadScenesErrorMessage: + loadScenesErrorMessage ?? this.loadScenesErrorMessage, + loadAutomationErrorMessage: + loadAutomationErrorMessage ?? this.loadAutomationErrorMessage, searchText: searchText ?? this.searchText, isTabToRun: isTabToRun ?? this.isTabToRun, isAutomation: isAutomation ?? this.isAutomation, - selectedAutomationOperator: selectedAutomationOperator ?? this.selectedAutomationOperator, + selectedAutomationOperator: + selectedAutomationOperator ?? this.selectedAutomationOperator, effectiveTime: effectiveTime ?? this.effectiveTime, + sceneId: sceneId ?? this.sceneId, + automationId: automationId ?? this.automationId, + isUpdate: isUpdate ?? this.isUpdate, ); } @@ -94,6 +109,9 @@ class RoutineState extends Equatable { isTabToRun, isAutomation, selectedAutomationOperator, - effectiveTime + effectiveTime, + sceneId, + automationId, + isUpdate ]; } diff --git a/lib/pages/routiens/models/routine_model.dart b/lib/pages/routiens/models/routine_model.dart index fe22a38c..bb3e117b 100644 --- a/lib/pages/routiens/models/routine_model.dart +++ b/lib/pages/routiens/models/routine_model.dart @@ -24,7 +24,14 @@ class ScenesModel { String toRawJson() => json.encode(toJson()); - Uint8List get iconInBytes => base64Decode(icon ?? ''); + Uint8List? get iconInBytes { + if (icon == null || icon?.isEmpty == true) return null; + try { + return base64Decode(icon!); + } catch (e) { + return null; + } + } factory ScenesModel.fromJson(Map json, {bool? isAutomation}) { diff --git a/lib/pages/routiens/view/create_new_routine_view.dart b/lib/pages/routiens/view/create_new_routine_view.dart index 38750991..320eb15d 100644 --- a/lib/pages/routiens/view/create_new_routine_view.dart +++ b/lib/pages/routiens/view/create_new_routine_view.dart @@ -6,8 +6,16 @@ import 'package:syncrow_web/pages/routiens/widgets/then_container.dart'; import 'package:syncrow_web/utils/color_manager.dart'; class CreateNewRoutineView extends StatelessWidget { - const CreateNewRoutineView({super.key}); + final bool isUpdate; + final String? routineId; + final bool isScene; + const CreateNewRoutineView({ + super.key, + this.isUpdate = false, + this.routineId, + this.isScene = true, + }); @override Widget build(BuildContext context) { return Container( diff --git a/lib/pages/routiens/widgets/main_routine_view/fetch_routine_scenes_automation.dart b/lib/pages/routiens/widgets/main_routine_view/fetch_routine_scenes_automation.dart index 031b8f63..375491f7 100644 --- a/lib/pages/routiens/widgets/main_routine_view/fetch_routine_scenes_automation.dart +++ b/lib/pages/routiens/widgets/main_routine_view/fetch_routine_scenes_automation.dart @@ -1,6 +1,8 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:syncrow_web/pages/device_managment/all_devices/bloc/switch_tabs/switch_tabs_bloc.dart'; import 'package:syncrow_web/pages/routiens/bloc/routine_bloc/routine_bloc.dart'; +import 'package:syncrow_web/pages/routiens/view/create_new_routine_view.dart'; import 'package:syncrow_web/pages/routiens/widgets/main_routine_view/routine_view_card.dart'; import 'package:syncrow_web/utils/color_manager.dart'; import 'package:syncrow_web/utils/constants/assets.dart'; diff --git a/lib/services/routines_api.dart b/lib/services/routines_api.dart index 1483b8ec..7fc3b1bf 100644 --- a/lib/services/routines_api.dart +++ b/lib/services/routines_api.dart @@ -85,7 +85,7 @@ class SceneApi { List scenes = []; for (var scene in scenesJson) { - scenes.add(ScenesModel.fromJson(scene)); + scenes.add(ScenesModel.fromJson(scene, isAutomation: false)); } return scenes; },