Pulled latest changes

This commit is contained in:
Abdullah Alassaf
2024-11-30 21:37:55 +03:00
16 changed files with 870 additions and 342 deletions

View File

@ -3,12 +3,17 @@ import 'dart:async';
import 'package:bloc/bloc.dart'; import 'package:bloc/bloc.dart';
import 'package:equatable/equatable.dart'; import 'package:equatable/equatable.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:syncrow_web/pages/device_managment/all_devices/models/devices_model.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_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/create_scene_and_autoamtion/create_scene_model.dart';
import 'package:syncrow_web/pages/routiens/models/delay/delay_fucntions.dart';
import 'package:syncrow_web/pages/routiens/models/device_functions.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_details_model.dart';
import 'package:syncrow_web/pages/routiens/models/routine_model.dart'; import 'package:syncrow_web/pages/routiens/models/routine_model.dart';
import 'package:syncrow_web/services/devices_mang_api.dart';
import 'package:syncrow_web/services/routines_api.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_event.dart';
part 'routine_state.dart'; part 'routine_state.dart';
@ -34,11 +39,11 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
on<ResetRoutineState>(_onResetRoutineState); on<ResetRoutineState>(_onResetRoutineState);
on<GetSceneDetails>(_onGetSceneDetails); on<GetSceneDetails>(_onGetSceneDetails);
on<GetAutomationDetails>(_onGetAutomationDetails); on<GetAutomationDetails>(_onGetAutomationDetails);
// on<InitializeRoutineState>(_onInitializeRoutineState);
on<DeleteScene>(_deleteScene); on<DeleteScene>(_deleteScene);
on<DeleteAutomation>(_deleteAutomation); // on<DeleteAutomation>(_deleteAutomation);
// on<RemoveFunction>(_onRemoveFunction); on<FetchDevicesInRoutine>(_fetchDevices);
// on<ClearFunctions>(_onClearFunctions); on<UpdateScene>(_onUpdateScene);
on<UpdateAutomation>(_onUpdateAutomation);
} }
void _onAddToIfContainer(AddToIfContainer event, Emitter<RoutineState> emit) { void _onAddToIfContainer(AddToIfContainer event, Emitter<RoutineState> emit) {
@ -411,20 +416,246 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
emit(state.copyWith(routineName: event.name)); emit(state.copyWith(routineName: event.name));
} }
(List<Map<String, dynamic>>, List<Map<String, dynamic>>, Map<String, List<DeviceFunctionData>>)
_createCardData(
List<RoutineAction> actions,
List<RoutineCondition>? conditions,
Map<String, List<DeviceFunctionData>> currentFunctions,
bool isTabToRun,
) {
final ifItems = isTabToRun
? [
{
'entityId': 'tab_to_run',
'uniqueCustomId': const Uuid().v4(),
'deviceId': 'tab_to_run',
'title': 'Tab to run',
'productType': 'tab_to_run',
'imagePath': Assets.tabToRun,
}
]
: conditions?.map((condition) {
final matchingDevice = state.devices.firstWhere(
(device) => device.uuid == condition.entityId,
orElse: () => AllDevicesModel(
uuid: condition.entityId,
name: condition.entityId,
productType: condition.entityType,
),
);
final cardData = {
'entityId': condition.entityId,
'uniqueCustomId': const Uuid().v4(),
'deviceId': condition.entityId,
'title': matchingDevice.name ?? condition.entityId,
'productType': condition.entityType,
'imagePath': matchingDevice.getDefaultIcon(condition.entityType),
};
final functions = matchingDevice.functions;
for (var function in functions) {
if (function.code == condition.expr.statusCode) {
currentFunctions[cardData['uniqueCustomId'] ?? ''] = [
DeviceFunctionData(
entityId: condition.entityId,
functionCode: condition.expr.statusCode,
value: condition.expr.statusValue,
operationName: function.operationName,
),
];
break;
}
}
return cardData;
}).toList() ??
[];
final thenItems = 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,
'imagePath': matchingDevice.getDefaultIcon(action.productType),
};
final functions = matchingDevice.functions;
if (action.executorProperty != null && action.actionExecutor != 'delay') {
final functionCode = action.executorProperty!.functionCode;
for (var function in functions) {
if (function.code == functionCode) {
currentFunctions[cardData['uniqueCustomId'] ?? ''] = [
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',
);
currentFunctions[cardData['uniqueCustomId'] ?? ''] = [
DeviceFunctionData(
entityId: action.entityId,
functionCode: 'delay',
value: action.executorProperty?.delaySeconds ?? 0,
operationName: delayFunction.operationName,
),
];
}
return cardData;
}).toList();
return (thenItems, ifItems, currentFunctions);
}
Future<void> _onGetSceneDetails(GetSceneDetails event, Emitter<RoutineState> emit) async { Future<void> _onGetSceneDetails(GetSceneDetails event, Emitter<RoutineState> emit) async {
try { try {
emit(state.copyWith( emit(state.copyWith(
isLoading: true, isLoading: true,
isTabToRun: event.isTabToRun, isTabToRun: event.isTabToRun,
isUpdate: true, isUpdate: true,
sceneId: event.sceneId, sceneId: event.sceneId,
isAutomation: false)); isAutomation: false,
ifItems: [],
thenItems: [],
));
final sceneDetails = await SceneApi.getSceneDetails(event.sceneId); final sceneDetails = await SceneApi.getSceneDetails(event.sceneId);
add(InitializeRoutineState(sceneDetails));
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);
if (event.isTabToRun) {
thenItems = sceneDetails.actions.map((action) {
AllDevicesModel? matchingDevice;
for (var device in state.devices) {
if (device.uuid == action.entityId) {
matchingDevice = device;
break;
}
}
final cardData = {
'entityId': action.entityId,
'uniqueCustomId': const Uuid().v4(),
'deviceId': action.actionExecutor == 'delay' ? 'delay' : action.entityId,
'title': action.actionExecutor == 'delay'
? 'Delay'
: action.type == 'automation'
? action.name ?? 'Automation'
: (matchingDevice?.name ?? 'Device'),
'productType': action.productType,
'functions': matchingDevice?.functions,
'imagePath': matchingDevice?.getDefaultIcon(action.productType),
'device': matchingDevice ?? null,
'name': action.name,
'type': action.type,
};
if (action.type == 'automation') {
updatedFunctions[cardData['uniqueCustomId'].toString()] = [
DeviceFunctionData(
entityId: action.entityId,
functionCode: 'rule',
value: action.actionExecutor,
operationName: action.name ?? 'Automation',
),
];
} else 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,
),
];
}
return cardData;
}).toList();
ifItems = [
{
'entityId': 'tab_to_run',
'uniqueCustomId': const Uuid().v4(),
'deviceId': 'tab_to_run',
'title': 'Tab to run',
'productType': 'tab_to_run',
'imagePath': Assets.tabToRun,
}
];
} else {
final result = _createCardData(
sceneDetails.actions,
sceneDetails.conditions,
updatedFunctions,
false,
);
thenItems = result.$1;
ifItems = result.$2;
}
emit(state.copyWith(
isLoading: false,
routineName: sceneDetails.name,
selectedIcon: sceneDetails.iconId,
selectedAutomationOperator: sceneDetails.decisionExpr,
effectiveTime: sceneDetails.effectiveTime,
isAutomation: false,
isTabToRun: event.isTabToRun,
thenItems: thenItems,
ifItems: ifItems,
selectedFunctions: updatedFunctions,
sceneId: sceneDetails.sceneId,
));
} catch (e) { } catch (e) {
emit(state.copyWith( emit(state.copyWith(
isLoading: false, isLoading: false,
errorMessage: 'Failed to load scene details', errorMessage: 'Failed to load scene details: $e',
)); ));
} }
} }
@ -434,99 +665,147 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
try { try {
emit(state.copyWith( emit(state.copyWith(
isLoading: true, isLoading: true,
isAutomation: event.isAutomation,
automationId: event.automationId,
isTabToRun: false,
isUpdate: true, isUpdate: true,
isTabToRun: false,
automationId: event.automationId,
isAutomation: true,
ifItems: [],
thenItems: [],
)); ));
final automationDetails = await SceneApi.getAutomationDetails(event.automationId); final automationDetails = await SceneApi.getAutomationDetails(event.automationId);
add(InitializeRoutineState(automationDetails));
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) { } catch (e) {
emit(state.copyWith( emit(state.copyWith(
isLoading: false, isLoading: false,
errorMessage: 'Failed to load automation details', errorMessage: 'Failed to load automation details: $e',
)); ));
} }
} }
// void _onInitializeRoutineState(
// InitializeRoutineState event, Emitter<RoutineState> emit) {
// final routineDetails = event.routineDetails;
// // Convert actions to draggable cards for the THEN container
// final thenItems = routineDetails.actions.map((action) {
// final Map<String, dynamic> 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>[
// 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<String, dynamic> 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>[
// 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() { RoutineState _resetState() {
return const RoutineState( return const RoutineState(
ifItems: [], ifItems: [],
@ -555,7 +834,12 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
FutureOr<void> _deleteScene(DeleteScene event, Emitter<RoutineState> emit) { FutureOr<void> _deleteScene(DeleteScene event, Emitter<RoutineState> emit) {
try { try {
emit(state.copyWith(isLoading: true)); emit(state.copyWith(isLoading: true));
SceneApi.deleteScene(unitUuid: spaceId, sceneId: event.sceneId); if (state.isTabToRun) {
SceneApi.deleteScene(unitUuid: spaceId, sceneId: event.id);
} else {
SceneApi.deleteAutomation(unitUuid: spaceId, automationId: event.id);
}
add(const LoadScenes(spaceId, communityId)); add(const LoadScenes(spaceId, communityId));
add(const LoadAutomation(spaceId)); add(const LoadAutomation(spaceId));
emit(_resetState()); emit(_resetState());
@ -567,17 +851,173 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
} }
} }
FutureOr<void> _deleteAutomation(DeleteAutomation event, Emitter<RoutineState> emit) { // FutureOr<void> _deleteAutomation(DeleteAutomation event, Emitter<RoutineState> emit) {
// try {
// emit(state.copyWith(isLoading: true));
// add(const LoadAutomation(spaceId));
// add(const LoadScenes(spaceId, communityId));
// emit(_resetState());
// } catch (e) {
// emit(state.copyWith(
// isLoading: false,
// errorMessage: 'Failed to delete automation',
// ));
// }
// }
FutureOr<void> _fetchDevices(FetchDevicesInRoutine event, Emitter<RoutineState> emit) async {
emit(state.copyWith(isLoading: true));
try { try {
final devices = await DevicesManagementApi().fetchDevices();
emit(state.copyWith(isLoading: false, devices: devices));
} catch (e) {
emit(state.copyWith(isLoading: false));
}
}
FutureOr<void> _onUpdateScene(UpdateScene event, Emitter<RoutineState> emit) async {
try {
// Check if first action is delay
if (_isFirstActionDelay(state.thenItems)) {
emit(state.copyWith(
errorMessage: 'Cannot have delay as the first action',
isLoading: false,
));
return;
}
emit(state.copyWith(isLoading: true)); emit(state.copyWith(isLoading: true));
SceneApi.deleteAutomation(unitUuid: spaceId, automationId: event.automationId);
add(const LoadAutomation(spaceId)); final actions = state.thenItems.expand((item) {
add(const LoadScenes(spaceId, communityId)); final functions = state.selectedFunctions[item['uniqueCustomId']] ?? [];
emit(_resetState()); return functions.map((function) {
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: int.tryParse(function.value.toString()) ?? 0,
),
);
}
return CreateSceneAction(
entityId: function.entityId,
actionExecutor: 'device_issue',
executorProperty: CreateSceneExecutorProperty(
functionCode: function.functionCode,
functionValue: function.value,
delaySeconds: 0,
),
);
});
}).toList();
final createSceneModel = CreateSceneModel(
spaceUuid: state.sceneId ?? '',
iconId: state.selectedIcon ?? '',
showInDevice: true,
sceneName: state.routineName ?? '',
decisionExpr: 'and',
actions: actions,
);
final result = await SceneApi.updateScene(createSceneModel, state.sceneId ?? '');
if (result['success']) {
emit(_resetState());
add(const LoadScenes(spaceId, communityId));
} else {
emit(state.copyWith(
isLoading: false,
errorMessage: result['message'],
));
}
} catch (e) { } catch (e) {
emit(state.copyWith( emit(state.copyWith(
isLoading: false, isLoading: false,
errorMessage: 'Failed to delete automation', errorMessage: 'Something went wrong',
));
}
}
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;
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();
final actions = state.thenItems
.map((item) {
final functions = state.selectedFunctions[item['uniqueCustomId']] ?? [];
if (functions.isEmpty) return null;
final function = functions.first;
return AutomationAction(
entityId: function.entityId,
actionExecutor: function.actionExecutor,
executorProperty: ExecutorProperty(
functionCode: function.functionCode,
functionValue: function.value,
delaySeconds:
function.functionCode == 'delay' ? (function.value as num).toInt() : null,
),
);
})
.whereType<AutomationAction>()
.toList();
final createAutomationModel = CreateAutomationModel(
spaceUuid: spaceId,
automationName: state.routineName ?? '',
decisionExpr: state.selectedAutomationOperator,
effectiveTime: state.effectiveTime ?? EffectiveTime(start: '', end: '', loops: ''),
conditions: conditions,
actions: actions,
);
await SceneApi.updateAutomation(createAutomationModel, state.automationId ?? '');
add(const LoadAutomation(spaceId));
emit(state.copyWith(isLoading: false));
} catch (e) {
emit(state.copyWith(
isLoading: false,
errorMessage: 'Failed to update automation: $e',
)); ));
} }
} }

