mirror of
https://github.com/SyncrowIOT/web.git
synced 2025-07-10 15:17:31 +00:00
fixed autoamtion update
This commit is contained in:
@ -44,7 +44,6 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
|||||||
on<FetchDevicesInRoutine>(_fetchDevices);
|
on<FetchDevicesInRoutine>(_fetchDevices);
|
||||||
on<UpdateScene>(_onUpdateScene);
|
on<UpdateScene>(_onUpdateScene);
|
||||||
on<UpdateAutomation>(_onUpdateAutomation);
|
on<UpdateAutomation>(_onUpdateAutomation);
|
||||||
on<SetAutomationActionExecutor>(_onSetAutomationActionExecutor);
|
|
||||||
on<TriggerSwitchTabsEvent>(_triggerSwitchTabsEvent);
|
on<TriggerSwitchTabsEvent>(_triggerSwitchTabsEvent);
|
||||||
on<CreateNewRoutineViewEvent>(_createNewRoutineViewEvent);
|
on<CreateNewRoutineViewEvent>(_createNewRoutineViewEvent);
|
||||||
}
|
}
|
||||||
@ -368,21 +367,25 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
final actions = state.thenItems.expand((item) {
|
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']] ?? [];
|
final functions = state.selectedFunctions[item['uniqueCustomId']] ?? [];
|
||||||
|
|
||||||
return functions.map((function) {
|
return functions.map((function) {
|
||||||
if (function.functionCode == 'automation') {
|
if (function.functionCode == 'automation') {
|
||||||
return AutomationAction(
|
return AutomationAction(
|
||||||
actionType: 'automation',
|
actionType: 'automation',
|
||||||
entityId: function.entityId,
|
entityId: function.entityId,
|
||||||
actionExecutor: function.value,
|
actionExecutor: function.value,
|
||||||
);
|
executorProperty: null,
|
||||||
}
|
|
||||||
|
|
||||||
if (function.functionCode == 'tap_to_run') {
|
|
||||||
return AutomationAction(
|
|
||||||
actionType: 'scene',
|
|
||||||
entityId: function.entityId,
|
|
||||||
actionExecutor: function.value,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -698,7 +701,7 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
|||||||
operationName: 'Automation',
|
operationName: 'Automation',
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
emit(state.copyWith(automationActionExecutor: action.actionExecutor));
|
// emit(state.copyWith(automationActionExecutor: action.actionExecutor));
|
||||||
} else if (action.executorProperty != null &&
|
} else if (action.executorProperty != null &&
|
||||||
action.actionExecutor != 'delay') {
|
action.actionExecutor != 'delay') {
|
||||||
if (!updatedFunctions.containsKey(uniqueCustomId)) {
|
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(
|
FutureOr<void> _onResetRoutineState(
|
||||||
ResetRoutineState event, Emitter<RoutineState> emit) {
|
ResetRoutineState event, Emitter<RoutineState> emit) {
|
||||||
emit(state.copyWith(
|
emit(state.copyWith(
|
||||||
@ -1087,65 +936,112 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
|||||||
|
|
||||||
FutureOr<void> _onUpdateAutomation(
|
FutureOr<void> _onUpdateAutomation(
|
||||||
UpdateAutomation event, Emitter<RoutineState> emit) async {
|
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 {
|
try {
|
||||||
final conditions = state.ifItems
|
if (state.routineName == null || state.routineName!.isEmpty) {
|
||||||
.map((item) {
|
emit(state.copyWith(
|
||||||
final functions =
|
errorMessage: 'Automation name is required',
|
||||||
state.selectedFunctions[item['uniqueCustomId']] ?? [];
|
));
|
||||||
if (functions.isEmpty) return null;
|
return;
|
||||||
|
}
|
||||||
|
if (_isFirstActionDelay(state.thenItems)) {
|
||||||
|
emit(state.copyWith(
|
||||||
|
errorMessage: 'Cannot have delay as the first action',
|
||||||
|
isLoading: false,
|
||||||
|
));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
final function = functions.first;
|
if (_isLastActionDelay(state.thenItems)) {
|
||||||
return Condition(
|
emit(state.copyWith(
|
||||||
code: state.ifItems.indexOf(item) + 1,
|
errorMessage: 'Cannot have delay as the last action',
|
||||||
entityId: function.entityId,
|
isLoading: false,
|
||||||
entityType: item['productType'],
|
));
|
||||||
expr: ConditionExpr(
|
return;
|
||||||
statusCode: function.functionCode,
|
}
|
||||||
statusValue: function.value,
|
emit(state.copyWith(isLoading: true, errorMessage: null));
|
||||||
comparator: function.condition ?? '==',
|
|
||||||
),
|
|
||||||
);
|
|
||||||
})
|
|
||||||
.whereType<Condition>()
|
|
||||||
.toList();
|
|
||||||
|
|
||||||
final actions = state.thenItems
|
final conditions = state.ifItems.expand((item) {
|
||||||
.map((item) {
|
final functions = state.selectedFunctions[item['uniqueCustomId']] ?? [];
|
||||||
final functions =
|
return functions.map((function) {
|
||||||
state.selectedFunctions[item['uniqueCustomId']] ?? [];
|
return Condition(
|
||||||
if (functions.isEmpty) return null;
|
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(
|
return AutomationAction(
|
||||||
actionType: 'automation',
|
actionType: 'automation',
|
||||||
entityId: function.entityId,
|
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(
|
executorProperty: ExecutorProperty(
|
||||||
functionCode: function.functionCode,
|
delaySeconds: int.tryParse(function.value.toString()) ?? 0,
|
||||||
functionValue: function.value,
|
|
||||||
delaySeconds: function.functionCode == 'delay'
|
|
||||||
? (function.value as num).toInt()
|
|
||||||
: null,
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
})
|
}
|
||||||
.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(
|
final createAutomationModel = CreateAutomationModel(
|
||||||
spaceUuid: spaceId,
|
spaceUuid: spaceId,
|
||||||
automationName: state.routineName ?? '',
|
automationName: state.routineName ?? '',
|
||||||
decisionExpr: state.selectedAutomationOperator,
|
decisionExpr: state.selectedAutomationOperator,
|
||||||
effectiveTime:
|
effectiveTime: EffectiveTime(
|
||||||
state.effectiveTime ?? EffectiveTime(start: '', end: '', loops: ''),
|
start: state.effectiveTime?.start ?? '00:00',
|
||||||
|
end: state.effectiveTime?.end ?? '23:59',
|
||||||
|
loops: state.effectiveTime?.loops ?? '1111111',
|
||||||
|
),
|
||||||
conditions: conditions,
|
conditions: conditions,
|
||||||
actions: actions,
|
actions: actions,
|
||||||
);
|
);
|
||||||
@ -1155,8 +1051,8 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
|||||||
|
|
||||||
if (result['success']) {
|
if (result['success']) {
|
||||||
add(ResetRoutineState());
|
add(ResetRoutineState());
|
||||||
add(const LoadScenes(spaceId, communityId));
|
|
||||||
add(const LoadAutomation(spaceId));
|
add(const LoadAutomation(spaceId));
|
||||||
|
add(const LoadScenes(spaceId, communityId));
|
||||||
} else {
|
} else {
|
||||||
emit(state.copyWith(
|
emit(state.copyWith(
|
||||||
isLoading: false,
|
isLoading: false,
|
||||||
@ -1166,14 +1062,198 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
|||||||
} catch (e) {
|
} catch (e) {
|
||||||
emit(state.copyWith(
|
emit(state.copyWith(
|
||||||
isLoading: false,
|
isLoading: false,
|
||||||
errorMessage: 'Failed to update automation: $e',
|
errorMessage: 'Something went wrong',
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FutureOr<void> _onSetAutomationActionExecutor(
|
Future<void> _onGetAutomationDetails(
|
||||||
SetAutomationActionExecutor event, Emitter<RoutineState> emit) {
|
GetAutomationDetails event, Emitter<RoutineState> emit) async {
|
||||||
emit(state.copyWith(
|
try {
|
||||||
automationActionExecutor: event.automationActionExecutor));
|
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',
|
||||||
|
));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,7 @@ class RoutineState extends Equatable {
|
|||||||
final String? automationId;
|
final String? automationId;
|
||||||
final bool? isUpdate;
|
final bool? isUpdate;
|
||||||
final List<AllDevicesModel> devices;
|
final List<AllDevicesModel> devices;
|
||||||
final String? automationActionExecutor;
|
// final String? automationActionExecutor;
|
||||||
final bool routineTab;
|
final bool routineTab;
|
||||||
final bool createRoutineView;
|
final bool createRoutineView;
|
||||||
|
|
||||||
@ -48,7 +48,7 @@ class RoutineState extends Equatable {
|
|||||||
this.automationId,
|
this.automationId,
|
||||||
this.isUpdate,
|
this.isUpdate,
|
||||||
this.devices = const [],
|
this.devices = const [],
|
||||||
this.automationActionExecutor,
|
// this.automationActionExecutor,
|
||||||
this.routineTab = false,
|
this.routineTab = false,
|
||||||
this.createRoutineView = false});
|
this.createRoutineView = false});
|
||||||
|
|
||||||
@ -73,7 +73,7 @@ class RoutineState extends Equatable {
|
|||||||
String? automationId,
|
String? automationId,
|
||||||
bool? isUpdate,
|
bool? isUpdate,
|
||||||
List<AllDevicesModel>? devices,
|
List<AllDevicesModel>? devices,
|
||||||
String? automationActionExecutor,
|
// String? automationActionExecutor,
|
||||||
TextEditingController? nameController,
|
TextEditingController? nameController,
|
||||||
bool? routineTab,
|
bool? routineTab,
|
||||||
bool? createRoutineView,
|
bool? createRoutineView,
|
||||||
@ -88,18 +88,21 @@ class RoutineState extends Equatable {
|
|||||||
errorMessage: errorMessage ?? this.errorMessage,
|
errorMessage: errorMessage ?? this.errorMessage,
|
||||||
routineName: routineName ?? this.routineName,
|
routineName: routineName ?? this.routineName,
|
||||||
selectedIcon: selectedIcon ?? this.selectedIcon,
|
selectedIcon: selectedIcon ?? this.selectedIcon,
|
||||||
loadScenesErrorMessage: loadScenesErrorMessage ?? this.loadScenesErrorMessage,
|
loadScenesErrorMessage:
|
||||||
loadAutomationErrorMessage: loadAutomationErrorMessage ?? this.loadAutomationErrorMessage,
|
loadScenesErrorMessage ?? this.loadScenesErrorMessage,
|
||||||
|
loadAutomationErrorMessage:
|
||||||
|
loadAutomationErrorMessage ?? this.loadAutomationErrorMessage,
|
||||||
searchText: searchText ?? this.searchText,
|
searchText: searchText ?? this.searchText,
|
||||||
isTabToRun: isTabToRun ?? this.isTabToRun,
|
isTabToRun: isTabToRun ?? this.isTabToRun,
|
||||||
isAutomation: isAutomation ?? this.isAutomation,
|
isAutomation: isAutomation ?? this.isAutomation,
|
||||||
selectedAutomationOperator: selectedAutomationOperator ?? this.selectedAutomationOperator,
|
selectedAutomationOperator:
|
||||||
|
selectedAutomationOperator ?? this.selectedAutomationOperator,
|
||||||
effectiveTime: effectiveTime ?? this.effectiveTime,
|
effectiveTime: effectiveTime ?? this.effectiveTime,
|
||||||
sceneId: sceneId ?? this.sceneId,
|
sceneId: sceneId ?? this.sceneId,
|
||||||
automationId: automationId ?? this.automationId,
|
automationId: automationId ?? this.automationId,
|
||||||
isUpdate: isUpdate ?? this.isUpdate,
|
isUpdate: isUpdate ?? this.isUpdate,
|
||||||
devices: devices ?? this.devices,
|
devices: devices ?? this.devices,
|
||||||
automationActionExecutor: automationActionExecutor ?? this.automationActionExecutor,
|
// automationActionExecutor: automationActionExecutor ?? this.automationActionExecutor,
|
||||||
routineTab: routineTab ?? this.routineTab,
|
routineTab: routineTab ?? this.routineTab,
|
||||||
createRoutineView: createRoutineView ?? this.createRoutineView);
|
createRoutineView: createRoutineView ?? this.createRoutineView);
|
||||||
}
|
}
|
||||||
@ -126,7 +129,7 @@ class RoutineState extends Equatable {
|
|||||||
automationId,
|
automationId,
|
||||||
isUpdate,
|
isUpdate,
|
||||||
devices,
|
devices,
|
||||||
automationActionExecutor,
|
// automationActionExecutor,
|
||||||
routineTab,
|
routineTab,
|
||||||
createRoutineView
|
createRoutineView
|
||||||
];
|
];
|
||||||
|
@ -152,7 +152,8 @@ class AutomationAction {
|
|||||||
return {
|
return {
|
||||||
'entityId': entityId,
|
'entityId': entityId,
|
||||||
'actionExecutor': actionExecutor,
|
'actionExecutor': actionExecutor,
|
||||||
'executorProperty': executorProperty?.toMap(),
|
if (executorProperty != null)
|
||||||
|
'executorProperty': executorProperty?.toMap(),
|
||||||
'actionType': actionType
|
'actionType': actionType
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -7,100 +7,106 @@ import 'package:syncrow_web/pages/routiens/widgets/dialog_header.dart';
|
|||||||
import 'package:syncrow_web/pages/routiens/widgets/dialog_footer.dart';
|
import 'package:syncrow_web/pages/routiens/widgets/dialog_footer.dart';
|
||||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
import 'package:syncrow_web/utils/constants/assets.dart';
|
||||||
|
|
||||||
class AutomationDialog extends StatelessWidget {
|
class AutomationDialog extends StatefulWidget {
|
||||||
final String automationName;
|
final String automationName;
|
||||||
final String automationId;
|
final String automationId;
|
||||||
final String uniqueCustomId;
|
final String uniqueCustomId;
|
||||||
|
final String? passedAutomationActionExecutor;
|
||||||
|
|
||||||
const AutomationDialog({
|
const AutomationDialog({
|
||||||
super.key,
|
super.key,
|
||||||
required this.automationName,
|
required this.automationName,
|
||||||
required this.automationId,
|
required this.automationId,
|
||||||
required this.uniqueCustomId,
|
required this.uniqueCustomId,
|
||||||
|
this.passedAutomationActionExecutor,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
State<AutomationDialog> createState() => _AutomationDialogState();
|
||||||
return BlocBuilder<RoutineBloc, RoutineState>(
|
}
|
||||||
builder: (context, state) {
|
|
||||||
final String? initialSelection = state.automationActionExecutor;
|
|
||||||
|
|
||||||
return Dialog(
|
class _AutomationDialogState extends State<AutomationDialog> {
|
||||||
shape:
|
String? selectedAutomationActionExecutor;
|
||||||
RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
|
|
||||||
child: Container(
|
@override
|
||||||
width: 400,
|
void initState() {
|
||||||
padding: const EdgeInsets.all(16),
|
super.initState();
|
||||||
child: Column(
|
List<DeviceFunctionData>? functions = context
|
||||||
mainAxisSize: MainAxisSize.min,
|
.read<RoutineBloc>()
|
||||||
children: [
|
.state
|
||||||
DialogHeader(automationName),
|
.selectedFunctions[widget.uniqueCustomId];
|
||||||
const SizedBox(height: 16),
|
for (DeviceFunctionData data in functions ?? []) {
|
||||||
ListTile(
|
if (data.entityId == widget.automationId) {
|
||||||
leading:
|
selectedAutomationActionExecutor = data.value;
|
||||||
SvgPicture.asset(Assets.acPower, width: 24, height: 24),
|
}
|
||||||
title: const Text('Enable'),
|
}
|
||||||
trailing: Radio<String?>(
|
}
|
||||||
value: 'rule_enable',
|
|
||||||
groupValue: initialSelection,
|
@override
|
||||||
onChanged: (String? value) {
|
Widget build(BuildContext context) {
|
||||||
if (value != null) {
|
return Dialog(
|
||||||
context.read<RoutineBloc>().add(
|
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
|
||||||
SetAutomationActionExecutor(
|
child: Container(
|
||||||
automationActionExecutor: value,
|
width: 400,
|
||||||
),
|
padding: const EdgeInsets.all(16),
|
||||||
);
|
child: Column(
|
||||||
}
|
mainAxisSize: MainAxisSize.min,
|
||||||
},
|
children: [
|
||||||
),
|
DialogHeader(widget.automationName),
|
||||||
),
|
const SizedBox(height: 16),
|
||||||
ListTile(
|
ListTile(
|
||||||
leading: SvgPicture.asset(Assets.acPowerOff,
|
leading: SvgPicture.asset(Assets.acPower, width: 24, height: 24),
|
||||||
width: 24, height: 24),
|
title: const Text('Enable'),
|
||||||
title: const Text('Disable'),
|
trailing: Radio<String?>(
|
||||||
trailing: Radio<String?>(
|
value: 'rule_enable',
|
||||||
value: 'rule_disable',
|
groupValue: selectedAutomationActionExecutor,
|
||||||
groupValue: initialSelection,
|
onChanged: (String? value) {
|
||||||
onChanged: (String? value) {
|
setState(() {
|
||||||
if (value != null) {
|
selectedAutomationActionExecutor = 'rule_enable';
|
||||||
context.read<RoutineBloc>().add(
|
});
|
||||||
SetAutomationActionExecutor(
|
}),
|
||||||
automationActionExecutor: value,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(height: 16),
|
|
||||||
DialogFooter(
|
|
||||||
onConfirm: () {
|
|
||||||
if (state.automationActionExecutor != null) {
|
|
||||||
context.read<RoutineBloc>().add(
|
|
||||||
AddFunctionToRoutine(
|
|
||||||
[
|
|
||||||
DeviceFunctionData(
|
|
||||||
entityId: automationId,
|
|
||||||
functionCode: 'automation',
|
|
||||||
value: state.automationActionExecutor,
|
|
||||||
operationName: 'Automation',
|
|
||||||
),
|
|
||||||
],
|
|
||||||
uniqueCustomId,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
Navigator.of(context).pop(true);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onCancel: () => Navigator.of(context).pop(false),
|
|
||||||
isConfirmEnabled: state.automationActionExecutor != null,
|
|
||||||
dialogWidth: 400,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
),
|
ListTile(
|
||||||
);
|
leading:
|
||||||
},
|
SvgPicture.asset(Assets.acPowerOff, width: 24, height: 24),
|
||||||
|
title: const Text('Disable'),
|
||||||
|
trailing: Radio<String?>(
|
||||||
|
value: 'rule_disable',
|
||||||
|
groupValue: selectedAutomationActionExecutor,
|
||||||
|
onChanged: (String? value) {
|
||||||
|
setState(() {
|
||||||
|
selectedAutomationActionExecutor = 'rule_disable';
|
||||||
|
});
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 16),
|
||||||
|
DialogFooter(
|
||||||
|
onConfirm: () {
|
||||||
|
if (selectedAutomationActionExecutor != null) {
|
||||||
|
context.read<RoutineBloc>().add(
|
||||||
|
AddFunctionToRoutine(
|
||||||
|
[
|
||||||
|
DeviceFunctionData(
|
||||||
|
entityId: widget.automationId,
|
||||||
|
functionCode: 'automation',
|
||||||
|
value: selectedAutomationActionExecutor,
|
||||||
|
operationName: 'Automation',
|
||||||
|
),
|
||||||
|
],
|
||||||
|
widget.uniqueCustomId,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
Navigator.of(context).pop(true);
|
||||||
|
},
|
||||||
|
onCancel: () => Navigator.of(context).pop(),
|
||||||
|
isConfirmEnabled: selectedAutomationActionExecutor != null,
|
||||||
|
dialogWidth: 400,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -87,8 +87,11 @@ class ThenContainer extends StatelessWidget {
|
|||||||
...state.thenItems[index],
|
...state.thenItems[index],
|
||||||
'imagePath':
|
'imagePath':
|
||||||
Assets.automation,
|
Assets.automation,
|
||||||
'title': state
|
'title':
|
||||||
.thenItems[index]['name'],
|
state.thenItems[index]
|
||||||
|
['name'] ??
|
||||||
|
state.thenItems[index]
|
||||||
|
['title'],
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
@ -171,7 +174,7 @@ class ThenContainer extends StatelessWidget {
|
|||||||
if (mutableData['type'] == 'tap_to_run' && state.isAutomation) {
|
if (mutableData['type'] == 'tap_to_run' && state.isAutomation) {
|
||||||
context.read<RoutineBloc>().add(AddToThenContainer({
|
context.read<RoutineBloc>().add(AddToThenContainer({
|
||||||
...mutableData,
|
...mutableData,
|
||||||
'imagePath': Assets.logo,
|
'imagePath': mutableData['imagePath'] ?? Assets.logo,
|
||||||
'title': mutableData['name'],
|
'title': mutableData['name'],
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user