fixed autoamtion update

This commit is contained in:
ashraf_personal
2024-12-03 00:29:59 +03:00
parent 2f5c5d7da1
commit c58f2eb24e
5 changed files with 399 additions and 306 deletions

View File

@ -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',
));
}
}
}