View File

@ -84,8 +84,7 @@ class RemoveDragCard extends RoutineEvent {
final int index; final int index;
final bool isFromThen; final bool isFromThen;
final String key; final String key;
const RemoveDragCard( const RemoveDragCard({required this.index, required this.isFromThen, required this.key});
{required this.index, required this.isFromThen, required this.key});
@override @override
List<Object> get props => [index, isFromThen, key]; List<Object> get props => [index, isFromThen, key];
} }
@ -105,12 +104,10 @@ class EffectiveTimePeriodEvent extends RoutineEvent {
} }
class CreateAutomationEvent extends RoutineEvent { class CreateAutomationEvent extends RoutineEvent {
// final CreateAutomationModel createAutomationModel;
final String? automationId; final String? automationId;
final bool updateAutomation; final bool updateAutomation;
const CreateAutomationEvent({ const CreateAutomationEvent({
//required this.createAutomationModel,
this.automationId, this.automationId,
this.updateAutomation = false, this.updateAutomation = false,
}); });
@ -159,21 +156,33 @@ class InitializeRoutineState extends RoutineEvent {
} }
class DeleteScene extends RoutineEvent { class DeleteScene extends RoutineEvent {
final String sceneId; final String id;
final String unitUuid; const DeleteScene({required this.id});
const DeleteScene({required this.sceneId, required this.unitUuid});
@override @override
List<Object> get props => [sceneId]; List<Object> get props => [id];
} }
class DeleteAutomation extends RoutineEvent { // class DeleteAutomation extends RoutineEvent {
final String automationId; // final String automationId;
final String unitUuid; // const DeleteAutomation({required this.automationId});
const DeleteAutomation({required this.automationId, required this.unitUuid}); // @override
// List<Object> get props => [automationId];
// }
class UpdateScene extends RoutineEvent {
const UpdateScene();
@override @override
List<Object> get props => [automationId]; List<Object> get props => [];
} }
class UpdateAutomation extends RoutineEvent {
const UpdateAutomation();
@override
List<Object> get props => [];
}
class FetchDevicesInRoutine extends RoutineEvent {}
class ResetRoutineState extends RoutineEvent {} class ResetRoutineState extends RoutineEvent {}
class ClearFunctions extends RoutineEvent {} class ClearFunctions extends RoutineEvent {}

View File

@ -21,6 +21,7 @@ class RoutineState extends Equatable {
final String? sceneId; final String? sceneId;
final String? automationId; final String? automationId;
final bool? isUpdate; final bool? isUpdate;
final List<AllDevicesModel> devices;
const RoutineState({ const RoutineState({
this.ifItems = const [], this.ifItems = const [],
@ -43,6 +44,7 @@ class RoutineState extends Equatable {
this.sceneId, this.sceneId,
this.automationId, this.automationId,
this.isUpdate, this.isUpdate,
this.devices = const [],
}); });
RoutineState copyWith({ RoutineState copyWith({
@ -65,6 +67,7 @@ class RoutineState extends Equatable {
String? sceneId, String? sceneId,
String? automationId, String? automationId,
bool? isUpdate, bool? isUpdate,
List<AllDevicesModel>? devices,
}) { }) {
return RoutineState( return RoutineState(
ifItems: ifItems ?? this.ifItems, ifItems: ifItems ?? this.ifItems,
@ -89,6 +92,7 @@ class RoutineState extends Equatable {
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,
); );
} }
@ -112,6 +116,7 @@ class RoutineState extends Equatable {
effectiveTime, effectiveTime,
sceneId, sceneId,
automationId, automationId,
isUpdate isUpdate,
devices,
]; ];
} }

View File

@ -54,23 +54,27 @@ class SaveRoutineHelper {
), ),
if (state.isAutomation) if (state.isAutomation)
...state.ifItems.map((item) { ...state.ifItems.map((item) {
final functions = final functions = state.selectedFunctions[
state.selectedFunctions[item['uniqueCustomId']] ?? []; item['uniqueCustomId']] ??
[];
return ListTile( return ListTile(
leading: SvgPicture.asset( leading: SvgPicture.asset(
item['imagePath'], item['imagePath'],
width: 22, width: 22,
height: 22, height: 22,
), ),
title: title: Text(item['title'],
Text(item['title'], style: const TextStyle(fontSize: 14)), style: const TextStyle(fontSize: 14)),
subtitle: Wrap( subtitle: Wrap(
children: functions children: functions
.map((f) => Text( .map((f) => Text(
'${f.operationName}: ${f.value}, ', '${f.operationName}: ${f.value}, ',
style: const TextStyle( style: const TextStyle(
color: ColorsManager.grayColor, fontSize: 8), color: ColorsManager
overflow: TextOverflow.ellipsis, .grayColor,
fontSize: 8),
overflow:
TextOverflow.ellipsis,
maxLines: 3, maxLines: 3,
)) ))
.toList(), .toList(),
@ -95,22 +99,25 @@ class SaveRoutineHelper {
), ),
const SizedBox(height: 8), const SizedBox(height: 8),
...state.thenItems.map((item) { ...state.thenItems.map((item) {
final functions = final functions = state.selectedFunctions[
state.selectedFunctions[item['uniqueCustomId']] ?? []; item['uniqueCustomId']] ??
[];
return ListTile( return ListTile(
leading: SvgPicture.asset( leading: SvgPicture.asset(
item['imagePath'], item['imagePath'],
width: 22, width: 22,
height: 22, height: 22,
), ),
title: title: Text(item['title'],
Text(item['title'], style: const TextStyle(fontSize: 14)), style: const TextStyle(fontSize: 14)),
subtitle: Wrap( subtitle: Wrap(
children: functions children: functions
.map((f) => Text( .map((f) => Text(
'${f.operationName}: ${f.value}, ', '${f.operationName}: ${f.value}, ',
style: const TextStyle( style: const TextStyle(
color: ColorsManager.grayColor, fontSize: 8), color:
ColorsManager.grayColor,
fontSize: 8),
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
maxLines: 3, maxLines: 3,
)) ))
@ -136,9 +143,25 @@ class SaveRoutineHelper {
onCancel: () => Navigator.pop(context, false), onCancel: () => Navigator.pop(context, false),
onConfirm: () { onConfirm: () {
if (state.isAutomation) { if (state.isAutomation) {
context.read<RoutineBloc>().add(const CreateAutomationEvent()); if (state.automationId != null) {
context
.read<RoutineBloc>()
.add(const UpdateAutomation());
} else {
context
.read<RoutineBloc>()
.add(const CreateAutomationEvent());
}
} else { } else {
context.read<RoutineBloc>().add(const CreateSceneEvent()); if (state.sceneId != null) {
context
.read<RoutineBloc>()
.add(const UpdateScene());
} else {
context
.read<RoutineBloc>()
.add(const CreateSceneEvent());
}
} }
Navigator.pop(context, true); Navigator.pop(context, true);

View File

@ -17,7 +17,7 @@ class CreateAutomationModel {
required this.actions, required this.actions,
}); });
Map<String, dynamic> toMap() { Map<String, dynamic> toMap([String? automationId]) {
return { return {
'spaceUuid': spaceUuid, 'spaceUuid': spaceUuid,
'automationName': automationName, 'automationName': automationName,
@ -41,7 +41,7 @@ class CreateAutomationModel {
); );
} }
String toJson() => json.encode(toMap()); String toJson(String? automationId) => json.encode(toMap(automationId));
factory CreateAutomationModel.fromJson(String source) => factory CreateAutomationModel.fromJson(String source) =>
CreateAutomationModel.fromMap(json.decode(source)); CreateAutomationModel.fromMap(json.decode(source));

View File

@ -13,6 +13,8 @@ class RoutineDetailsModel {
final EffectiveTime? effectiveTime; final EffectiveTime? effectiveTime;
final List<RoutineCondition>? conditions; final List<RoutineCondition>? conditions;
final String? type; final String? type;
final String? sceneId;
final String? automationId;
RoutineDetailsModel({ RoutineDetailsModel({
required this.spaceUuid, required this.spaceUuid,
@ -24,6 +26,8 @@ class RoutineDetailsModel {
this.effectiveTime, this.effectiveTime,
this.conditions, this.conditions,
this.type, this.type,
this.sceneId,
this.automationId,
}); });
// Convert to CreateSceneModel // Convert to CreateSceneModel
@ -44,8 +48,7 @@ class RoutineDetailsModel {
spaceUuid: spaceUuid, spaceUuid: spaceUuid,
automationName: name, automationName: name,
decisionExpr: decisionExpr, decisionExpr: decisionExpr,
effectiveTime: effectiveTime: effectiveTime ?? EffectiveTime(start: '', end: '', loops: ''),
effectiveTime ?? EffectiveTime(start: '', end: '', loops: ''),
conditions: conditions?.map((c) => c.toCondition()).toList() ?? [], conditions: conditions?.map((c) => c.toCondition()).toList() ?? [],
actions: actions.map((a) => a.toAutomationAction()).toList(), actions: actions.map((a) => a.toAutomationAction()).toList(),
); );
@ -57,12 +60,13 @@ class RoutineDetailsModel {
'name': name, 'name': name,
'decisionExpr': decisionExpr, 'decisionExpr': decisionExpr,
'actions': actions.map((x) => x.toMap()).toList(), 'actions': actions.map((x) => x.toMap()).toList(),
if (iconId != null) 'iconId': iconId, if (iconId != null) 'iconUuid': iconId,
if (showInDevice != null) 'showInDevice': showInDevice, if (showInDevice != null) 'showInDevice': showInDevice,
if (effectiveTime != null) 'effectiveTime': effectiveTime!.toMap(), if (effectiveTime != null) 'effectiveTime': effectiveTime!.toMap(),
if (conditions != null) if (conditions != null) 'conditions': conditions!.map((x) => x.toMap()).toList(),
'conditions': conditions!.map((x) => x.toMap()).toList(),
if (type != null) 'type': type, if (type != null) 'type': type,
if (sceneId != null) 'sceneId': sceneId,
if (automationId != null) 'automationId': automationId,
}; };
} }
@ -74,16 +78,16 @@ class RoutineDetailsModel {
actions: List<RoutineAction>.from( actions: List<RoutineAction>.from(
map['actions']?.map((x) => RoutineAction.fromMap(x)) ?? [], map['actions']?.map((x) => RoutineAction.fromMap(x)) ?? [],
), ),
iconId: map['iconId'], iconId: map['iconUuid'],
showInDevice: map['showInDevice'], showInDevice: map['showInDevice'],
effectiveTime: map['effectiveTime'] != null effectiveTime:
? EffectiveTime.fromMap(map['effectiveTime']) map['effectiveTime'] != null ? EffectiveTime.fromMap(map['effectiveTime']) : null,
: null,
conditions: map['conditions'] != null conditions: map['conditions'] != null
? List<RoutineCondition>.from( ? List<RoutineCondition>.from(map['conditions'].map((x) => RoutineCondition.fromMap(x)))
map['conditions'].map((x) => RoutineCondition.fromMap(x)))
: null, : null,
type: map['type'], type: map['type'],
sceneId: map['sceneId'],
automationId: map['automationId'],
); );
} }
@ -96,12 +100,18 @@ class RoutineDetailsModel {
class RoutineAction { class RoutineAction {
final String entityId; final String entityId;
final String actionExecutor; final String actionExecutor;
final String? name;
final RoutineExecutorProperty? executorProperty; final RoutineExecutorProperty? executorProperty;
final String productType;
final String? type;
RoutineAction({ RoutineAction({
required this.entityId, required this.entityId,
required this.actionExecutor, required this.actionExecutor,
required this.productType,
this.executorProperty, this.executorProperty,
this.name,
this.type,
}); });
CreateSceneAction toCreateSceneAction() { CreateSceneAction toCreateSceneAction() {
@ -124,8 +134,9 @@ class RoutineAction {
return { return {
'entityId': entityId, 'entityId': entityId,
'actionExecutor': actionExecutor, 'actionExecutor': actionExecutor,
if (executorProperty != null) if (type != null) 'type': type,
'executorProperty': executorProperty!.toMap(), if (name != null) 'name': name,
if (executorProperty != null) 'executorProperty': executorProperty!.toMap(),
}; };
} }
@ -133,6 +144,9 @@ class RoutineAction {
return RoutineAction( return RoutineAction(
entityId: map['entityId'] ?? '', entityId: map['entityId'] ?? '',
actionExecutor: map['actionExecutor'] ?? '', actionExecutor: map['actionExecutor'] ?? '',
productType: map['productType'] ?? '',
name: map['name'] ?? '',
type: map['type'] ?? '',
executorProperty: map['executorProperty'] != null executorProperty: map['executorProperty'] != null
? RoutineExecutorProperty.fromMap(map['executorProperty']) ? RoutineExecutorProperty.fromMap(map['executorProperty'])
: null, : null,
@ -189,12 +203,14 @@ class RoutineCondition {
final String entityId; final String entityId;
final String entityType; final String entityType;
final RoutineConditionExpr expr; final RoutineConditionExpr expr;
final String productType;
RoutineCondition({ RoutineCondition({
required this.code, required this.code,
required this.entityId, required this.entityId,
required this.entityType, required this.entityType,
required this.expr, required this.expr,
required this.productType,
}); });
Condition toCondition() { Condition toCondition() {
@ -221,6 +237,7 @@ class RoutineCondition {
entityId: map['entityId'] ?? '', entityId: map['entityId'] ?? '',
entityType: map['entityType'] ?? '', entityType: map['entityType'] ?? '',
expr: RoutineConditionExpr.fromMap(map['expr']), expr: RoutineConditionExpr.fromMap(map['expr']),
productType: map['productType'] ?? '',
); );
} }
} }

View File

@ -16,6 +16,7 @@ class CreateNewRoutineView extends StatelessWidget {
this.routineId, this.routineId,
this.isScene = true, this.isScene = true,
}); });
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Container( return Container(

View File

@ -7,9 +7,20 @@ import 'package:syncrow_web/pages/routiens/widgets/main_routine_view/fetch_routi
import 'package:syncrow_web/pages/routiens/widgets/main_routine_view/routine_view_card.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/color_manager.dart';
class RoutinesView extends StatelessWidget { class RoutinesView extends StatefulWidget {
const RoutinesView({super.key}); const RoutinesView({super.key});
@override
State<RoutinesView> createState() => _RoutinesViewState();
}
class _RoutinesViewState extends State<RoutinesView> {
@override
void initState() {
super.initState();
context.read<RoutineBloc>().add(FetchDevicesInRoutine());
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return BlocBuilder<SwitchTabsBloc, SwitchTabsState>( return BlocBuilder<SwitchTabsBloc, SwitchTabsState>(

View File

@ -42,8 +42,9 @@ class DeleteSceneWidget extends StatelessWidget {
Container(width: 1, height: 50, color: ColorsManager.greyColor), Container(width: 1, height: 50, color: ColorsManager.greyColor),
InkWell( InkWell(
onTap: () { onTap: () {
// context.read<RoutineBloc>().add( context.read<RoutineBloc>().add(DeleteScene(
// DeleteAutomation(automationId: automationId, unitUuid: unitUuid)); id: context.read<RoutineBloc>().state.automationId!,
));
Navigator.of(context).pop(); Navigator.of(context).pop();
Navigator.of(context).pop(); Navigator.of(context).pop();
}, },

View File

@ -83,15 +83,19 @@ class DraggableCard extends StatelessWidget {
? SvgPicture.asset( ? SvgPicture.asset(
imagePath, imagePath,
) )
: Image.memory( : imagePath.contains('.png')
base64Decode(imagePath), ? Image.asset(
), imagePath,
)
: Image.memory(
base64Decode(imagePath),
),
), ),
const SizedBox(height: 8), const SizedBox(height: 8),
Padding( Padding(
padding: const EdgeInsets.symmetric(horizontal: 3), padding: const EdgeInsets.symmetric(horizontal: 3),
child: Text( child: Text(
title, deviceData['title'] ?? deviceData['name'] ?? title,
textAlign: TextAlign.center, textAlign: TextAlign.center,
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
maxLines: 2, maxLines: 2,
@ -104,7 +108,6 @@ class DraggableCard extends StatelessWidget {
], ],
), ),
if (deviceFunctions.isNotEmpty) if (deviceFunctions.isNotEmpty)
// const Divider(height: 1),
...deviceFunctions.map((function) => Row( ...deviceFunctions.map((function) => Row(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [

View File

@ -1,5 +1,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.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/bloc/routine_bloc/routine_bloc.dart';
import 'package:syncrow_web/pages/routiens/widgets/main_routine_view/routine_view_card.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/color_manager.dart';
@ -67,7 +68,18 @@ class _FetchRoutineScenesState extends State<FetchRoutineScenesAutomation>
right: isSmallScreenSize(context) ? 4.0 : 8.0, right: isSmallScreenSize(context) ? 4.0 : 8.0,
), ),
child: RoutineViewCard( child: RoutineViewCard(
onTap: () {}, onTap: () {
BlocProvider.of<SwitchTabsBloc>(context).add(
const CreateNewRoutineViewEvent(true),
);
context.read<RoutineBloc>().add(
GetSceneDetails(
sceneId: state.scenes[index].id,
isTabToRun: true,
isUpdate: true,
),
);
},
textString: state.scenes[index].name, textString: state.scenes[index].name,
icon: state.scenes[index].icon ?? Assets.logoHorizontal, icon: state.scenes[index].icon ?? Assets.logoHorizontal,
isFromScenes: true, isFromScenes: true,
@ -105,7 +117,17 @@ class _FetchRoutineScenesState extends State<FetchRoutineScenesAutomation>
right: isSmallScreenSize(context) ? 4.0 : 8.0, right: isSmallScreenSize(context) ? 4.0 : 8.0,
), ),
child: RoutineViewCard( child: RoutineViewCard(
onTap: () {}, onTap: () {
BlocProvider.of<SwitchTabsBloc>(context).add(
const CreateNewRoutineViewEvent(true),
);
context.read<RoutineBloc>().add(
GetAutomationDetails(
automationId: state.automations[index].id,
isAutomation: true,
isUpdate: true),
);
},
textString: state.automations[index].name, textString: state.automations[index].name,
icon: state.automations[index].icon ?? Assets.automation, icon: state.automations[index].icon ?? Assets.automation,
), ),

View File

@ -1,6 +1,5 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_web/pages/device_managment/all_devices/bloc/device_mgmt_bloc/device_managment_bloc.dart';
import 'package:syncrow_web/pages/device_managment/all_devices/models/devices_model.dart'; import 'package:syncrow_web/pages/device_managment/all_devices/models/devices_model.dart';
import 'package:syncrow_web/pages/routiens/bloc/routine_bloc/routine_bloc.dart'; import 'package:syncrow_web/pages/routiens/bloc/routine_bloc/routine_bloc.dart';
import 'package:syncrow_web/pages/routiens/widgets/dragable_card.dart'; import 'package:syncrow_web/pages/routiens/widgets/dragable_card.dart';
@ -10,68 +9,67 @@ class RoutineDevices extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return BlocProvider( return BlocBuilder<RoutineBloc, RoutineState>(
create: (context) => DeviceManagementBloc()..add(FetchDevices()), builder: (context, state) {
child: BlocBuilder<DeviceManagementBloc, DeviceManagementState>( if (state.isLoading) {
builder: (context, state) {
if (state is DeviceManagementLoaded) {
List<AllDevicesModel> deviceList = state.devices
.where((device) =>
device.productType == 'AC' ||
device.productType == '1G' ||
device.productType == '2G' ||
device.productType == '3G')
.toList();
// Provide the RoutineBloc to the child widgets
return BlocBuilder<RoutineBloc, RoutineState>(
builder: (context, routineState) {
return Wrap(
spacing: 10,
runSpacing: 10,
children: deviceList.asMap().entries.map((entry) {
final device = entry.value;
if (routineState.searchText != null && routineState.searchText!.isNotEmpty) {
return device.name!
.toLowerCase()
.contains(routineState.searchText!.toLowerCase())
? DraggableCard(
imagePath: device.getDefaultIcon(device.productType),
title: device.name ?? '',
deviceData: {
'device': device,
'imagePath': device.getDefaultIcon(device.productType),
'title': device.name ?? '',
'deviceId': device.uuid,
'productType': device.productType,
'functions': device.functions,
'uniqueCustomId': '',
},
)
: Container();
} else {
return DraggableCard(
imagePath: device.getDefaultIcon(device.productType),
title: device.name ?? '',
deviceData: {
'device': device,
'imagePath': device.getDefaultIcon(device.productType),
'title': device.name ?? '',
'deviceId': device.uuid,
'productType': device.productType,
'functions': device.functions,
'uniqueCustomId': '',
},
);
}
}).toList(),
);
},
);
}
return const Center(child: CircularProgressIndicator()); return const Center(child: CircularProgressIndicator());
}, }
),
Future.delayed(const Duration(seconds: 1), () {
if (state.devices.isEmpty) {
return const Center(child: Text('No devices found'));
}
});
List<AllDevicesModel> deviceList = state.devices
.where((device) =>
device.productType == 'AC' ||
device.productType == '1G' ||
device.productType == '2G' ||
device.productType == '3G')
.toList();
return Wrap(
spacing: 10,
runSpacing: 10,
children: deviceList.asMap().entries.map((entry) {
final device = entry.value;
if (state.searchText != null && state.searchText!.isNotEmpty) {
return device.name!
.toLowerCase()
.contains(state.searchText!.toLowerCase())
? DraggableCard(
imagePath: device.getDefaultIcon(device.productType),
title: device.name ?? '',
deviceData: {
'device': device,
'imagePath': device.getDefaultIcon(device.productType),
'title': device.name ?? '',
'deviceId': device.uuid,
'productType': device.productType,
'functions': device.functions,
'uniqueCustomId': '',
},
)
: Container();
} else {
return DraggableCard(
imagePath: device.getDefaultIcon(device.productType),
title: device.name ?? '',
deviceData: {
'device': device,
'imagePath': device.getDefaultIcon(device.productType),
'title': device.name ?? '',
'deviceId': device.uuid,
'productType': device.productType,
'functions': device.functions,
'uniqueCustomId': '',
},
);
}
}).toList(),
);
},
); );
} }
} }

View File

@ -1,6 +1,5 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_web/pages/common/custom_dialog.dart';
import 'package:syncrow_web/pages/routiens/bloc/effective_period/effect_period_bloc.dart'; import 'package:syncrow_web/pages/routiens/bloc/effective_period/effect_period_bloc.dart';
import 'package:syncrow_web/pages/routiens/bloc/effective_period/effect_period_state.dart'; import 'package:syncrow_web/pages/routiens/bloc/effective_period/effect_period_state.dart';
import 'package:syncrow_web/pages/routiens/bloc/routine_bloc/routine_bloc.dart'; import 'package:syncrow_web/pages/routiens/bloc/routine_bloc/routine_bloc.dart';
@ -169,8 +168,9 @@ class SettingHelper {
fontSize: 14)), fontSize: 14)),
], ],
), ),
// if (context.read<RoutineBloc>().state.isAutomation) if (context.read<RoutineBloc>().state.isUpdate ??
const DeleteSceneWidget() false)
const DeleteSceneWidget()
], ],
)), )),
], ],
@ -288,8 +288,9 @@ class SettingHelper {
fontSize: 14)), fontSize: 14)),
], ],
), ),
// if (context.read<RoutineBloc>().state.isAutomation) if (context.read<RoutineBloc>().state.isUpdate ??
const DeleteSceneWidget() false)
const DeleteSceneWidget()
], ],
)), )),
], ],

