mirror of
https://github.com/SyncrowIOT/web.git
synced 2025-07-16 01:56:24 +00:00
fixed autoamtion update
This commit is contained in:
@ -44,7 +44,6 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
||||
on<FetchDevicesInRoutine>(_fetchDevices);
|
||||
on<UpdateScene>(_onUpdateScene);
|
||||
on<UpdateAutomation>(_onUpdateAutomation);
|
||||
on<SetAutomationActionExecutor>(_onSetAutomationActionExecutor);
|
||||
on<TriggerSwitchTabsEvent>(_triggerSwitchTabsEvent);
|
||||
on<CreateNewRoutineViewEvent>(_createNewRoutineViewEvent);
|
||||
}
|
||||
@ -368,21 +367,25 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
||||
}
|
||||
|
||||
final actions = state.thenItems.expand((item) {
|
||||
if (item['type'] == 'tap_to_run') {
|
||||
return [
|
||||
AutomationAction(
|
||||
actionType: 'scene',
|
||||
entityId: item['deviceId'],
|
||||
actionExecutor: 'rule_trigger',
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
final functions = state.selectedFunctions[item['uniqueCustomId']] ?? [];
|
||||
|
||||
return functions.map((function) {
|
||||
if (function.functionCode == 'automation') {
|
||||
return AutomationAction(
|
||||
actionType: 'automation',
|
||||
entityId: function.entityId,
|
||||
actionExecutor: function.value,
|
||||
);
|
||||
}
|
||||
|
||||
if (function.functionCode == 'tap_to_run') {
|
||||
return AutomationAction(
|
||||
actionType: 'scene',
|
||||
entityId: function.entityId,
|
||||
actionExecutor: function.value,
|
||||
executorProperty: null,
|
||||
);
|
||||
}
|
||||
|
||||
@ -698,7 +701,7 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
||||
operationName: 'Automation',
|
||||
),
|
||||
);
|
||||
emit(state.copyWith(automationActionExecutor: action.actionExecutor));
|
||||
// emit(state.copyWith(automationActionExecutor: action.actionExecutor));
|
||||
} else if (action.executorProperty != null &&
|
||||
action.actionExecutor != 'delay') {
|
||||
if (!updatedFunctions.containsKey(uniqueCustomId)) {
|
||||
@ -772,160 +775,6 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _onGetAutomationDetails(
|
||||
GetAutomationDetails event, Emitter<RoutineState> 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<Map<String, dynamic>> thenItems;
|
||||
final List<Map<String, dynamic>> ifItems;
|
||||
final Map<String, List<DeviceFunctionData>> updatedFunctions =
|
||||
Map<String, List<DeviceFunctionData>>.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',
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
FutureOr<void> _onResetRoutineState(
|
||||
ResetRoutineState event, Emitter<RoutineState> emit) {
|
||||
emit(state.copyWith(
|
||||
@ -1087,65 +936,112 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
||||
|
||||
FutureOr<void> _onUpdateAutomation(
|
||||
UpdateAutomation event, Emitter<RoutineState> 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;
|
||||
if (state.routineName == null || state.routineName!.isEmpty) {
|
||||
emit(state.copyWith(
|
||||
errorMessage: 'Automation name is required',
|
||||
));
|
||||
return;
|
||||
}
|
||||
if (_isFirstActionDelay(state.thenItems)) {
|
||||
emit(state.copyWith(
|
||||
errorMessage: 'Cannot have delay as the first action',
|
||||
isLoading: false,
|
||||
));
|
||||
return;
|
||||
}
|
||||
|
||||
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<Condition>()
|
||||
.toList();
|
||||
if (_isLastActionDelay(state.thenItems)) {
|
||||
emit(state.copyWith(
|
||||
errorMessage: 'Cannot have delay as the last action',
|
||||
isLoading: false,
|
||||
));
|
||||
return;
|
||||
}
|
||||
emit(state.copyWith(isLoading: true, errorMessage: null));
|
||||
|
||||
final actions = state.thenItems
|
||||
.map((item) {
|
||||
final functions =
|
||||
state.selectedFunctions[item['uniqueCustomId']] ?? [];
|
||||
if (functions.isEmpty) return null;
|
||||
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();
|
||||
|
||||
final function = functions.first;
|
||||
if (conditions.isEmpty) {
|
||||
emit(state.copyWith(
|
||||
isLoading: false,
|
||||
errorMessage: 'At least one condition is required',
|
||||
));
|
||||
return;
|
||||
}
|
||||
|
||||
final actions = state.thenItems.expand((item) {
|
||||
if (item['type'] == 'tap_to_run' || item['type'] == 'scene') {
|
||||
return [
|
||||
AutomationAction(
|
||||
actionType: 'scene',
|
||||
entityId: item['deviceId'],
|
||||
actionExecutor: 'rule_trigger',
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
final functions = state.selectedFunctions[item['uniqueCustomId']] ?? [];
|
||||
|
||||
return functions.map((function) {
|
||||
if (function.functionCode == 'automation') {
|
||||
return AutomationAction(
|
||||
actionType: 'automation',
|
||||
entityId: function.entityId,
|
||||
actionExecutor: function.actionExecutor,
|
||||
actionExecutor: function.value,
|
||||
executorProperty: null,
|
||||
);
|
||||
}
|
||||
|
||||
if (item['deviceId'] == 'delay') {
|
||||
return AutomationAction(
|
||||
entityId: function.entityId,
|
||||
actionType: 'automation',
|
||||
actionExecutor: 'delay',
|
||||
executorProperty: ExecutorProperty(
|
||||
functionCode: function.functionCode,
|
||||
functionValue: function.value,
|
||||
delaySeconds: function.functionCode == 'delay'
|
||||
? (function.value as num).toInt()
|
||||
: null,
|
||||
delaySeconds: int.tryParse(function.value.toString()) ?? 0,
|
||||
),
|
||||
);
|
||||
})
|
||||
.whereType<AutomationAction>()
|
||||
.toList();
|
||||
}
|
||||
|
||||
return AutomationAction(
|
||||
entityId: function.entityId,
|
||||
actionExecutor: 'device_issue',
|
||||
actionType: 'automation',
|
||||
executorProperty: ExecutorProperty(
|
||||
functionCode: function.functionCode,
|
||||
functionValue: function.value,
|
||||
),
|
||||
);
|
||||
});
|
||||
}).toList();
|
||||
|
||||
final createAutomationModel = CreateAutomationModel(
|
||||
spaceUuid: spaceId,
|
||||
automationName: state.routineName ?? '',
|
||||
decisionExpr: state.selectedAutomationOperator,
|
||||
effectiveTime:
|
||||
state.effectiveTime ?? EffectiveTime(start: '', end: '', loops: ''),
|
||||
effectiveTime: EffectiveTime(
|
||||
start: state.effectiveTime?.start ?? '00:00',
|
||||
end: state.effectiveTime?.end ?? '23:59',
|
||||
loops: state.effectiveTime?.loops ?? '1111111',
|
||||
),
|
||||
conditions: conditions,
|
||||
actions: actions,
|
||||
);
|
||||
@ -1155,8 +1051,8 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
||||
|
||||
if (result['success']) {
|
||||
add(ResetRoutineState());
|
||||
add(const LoadScenes(spaceId, communityId));
|
||||
add(const LoadAutomation(spaceId));
|
||||
add(const LoadScenes(spaceId, communityId));
|
||||
} else {
|
||||
emit(state.copyWith(
|
||||
isLoading: false,
|
||||
@ -1166,14 +1062,198 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
||||
} catch (e) {
|
||||
emit(state.copyWith(
|
||||
isLoading: false,
|
||||
errorMessage: 'Failed to update automation: $e',
|
||||
errorMessage: 'Something went wrong',
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
FutureOr<void> _onSetAutomationActionExecutor(
|
||||
SetAutomationActionExecutor event, Emitter<RoutineState> emit) {
|
||||
emit(state.copyWith(
|
||||
automationActionExecutor: event.automationActionExecutor));
|
||||
Future<void> _onGetAutomationDetails(
|
||||
GetAutomationDetails event, Emitter<RoutineState> 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 Map<String, Map<String, dynamic>> deviceCards = {};
|
||||
final Map<String, List<DeviceFunctionData>> updatedFunctions =
|
||||
Map<String, List<DeviceFunctionData>>.from(state.selectedFunctions);
|
||||
|
||||
for (RoutineCondition condition in automationDetails.conditions ?? []) {
|
||||
AllDevicesModel? matchingDevice = state.devices.firstWhere(
|
||||
(device) => device.uuid == condition.entityId,
|
||||
orElse: () => AllDevicesModel(
|
||||
uuid: condition.entityId,
|
||||
name: condition.entityId,
|
||||
productType: condition.productType,
|
||||
),
|
||||
);
|
||||
|
||||
final deviceId = condition.entityId;
|
||||
|
||||
if (!deviceCards.containsKey(deviceId)) {
|
||||
deviceCards[deviceId] = {
|
||||
'entityId': condition.entityId,
|
||||
'deviceId': condition.entityId,
|
||||
'uniqueCustomId': const Uuid().v4(),
|
||||
'title': matchingDevice.name ?? 'Device',
|
||||
'productType': condition.productType,
|
||||
'functions': matchingDevice.functions,
|
||||
'imagePath': matchingDevice.getDefaultIcon(condition.productType),
|
||||
'device': matchingDevice,
|
||||
'type': 'condition',
|
||||
};
|
||||
}
|
||||
|
||||
final cardData = deviceCards[deviceId]!;
|
||||
final uniqueCustomId = cardData['uniqueCustomId'].toString();
|
||||
|
||||
if (!updatedFunctions.containsKey(uniqueCustomId)) {
|
||||
updatedFunctions[uniqueCustomId] = [];
|
||||
}
|
||||
|
||||
final functions = matchingDevice.functions;
|
||||
for (var function in functions) {
|
||||
if (function.code == condition.expr.statusCode) {
|
||||
updatedFunctions[uniqueCustomId]!.add(
|
||||
DeviceFunctionData(
|
||||
entityId: condition.entityId,
|
||||
functionCode: condition.expr.statusCode,
|
||||
value: condition.expr.statusValue,
|
||||
operationName: function.operationName,
|
||||
),
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Process actions (thenItems)
|
||||
for (var action in automationDetails.actions) {
|
||||
AllDevicesModel? matchingDevice = state.devices.firstWhere(
|
||||
(device) => device.uuid == action.entityId,
|
||||
orElse: () => AllDevicesModel(
|
||||
uuid: action.entityId,
|
||||
name: action.entityId,
|
||||
productType: action.productType,
|
||||
),
|
||||
);
|
||||
|
||||
final deviceId = action.actionExecutor == 'delay'
|
||||
? '${action.entityId}_delay'
|
||||
: action.entityId;
|
||||
|
||||
if (!deviceCards.containsKey(deviceId)) {
|
||||
deviceCards[deviceId] = {
|
||||
'entityId': action.entityId,
|
||||
'deviceId':
|
||||
action.actionExecutor == 'delay' ? 'delay' : action.entityId,
|
||||
'uniqueCustomId': const Uuid().v4(),
|
||||
'title': action.actionExecutor == 'delay'
|
||||
? 'Delay'
|
||||
: (action.type == 'scene' || action.type == 'automation')
|
||||
? action.name
|
||||
: (matchingDevice.name ?? 'Device'),
|
||||
'productType': action.productType,
|
||||
'functions': matchingDevice.functions,
|
||||
'imagePath': action.actionExecutor == 'delay'
|
||||
? Assets.delay
|
||||
: action.type == 'automation'
|
||||
? Assets.automation
|
||||
: matchingDevice.getDefaultIcon(action.productType),
|
||||
'device': matchingDevice,
|
||||
'type': action.type == 'scene'
|
||||
? 'scene'
|
||||
: action.type == 'automation'
|
||||
? 'automation'
|
||||
: 'action',
|
||||
};
|
||||
}
|
||||
|
||||
final cardData = deviceCards[deviceId]!;
|
||||
final uniqueCustomId = cardData['uniqueCustomId'].toString();
|
||||
|
||||
if (!updatedFunctions.containsKey(uniqueCustomId)) {
|
||||
updatedFunctions[uniqueCustomId] = [];
|
||||
}
|
||||
|
||||
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[uniqueCustomId]!.add(
|
||||
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[uniqueCustomId]!.add(
|
||||
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[uniqueCustomId]!.add(
|
||||
DeviceFunctionData(
|
||||
entityId: action.entityId,
|
||||
functionCode: 'automation',
|
||||
value: action.actionExecutor,
|
||||
operationName: action.name ?? 'Automation',
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
final ifItems = deviceCards.values
|
||||
.where((card) => card['type'] == 'condition')
|
||||
.toList();
|
||||
final thenItems = deviceCards.values
|
||||
.where((card) =>
|
||||
card['type'] == 'action' ||
|
||||
card['type'] == 'automation' ||
|
||||
card['type'] == 'scene')
|
||||
.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',
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user