diff --git a/lib/pages/routiens/bloc/routine_bloc/routine_bloc.dart b/lib/pages/routiens/bloc/routine_bloc/routine_bloc.dart index 7694e8ec..0a9e6b0a 100644 --- a/lib/pages/routiens/bloc/routine_bloc/routine_bloc.dart +++ b/lib/pages/routiens/bloc/routine_bloc/routine_bloc.dart @@ -15,9 +15,6 @@ part 'routine_state.dart'; const spaceId = '25c96044-fadf-44bb-93c7-3c079e527ce6'; class RoutineBloc extends Bloc { - // bool isAutomation = false; - // bool isTabToRun = false; - RoutineBloc() : super(const RoutineState()) { on(_onAddToIfContainer); on(_onAddToThenContainer); @@ -159,50 +156,54 @@ class RoutineBloc extends Bloc { emit(state.copyWith(isLoading: true)); - final actions = state.thenItems - .map((item) { - final functions = - state.selectedFunctions[item['uniqueCustomId']] ?? []; - if (functions.isEmpty) return null; - - final function = functions.first; - if (item['deviceId'] == 'delay') { - return CreateSceneAction( - entityId: function.entityId, - actionExecutor: 'delay', - executorProperty: CreateSceneExecutorProperty( - functionCode: '', - functionValue: '', - delaySeconds: function.value, - ), - ); - } - + 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: 'device_issue', + actionExecutor: function.value, + executorProperty: null, + ); + } + + if (item['deviceId'] == 'delay') { + return CreateSceneAction( + entityId: function.entityId, + actionExecutor: 'delay', executorProperty: CreateSceneExecutorProperty( - functionCode: function.functionCode.toString(), - functionValue: function.value, - delaySeconds: 0, + functionCode: '', + functionValue: '', + delaySeconds: int.tryParse(function.value.toString()) ?? 0, ), ); - }) - .whereType() - .toList(); + } + + 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 ?? '', + sceneName: state.routineName!, decisionExpr: 'and', actions: actions, ); final result = await SceneApi.createScene(createSceneModel); if (result['success']) { - emit(const RoutineState()); + emit(_resetState()); + add(const LoadScenes(spaceId)); } else { emit(state.copyWith( isLoading: false, @@ -212,7 +213,7 @@ class RoutineBloc extends Bloc { } catch (e) { emit(state.copyWith( isLoading: false, - errorMessage: e.toString(), + errorMessage: 'Something went wrong', )); } } @@ -229,26 +230,24 @@ class RoutineBloc extends Bloc { emit(state.copyWith(isLoading: true)); - final conditions = state.ifItems - .map((item) { - final functions = - state.selectedFunctions[item['uniqueCustomId']] ?? []; - if (functions.isEmpty) return null; - - final function = functions.first; - return CreateCondition( - code: state.ifItems.indexOf(item) + 1, - entityId: function.entityId, - entityType: 'device_report', - expr: ConditionExpr( - statusCode: function.functionCode, - comparator: function.condition ?? '==', - statusValue: function.value, - ), - ); - }) - .whereType() - .toList(); + 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( @@ -258,61 +257,54 @@ class RoutineBloc extends Bloc { 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( - unitUuid: spaceId, + spaceUuid: spaceId, automationName: state.routineName!, decisionExpr: state.selectedAutomationOperator, - effectiveTime: state.effectiveTime ?? - EffectiveTime( - start: '00:00', - end: '23:59', - loops: '1111111', - ), + effectiveTime: EffectiveTime( + start: state.effectiveTime?.start ?? '00:00', + end: state.effectiveTime?.end ?? '23:59', + loops: state.effectiveTime?.loops ?? '1111111', + ), conditions: conditions, - actions: state.thenItems - .map((item) { - final functions = - state.selectedFunctions[item['uniqueCustomId']] ?? []; - if (functions.isEmpty) return null; - - final function = functions.first; - 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: function.value, - ), - ); - } - - return CreateSceneAction( - entityId: function.entityId, - actionExecutor: 'device_issue', - executorProperty: CreateSceneExecutorProperty( - functionCode: function.functionCode, - functionValue: function.value, - delaySeconds: 0, - ), - ); - }) - .whereType() - .toList(), + actions: actions, ); final result = await SceneApi.createAutomation(createAutomationModel); if (result['success']) { - emit(const RoutineState()); + emit(_resetState()); + add(const LoadAutomation(spaceId)); } else { emit(state.copyWith( isLoading: false, @@ -322,7 +314,7 @@ class RoutineBloc extends Bloc { } catch (e) { emit(state.copyWith( isLoading: false, - errorMessage: e.toString(), + errorMessage: 'Something went wrong', )); } } @@ -349,6 +341,7 @@ class RoutineBloc extends Bloc { FutureOr _onEffectiveTimeEvent( EffectiveTimePeriodEvent event, Emitter emit) { + debugPrint(event.effectiveTime.toString()); emit(state.copyWith(effectiveTime: event.effectiveTime)); } @@ -356,4 +349,25 @@ class RoutineBloc extends Bloc { SetRoutineName event, Emitter emit) { emit(state.copyWith(routineName: event.name)); } + + 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: 'AND', + effectiveTime: null, + routineName: null, + ); + } } diff --git a/lib/pages/routiens/helper/save_routine_helper.dart b/lib/pages/routiens/helper/save_routine_helper.dart index c6a8b2aa..2a57baa5 100644 --- a/lib/pages/routiens/helper/save_routine_helper.dart +++ b/lib/pages/routiens/helper/save_routine_helper.dart @@ -142,9 +142,16 @@ class SaveRoutineHelper { DialogFooter( onCancel: () => Navigator.pop(context), onConfirm: () { - context - .read() - .add(const CreateSceneEvent()); + if (state.isAutomation) { + context + .read() + .add(const CreateAutomationEvent()); + } else { + context + .read() + .add(const CreateSceneEvent()); + } + Navigator.pop(context); }, isConfirmEnabled: true, diff --git a/lib/pages/routiens/models/create_scene_and_autoamtion/create_automation_model.dart b/lib/pages/routiens/models/create_scene_and_autoamtion/create_automation_model.dart index f7bb1fb5..cd9a9c60 100644 --- a/lib/pages/routiens/models/create_scene_and_autoamtion/create_automation_model.dart +++ b/lib/pages/routiens/models/create_scene_and_autoamtion/create_automation_model.dart @@ -1,18 +1,187 @@ - import 'dart:convert'; import 'package:syncrow_web/pages/routiens/models/create_scene_and_autoamtion/create_scene_model.dart'; +// class CreateAutomationModel { +// String unitUuid; +// String automationName; +// String decisionExpr; +// EffectiveTime effectiveTime; +// List conditions; +// List actions; + +// CreateAutomationModel({ +// required this.unitUuid, +// required this.automationName, +// required this.decisionExpr, +// required this.effectiveTime, +// required this.conditions, +// required this.actions, +// }); + +// CreateAutomationModel copyWith({ +// String? unitUuid, +// String? automationName, +// String? decisionExpr, +// EffectiveTime? effectiveTime, +// List? conditions, +// List? actions, +// }) { +// return CreateAutomationModel( +// unitUuid: unitUuid ?? this.unitUuid, +// automationName: automationName ?? this.automationName, +// decisionExpr: decisionExpr ?? this.decisionExpr, +// effectiveTime: effectiveTime ?? this.effectiveTime, +// conditions: conditions ?? this.conditions, +// actions: actions ?? this.actions, +// ); +// } + +// Map toMap([String? automationId]) { +// return { +// if (automationId == null) 'spaceUuid': unitUuid, +// 'automationName': automationName, +// 'decisionExpr': decisionExpr, +// 'effectiveTime': effectiveTime.toMap(), +// 'conditions': conditions.map((x) => x.toMap()).toList(), +// 'actions': actions.map((x) => x.toMap()).toList(), +// }; +// } + +// factory CreateAutomationModel.fromMap(Map map) { +// return CreateAutomationModel( +// unitUuid: map['spaceUuid'] ?? '', +// automationName: map['automationName'] ?? '', +// decisionExpr: map['decisionExpr'] ?? '', +// effectiveTime: EffectiveTime.fromMap(map['effectiveTime']), +// conditions: List.from( +// map['conditions']?.map((x) => CreateCondition.fromMap(x))), +// actions: List.from( +// map['actions']?.map((x) => CreateSceneAction.fromMap(x))), +// ); +// } + +// String toJson([String? automationId]) => json.encode(toMap(automationId)); + +// factory CreateAutomationModel.fromJson(String source) => +// CreateAutomationModel.fromMap(json.decode(source)); + +// @override +// String toString() { +// return 'CreateAutomationModel(unitUuid: $unitUuid, automationName: $automationName, decisionExpr: $decisionExpr, effectiveTime: $effectiveTime, conditions: $conditions, actions: $actions)'; +// } +// } + +// class EffectiveTime { +// String start; +// String end; +// String loops; + +// EffectiveTime({ +// required this.start, +// required this.end, +// required this.loops, +// }); + +// Map toMap() { +// return { +// 'start': start, +// 'end': end, +// 'loops': loops, +// }; +// } + +// factory EffectiveTime.fromMap(Map map) { +// return EffectiveTime( +// start: map['start'] ?? '', +// end: map['end'] ?? '', +// loops: map['loops'] ?? '', +// ); +// } + +// @override +// String toString() => 'EffectiveTime(start: $start, end: $end, loops: $loops)'; +// } + +// class CreateCondition { +// int code; +// String entityId; +// String entityType; +// ConditionExpr expr; + +// CreateCondition({ +// required this.code, +// required this.entityId, +// required this.entityType, +// required this.expr, +// }); + +// Map toMap() { +// return { +// 'code': code, +// 'entityId': entityId, +// 'entityType': entityType, +// 'expr': expr.toMap(), +// }; +// } + +// factory CreateCondition.fromMap(Map map) { +// return CreateCondition( +// code: map['code'] ?? 0, +// entityId: map['entityId'] ?? '', +// entityType: map['entityType'] ?? '', +// expr: ConditionExpr.fromMap(map['expr']), +// ); +// } + +// @override +// String toString() => +// 'CreateCondition(code: $code, entityId: $entityId, entityType: $entityType, expr: $expr)'; +// } + +// class ConditionExpr { +// String statusCode; +// String comparator; +// dynamic statusValue; + +// ConditionExpr({ +// required this.statusCode, +// required this.comparator, +// required this.statusValue, +// }); + +// Map toMap() { +// return { +// 'statusCode': statusCode, +// 'comparator': comparator, +// 'statusValue': statusValue, +// }; +// } + +// factory ConditionExpr.fromMap(Map map) { +// return ConditionExpr( +// statusCode: map['statusCode'] ?? '', +// comparator: map['comparator'] ?? '', +// statusValue: map['statusValue'], +// ); +// } + +// @override +// String toString() => +// 'ConditionExpr(statusCode: $statusCode, comparator: $comparator, statusValue: $statusValue)'; +// } +import 'dart:convert'; + class CreateAutomationModel { - String unitUuid; + String spaceUuid; String automationName; String decisionExpr; EffectiveTime effectiveTime; - List conditions; - List actions; + List conditions; + List actions; CreateAutomationModel({ - required this.unitUuid, + required this.spaceUuid, required this.automationName, required this.decisionExpr, required this.effectiveTime, @@ -20,27 +189,9 @@ class CreateAutomationModel { required this.actions, }); - CreateAutomationModel copyWith({ - String? unitUuid, - String? automationName, - String? decisionExpr, - EffectiveTime? effectiveTime, - List? conditions, - List? actions, - }) { - return CreateAutomationModel( - unitUuid: unitUuid ?? this.unitUuid, - automationName: automationName ?? this.automationName, - decisionExpr: decisionExpr ?? this.decisionExpr, - effectiveTime: effectiveTime ?? this.effectiveTime, - conditions: conditions ?? this.conditions, - actions: actions ?? this.actions, - ); - } - - Map toMap([String? automationId]) { + Map toMap() { return { - if (automationId == null) 'spaceUuid': unitUuid, + 'spaceUuid': spaceUuid, 'automationName': automationName, 'decisionExpr': decisionExpr, 'effectiveTime': effectiveTime.toMap(), @@ -51,26 +202,21 @@ class CreateAutomationModel { factory CreateAutomationModel.fromMap(Map map) { return CreateAutomationModel( - unitUuid: map['spaceUuid'] ?? '', + spaceUuid: map['spaceUuid'] ?? '', automationName: map['automationName'] ?? '', decisionExpr: map['decisionExpr'] ?? '', effectiveTime: EffectiveTime.fromMap(map['effectiveTime']), - conditions: List.from( - map['conditions']?.map((x) => CreateCondition.fromMap(x))), - actions: List.from( - map['actions']?.map((x) => CreateSceneAction.fromMap(x))), + conditions: List.from( + map['conditions']?.map((x) => Condition.fromMap(x)) ?? []), + actions: List.from( + map['actions']?.map((x) => AutomationAction.fromMap(x)) ?? []), ); } - String toJson([String? automationId]) => json.encode(toMap(automationId)); + String toJson() => json.encode(toMap()); factory CreateAutomationModel.fromJson(String source) => CreateAutomationModel.fromMap(json.decode(source)); - - @override - String toString() { - return 'CreateAutomationModel(unitUuid: $unitUuid, automationName: $automationName, decisionExpr: $decisionExpr, effectiveTime: $effectiveTime, conditions: $conditions, actions: $actions)'; - } } class EffectiveTime { @@ -99,18 +245,15 @@ class EffectiveTime { loops: map['loops'] ?? '', ); } - - @override - String toString() => 'EffectiveTime(start: $start, end: $end, loops: $loops)'; } -class CreateCondition { +class Condition { int code; String entityId; String entityType; ConditionExpr expr; - CreateCondition({ + Condition({ required this.code, required this.entityId, required this.entityType, @@ -126,18 +269,14 @@ class CreateCondition { }; } - factory CreateCondition.fromMap(Map map) { - return CreateCondition( - code: map['code'] ?? 0, + factory Condition.fromMap(Map map) { + return Condition( + code: map['code']?.toInt() ?? 0, entityId: map['entityId'] ?? '', entityType: map['entityType'] ?? '', expr: ConditionExpr.fromMap(map['expr']), ); } - - @override - String toString() => - 'CreateCondition(code: $code, entityId: $entityId, entityType: $entityType, expr: $expr)'; } class ConditionExpr { @@ -166,8 +305,62 @@ class ConditionExpr { statusValue: map['statusValue'], ); } - - @override - String toString() => - 'ConditionExpr(statusCode: $statusCode, comparator: $comparator, statusValue: $statusValue)'; +} + +class AutomationAction { + String entityId; + String actionExecutor; + ExecutorProperty? executorProperty; + + AutomationAction({ + required this.entityId, + required this.actionExecutor, + this.executorProperty, + }); + + Map toMap() { + return { + 'entityId': entityId, + 'actionExecutor': actionExecutor, + 'executorProperty': executorProperty?.toMap(), + }; + } + + factory AutomationAction.fromMap(Map map) { + return AutomationAction( + entityId: map['entityId'] ?? '', + actionExecutor: map['actionExecutor'] ?? '', + executorProperty: map['executorProperty'] != null + ? ExecutorProperty.fromMap(map['executorProperty']) + : null, + ); + } +} + +class ExecutorProperty { + String? functionCode; + dynamic functionValue; + int? delaySeconds; + + ExecutorProperty({ + this.functionCode, + this.functionValue, + this.delaySeconds, + }); + + Map toMap() { + return { + if (functionCode != null) 'functionCode': functionCode, + if (functionValue != null) 'functionValue': functionValue, + if (delaySeconds != null) 'delaySeconds': delaySeconds, + }; + } + + factory ExecutorProperty.fromMap(Map map) { + return ExecutorProperty( + functionCode: map['functionCode'], + functionValue: map['functionValue'], + delaySeconds: map['delaySeconds']?.toInt(), + ); + } } diff --git a/lib/pages/routiens/widgets/routine_dialogs/automation_dialog.dart b/lib/pages/routiens/widgets/routine_dialogs/automation_dialog.dart index c494622a..06995882 100644 --- a/lib/pages/routiens/widgets/routine_dialogs/automation_dialog.dart +++ b/lib/pages/routiens/widgets/routine_dialogs/automation_dialog.dart @@ -74,7 +74,7 @@ class _AutomationDialogState extends State { DeviceFunctionData( entityId: widget.automationId, functionCode: 'automation', - value: _isEnabled, + value: _isEnabled ? 'rule_enable' : 'rule_disable', operationName: 'Automation', ), ], diff --git a/lib/services/routines_api.dart b/lib/services/routines_api.dart index f92f212f..756d533e 100644 --- a/lib/services/routines_api.dart +++ b/lib/services/routines_api.dart @@ -29,11 +29,13 @@ class SceneApi { rethrow; } } + // // create automation static Future> createAutomation( CreateAutomationModel createAutomationModel) async { try { + debugPrint("automation body ${createAutomationModel.toMap()}"); final response = await _httpService.post( path: ApiEndpoints.createAutomation, body: createAutomationModel.toMap(), @@ -42,8 +44,10 @@ class SceneApi { return json; }, ); + debugPrint('create automation response: $response'); return response; } catch (e) { + debugPrint(e.toString()); rethrow; } }