View File

@ -26,73 +26,87 @@ class ThenContainer extends StatelessWidget {
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
const Text('THEN', const Text('THEN', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
style: TextStyle(
fontSize: 18, fontWeight: FontWeight.bold)),
const SizedBox(height: 16), const SizedBox(height: 16),
Wrap( state.isLoading && state.isUpdate == true
spacing: 8, ? const Center(
runSpacing: 8, child: CircularProgressIndicator(),
children: List.generate( )
state.thenItems.length, : Wrap(
(index) => GestureDetector( spacing: 8,
onTap: () async { runSpacing: 8,
if (state.thenItems[index]['deviceId'] == children: List.generate(
'delay') { state.thenItems.length,
final result = await DelayHelper (index) => GestureDetector(
.showDelayPickerDialog( onTap: () async {
if (state.thenItems[index]['deviceId'] == 'delay') {
final result = await DelayHelper.showDelayPickerDialog(
context, state.thenItems[index]); context, state.thenItems[index]);
if (result != null) { if (result != null) {
context context.read<RoutineBloc>().add(AddToThenContainer({
.read<RoutineBloc>() ...state.thenItems[index],
.add(AddToThenContainer({ 'imagePath': Assets.delay,
...state.thenItems[index], 'title': 'Delay',
'imagePath': Assets.delay, }));
'title': 'Delay', }
})); return;
} }
return;
}
final result = await DeviceDialogHelper if (state.thenItems[index]['type'] == 'automation') {
.showDeviceDialog( final result = await showDialog<bool>(
context: context,
builder: (BuildContext context) => AutomationDialog(
automationName:
state.thenItems[index]['name'] ?? 'Automation',
automationId:
state.thenItems[index]['deviceId'] ?? '',
uniqueCustomId: state.thenItems[index]
['uniqueCustomId'],
),
);
if (result != null) {
context.read<RoutineBloc>().add(AddToThenContainer({
...state.thenItems[index],
'imagePath': Assets.automation,
'title': state.thenItems[index]['name'],
}));
}
return;
}
final result = await DeviceDialogHelper.showDeviceDialog(
context, state.thenItems[index], context, state.thenItems[index],
removeComparetors: true); removeComparetors: true);
if (result != null) { if (result != null) {
context.read<RoutineBloc>().add( context
AddToThenContainer( .read<RoutineBloc>()
state.thenItems[index])); .add(AddToThenContainer(state.thenItems[index]));
} else if (!['AC', '1G', '2G', '3G'] } else if (!['AC', '1G', '2G', '3G']
.contains(state.thenItems[index] .contains(state.thenItems[index]['productType'])) {
['productType'])) { context
context.read<RoutineBloc>().add( .read<RoutineBloc>()
AddToThenContainer( .add(AddToThenContainer(state.thenItems[index]));
state.thenItems[index])); }
} },
}, child: DraggableCard(
child: DraggableCard( imagePath: state.thenItems[index]['imagePath'] ?? '',
imagePath: state.thenItems[index] title: state.thenItems[index]['title'] ?? '',
['imagePath'] ?? deviceData: state.thenItems[index],
'', padding:
title: const EdgeInsets.symmetric(horizontal: 4, vertical: 8),
state.thenItems[index]['title'] ?? '', isFromThen: true,
deviceData: state.thenItems[index], isFromIf: false,
padding: const EdgeInsets.symmetric( onRemove: () {
horizontal: 4, vertical: 8), context.read<RoutineBloc>().add(RemoveDragCard(
isFromThen: true,
isFromIf: false,
onRemove: () {
context.read<RoutineBloc>().add(
RemoveDragCard(
index: index, index: index,
isFromThen: true, isFromThen: true,
key: state.thenItems[index] key: state.thenItems[index]['uniqueCustomId']));
['uniqueCustomId'])); },
}, ),
), ))),
))),
], ],
), ),
), ),
@ -143,8 +157,7 @@ class ThenContainer extends StatelessWidget {
} }
if (mutableData['deviceId'] == 'delay') { if (mutableData['deviceId'] == 'delay') {
final result = final result = await DelayHelper.showDelayPickerDialog(context, mutableData);
await DelayHelper.showDelayPickerDialog(context, mutableData);
if (result != null) { if (result != null) {
context.read<RoutineBloc>().add(AddToThenContainer({ context.read<RoutineBloc>().add(AddToThenContainer({
@ -156,13 +169,11 @@ class ThenContainer extends StatelessWidget {
return; return;
} }
final result = await DeviceDialogHelper.showDeviceDialog( final result = await DeviceDialogHelper.showDeviceDialog(context, mutableData,
context, mutableData,
removeComparetors: true); removeComparetors: true);
if (result != null) { if (result != null) {
context.read<RoutineBloc>().add(AddToThenContainer(mutableData)); context.read<RoutineBloc>().add(AddToThenContainer(mutableData));
} else if (!['AC', '1G', '2G', '3G'] } else if (!['AC', '1G', '2G', '3G'].contains(mutableData['productType'])) {
.contains(mutableData['productType'])) {
context.read<RoutineBloc>().add(AddToThenContainer(mutableData)); context.read<RoutineBloc>().add(AddToThenContainer(mutableData));
} }
}, },

View File

@ -138,29 +138,49 @@ class SceneApi {
path: ApiEndpoints.getAutomationDetails path: ApiEndpoints.getAutomationDetails
.replaceAll('{automationId}', automationId), .replaceAll('{automationId}', automationId),
showServerMessage: false, showServerMessage: false,
expectedResponseModel: (json) => RoutineDetailsModel.fromJson(json), expectedResponseModel: (json) => RoutineDetailsModel.fromMap(json),
);
return response;
} catch (e) {
rethrow;
}
}
//update Scene
static updateScene(CreateSceneModel createSceneModel, String sceneId) async {
try {
final response = await _httpService.put(
path: ApiEndpoints.updateScene.replaceAll('{sceneId}', sceneId),
body: createSceneModel
.toJson(sceneId.isNotEmpty == true ? sceneId : null),
expectedResponseModel: (json) {
return json;
},
);
return response;
} catch (e) {
rethrow;
}
}
//update automation
static updateAutomation(
CreateAutomationModel createAutomationModel, String automationId) async {
try {
final response = await _httpService.put(
path: ApiEndpoints.updateAutomation
.replaceAll('{automationId}', automationId),
body: createAutomationModel
.toJson(automationId.isNotEmpty == true ? automationId : null),
expectedResponseModel: (json) {
return json;
},
); );
return response; return response;
} catch (e) { } catch (e) {
rethrow; rethrow;
} }
} }
//
// //updateAutomationStatus
// static Future<bool> updateAutomationStatus(String automationId,
// AutomationStatusUpdate createAutomationEnable) async {
// try {
// final response = await _httpService.put(
// path: ApiEndpoints.updateAutomationStatus
// .replaceAll('{automationId}', automationId),
// body: createAutomationEnable.toMap(),
// expectedResponseModel: (json) => json['success'],
// );
// return response;
// } catch (e) {
// rethrow;
// }
// }
//getScene //getScene
static Future<RoutineDetailsModel> getSceneDetails(String sceneId) async { static Future<RoutineDetailsModel> getSceneDetails(String sceneId) async {
@ -168,52 +188,15 @@ class SceneApi {
final response = await _httpService.get( final response = await _httpService.get(
path: ApiEndpoints.getScene.replaceAll('{sceneId}', sceneId), path: ApiEndpoints.getScene.replaceAll('{sceneId}', sceneId),
showServerMessage: false, showServerMessage: false,
expectedResponseModel: (json) => RoutineDetailsModel.fromJson(json), expectedResponseModel: (json) =>
RoutineDetailsModel.fromMap(json['data']),
); );
return response; return response;
} catch (e) { } catch (e) {
rethrow; rethrow;
} }
} }
//
// //update Scene
// static updateScene(CreateSceneModel createSceneModel, String sceneId) async {
// try {
// final response = await _httpService.put(
// path: ApiEndpoints.updateScene.replaceAll('{sceneId}', sceneId),
// body: createSceneModel
// .toJson(sceneId.isNotEmpty == true ? sceneId : null),
// expectedResponseModel: (json) {
// return json;
// },
// );
// return response;
// } catch (e) {
// rethrow;
// }
// }
//
// //update automation
// static updateAutomation(
// CreateAutomationModel createAutomationModel, String automationId) async {
// try {
// final response = await _httpService.put(
// path: ApiEndpoints.updateAutomation
// .replaceAll('{automationId}', automationId),
// body: createAutomationModel
// .toJson(automationId.isNotEmpty == true ? automationId : null),
// expectedResponseModel: (json) {
// return json;
// },
// );
// return response;
// } catch (e) {
// rethrow;
// }
// }
//
//delete Scene //delete Scene
static Future<bool> deleteScene( static Future<bool> deleteScene(
{required String unitUuid, required String sceneId}) async { {required String unitUuid, required String sceneId}) async {
@ -230,7 +213,7 @@ class SceneApi {
rethrow; rethrow;
} }
} }
// delete automation // delete automation
static Future<bool> deleteAutomation( static Future<bool> deleteAutomation(
{required String unitUuid, required String automationId}) async { {required String unitUuid, required String automationId}) async {

View File

@ -74,4 +74,7 @@ abstract class ApiEndpoints {
static const String deleteScene = '/scene/tap-to-run/{sceneId}'; static const String deleteScene = '/scene/tap-to-run/{sceneId}';
static const String deleteAutomation = '/automation/{automationId}'; static const String deleteAutomation = '/automation/{automationId}';
static const String updateScene = '/scene/tap-to-run/{sceneId}';
static const String updateAutomation = '/automation/{automationId}';
} }